]> granicus.if.org Git - neomutt/commitdiff
Improve hierarchy information accuracy in IMAP browser
authorNaveen Nathan <naveen@lastninja.net>
Tue, 23 Apr 2019 17:04:05 +0000 (03:04 +1000)
committerRichard Russon <rich@flatcap.org>
Thu, 25 Apr 2019 09:42:34 +0000 (10:42 +0100)
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 f8af6b08d4b443b5ec8d08983abee0f7dee1429f..2e842faad655b81be57c0412f651adc06a474880 100644 (file)
@@ -190,7 +190,8 @@ int imap_browse(const char *path, struct BrowserState *state)
   char buf[PATH_MAX];
   char mbox[PATH_MAX];
   char munged_mbox[PATH_MAX];
-  char list_cmd[5];
+  char list_cmd[18];
+  int len;
   int n;
   char ctmp;
   bool showparents = false;
@@ -204,7 +205,6 @@ int imap_browse(const char *path, struct BrowserState *state)
 
   save_lsub = C_ImapCheckSubscribed;
   C_ImapCheckSubscribed = false;
-  mutt_str_strfcpy(list_cmd, C_ImapListSubscribed ? "LSUB" : "LIST", sizeof(list_cmd));
 
   // Pick first mailbox connected to the same server
   struct MailboxNode *np = NULL;
@@ -222,6 +222,21 @@ int imap_browse(const char *path, struct BrowserState *state)
   if (!adata)
     goto fail;
 
+  if (C_ImapListSubscribed)
+  {
+    const char *lsub_cmd = "LSUB";
+
+    /* RFC3348 section 3 states LSUB is unreliable for hierarchy information.
+     * The newer LIST extensions are designed for this.  */
+    if (adata->capabilities & IMAP_CAP_LIST_EXTENDED)
+      lsub_cmd = "LIST (SUBSCRIBED)";
+    mutt_str_strfcpy(list_cmd, lsub_cmd, sizeof(list_cmd));
+  }
+  else
+  {
+    mutt_str_strfcpy(list_cmd, "LIST", sizeof(list_cmd));
+  }
+
   mutt_message(_("Getting folder list..."));
 
   /* skip check for parents when at the root */
@@ -244,7 +259,9 @@ int imap_browse(const char *path, struct BrowserState *state)
     /* if our target exists and has inferiors, enter it if we
      * aren't already going to */
     imap_munge_mbox_name(adata->unicode, 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 (adata->capabilities & IMAP_CAP_LIST_EXTENDED)
+      snprintf(buf + len, sizeof(buf) - len, " RETURN (CHILDREN)");
     imap_cmd_start(adata, buf);
     adata->cmdresult = &list;
     do
@@ -332,7 +349,9 @@ int imap_browse(const char *path, struct BrowserState *state)
   snprintf(buf, sizeof(buf), "%s%%", mbox);
   imap_munge_mbox_name(adata->unicode, munged_mbox, sizeof(munged_mbox), buf);
   mutt_debug(LL_DEBUG3, "%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 (adata->capabilities & IMAP_CAP_LIST_EXTENDED)
+    snprintf(buf + len, sizeof(buf) - len, " RETURN (CHILDREN)");
   if (browse_add_list_result(adata, buf, state, false))
     goto fail;
 
index ae1ce710e0581094dbbe7e9e71abd2f5a2f544fd..4d41200acc4fc62174236b87727762a5fc08e5e3 100644 (file)
@@ -68,7 +68,8 @@ static const char *const Capabilities[] = {
   "AUTH=GSSAPI", "AUTH=ANONYMOUS", "AUTH=OAUTHBEARER",
   "STARTTLS",    "LOGINDISABLED",  "IDLE",
   "SASL-IR",     "ENABLE",         "CONDSTORE",
-  "QRESYNC",     "X-GM-EXT-1",     NULL,
+  "QRESYNC",     "LIST-EXTENDED",  "X-GM-EXT-1",
+  NULL,
 };
 
 /**
index 2d0b012ebe05701f4c78d4900d2b73678564069c..1ec17e0e5e2085e916c4f901601d790ce1a38842 100644 (file)
@@ -133,9 +133,10 @@ typedef uint32_t ImapCapFlags;              ///< Flags, e.g. #IMAP_CAP_IMAP4
 #define IMAP_CAP_ENABLE           (1 << 13) ///< RFC5161
 #define IMAP_CAP_CONDSTORE        (1 << 14) ///< RFC7162
 #define IMAP_CAP_QRESYNC          (1 << 15) ///< RFC7162
-#define IMAP_CAP_X_GM_EXT_1       (1 << 16) ///< https://developers.google.com/gmail/imap/imap-extensions
+#define IMAP_CAP_LIST_EXTENDED    (1 << 16) ///< RFC5258: IMAP4 LIST Command Extensions
+#define IMAP_CAP_X_GM_EXT_1       (1 << 17) ///< https://developers.google.com/gmail/imap/imap-extensions
 
-#define IMAP_CAP_ALL             ((1 << 17) - 1)
+#define IMAP_CAP_ALL             ((1 << 18) - 1)
 
 /**
  * struct ImapList - Items in an IMAP browser