From 2526f63a480644c2b70494cbbbc3c9ce19f682f7 Mon Sep 17 00:00:00 2001 From: Thomas Roessler Date: Mon, 21 Aug 2000 11:30:28 +0000 Subject: [PATCH] patch-bac.command-2 --- imap/auth_anon.c | 4 +- imap/auth_cram.c | 4 +- imap/auth_gss.c | 10 +- imap/auth_login.c | 6 ++ imap/auth_sasl.c | 4 +- imap/browse.c | 2 +- imap/command.c | 182 ++++++++++++++++++++------------- imap/imap.c | 242 +++++--------------------------------------- imap/imap_private.h | 29 ++---- imap/message.c | 30 +++--- 10 files changed, 172 insertions(+), 341 deletions(-) diff --git a/imap/auth_anon.c b/imap/auth_anon.c index a7fd87ff..d9e48289 100644 --- a/imap/auth_anon.c +++ b/imap/auth_anon.c @@ -41,7 +41,7 @@ imap_auth_res_t imap_auth_anon (IMAP_DATA* idata) imap_cmd_start (idata, "AUTHENTICATE ANONYMOUS"); do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_RESPOND) @@ -53,7 +53,7 @@ imap_auth_res_t imap_auth_anon (IMAP_DATA* idata) mutt_socket_write (idata->conn, "ZHVtbXkK\r\n"); /* base64 ("dummy") */ do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_DONE) diff --git a/imap/auth_cram.c b/imap/auth_cram.c index 00e0f0d9..f41ef4c5 100644 --- a/imap/auth_cram.c +++ b/imap/auth_cram.c @@ -58,7 +58,7 @@ imap_auth_res_t imap_auth_cram_md5 (IMAP_DATA* idata) * correspond to that of an RFC 822 'msg-id' [RFC822] as described in [POP3]. */ do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_RESPOND) @@ -103,7 +103,7 @@ imap_auth_res_t imap_auth_cram_md5 (IMAP_DATA* idata) mutt_socket_write (idata->conn, ibuf); do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_DONE) diff --git a/imap/auth_gss.c b/imap/auth_gss.c index bf59c019..b1f03a37 100644 --- a/imap/auth_gss.c +++ b/imap/auth_gss.c @@ -90,7 +90,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) /* expect a null continuation response ("+") */ do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_RESPOND) @@ -127,7 +127,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) /* end authentication attempt */ mutt_socket_write (idata->conn, "*\r\n"); do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); goto bail; } @@ -142,7 +142,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) if (maj_stat == GSS_S_CONTINUE_NEEDED) { do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_RESPOND) @@ -163,7 +163,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) /* get security flags and buffer size */ do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_RESPOND) @@ -230,7 +230,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata) /* Joy of victory or agony of defeat? */ do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_DONE) { diff --git a/imap/auth_login.c b/imap/auth_login.c index 731f14f3..fff5baa6 100644 --- a/imap/auth_login.c +++ b/imap/auth_login.c @@ -29,6 +29,12 @@ imap_auth_res_t imap_auth_login (IMAP_DATA* idata) char buf[STRING]; int rc; + if (mutt_bit_isset (idata->capabilities, LOGINDISABLED)) + { + mutt_message _("LOGIN disabled on this server."); + return IMAP_AUTH_UNAVAIL; + } + if (mutt_account_getuser (&idata->conn->account)) return IMAP_AUTH_FAILURE; if (mutt_account_getpass (&idata->conn->account)) diff --git a/imap/auth_sasl.c b/imap/auth_sasl.c index 5e01331b..b628d8fc 100644 --- a/imap/auth_sasl.c +++ b/imap/auth_sasl.c @@ -98,7 +98,7 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata) while (rc == SASL_CONTINUE) { do - irc = imap_cmd_resp (idata); + irc = imap_cmd_step (idata); while (irc == IMAP_CMD_CONTINUE); if (irc == IMAP_CMD_FAIL) @@ -147,7 +147,7 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata) } while (irc != IMAP_CMD_DONE) - if ((irc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE) + if ((irc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; if (rc != SASL_OK) diff --git a/imap/browse.c b/imap/browse.c index 1571a705..cd3b0470 100644 --- a/imap/browse.c +++ b/imap/browse.c @@ -347,7 +347,7 @@ static int browse_get_namespace (IMAP_DATA* idata, char* nsbuf, int nsblen, do { - if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE) + if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; s = imap_next_word (idata->buf); diff --git a/imap/command.c b/imap/command.c index 609f04e6..a406c942 100644 --- a/imap/command.c +++ b/imap/command.c @@ -32,24 +32,43 @@ #define IMAP_CMD_BUFSIZE 512 /* forward declarations */ +static void cmd_finish (IMAP_DATA* idata); +static void cmd_handle_fatal (IMAP_DATA* idata); +static int cmd_handle_untagged (IMAP_DATA* idata); static void cmd_make_sequence (char* buf, size_t buflen); static void cmd_parse_capabilities (IMAP_DATA* idata, char* s); static void cmd_parse_expunge (IMAP_DATA* idata, char* s); static void cmd_parse_myrights (IMAP_DATA* idata, char* s); -static char *Capabilities[] = {"IMAP4", "IMAP4rev1", "STATUS", "ACL", - "NAMESPACE", "AUTH=CRAM-MD5", "AUTH=KERBEROS_V4", "AUTH=GSSAPI", - "AUTH=LOGIN", "AUTH-LOGIN", "AUTH=PLAIN", "AUTH=SKEY", "IDLE", - "LOGIN-REFERRALS", "MAILBOX-REFERRALS", "QUOTA", "SCAN", "SORT", - "THREAD=ORDEREDSUBJECT", "UIDPLUS", "AUTH=ANONYMOUS", NULL}; +static char *Capabilities[] = { + "IMAP4", + "IMAP4rev1", + "STATUS", + "ACL", + "NAMESPACE", + "AUTH=CRAM-MD5", + "AUTH=GSSAPI", + "AUTH=ANONYMOUS", + "STARTTLS", + "LOGINDISABLED", + + NULL +}; /* imap_cmd_start: Given an IMAP command, send it to the server. * Currently a minor convenience, but helps to route all IMAP commands * through a single interface. */ -void imap_cmd_start (IMAP_DATA* idata, const char* cmd) +int imap_cmd_start (IMAP_DATA* idata, const char* cmd) { char* out; int outlen; + int rc = 0; + + if (idata->status == IMAP_FATAL) + { + cmd_handle_fatal (idata); + return IMAP_CMD_FAIL; + } cmd_make_sequence (idata->seq, sizeof (idata->seq)); /* seq, space, cmd, \r\n\0 */ @@ -57,20 +76,28 @@ void imap_cmd_start (IMAP_DATA* idata, const char* cmd) out = (char*) safe_malloc (outlen); snprintf (out, outlen, "%s %s\r\n", idata->seq, cmd); - mutt_socket_write (idata->conn, out); + rc = mutt_socket_write (idata->conn, out); - safe_free ((void**) &out); + FREE (&out); + + return (rc < 0) ? IMAP_CMD_FAIL : 0; } -/* imap_cmd_resp: Reads server responses from an IMAP command, detects +/* imap_cmd_step: 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) +int imap_cmd_step (IMAP_DATA* idata) { unsigned int len = 0; int c; + if (idata->status == IMAP_FATAL) + { + cmd_handle_fatal (idata); + return IMAP_CMD_FAIL; + } + /* read into buffer, expanding buffer as necessary until we have a full * line */ do @@ -79,15 +106,14 @@ int imap_cmd_resp (IMAP_DATA* idata) { 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)); + dprint (3, (debugfile, "imap_cmd_step: 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, closing connection.\n")); + dprint (1, (debugfile, "imap_cmd_step: Error while reading server response, closing connection.\n")); mutt_socket_close (idata->conn); - idata->state = IMAP_DISCONNECTED; idata->status = IMAP_FATAL; return IMAP_CMD_FAIL; } @@ -104,12 +130,12 @@ int imap_cmd_resp (IMAP_DATA* idata) { 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)); + dprint (3, (debugfile, "imap_cmd_step: 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)) + cmd_handle_untagged (idata)) return IMAP_CMD_FAIL; /* server demands a continuation response from us */ @@ -119,59 +145,13 @@ int imap_cmd_resp (IMAP_DATA* idata) /* tagged completion code */ if (!mutt_strncmp (idata->buf, idata->seq, SEQLEN)) { - imap_cmd_finish (idata); + 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) */ -void imap_cmd_finish (IMAP_DATA* idata) -{ - if (!(idata->state == IMAP_SELECTED) || idata->ctx->closing) - { - idata->status = 0; - mutt_clear_error (); - return; - } - - if ((idata->status == IMAP_NEW_MAIL || - (idata->reopen & (IMAP_EXPUNGE_PENDING|IMAP_NEWMAIL_PENDING))) - && (idata->reopen & IMAP_REOPEN_ALLOW)) - { - int count = idata->newMailCount; - - if (!(idata->reopen & IMAP_EXPUNGE_PENDING) && - ((idata->status == IMAP_NEW_MAIL) || (idata->reopen & IMAP_NEWMAIL_PENDING)) - && count > idata->ctx->msgcount) - { - /* read new mail messages */ - dprint (1, (debugfile, "imap_cmd_finish: fetching new mail\n")); - - count = imap_read_headers (idata->ctx, idata->ctx->msgcount, count-1)+1; - idata->check_status = IMAP_NEW_MAIL; - idata->reopen &= ~IMAP_NEWMAIL_PENDING; - } - else - { - imap_expunge_mailbox (idata); - idata->check_status = IMAP_REOPENED; - idata->reopen &= ~(IMAP_EXPUNGE_PENDING|IMAP_NEWMAIL_PENDING); - } - - } - else if (!(idata->reopen & IMAP_REOPEN_ALLOW)) - { - if (idata->status == IMAP_NEW_MAIL) - idata->reopen |= IMAP_NEWMAIL_PENDING; - } - - idata->status = 0; -} - /* imap_code: returns 1 if the command result was OK, or 0 if NO or BAD */ int imap_code (const char *s) { @@ -194,6 +174,12 @@ int imap_exec (IMAP_DATA* idata, const char* cmd, int flags) int outlen; int rc; + if (idata->status == IMAP_FATAL) + { + cmd_handle_fatal (idata); + return -1; + } + /* create sequence for command */ cmd_make_sequence (idata->seq, sizeof (idata->seq)); /* seq, space, cmd, \r\n\0 */ @@ -201,13 +187,15 @@ int imap_exec (IMAP_DATA* idata, const char* cmd, int flags) out = (char*) safe_malloc (outlen); snprintf (out, outlen, "%s %s\r\n", idata->seq, cmd); - mutt_socket_write_d (idata->conn, out, + rc = mutt_socket_write_d (idata->conn, out, flags & IMAP_CMD_PASS ? IMAP_LOG_PASS : IMAP_LOG_CMD); - safe_free ((void**) &out); + if (rc < 0) + return -1; + do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_DONE) @@ -232,13 +220,62 @@ int imap_exec (IMAP_DATA* idata, const char* cmd, int flags) return 0; } -/* imap_handle_untagged: fallback parser for otherwise unhandled messages. */ -int imap_handle_untagged (IMAP_DATA* idata, char* s) +/* 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). Called automatically by imap_cmd_step */ +static void cmd_finish (IMAP_DATA* idata) { - char *pn; + if (!(idata->state == IMAP_SELECTED) || idata->ctx->closing) + { + mutt_clear_error (); + return; + } + + if ((idata->reopen & IMAP_REOPEN_ALLOW) && + (idata->reopen & (IMAP_EXPUNGE_PENDING|IMAP_NEWMAIL_PENDING))) + { + int count = idata->newMailCount; + + if (!(idata->reopen & IMAP_EXPUNGE_PENDING) && + (idata->reopen & IMAP_NEWMAIL_PENDING) + && count > idata->ctx->msgcount) + { + /* read new mail messages */ + dprint (2, (debugfile, "cmd_finish: Fetching new mail\n")); + count = imap_read_headers (idata, idata->ctx->msgcount, count-1)+1; + /* check_status: curs_main uses imap_check_mailbox to detect + * whether the index needs updating */ + idata->check_status = IMAP_NEWMAIL_PENDING; + idata->reopen &= ~IMAP_NEWMAIL_PENDING; + } + else + { + dprint (2, (debugfile, "cmd_finish: Expunging mailbox\n")); + imap_expunge_mailbox (idata); + idata->reopen &= ~(IMAP_EXPUNGE_PENDING|IMAP_NEWMAIL_PENDING); + } + } + + idata->status = 0; +} + +/* cmd_handle_fatal: when IMAP_DATA is in fatal state, do what we can */ +static void cmd_handle_fatal (IMAP_DATA* idata) +{ + if ((idata->state == IMAP_SELECTED) && + (idata->reopen & IMAP_REOPEN_ALLOW) && + !idata->ctx->closing) + mx_fastclose_mailbox (idata->ctx); +} + +/* cmd_handle_untagged: fallback parser for otherwise unhandled messages. */ +static int cmd_handle_untagged (IMAP_DATA* idata) +{ + char* s; + char* pn; int count; - s = imap_next_word (s); + s = imap_next_word (idata->buf); if ((idata->state == IMAP_SELECTED) && isdigit (*s)) { @@ -263,22 +300,21 @@ int imap_handle_untagged (IMAP_DATA* idata, char* s) */ mutt_error _("Fatal error. Message count is out of sync!"); idata->status = IMAP_FATAL; - mx_fastclose_mailbox (idata->ctx); return -1; } /* at least the InterChange server sends EXISTS messages freely, * even when there is no new mail */ else if (count == idata->ctx->msgcount) dprint (3, (debugfile, - "imap_handle_untagged: superfluous EXISTS message.\n")); + "cmd_handle_untagged: superfluous EXISTS message.\n")); else { if (!(idata->reopen & IMAP_EXPUNGE_PENDING)) { dprint (2, (debugfile, - "imap_handle_untagged: New mail in %s - %d messages total.\n", + "cmd_handle_untagged: New mail in %s - %d messages total.\n", idata->mailbox, count)); - idata->status = IMAP_NEW_MAIL; + idata->reopen |= IMAP_NEWMAIL_PENDING; } idata->newMailCount = count; } diff --git a/imap/imap.c b/imap/imap.c index 86ec6511..c122df69 100644 --- a/imap/imap.c +++ b/imap/imap.c @@ -231,210 +231,6 @@ void imap_expunge_mailbox (IMAP_DATA* idata) mutt_sort_headers (idata->ctx, 1); } -#if 0 -/* imap_reopen_mailbox: Reopen an imap mailbox. This is used when the - * server sends an EXPUNGE message, indicating that some messages may have - * been deleted. This is a heavy handed approach, as it reparses all of the - * headers, but it should guarantee correctness. Later, we might implement - * something to actually only remove the messages that are marked - * EXPUNGE. - */ -int imap_reopen_mailbox (IMAP_DATA* idata) -{ - HEADER **old_hdrs; - CONTEXT* ctx; - int old_msgcount; - char buf[LONG_STRING]; - char bufout[LONG_STRING]; - char *pc = NULL; - int count = 0; - int msg_mod = 0; - int n; - int i, j; - int index_hint_set; - - ctx = idata->ctx; - - ctx->quiet = 1; - - if (Sort != SORT_ORDER) - { - short old_sort; - - old_sort = Sort; - Sort = SORT_ORDER; - mutt_sort_headers (ctx, 1); - Sort = old_sort; - } - - old_hdrs = NULL; - old_msgcount = 0; - - /* simulate a close */ - hash_destroy (&ctx->id_hash, NULL); - hash_destroy (&ctx->subj_hash, NULL); - safe_free ((void **) &ctx->v2r); - if (ctx->readonly) - { - for (i = 0; i < ctx->msgcount; i++) - mutt_free_header (&(ctx->hdrs[i])); /* nothing to do! */ - safe_free ((void **) &ctx->hdrs); - } - else - { - /* save the old headers */ - old_msgcount = ctx->msgcount; - old_hdrs = ctx->hdrs; - ctx->hdrs = NULL; - } - - ctx->hdrmax = 0; /* force allocation of new headers */ - ctx->msgcount = 0; - ctx->vcount = 0; - ctx->tagged = 0; - ctx->deleted = 0; - ctx->new = 0; - ctx->unread = 0; - ctx->flagged = 0; - ctx->changed = 0; - ctx->id_hash = hash_create (1031); - ctx->subj_hash = hash_create (1031); - - mutt_message (_("Reopening mailbox... %s"), CTX_DATA->mailbox); - imap_munge_mbox_name (buf, sizeof (buf), CTX_DATA->mailbox); - snprintf (bufout, sizeof (bufout), "STATUS %s (MESSAGES)", buf); - - imap_cmd_start (CTX_DATA, bufout); - - do - { - if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0) - break; - - if (buf[0] == '*') - { - pc = buf + 2; - - if (!mutt_strncasecmp ("STATUS", pc, 6) && - (pc = (char *) mutt_stristr (pc, "MESSAGES"))) - { - char* pn; - - /* skip "MESSAGES" */ - pc += 8; - SKIPWS (pc); - pn = pc; - - while (*pc && isdigit (*pc)) - pc++; - *pc++ = 0; - n = atoi (pn); - count = n; - } - else if (imap_handle_untagged (CTX_DATA, buf) != 0) - return -1; - } - } - while (mutt_strncmp (CTX_DATA->seq, buf, mutt_strlen (CTX_DATA->seq)) != 0); - - if (!imap_code (buf)) - { - char *s; - s = imap_next_word (buf); /* skip seq */ - s = imap_next_word (s); /* Skip response */ - mutt_error ("%s", s); - sleep (1); - return -1; - } - - ctx->hdrmax = count; - ctx->hdrs = safe_malloc (count * sizeof (HEADER *)); - ctx->v2r = safe_malloc (count * sizeof (int)); - ctx->msgcount = 0; - count = imap_read_headers (ctx, 0, count - 1) + 1; - - index_hint_set = 1; - - if (!ctx->readonly) - { - for (i = 0; i < ctx->msgcount; i++) - { - int found = 0; - - /* some messages have been deleted, and new messages have been - * appended at the end; the heuristic is that old messages have then - * "advanced" towards the beginning of the folder, so we begin the - * search at index "i" - */ - for (j = i; j < old_msgcount; j++) - { - if (old_hdrs[j] == NULL) - continue; - if (mbox_strict_cmp_headers (ctx->hdrs[i], old_hdrs[j])) - { - found = 1; - break; - } - } - if (!found) - { - for (j = 0; j < i && j < old_msgcount; j++) - { - if (old_hdrs[j] == NULL) - continue; - if (mbox_strict_cmp_headers (ctx->hdrs[i], old_hdrs[j])) - { - found = 1; - break; - } - } - } - if (found) - { - /* this is best done here */ -/* - if (!index_hint_set && *index_hint == j) - *index_hint = i; -*/ - - if (old_hdrs[j]->changed) - { - /* Only update the flags if the old header was changed; - * otherwise, the header may have been modified - * externally, and we don't want to lose _those_ changes - */ - - mutt_set_flag (ctx, ctx->hdrs[i], M_FLAG, old_hdrs[j]->flagged); - mutt_set_flag (ctx, ctx->hdrs[i], M_REPLIED, old_hdrs[j]->replied); - mutt_set_flag (ctx, ctx->hdrs[i], M_OLD, old_hdrs[j]->old); - mutt_set_flag (ctx, ctx->hdrs[i], M_READ, old_hdrs[j]->read); - } - mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, old_hdrs[j]->deleted); - mutt_set_flag (ctx, ctx->hdrs[i], M_TAG, old_hdrs[j]->tagged); - - /* we don't need this header any more */ - mutt_free_header (&(old_hdrs[j])); - } - } - - /* free the remaining old headers */ - for (j = 0; j < old_msgcount; j++) - { - if (old_hdrs[j]) - { - mutt_free_header (&(old_hdrs[j])); - msg_mod = 1; - } - } - safe_free ((void **) &old_hdrs); - } - - ctx->quiet = 0; - - return 0; -} -#endif - static int imap_get_delim (IMAP_DATA *idata) { char *s; @@ -448,7 +244,7 @@ static int imap_get_delim (IMAP_DATA *idata) do { - if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE) + if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; s = imap_next_word (idata->buf); @@ -572,7 +368,7 @@ int imap_open_connection (IMAP_DATA* idata) idata->state = IMAP_CONNECTED; - if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE) + if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE) goto bail; if (mutt_strncmp ("* OK", idata->buf, 4) == 0) @@ -685,6 +481,9 @@ int imap_open_mailbox (CONTEXT* ctx) /* once again the context is new */ ctx->data = idata; + if (idata->status == IMAP_FATAL) + return -1; + /* Clean up path and replace the one in the ctx */ imap_fix_path (idata, mx.mbox, buf, sizeof (buf)); FREE(&(idata->mailbox)); @@ -713,7 +512,7 @@ int imap_open_mailbox (CONTEXT* ctx) { char *pc; - if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE) + if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; pc = idata->buf + 2; @@ -722,7 +521,7 @@ int imap_open_mailbox (CONTEXT* ctx) { /* imap_handle_untagged will have picked up the EXISTS message and * set the NEW_MAIL flag. We clear it here. */ - idata->status = 0; + idata->reopen &= ~IMAP_NEWMAIL_PENDING; count = idata->newMailCount; idata->newMailCount = 0; } @@ -821,7 +620,7 @@ int imap_open_mailbox (CONTEXT* ctx) ctx->hdrs = safe_malloc (count * sizeof (HEADER *)); ctx->v2r = safe_malloc (count * sizeof (int)); ctx->msgcount = 0; - count = imap_read_headers (ctx, 0, count - 1) + 1; + count = imap_read_headers (idata, 0, count - 1) + 1; dprint (1, (debugfile, "imap_open_mailbox(): msgcount is %d\n", ctx->msgcount)); return 0; @@ -894,7 +693,7 @@ void imap_logout (IMAP_DATA* idata) * receive a bye response (so it doesn't freak out and close the conn) */ idata->status = IMAP_BYE; imap_cmd_start (idata, "LOGOUT"); - while (imap_cmd_resp (idata) == IMAP_CMD_CONTINUE) + while (imap_cmd_step (idata) == IMAP_CMD_CONTINUE) ; } @@ -1167,7 +966,9 @@ void imap_close_mailbox (CONTEXT* ctx) idata->reopen &= IMAP_REOPEN_ALLOW; - if ((idata->state == IMAP_SELECTED) && (ctx == idata->ctx)) + if ((idata->status != IMAP_FATAL) && + (idata->state == IMAP_SELECTED) && + (ctx == idata->ctx)) { if (!(idata->noclose) && imap_exec (idata, "CLOSE", 0)) imap_error ("CLOSE failed", idata->buf); @@ -1193,7 +994,7 @@ void imap_close_mailbox (CONTEXT* ctx) /* use the NOOP command to poll for new mail * * return values: - * M_REOPENED mailbox has been reopened + * M_REOPENED mailbox has been externally modified * M_NEW_MAIL new mail has arrived! * 0 no change * -1 error @@ -1224,17 +1025,20 @@ int imap_check_mailbox (CONTEXT *ctx, int *index_hint) { if (ImapCheckTimeout) checktime += t; - idata->check_status = 0; if (imap_exec (idata, "NOOP", 0) != 0) { imap_error ("imap_check_mailbox", idata->buf); return -1; } - if (idata->check_status == IMAP_NEW_MAIL) + if (idata->check_status & IMAP_NEWMAIL_PENDING) + { + idata->check_status &= ~IMAP_NEWMAIL_PENDING; return M_NEW_MAIL; - if (idata->check_status == IMAP_REOPENED) - return M_REOPENED; + } + + /* TODO: we should be able to detect external changes and return + * M_REOPENED here. */ } return 0; @@ -1305,7 +1109,7 @@ int imap_mailbox_check (char* path, int new) do { - if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE) + if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; s = imap_next_word (idata->buf); @@ -1352,7 +1156,7 @@ int imap_parse_list_response(IMAP_DATA* idata, char **name, int *noselect, *name = NULL; - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); if (rc == IMAP_CMD_DONE) return 0; if (rc != IMAP_CMD_CONTINUE) @@ -1400,7 +1204,7 @@ int imap_parse_list_response(IMAP_DATA* idata, char **name, int *noselect, { if (imap_get_literal_count(idata->buf, &bytes) < 0) return -1; - if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE) + if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE) return -1; *name = idata->buf; } diff --git a/imap/imap_private.h b/imap/imap_private.h index 412e9521..b574ee81 100644 --- a/imap/imap_private.h +++ b/imap/imap_private.h @@ -54,7 +54,6 @@ enum { IMAP_FATAL = 1, - IMAP_NEW_MAIL, IMAP_BYE, IMAP_REOPENED }; @@ -92,7 +91,7 @@ enum RIGHTSMAX }; -/* Capabilities */ +/* Capabilities we are interested in */ enum { IMAP4 = 0, @@ -101,21 +100,10 @@ enum ACL, /* RFC 2086: IMAP4 ACL extension */ NAMESPACE, /* RFC 2342: IMAP4 Namespace */ ACRAM_MD5, /* RFC 2195: CRAM-MD5 authentication */ - AKERBEROS_V4, /* AUTH=KERBEROS_V4 */ AGSSAPI, /* RFC 1731: GSSAPI authentication */ - /* From here down, we don't care */ - ALOGIN, /* AUTH=LOGIN */ - AUTH_LOGIN, /* AUTH-LOGIN */ - APLAIN, /* AUTH=PLAIN */ - ASKEY, /* AUTH=SKEY */ - IDLE, /* RFC 2177: IMAP4 IDLE command */ - LOGIN_REFERRALS, /* LOGIN-REFERRALS */ - MAILBOX_REFERRALS, /* MAILBOX-REFERRALS */ - SCAN, - SORT, - TORDEREDSUBJECT, /* THREAD=ORDEREDSUBJECT */ - UIDPLUS, /* RFC 2859: IMAP4 UIDPLUS extension */ AUTH_ANON, /* AUTH=ANONYMOUS */ + STARTTLS, /* RFC 2595: STARTTLS */ + LOGINDISABLED, /* LOGINDISABLED */ CAPMAX }; @@ -149,7 +137,6 @@ typedef struct CONNECTION *conn; unsigned char state; unsigned char status; - unsigned char check_status; unsigned char capabilities[(CAPMAX + 7)/8]; char seq[SEQLEN+1]; /* command input buffer */ @@ -169,6 +156,7 @@ typedef struct char delim; CONTEXT *ctx; char *mailbox; + unsigned short check_status; unsigned char reopen; unsigned char rights[(RIGHTSMAX + 7)/8]; unsigned int newMailCount; @@ -193,24 +181,21 @@ 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); void imap_logout (IMAP_DATA* idata); /* auth.c */ 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_cmd_start (IMAP_DATA* idata, const char* cmd); +int imap_cmd_step (IMAP_DATA* idata); int imap_code (const char* s); int imap_exec (IMAP_DATA* idata, const char* cmd, int flags); -int imap_handle_untagged (IMAP_DATA* idata, char* s); /* message.c */ void imap_add_keywords (char* s, HEADER* keywords, LIST* mailbox_flags); void imap_free_header_data (void** data); -int imap_read_headers (CONTEXT* ctx, int msgbegin, int msgend); +int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend); /* util.c */ int imap_continue (const char* msg, const char* resp); diff --git a/imap/message.c b/imap/message.c index 74c4da85..ad25e918 100644 --- a/imap/message.c +++ b/imap/message.c @@ -43,9 +43,9 @@ static char* msg_parse_flags (IMAP_HEADER* h, char* s); * msgno of the last message read. It will return a value other than * msgend if mail comes in while downloading headers (in theory). */ -int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) +int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend) { - IMAP_DATA* idata; + CONTEXT* ctx; char buf[LONG_STRING]; char hdrreq[STRING]; FILE *fp; @@ -56,8 +56,8 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) 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; - + ctx = idata->ctx; + /* define search string */ if (mutt_bit_isset (idata->capabilities,IMAP4REV1)) { @@ -84,8 +84,8 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) unlink (tempfile); /* make sure context has room to hold the mailbox */ - while ((msgend) >= ctx->hdrmax) - mx_alloc_memory (ctx); + while ((msgend) >= idata->ctx->hdrmax) + mx_alloc_memory (idata->ctx); for (msgno = msgbegin; msgno <= msgend ; msgno++) { @@ -123,11 +123,11 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) { mfhrc = 0; - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); if (rc != IMAP_CMD_CONTINUE) break; - if ((mfhrc = msg_fetch_header (ctx, &h, idata->buf, fp)) == -1) + if ((mfhrc = msg_fetch_header (idata->ctx, &h, idata->buf, fp)) == -1) continue; else if (mfhrc < 0) break; @@ -175,12 +175,12 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) /* h.data shouldn't be freed here, it is kept in ctx->headers */ /* in case we get new mail while fetching the headers */ - if (idata->status == IMAP_NEW_MAIL) + if (idata->reopen & IMAP_NEWMAIL_PENDING) { msgend = idata->newMailCount - 1; while ((msgend) >= ctx->hdrmax) mx_alloc_memory (ctx); - idata->status = 0; + idata->status &= ~IMAP_NEWMAIL_PENDING; } } @@ -247,7 +247,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) imap_cmd_start (idata, buf); do { - if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE) + if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; pc = idata->buf; @@ -279,7 +279,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) if (imap_read_literal (msg->fp, idata, bytes) < 0) goto bail; /* pick up trailing line */ - if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE) + if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) goto bail; pc = idata->buf; @@ -423,7 +423,7 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg) imap_cmd_start (idata, buf); do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (rc != IMAP_CMD_RESPOND) @@ -461,7 +461,7 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg) fclose (fp); do - rc = imap_cmd_resp (idata); + rc = imap_cmd_step (idata); while (rc == IMAP_CMD_CONTINUE); if (!imap_code (idata->buf)) @@ -663,7 +663,7 @@ static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp) * (eg Domino puts FLAGS here). Nothing wrong with that, either. * This all has to go - we should accept literals and nonliterals * interchangeably at any time. */ - if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE) + if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE) return -2; if (msg_parse_fetch (h, idata->buf) == -1) -- 2.40.0