<<< Date Index >>>     <<< Thread Index >>>

[PATCH] IMAP old message status on read-only folders



If Cyrus (at least) does not grant the connecting user the "w" (write)
permission, then mutt can't store "old".  The standard "read"
permissions are "lrs", where the "s" lets the \Seen flag be set.

The new parse code broke mutt's ability to show unseen non-recent mails
as "O", instead always showing them as "N".

Also, a cut&paste error meant that the parsing was going wrong because
the current offset was not being offset sufficiently on the \Recent
flag, only going up by 5 chars instead of 7.

I'm not quite sure how, but this seems to have affected mutt's
visibility of the \* flag, so mutt didn't think that it could write the
"old" flag if it didn't already exist, so mutt would refuse to flag
mails as old.  I can't see why this should have been the case though,
since mutt should just have seen a flag called "nt" and one called "\*"
(assuming no other flags between \Recent and \*).  My diagnosis of why
mutt wasn't writing out old might be wrong here.

All in all, my less-frequently-read folders ended up with a lot of
permanently new mail.  ;^)

Attached is (for sure, thanks to the Attach: pseudo-header (Yaay!)) a
patch which, if "old" is _NOT_ present in the flags, will include unseen
non-recent mails as "old", despite the lack of the old.

If it's acceptable to flag all unseen non-recent mails as "old",
irregardless of mutt's own flag, then the patch could be made simpler
and less intrusive code-wise, but I opted for less intrusive semantics.

Thanks,
-- 
I am keeping international relations on a peaceable footing.
You are biding your time before acting.
He is coddling tyrants.
 -- Roger BW on topic of verb conjugation
diff -urp mutt/imap/imap.c mutt-newold/imap/imap.c
--- mutt/imap/imap.c    2006-01-16 01:53:31.000000000 +0100
+++ mutt-newold/imap/imap.c     2006-01-20 16:01:34.000000000 +0100
@@ -701,28 +701,33 @@ int imap_open_mailbox (CONTEXT* ctx)
     ctx->readonly = 1;
   }
 
-#ifdef DEBUG
-  /* dump the mailbox flags we've found */
-  if (debuglevel > 2)
+  idata->folder_opts &= ~IMAP_FOLDEROPTS_NOOLD;
+
+  /* set folder options which are dependent upon flags */
+  /* if debugging, dump the mailbox flags we've found */
+  if (!idata->flags)
+    dprint (3, (debugfile, "No folder flags found\n"));
+  else
   {
-    if (!idata->flags)
-      dprint (3, (debugfile, "No folder flags found\n"));
-    else
-    {
-      LIST* t = idata->flags;
+    LIST* t = idata->flags;
+    int seen_old = 0;
 
-      dprint (3, (debugfile, "Mailbox flags: "));
+    dprint (3, (debugfile, "Mailbox flags: "));
 
+    t = t->next;
+    while (t)
+    {
+      dprint (3, (debugfile, "[%s] ", t->data));
+      if (!ascii_strcasecmp (t->data, "old"))
+       seen_old = 1;
       t = t->next;
-      while (t)
-      {
-        dprint (3, (debugfile, "[%s] ", t->data));
-        t = t->next;
-      }
-      dprint (3, (debugfile, "\n"));
     }
+    if (!seen_old) {
+      idata->folder_opts |= IMAP_FOLDEROPTS_NOOLD;
+      dprint (3, (debugfile, " (no 'old' flag!)"));
+    }
+    dprint (3, (debugfile, "\n"));
   }
-#endif
 
   if (!(mutt_bit_isset(idata->rights, IMAP_ACL_DELETE) ||
         mutt_bit_isset(idata->rights, IMAP_ACL_SEEN) ||
diff -urp mutt/imap/imap_private.h mutt-newold/imap/imap_private.h
--- mutt/imap/imap_private.h    2005-12-23 19:20:02.000000000 +0100
+++ mutt-newold/imap/imap_private.h     2006-01-20 14:56:23.000000000 +0100
@@ -66,6 +66,9 @@
 #define IMAP_CMD_FAIL_OK (1<<0)
 #define IMAP_CMD_PASS    (1<<1)
 
+/* parse adjustment flags for server features */
+#define IMAP_FOLDEROPTS_NOOLD (1<<0)
+
 enum
 {
   IMAP_FATAL = 1,
@@ -222,6 +225,7 @@ typedef struct
   IMAP_CACHE cache[IMAP_CACHE_LEN];
   unsigned int uid_validity;
   unsigned int uidnext;
+  unsigned char folder_opts;
   
   /* all folder flags - system flags AND keywords */
   LIST *flags;
diff -urp mutt/imap/message.c mutt-newold/imap/message.c
--- mutt/imap/message.c 2005-12-23 19:20:02.000000000 +0100
+++ mutt-newold/imap/message.c  2006-01-20 15:44:20.000000000 +0100
@@ -47,8 +47,8 @@ static FILE* msg_cache_put (IMAP_DATA* i
 static void flush_buffer(char* buf, size_t* len, CONNECTION* conn);
 static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf,
   FILE* fp);
-static int msg_parse_fetch (IMAP_HEADER* h, char* s);
-static char* msg_parse_flags (IMAP_HEADER* h, char* s);
+static int msg_parse_fetch (IMAP_HEADER* h, char* s, unsigned char 
folder_opts);
+static char* msg_parse_flags (IMAP_HEADER* h, char* s, unsigned char 
folder_opts);
 
 /* imap_read_headers:
  * Changed to read many headers instead of just one. It will return the
@@ -975,7 +975,7 @@ char* imap_set_flags (IMAP_DATA* idata, 
   newh.data = hd;
 
   dprint (2, (debugfile, "imap_fetch_message: parsing FLAGS\n"));
-  if ((s = msg_parse_flags (&newh, s)) == NULL)
+  if ((s = msg_parse_flags (&newh, s, idata->folder_opts)) == NULL)
     return NULL;
   
   /* YAUH (yet another ugly hack): temporarily set context to
@@ -1035,7 +1035,7 @@ static int msg_fetch_header (CONTEXT* ct
 
   /* FIXME: current implementation - call msg_parse_fetch - if it returns -2,
    *   read header lines and call it again. Silly. */
-  if ((rc = msg_parse_fetch (h, buf) != -2) || !fp)
+  if ((rc = msg_parse_fetch (h, buf, idata->folder_opts) != -2) || !fp)
     return rc;
   
   if (imap_get_literal_count (buf, &bytes) == 0)
@@ -1049,7 +1049,7 @@ static int msg_fetch_header (CONTEXT* ct
     if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
       return rc;
   
-    if (msg_parse_fetch (h, idata->buf) == -1)
+    if (msg_parse_fetch (h, idata->buf, idata->folder_opts) == -1)
       return rc;
   }
 
@@ -1063,7 +1063,7 @@ static int msg_fetch_header (CONTEXT* ct
 }
 
 /* msg_parse_fetch: handle headers returned from header fetch */
-static int msg_parse_fetch (IMAP_HEADER *h, char *s)
+static int msg_parse_fetch (IMAP_HEADER *h, char *s, unsigned char folder_opts)
 {
   char tmp[SHORT_STRING];
   char *ptmp;
@@ -1077,7 +1077,7 @@ static int msg_parse_fetch (IMAP_HEADER 
 
     if (ascii_strncasecmp ("FLAGS", s, 5) == 0)
     {
-      if ((s = msg_parse_flags (h, s)) == NULL)
+      if ((s = msg_parse_flags (h, s, folder_opts)) == NULL)
         return -1;
     }
     else if (ascii_strncasecmp ("UID", s, 3) == 0)
@@ -1137,9 +1137,10 @@ static int msg_parse_fetch (IMAP_HEADER 
 }
 
 /* msg_parse_flags: read a FLAGS token into an IMAP_HEADER */
-static char* msg_parse_flags (IMAP_HEADER* h, char* s)
+static char* msg_parse_flags (IMAP_HEADER* h, char* s, unsigned char 
folder_opts)
 {
   IMAP_HEADER_DATA* hd = h->data;
+  int recent = 0;
 
   /* sanity-check string */
   if (ascii_strncasecmp ("FLAGS", s, 5) != 0)
@@ -1184,8 +1185,11 @@ static char* msg_parse_flags (IMAP_HEADE
       s += 5;
       hd->read = 1;
     }
-    else if (ascii_strncasecmp ("\\recent", s, 5) == 0)
+    else if (ascii_strncasecmp ("\\recent", s, 7) == 0)
+    {
       s += 7;
+      recent = 1;
+    }
     else if (ascii_strncasecmp ("old", s, 3) == 0)
     {
       s += 3;
@@ -1220,6 +1224,11 @@ static char* msg_parse_flags (IMAP_HEADE
     return NULL;
   }
 
+  /* Some servers don't explicitly store old (eg, on read-only boxes),
+   * the absense of \Recent is the indicator.  Eg, Cyrus */
+  if ((recent == 0) && (hd->read == 0) && (folder_opts & 
IMAP_FOLDEROPTS_NOOLD))
+    hd->old = 1;
+
   return s;
 }