summaryrefslogtreecommitdiffstats
path: root/imap
diff options
context:
space:
mode:
authorThomas Roessler <roessler@does-not-exist.org>2000-08-05 17:50:01 +0000
committerThomas Roessler <roessler@does-not-exist.org>2000-08-05 17:50:01 +0000
commitfa002c59576b77da5ec933e61c15c4b5109c6bc4 (patch)
tree0d2b688f78327fc04cd6363f194c6ed8de798ffc /imap
parent661ac8a44b29182ec42f768fc42496cdca5a6c6b (diff)
Unified IMAP command code.
Diffstat (limited to 'imap')
-rw-r--r--imap/Makefile.am4
-rw-r--r--imap/auth_anon.c24
-rw-r--r--imap/auth_cram.c23
-rw-r--r--imap/auth_gss.c39
-rw-r--r--imap/auth_login.c5
-rw-r--r--imap/auth_sasl.c28
-rw-r--r--imap/browse.c174
-rw-r--r--imap/command.c111
-rw-r--r--imap/imap.c358
-rw-r--r--imap/imap_private.h19
-rw-r--r--imap/message.c376
11 files changed, 603 insertions, 558 deletions
diff --git a/imap/Makefile.am b/imap/Makefile.am
index 9f5a6fa7..c049fae0 100644
--- a/imap/Makefile.am
+++ b/imap/Makefile.am
@@ -9,7 +9,7 @@ endif
if USE_SASL
SASLSOURCES = auth_sasl.c
else
-CRAMSOURCES = auth_cram.c
+CRAMSOURCES = auth_cram.c md5c.c
endif
if USE_SSL
@@ -25,5 +25,5 @@ noinst_LIBRARIES = libimap.a
noinst_HEADERS = auth.h imap_private.h md5.h message.h $(SSLHEADERS)
libimap_a_SOURCES = auth.c auth_anon.c auth_login.c browse.c \
- command.c imap.c imap.h md5c.c message.c utf7.c \
+ command.c imap.c imap.h message.c utf7.c \
util.c $(GSSSOURCES) $(SASLSOURCES) $(CRAMSOURCES) $(SSLSOURCES)
diff --git a/imap/auth_anon.c b/imap/auth_anon.c
index 09ec71db..a7fd87ff 100644
--- a/imap/auth_anon.c
+++ b/imap/auth_anon.c
@@ -25,7 +25,7 @@
/* this is basically a stripped-down version of the cram-md5 method. */
imap_auth_res_t imap_auth_anon (IMAP_DATA* idata)
{
- char buf[LONG_STRING];
+ int rc;
if (!mutt_bit_isset (idata->capabilities, AUTH_ANON))
return IMAP_AUTH_UNAVAIL;
@@ -40,29 +40,29 @@ imap_auth_res_t imap_auth_anon (IMAP_DATA* idata)
imap_cmd_start (idata, "AUTHENTICATE ANONYMOUS");
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- {
- dprint (1, (debugfile, "Error receiving server response.\n"));
- goto bail;
- }
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
- if (buf[0] != '+')
+ if (rc != IMAP_CMD_RESPOND)
{
dprint (1, (debugfile, "Invalid response from server.\n"));
goto bail;
}
- strfcpy (buf, "ZHVtbXkK\r\n", sizeof (buf)); /* base64 ("dummy") */
-
- mutt_socket_write (idata->conn, buf);
+ mutt_socket_write (idata->conn, "ZHVtbXkK\r\n"); /* base64 ("dummy") */
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_DONE)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
goto bail;
}
- if (imap_code (buf))
+ if (imap_code (idata->buf))
return IMAP_AUTH_SUCCESS;
bail:
diff --git a/imap/auth_cram.c b/imap/auth_cram.c
index 9736ee36..00e0f0d9 100644
--- a/imap/auth_cram.c
+++ b/imap/auth_cram.c
@@ -36,6 +36,7 @@ imap_auth_res_t imap_auth_cram_md5 (IMAP_DATA* idata)
char ibuf[LONG_STRING], obuf[LONG_STRING];
unsigned char hmac_response[MD5_DIGEST_LEN];
int len;
+ int rc;
if (!mutt_bit_isset (idata->capabilities, ACRAM_MD5))
return IMAP_AUTH_UNAVAIL;
@@ -56,19 +57,17 @@ imap_auth_res_t imap_auth_cram_md5 (IMAP_DATA* idata)
* primary host name of the server. The syntax of the unencoded form must
* correspond to that of an RFC 822 'msg-id' [RFC822] as described in [POP3].
*/
- if (mutt_socket_readln (ibuf, sizeof (ibuf), idata->conn) < 0)
- {
- dprint (1, (debugfile, "Error receiving server response.\n"));
- goto bail;
- }
-
- if (ibuf[0] != '+')
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_RESPOND)
{
dprint (1, (debugfile, "Invalid response from server: %s\n", ibuf));
goto bail;
}
- if ((len = mutt_from_base64 (obuf, ibuf + 2)) == -1)
+ if ((len = mutt_from_base64 (obuf, idata->buf + 2)) == -1)
{
dprint (1, (debugfile, "Error decoding base64 response.\n"));
goto bail;
@@ -103,13 +102,17 @@ imap_auth_res_t imap_auth_cram_md5 (IMAP_DATA* idata)
strcpy (ibuf + strlen (ibuf), "\r\n");
mutt_socket_write (idata->conn, ibuf);
- if (mutt_socket_readln (ibuf, LONG_STRING, idata->conn) < 0)
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_DONE)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
goto bail;
}
- if (imap_code (ibuf))
+ if (imap_code (idata->buf))
return IMAP_AUTH_SUCCESS;
bail:
diff --git a/imap/auth_gss.c b/imap/auth_gss.c
index 96f79b56..bf59c019 100644
--- a/imap/auth_gss.c
+++ b/imap/auth_gss.c
@@ -54,6 +54,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
OM_uint32 maj_stat, min_stat;
char buf1[GSS_BUFSIZE], buf2[GSS_BUFSIZE], server_conf_flags;
unsigned long buf_size;
+ int rc;
if (!mutt_bit_isset (idata->capabilities, AGSSAPI))
return IMAP_AUTH_UNAVAIL;
@@ -88,14 +89,11 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
imap_cmd_start (idata, "AUTHENTICATE GSSAPI");
/* expect a null continuation response ("+") */
- if (mutt_socket_readln (buf1, sizeof (buf1), idata->conn) < 0)
- {
- dprint (1, (debugfile, "Error receiving server response.\n"));
- gss_release_name (&min_stat, &target_name);
- goto bail;
- }
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
- if (buf1[0] != '+')
+ if (rc != IMAP_CMD_RESPOND)
{
dprint (2, (debugfile, "Invalid response from server: %s\n", buf1));
gss_release_name (&min_stat, &target_name);
@@ -128,7 +126,9 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
gss_release_name (&min_stat, &target_name);
/* end authentication attempt */
mutt_socket_write (idata->conn, "*\r\n");
- mutt_socket_readln (buf1, sizeof (buf1), idata->conn);
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
goto bail;
}
@@ -141,14 +141,18 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
if (maj_stat == GSS_S_CONTINUE_NEEDED)
{
- if (mutt_socket_readln (buf1, sizeof (buf1), idata->conn) < 0)
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_RESPOND)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
gss_release_name (&min_stat, &target_name);
goto bail;
}
- request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
+ request_buf.length = mutt_from_base64 (buf2, idata->buf + 2);
request_buf.value = buf2;
sec_token = &request_buf;
}
@@ -158,12 +162,16 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
gss_release_name (&min_stat, &target_name);
/* get security flags and buffer size */
- if (mutt_socket_readln (buf1, sizeof (buf1), idata->conn) < 0)
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_RESPOND)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
goto bail;
}
- request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
+ request_buf.length = mutt_from_base64 (buf2, idata->buf + 2);
request_buf.value = buf2;
maj_stat = gss_unwrap (&min_stat, context, &request_buf, &send_token,
@@ -221,13 +229,16 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
mutt_socket_write (idata->conn, buf1);
/* Joy of victory or agony of defeat? */
- if (mutt_socket_readln (buf1, GSS_BUFSIZE, idata->conn) < 0)
+ do
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
+ if (rc != IMAP_CMD_DONE)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
mutt_socket_write(idata->conn, "*\r\n");
goto bail;
}
- if (imap_code (buf1))
+ if (imap_code (idata->buf))
{
/* flush the security context */
dprint (2, (debugfile, "Releasing GSS credentials\n"));
diff --git a/imap/auth_login.c b/imap/auth_login.c
index 757c3538..731f14f3 100644
--- a/imap/auth_login.c
+++ b/imap/auth_login.c
@@ -26,7 +26,7 @@
imap_auth_res_t imap_auth_login (IMAP_DATA* idata)
{
char q_user[SHORT_STRING], q_pass[SHORT_STRING];
- char buf[LONG_STRING];
+ char buf[STRING];
int rc;
if (mutt_account_getuser (&idata->conn->account))
@@ -49,8 +49,7 @@ imap_auth_res_t imap_auth_login (IMAP_DATA* idata)
#endif
snprintf (buf, sizeof (buf), "LOGIN %s %s", q_user, q_pass);
- rc = imap_exec (buf, sizeof (buf), idata, buf,
- IMAP_CMD_FAIL_OK | IMAP_CMD_PASS);
+ rc = imap_exec (idata, buf, IMAP_CMD_FAIL_OK | IMAP_CMD_PASS);
if (!rc)
return IMAP_AUTH_SUCCESS;
diff --git a/imap/auth_sasl.c b/imap/auth_sasl.c
index 946500ec..5e01331b 100644
--- a/imap/auth_sasl.c
+++ b/imap/auth_sasl.c
@@ -31,7 +31,7 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
{
sasl_conn_t* saslconn;
sasl_interact_t* interaction = NULL;
- int rc;
+ int rc, irc;
char buf[LONG_STRING];
const char* mech;
char* pc;
@@ -92,27 +92,27 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
snprintf (buf, sizeof (buf), "AUTHENTICATE %s", mech);
imap_cmd_start (idata, buf);
+ irc = IMAP_CMD_CONTINUE;
/* looping protocol */
while (rc == SASL_CONTINUE)
{
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+ do
+ irc = imap_cmd_resp (idata);
+ while (irc == IMAP_CMD_CONTINUE);
+
+ if (irc == IMAP_CMD_FAIL)
goto bail;
- if (!mutt_strncmp (buf, "+ ", 2))
+ if (irc == IMAP_CMD_RESPOND)
{
- if (sasl_decode64 (buf+2, strlen (buf+2), buf, &len) != SASL_OK)
+ if (sasl_decode64 (idata->buf+2, strlen (idata->buf+2), buf, &len) !=
+ SASL_OK)
{
dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n"));
goto bail;
}
}
- else if ((buf[0] == '*'))
- {
- if (imap_handle_untagged (idata, buf))
- goto bail;
- else continue;
- }
if (!client_start)
do
@@ -146,14 +146,14 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
}
}
- while (mutt_strncmp (buf, idata->seq, SEQLEN))
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- goto bail;
+ while (irc != IMAP_CMD_DONE)
+ if ((irc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+ break;
if (rc != SASL_OK)
goto bail;
- if (imap_code (buf))
+ if (imap_code (idata->buf))
{
mutt_sasl_setup_conn (idata->conn, saslconn);
return IMAP_AUTH_SUCCESS;
diff --git a/imap/browse.c b/imap/browse.c
index c63487ee..1571a705 100644
--- a/imap/browse.c
+++ b/imap/browse.c
@@ -36,10 +36,11 @@ static int browse_get_namespace (IMAP_DATA *idata, char *nsbuf, int nsblen,
static int browse_verify_namespace (IMAP_DATA* idata,
IMAP_NAMESPACE_INFO* nsi, int nns);
+/* imap_browse: IMAP hook into the folder browser, fills out browser_state,
+ * given a current folder to browse */
int imap_browse (char* path, struct browser_state* state)
{
- CONNECTION *conn;
- IMAP_DATA *idata;
+ IMAP_DATA* idata;
char buf[LONG_STRING];
char nsbuf[LONG_STRING];
char mbox[LONG_STRING];
@@ -67,7 +68,6 @@ int imap_browse (char* path, struct browser_state* state)
if (!(idata = imap_conn_find (&(mx.account), 0)))
return -1;
- conn = idata->conn;
if (mx.mbox[0] == '\0')
{
@@ -84,24 +84,6 @@ int imap_browse (char* path, struct browser_state* state)
if (browse_verify_namespace (idata, nsi, nns) != 0)
return -1;
}
- /* What if you have a shared namespace of ""? You'll never be
- * able to browse it. This isn't conjecture: connect to the Cyrus
- * reference server (cyrus.andrew.cmu.edu) as anonymous. argh! */
-#if 0
- if (!mx.mbox) /* Any explicitly set imap_home_namespace wins */
- {
- for (i = 0; i < nns; i++)
- if (nsi[i].listable &&
- (nsi[i].type == IMAP_NS_PERSONAL || nsi[i].type == IMAP_NS_SHARED))
- {
- mx.mbox = nsi->prefix;
- nsi->home_namespace = 1;
- break;
- }
- }
- else
- dprint (4, (debugfile, "Home namespace: %s\n", mx.mbox));
-#endif
}
mutt_message _("Getting folder list...");
@@ -116,7 +98,7 @@ int imap_browse (char* path, struct browser_state* state)
strncpy (mbox, buf, sizeof (mbox) - 1);
n = mutt_strlen (mbox);
- dprint (3, (debugfile, "imap_init_browse: mbox: %s\n", mbox));
+ dprint (3, (debugfile, "imap_browse: mbox: %s\n", mbox));
/* if our target exists and has inferiors, enter it if we
* aren't already going to */
@@ -126,8 +108,8 @@ int imap_browse (char* path, struct browser_state* state)
imap_cmd_start (idata, buf);
do
{
- if (imap_parse_list_response(idata, buf, sizeof(buf), &cur_folder,
- &noselect, &noinferiors, &(idata->delim)) != 0)
+ if (imap_parse_list_response (idata, &cur_folder, &noselect,
+ &noinferiors, &idata->delim) != 0)
return -1;
if (cur_folder)
@@ -142,7 +124,7 @@ int imap_browse (char* path, struct browser_state* state)
}
}
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+ while (mutt_strncmp (idata->buf, idata->seq, SEQLEN));
}
/* if we're descending a folder, mark it as current in browser_state */
@@ -247,7 +229,6 @@ int imap_browse (char* path, struct browser_state* state)
static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
struct browser_state* state, short isparent)
{
- char buf[LONG_STRING];
char *name;
int noselect;
int noinferiors;
@@ -264,8 +245,8 @@ static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
do
{
- if (imap_parse_list_response(idata, buf, sizeof(buf), &name,
- &noselect, &noinferiors, &(idata->delim)) != 0)
+ if (imap_parse_list_response(idata, &name, &noselect, &noinferiors,
+ &idata->delim) != 0)
return -1;
if (name)
@@ -279,7 +260,7 @@ static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
isparent);
}
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+ while ((mutt_strncmp (idata->buf, idata->seq, SEQLEN) != 0));
return 0;
}
@@ -351,13 +332,13 @@ static int compare_names(struct folder_file *a, struct folder_file *b)
static int browse_get_namespace (IMAP_DATA* idata, char* nsbuf, int nsblen,
IMAP_NAMESPACE_INFO* nsi, int nsilen, int* nns)
{
- char buf[LONG_STRING];
char *s;
int n;
char ns[LONG_STRING];
char delim = '/';
int type;
int nsbused = 0;
+ int rc;
*nns = 0;
nsbuf[nsblen-1] = '\0';
@@ -366,89 +347,84 @@ static int browse_get_namespace (IMAP_DATA* idata, char* nsbuf, int nsblen,
do
{
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- return -1;
+ if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+ break;
- if (buf[0] == '*')
+ s = imap_next_word (idata->buf);
+ if (mutt_strncasecmp ("NAMESPACE", s, 9) == 0)
{
- s = imap_next_word (buf);
- if (mutt_strncasecmp ("NAMESPACE", s, 9) == 0)
+ /* There are three sections to the response, User, Other, Shared,
+ * and maybe more by extension */
+ for (type = IMAP_NS_PERSONAL; *s; type++)
{
- /* There are three sections to the response, User, Other, Shared,
- * and maybe more by extension */
- for (type = IMAP_NS_PERSONAL; *s; type++)
+ s = imap_next_word (s);
+ if (*s && strncmp (s, "NIL", 3))
{
- s = imap_next_word (s);
- if (*s && strncmp (s, "NIL", 3))
+ s++;
+ while (*s && *s != ')')
{
- s++;
- while (*s && *s != ')')
- {
- s++; /* skip ( */
- /* copy namespace */
- n = 0;
- delim = '\0';
+ s++; /* skip ( */
+ /* copy namespace */
+ n = 0;
+ delim = '\0';
- if (*s == '\"')
+ if (*s == '\"')
+ {
+ s++;
+ while (*s && *s != '\"')
{
- s++;
- while (*s && *s != '\"')
- {
- if (*s == '\\')
- s++;
- ns[n++] = *s;
+ if (*s == '\\')
s++;
- }
+ ns[n++] = *s;
+ s++;
}
- else
- while (*s && !ISSPACE (*s))
- {
- ns[n++] = *s;
- s++;
- }
- ns[n] = '\0';
- /* delim? */
- s = imap_next_word (s);
- /* delimiter is meaningless if namespace is "". Why does
- * Cyrus provide one?! */
- if (n && *s && *s == '\"')
- {
- if (s[1] && s[2] == '\"')
- delim = s[1];
- else if (s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
- delim = s[2];
- }
- /* skip "" namespaces, they are already listed at the root */
- if ((ns[0] != '\0') && (nsbused < nsblen) && (*nns < nsilen))
+ }
+ else
+ while (*s && !ISSPACE (*s))
{
- dprint (3, (debugfile, "browse_get_namespace: adding %s\n", ns));
- nsi->type = type;
- /* Cyrus doesn't append the delimiter to the namespace,
- * but UW-IMAP does. We'll strip it here and add it back
- * as if it were a normal directory, from the browser */
- if (n && (ns[n-1] == delim))
- ns[--n] = '\0';
- strncpy(nsbuf+nsbused,ns,nsblen-nsbused-1);
- nsi->prefix = nsbuf+nsbused;
- nsbused += n+1;
- nsi->delim = delim;
- nsi++;
- (*nns)++;
+ ns[n++] = *s;
+ s++;
}
- while (*s && *s != ')') s++;
- s++;
+ ns[n] = '\0';
+ /* delim? */
+ s = imap_next_word (s);
+ /* delimiter is meaningless if namespace is "". Why does
+ * Cyrus provide one?! */
+ if (n && *s && *s == '\"')
+ {
+ if (s[1] && s[2] == '\"')
+ delim = s[1];
+ else if (s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
+ delim = s[2];
+ }
+ /* skip "" namespaces, they are already listed at the root */
+ if ((ns[0] != '\0') && (nsbused < nsblen) && (*nns < nsilen))
+ {
+ dprint (3, (debugfile, "browse_get_namespace: adding %s\n", ns));
+ nsi->type = type;
+ /* Cyrus doesn't append the delimiter to the namespace,
+ * but UW-IMAP does. We'll strip it here and add it back
+ * as if it were a normal directory, from the browser */
+ if (n && (ns[n-1] == delim))
+ ns[--n] = '\0';
+ strncpy (nsbuf+nsbused,ns,nsblen-nsbused-1);
+ nsi->prefix = nsbuf+nsbused;
+ nsbused += n+1;
+ nsi->delim = delim;
+ nsi++;
+ (*nns)++;
}
+ while (*s && *s != ')') s++;
+ s++;
}
}
}
- else
- {
- if (imap_handle_untagged (idata, buf) != 0)
- return (-1);
- }
}
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+ while (rc == IMAP_CMD_CONTINUE);
+
+ if (rc != IMAP_CMD_DONE)
+ return -1;
return 0;
}
@@ -481,12 +457,12 @@ static int browse_verify_namespace (IMAP_DATA* idata,
nsi->home_namespace = 0;
do
{
- if (imap_parse_list_response(idata, buf, sizeof(buf), &name,
- &(nsi->noselect), &(nsi->noinferiors), &delim) != 0)
+ if (imap_parse_list_response(idata, &name, &nsi->noselect,
+ &nsi->noinferiors, &delim) != 0)
return -1;
nsi->listable |= (name != NULL);
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+ while ((mutt_strncmp (idata->buf, idata->seq, SEQLEN) != 0));
}
return 0;
diff --git a/imap/command.c b/imap/command.c
index 02d2bb3c..8d628296 100644
--- a/imap/command.c
+++ b/imap/command.c
@@ -29,6 +29,8 @@
#include <ctype.h>
#include <stdlib.h>
+#define IMAP_CMD_BUFSIZE 512
+
/* forward declarations */
static void cmd_make_sequence (char* buf, size_t buflen);
static void cmd_parse_capabilities (IMAP_DATA* idata, char* s);
@@ -60,6 +62,67 @@ void imap_cmd_start (IMAP_DATA* idata, const char* cmd)
safe_free ((void**) &out);
}
+/* imap_cmd_resp: Reads server responses from an IMAP command, detects
+ * tagged completion response, handles untagged messages, can read
+ * arbitrarily large strings (using malloc, so don't make it _too_
+ * large!). */
+int imap_cmd_resp (IMAP_DATA* idata)
+{
+ unsigned int len = 0;
+ int c;
+
+ /* read into buffer, expanding buffer as necessary until we have a full
+ * line */
+ do
+ {
+ if (len == idata->blen)
+ {
+ safe_realloc ((void**) &idata->buf, idata->blen + IMAP_CMD_BUFSIZE);
+ idata->blen = idata->blen + IMAP_CMD_BUFSIZE;
+ dprint (3, (debugfile, "imap_cmd_resp: grew buffer to %u bytes\n", idata->blen));
+ }
+
+ if ((c = mutt_socket_readln (idata->buf + len, idata->blen - len,
+ idata->conn)) < 0)
+ {
+ dprint (1, (debugfile, "imap_cmd_resp: Error while reading server response.\n"));
+ return IMAP_CMD_FAIL;
+ }
+
+ len += c;
+ }
+ /* if we've read all the way to the end of the buffer, we haven't read a
+ * full line (mutt_socket_readln strips the \r, so we always have at least
+ * one character free when we've read a full line) */
+ while (len == idata->blen);
+
+ /* don't let one large string make idata->buf hog memory forever */
+ if ((idata->blen > IMAP_CMD_BUFSIZE) && (len <= IMAP_CMD_BUFSIZE))
+ {
+ safe_realloc ((void**) &idata->buf, IMAP_CMD_BUFSIZE);
+ idata->blen = IMAP_CMD_BUFSIZE;
+ dprint (3, (debugfile, "imap_cmd_resp: shrank buffer to %u bytes\n", idata->blen));
+ }
+
+ /* handle untagged messages. The caller still gets its shot afterwards. */
+ if (!strncmp (idata->buf, "* ", 2) &&
+ imap_handle_untagged (idata, idata->buf))
+ return IMAP_CMD_FAIL;
+
+ /* server demands a continuation response from us */
+ if (!strncmp (idata->buf, "+ ", 2))
+ return IMAP_CMD_RESPOND;
+
+ /* tagged completion code */
+ if (!mutt_strncmp (idata->buf, idata->seq, SEQLEN))
+ {
+ imap_cmd_finish (idata);
+ return IMAP_CMD_DONE;
+ }
+
+ return IMAP_CMD_CONTINUE;
+}
+
/* imap_cmd_finish: When the caller has finished reading command responses,
* it must call this routine to perform cleanup (eg fetch new mail if
* detected, do expunge) */
@@ -104,7 +167,6 @@ void imap_cmd_finish (IMAP_DATA* idata)
}
idata->status = 0;
- mutt_clear_error ();
}
/* imap_code: returns 1 if the command result was OK, or 0 if NO or BAD */
@@ -123,11 +185,11 @@ int imap_code (const char *s)
* IMAP_CMD_PASS: command contains a password. Suppress logging.
* Return 0 on success, -1 on Failure, -2 on OK Failure
*/
-int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd,
- int flags)
+int imap_exec (IMAP_DATA* idata, const char* cmd, int flags)
{
char* out;
int outlen;
+ int rc;
/* create sequence for command */
cmd_make_sequence (idata->seq, sizeof (idata->seq));
@@ -142,30 +204,24 @@ int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd,
safe_free ((void**) &out);
do
- {
- if (mutt_socket_readln (buf, buflen, idata->conn) < 0)
- return -1;
-
- if (buf[0] == '*' && imap_handle_untagged (idata, buf) != 0)
- return -1;
- }
- while (mutt_strncmp (buf, idata->seq, SEQLEN) != 0);
+ rc = imap_cmd_resp (idata);
+ while (rc == IMAP_CMD_CONTINUE);
- imap_cmd_finish (idata);
+ if (rc != IMAP_CMD_DONE)
+ return -1;
- if (!imap_code (buf))
+ if (!imap_code (idata->buf))
{
char *pc;
if (flags & IMAP_CMD_FAIL_OK)
return -2;
- dprint (1, (debugfile, "imap_exec: command failed: %s\n", buf));
- pc = buf + SEQLEN;
- SKIPWS (pc);
+ dprint (1, (debugfile, "imap_exec: command failed: %s\n", idata->buf));
+ pc = idata->buf;
pc = imap_next_word (pc);
mutt_error ("%s", pc);
- sleep (1);
+ sleep (2);
return -1;
}
@@ -174,7 +230,7 @@ int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd,
}
/* imap_handle_untagged: fallback parser for otherwise unhandled messages. */
-int imap_handle_untagged (IMAP_DATA *idata, char *s)
+int imap_handle_untagged (IMAP_DATA* idata, char* s)
{
char *pn;
int count;
@@ -191,6 +247,8 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s)
*/
if (mutt_strncasecmp ("EXISTS", s, 6) == 0)
{
+ dprint (2, (debugfile, "Handling EXISTS\n"));
+
/* new mail arrived */
count = atoi (pn);
@@ -232,6 +290,12 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s)
cmd_parse_myrights (idata, s);
else if (mutt_strncasecmp ("BYE", s, 3) == 0)
{
+ dprint (2, (debugfile, "Handling BYE\n"));
+
+ /* check if we're logging out */
+ if (idata->status == IMAP_BYE)
+ return 0;
+
/* server shut down our connection */
s += 3;
SKIPWS (s);
@@ -246,13 +310,12 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s)
}
else if (option (OPTIMAPSERVERNOISE) && (mutt_strncasecmp ("NO", s, 2) == 0))
{
+ dprint (2, (debugfile, "Handling untagged NO\n"));
+
/* Display the warning message from the server */
mutt_error ("%s", s+3);
sleep (2);
}
- else
- dprint (1, (debugfile, "imap_handle_untagged(): unhandled request: %s\n",
- s));
return 0;
}
@@ -274,6 +337,8 @@ static void cmd_parse_capabilities (IMAP_DATA* idata, char* s)
{
int x;
+ dprint (2, (debugfile, "Handling CAPABILITY\n"));
+
idata->capstr = safe_strdup (imap_next_word (s));
while (*s)
@@ -295,6 +360,8 @@ static void cmd_parse_expunge (IMAP_DATA* idata, char* s)
int expno, cur;
HEADER* h;
+ dprint (2, (debugfile, "Handling EXPUNGE\n"));
+
expno = atoi (s);
/* walk headers, zero seqno of expunged message, decrement seqno of those
@@ -317,6 +384,8 @@ static void cmd_parse_expunge (IMAP_DATA* idata, char* s)
/* cmd_parse_myrights: set rights bits according to MYRIGHTS response */
static void cmd_parse_myrights (IMAP_DATA* idata, char* s)
{
+ dprint (2, (debugfile, "Handling MYRIGHTS\n"));
+
s = imap_next_word (s);
s = imap_next_word (s);
diff --git a/imap/imap.c b/imap/imap.c
index ca66b2f4..102b9820 100644
--- a/imap/imap.c
+++ b/imap/imap.c
@@ -52,11 +52,12 @@ int imap_create_mailbox (CONTEXT* ctx, char* mailbox)
imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
snprintf (buf, sizeof (buf), "CREATE %s", mbox);
- if (imap_exec (buf, sizeof (buf), CTX_DATA, buf, 0) != 0)
+ if (imap_exec ((IMAP_DATA*) ctx->data, buf, 0) != 0)
{
- imap_error ("imap_create_mailbox()", buf);
+ imap_error ("imap_create_mailbox", CTX_DATA->buf);
return -1;
}
+
return 0;
}
@@ -67,8 +68,11 @@ int imap_delete_mailbox (CONTEXT* ctx, char* mailbox)
imap_quote_string (mbox, sizeof (mbox), mailbox);
snprintf (buf, sizeof (buf), "DELETE %s", mbox);
- if (imap_exec (buf, sizeof (buf), CTX_DATA, buf, 0) != 0)
+ if (imap_exec ((IMAP_DATA*) ctx->data, buf, 0) != 0)
+ {
+ imap_error ("imap_delete_mailbox", CTX_DATA->buf);
return -1;
+ }
return 0;
}
@@ -429,8 +433,8 @@ int imap_reopen_mailbox (IMAP_DATA* idata)
static int imap_get_delim (IMAP_DATA *idata)
{
- char buf[LONG_STRING];
char *s;
+ int rc;
/* assume that the delim is /. If this fails, we're in bigger trouble
* than getting the delim wrong */
@@ -440,31 +444,31 @@ static int imap_get_delim (IMAP_DATA *idata)
do
{
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- return -1;
+ if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+ break;
- if (buf[0] == '*')
+ s = imap_next_word (idata->buf);
+ if (mutt_strncasecmp ("LIST", s, 4) == 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 (imap_handle_untagged (idata, buf) != 0)
- return -1;
- }
+ 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];
}
}
- while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+ while (rc == IMAP_CMD_CONTINUE);
- return 0;
+ if (rc != IMAP_CMD_DONE)
+ {
+ dprint (1, (debugfile, "imap_get_delim: failed.\n"));
+ return -1;
+ }
+
+ dprint (2, (debugfile, "Delimiter: %c\n", idata->delim));
+
+ return -1;
}
/* get rights for folder, let imap_handle_untagged do the rest */
@@ -475,7 +479,7 @@ static int imap_check_acl (IMAP_DATA *idata)
imap_munge_mbox_name (mbox, sizeof(mbox), idata->mailbox);
snprintf (buf, sizeof (buf), "MYRIGHTS %s", mbox);
- if (imap_exec (buf, sizeof (buf), idata, buf, 0) != 0)
+ if (imap_exec (idata, buf, 0) != 0)
{
imap_error ("imap_check_acl", buf);
return -1;
@@ -486,11 +490,9 @@ static int imap_check_acl (IMAP_DATA *idata)
/* imap_check_capabilities: make sure we can log in to this server. */
static int imap_check_capabilities (IMAP_DATA* idata)
{
- char buf[LONG_STRING];
-
- if (imap_exec (buf, sizeof (buf), idata, "CAPABILITY", 0) != 0)
+ if (imap_exec (idata, "CAPABILITY", 0) != 0)
{
- imap_error ("imap_check_capabilities", buf);
+ imap_error ("imap_check_capabilities", idata->buf);
return -1;
}
@@ -566,17 +568,17 @@ int imap_open_connection (IMAP_DATA* idata)
idata->state = IMAP_CONNECTED;
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+ if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE)
goto bail;
- if (mutt_strncmp ("* OK", buf, 4) == 0)
+ if (mutt_strncmp ("* OK", idata->buf, 4) == 0)
{
if (imap_check_capabilities (idata) || imap_authenticate (idata))
goto bail;
}
- else if (mutt_strncmp ("* PREAUTH", buf, 9) == 0)
+ else if (mutt_strncmp ("* PREAUTH", idata->buf, 9) == 0)
{
- if (imap_check_capabilities(idata) != 0)
+ if (imap_check_capabilities (idata) != 0)
goto bail;
}
else
@@ -662,8 +664,8 @@ int imap_open_mailbox (CONTEXT* ctx)
char buf[LONG_STRING];
char bufout[LONG_STRING];
int count = 0;
- int n;
IMAP_MBOX mx;
+ int rc;
if (imap_parse_path (ctx->path, &mx))
{
@@ -677,7 +679,7 @@ int imap_open_mailbox (CONTEXT* ctx)
conn = idata->conn;
/* once again the context is new */
- ctx->data = (void *) idata;
+ ctx->data = idata;
/* Clean up path and replace the one in the ctx */
imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
@@ -707,56 +709,53 @@ int imap_open_mailbox (CONTEXT* ctx)
{
char *pc;
- if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
+ if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
break;
- if (buf[0] == '*')
+ pc = idata->buf + 2;
+ pc = imap_next_word (pc);
+ if (!mutt_strncasecmp ("EXISTS", pc, 6))
{
- pc = buf + 2;
+ /* imap_handle_untagged will have picked up the EXISTS message and
+ * set the NEW_MAIL flag. We clear it here. */
+ idata->status = 0;
+ count = idata->newMailCount;
+ idata->newMailCount = 0;
+ }
- if (isdigit (*pc))
- {
- char *pn = pc;
+ pc = idata->buf + 2;
- while (*pc && isdigit (*pc))
- pc++;
- *pc++ = '\0';
- n = atoi (pn);
- SKIPWS (pc);
- if (mutt_strncasecmp ("EXISTS", pc, 6) == 0)
- count = n;
- }
- /* Obtain list of available flags here, may be overridden by a
- * PERMANENTFLAGS tag in the OK response */
- else