]> granicus.if.org Git - neomutt/commitdiff
Replace imap_parse_list_response with a proper untagged response handler.
authorBrendan Cully <brendan@kublai.com>
Mon, 19 Dec 2005 17:07:59 +0000 (17:07 +0000)
committerBrendan Cully <brendan@kublai.com>
Mon, 19 Dec 2005 17:07:59 +0000 (17:07 +0000)
imap/browse.c
imap/command.c
imap/imap.c
imap/imap_private.h

index fb5d8b3bdd6f7936d02a4f4a8d8ed5b8fce8ef85..5e8b3820026cec95b02238e18f2404dcae785ad2 100644 (file)
@@ -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;
index e8d5f4d51e14199f72329f1d761a2d5f5435ac2b..64c819e877fcf716dc6bf239eb5edaa0a0453e5e 100644 (file)
@@ -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';
index 4a2eef742f392d94cedb6bb8969d4429193472c7..c2956b2983a886238dcc38a92118f668f54e9678 100644 (file)
@@ -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)
   {
index 71aab69c03ff837c6f776bb16e2b17206ff34906..3531142425b0b612edc56092b76b44699d7834fa 100644 (file)
@@ -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);