]> granicus.if.org Git - mutt/commitdiff
* Small imap/Makefile.am tweak for make dist
authorThomas Roessler <roessler@does-not-exist.org>
Mon, 6 Sep 1999 09:16:50 +0000 (09:16 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Mon, 6 Sep 1999 09:16:50 +0000 (09:16 +0000)
* Hold on to mailbox flags, message flags, do update in one pass
  instead of two, halving traffic on mailbox sync.

* Update message flags at fetch as well as header download, if the
  server thinks they've changed. Saves some unneeded updates on
  sync.

* Move some structures out of imap_private.h into message.h, since
  they are local now.

(From: Brendan Cully <brendan@kublai.com>)

imap/Makefile.am
imap/TODO
imap/imap.c
imap/imap.h
imap/imap_private.h
imap/message.c
imap/message.h [new file with mode: 0644]
mutt.h
muttlib.c

index f4744300bd14fa54339c19070fb02e8056d03164..33eca53e1fc08dd0427fded9048653a1424e21cd 100644 (file)
@@ -2,8 +2,10 @@
 
 AUTOMAKE_OPTIONS = foreign
 
+EXTRA_DIST = BUGS TODO
+
 noinst_LIBRARIES = libimap.a
-noinst_HEADERS = imap_private.h imap_socket.h md5.h
+noinst_HEADERS = imap_private.h imap_socket.h md5.h message.h
 
 libimap_a_SOURCES = imap.c imap.h auth.c browse.c md5c.c socket.c \
        message.c
index 1a0094ea8961321657fb35145d6ffb2dcd9f0169..340071d77f1f17c614e9c43d8564a05d1f819eb6 100644 (file)
--- a/imap/TODO
+++ b/imap/TODO
@@ -1,5 +1,6 @@
 IMAP enhancements/fixes, by priority:
 
+[ -- socket -- ]
 * Smarter connection code. Mutt should handle dropped connections/routing
   problems gracefully. It should be able to transparently reconnect. This
   is facilitated by the next item.
@@ -12,19 +13,28 @@ IMAP enhancements/fixes, by priority:
 
   PRIORITY: [***]
 
-* Optimise message updating. Two flags stores per message should be
-  unnecessary. It could be brought to one easily. Better would be to use
-  message ranges to store common flags en masse. This is facilitated by the
-  next item.
+[ -- browsing -- ]
+* Investigate a new way of displaying folders with subfolders and messages.
+  Possibly we could use a tree-view in the browser, w/ expand, collapse.
+  For low-bandwidth lines we could defer getting subfolder lists until the
+  folder is expanded.
+
+[ -- new features -- ]
+* Implement server message COPY, instead of FETCH/APPEND.
+
+  PRIORITY: [** ]
+
+* Implement the received folder on IMAP. (Wait on COPY).
 
   PRIORITY: [** ]
 
-* More complete mailbox caching. All the data for a message should be held
-  locally so that updates can be done without requerying the server.
+* Commands for creating/deleting folders on the server, since users may not
+  otherwise be able to do this on IMAP servers.
 
   PRIORITY: [** ]
 
-* Implement server message copy, instead of FETCH/APPEND.
+* Implement READ-ONLY support, and the x (quit without saving changes)
+  command.
 
   PRIORITY: [** ]
 
@@ -45,4 +55,4 @@ IMAP enhancements/fixes, by priority:
   PRIORITY: [*  ]
 
 Brendan Cully <brendan@kublai.com>
-Updated: 19990826
+Updated: 19990904
index e4dcaacc5dcb13dd4ab93ce260056ce88a99a7c8..ea66c6888d1468d7e76a6e582163110bdd9c074f 100644 (file)
@@ -49,6 +49,8 @@ static int imap_wordcasecmp(const char *a, const char *b);
 static void imap_parse_capabilities (IMAP_DATA *idata, char *s);
 static int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint);
 static int imap_get_delim (IMAP_DATA *idata, CONNECTION *conn);
+static char* imap_get_flags (LIST** hflags, char* s);
+static int imap_has_flag (LIST* flag_list, const char* flag);
 static int imap_check_acl (IMAP_DATA *idata);
 static int imap_check_capabilities (IMAP_DATA *idata);
 static int imap_create_mailbox (IMAP_DATA *idata, char *mailbox);
@@ -869,6 +871,60 @@ int imap_open_connection (IMAP_DATA *idata, CONNECTION *conn)
   return 0;
 }
 
+/* imap_get_flags: Make a simple list out of a FLAGS response.
+ *   return stream following FLAGS response */
+static char* imap_get_flags (LIST** hflags, char* s)
+{
+  LIST* flags;
+  char* flag_word;
+  char ctmp;
+
+  /* sanity-check string */
+  if (mutt_strncasecmp ("FLAGS", s, 5) != 0)
+  {
+    dprint (1, (debugfile, "imap_get_flags: not a FLAGS response: %s\n",
+      s));
+    return NULL;
+  }
+  s += 5;
+  SKIPWS(s);
+  if (*s != '(')
+  {
+    dprint (1, (debugfile, "imap_get_flags: bogus FLAGS response: %s\n",
+      s));
+    return NULL;
+  }
+
+  /* create list, update caller's flags handle */
+  flags = mutt_new_list();
+  *hflags = flags;
+
+  while (*s && *s != ')')
+  {
+    s++;
+    SKIPWS(s);
+    flag_word = s;
+    while (*s && (*s != ')') && !ISSPACE (*s))
+      s++;
+    ctmp = *s;
+    *s = '\0';
+    mutt_add_list (flags, flag_word);
+    *s = ctmp;
+  }
+
+  /* note bad flags response */
+  if (*s != ')')
+  {
+    dprint (1, (debugfile,
+      "imap_get_flags: Unterminated FLAGS response: %s\n", s));
+    return NULL;
+  }
+
+  s++;
+
+  return s;
+}
+
 int imap_open_mailbox (CONTEXT *ctx)
 {
   CONNECTION *conn;
@@ -940,18 +996,63 @@ int imap_open_mailbox (CONTEXT *ctx)
 
        while (*pc && isdigit (*pc))
          pc++;
-       *pc++ = 0;
+       *pc++ = '\0';
        n = atoi (pn);
        SKIPWS (pc);
        if (mutt_strncasecmp ("EXISTS", pc, 6) == 0)
          count = n;
       }
+      /* Obtain list of available flags here, may be overridden by a
+       * PERMANENTFLAGS tag in the OK response */
+      else if (mutt_strncasecmp ("FLAGS", pc, 5) == 0)
+      {
+        /* don't override PERMANENTFLAGS */
+        if (!idata->mailbox_flags)
+        {
+          dprint (2, (debugfile, "Getting mailbox FLAGS\n"));
+          if ((pc = imap_get_flags (&(idata->mailbox_flags), pc)) == NULL)
+            return -1;
+        }
+      }
+      /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
+      else if (mutt_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0)
+      {
+        dprint (2, (debugfile,
+          "Getting mailbox PERMANENTFLAGS\n"));
+        /* safe to call on NULL */
+        mutt_free_list (&(idata->mailbox_flags));
+       /* skip "OK [PERMANENT" so syntax is the same as FLAGS */
+        pc += 13;
+        if ((pc = imap_get_flags (&(idata->mailbox_flags), pc)) == NULL)
+          return -1;
+      }
       else if (imap_handle_untagged (idata, buf) != 0)
        return (-1);
     }
   }
   while (mutt_strncmp (seq, buf, mutt_strlen (seq)) != 0);
 
+  /* dump the mailbox flags we've found */
+  if (debuglevel > 2)
+  {
+    if (!idata->mailbox_flags)
+      dprint (3, (debugfile, "No folder flags found\n"));
+    else
+    {
+      LIST* t = idata->mailbox_flags;
+
+      dprint (3, (debugfile, "Mailbox flags: "));
+
+      t = t->next;
+      while (t)
+      {
+        dprint (3, (debugfile, "[%s] ", t->data));
+        t = t->next;
+      }
+      dprint (3, (debugfile, "\n"));
+    }
+  }
+
   if (!imap_code (buf))
   {
     char *s;
@@ -1160,18 +1261,52 @@ int imap_close_connection (CONTEXT *ctx)
   return 0;
 }
 
-static void _imap_set_flag (CONTEXT *ctx, int aclbit, int flag, const char *str, 
-                    char *sf, char *uf)
+/* imap_has_flag: do a caseless comparison of the flag against a flag list,
+ *   return 1 if found or flag list has '\*', 0 otherwise */
+static int imap_has_flag (LIST* flag_list, const char* flag)
 {
-  if (mutt_bit_isset (CTX_DATA->rights, aclbit))
+  if (!flag_list)
+    return 0;
+
+  flag_list = flag_list->next;
+  while (flag_list)
   {
-    if (flag)
-      strcat (sf, str);
-    else
-      strcat (uf, str);
+    if (!mutt_strncasecmp (flag_list->data, flag, strlen (flag_list->data)))
+      return 1;
+
+    flag_list = flag_list->next;
+  }
+
+  return 0;
+}
+
+/* imap_stringify_flaglist: concatenate custom IMAP tags to list, if they
+ *   appear in the folder flags list. Why wouldn't they? */
+static void imap_stringify_flaglist (LIST* flags, LIST* mailbox_flags, char *s)
+{
+  if (!mailbox_flags || !flags)
+    return;
+
+  flags = flags->next;
+  while (flags)
+  {
+    if (imap_has_flag (mailbox_flags, flags->data))
+    {
+      strcat (s, flags->data);
+      strcat (s, " ");
+    }
+    flags = flags->next;
   }
 }
 
+static void imap_set_flag (CONTEXT *ctx, int aclbit, int flag, const char *str, 
+  char *flags)
+{
+  if (mutt_bit_isset (CTX_DATA->rights, aclbit))
+    if (flag)
+      strcat (flags, str);
+}
+
 /* update the IMAP server to reflect message changes done within mutt.
  * Arguments
  *   ctx: the current context
@@ -1180,8 +1315,7 @@ int imap_sync_mailbox (CONTEXT *ctx, int expunge)
 {
   char seq[8];
   char buf[LONG_STRING];
-  char set_flags[LONG_STRING];
-  char unset_flags[LONG_STRING];
+  char flags[LONG_STRING];
   int n;
 
   /* save status changes */
@@ -1193,39 +1327,30 @@ int imap_sync_mailbox (CONTEXT *ctx, int expunge)
                n+1, ctx->msgcount);
       mutt_message (buf);
       
-      *set_flags = '\0';
-      *unset_flags = '\0';
+      flags[0] = '\0';
       
-      _imap_set_flag (ctx, IMAP_ACL_SEEN, ctx->hdrs[n]->read, "\\Seen ", set_flags, unset_flags);
-      _imap_set_flag (ctx, IMAP_ACL_WRITE, ctx->hdrs[n]->flagged, "\\Flagged ", set_flags, unset_flags);
-      _imap_set_flag (ctx, IMAP_ACL_WRITE, ctx->hdrs[n]->replied, "\\Answered ", set_flags, unset_flags);
-      _imap_set_flag (ctx, IMAP_ACL_DELETE, ctx->hdrs[n]->deleted, "\\Deleted", set_flags, unset_flags);
+      imap_set_flag (ctx, IMAP_ACL_SEEN, ctx->hdrs[n]->read, "\\Seen ",
+        flags);
+      imap_set_flag (ctx, IMAP_ACL_WRITE, ctx->hdrs[n]->flagged, "\\Flagged ",
+        flags);
+      imap_set_flag (ctx, IMAP_ACL_WRITE, ctx->hdrs[n]->replied,
+        "\\Answered ", flags);
+      imap_set_flag (ctx, IMAP_ACL_DELETE, ctx->hdrs[n]->deleted, "\\Deleted ",
+        flags);
+
+      /* now make sure we don't lose custom tags */
+      imap_stringify_flaglist (ctx->hdrs[n]->server_flags,
+        CTX_DATA->mailbox_flags, flags);
       
-      mutt_remove_trailing_ws (set_flags);
-      mutt_remove_trailing_ws (unset_flags);
+      mutt_remove_trailing_ws (flags);
       
-      if (*set_flags)
-      {
-       imap_make_sequence (seq, sizeof (seq));
-       snprintf (buf, sizeof (buf), "%s STORE %d +FLAGS.SILENT (%s)\r\n", seq,
-                 ctx->hdrs[n]->index + 1, set_flags);
-       if (imap_exec (buf, sizeof (buf), CTX_DATA, seq, buf, 0) != 0)
-       {
-         imap_error ("imap_sync_mailbox()", buf);
-         return (-1);
-       }
-      }
-      
-      if (*unset_flags)
+      imap_make_sequence (seq, sizeof (seq));
+      snprintf (buf, sizeof (buf), "%s STORE %d FLAGS.SILENT (%s)\r\n", seq,
+        ctx->hdrs[n]->index + 1, NONULL(flags));
+      if (imap_exec (buf, sizeof (buf), CTX_DATA, seq, buf, 0) != 0)
       {
-       imap_make_sequence (seq, sizeof (seq));
-       snprintf (buf, sizeof (buf), "%s STORE %d -FLAGS.SILENT (%s)\r\n", seq,
-                 ctx->hdrs[n]->index + 1, unset_flags);
-       if (imap_exec (buf, sizeof (buf), CTX_DATA, seq, buf, 0) != 0)
-       {
-         imap_error ("imap_sync_mailbox()", buf);
-         return (-1);
-       }
+        imap_error ("imap_sync_mailbox()", buf);
+        return (-1);
       }
     }
   }
index 8841049206a69cbc923a177393764df9f6eabece..52e71adab202bd1bf806ecd7070f0e2058f57c04 100644 (file)
@@ -22,9 +22,7 @@
 #include "browser.h"
 #include "mailbox.h"
 
-int imap_append_message (CONTEXT *ctx, MESSAGE *msg);
 int imap_check_mailbox (CONTEXT *ctx, int *index_hint);
-int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno);
 int imap_open_mailbox (CONTEXT *ctx);
 int imap_open_mailbox_append (CONTEXT *ctx);
 int imap_parse_path (char *path, char *host, size_t hlen, int *port,
@@ -40,4 +38,8 @@ int imap_complete (char* dest, size_t dlen, char* path);
 void imap_qualify_path (char* dest, size_t len, const char* host, int port,
   const char* path, const char* name);
 
+/* message.c */
+int imap_append_message (CONTEXT *ctx, MESSAGE *msg);
+int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno);
+
 #endif
index 1dd8ba4b1ee67bfbfc7529babe01aa44d9e4bf08..6b10bcbc43a943b3e572643663a7f93705de74f8 100644 (file)
@@ -119,24 +119,6 @@ typedef struct
   int noinferiors;
 } IMAP_NAMESPACE_INFO;
 
-/* Linked list to hold header information while downloading message
- * headers
- */
-typedef struct imap_header_info
-{
-  unsigned int read : 1;
-  unsigned int old : 1;
-  unsigned int deleted : 1;
-  unsigned int flagged : 1;
-  unsigned int replied : 1;
-  unsigned int changed : 1;
-  unsigned int number;
-
-  time_t received;
-  long content_length;
-  struct imap_header_info *next;
-} IMAP_HEADER_INFO;
-
 typedef struct
 {
   /* This data is specific to a CONNECTION to an IMAP server */
@@ -153,6 +135,7 @@ typedef struct
   unsigned char rights[(RIGHTSMAX + 7)/8];
   unsigned int newMailCount;
   IMAP_CACHE cache[IMAP_CACHE_LEN];
+  LIST *mailbox_flags;
 } IMAP_DATA;
 
 /* -- macros -- */
index 1d0d9959f5e4a137f439e3d7b0721e52137cc3bf..5789d5da1c1bf028c553bc320c9a71c9b390f997 100644 (file)
@@ -25,6 +25,7 @@
 #include "mutt.h"
 #include "imap.h"
 #include "imap_private.h"
+#include "message.h"
 #include "mx.h"
 
 #ifdef _PGPPATH
@@ -32,7 +33,8 @@
 #endif
 
 static void flush_buffer(char *buf, size_t *len, CONNECTION *conn);
-static int parse_fetch (IMAP_HEADER_INFO *h, char *s);
+static int msg_parse_fetch (IMAP_HEADER_INFO *h, char *s);
+static char* msg_parse_flags (IMAP_FLAGS* flags, char* s);
 
 /* imap_read_headers:
  * Changed to read many headers instead of just one. It will return the
@@ -66,8 +68,8 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
     return (-1);
   }
 
-  h0=safe_malloc(sizeof(IMAP_HEADER_INFO));
-  h=h0;
+  h0 = (IMAP_HEADER_INFO*) safe_malloc(sizeof(IMAP_HEADER_INFO));
+  h = h0;
   for (msgno=msgbegin; msgno <= msgend ; msgno++)
   {
     snprintf (buf, sizeof (buf), _("Fetching message headers... [%d/%d]"), 
@@ -168,7 +170,7 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
     while ((msgno + 1) >= fetchlast && mutt_strncmp (seq, buf, SEQLEN) != 0);
 
     h->content_length = -bytes;
-    if (parse_fetch (h, fetchbuf) == -1)
+    if (msg_parse_fetch (h, fetchbuf) == -1)
       return (-1);
 
     /* subtract the header length; the total message size will be
@@ -202,20 +204,21 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
 
     ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno], 0);
     ploc=ftell(fp);
-    ctx->hdrs[msgno]->read = h->read;
-    ctx->hdrs[msgno]->old = h->old;
-    ctx->hdrs[msgno]->deleted = h->deleted;
-    ctx->hdrs[msgno]->flagged = h->flagged;
-    ctx->hdrs[msgno]->replied = h->replied;
-    ctx->hdrs[msgno]->changed = h->changed;
+    ctx->hdrs[msgno]->read = h->flags.read;
+    ctx->hdrs[msgno]->old = h->flags.old;
+    ctx->hdrs[msgno]->deleted = h->flags.deleted;
+    ctx->hdrs[msgno]->flagged = h->flags.flagged;
+    ctx->hdrs[msgno]->replied = h->flags.replied;
+    ctx->hdrs[msgno]->changed = h->flags.changed;
+    ctx->hdrs[msgno]->server_flags = h->flags.server_flags;
     ctx->hdrs[msgno]->received = h->received;
     ctx->hdrs[msgno]->content->length = h->content_length;
 
-    mx_update_context(ctx); /* increments ->msgcount */
+    mx_update_context (ctx); /* increments ->msgcount */
 
     htemp=h;
     h=h->next;
-    safe_free((void **) &htemp);
+    safe_free ((void **) &htemp);
   }
   fclose(fp);
   unlink(tempfile);
@@ -314,6 +317,37 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
            }
            pc = buf;
          }
+          /* UW-IMAP will provide a FLAGS update here if the FETCH causes a
+           * change (eg from \Unseen to \Seen) */
+          else if (strncasecmp ("FLAGS", pc, 5) == 0)
+          {
+           IMAP_FLAGS flags;
+            HEADER* h = ctx->hdrs[msgno];
+
+            flags.server_flags = NULL;
+
+            dprint (2, (debugfile, "imap_fetch_message: parsing FLAGS\n"));
+            if ((pc = msg_parse_flags (&flags, pc)) == NULL)
+              return -1;
+
+            /* update context sums */
+            ctx->new += ((flags.read | flags.old) ? 0 : 1) -
+              ((h->read | h->old) ? 0 : 1);
+            ctx->unread += h->read - flags.read;
+            ctx->deleted += h->deleted = flags.deleted;
+            ctx->flagged += h->flagged - flags.flagged;
+
+            /* now commit the new flags */
+            ctx->hdrs[msgno]->read = flags.read;
+            ctx->hdrs[msgno]->old = flags.old;
+            ctx->hdrs[msgno]->deleted = flags.deleted;
+            ctx->hdrs[msgno]->flagged = flags.flagged;
+            ctx->hdrs[msgno]->replied = flags.replied;
+            ctx->hdrs[msgno]->changed = flags.changed;
+
+            mutt_free_list (&(h->server_flags));
+            h->server_flags = flags.server_flags;
+          }
        }
       }
       else if (imap_handle_untagged (CTX_DATA, buf) != 0)
@@ -471,129 +505,163 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
   return 0;
 }
 
-/* parse_fetch: handle headers returned from header fetch */
-static int parse_fetch (IMAP_HEADER_INFO *h, char *s)
+/* msg_parse_fetch: handle headers returned from header fetch */
+static int msg_parse_fetch (IMAP_HEADER_INFO *h, char *s)
 {
   char tmp[SHORT_STRING];
   char *ptmp;
-  int state = 0;
-  int recent = 0;
 
   if (!s)
     return (-1);
 
-  h->old = 0;
-
   while (*s)
   {
     SKIPWS (s);
 
-    switch (state)
+    if (mutt_strncasecmp ("FLAGS", s, 5) == 0)
     {
-      case 0:
-       if (mutt_strncasecmp ("FLAGS", s, 5) == 0)
-       {
-         s += 5;
-         SKIPWS (s);
-         if (*s != '(')
-         {
-           dprint (1, (debugfile, "parse_fetch(): bogus FLAGS entry: %s\n", s));
-           return (-1); /* parse error */
-         }
-         /* we're about to get a new set of headers, so clear the old ones. */
-         h->deleted = 0;
-          h->flagged = 0;
-         h->replied = 0;
-          h->read = 0;
-          h->old = 0;
-         h->changed = 0;
-          recent = 0;
-         s++;
-         state = 1;
-       }
-       else if (mutt_strncasecmp ("INTERNALDATE", s, 12) == 0)
-       {
-         s += 12;
-         SKIPWS (s);
-         if (*s != '\"')
-         {
-           dprint (1, (debugfile, "parse_fetch(): bogus INTERNALDATE entry: %s\n", s));
-           return (-1);
-         }
-         s++;
-         ptmp = tmp;
-         while (*s && *s != '\"')
-           *ptmp++ = *s++;
-         if (*s != '\"')
-           return (-1);
-         s++; /* skip past the trailing " */
-         *ptmp = 0;
-         h->received = imap_parse_date (tmp);
-       }
-       else if (mutt_strncasecmp ("RFC822.SIZE", s, 11) == 0)
-       {
-         s += 11;
-         SKIPWS (s);
-         ptmp = tmp;
-         while (isdigit (*s))
-           *ptmp++ = *s++;
-         *ptmp = 0;
-         h->content_length += atoi (tmp);
-       }
-       else if (*s == ')')
-         s++; /* end of request */
-       else if (*s)
-       {
-         /* got something i don't understand */
-         imap_error ("parse_fetch()", s);
-         return (-1);
-       }
-       break;
-      case 1: /* flags */
-       if (*s == ')')
-       {
-         s++;
-          /* if a message is neither seen nor recent, it is OLD. */
-          if (option (OPTMARKOLD) && !recent && !(h->read))
-            h->old = 1;
-         state = 0;
-       }
-       else if (mutt_strncasecmp ("\\deleted", s, 8) == 0)
-       {
-         s += 8;
-         h->deleted = 1;
-       }
-       else if (mutt_strncasecmp ("\\flagged", s, 8) == 0)
-       {
-         s += 8;
-         h->flagged = 1;
-       }
-       else if (mutt_strncasecmp ("\\answered", s, 9) == 0)
-       {
-         s += 9;
-         h->replied = 1;
-       }
-       else if (mutt_strncasecmp ("\\seen", s, 5) == 0)
-       {
-         s += 5;
-         h->read = 1;
-       }
-       else if (mutt_strncasecmp ("\\recent", s, 5) == 0)
-       {
-         s += 7;
-         recent = 1;
-       }
-       else
-       {
-         while (*s && !ISSPACE (*s) && *s != ')')
-           s++;
-       }
-       break;
+      h->flags.server_flags = NULL;
+      if ((s = msg_parse_flags (&(h->flags), s)) == NULL)
+        return -1;
+    }
+    else if (mutt_strncasecmp ("INTERNALDATE", s, 12) == 0)
+    {
+      s += 12;
+      SKIPWS (s);
+      if (*s != '\"')
+      {
+        dprint (1, (debugfile, "msg_parse_fetch(): bogus INTERNALDATE entry: %s\n", s));
+        return -1;
+      }
+      s++;
+      ptmp = tmp;
+      while (*s && *s != '\"')
+        *ptmp++ = *s++;
+      if (*s != '\"')
+        return -1;
+      s++; /* skip past the trailing " */
+      *ptmp = 0;
+      h->received = imap_parse_date (tmp);
+    }
+    else if (mutt_strncasecmp ("RFC822.SIZE", s, 11) == 0)
+    {
+      s += 11;
+      SKIPWS (s);
+      ptmp = tmp;
+      while (isdigit (*s))
+        *ptmp++ = *s++;
+      *ptmp = 0;
+      h->content_length += atoi (tmp);
+    }
+    else if (*s == ')')
+      s++; /* end of request */
+    else if (*s)
+    {
+      /* got something i don't understand */
+      imap_error ("msg_parse_fetch", s);
+      return (-1);
     }
   }
+
   return 0;
 }
 
+/* msg_parse_flags: fill out the message header according to the flags from the
+ *   server. Expects a flags line of the form "FLAGS (flag flag ...)" */
+static char* msg_parse_flags (IMAP_FLAGS* flags, char* s)
+{
+  int recent = 0;
+
+  /* sanity-check string */
+  if (mutt_strncasecmp ("FLAGS", s, 5) != 0)
+  {
+    dprint (1, (debugfile, "msg_parse_flags: not a FLAGS response: %s\n",
+      s));
+    return NULL;
+  }
+  s += 5;
+  SKIPWS(s);
+  if (*s != '(')
+  {
+    dprint (1, (debugfile, "msg_parse_flags: bogus FLAGS response: %s\n",
+      s));
+    return NULL;
+  }
+  s++;
+
+  /* reset the current flags */
+  flags->deleted = 0;
+  flags->flagged = 0;
+  flags->replied = 0;
+  flags->read = 0;
+  flags->old = 0;
+  flags->changed = 0;
+
+  /* start parsing */
+  while (*s && *s != ')')
+  {
+    if (mutt_strncasecmp ("\\deleted", s, 8) == 0)
+    {
+      s += 8;
+      flags->deleted = 1;
+    }
+    else if (mutt_strncasecmp ("\\flagged", s, 8) == 0)
+    {
+      s += 8;
+      flags->flagged = 1;
+    }
+    else if (mutt_strncasecmp ("\\answered", s, 9) == 0)
+    {
+      s += 9;
+      flags->replied = 1;
+    }
+    else if (mutt_strncasecmp ("\\seen", s, 5) == 0)
+    {
+      s += 5;
+      flags->read = 1;
+    }
+    else if (mutt_strncasecmp ("\\recent", s, 5) == 0)
+    {
+      s += 7;
+      recent = 1;
+    }
+    else
+    {
+      /* store custom flags as well */
+      char ctmp;
+      char* flag_word = s;
+
+      if (!flags->server_flags)
+        flags->server_flags = mutt_new_list ();
+
+      while (*s && !ISSPACE (*s) && *s != ')')
+        s++;
+      ctmp = *s;
+      *s = '\0';
+      mutt_add_list (flags->server_flags, flag_word);
+      *s = ctmp;
+    }
+    SKIPWS(s);
+  }
+
+  /* wrap up, or note bad flags response */
+  if (*s == ')')
+  {
+    /* if a message is neither seen nor recent, it is OLD. */
+    if (option (OPTMARKOLD) && !recent && !(flags->read))
+      flags->old = 1;
+    s++;
+  }
+  else
+  {
+    dprint (1, (debugfile,
+      "msg_parse_flags: Unterminated FLAGS response: %s\n", s));
+    return NULL;
+  }
+
+  return s;
+}
+
 static void flush_buffer(char *buf, size_t *len, CONNECTION *conn)
 {
   buf[*len] = '\0';
diff --git a/imap/message.h b/imap/message.h
new file mode 100644 (file)
index 0000000..1669d8c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
+ * Copyright (C) 1999 Brendan Cully <brendan@kublai.com>
+ * 
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ * 
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */ 
+
+/* message.c data structures */
+
+#ifndef MESSAGE_H
+#define MESSAGE_H 1
+
+/* Data from the FLAGS response */
+typedef struct imap_flags
+{
+  unsigned int read : 1;
+  unsigned int old : 1;
+  unsigned int deleted : 1;
+  unsigned int flagged : 1;
+  unsigned int replied : 1;
+  unsigned int changed : 1;
+
+  LIST* server_flags;  /* flags mutt doesn't use, but the server does */
+} IMAP_FLAGS;
+
+/* Linked list to hold header information while downloading message
+ * headers */
+typedef struct imap_header_info
+{
+  IMAP_FLAGS flags;
+  unsigned int number;
+
+  time_t received;
+  long content_length;
+  struct imap_header_info *next;
+} IMAP_HEADER_INFO;
+
+#endif
diff --git a/mutt.h b/mutt.h
index 7306db1880c8e0d73c74c71528589dc885b6fd5c..a3a5110d5d85e93f68e0e4f3250e049cb3217bcf 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -583,7 +583,10 @@ typedef struct header
 #ifdef MIXMASTER
   LIST *chain;
 #endif
-  
+
+#ifdef USE_IMAP
+  LIST *server_flags;  /* server custom flags, which should be preserved */
+#endif
 } HEADER;
 
 #include "mutt_regex.h"
index c73d0e06e03a8f28f8a2d01ef14e7d5452a1d7d1..c8cdedaa0f7de48803f841c33e4c1d165b561ba6 100644 (file)
--- a/muttlib.c
+++ b/muttlib.c
@@ -158,6 +158,9 @@ void mutt_free_header (HEADER **h)
   safe_free ((void **) &(*h)->path);
 #ifdef MIXMASTER
   mutt_free_list (&(*h)->chain);
+#endif
+#ifdef USE_IMAP
+  mutt_free_list (&(*h)->server_flags);
 #endif
   safe_free ((void **) h);
 }