From cc96d995fc2549ec264c1b02c8464a8816f83df9 Mon Sep 17 00:00:00 2001 From: Brendan Cully <brendan@kublai.com> Date: Mon, 19 Dec 2005 17:07:59 +0000 Subject: [PATCH] Replace imap_parse_list_response with a proper untagged response handler. --- imap/browse.c | 71 +++++++++++------------- imap/command.c | 129 ++++++++++++++++++++++++++++---------------- imap/imap.c | 103 ++++------------------------------- imap/imap_private.h | 12 ++++- 4 files changed, 134 insertions(+), 181 deletions(-) diff --git a/imap/browse.c b/imap/browse.c index fb5d8b3bd..5e8b38200 100644 --- a/imap/browse.c +++ b/imap/browse.c @@ -45,6 +45,7 @@ static int browse_verify_namespace (IMAP_DATA* idata, int imap_browse (char* path, struct browser_state* state) { IMAP_DATA* idata; + IMAP_LIST list; char buf[LONG_STRING]; char buf2[LONG_STRING]; char nsbuf[LONG_STRING]; @@ -57,10 +58,7 @@ int imap_browse (char* path, struct browser_state* state) int nsup; char ctmp; int nns = 0; - char *cur_folder; short showparents = 0; - int noselect; - int noinferiors; int save_lsub; IMAP_MBOX mx; @@ -114,29 +112,26 @@ int imap_browse (char* path, struct browser_state* state) { snprintf (buf, sizeof (buf), "%s \"\" \"%s\"", list_cmd, mbox); imap_cmd_start (idata, buf); - do + idata->cmddata = &list; + do { - if ((rc = imap_parse_list_response (idata, &cur_folder, &noselect, - &noinferiors, &idata->delim)) == IMAP_CMD_BAD) - goto fail; - - if (cur_folder) + rc = imap_cmd_step (idata); + if (rc == IMAP_CMD_CONTINUE && list.name) { - imap_unmunge_mbox_name (cur_folder); - - if (!noinferiors && cur_folder[0] && + if (!list.noinferiors && list.name[0] && (n = strlen (mbox)) < LONG_STRING-1) { - mbox[n++] = idata->delim; + mbox[n++] = list.delim; mbox[n] = '\0'; } } } while (rc == IMAP_CMD_CONTINUE); + idata->cmddata = NULL; } /* if we're descending a folder, mark it as current in browser_state */ - if (mbox[n-1] == idata->delim) + if (mbox[n-1] == list.delim) { /* don't show parents in the home namespace */ if (!home_namespace) @@ -152,7 +147,7 @@ int imap_browse (char* path, struct browser_state* state) * and tack on delimiter ourselves. * Further note: UW-IMAP servers return nothing when asked for * NAMESPACES without delimiters at the end. Argh! */ - for (n--; n >= 0 && mbox[n] != idata->delim ; n--); + for (n--; n >= 0 && mbox[n] != list.delim ; n--); if (n > 0) /* "aaaa/bbbb/" -> "aaaa" */ { /* forget the check, it is too delicate (see above). Have we ever @@ -163,7 +158,7 @@ int imap_browse (char* path, struct browser_state* state) if (showparents) { dprint (3, (debugfile, "imap_init_browse: adding parent %s\n", mbox)); - imap_add_folder (idata->delim, mbox, 1, 0, state, 1); + imap_add_folder (list.delim, mbox, 1, 0, state, 1); } /* if our target isn't a folder, we are in our superior */ @@ -362,9 +357,7 @@ int imap_mailbox_rename(const char* mailbox) static int browse_add_list_result (IMAP_DATA* idata, const char* cmd, struct browser_state* state, short isparent) { - char *name; - int noselect; - int noinferiors; + IMAP_LIST list; IMAP_MBOX mx; int rc; @@ -376,31 +369,27 @@ static int browse_add_list_result (IMAP_DATA* idata, const char* cmd, } imap_cmd_start (idata, cmd); - - do + idata->cmddata = &list; + do { - if ((rc = imap_parse_list_response(idata, &name, &noselect, &noinferiors, - &idata->delim)) == IMAP_CMD_BAD) - { - FREE (&mx.mbox); - return -1; - } + rc = imap_cmd_step (idata); - if (name) + if (rc == IMAP_CMD_CONTINUE && list.name) { /* Let a parent folder never be selectable for navigation */ if (isparent) - noselect = 1; + list.noselect = 1; /* prune current folder from output */ - if (isparent || mutt_strncmp (name, mx.mbox, strlen (name))) - imap_add_folder (idata->delim, name, noselect, noinferiors, state, - isparent); + if (isparent || mutt_strncmp (list.name, mx.mbox, strlen (list.name))) + imap_add_folder (list.delim, list.name, list.noselect, list.noinferiors, + state, isparent); } } while (rc == IMAP_CMD_CONTINUE); + idata->cmddata = NULL; FREE (&mx.mbox); - return 0; + return rc == IMAP_CMD_OK ? 0 : -1; } /* imap_add_folder: add a folder name to the browser list, formatting it as @@ -581,9 +570,8 @@ static int browse_verify_namespace (IMAP_DATA* idata, IMAP_NAMESPACE_INFO *nsi, int nns) { char buf[LONG_STRING]; + IMAP_LIST list; int i = 0; - char *name; - char delim; int rc; for (i = 0; i < nns; i++, nsi++) @@ -600,17 +588,20 @@ static int browse_verify_namespace (IMAP_DATA* idata, option (OPTIMAPLSUB) ? "LSUB" : "LIST", nsi->prefix); imap_cmd_start (idata, buf); - + idata->cmddata = &list; nsi->listable = 0; nsi->home_namespace = 0; do { - if ((rc = imap_parse_list_response(idata, &name, &nsi->noselect, - &nsi->noinferiors, &delim)) == IMAP_CMD_BAD) - return -1; - nsi->listable |= (name != NULL); + rc = imap_cmd_step (idata); + if (rc == IMAP_CMD_CONTINUE && list.name) + nsi->listable |= (list.name[0] != '\0'); } while (rc == IMAP_CMD_CONTINUE); + idata->cmddata = NULL; + + if (rc != IMAP_CMD_OK) + return -1; } return 0; diff --git a/imap/command.c b/imap/command.c index e8d5f4d51..64c819e87 100644 --- a/imap/command.c +++ b/imap/command.c @@ -43,6 +43,7 @@ static void cmd_handle_fatal (IMAP_DATA* idata); static int cmd_handle_untagged (IMAP_DATA* idata); static void cmd_parse_capabilities (IMAP_DATA* idata, char* s); static void cmd_parse_expunge (IMAP_DATA* idata, const char* s); +static void cmd_parse_list (IMAP_DATA* idata, char* s); static void cmd_parse_lsub (IMAP_DATA* idata, char* s); static void cmd_parse_fetch (IMAP_DATA* idata, char* s); static void cmd_parse_myrights (IMAP_DATA* idata, const char* s); @@ -412,6 +413,8 @@ static int cmd_handle_untagged (IMAP_DATA* idata) } else if (ascii_strncasecmp ("CAPABILITY", s, 10) == 0) cmd_parse_capabilities (idata, s); + else if (ascii_strncasecmp ("LIST", s, 4) == 0) + cmd_parse_list (idata, s); else if (ascii_strncasecmp ("LSUB", s, 4) == 0) cmd_parse_lsub (idata, s); else if (ascii_strncasecmp ("MYRIGHTS", s, 8) == 0) @@ -563,63 +566,97 @@ static void cmd_parse_fetch (IMAP_DATA* idata, char* s) } } -static void cmd_parse_lsub (IMAP_DATA* idata, char* s) +static void cmd_parse_list (IMAP_DATA* idata, char* s) { - char buf[STRING]; - char errstr[STRING]; - BUFFER err, token; - ciss_url_t url; - char *ep; + IMAP_LIST* list; + char delimbuf[5]; /* worst case: "\\"\0 */ - if (!option (OPTIMAPCHECKSUBSCRIBED)) + if (!idata->cmddata) + { + dprint (2, (debugfile, "Ignoring LIST response\n")); return; + } - s = imap_next_word (s); /* flags */ - + list = (IMAP_LIST*)idata->cmddata; + memset (list, 0, sizeof (IMAP_LIST)); + + /* flags */ + s = imap_next_word (s); if (*s != '(') { - dprint (1, (debugfile, "Bad LSUB response\n")); + dprint (1, (debugfile, "Bad LIST response\n")); return; } - s++; - ep = s; - for (ep = s; *ep && *ep != ')'; ep++) - ; - do + while (*s) { if (!ascii_strncasecmp (s, "\\NoSelect", 9)) - return; - while (s < ep && *s != ' ' && *s != ')') - s++; - if (*s == ' ') - s++; - } while (s != ep); - - s = imap_next_word (s); /* delim */ - s = imap_next_word (s); /* name */ - - if (s) - { - imap_unmunge_mbox_name (s); - dprint (2, (debugfile, "Subscribing to %s\n", s)); + list->noselect = 1; + else if (!ascii_strncasecmp (s, "\\NoInferiors", 12)) + list->noinferiors = 1; + /* See draft-gahrns-imap-child-mailbox-?? */ + else if (!ascii_strncasecmp (s, "\\HasNoChildren", 14)) + list->noinferiors = 1; - strfcpy (buf, "mailboxes \"", sizeof (buf)); - mutt_account_tourl (&idata->conn->account, &url); - url.path = s; - if (!mutt_strcmp (url.user, ImapUser)) - url.user = NULL; - url_ciss_tostring (&url, buf + 11, sizeof (buf) - 10, 0); - safe_strcat (buf, sizeof (buf), "\""); - memset (&token, 0, sizeof (token)); - err.data = errstr; - err.dsize = sizeof (errstr); - if (mutt_parse_rc_line (buf, &token, &err)) - dprint (1, (debugfile, "Error adding subscribed mailbox: %s\n", errstr)); - FREE (&token.data); - } - else - dprint (1, (debugfile, "Bad LSUB response\n")); + s = imap_next_word (s); + if (*(s - 2) == ')') + break; + } + + /* Delimiter */ + if (ascii_strncasecmp (s, "NIL", 3)) + { + delimbuf[0] = '\0'; + safe_strcat (delimbuf, 5, s); + imap_unquote_string (delimbuf); + list->delim = delimbuf[0]; + } + + /* Name */ + s = imap_next_word (s); + imap_unmunge_mbox_name (s); + list->name = s; +} + +static void cmd_parse_lsub (IMAP_DATA* idata, char* s) +{ + char buf[STRING]; + char errstr[STRING]; + BUFFER err, token; + ciss_url_t url; + IMAP_LIST list; + + if (idata->cmddata) + { + /* caller will handle response itself */ + cmd_parse_list (idata, s); + return; + } + + if (!option (OPTIMAPCHECKSUBSCRIBED)) + return; + + idata->cmddata = &list; + cmd_parse_list (idata, s); + idata->cmddata = NULL; + if (!list.name) + return; + + dprint (2, (debugfile, "Subscribing to %s\n", list.name)); + + strfcpy (buf, "mailboxes \"", sizeof (buf)); + mutt_account_tourl (&idata->conn->account, &url); + url.path = list.name; + if (!mutt_strcmp (url.user, ImapUser)) + url.user = NULL; + url_ciss_tostring (&url, buf + 11, sizeof (buf) - 10, 0); + safe_strcat (buf, sizeof (buf), "\""); + memset (&token, 0, sizeof (token)); + err.data = errstr; + err.dsize = sizeof (errstr); + if (mutt_parse_rc_line (buf, &token, &err)) + dprint (1, (debugfile, "Error adding subscribed mailbox: %s\n", errstr)); + FREE (&token.data); } /* cmd_parse_myrights: set rights bits according to MYRIGHTS response */ @@ -714,8 +751,6 @@ static void cmd_parse_status (IMAP_DATA* idata, char* s) IMAP_STATUS *status, sb; int olduv, oldun; - dprint (2, (debugfile, "Handling STATUS\n")); - mailbox = imap_next_word (s); s = imap_next_word (mailbox); *(s - 1) = '\0'; diff --git a/imap/imap.c b/imap/imap.c index 4a2eef742..c2956b298 100644 --- a/imap/imap.c +++ b/imap/imap.c @@ -1573,82 +1573,6 @@ int imap_search (CONTEXT* ctx, const pattern_t* pat) return 0; } -/* 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; - - rc = imap_cmd_step (idata); - if (rc == IMAP_CMD_OK) - return rc; - if (rc != IMAP_CMD_CONTINUE) - return IMAP_CMD_BAD; - - s = imap_next_word (idata->buf); - if ((ascii_strncasecmp ("LIST", s, 4) == 0) || - (ascii_strncasecmp ("LSUB", s, 4) == 0)) - { - *noselect = 0; - *noinferiors = 0; - - s = imap_next_word (s); /* flags */ - if (*s == '(') - { - char *ep; - - s++; - ep = s; - while (*ep && *ep != ')') ep++; - do - { - if (!ascii_strncasecmp (s, "\\NoSelect", 9)) - *noselect = 1; - if (!ascii_strncasecmp (s, "\\NoInferiors", 12)) - *noinferiors = 1; - /* See draft-gahrns-imap-child-mailbox-?? */ - if (!ascii_strncasecmp (s, "\\HasNoChildren", 14)) - *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 (ascii_strncasecmp (s, "NIL", 3)) - { - 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 IMAP_CMD_BAD; - if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE) - return IMAP_CMD_BAD; - *name = idata->buf; - } - else - *name = s; - } - - return IMAP_CMD_CONTINUE; -} - int imap_subscribe (char *path, int subscribe) { CONNECTION *conn; @@ -1776,9 +1700,7 @@ int imap_complete(char* dest, size_t dlen, char* path) { IMAP_DATA* idata; char list[LONG_STRING]; char buf[LONG_STRING]; - char* list_word = NULL; - int noselect, noinferiors; - char delim; + IMAP_LIST listresp; char completion[LONG_STRING]; int clen, matchlen = 0; int completions = 0; @@ -1816,39 +1738,36 @@ int imap_complete(char* dest, size_t dlen, char* path) { /* and see what the results are */ strfcpy (completion, NONULL(mx.mbox), sizeof(completion)); + idata->cmddata = &listresp; do { - if ((rc = imap_parse_list_response(idata, &list_word, &noselect, &noinferiors, - &delim)) == IMAP_CMD_BAD) - break; + rc = imap_cmd_step (idata); - if (list_word) + if (rc == IMAP_CMD_CONTINUE && listresp.name) { - /* store unquoted */ - imap_unmunge_mbox_name (list_word); - /* if the folder isn't selectable, append delimiter to force browse * to enter it on second tab. */ - if (noselect) + if (listresp.noselect) { - clen = strlen(list_word); - list_word[clen++] = delim; - list_word[clen] = '\0'; + clen = strlen(listresp.name); + listresp.name[clen++] = listresp.delim; + listresp.name[clen] = '\0'; } /* copy in first word */ if (!completions) { - strfcpy (completion, list_word, sizeof(completion)); + strfcpy (completion, listresp.name, sizeof(completion)); matchlen = strlen (completion); completions++; continue; } - matchlen = longest_common_prefix (completion, list_word, 0, matchlen); + matchlen = longest_common_prefix (completion, listresp.name, 0, matchlen); completions++; } } while (rc == IMAP_CMD_CONTINUE); + idata->cmddata = NULL; if (completions) { diff --git a/imap/imap_private.h b/imap/imap_private.h index 71aab69c0..353114242 100644 --- a/imap/imap_private.h +++ b/imap/imap_private.h @@ -162,6 +162,16 @@ typedef struct unsigned int unseen; } IMAP_STATUS; +typedef struct +{ + char* name; + + char delim; + /* if we end up storing a lot of these we could turn this into a bitfield */ + unsigned char noselect; + unsigned char noinferiors; +} IMAP_LIST; + /* IMAP command structure */ typedef struct { @@ -229,8 +239,6 @@ void imap_mboxcache_free (IMAP_DATA* idata); int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag, int changed); int imap_open_connection (IMAP_DATA* idata); IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags); -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, progress_t*); void imap_expunge_mailbox (IMAP_DATA* idata); void imap_logout (IMAP_DATA* idata); -- 2.40.0