]> granicus.if.org Git - mutt/commitdiff
Improve hierarchy information accuracy in IMAP browser
authorNaveen Nathan <mutt@t.lastninja.net>
Tue, 23 Apr 2019 17:04:05 +0000 (03:04 +1000)
committerKevin McCarthy <kevin@8t8.us>
Tue, 23 Apr 2019 19:28:12 +0000 (12:28 -0700)
Currently the IMAP browser relies on LIST and LSUB (for listing subscribed
folders) which may not provide the required hierarchy information.

RFC3348 section 3 goes as far as stating that a client mustn't rely on LSUB
for hierarchy information.

This patch implements the LIST command extensions specified in RFC5258
requiring that a server must respond with hierarchy information for
listed folders (whether or not filtering on subscribed folders).

imap/browse.c
imap/command.c
imap/imap_private.h

index 1aa4d3574c8ebbe1fa082e22cbf7aa0b1f6acadf..8a2a9a6aae4bef13c70f00beb56b5f2ad2efa32e 100644 (file)
@@ -46,7 +46,8 @@ int imap_browse (const char* path, struct browser_state* state)
   char buf[LONG_STRING*2];
   char mbox[LONG_STRING];
   char munged_mbox[LONG_STRING];
-  char list_cmd[5];
+  char list_cmd[18];
+  int len;
   int n;
   int nsup;
   char ctmp;
@@ -62,11 +63,26 @@ int imap_browse (const char* path, struct browser_state* state)
 
   save_lsub = option (OPTIMAPCHECKSUBSCRIBED);
   unset_option (OPTIMAPCHECKSUBSCRIBED);
-  strfcpy (list_cmd, option (OPTIMAPLSUB) ? "LSUB" : "LIST", sizeof (list_cmd));
 
   if (!(idata = imap_conn_find (&(mx.account), 0)))
     goto fail;
 
+  if (option (OPTIMAPLSUB))
+  {
+    const char *lsub_cmd = "LSUB";
+
+    /* RFC3348 section 3 states LSUB is unreliable for hierarchy information.
+     * The newer LIST extensions are designed for this.
+     */
+    if (mutt_bit_isset (idata->capabilities, LIST_EXTENDED))
+      lsub_cmd = "LIST (SUBSCRIBED)";
+    strfcpy (list_cmd, lsub_cmd, sizeof (list_cmd));
+  }
+  else
+  {
+    strfcpy (list_cmd, "LIST", sizeof (list_cmd));
+  }
+
   mutt_message _("Getting folder list...");
 
   /* skip check for parents when at the root */
@@ -89,7 +105,9 @@ int imap_browse (const char* path, struct browser_state* state)
     /* if our target exists and has inferiors, enter it if we
      * aren't already going to */
     imap_munge_mbox_name (idata, munged_mbox, sizeof (munged_mbox), mbox);
-    snprintf (buf, sizeof (buf), "%s \"\" %s", list_cmd, munged_mbox);
+    len = snprintf (buf, sizeof (buf), "%s \"\" %s", list_cmd, munged_mbox);
+    if (mutt_bit_isset (idata->capabilities, LIST_EXTENDED))
+      snprintf (buf + len, sizeof(buf) - len, " RETURN (CHILDREN)");
     imap_cmd_start (idata, buf);
     idata->cmdtype = IMAP_CT_LIST;
     idata->cmddata = &list;
@@ -181,7 +199,9 @@ int imap_browse (const char* path, struct browser_state* state)
   snprintf (buf, sizeof (buf), "%s%%", mbox);
   imap_munge_mbox_name (idata, munged_mbox, sizeof (munged_mbox), buf);
   dprint (3, (debugfile, "%s\n", munged_mbox));
-  snprintf (buf, sizeof (buf), "%s \"\" %s", list_cmd, munged_mbox);
+  len = snprintf (buf, sizeof (buf), "%s \"\" %s", list_cmd, munged_mbox);
+  if (mutt_bit_isset (idata->capabilities, LIST_EXTENDED))
+    snprintf (buf + len, sizeof(buf) - len, " RETURN (CHILDREN)");
   if (browse_add_list_result (idata, buf, state, 0))
     goto fail;
 
index 21f6a40b0383b64ef7b6cc31ed7c46354b75d237..91457a114b1ab4737c38e2dfbea49d94000ea368 100644 (file)
@@ -73,6 +73,7 @@ static const char * const Capabilities[] = {
   "ENABLE",
   "CONDSTORE",
   "QRESYNC",
+  "LIST-EXTENDED",
 
   NULL
 };
index 075236722eb3116aae3c25f5cfec8b3024a0752e..7d12ec2507b71883767fdcd3290aedd1d2659305 100644 (file)
@@ -120,6 +120,7 @@ enum
   ENABLE,                       /* RFC 5161 */
   CONDSTORE,                    /* RFC 7162 */
   QRESYNC,                      /* RFC 7162 */
+  LIST_EXTENDED,                /* RFC 5258: IMAP4 - LIST Command Extensions */
 
   CAPMAX
 };