summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Roessler <roessler@does-not-exist.org>1999-02-09 20:50:36 +0000
committerThomas Roessler <roessler@does-not-exist.org>1999-02-09 20:50:36 +0000
commit5ba906d2a77b9b45e46ed23a6959f7a97a6ad68e (patch)
treedeaead3c88005ef70d4d954cca3552083294e145
parente4f9683bb99a38bd46b9e7f2d18d2a35dfcd94bf (diff)
Brandon's IMAP clean-up; new czech translation.
-rw-r--r--OPS5
-rw-r--r--browser.c153
-rw-r--r--browser.h48
-rw-r--r--complete.c15
-rw-r--r--doc/manual.sgml.in52
-rw-r--r--functions.h5
-rw-r--r--imap.c988
-rw-r--r--imap.h22
-rw-r--r--init.h4
-rw-r--r--menu.c7
-rw-r--r--mutt.h4
-rw-r--r--mutt_socket.h2
-rw-r--r--mx.c4
-rw-r--r--po/cs.po33
-rw-r--r--socket.c32
15 files changed, 1104 insertions, 270 deletions
diff --git a/OPS b/OPS
index e5add27a..23a60fee 100644
--- a/OPS
+++ b/OPS
@@ -6,6 +6,9 @@ OP_BOUNCE_MESSAGE "remail a message to another user"
OP_BROWSER_NEW_FILE "select a new file in this directory"
OP_BROWSER_VIEW_FILE "view file"
OP_BROWSER_TELL "display the currently selected file's name"
+OP_BROWSER_SUBSCRIBE "subscribe to current mailbox (IMAP Only)"
+OP_BROWSER_UNSUBSCRIBE "unsubscribe to current mailbox (IMAP Only)"
+OP_BROWSER_TOGGLE_LSUB "toggle view all/subscribed mailboxes (IMAP Only)"
OP_CHANGE_DIRECTORY "change directories"
OP_CHECK_NEW "check mailboxes for new mail"
OP_COMPOSE_ATTACH_FILE "attach a file(s) to this message"
@@ -143,7 +146,7 @@ OP_TAG_SUBTHREAD "tag the current subthread"
OP_TAG_THREAD "tag the current thread"
OP_TOGGLE_NEW "toggle a message's 'new' flag"
OP_TOGGLE_WRITE "toggle whether the mailbox will be rewritten"
-OP_TOGGLE_MAILBOXES "toggle wether to browse mailboxes or all files"
+OP_TOGGLE_MAILBOXES "toggle whether to browse mailboxes or all files"
OP_TOP_PAGE "move to the top of the page"
OP_UNDELETE "undelete the current entry"
OP_UNDELETE_THREAD "undelete all messages in thread"
diff --git a/browser.c b/browser.c
index ae4a29d9..e6264561 100644
--- a/browser.c
+++ b/browser.c
@@ -23,6 +23,10 @@
#include "mapping.h"
#include "sort.h"
#include "mailbox.h"
+#include "browser.h"
+#ifdef USE_IMAP
+#include "imap.h"
+#endif
#include <stdlib.h>
#include <dirent.h>
@@ -33,23 +37,6 @@
#include <pwd.h>
#include <grp.h>
-struct folder_file
-{
- mode_t mode;
- time_t mtime;
- off_t size;
- char *name;
- char *desc;
- short tagged;
-};
-
-struct browser_state
-{
- struct folder_file *entry;
- short entrylen; /* number of real entries */
- short entrymax; /* max entry */
-};
-
static struct mapping_t FolderHelp[] = {
{ N_("Exit"), OP_EXIT },
{ N_("Chdir"), OP_CHANGE_DIRECTORY },
@@ -456,6 +443,12 @@ static void init_menu (struct browser_state *state, MUTTMENU *menu, char *title,
{
strfcpy (path, LastDir, sizeof (path));
mutt_pretty_mailbox (path);
+#ifdef USE_IMAP
+ if (state->imap_browse && option (OPTIMAPLSUB))
+ snprintf (title, titlelen, _("Subscribed [%s], File mask: %s"),
+ path, Mask.pattern);
+ else
+#endif
snprintf (title, titlelen, _("Directory [%s], File mask: %s"),
path, Mask.pattern);
}
@@ -491,6 +484,17 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
if (*f)
{
mutt_expand_path (f, flen);
+#ifdef USE_IMAP
+ if (mx_is_imap (f))
+ {
+ init_state (&state, NULL);
+ state.imap_browse = 1;
+ imap_init_browse (f, &state);
+ strfcpy (LastDir, f, sizeof (LastDir));
+ }
+ else
+ {
+#endif
for (i = mutt_strlen (f) - 1; i > 0 && f[i] != '/' ; i--);
if (i > 0)
{
@@ -520,9 +524,23 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
else
strfcpy (prefix, f + i + 1, sizeof (prefix));
killPrefix = 1;
+#ifdef USE_IMAP
+ }
+#endif
+ }
+ else
+ {
+ if (!LastDir[0])
+ strfcpy (LastDir, NONULL(Maildir), sizeof (LastDir));
+#ifdef USE_IMAP
+ if (!buffy && mx_is_imap (LastDir))
+ {
+ init_state (&state, NULL);
+ state.imap_browse = 1;
+ imap_init_browse (LastDir, &state);
+ }
+#endif
}
- else if (!LastDir[0])
- strfcpy (LastDir, NONULL(Maildir), sizeof (LastDir));
*f = 0;
@@ -531,7 +549,11 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
if (examine_mailboxes (NULL, &state) == -1)
return;
}
- else if (examine_directory (NULL, &state, LastDir, prefix) == -1)
+ else
+#ifdef USE_IMAP
+ if (!state.imap_browse)
+#endif
+ if (examine_directory (NULL, &state, LastDir, prefix) == -1)
return;
menu = mutt_new_menu ();
@@ -561,7 +583,11 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
if (S_ISDIR (state.entry[menu->current].mode) ||
(S_ISLNK (state.entry[menu->current].mode) &&
- link_is_dir (state.entry[menu->current].name)))
+ link_is_dir (state.entry[menu->current].name))
+#ifdef USE_IMAP
+ || state.entry[menu->current].notfolder
+#endif
+ )
{
/* make sure this isn't a MH or maildir mailbox */
if (buffy)
@@ -569,11 +595,21 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
strfcpy (buf, state.entry[menu->current].name, sizeof (buf));
mutt_expand_path (buf, sizeof (buf));
}
+#ifdef USE_IMAP
+ else if (state.imap_browse)
+ {
+ strfcpy (buf, state.entry[menu->current].name, sizeof (buf));
+ }
+#endif
else
snprintf (buf, sizeof (buf), "%s/%s", LastDir,
state.entry[menu->current].name);
- if (mx_get_magic (buf) <= 0)
+ if ((mx_get_magic (buf) <= 0)
+#ifdef USE_IMAP
+ || state.entry[menu->current].notfolder
+#endif
+ )
{
char OldLastDir[_POSIX_PATH_MAX];
@@ -604,6 +640,13 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
sprintf (LastDir, "%s", state.entry[menu->current].name);
mutt_expand_path (LastDir, sizeof (LastDir));
}
+#ifdef USE_IMAP
+ else if (state.imap_browse)
+ {
+ strfcpy (LastDir, state.entry[menu->current].name,
+ sizeof (LastDir));
+ }
+#endif
else
sprintf (LastDir + mutt_strlen (LastDir), "/%s",
state.entry[menu->current].name);
@@ -615,6 +658,16 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
killPrefix = 0;
}
buffy = 0;
+#ifdef USE_IMAP
+ if (state.imap_browse)
+ {
+ init_state (&state, NULL);
+ state.imap_browse = 1;
+ imap_init_browse (LastDir, &state);
+ menu->data = state.entry;
+ }
+ else
+#endif
if (examine_directory (menu, &state, LastDir, prefix) == -1)
{
/* try to restore the old values */
@@ -637,6 +690,12 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
strfcpy (f, state.entry[menu->current].name, flen);
mutt_expand_path (f, flen);
}
+#ifdef USE_IMAP
+ else if (state.imap_browse)
+ {
+ strfcpy (f, state.entry[menu->current].name, flen);
+ }
+#endif
else
snprintf (f, flen, "%s/%s", LastDir, state.entry[menu->current].name);
@@ -684,10 +743,35 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
if(state.entrylen)
mutt_message(state.entry[menu->current].name);
break;
+
+#ifdef USE_IMAP
+ case OP_BROWSER_SUBSCRIBE:
+ imap_subscribe (state.entry[menu->current].name, 1);
+ break;
+
+ case OP_BROWSER_UNSUBSCRIBE:
+ imap_subscribe (state.entry[menu->current].name, 0);
+ break;
+
+ case OP_BROWSER_TOGGLE_LSUB:
+ if (option (OPTIMAPLSUB))
+ {
+ unset_option (OPTIMAPLSUB);
+ }
+ else
+ {
+ set_option (OPTIMAPLSUB);
+ }
+ mutt_ungetch (0, OP_CHECK_NEW);
+ break;
+#endif
case OP_CHANGE_DIRECTORY:
strfcpy (buf, LastDir, sizeof (buf));
+#ifdef USE_IMAP
+ if (!state.imap_browse)
+#endif
{/* add '/' at the end of the directory name */
int len=mutt_strlen(LastDir);
if (sizeof (buf) > len)
@@ -699,6 +783,21 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
{
buffy = 0;
mutt_expand_path (buf, sizeof (buf));
+#ifdef USE_IMAP
+ if (mx_is_imap (buf))
+ {
+ strfcpy (LastDir, buf, sizeof (LastDir));
+ destroy_state (&state);
+ init_state (&state, NULL);
+ state.imap_browse = 1;
+ imap_init_browse (LastDir, &state);
+ menu->data = state.entry;
+ menu->current = 0;
+ menu->top = 0;
+ init_menu (&state, menu, title, sizeof (title), buffy);
+ }
+ else
+#endif
if (stat (buf, &st) == 0)
{
if (S_ISDIR (st.st_mode))
@@ -834,11 +933,21 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
destroy_state (&state);
prefix[0] = 0;
killPrefix = 0;
+
if (buffy)
{
if (examine_mailboxes (menu, &state) == -1)
return;
}
+#ifdef USE_IMAP
+ else if (mx_is_imap (LastDir))
+ {
+ init_state (&state, NULL);
+ state.imap_browse = 1;
+ imap_init_browse (LastDir, &state);
+ menu->data = state.entry;
+ }
+#endif
else if (examine_directory (menu, &state, LastDir, prefix) == -1)
return;
init_menu (&state, menu, title, sizeof (title), buffy);
diff --git a/browser.h b/browser.h
new file mode 100644
index 00000000..b19fb5b4
--- /dev/null
+++ b/browser.h
@@ -0,0 +1,48 @@
+/* $Id$ */
+/*
+ * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _BROWSER_H
+#define _BROWSER_H 1
+
+struct folder_file
+{
+ mode_t mode;
+ time_t mtime;
+ off_t size;
+ char *name;
+ char *desc;
+#ifdef USE_IMAP
+ short notfolder;
+#endif
+};
+
+struct browser_state
+{
+ struct folder_file *entry;
+ short entrylen; /* number of real entries */
+ short entrymax; /* max entry */
+#ifdef USE_IMAP
+ short imap_browse;
+ int noselect : 1;
+ int marked : 1;
+ int unmarked : 1;
+#endif
+};
+
+#endif /* _BROWSER_H */
diff --git a/complete.c b/complete.c
index f8d708f5..f3f58f57 100644
--- a/complete.c
+++ b/complete.c
@@ -32,7 +32,7 @@
int mutt_complete (char *s)
{
char *p;
- DIR *dirp;
+ DIR *dirp = NULL;
struct dirent *de;
int i ,init=0;
size_t len;
@@ -85,12 +85,23 @@ int mutt_complete (char *s)
/* no directory name, so assume current directory. */
dirpart[0] = 0;
strfcpy (filepart, s, sizeof (filepart));
- dirp = opendir (".");
+#ifdef USE_IMAP
+ if (s[0] != '{')
+#endif
+ dirp = opendir (".");
}
}
if (dirp == NULL)
{
+#ifdef USE_IMAP
+ /* If we are trying to complete an IMAP folder, it will start with {
+ * in which case, we just return 0 at this point. Eventually, we
+ * might complete the actually folder name from the server
+ */
+ if ((s[0] == '{') || (exp_dirpart[0] == '{'))
+ return 0;
+#endif
dprint (1, (debugfile, "mutt_complete(): %s: %s (errno %d).\n", exp_dirpart, strerror (errno), errno));
return (-1);
}
diff --git a/doc/manual.sgml.in b/doc/manual.sgml.in
index d49d1337..7ddcdb3f 100644
--- a/doc/manual.sgml.in
+++ b/doc/manual.sgml.in
@@ -1811,7 +1811,7 @@ url="http://www.ccil.org/~esr/fetchmail" name="fetchmail">
If Mutt was compiled with IMAP support (by running the <em/configure/
script with the <em/--enable-imap/ flag), it has the ability to work
-with folders located on a remote imap server.
+with folders located on a remote IMAP server.
You can access the remote inbox by selecting the folder
<tt/{imapserver}inbox/, where <tt/imapserver/ is the name of the IMAP
@@ -1821,8 +1821,30 @@ server, you should use <tt>{imapserver}path/to/folder</tt> where
<tt>path/to/folder</tt> is the path of the folder you want to access
relative to your home directory.
-<bf/Note:/ The IMAP support is in a very early state and quite
-unstable at the moment. If you need a more stable way to access your
+You can select an alternative port by specifying it with the server, ie:
+<tt/{imapserver:port}inbox/.
+
+Note that not all servers use / as the hierarchy separator. Mutt should
+correctly notice which separator is being used by the server and convert
+paths accordingly.
+
+When browsing folders on an IMAP server, you can toggle whether to look
+at only the folders you are subscribed to, or all folders with the
+<em/toggle-subscribed/ command. See also the
+<ref id="imap&lowbar;list&lowbar;subscribed" name="&dollar;imap&lowbar;list&lowbar;subscribed"> variable.
+
+Mutt was designed to work with IMAP4rev1 servers, and has been tested
+with both the UWash IMAP server v11.241 and the Cyrus IMAP server v1.5.14.
+Note that if you are using mbox as the mail store on the UWash server,
+the server will disconnect a client if another client selects the same
+folder.
+
+Mutt currently does not support completion of IMAP folder names. Hit
+the <em/complete/ key again to go to the IMAP browser.
+
+<bf/Note:/ The IMAP support has had very limited testing due to a lack
+of developers using it. It should work with the reference servers
+mentioned above, but if you need a more stable way to access your
IMAP folder, consider using a specialized program, such as <htmlurl
url="http://www.ccil.org/~esr/fetchmail" name="fetchmail">.
@@ -2953,6 +2975,15 @@ Default: 0
This variable configures how often (in seconds) IMAP should look for
new mail.
+<sect2>imap&lowbar;list&lowbar;subscribed<label id="imap_list_subscribed">
+<p>
+Type: boolean<newline>
+Default: unset
+
+This variable configures whether IMAP folder browsing will look for only
+subscribed folders or all folders. This can be toggled in the IMAP
+browser with the <em/toggle-subscribed/ command.
+
<sect2>imap&lowbar;pass<label id="imap_pass">
<p>
Type: string<newline>
@@ -2964,6 +2995,16 @@ you should only use this option when you are on a fairly secure machine,
because the superuser can read your muttrc even if you are the only one who
can read the file.
+<sect2>imap&lowbar;passive<label id="imap_passive">
+<p>
+Type: boolean<newline>
+Default: set
+
+When set, mutt will not open new IMAP connections to check for new mail.
+Mutt will only check for new mail over existing IMAP connections. This
+is useful if you don't want to be prompted to user/password pairs on
+mutt invocation, or if opening the connection is slow.
+
<sect2>imap&lowbar;user<label id="imap_user">
<p>
Type: string<newline>
@@ -4604,6 +4645,11 @@ search-reverse ESC / search backwards for a regular expression
select-new N select a new file in this directory
sort o sort messages
sort-reverse O sort messages in reverse order
+toggle-mailboxes TAB toggle whether to browse mailboxes or all files
+view-file SPACE view file
+subscribe s subscribe to current mailbox (IMAP Only)
+unsubscribe u unsubscribe to current mailbox (IMAP Only)
+toggle-subscribed T toggle view all/subscribed mailboxes (IMAP Only)
</verb>
<sect2>pgp
<p>
diff --git a/functions.h b/functions.h
index 125dedcf..4b5ec6c3 100644
--- a/functions.h
+++ b/functions.h
@@ -323,6 +323,11 @@ struct binding_t OpBrowser[] = {
{ "check-new", OP_CHECK_NEW, NULL },
{ "toggle-mailboxes", OP_TOGGLE_MAILBOXES, "\t" },
{ "view-file", OP_BROWSER_VIEW_FILE, " " },
+#ifdef USE_IMAP
+ { "subscribe", OP_BROWSER_SUBSCRIBE, "s" },
+ { "unsubscribe", OP_BROWSER_UNSUBSCRIBE, "u" },
+ { "toggle-subscribed", OP_BROWSER_TOGGLE_LSUB, "T" },
+#endif
{ NULL, 0, NULL }
};
diff --git a/imap.c b/imap.c
index 92ac8e2a..b45b8b03 100644
--- a/imap.c
+++ b/imap.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
+ * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +24,7 @@
#include "globals.h"
#include "mutt_socket.h"
#include "sort.h"
+#include "browser.h"
#include <unistd.h>
#include <netinet/in.h>
@@ -65,6 +67,15 @@ enum
IMAP_OK_FAIL
};
+enum
+{
+ /* States */
+ IMAP_DISCONNECTED = 0,
+ IMAP_CONNECTED,
+ IMAP_AUTHENTICATED,
+ IMAP_SELECTED
+};
+
typedef struct
{
unsigned int index;
@@ -73,15 +84,21 @@ typedef struct
typedef struct
{
+ /* This data is specific to a CONNECTION to an IMAP server */
short status;
- unsigned short newMailCount;
- char *mailbox;
- short xxx;
- IMAP_CACHE cache[IMAP_CACHE_LEN];
+ short state;
+ char delim;
CONNECTION *conn;
+
+ /* The following data is all specific to the currently SELECTED mbox */
+ CONTEXT *selected_ctx;
+ char *selected_mailbox;
+ unsigned int newMailCount;
+ IMAP_CACHE cache[IMAP_CACHE_LEN];
} IMAP_DATA;
#define CTX_DATA ((IMAP_DATA *) ctx->data)
+#define CONN_DATA ((IMAP_DATA *) conn->data)
#define SELCTX_DATA ((IMAP_DATA *) selctx->data)
/* Linked list to hold header information while downloading message
@@ -102,14 +119,15 @@ typedef struct imap_header_info
struct imap_header_info *next;
} IMAP_HEADER_INFO;
-
static void imap_make_sequence (char *buf, size_t buflen)
{
static int sequence = 0;
snprintf (buf, buflen, "a%04d", sequence++);
-}
+ if (sequence > 9999)
+ sequence = 0;
+}
static void imap_error (const char *where, const char *msg)
{
@@ -307,6 +325,36 @@ static void imap_quote_string (char *dest, size_t slen, const char *src)
*pt = 0;
}
+static void imap_unquote_string (char *s)
+{
+ char *d = s;
+
+ if (*s == '\"')
+ s++;
+ else
+ return;
+
+ while (*s)
+ {
+ if (*s == '\"')
+ {
+ *d = '\0';
+ return;
+ }
+ if (*s == '\\')
+ {
+ s++;
+ }
+ if (*s)
+ {
+ *d = *s;
+ d++;
+ s++;
+ }
+ }
+ *d = '\0';
+}
+
static int imap_read_bytes (FILE *fp, CONNECTION *conn, long bytes)
{
long pos;
@@ -342,15 +390,14 @@ static char *imap_next_word (char *s)
return s;
}
-static int imap_handle_untagged (CONTEXT *ctx, char *s)
+static int imap_handle_untagged (IMAP_DATA *idata, char *s)
{
char *pn;
int count;
- CONTEXT *selctx = (CONTEXT *)(CTX_DATA->conn->data);
s = imap_next_word (s);
- if (isdigit (*s))
+ if ((idata->state == IMAP_SELECTED) && isdigit (*s))
{
pn = s;
s = imap_next_word (s);
@@ -363,30 +410,27 @@ static int imap_handle_untagged (CONTEXT *ctx, char *s)
/* new mail arrived */
count = atoi (pn);
- if ( (SELCTX_DATA->status != IMAP_EXPUNGE) &&
- count < selctx->msgcount)
+ if ( (idata->status != IMAP_EXPUNGE) &&
+ count < idata->selected_ctx->msgcount)
{
/* something is wrong because the server reported fewer messages
* than we previously saw
*/
mutt_error _("Fatal error. Message count is out of sync!");
- SELCTX_DATA->status = IMAP_FATAL;
- CTX_DATA->status = IMAP_FATAL;
- mx_fastclose_mailbox (ctx);
- if (ctx != selctx)
- mx_fastclose_mailbox (selctx);
+ idata->status = IMAP_FATAL;
+ mx_fastclose_mailbox (idata->selected_ctx);
return (-1);
}
else
{
- if (SELCTX_DATA->status != IMAP_EXPUNGE)
- SELCTX_DATA->status = IMAP_NEW_MAIL;
- SELCTX_DATA->newMailCount = count;
+ if (idata->status != IMAP_EXPUNGE)
+ idata->status = IMAP_NEW_MAIL;
+ idata->newMailCount = count;
}
}
else if (mutt_strncasecmp ("EXPUNGE", s, 7) == 0)
{
- SELCTX_DATA->status = IMAP_EXPUNGE;
+ idata->status = IMAP_EXPUNGE;
}
}
else if (mutt_strncasecmp ("BYE", s, 3) == 0)
@@ -395,11 +439,9 @@ static int imap_handle_untagged (CONTEXT *ctx, char *s)
s += 3;
SKIPWS (s);
mutt_error (s);
- SELCTX_DATA->status = IMAP_BYE;
- CTX_DATA->status = IMAP_BYE;
- mx_fastclose_mailbox (ctx);
- if (ctx != selctx)
- mx_fastclose_mailbox (selctx);
+ idata->status = IMAP_BYE;
+ if (idata->state == IMAP_SELECTED)
+ mx_fastclose_mailbox (idata->selected_ctx);
return (-1);
}
else
@@ -515,7 +557,7 @@ static int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
pc = buf;
}
}
- else if (imap_handle_untagged (ctx, buf) != 0)
+ else if (imap_handle_untagged (CTX_DATA, buf) != 0)
return (-1);
}
}
@@ -643,8 +685,8 @@ static int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint)
ctx->id_hash = hash_create (1031);
ctx->subj_hash = hash_create (1031);
- mutt_message (_("Reopening mailbox..."), CTX_DATA->mailbox);
- imap_quote_string (buf, sizeof(buf), CTX_DATA->mailbox);
+ mutt_message (_("Reopening mailbox... %s"), CTX_DATA->selected_mailbox);
+ imap_quote_string (buf, sizeof(buf), CTX_DATA->selected_mailbox);
imap_make_sequence (seq, sizeof (seq));
snprintf (bufout, sizeof (bufout), "%s SELECT %s\r\n", seq, buf);
mutt_socket_write (CTX_DATA->conn, bufout);
@@ -670,12 +712,23 @@ static int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint)
if (mutt_strncasecmp ("EXISTS", pc, 6) == 0)
count = n;
}
- else if (imap_handle_untagged (ctx, buf) != 0)
+ else if (imap_handle_untagged (CTX_DATA, buf) != 0)
return (-1);
}
}
while (mutt_strncmp (seq, buf, mutt_strlen (seq)) != 0);
+ if (!imap_code (buf))
+ {
+ char *s;
+ s = imap_next_word (buf); /* skip seq */
+ s = imap_next_word (s); /* Skip response */
+ CTX_DATA->state = IMAP_AUTHENTICATED;
+ mutt_error (s);
+ sleep (1);
+ return (-1);
+ }
+
ctx->hdrmax = count;
ctx->hdrs = safe_malloc (count * sizeof (HEADER *));
ctx->v2r = safe_malloc (count * sizeof (int));
@@ -768,47 +821,48 @@ static int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint)
* failing, this is used for checking for a mailbox on append and login
* Return 0 on success, -1 on Failure, -2 on OK Failure
*/
-static int imap_exec (char *buf, size_t buflen,
- CONTEXT *ctx, const char *seq, const char *cmd, int flags)
+static int imap_exec (char *buf, size_t buflen, IMAP_DATA *idata,
+ const char *seq, const char *cmd, int flags)
{
int count;
- CONTEXT *selctx = (CONTEXT *)(CTX_DATA->conn->data);
- mutt_socket_write (CTX_DATA->conn, cmd);
+ mutt_socket_write (idata->conn, cmd);
do
{
- if (mutt_socket_read_line_d (buf, buflen, CTX_DATA->conn) < 0)
+ if (mutt_socket_read_line_d (buf, buflen, idata->conn) < 0)
return (-1);
- if (buf[0] == '*' && imap_handle_untagged (ctx, buf) != 0)
+ if (buf[0] == '*' && imap_handle_untagged (idata, buf) != 0)
return (-1);
}
while (mutt_strncmp (buf, seq, SEQLEN) != 0);
- if (!selctx->closing &&
- (SELCTX_DATA->status == IMAP_NEW_MAIL ||
- SELCTX_DATA->status == IMAP_EXPUNGE))
+ if ((idata->state == IMAP_SELECTED) &&
+ !idata->selected_ctx->closing &&
+ (idata->status == IMAP_NEW_MAIL ||
+ idata->status == IMAP_EXPUNGE))
{
- count = SELCTX_DATA->newMailCount;
+ count = idata->newMailCount;
- if (SELCTX_DATA->status == IMAP_NEW_MAIL && count > selctx->msgcount)
+ if (idata->status == IMAP_NEW_MAIL && count > idata->selected_ctx->msgcount)
{
/* read new mail messages */
dprint (1, (debugfile, "imap_exec(): new mail detected\n"));
- while (count > selctx->hdrmax)
- mx_alloc_memory (selctx);
+ while (count > idata->selected_ctx->hdrmax)
+ mx_alloc_memory (idata->selected_ctx);
- count = imap_read_headers (selctx, selctx->msgcount, count - 1) + 1;
+ count = imap_read_headers (idata->selected_ctx,
+ idata->selected_ctx->msgcount, count - 1) + 1;
}
else
{
- imap_reopen_mailbox (selctx, NULL);
+ imap_reopen_mailbox (idata->selected_ctx, NULL);
}
- SELCTX_DATA->status = 0;
+ idata->status = 0;
mutt_clear_error ();
}
@@ -831,153 +885,240 @@ static int imap_exec (char *buf, size_t buflen,
return 0;
}
-static int imap_parse_path (char *path, char *host, size_t hlen, char **mbox)
+static int imap_get_delim (IMAP_DATA *idata, CONNECTION *conn)
+{
+ char buf[LONG_STRING];
+ char seq[8];
+ char *s;
+
+ /* assume that the delim is /. If this fails, we're in bigger trouble
+ * than getting the delim wrong */
+ idata->delim = '/';
+
+ imap_make_sequence (seq, sizeof (seq));
+ snprintf (buf, sizeof (buf), "%s LIST \"\" \"\"\r\n", seq);
+
+ mutt_socket_write (conn, buf);
+
+ do
+ {
+ if (mutt_socket_read_line_d (buf, sizeof (buf), conn) < 0)
+ {
+ return (-1);
+ }
+
+ if (buf[0] == '*')
+ {
+ s = imap_next_word (buf);
+ if (mutt_strncasecmp ("LIST", s, 4) == 0)
+ {
+ s = imap_next_word (s);
+ s = imap_next_word (s);
+ if (s && s[0] == '\"' && s[1] && s[2] == '\"')
+ idata->delim = s[1];
+ else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
+ idata->delim = s[2];
+ }
+ else
+ {
+ if (conn->data &&
+ imap_handle_untagged (idata, buf) != 0)
+ return (-1);
+ }
+ }
+ }
+ while ((mutt_strncmp (buf, seq, SEQLEN) != 0));
+ return 0;
+}
+
+static int imap_parse_path (char *path, char *host, size_t hlen, int *port,
+ char **mbox)
{
int n;
char *pc;
+ char *pt;
+ /* set default port */
+ *port = IMAP_PORT;
pc = path;
if (*pc != '{')
return (-1);
pc++;
n = 0;
- while (*pc && *pc != '}' && (n < hlen-1))
+ while (*pc && *pc != '}' && *pc != ':' && (n < hlen-1))
host[n++] = *pc++;
host[n] = 0;
if (!*pc)
return (-1);
+ if (*pc == ':')
+ {
+ pc++;
+ pt = pc;
+ while (*pc && *pc != '}') pc++;
+ if (!*pc)
+ return (-1);
+ *pc = '\0';
+ *port = atoi (pt);
+ *pc = '}';
+ }
pc++;
*mbox = pc;
return 0;
}
-static int imap_open_connection (CONTEXT *ctx, CONNECTION *conn)
+/*
+ * Fix up the imap path. This is necessary because the rest of mutt
+ * assumes a hierarchy delimiter of '/', which is not necessarily true
+ * in IMAP. Additionally, the filesystem converts multiple hierarchy
+ * delimiters into a single one, ie "///" is equal to "/". IMAP servers
+ * are not required to do this.
+ */
+static char *imap_fix_path (IMAP_DATA *idata, char *mailbox, char *path,
+ size_t plen)
+{
+ int x = 0;
+
+ if (!mailbox || !*mailbox)
+ {
+ strfcpy (path, "INBOX", plen);
+ return path;
+ }
+
+ while (mailbox && *mailbox && (x < (plen - 1)))
+ {
+ if ((*mailbox == '/') || (*mailbox == idata->delim))
+ {
+ while ((*mailbox == '/') || (*mailbox == idata->delim)) mailbox++;
+ path[x] = idata->delim;
+ }
+ else
+ {
+ path[x] = *mailbox;
+ mailbox++;
+ }
+ x++;
+ }
+ path[x] = '\0';
+ return path;
+}
+
+static int imap_authenticate (IMAP_DATA *idata, CONNECTION *conn)
{
- char *portnum, *hostname;
- struct sockaddr_in sin;
- struct hostent *he;
char buf[LONG_STRING];
char user[SHORT_STRING], q_user[SHORT_STRING];
char pass[SHORT_STRING], q_pass[SHORT_STRING];
char seq[16];
- memset (&sin, 0, sizeof (sin));
- hostname = safe_strdup (conn->server);
- portnum = strrchr (hostname, ':');
- if (portnum)
- {
- *portnum=0;
- portnum++;
- }
- sin.sin_port = htons (portnum ? atoi(portnum) : IMAP_PORT);
- sin.sin_family = AF_INET;
- if ((he = gethostbyname (hostname)) == NULL)
- {
- safe_free ((void*)&hostname);
- mutt_perror (conn->server);
- return (-1);
- }
- safe_free ((void*)&hostname);
- memcpy (&sin.sin_addr, he->h_addr_list[0], he->h_length);
+ int r = 1;
- if ((conn->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0)
+ while (r != 0)
{
- mutt_perror ("socket");
- return (-1);
+ if (!ImapUser)
+ {
+ strfcpy (user, NONULL(Username), sizeof (user));
+ if (mutt_get_field (_("IMAP Username: "), user, sizeof (user), 0) != 0 ||
+ !user[0])
+ {
+ user[0] = 0;
+ return (-1);
+ }
+ }
+ else
+ strfcpy (user, ImapUser, sizeof (user));
+
+ if (!ImapPass)
+ {
+ pass[0]=0;
+ snprintf (buf, sizeof (buf), _("Password for %s@%s: "), user, conn->server);
+ if (mutt_get_field (buf, pass, sizeof (pass), M_PASS) != 0 ||
+ !pass[0])
+ {
+ return (-1);
+ }
+ }
+ else
+ strfcpy (pass, ImapPass, sizeof (pass));
+
+ imap_quote_string (q_user, sizeof (q_user), user);
+ imap_quote_string (q_pass, sizeof (q_pass), pass);
+
+ mutt_message _("Logging in...");
+ imap_make_sequence (seq, sizeof (seq));
+ snprintf (buf, sizeof (buf), "%s LOGIN %s %s\r\n", seq, q_user, q_pass);
+ r = imap_exec (buf, sizeof (buf), idata, seq, buf, IMAP_OK_FAIL);
+ if (r == -1)
+ {
+ /* connection or protocol problem */
+ imap_error ("imap_open_connection()", buf);
+ return (-1);
+ }
+ else if (r == -2)
+ {
+ /* Login failed, try again */
+ mutt_error _("Login failed.");
+ sleep (1);
+ FREE (&ImapUser);
+ FREE (&ImapPass);
+ }
+ else
+ {
+ /* If they have a successful login, we may as well cache the
+ * user/password. */
+ if (!ImapUser)
+ ImapUser = safe_strdup (user);
+ if (!ImapPass)
+ ImapPass = safe_strdup (pass);
+ }
}
+ return 0;
+}
- mutt_message (_("Connecting to %s..."), conn->server);
+static int imap_open_connection (IMAP_DATA *idata, CONNECTION *conn)
+{
+ char buf[LONG_STRING];