From fa002c59576b77da5ec933e61c15c4b5109c6bc4 Mon Sep 17 00:00:00 2001 From: Thomas Roessler Date: Sat, 5 Aug 2000 17:50:01 +0000 Subject: Unified IMAP command code. --- imap/Makefile.am | 4 +- imap/auth_anon.c | 24 ++-- imap/auth_cram.c | 23 ++-- imap/auth_gss.c | 39 ++++-- imap/auth_login.c | 5 +- imap/auth_sasl.c | 28 ++-- imap/browse.c | 174 +++++++++++------------- imap/command.c | 111 +++++++++++++--- imap/imap.c | 358 ++++++++++++++++++++++++------------------------- imap/imap_private.h | 19 ++- imap/message.c | 376 +++++++++++++++++++++++++--------------------------- 11 files changed, 603 insertions(+), 558 deletions(-) (limited to 'imap') 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 #include +#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 if (mutt_strncasecmp ("FLAGS", pc, 5) == 0) - { - /* don't override PERMANENTFLAGS */ - if (!idata->flags) - { - dprint (2, (debugfile, "Getting mailbox FLAGS\n")); - if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL) - return -1; - } - } - /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */ - else if (mutt_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0) + /* Obtain list of available flags here, may be overridden by a + * PERMANENTFLAGS tag in the OK response */ + if (mutt_strncasecmp ("FLAGS", pc, 5) == 0) + { + /* don't override PERMANENTFLAGS */ + if (!idata->flags) { - dprint (2, (debugfile, - "Getting mailbox PERMANENTFLAGS\n")); - /* safe to call on NULL */ - mutt_free_list (&(idata->flags)); - /* skip "OK [PERMANENT" so syntax is the same as FLAGS */ - pc += 13; - if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL) - return -1; + dprint (2, (debugfile, "Getting mailbox FLAGS\n")); + if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL) + return -1; } - else if (imap_handle_untagged (idata, buf) != 0) - return (-1); + } + /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */ + else if (mutt_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0) + { + dprint (2, (debugfile, "Getting mailbox PERMANENTFLAGS\n")); + /* safe to call on NULL */ + mutt_free_list (&(idata->flags)); + /* skip "OK [PERMANENT" so syntax is the same as FLAGS */ + pc += 13; + if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL) + return -1; } } - while (mutt_strncmp (idata->seq, buf, mutt_strlen (idata->seq)) != 0); + while (rc == IMAP_CMD_CONTINUE); + + if (rc != IMAP_CMD_DONE) + return -1; + /* check for READ-ONLY notification */ - if (!strncmp (imap_get_qualifier (buf), "[READ-ONLY]", 11)) + if (!strncmp (imap_get_qualifier (idata->buf), "[READ-ONLY]", 11)) { dprint (2, (debugfile, "Mailbox is read-only.\n")); ctx->readonly = 1; @@ -785,10 +784,10 @@ int imap_open_mailbox (CONTEXT* ctx) } #endif - if (!imap_code (buf)) + if (!imap_code (idata->buf)) { char *s; - s = imap_next_word (buf); /* skip seq */ + s = imap_next_word (idata->buf); /* skip seq */ s = imap_next_word (s); /* Skip response */ mutt_error ("%s", s); idata->state = IMAP_AUTHENTICATED; @@ -866,7 +865,7 @@ int imap_open_mailbox_append (CONTEXT *ctx) return -1; } - r = imap_exec (buf, sizeof (buf), idata, buf, IMAP_CMD_FAIL_OK); + r = imap_exec (idata, buf, IMAP_CMD_FAIL_OK); if (r == -2) { /* command failed cause folder doesn't exist */ @@ -884,18 +883,15 @@ int imap_open_mailbox_append (CONTEXT *ctx) return 0; } +/* imap_logout: Gracefully log out of server. */ void imap_logout (IMAP_DATA* idata) { - char buf[LONG_STRING]; - + /* we set status here to let imap_handle_untagged know we _expect_ to + * receive a bye response (so it doesn't freak out and close the conn) */ + idata->status = IMAP_BYE; imap_cmd_start (idata, "LOGOUT"); - - do - { - if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0) - break; - } - while (mutt_strncmp (idata->seq, buf, SEQLEN) != 0); + while (imap_cmd_resp (idata) == IMAP_CMD_CONTINUE) + ; } int imap_close_connection (CONTEXT *ctx) @@ -1070,7 +1066,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint) mutt_message (_("Marking %d messages deleted..."), deleted); snprintf (tmp, sizeof (tmp), "UID STORE %s +FLAGS.SILENT (\\Deleted)", buf); - if (imap_exec (buf, sizeof (buf), idata, tmp, 0) != 0) + if (imap_exec (idata, tmp, 0) != 0) /* continue, let regular store try before giving up */ dprint(2, (debugfile, "imap_sync_mailbox: fast delete failed\n")); else @@ -1125,7 +1121,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint) /* after all this it's still possible to have no flags, if you * have no ACL rights */ - if (*flags && (imap_exec (buf, sizeof (buf), idata, buf, 0) != 0) && + if (*flags && (imap_exec (idata, buf, 0) != 0) && (err_continue != M_YES)) { err_continue = imap_continue ("imap_sync_mailbox: STORE failed", buf); @@ -1143,7 +1139,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint) mutt_bit_isset(idata->rights, IMAP_ACL_DELETE)) { mutt_message _("Expunging messages from server..."); - if (imap_exec (buf, sizeof (buf), CTX_DATA, "EXPUNGE", 0) != 0) + if (imap_exec (idata, "EXPUNGE", 0) != 0) { imap_error ("imap_sync_mailbox: EXPUNGE failed", buf); return -1; @@ -1157,7 +1153,6 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint) void imap_close_mailbox (CONTEXT* ctx) { IMAP_DATA* idata; - char buf[LONG_STRING]; int i; idata = (IMAP_DATA*) ctx->data; @@ -1172,8 +1167,8 @@ void imap_close_mailbox (CONTEXT* ctx) if (!(idata->noclose)) { mutt_message _("Closing mailbox..."); - if (imap_exec (buf, sizeof (buf), idata, "CLOSE", 0) != 0) - imap_error ("CLOSE failed", buf); + if (imap_exec (idata, "CLOSE", 0) != 0) + imap_error ("CLOSE failed", idata->buf); } idata->state = IMAP_AUTHENTICATED; @@ -1204,10 +1199,13 @@ void imap_close_mailbox (CONTEXT* ctx) */ int imap_check_mailbox (CONTEXT *ctx, int *index_hint) { - char buf[LONG_STRING]; static time_t checktime=0; + + IMAP_DATA* idata; time_t t = 0; + idata = (IMAP_DATA*) ctx->data; + /* * gcc thinks it has to warn about uninitialized use * of t. This is wrong. @@ -1219,21 +1217,22 @@ int imap_check_mailbox (CONTEXT *ctx, int *index_hint) t -= checktime; } + /* TODO: wtf?! */ if ((ImapCheckTimeout && t >= ImapCheckTimeout) - || ((CTX_DATA->reopen & IMAP_REOPEN_ALLOW) && (CTX_DATA->reopen & ~IMAP_REOPEN_ALLOW))) + || ((idata->reopen & IMAP_REOPEN_ALLOW) && (idata->reopen & ~IMAP_REOPEN_ALLOW))) { if (ImapCheckTimeout) checktime += t; - CTX_DATA->check_status = 0; - if (imap_exec (buf, sizeof (buf), CTX_DATA, "NOOP", 0) != 0) + idata->check_status = 0; + if (imap_exec (idata, "NOOP", 0) != 0) { - imap_error ("imap_check_mailbox()", buf); + imap_error ("imap_check_mailbox", idata->buf); return -1; } - if (CTX_DATA->check_status == IMAP_NEW_MAIL) + if (idata->check_status == IMAP_NEW_MAIL) return M_NEW_MAIL; - if (CTX_DATA->check_status == IMAP_REOPENED) + if (idata->check_status == IMAP_REOPENED) return M_REOPENED; } @@ -1257,6 +1256,7 @@ int imap_mailbox_check (char* path, int new) int msgcount = 0; int connflags = 0; IMAP_MBOX mx; + int rc; if (imap_parse_path (path, &mx)) return -1; @@ -1304,119 +1304,107 @@ int imap_mailbox_check (char* path, int new) do { - if (mutt_socket_readln (buf, sizeof (buf), 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 ("STATUS", s, 6) == 0) { - s = imap_next_word (buf); - if (mutt_strncasecmp ("STATUS", s, 6) == 0) + s = imap_next_word (s); + /* The mailbox name may or may not be quoted here. We could try to + * munge the server response and compare with quoted (or vise versa) + * but it is probably more efficient to just strncmp against both. */ + if (mutt_strncmp (mbox_unquoted, s, mutt_strlen (mbox_unquoted)) == 0 + || mutt_strncmp (mbox, s, mutt_strlen (mbox)) == 0) { s = imap_next_word (s); - /* The mailbox name may or may not be quoted here. We could try to - * munge the server response and compare with quoted (or vise versa) - * but it is probably more efficient to just strncmp against both. */ - if (mutt_strncmp (mbox_unquoted, s, mutt_strlen (mbox_unquoted)) == 0 - || mutt_strncmp (mbox, s, mutt_strlen (mbox)) == 0) + s = imap_next_word (s); + if (isdigit (*s)) { - s = imap_next_word (s); - s = imap_next_word (s); - if (isdigit (*s)) + if (*s != '0') { - if (*s != '0') - { - dprint (1, (debugfile, "Mail in %s\n", path)); - msgcount = atoi(s); - } + dprint (1, (debugfile, "Mail in %s\n", path)); + msgcount = atoi(s); } } - else - dprint (1, (debugfile, "imap_mailbox_check: STATUS response doesn't match requested mailbox.\n")); } else - { - if (conn->data && - imap_handle_untagged (idata, buf) != 0) - return -1; - } + dprint (1, (debugfile, "imap_mailbox_check: STATUS response doesn't match requested mailbox.\n")); } } - while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0)); - - imap_cmd_finish (idata); + while (rc == IMAP_CMD_CONTINUE); return msgcount; } -int imap_parse_list_response(IMAP_DATA* idata, char *buf, int buflen, - char **name, int *noselect, int *noinferiors, char *delim) +/* all this listing/browsing is a mess. I don't like that name is a pointer + * into idata->buf (used to be a pointer into the passed in buffer, just + * as bad), nor do I like the fact that the fetch is done here. This + * code can't possibly handle non-LIST untagged responses properly. + * FIXME. ?! */ +int imap_parse_list_response(IMAP_DATA* idata, char **name, int *noselect, + int *noinferiors, char *delim) { char *s; long bytes; + int rc; *name = NULL; - if (mutt_socket_readln (buf, buflen, idata->conn) < 0) + rc = imap_cmd_resp (idata); + if (rc == IMAP_CMD_DONE) + return 0; + if (rc != IMAP_CMD_CONTINUE) return -1; - if (buf[0] == '*') + s = imap_next_word (idata->buf); + if ((mutt_strncasecmp ("LIST", s, 4) == 0) || + (mutt_strncasecmp ("LSUB", s, 4) == 0)) { - s = imap_next_word (buf); - if ((mutt_strncasecmp ("LIST", s, 4) == 0) || - (mutt_strncasecmp ("LSUB", s, 4) == 0)) - { - *noselect = 0; - *noinferiors = 0; + *noselect = 0; + *noinferiors = 0; - s = imap_next_word (s); /* flags */ - if (*s == '(') - { - char *ep; - - s++; - ep = s; - while (*ep && *ep != ')') ep++; - do { - if (!strncasecmp (s, "\\NoSelect", 9)) - *noselect = 1; - if (!strncasecmp (s, "\\NoInferiors", 12)) - *noinferiors = 1; - if (*s != ')') - s++; - while (*s && *s != '\\' && *s != ')') s++; - } while (s != ep); - } - else - return (0); - s = imap_next_word (s); /* delim */ - /* Reset the delimiter, this can change */ - if (strncmp (s, "NIL", 3)) + s = imap_next_word (s); /* flags */ + if (*s == '(') + { + char *ep; + + s++; + ep = s; + while (*ep && *ep != ')') ep++; + do { - if (s && s[0] == '\"' && s[1] && s[2] == '\"') - *delim = s[1]; - else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"') - *delim = s[2]; - } - s = imap_next_word (s); /* name */ - if (s && *s == '{') /* Literal */ - { - int len; - - if (imap_get_literal_count(buf, &bytes) < 0) - return -1; - len = mutt_socket_readln (buf, buflen, idata->conn); - if (len < 0) - return -1; - *name = buf; - } - else - *name = s; + if (!strncasecmp (s, "\\NoSelect", 9)) + *noselect = 1; + if (!strncasecmp (s, "\\NoInferiors", 12)) + *noinferiors = 1; + if (*s != ')') + s++; + while (*s && *s != '\\' && *s != ')') s++; + } while (s != ep); } else + return 0; + s = imap_next_word (s); /* delim */ + /* Reset the delimiter, this can change */ + if (strncmp (s, "NIL", 3)) { - if (imap_handle_untagged (idata, buf) != 0) + if (s && s[0] == '\"' && s[1] && s[2] == '\"') + *delim = s[1]; + else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"') + *delim = s[2]; + } + s = imap_next_word (s); /* name */ + if (s && *s == '{') /* Literal */ + { + if (imap_get_literal_count(idata->buf, &bytes) < 0) return -1; + if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE) + return -1; + *name = idata->buf; } + else + *name = s; } return 0; @@ -1448,7 +1436,7 @@ int imap_subscribe (char *path, int subscribe) snprintf (buf, sizeof (buf), "%s %s", subscribe ? "SUBSCRIBE" : "UNSUBSCRIBE", mbox); - if (imap_exec (buf, sizeof (buf), idata, buf, 0) < 0) + if (imap_exec (idata, buf, 0) < 0) return -1; return 0; @@ -1499,8 +1487,8 @@ int imap_complete(char* dest, size_t dlen, char* path) { strfcpy (completion, mx.mbox, sizeof(completion)); do { - if (imap_parse_list_response(idata, buf, sizeof(buf), &list_word, - &noselect, &noinferiors, &delim)) + if (imap_parse_list_response(idata, &list_word, &noselect, &noinferiors, + &delim)) break; if (list_word) @@ -1535,7 +1523,7 @@ int imap_complete(char* dest, size_t dlen, char* path) { completions++; } } - while (mutt_strncmp(idata->seq, buf, SEQLEN)); + while (mutt_strncmp(idata->seq, idata->buf, SEQLEN)); if (completions) { diff --git a/imap/imap_private.h b/imap/imap_private.h index e404f19d..fe197a64 100644 --- a/imap/imap_private.h +++ b/imap/imap_private.h @@ -32,6 +32,12 @@ #define IMAP_LOG_LTRL 4 #define IMAP_LOG_PASS 5 +/* IMAP command responses */ +#define IMAP_CMD_DONE (0) +#define IMAP_CMD_FAIL (-1) +#define IMAP_CMD_CONTINUE (1) +#define IMAP_CMD_RESPOND (2) + /* number of entries in the hash table */ #define IMAP_CACHE_LEN 10 @@ -145,6 +151,10 @@ typedef struct unsigned char status; unsigned char check_status; unsigned char capabilities[(CAPMAX + 7)/8]; + char seq[SEQLEN+1]; + /* command input buffer */ + char* buf; + unsigned int blen; /* let me explain capstr: SASL needs the capability string (not bits). * we have 3 options: * 1. rerun CAPABILITY inside SASL function. @@ -154,7 +164,6 @@ typedef struct * tracking all possible capabilities. bah. (1) I don't like because * it's just no fun to get the same information twice */ char* capstr; - char seq[SEQLEN+1]; /* The following data is all specific to the currently SELECTED mbox */ char delim; @@ -180,8 +189,8 @@ int imap_make_msg_set (IMAP_DATA* idata, char* buf, size_t buflen, int flag, int imap_open_connection (IMAP_DATA* idata); IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags); time_t imap_parse_date (char* s); -int imap_parse_list_response(IMAP_DATA* idata, char* buf, int buflen, - char** name, int* noselect, int* noinferiors, char* delim); +int imap_parse_list_response(IMAP_DATA* idata, char** name, int* noselect, + int* noinferiors, char* delim); int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes); void imap_expunge_mailbox (IMAP_DATA* idata); int imap_reopen_mailbox (IMAP_DATA* idata); @@ -192,10 +201,10 @@ int imap_authenticate (IMAP_DATA* idata); /* command.c */ void imap_cmd_start (IMAP_DATA* idata, const char* cmd); +int imap_cmd_resp (IMAP_DATA* idata); void imap_cmd_finish (IMAP_DATA* idata); int imap_code (const char* s); -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); int imap_handle_untagged (IMAP_DATA* idata, char* s); /* message.c */ diff --git a/imap/message.c b/imap/message.c index 3ea4b4cc..a5e5fccd 100644 --- a/imap/message.c +++ b/imap/message.c @@ -45,23 +45,26 @@ static char* msg_parse_flags (IMAP_HEADER* h, char* s); */ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) { + IMAP_DATA* idata; char buf[LONG_STRING]; char hdrreq[STRING]; FILE *fp; char tempfile[_POSIX_PATH_MAX]; int msgno; IMAP_HEADER h; - int rc; + int rc, mfhrc; int fetchlast = 0; const char *want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE IN-REPLY-TO REPLY-TO LINES X-LABEL"; + + idata = (IMAP_DATA*) ctx->data; /* define search string */ - if (mutt_bit_isset (CTX_DATA->capabilities,IMAP4REV1)) + if (mutt_bit_isset (idata->capabilities,IMAP4REV1)) { snprintf (hdrreq, sizeof (hdrreq), "BODY.PEEK[HEADER.FIELDS (%s)]", want_headers); } - else if (mutt_bit_isset (CTX_DATA->capabilities,IMAP4)) + else if (mutt_bit_isset (idata->capabilities,IMAP4)) { snprintf (hdrreq, sizeof (hdrreq), "RFC822.HEADER.LINES (%s)", want_headers); @@ -69,7 +72,7 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) else { /* Unable to fetch headers for lower versions */ mutt_error _("Unable to fetch headers from this IMAP server version."); - sleep (1); /* pause a moment to let the user see the error */ + sleep (2); /* pause a moment to let the user see the error */ return -1; } @@ -102,7 +105,7 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) "FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)", msgno + 1, msgend + 1, hdrreq); - imap_cmd_start (CTX_DATA, buf); + imap_cmd_start (idata, buf); fetchlast = msgend + 1; } @@ -118,72 +121,66 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) */ do { - rc = 0; - - if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0) - { - imap_free_header_data ((void**) &h.data); - fclose (fp); - return -1; - } - - if (buf[0] == '*') - { - if ((rc = msg_fetch_header (ctx, &h, buf, fp))) - { - if (rc == -1 && !imap_handle_untagged (CTX_DATA, buf)) - continue; - else - { - imap_free_header_data ((void**) h.data); - fclose (fp); - return -1; - } - } + mfhrc = 0; + + rc = imap_cmd_resp (idata); + if (rc != IMAP_CMD_CONTINUE) + break; + + if ((mfhrc = msg_fetch_header (ctx, &h, idata->buf, fp)) == -1) + continue; + else if (mfhrc < 0) + break; + + /* make sure we don't get remnants from older larger message headers */ + fputs ("\n\n", fp); + + /* update context with message header */ + ctx->hdrs[msgno] = mutt_new_header (); + ctx->hdrs[msgno]->index = ctx->msgcount; + + /* messages which have not been expunged are ACTIVE (borrowed from mh + * folders) */ + ctx->hdrs[msgno]->active = 1; + ctx->hdrs[msgno]->read = h.read; + ctx->hdrs[msgno]->old = h.old; + ctx->hdrs[msgno]->deleted = h.deleted; + ctx->hdrs[msgno]->flagged = h.flagged; + ctx->hdrs[msgno]->replied = h.replied; + ctx->hdrs[msgno]->changed = h.changed; + ctx->hdrs[msgno]->received = h.received; + ctx->hdrs[msgno]->data = (void *) (h.data); + + rewind (fp); + /* NOTE: if Date: header is missing, mutt_read_rfc822_header depends + * on h.received being set */ + ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno], + 0, 0); + /* content built as a side-effect of mutt_read_rfc822_header */ + ctx->hdrs[msgno]->content->length = h.content_length; + + mx_update_context (ctx); /* increments ->msgcount */ + } + while ((rc != IMAP_CMD_DONE) && ((mfhrc == -1) || + ((msgno + 1) >= fetchlast))); - /* make sure we don't get remnants from older larger message headers */ - fputs ("\n\n", fp); - - /* update context with message header */ - ctx->hdrs[msgno] = mutt_new_header (); - ctx->hdrs[msgno]->index = ctx->msgcount; - - /* messages which have not been expunged are ACTIVE (borrowed from - * mh folders) */ - ctx->hdrs[msgno]->active = 1; - ctx->hdrs[msgno]->read = h.read; - ctx->hdrs[msgno]->old = h.old; - ctx->hdrs[msgno]->deleted = h.deleted; - ctx->hdrs[msgno]->flagged = h.flagged; - ctx->hdrs[msgno]->replied = h.replied; - ctx->hdrs[msgno]->changed = h.changed; - ctx->hdrs[msgno]->received = h.received; - ctx->hdrs[msgno]->data = (void *) (h.data); - - rewind (fp); - /* NOTE: if Date: header is missing, mutt_read_rfc822_header depends - * on h.received being set */ - ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno], - 0, 0); - /* content built as a side-effect of mutt_read_rfc822_header */ - ctx->hdrs[msgno]->content->length = h.content_length; - - mx_update_context (ctx); /* increments ->msgcount */ + if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_DONE))) + { + imap_free_header_data ((void**) &h.data); + fclose (fp); - } + return -1; } - while ((rc == -1) || ((msgno + 1) >= fetchlast && - !mutt_strncmp (CTX_DATA->seq, buf, SEQLEN) != 0)); - + /* h.data shouldn't be freed here, it is kept in ctx->headers */ /* in case we get new mail while fetching the headers */ - if (CTX_DATA->status == IMAP_NEW_MAIL) + if (idata->status == IMAP_NEW_MAIL) { - msgend = CTX_DATA->newMailCount - 1; + msgend = idata->newMailCount - 1; while ((msgend) >= ctx->hdrmax) mx_alloc_memory (ctx); - CTX_DATA->status = 0; + idata->status = 0; } } @@ -194,6 +191,7 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) { + IMAP_DATA* idata; char buf[LONG_STRING]; char path[_POSIX_PATH_MAX]; char *pc; @@ -201,10 +199,13 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) int uid; int cacheno; IMAP_CACHE *cache; + int rc; + + idata = (IMAP_DATA*) ctx->data; /* see if we already have the message in our cache */ cacheno = HEADER_DATA(ctx->hdrs[msgno])->uid % IMAP_CACHE_LEN; - cache = &CTX_DATA->cache[cacheno]; + cache = &idata->cache[cacheno]; if (cache->path) { @@ -240,104 +241,102 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) snprintf (buf, sizeof (buf), "UID FETCH %d RFC822", HEADER_DATA(ctx->hdrs[msgno])->uid); - imap_cmd_start (CTX_DATA, buf); + imap_cmd_start (idata, buf); do { - if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0) - goto bail; + if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE) + continue; - if (buf[0] == '*') + pc = idata->buf; + pc = imap_next_word (pc); + pc = imap_next_word (pc); + if (!mutt_strncasecmp ("FETCH", pc, 5)) { - pc = buf; - pc = imap_next_word (pc); - pc = imap_next_word (pc); - if (mutt_strncasecmp ("FETCH", pc, 5) == 0) + while (*pc) { - while (*pc) + pc = imap_next_word (pc); + if (pc[0] == '(') + pc++; + if (strncasecmp ("UID", pc, 3) == 0) { pc = imap_next_word (pc); - if (pc[0] == '(') - pc++; - if (strncasecmp ("UID", pc, 3) == 0) - { - pc = imap_next_word (pc); - uid = atoi (pc); - if (uid != HEADER_DATA(ctx->hdrs[msgno])->uid) - mutt_error (_("The message index is incorrect. Try reopening the mailbox.")); - } - else if (strncasecmp ("RFC822", pc, 6) == 0) + uid = atoi (pc); + if (uid != HEADER_DATA(ctx->hdrs[msgno])->uid) + mutt_error (_("The message index is incorrect. Try reopening the mailbox.")); + } + else if (strncasecmp ("RFC822", pc, 6) == 0) + { + pc = imap_next_word (pc); + if (imap_get_literal_count(pc, &bytes) < 0) { - pc = imap_next_word (pc); - if (imap_get_literal_count(pc, &bytes) < 0) - { - imap_error ("imap_fetch_message()", buf); - goto bail; - } - if (imap_read_literal (msg->fp, CTX_DATA, bytes) < 0) - goto bail; - /* pick up trailing line */ - if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0) - goto bail; - pc = buf; + imap_error ("imap_fetch_message()", buf); + goto bail; } - /* UW-IMAP will provide a FLAGS update here if the FETCH causes a - * change (eg from \Unseen to \Seen). - * Uncommitted changes in mutt take precedence. If we decide to - * incrementally update flags later, this won't stop us syncing */ - else if ((strncasecmp ("FLAGS", pc, 5) == 0) && - !ctx->hdrs[msgno]->changed) - { - IMAP_HEADER newh; - HEADER* h = ctx->hdrs[msgno]; - unsigned char readonly; - - memset (&newh, 0, sizeof (newh)); - newh.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA)); - - dprint (2, (debugfile, "imap_fetch_message: parsing FLAGS\n")); - if ((pc = msg_parse_flags (&newh, pc)) == NULL) - goto bail; + if (imap_read_literal (msg->fp, idata, bytes) < 0) + goto bail; + /* pick up trailing line */ + if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE) + goto bail; + pc = idata->buf; + } + /* UW-IMAP will provide a FLAGS update here if the FETCH causes a + * change (eg from \Unseen to \Seen). + * Uncommitted changes in mutt take precedence. If we decide to + * incrementally update flags later, this won't stop us syncing */ + else if ((strncasecmp ("FLAGS", pc, 5) == 0) && + !ctx->hdrs[msgno]->changed) + { + IMAP_HEADER newh; + HEADER* h = ctx->hdrs[msgno]; + unsigned char readonly; + + memset (&newh, 0, sizeof (newh)); + newh.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA)); + + dprint (2, (debugfile, "imap_fetch_message: parsing FLAGS\n")); + if ((pc = msg_parse_flags (&newh, pc)) == NULL) + goto bail; - /* this is less efficient than the code which used to be here, - * but (1) this is only invoked when fetching messages, and (2) - * this way, we can make sure that side effects of flag changes - * are taken account of the proper way. - */ - - /* YAUH (yet another ugly hack): temporarily set context to - * read-write even if it's read-only, so *server* updates of - * flags can be processed by mutt_set_flag. ctx->changed must - * be restored afterwards */ - readonly = ctx->readonly; - ctx->readonly = 0; + /* this is less efficient than the code which used to be here, + * but (1) this is only invoked when fetching messages, and (2) + * this way, we can make sure that side effects of flag changes + * are taken account of the proper way. + */ + + /* YAUH (yet another ugly hack): temporarily set context to + * read-write even if it's read-only, so *server* updates of + * flags can be processed by mutt_set_flag. ctx->changed must + * be restored afterwards */ + readonly = ctx->readonly; + ctx->readonly = 0; - mutt_set_flag (ctx, h, M_NEW, - !(newh.read || newh.old || h->read || h->old)); - mutt_set_flag (ctx, h, M_OLD, newh.old); - mutt_set_flag (ctx, h, M_READ, h->read || newh.read); - mutt_set_flag (ctx, h, M_DELETE, h->deleted || newh.deleted); - mutt_set_flag (ctx, h, M_FLAG, h->flagged || newh.flagged); - mutt_set_flag (ctx, h, M_REPLIED, h->replied || newh.replied); - - /* this message is now definitively *not* changed (mutt_set_flag - * marks things changed as a side-effect) */ - h->changed = 0; - ctx->changed &= ~readonly; - ctx->readonly = readonly; - - mutt_free_list (&(HEADER_DATA(h)->keywords)); - HEADER_DATA(h)->keywords = newh.data->keywords; - FREE(&newh.data); - } + mutt_set_flag (ctx, h, M_NEW, + !(newh.read || newh.old || h->read || h->old)); + mutt_set_flag (ctx, h, M_OLD, newh.old); + mutt_set_flag (ctx, h, M_READ, h->read || newh.read); + mutt_set_flag (ctx, h, M_DELETE, h->deleted || newh.deleted); + mutt_set_flag (ctx, h, M_FLAG, h->flagged || newh.flagged); + mutt_set_flag (ctx, h, M_REPLIED, h->replied || newh.replied); + + /* this message is now definitively *not* changed (mutt_set_flag + * marks things changed as a side-effect) */ + h->changed = 0; + ctx->changed &= ~readonly; + ctx->readonly = readonly; + + mutt_free_list (&(HEADER_DATA(h)->keywords)); + HEADER_DATA(h)->keywords = newh.data->keywords; + FREE(&newh.data); } } - else if (imap_handle_untagged (CTX_DATA, buf) != 0) - goto bail; } } - while (mutt_strncmp (buf, CTX_DATA->seq, SEQLEN) != 0); + while (rc == IMAP_CMD_CONTINUE); - if (!imap_code (buf)) + if (rc != IMAP_CMD_DONE) + goto bail; + + if (!imap_code (idata->buf)) goto bail; /* Update the header information. Previously, we only downloaded a @@ -380,6 +379,7 @@ bail: int imap_append_message (CONTEXT *ctx, MESSAGE *msg) { + IMAP_DATA* idata; FILE *fp; char buf[LONG_STRING]; char mbox[LONG_STRING]; @@ -387,11 +387,14 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg) size_t len; int c, last; IMAP_MBOX mx; + int rc; + + idata = (IMAP_DATA*) ctx->data; if (imap_parse_path (ctx->path, &mx)) - return (-1); + return -1; - imap_fix_path (CTX_DATA, mx.mbox, mailbox, sizeof (mailbox)); + imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox)); if ((fp = fopen (msg->path, "r")) == NULL) { @@ -411,31 +414,19 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg) imap_munge_mbox_name (mbox, sizeof (mbox), mailbox); snprintf (buf, sizeof (buf), "APPEND %s {%d}", mbox, len); - imap_cmd_start (CTX_DATA, buf); - - do - { - if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0) - { - fclose (fp); - return (-1); - } + imap_cmd_start (idata, buf); - if (buf[0] == '*' && imap_handle_untagged (CTX_DATA, buf) != 0) - { - fclose (fp); - return (-1); - } - } - while ((mutt_strncmp (buf, CTX_DATA->seq, SEQLEN) != 0) && (buf[0] != '+')); + do + rc = imap_cmd_resp (idata); + while (rc == IMAP_CMD_CONTINUE); - if (buf[0] != '+') + if (rc != IMAP_CMD_RESPOND) { char *pc; - dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", buf)); + dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", idata->buf)); - pc = buf + SEQLEN; + pc = idata->buf + SEQLEN; SKIPWS (pc); pc = imap_next_word (pc); mutt_error ("%s", pc); @@ -454,31 +445,25 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg) buf[len++] = c; if (len > sizeof(buf) - 3) - flush_buffer(buf, &len, CTX_DATA->conn); + flush_buffer(buf, &len, idata->conn); } if (len) - flush_buffer(buf, &len, CTX_DATA->conn); + flush_buffer(buf, &len, idata->conn); - mutt_socket_write (CTX_DATA->conn, "\r\n"); + mutt_socket_write (idata->conn, "\r\n"); fclose (fp); do - { - if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0) - return (-1); + rc = imap_cmd_resp (idata); + while (rc == IMAP_CMD_CONTINUE); - if (buf[0] == '*' && imap_handle_untagged (CTX_DATA, buf) != 0) - return (-1); - } - while (mutt_strncmp (buf, CTX_DATA->seq, SEQLEN) != 0); - - if (!imap_code (buf)) + if (!imap_code (idata->buf)) { char *pc; - dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", buf)); - pc = buf + SEQLEN; + dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", idata->buf)); + pc = idata->buf + SEQLEN; SKIPWS (pc); pc = imap_next_word (pc); mutt_error ("%s", pc); @@ -497,6 +482,7 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg) * 1: non-fatal error - try fetch/append */ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete) { + IMAP_DATA* idata; char buf[HUGE_STRING]; char cmd[LONG_STRING]; char mbox[LONG_STRING]; @@ -505,6 +491,8 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete) int n; IMAP_MBOX mx; + idata = (IMAP_DATA*) ctx->data; + if (imap_parse_path (dest, &mx)) { dprint (1, (debugfile, "imap_copy_message: bad destination %s\n", dest)); @@ -519,12 +507,12 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete) return 1; } - imap_fix_path (CTX_DATA, mx.mbox, cmd, sizeof (cmd)); + imap_fix_path (idata, mx.mbox, cmd, sizeof (cmd)); /* Null HEADER* means copy tagged messages */ if (!h) { - rc = imap_make_msg_set (CTX_DATA, buf, sizeof (buf), M_TAG, 0); + rc = imap_make_msg_set (idata, buf, sizeof (buf), M_TAG, 0); if (!rc) { dprint (1, (debugfile, "imap_copy_messages: No messages tagged\n")); @@ -542,13 +530,13 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete) strncpy (mbox, cmd, sizeof (mbox)); imap_munge_mbox_name (mmbox, sizeof (mmbox), cmd); snprintf (cmd, sizeof (cmd), "UID COPY %s %s", buf, mmbox); - rc = imap_exec (buf, sizeof (buf), CTX_DATA, cmd, IMAP_CMD_FAIL_OK); + rc = imap_exec (idata, cmd, IMAP_CMD_FAIL_OK); if (rc == -2) { /* bail out if command failed for reasons other than nonexistent target */ - if (strncmp (imap_get_qualifier (buf), "[TRYCREATE]", 11)) + if (strncmp (imap_get_qualifier (idata->buf), "[TRYCREATE]", 11)) { - imap_error ("imap_copy_messages", buf); + imap_error ("imap_copy_messages", idata->buf); return -1; } dprint (2, (debugfile, "imap_copy_messages: server suggests TRYCREATE\n")); @@ -562,11 +550,11 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete) return -1; /* try again */ - rc = imap_exec (buf, sizeof (buf), CTX_DATA, cmd, 0); + rc = imap_exec (idata, cmd, 0); } if (rc != 0) { - imap_error ("imap_copy_messages", buf); + imap_error ("imap_copy_messages", idata->buf); return -1; } @@ -633,9 +621,12 @@ void imap_free_header_data (void** data) * -2 if the string is a corrupt fetch response */ static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp) { + IMAP_DATA* idata; long bytes; int rc = -1;