diff options
author | Thomas Roessler <roessler@does-not-exist.org> | 2000-08-05 17:50:01 +0000 |
---|---|---|
committer | Thomas Roessler <roessler@does-not-exist.org> | 2000-08-05 17:50:01 +0000 |
commit | fa002c59576b77da5ec933e61c15c4b5109c6bc4 (patch) | |
tree | 0d2b688f78327fc04cd6363f194c6ed8de798ffc /imap | |
parent | 661ac8a44b29182ec42f768fc42496cdca5a6c6b (diff) |
Unified IMAP command code.
Diffstat (limited to 'imap')
-rw-r--r-- | imap/Makefile.am | 4 | ||||
-rw-r--r-- | imap/auth_anon.c | 24 | ||||
-rw-r--r-- | imap/auth_cram.c | 23 | ||||
-rw-r--r-- | imap/auth_gss.c | 39 | ||||
-rw-r--r-- | imap/auth_login.c | 5 | ||||
-rw-r--r-- | imap/auth_sasl.c | 28 | ||||
-rw-r--r-- | imap/browse.c | 174 | ||||
-rw-r--r-- | imap/command.c | 111 | ||||
-rw-r--r-- | imap/imap.c | 358 | ||||
-rw-r--r-- | imap/imap_private.h | 19 | ||||
-rw-r--r-- | imap/message.c | 376 |
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 |