]> granicus.if.org Git - mutt/commitdiff
Handle expunged messages. From Brendan Cully.
authorThomas Roessler <roessler@does-not-exist.org>
Fri, 28 Jul 2000 08:52:36 +0000 (08:52 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Fri, 28 Jul 2000 08:52:36 +0000 (08:52 +0000)
imap/command.c
imap/imap.c
imap/imap_private.h
imap/message.c
imap/message.h
mutt.h
muttlib.c
mx.c

index c71d984144a20ee67ca22c6c5015f38c17eb863f..12bacce27fe8f8b59f66ea44e608157d2f0bddb4 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "mutt.h"
 #include "imap_private.h"
+#include "message.h"
 #include "mx.h"
 
 #include <ctype.h>
@@ -30,7 +31,8 @@
 
 /* forward declarations */
 static void cmd_make_sequence (char* buf, size_t buflen);
-static void cmd_parse_capabilities (IMAP_DATA *idata, char *s);
+static void cmd_parse_capabilities (IMAP_DATA* idata, char* s);
+static void cmd_parse_expunge (IMAP_DATA* idata, char* s);
 static void cmd_parse_myrights (IMAP_DATA* idata, char* s);
 
 static char *Capabilities[] = {"IMAP4", "IMAP4rev1", "STATUS", "ACL", 
@@ -71,7 +73,6 @@ void imap_cmd_finish (IMAP_DATA* idata)
   }
   
   if ((idata->status == IMAP_NEW_MAIL || 
-       idata->status == IMAP_EXPUNGE ||
        (idata->reopen & (IMAP_REOPEN_PENDING|IMAP_NEWMAIL_PENDING)))
       && (idata->reopen & IMAP_REOPEN_ALLOW))
   {
@@ -90,7 +91,7 @@ void imap_cmd_finish (IMAP_DATA* idata)
     }
     else
     {
-      imap_reopen_mailbox (idata->ctx, NULL);
+      imap_expunge_mailbox (idata);
       idata->check_status = IMAP_REOPENED;
       idata->reopen &= ~(IMAP_REOPEN_PENDING|IMAP_NEWMAIL_PENDING);
     }
@@ -100,9 +101,6 @@ void imap_cmd_finish (IMAP_DATA* idata)
   {
     if (idata->status == IMAP_NEW_MAIL)
       idata->reopen |= IMAP_NEWMAIL_PENDING;
-    
-    if (idata->status == IMAP_EXPUNGE)
-      idata->reopen |= IMAP_REOPEN_PENDING;
   }
 
   idata->status = 0;
@@ -196,7 +194,8 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s)
       /* new mail arrived */
       count = atoi (pn);
 
-      if ( (idata->status != IMAP_EXPUNGE) && count < idata->ctx->msgcount)
+      if ( !(idata->reopen & IMAP_REOPEN_PENDING) &&
+          count < idata->ctx->msgcount)
       {
        /* something is wrong because the server reported fewer messages
         * than we previously saw
@@ -213,7 +212,7 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s)
           "imap_handle_untagged: superfluous EXISTS message.\n"));
       else
       {
-       if (idata->status != IMAP_EXPUNGE)
+       if (!(idata->reopen & IMAP_REOPEN_PENDING))
         {
           dprint (2, (debugfile,
             "imap_handle_untagged: New mail in %s - %d messages total.\n",
@@ -224,7 +223,8 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s)
       }
     }
     else if (mutt_strncasecmp ("EXPUNGE", s, 7) == 0)
-       idata->status = IMAP_EXPUNGE;
+      /* pn vs. s: need initial seqno */
+      cmd_parse_expunge (idata, pn);
   }
   else if (mutt_strncasecmp ("CAPABILITY", s, 10) == 0)
     cmd_parse_capabilities (idata, s);
@@ -248,7 +248,7 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s)
   {
     /* Display the warning message from the server */
     mutt_error ("%s", s+3);
-    sleep (1);
+    sleep (2);
   }
   else
     dprint (1, (debugfile, "imap_handle_untagged(): unhandled request: %s\n",
@@ -270,7 +270,7 @@ static void cmd_make_sequence (char* buf, size_t buflen)
 
 /* cmd_parse_capabilities: set capability bits according to CAPABILITY
  *   response */
-static void cmd_parse_capabilities (IMAP_DATA *idata, char *s)
+static void cmd_parse_capabilities (IMAP_DATA* idata, char* s)
 {
   int x;
 
@@ -286,6 +286,32 @@ static void cmd_parse_capabilities (IMAP_DATA *idata, char *s)
   }   
 }
 
+/* cmd_parse_expunge: mark headers with new sequence ID and mark idata to
+ *   be reopened at our earliest convenience */
+static void cmd_parse_expunge (IMAP_DATA* idata, char* s)
+{
+  int expno, cur;
+  HEADER* h;
+
+  expno = atoi (s);
+
+  /* walk headers, zero seqno of expunged message, decrement seqno of those
+   * above. Possibly we could avoid walking the whole list by resorting
+   * and guessing a good starting point, but I'm guessing the resort would
+   * nullify the gains */
+  for (cur = 0; cur < idata->ctx->msgcount; cur++)
+  {
+    h = idata->ctx->hdrs[cur];
+
+    if (HEADER_DATA (h)->sid == expno)
+      HEADER_DATA (h)->sid = 0;
+    else if (HEADER_DATA (h)->sid > expno)
+      HEADER_DATA (h)->sid--;
+  }
+
+  idata->reopen |= IMAP_REOPEN_PENDING;
+}
+
 /* cmd_parse_myrights: set rights bits according to MYRIGHTS response */
 static void cmd_parse_myrights (IMAP_DATA* idata, char* s)
 {
index 3ffeb9452a985760d1ecaac51dbc61e255a69077..7f9738cc82110c0d677071aaf797d53fac49ffe3 100644 (file)
@@ -27,6 +27,7 @@
 #include "globals.h"
 #include "sort.h"
 #include "browser.h"
+#include "message.h"
 #include "imap_private.h"
 
 #include <unistd.h>
@@ -186,6 +187,40 @@ int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes)
   return 0;
 }
 
+/* imap_expunge_mailbox: Purge IMAP portion of expunged messages from the
+ *   context. Must not be done while something has a handle on any headers
+ *   (eg inside pager or editor). mx_update_tables and mutt_sort_headers
+ *   must be called afterwards. */
+void imap_expunge_mailbox (IMAP_DATA* idata)
+{
+  HEADER* h;
+  int i, cacheno;
+
+  for (i = 0; i < idata->ctx->msgcount; i++)
+  {
+    h = idata->ctx->hdrs[i];
+
+    if (!HEADER_DATA(h)->sid)
+    {
+      dprint (2, (debugfile, "Expunging message UID %d.\n", HEADER_DATA (h)->uid));
+
+      h->active = 0;
+
+      /* free cached body from disk, if neccessary */
+      cacheno = HEADER_DATA(h)->uid % IMAP_CACHE_LEN;
+      if (idata->cache[cacheno].uid == HEADER_DATA(h)->uid &&
+         idata->cache[cacheno].path)
+      {
+       unlink (idata->cache[cacheno].path);
+       FREE (&idata->cache[cacheno].path);
+      }
+
+      imap_free_header_data (&h->data);
+    }
+  }
+}
+
+#if 0
 /* imap_reopen_mailbox: Reopen an imap mailbox.  This is used when the
  * server sends an EXPUNGE message, indicating that some messages may have
  * been deleted. This is a heavy handed approach, as it reparses all of the
@@ -193,9 +228,10 @@ int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes)
  * something to actually only remove the messages that are marked
  * EXPUNGE.
  */
-int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint)
+int imap_reopen_mailbox (IMAP_DATA* idata)
 {
   HEADER **old_hdrs;
+  CONTEXT* ctx;
   int old_msgcount;
   char buf[LONG_STRING];
   char bufout[LONG_STRING];
@@ -206,6 +242,8 @@ int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint)
   int i, j;
   int index_hint_set;
 
+  ctx = idata->ctx;
+
   ctx->quiet = 1;
 
   if (Sort != SORT_ORDER)
@@ -304,7 +342,7 @@ int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint)
   ctx->msgcount = 0;
   count = imap_read_headers (ctx, 0, count - 1) + 1;
 
-  index_hint_set = (index_hint == NULL);
+  index_hint_set = 1;
 
   if (!ctx->readonly)
   {
@@ -343,8 +381,10 @@ int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint)
       if (found)
       {
        /* this is best done here */
+/*
        if (!index_hint_set && *index_hint == j)
          *index_hint = i;
+*/
 
        if (old_hdrs[j]->changed)
        {
@@ -382,6 +422,7 @@ int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint)
 
   return 0;
 }
+#endif
 
 static int imap_get_delim (IMAP_DATA *idata)
 {
@@ -1095,23 +1136,11 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
       mutt_bit_isset(idata->rights, IMAP_ACL_DELETE))
   {
     mutt_message _("Expunging messages from server...");
-    /* FIXME: these status changes seem dubious */
-    idata->status = IMAP_EXPUNGE;
     if (imap_exec (buf, sizeof (buf), CTX_DATA, "EXPUNGE", 0) != 0)
     {
       imap_error ("imap_sync_mailbox: EXPUNGE failed", buf);
       return -1;
     }
-    idata->status = 0;
-  }
-
-  for (n = 0; n < IMAP_CACHE_LEN; n++)
-  {
-    if (CTX_DATA->cache[n].path)
-    {
-      unlink (CTX_DATA->cache[n].path);
-      safe_free ((void **) &CTX_DATA->cache[n].path);
-    }
   }
 
   return 0;
index 35545ce328fad1b1b2762102261f2a25b5acf6c1..9aa65605e378bae150b26a521ae37b2b80833499 100644 (file)
@@ -49,7 +49,6 @@ enum
 {
   IMAP_FATAL = 1,
   IMAP_NEW_MAIL,
-  IMAP_EXPUNGE,
   IMAP_BYE,
   IMAP_REOPENED
 };
@@ -122,8 +121,8 @@ enum
 /* -- data structures -- */
 typedef struct
 {
-  unsigned int index;
-  char *path;
+  unsigned int uid;
+  charpath;
 } IMAP_CACHE;
 
 typedef struct 
@@ -175,7 +174,8 @@ time_t imap_parse_date (char* s);
 int imap_parse_list_response(IMAP_DATA* idata, char* buf, int buflen,
   char** name, int* noselect, int* noinferiors, char* delim);
 int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes);
-int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint);
+void imap_expunge_mailbox (IMAP_DATA* idata);
+int imap_reopen_mailbox (IMAP_DATA* idata);
 void imap_logout (IMAP_DATA* idata);
 
 /* auth.c */
index 954a1d6779752eb49ed9add5ab4fbbfdc4feae59..3c798ac7648a56094c871f1e401f53145caa5fdd 100644 (file)
@@ -141,6 +141,9 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
        ctx->hdrs[ctx->msgcount] = mutt_new_header ();
        ctx->hdrs[ctx->msgcount]->index = ctx->msgcount;
 
+       /* messages which have not been expunged are ACTIVE (borrowed from
+        * mh folders) */
+       ctx->hdrs[msgno]->active = 1;
        ctx->hdrs[msgno]->read = h->read;
        ctx->hdrs[msgno]->old = h->old;
        ctx->hdrs[msgno]->deleted = h->deleted;
@@ -189,14 +192,16 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
   char *pc;
   long bytes;
   int uid;
+  int cacheno;
   IMAP_CACHE *cache;
 
   /* see if we already have the message in our cache */
-  cache = &CTX_DATA->cache[ctx->hdrs[msgno]->index % IMAP_CACHE_LEN];
+  cacheno = HEADER_DATA(ctx->hdrs[msgno])->uid % IMAP_CACHE_LEN;
+  cache = &CTX_DATA->cache[cacheno];
 
   if (cache->path)
   {
-    if (cache->index == ctx->hdrs[msgno]->index)
+    if (cache->uid == HEADER_DATA(ctx->hdrs[msgno])->uid)
     {
       /* yes, so just return a pointer to the message */
       if (!(msg->fp = fopen (cache->path, "r")))
@@ -216,7 +221,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
 
   mutt_message _("Fetching message...");
 
-  cache->index = ctx->hdrs[msgno]->index;
+  cache->uid = HEADER_DATA(ctx->hdrs[msgno])->uid;
   mutt_mktemp (path);
   cache->path = safe_strdup (path);
   if (!(msg->fp = safe_fopen (path, "w+")))
@@ -628,7 +633,7 @@ static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp)
   
   /* skip to message number */
   buf = imap_next_word (buf);
-  h->number = atoi (buf);
+  h->data->sid = atoi (buf);
 
   /* find FETCH tag */
   buf = imap_next_word (buf);
index ea4d14248fe9aa5e93e2b246401b2e1643740757..af7ebd7fd0ca6470bf79ae2a01abc8b7cab9d596 100644 (file)
 /* IMAP-specific header data, stored as HEADER->data */
 typedef struct imap_header_data
 {
+  unsigned int sid;     /* server message sequence number */
   unsigned int uid;    /* 32-bit Message UID */
   LIST *keywords;
 } IMAP_HEADER_DATA;
 
-/* Linked list to hold header information while downloading message
- * headers */
 typedef struct
 {
   unsigned int read : 1;
@@ -42,7 +41,6 @@ typedef struct
   unsigned int changed : 1;
 
   IMAP_HEADER_DATA* data;
-  unsigned int number;
 
   time_t received;
   long content_length;
@@ -50,4 +48,5 @@ typedef struct
 
 /* -- macros -- */
 #define HEADER_DATA(ph) ((IMAP_HEADER_DATA*) ((ph)->data))
-#endif
+
+#endif /* MESSAGE_H */
diff --git a/mutt.h b/mutt.h
index c0099fe30f32df0392ae74b01d88aa65f74880df..c07f4d5936be57a709318fc4afc09961e4da330c 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -628,7 +628,7 @@ typedef struct header
 #endif
 
 #ifdef USE_IMAP
-  void *data;            /* driver-specific data (only used by IMAP */
+  void *data;            /* driver-specific data (only used by IMAP) */
 #endif
 } HEADER;
 
index e0bfc42766a300b5e1d47bc00d0e43f7ce776870..83c52970668ba029119ce70bab639bb4d903551b 100644 (file)
--- a/muttlib.c
+++ b/muttlib.c
@@ -262,6 +262,9 @@ void mutt_free_header (HEADER **h)
   safe_free ((void **) &(*h)->path);
 #ifdef MIXMASTER
   mutt_free_list (&(*h)->chain);
+#endif
+#ifdef USE_IMAP
+  safe_free ((void**) &(*h)->data);
 #endif
   safe_free ((void **) h);
 }
diff --git a/mx.c b/mx.c
index 61cd80c18e760c99d0590b42f9cb232e1eb42b09..676604b9cce931a5441cdb7096035b92f68aac20 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -1078,7 +1078,7 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint)
   {
 #ifdef USE_IMAP
     if (ctx->magic == M_IMAP && !purge)
-      mutt_message (_("%d kept."), ctx->msgcount);
+      mutt_message (_("Mailbox checkpointed."), ctx->msgcount);
     else
 #endif
     mutt_message (_("%d kept, %d deleted."), ctx->msgcount - ctx->deleted,
@@ -1098,7 +1098,15 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint)
     /* if we haven't deleted any messages, we don't need to resort */
     if (purge)
     {
-      mx_update_tables(ctx, 1);
+#ifdef USE_IMAP
+      /* IMAP uses the active flag, since deleted messages may remain after
+       * a sync */
+      if (ctx->magic == M_IMAP)
+       mx_update_tables (ctx, 0);
+      else
+#endif
+       mx_update_tables (ctx, 1);
+
       mutt_sort_headers (ctx, 1); /* rethread from scratch */
     }
   }