]> granicus.if.org Git - neomutt/commitdiff
A first take at corrected mh/maildir support.
authorThomas Roessler <roessler@does-not-exist.org>
Tue, 22 Sep 1998 22:54:46 +0000 (22:54 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Tue, 22 Sep 1998 22:54:46 +0000 (22:54 +0000)
buffy.c
mbox.c
mh.c
mutt.h
mx.c
mx.h

diff --git a/buffy.c b/buffy.c
index 98c1a0effed6ab9534596347be404f13c64c28ce..d74e6cb1c1bf75f8208b1a5a0c6a66a24e804efc 100644 (file)
--- a/buffy.c
+++ b/buffy.c
@@ -220,7 +220,6 @@ int mutt_buffy_check (int force)
   DIR *dirp;
   char path[_POSIX_PATH_MAX];
   struct stat contex_sb;
-  int res;
   time_t t;
 
   /* fastest return if there are no mailboxes */
@@ -293,8 +292,12 @@ int mutt_buffy_check (int force)
        break;
 
       case M_MAILDIR:
+      case M_MH:
 
-       snprintf (path, sizeof (path), "%s/new", tmp->path);
+       if(tmp->magic == M_MAILDIR)
+         snprintf (path, sizeof (path), "%s/new", tmp->path);
+       else
+         strfcpy (path, tmp->path, sizeof(path));
        if ((dirp = opendir (path)) == NULL)
        {
          tmp->magic = 0;
@@ -313,20 +316,6 @@ int mutt_buffy_check (int force)
        closedir (dirp);
        break;
 
-      case M_MH:
-
-       res = mh_parse_sequences (NULL, tmp->path);
-       if (res >= 0)
-       {
-         BuffyCount += res;
-         tmp->new = res;
-       }
-       else
-       {
-         tmp->magic = 0;
-       }
-       break;
-
 #ifdef USE_IMAP
       case M_IMAP:
        if (imap_buffy_check (tmp->path) > 0)
diff --git a/mbox.c b/mbox.c
index b43319c2baca8a3811d8d1585fd3571a689689a5..5bab6973f89fdac3dec4f959bc133f2f103bb7ec 100644 (file)
--- a/mbox.c
+++ b/mbox.c
@@ -908,3 +908,174 @@ int mbox_close_mailbox (CONTEXT *ctx)
   mx_fastclose_mailbox (ctx);
   return 0;
 }
+
+int mutt_reopen_mailbox (CONTEXT *ctx, int *index_hint)
+{
+  int (*cmp_headers) (const HEADER *, const HEADER *) = NULL;
+  HEADER **old_hdrs;
+  int old_msgcount;
+  int msg_mod = 0;
+  int index_hint_set;
+  int i, j;
+  int rc = -1;
+
+  /* silent operations */
+  ctx->quiet = 1;
+  
+  mutt_message ("Reopening mailbox...");
+  
+  /* our heuristics require the old mailbox to be unsorted */
+  if (Sort != SORT_ORDER)
+  {
+    short old_sort;
+
+    old_sort = Sort;
+    Sort = SORT_ORDER;
+    mutt_sort_headers (ctx, 1);
+    Sort = old_sort;
+  }
+
+  old_hdrs = NULL;
+  old_msgcount = 0;
+  
+  /* simulate a close */
+  hash_destroy (&ctx->id_hash, NULL);
+  hash_destroy (&ctx->subj_hash, NULL);
+  safe_free ((void **) &ctx->v2r);
+  if (ctx->readonly)
+  {
+    for (i = 0; i < ctx->msgcount; i++)
+      mutt_free_header (&(ctx->hdrs[i])); /* nothing to do! */
+    safe_free ((void **) &ctx->hdrs);
+  }
+  else
+  {
+      /* save the old headers */
+    old_msgcount = ctx->msgcount;
+    old_hdrs = ctx->hdrs;
+    ctx->hdrs = NULL;
+  }
+
+  ctx->hdrmax = 0;     /* force allocation of new headers */
+  ctx->msgcount = 0;
+  ctx->vcount = 0;
+  ctx->tagged = 0;
+  ctx->deleted = 0;
+  ctx->new = 0;
+  ctx->unread = 0;
+  ctx->flagged = 0;
+  ctx->changed = 0;
+  ctx->id_hash = hash_create (257);
+  ctx->subj_hash = hash_create (257);
+
+  switch (ctx->magic)
+  {
+    case M_MBOX:
+      fseek (ctx->fp, 0, 0);
+      cmp_headers = mbox_strict_cmp_headers;
+      rc = mbox_parse_mailbox (ctx);
+      break;
+
+    case M_MMDF:
+      fseek (ctx->fp, 0, 0);
+      cmp_headers = mbox_strict_cmp_headers;
+      rc = mmdf_parse_mailbox (ctx);
+      break;
+
+    default:
+      rc = -1;
+      break;
+  }
+  
+  if (rc == -1)
+  {
+    /* free the old headers */
+    for (j = 0; j < old_msgcount; j++)
+      mutt_free_header (&(old_hdrs[j]));
+    safe_free ((void **) &old_hdrs);
+
+    ctx->quiet = 0;
+    return (-1);
+  }
+
+  /* now try to recover the old flags */
+
+  index_hint_set = (index_hint == NULL);
+
+  if (!ctx->readonly)
+  {
+    for (i = 0; i < ctx->msgcount; i++)
+    {
+      int found = 0;
+
+      /* some messages have been deleted, and new  messages have been
+       * appended at the end; the heuristic is that old messages have then
+       * "advanced" towards the beginning of the folder, so we begin the
+       * search at index "i"
+       */
+      for (j = i; j < old_msgcount; j++)
+      {
+       if (old_hdrs[j] == NULL)
+         continue;
+       if (cmp_headers (ctx->hdrs[i], old_hdrs[j]))
+       {
+         found = 1;
+         break;
+       }
+      }
+      if (!found)
+      {
+       for (j = 0; j < i; j++)
+       {
+         if (old_hdrs[j] == NULL)
+           continue;
+         if (cmp_headers (ctx->hdrs[i], old_hdrs[j]))
+         {
+           found = 1;
+           break;
+         }
+       }
+      }
+
+      if (found)
+      {
+       /* this is best done here */
+       if (!index_hint_set && *index_hint == j)
+         *index_hint = i;
+
+       if (old_hdrs[j]->changed)
+       {
+         /* Only update the flags if the old header was changed;
+          * otherwise, the header may have been modified externally,
+          * and we don't want to lose _those_ changes
+          */
+         mutt_set_flag (ctx, ctx->hdrs[i], M_FLAG, old_hdrs[j]->flagged);
+         mutt_set_flag (ctx, ctx->hdrs[i], M_REPLIED, old_hdrs[j]->replied);
+         mutt_set_flag (ctx, ctx->hdrs[i], M_OLD, old_hdrs[j]->old);
+         mutt_set_flag (ctx, ctx->hdrs[i], M_READ, old_hdrs[j]->read);
+       }
+       mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, old_hdrs[j]->deleted);
+       mutt_set_flag (ctx, ctx->hdrs[i], M_TAG, old_hdrs[j]->tagged);
+
+       /* we don't need this header any more */
+       mutt_free_header (&(old_hdrs[j]));
+      }
+    }
+
+    /* free the remaining old headers */
+    for (j = 0; j < old_msgcount; j++)
+    {
+      if (old_hdrs[j])
+      {
+       mutt_free_header (&(old_hdrs[j]));
+       msg_mod = 1;
+      }
+    }
+    safe_free ((void **) &old_hdrs);
+  }
+
+  ctx->quiet = 0;
+
+  return ((ctx->changed || msg_mod) ? M_REOPENED : M_NEW_MAIL);
+}
+
diff --git a/mh.c b/mh.c
index f880a9d8387e0c2230922906cd43de5f09ca84d1..305991da68bbef4ad631d2aad37119b13a594873 100644 (file)
--- a/mh.c
+++ b/mh.c
@@ -25,6 +25,7 @@
 #include "mailbox.h"
 #include "copy.h"
 #include "buffy.h"
+#include "sort.h"
 
 #include <sys/stat.h>
 #include <dirent.h>
 #include <errno.h>
 #include <string.h>
 
-static void maildir_parse_flags(HEADER *h)
+struct maildir
+{
+  HEADER *h;
+  char *canon_fname;
+  struct maildir *next;
+};
+
+static void maildir_free_entry(struct maildir **md)
+{
+  if(!md || !*md)
+    return;
+
+  safe_free((void **) &(*md)->canon_fname);
+  if((*md)->h)
+    mutt_free_header(&(*md)->h);
+
+  safe_free((void **) md);
+}
+  
+static void maildir_free_maildir(struct maildir **md)
+{
+  struct maildir *p, *q;
+  
+  if(!md || !*md)
+    return;
+  
+  for(p = *md; p; p = q)
+  {
+    q = p->next;
+    maildir_free_entry(&p);
+  }
+}
+
+static void maildir_parse_flags(HEADER *h, const char *path)
 {
   char *p;
 
@@ -42,7 +76,7 @@ static void maildir_parse_flags(HEADER *h)
   h->read = 0;
   h->replied = 0;
   
-  if ((p = strchr (h->path, ':')) != NULL && strncmp (p + 1, "2,", 2) == 0)
+  if ((p = strrchr (path, ':')) != NULL && strncmp (p + 1, "2,", 2) == 0)
   {
     p += 3;
     while (*p)
@@ -69,43 +103,34 @@ static void maildir_parse_flags(HEADER *h)
   }
 }
 
-
-void mh_parse_message (CONTEXT *ctx,
-                      const char *subdir,
-                      const char *fname,
-                      int *count,
-                      int isOld)
+static void maildir_update_mtime(CONTEXT *ctx)
 {
-  char path[_POSIX_PATH_MAX];
-  FILE *f;
-  HEADER *h;
+  char buf[_POSIX_PATH_MAX];
   struct stat st;
-
-  if (subdir)
-    snprintf (path, sizeof (path), "%s/%s/%s", ctx->path, subdir, fname);
+  
+  if(ctx->magic == M_MAILDIR)
+  {
+    snprintf(buf, sizeof(buf), "%s/%s", ctx->path, "cur");
+    if(stat (buf, &st) == 0)
+      ctx->mtime_cur = st.st_mtime;
+    snprintf(buf, sizeof(buf), "%s/%s", ctx->path, "new");
+  }
   else
-    snprintf (path, sizeof (path), "%s/%s", ctx->path, fname);
+    strfcpy(buf, ctx->path, sizeof(buf));
+  
+  if(stat(buf, &st) == 0)
+    ctx->mtime = st.st_mtime;
+}
 
-  if ((f = fopen (path, "r")) != NULL)
+static HEADER *maildir_parse_message(int magic, const char *fname, int is_old)
+{
+  FILE *f;
+  HEADER *h = NULL;
+  struct stat st;
+  
+  if ((f = fopen (fname, "r")) != NULL)
   {
-    (*count)++;
-
-    if (!ctx->quiet && ReadInc && ((*count % ReadInc) == 0 || *count == 1))
-      mutt_message ("Reading %s... %d", ctx->path, *count);
-
-    if (ctx->msgcount == ctx->hdrmax)
-      mx_alloc_memory (ctx);
-
-    h = ctx->hdrs[ctx->msgcount] = mutt_new_header ();
-
-    if (subdir)
-    {
-      snprintf (path, sizeof (path), "%s/%s", subdir, fname);
-      h->path = safe_strdup (path);
-    }
-    else
-      h->path = safe_strdup (fname);
-
+    h = mutt_new_header();
     h->env = mutt_read_rfc822_header (f, h);
 
     fstat (fileno (f), &st);
@@ -117,226 +142,137 @@ void mh_parse_message (CONTEXT *ctx,
     if (h->content->length <= 0)
       h->content->length = st.st_size - h->content->offset;
 
-    /* index doesn't have a whole lot of meaning for MH and maildir mailboxes,
-     * but this is used to find the current message after a resort in 
-     * the `index' event loop.
-     */
-    h->index = ctx->msgcount;
+    h->index = -1;
 
-    if (ctx->magic == M_MAILDIR)
+    if (magic == M_MAILDIR)
     {
       /* maildir stores its flags in the filename, so ignore the flags in
        * the header of the message
        */
 
-      h->old = isOld;
-      maildir_parse_flags(h);
+      h->old = is_old;
+      maildir_parse_flags(h, fname);
     }
-    /* set flags and update context info */
-    mx_update_context (ctx);
   }
+  return h;
 }
 
-/*
- * Mark all the mails in ctx read.
- */
-static void tag_all_read (CONTEXT * ctx)
+/* note that this routine will _not_ modify the context given by ctx. */
+
+static int maildir_parse_entry(CONTEXT *ctx, struct maildir ***last,
+                               const char *subdir, const char *fname,
+                               int *count, int is_old)
 {
-  int i;
+  struct maildir *entry;
+  HEADER *h;
+  char buf[_POSIX_PATH_MAX];
 
-  ctx->new = 0;
-  if (ctx->hdrs == NULL)
-    return;
-  for (i = 0; i < ctx->msgcount; i++)
+  if(subdir)
+    snprintf(buf, sizeof(buf), "%s/%s/%s", ctx->path, subdir, fname);
+  else
+    snprintf(buf, sizeof(buf), "%s/%s", ctx->path, fname);
+  
+  if((h = maildir_parse_message(ctx->magic, buf, is_old)) != NULL)
   {
-    ctx->hdrs[i]->read = 1;
-    ctx->hdrs[i]->old = 1;
-  }
-}
-
-/*
- * Mark one mail as unread
- */
-static int tag_unread (CONTEXT * ctx, char *name)
-{
-  int i;
+    if(count)
+    {
+      (*count)++;  
+      if (!ctx->quiet && ReadInc && ((*count % ReadInc) == 0 || *count == 1))
+       mutt_message ("Reading %s... %d", ctx->path, *count);
+    }
 
-  if (ctx->hdrs == NULL)
-    return (1);
-  for (i = ctx->msgcount - 1; i >= 0; i--)
-    if (!strcmp (name, ctx->hdrs[i]->path))
+    if (subdir)
     {
-      ctx->hdrs[i]->read = 0;
-      ctx->hdrs[i]->old = 0;
-      return (1);
+      snprintf (buf, sizeof (buf), "%s/%s", subdir, fname);
+      h->path = safe_strdup (buf);
     }
-  return (0);
+    else
+      h->path = safe_strdup (fname);
+    
+    entry = safe_calloc(sizeof(struct maildir), 1);
+    entry->h = h;
+    **last = entry;
+    *last = &entry->next;
+    
+    return 0;
+  }
+  
+  return -1;
 }
 
-/* Parse a .mh_sequences file.  Only supports "unseen:" field.
+/* Ignore the garbage files.  A valid MH message consists of only
+ * digits.  Deleted message get moved to a filename with a comma before
+ * it.
  */
 
-#define SKIP_BLANK(p)                                                  \
-    while ((*(p) == ' ') || (*(p) == '\t')) p++;
-
-#define SKIP_EOL(p)                                                     \
-{                                                                      \
-    while ((*p != '\0') && (*(p) != '\n') && (*(p) != '\r')) p++;      \
-    while ((*(p) == '\n') || (*(p) == '\r')) p++;                      \
-}
-
-/* Parses and returns the next unsigned number in the string <cur>, 
-   advancing the pointer to the character after the number ended.
- */
-static unsigned parse_number (const char **cur)
+int mh_valid_message (const char *s)
 {
-  unsigned i = 0;
-  for (; (**cur >= '0') && (**cur <= '9'); (*cur)++)
+  for (; *s; s++)
   {
-    i *= 10;
-    i += **cur - '0';
+    if (!isdigit ((unsigned char) *s))
+      return 0;
   }
-  return i;
+  return 1;
 }
 
-/* if context is NULL, it uses <folder> as the mailbox path, otherwise,
-   uses ctx->path.  If context is not null, tags all the unread messages 
-   and sets the position correctly.
-   returns the number of unread messages in the mailbox.
- */
-int mh_parse_sequences (CONTEXT * ctx, const char *folder)
+static int maildir_parse_dir(CONTEXT *ctx, struct maildir ***last,
+                            const char *subdir, int *count)
 {
-  FILE *mh_sequences;
-  struct stat sb;
-  char *content;
-  const char *cur;
-  int len;
-  int base, last;
+  DIR *dirp;
+  struct dirent *de;
   char buf[_POSIX_PATH_MAX];
-  char filename[100];
-  int unread = 0;
-  static HASH *cache = 0;
-  int *h;
-
-  if (!cache) {
-    cache = hash_create (100); /* If this ain't enough, read less mail! */
-    if (!cache)
-    {
-      mutt_error ("mh_parse_sequences: Unable to allocate hash table!\n");
-      return -1;
-    }
-  }
-
-  if (ctx)
-    folder = ctx->path;
-
-  snprintf (buf, sizeof (buf), "%s/.mh_sequences", folder);
-  if (stat (buf, &sb) != 0)
-    return (-1);
-
-  if (ctx)
-    tag_all_read (ctx);
-
-  if (!ctx && sb.st_mtime < BuffyDoneTime && (h = hash_find (cache, folder))) /* woo!  we win! */
-    return *h;
-
-  /*
-   * Parse the .mh_sequence to find the unread ones.
-   */
-
-  content = safe_malloc (sb.st_size + 100);
-  if (content == NULL)
+  int is_old = 0;
+  
+  if(subdir)
   {
-    mutt_perror ("malloc");
-    return (-1);
+    snprintf(buf, sizeof(buf), "%s/%s", ctx->path, subdir);
+    is_old = (strcmp("cur", subdir) == 0) && option(OPTMARKOLD);
   }
-  mh_sequences = fopen (buf, "r");
-  if (mh_sequences == NULL)
+  else
+    strfcpy(buf, ctx->path, sizeof(buf));
+  
+  if((dirp = opendir(buf)) == NULL)
+    return -1;
+
+  while ((de = readdir (dirp)) != NULL)
   {
-    mutt_message ("Cannot open %s", buf);
-    safe_free ((void **) &content);
-    return (-1);
+    if ((ctx->magic == M_MH && !mh_valid_message(de->d_name)) || (ctx->magic == M_MAILDIR && *de->d_name == '.'))
+      continue;
+    
+    /* FOO - really ignore the return value? */
+    
+    maildir_parse_entry(ctx, last, subdir, de->d_name, count, is_old);
   }
 
-  len = fread (content, 1, sb.st_size, mh_sequences);
-  content[len] = '\0';
-
-  fclose (mh_sequences);
+  closedir(dirp);
+  return 0;
+}
 
-  cur = content;
-  SKIP_BLANK (cur);
-  while (*cur != '\0')
+static void maildir_add_to_context(CONTEXT *ctx, struct maildir *md)
+{
+  while(md)
   {
-    if (!strncmp (cur, "unseen", 6))
+    if(md->h)
     {
-      cur += 6;
-      SKIP_BLANK (cur);
-      if (*cur == ':')
-      {
-       cur++;
-       SKIP_BLANK (cur);
-      }
-      while ((*cur >= '0') && (*cur <= '9'))
-      {
-       base = parse_number (&cur);
-       SKIP_BLANK (cur);
-       if (*cur == '-')
-       {
-         cur++;
-         SKIP_BLANK (cur);
-         last = parse_number (&cur);
-       }
-       else
-         last = base;
-       if (ctx)
-         for (; base <= last; base++)
-         {
-           sprintf (filename, "%d", base);
-           if (tag_unread (ctx, filename))
-             unread++;
-         }
-       else
-         unread += last - base + 1;
-       SKIP_BLANK (cur);
-      }
+      if(ctx->msgcount == ctx->hdrmax)
+       mx_alloc_memory(ctx);
+      
+      ctx->hdrs[ctx->msgcount] = md->h;
+      ctx->hdrs[ctx->msgcount]->index = ctx->msgcount;
+      ctx->size +=
+       md->h->content->length + md->h->content->offset - md->h->content->hdr_offset;
+      
+      md->h = NULL;
+      mx_update_context(ctx);
     }
-    SKIP_EOL (cur);
-    SKIP_BLANK (cur);
-  }
-  if (unread != 0)
-  {
-    mutt_message ("Folder %s : %d unread", folder, unread);
+    md = md->next;
   }
-  if (ctx)
-    ctx->new = unread;
-
-  safe_free ((void **) &content);
-
-  /* Cache the data so we only have to do 'stat's in the future */
-  if (!(h = hash_find (cache, folder)))
-  {
-    h = safe_malloc (sizeof (int));
-    if (!h)                            /* dear god, I hope not... */
-      return -1;
-    hash_insert (cache, folder, h, 1);  /* every other time we just adjust the pointer */
-  }
-  *h = unread;
-
-  return unread;
 }
 
-/* Ignore the garbage files.  A valid MH message consists of only
- * digits.  Deleted message get moved to a filename with a comma before
- * it.
- */
-int mh_valid_message (const char *s)
+static void maildir_move_to_context(CONTEXT *ctx, struct maildir **md)
 {
-  for (; *s; s++)
-  {
-    if (!isdigit ((unsigned char) *s))
-      return 0;
-  }
-  return 1;
+  maildir_add_to_context(ctx, *md);
+  maildir_free_maildir(md);
 }
 
 /* Read a MH/maildir style mailbox.
@@ -348,75 +284,23 @@ int mh_valid_message (const char *s)
  */
 int mh_read_dir (CONTEXT *ctx, const char *subdir)
 {
-  DIR *dirp;
-  struct dirent *de;
-  char buf[_POSIX_PATH_MAX];
-  int isOld = 0;
-  int count = 0;
-  struct stat st;
-  int has_mh_sequences = 0;
-
-  if (subdir)
-  {
-    snprintf (buf, sizeof (buf), "%s/%s", ctx->path, subdir);
-    isOld = (strcmp ("cur", subdir) == 0) && option (OPTMARKOLD);
-  }
-  else
-    strfcpy (buf, ctx->path, sizeof (buf));
-
-  if (stat (buf, &st) == -1)
-    return (-1);
-
-  if ((dirp = opendir (buf)) == NULL)
-    return (-1);
-
-  if (!subdir || (subdir && strcmp (subdir, "new") == 0))
-    ctx->mtime = st.st_mtime;
-
-  while ((de = readdir (dirp)) != NULL)
-  {
-    if (ctx->magic == M_MH)
-    {
-      if (!mh_valid_message (de->d_name))
-      {
-       if (!strcmp (de->d_name, ".mh_sequences"))
-         has_mh_sequences++;
-       continue;
-      }
-    }
-    else if (*de->d_name == '.')
-    {
-      /* Skip files that begin with a dot.  This currently isn't documented
-       * anywhere, but it was a suggestion from the author of QMail on the
-       * mailing list.
-       */
-      continue;
-    }
-
-    mh_parse_message (ctx, subdir, de->d_name, &count, isOld);
-  }
-  {
-    int i;
-#define this_body ctx->hdrs[i]->content
-    ctx->size = 0;
-    for (i = 0; i < ctx->msgcount; i++)
-      ctx->size += this_body->length + this_body->offset -
-       this_body->hdr_offset;
-#undef this_body
-  }
+  struct maildir *md;
+  struct maildir **last;
+  int count;
+  
+  md = NULL;
+  last = &md;
+  count = 0;
 
-  /*
-   * MH style .
-   */
-  if (has_mh_sequences)
-  {
-    mh_parse_sequences (ctx, NULL);
-  }
+  maildir_update_mtime(ctx);
 
-  closedir (dirp);
+  if(maildir_parse_dir(ctx, &last, subdir, &count) == -1)
+    return -1;
+  
+  maildir_move_to_context(ctx, &md);
   return 0;
 }
-
+  
 /* read a maildir style mailbox */
 int maildir_read_dir (CONTEXT * ctx)
 {
@@ -622,8 +506,17 @@ int mh_sync_mailbox (CONTEXT * ctx)
 {
   char path[_POSIX_PATH_MAX], tmp[_POSIX_PATH_MAX];
   int i, rc = 0;
-  FILE *mh_sequences;
-
+  
+  i = mh_check_mailbox(ctx, NULL);
+  if(i == M_REOPENED)
+  {
+    set_option(OPTSORTCOLLAPSE);
+    mutt_sort_headers(ctx, 1);
+    unset_option(OPTSORTCOLLAPSE);
+  }
+  
+  if(i == M_REOPENED || i == M_NEW_MAIL || i < 0)
+    return i;
 
   for (i = 0; i < ctx->msgcount; i++)
   {
@@ -655,127 +548,156 @@ int mh_sync_mailbox (CONTEXT * ctx)
       }
     }
   }
-
-  if(ctx->magic == M_MH)
-  {
-    snprintf (path, sizeof (path), "%s/%s", ctx->path, ".mh_sequences");
-    mh_sequences = fopen (path, "w");
-    if (mh_sequences == NULL)
-    {
-      mutt_message ("fopen %s failed", path);
-    }
-    else
-    {
-      fprintf (mh_sequences, "unseen: ");
-      for (i = 0; i < ctx->msgcount; i++)
-       if ((ctx->hdrs[i]->read == 0) && !(ctx->hdrs[i]->deleted))
-         fprintf (mh_sequences, "%s ", ctx->hdrs[i]->path);
-      fprintf (mh_sequences, "\n");
-      fclose (mh_sequences);
-    }
-  }
-
+  maildir_update_mtime(ctx);
   return (rc);
 }
 
-/* check for new mail */
-int mh_check_mailbox (CONTEXT * ctx, int *index_hint)
+static char *maildir_canon_filename(char *dest, char *src, size_t l)
 {
-  DIR *dirp;
-  struct dirent *de;
-  char buf[_POSIX_PATH_MAX];
-  struct stat st;
-  LIST *lst = NULL, *tmp = NULL, *prev;
-  int i, lng = 0;
-  int count = 0;
+  char *t, *u;
+  
+  if((t = strchr(src, '/')))
+    src = t + 1;
 
-  /* MH users might not like the behavior of this function because it could
-   * take awhile if there are many messages in the mailbox.
-   */
-  if (!option (OPTCHECKNEW))
-    return (0); /* disabled */
+  strfcpy(dest, src, l);
+  if((u = strchr(dest, ';')))
+    *u = '\0';
+  
+  return dest;
+}
 
-  if (ctx->magic == M_MH)
-    strfcpy (buf, ctx->path, sizeof (buf));
-  else
-    snprintf (buf, sizeof (buf), "%s/new", ctx->path);
 
-  if (stat (buf, &st) == -1)
-    return (-1);
+/* This function handles arrival of new mail and reopening of mh/maildir folders.
+ * Things are getting rather complex because we don't have a
+ * well-defined "mailbox order", so the tricks from mbox.c and mx.c
+ * won't work here.
+ */
 
-  if (st.st_mtime == ctx->mtime)
-    return (0); /* unchanged */
+int mh_check_mailbox(CONTEXT *ctx, int *index_hint)
+{
+  char buf[_POSIX_PATH_MAX], b1[LONG_STRING], b2[LONG_STRING];
+  struct stat st, st_cur;
+  short modified = 0, have_new = 0;
+  struct maildir *md, *p;
+  struct maildir **last;
+  HASH *fnames;
+  int i, j;
+  
+  if(!option (OPTCHECKNEW))
+    return 0;
+  
+  if(ctx->magic == M_MH)
+  {
+    strfcpy(buf, ctx->path, sizeof(buf));
+    if(stat(buf, &st) == -1)
+      return -1;
+  }
+  else if(ctx->magic == M_MAILDIR)
+  {
+    snprintf(buf, sizeof(buf), "%s/new", ctx->path);
+    if(stat(buf, &st) == -1)
+      return -1;
+    
+    snprintf(buf, sizeof(buf), "%s/cur", ctx->path);
+    if(stat(buf, &st_cur) == -1)
+      modified = 1;
 
-  if ((dirp = opendir (buf)) == NULL)
-    return (-1);
+  }
+  
+  if(!modified && ctx->magic == M_MAILDIR && st_cur.st_mtime > ctx->mtime_cur)
+    modified = 1;
+  
+  if(!modified && ctx->magic == M_MH && st.st_mtime > ctx->mtime)
+    modified = 1;
+  
+  if(modified || (ctx->magic == M_MAILDIR && st.st_mtime > ctx->mtime))
+    have_new = 1;
+  
+  if(!modified && !have_new)
+    return 0;
 
-  while ((de = readdir (dirp)) != NULL)
+  if(ctx->magic == M_MAILDIR)
+    ctx->mtime_cur = st_cur.st_mtime;
+  ctx->mtime = st.st_mtime;
+  
+  if(Sort != SORT_ORDER)
   {
-    if (ctx->magic == M_MH)
-    {
-      if (!mh_valid_message (de->d_name))
-       continue;
-    }
-    else /* maildir */
-    {
-      if (*de->d_name == '.')
-       continue;
-    }
+    short old_sort;
+    
+    old_sort = Sort;
+    Sort = SORT_ORDER;
+    mutt_sort_headers(ctx, 1);
+    Sort = old_sort;
+  }
+    
+  md = NULL;
+  last = &md;
+  
+  if(ctx->magic == M_MAILDIR)
+  {
+    if(have_new)
+      maildir_parse_dir(ctx, &last, "new", NULL);
+    if(modified)
+      maildir_parse_dir(ctx, &last, "cur", NULL);
+  }
+  else if(ctx->magic == M_MH)
+    maildir_parse_dir(ctx, &last, NULL, NULL);
 
-    if (tmp)
+  /* check for modifications and adjust flags */
+
+  fnames = hash_create(1024);
+  
+  for(p = md; p; p = p->next)
+  {
+    if(ctx->magic == M_MAILDIR)
     {
-      tmp->next = mutt_new_list ();
-      tmp = tmp->next;
+      maildir_canon_filename(b2, p->h->path, sizeof(b2));
+      p->canon_fname = safe_strdup(b2);
     }
     else
-      lst = tmp = mutt_new_list ();
-    tmp->data = safe_strdup (de->d_name);
+      p->canon_fname = safe_strdup(p->h->path);
+    
+    hash_insert(fnames, p->canon_fname, p, 0);
   }
-  closedir (dirp);
-
-  ctx->mtime = st.st_mtime; /* save the time we scanned at */
-
-  if (!lst)
-    return 0;
-
-  /* if maildir, skip the leading "new/" */
-  lng = (ctx->magic == M_MAILDIR) ? 4 : 0;
-
-  for (i = 0; i < ctx->msgcount; i++)
+  
+  for(i = 0; i < ctx->msgcount; i++)
   {
-    if (ctx->magic == M_MAILDIR && ctx->hdrs[i]->old)
-      continue; /* only look at NEW messages */
+    ctx->hdrs[i]->active = 0;
+    if(ctx->magic == M_MAILDIR)
+      maildir_canon_filename(b1, ctx->hdrs[i]->path, sizeof(b1));
+    else
+      strfcpy(b1, ctx->hdrs[i]->path, sizeof(b1));
 
-    prev = NULL;
-    tmp = lst;
-    while (tmp)
+    if((p = hash_find(fnames, b1)))
     {
-      if (strcmp (tmp->data, ctx->hdrs[i]->path + lng) == 0)
-      {
-       if (prev)
-         prev->next = tmp->next;
-       else
-         lst = lst->next;
-       safe_free ((void **) &tmp->data);
-       safe_free ((void **) &tmp);
-       break;
-      }
-      else
+      if(!p->h)
+       continue;
+
+      if(!mbox_strict_cmp_headers(ctx->hdrs[i], p->h))
+       continue;
+
+      if(modified)
       {
-       prev = tmp;
-       tmp = tmp->next;
+       if(!ctx->hdrs[i]->changed)
+       {
+         ctx->hdrs[i]->flagged = p->h->flagged;
+         ctx->hdrs[i]->replied = p->h->replied;
+         ctx->hdrs[i]->old     = p->h->old;
+         ctx->hdrs[i]->read    = p->h->read;
+       }
       }
+      
+      ctx->hdrs[i]->active = 1;
+      mutt_free_header(&p->h);
     }
   }
-
-  for (tmp = lst; tmp; tmp = lst)
-  {
-    mh_parse_message (ctx, (ctx->magic == M_MH ? NULL : "new"), tmp->data, &count, 0);
-
-    lst = tmp->next;
-    safe_free ((void **) &tmp->data);
-    safe_free ((void **) &tmp);
-  }
-
-  return (1);
+    
+  hash_destroy(&fnames, NULL);
+    
+  if(modified)
+    mx_update_tables(ctx, 0);
+
+  maildir_move_to_context(ctx, &md);
+  return modified ? M_REOPENED : have_new ? M_NEW_MAIL : 0;
 }
+
diff --git a/mutt.h b/mutt.h
index 9f3d647c1bca6b5867fa39cb7a4148f0e5393291..86f7af8a476a4833f32d4c774c256ee1a5f25c59 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -475,6 +475,10 @@ typedef struct body
 
 typedef struct header
 {
+  #ifdef _PGPPATH
+  unsigned int pgp : 3;
+#endif
+
   unsigned int mime : 1;    /* has a Mime-Version header? */
   unsigned int mailcap : 1; /* requires mailcap to display? */
   unsigned int flagged : 1; /* marked important? */
@@ -486,28 +490,14 @@ typedef struct header
   unsigned int read : 1;
   unsigned int expired : 1; /* already expired? */
   unsigned int superseded : 1; /* got superseded? */
-
-
-
-
-#ifdef _PGPPATH
-  unsigned int pgp : 3;
-#endif
-
-
-
-
-
-
-
-
-
   unsigned int replied : 1;
   unsigned int subject_changed : 1; /* used for threading */
   unsigned int display_subject : 1; /* used for threading */
   unsigned int fake_thread : 1;     /* no ref matched, but subject did */
   unsigned int threaded : 1;        /* message has been threaded */
 
+  unsigned int active : 1;
+  
   /* timezone of the sender of this message */
   unsigned int zhours : 5;
   unsigned int zminutes : 6;
@@ -571,6 +561,7 @@ typedef struct
   char *path;
   FILE *fp;
   time_t mtime;
+  time_t mtime_cur;            /* used with maildir folders */
   off_t size;
   off_t vsize;
   char *pattern;                /* limit pattern string */
diff --git a/mx.c b/mx.c
index 3522a07a98331424865d8a6a6e0882660aa53388..d2c7f104bea862346ada5f923691fa04d3bdf65d 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -829,6 +829,73 @@ int mx_close_mailbox (CONTEXT *ctx)
   return 0;
 }
 
+
+/* update a Context structure's internal tables. */
+
+void mx_update_tables(CONTEXT *ctx, int do_delete)
+{
+  int i, j;
+  
+  /* update memory to reflect the new state of the mailbox */
+  ctx->vcount = 0;
+  ctx->vsize = 0;
+  ctx->tagged = 0;
+  ctx->deleted = 0;
+  ctx->new = 0;
+  ctx->unread = 0;
+  ctx->changed = 0;
+  ctx->flagged = 0;
+#define this_body ctx->hdrs[j]->content
+  for (i = 0, j = 0; i < ctx->msgcount; i++)
+  {
+    if ((do_delete && !ctx->hdrs[i]->deleted) || 
+       (!do_delete && ctx->hdrs[i]->active))
+    {
+      if (i != j)
+      {
+       ctx->hdrs[j] = ctx->hdrs[i];
+       ctx->hdrs[i] = NULL;
+      }
+      ctx->hdrs[j]->msgno = j;
+      if (ctx->hdrs[j]->virtual != -1)
+      {
+       ctx->v2r[ctx->vcount] = j;
+       ctx->hdrs[j]->virtual = ctx->vcount++;
+       ctx->vsize += this_body->length + this_body->offset -
+         this_body->hdr_offset;
+      }
+      ctx->hdrs[j]->changed = 0;
+      if (ctx->hdrs[j]->tagged)
+       ctx->tagged++;
+      if (ctx->hdrs[j]->flagged)
+       ctx->flagged++;
+      if (!ctx->hdrs[j]->read)
+      { 
+       ctx->unread++;
+       if (!ctx->hdrs[j]->old)
+         ctx->new++;
+      } 
+      j++;
+    }
+    else
+    {
+      if (ctx->magic == M_MH || ctx->magic == M_MAILDIR)
+       ctx->size -= (ctx->hdrs[i]->content->length +
+                     ctx->hdrs[i]->content->offset -
+                     ctx->hdrs[i]->content->hdr_offset);
+      /* remove message from the hash tables */
+      if (ctx->hdrs[i]->env->real_subj)
+       hash_delete (ctx->subj_hash, ctx->hdrs[i]->env->real_subj, ctx->hdrs[i], NULL);
+      if (ctx->hdrs[i]->env->message_id)
+       hash_delete (ctx->id_hash, ctx->hdrs[i]->env->message_id, ctx->hdrs[i], NULL);
+      mutt_free_header (&ctx->hdrs[i]);
+    }
+  }
+#undef this_body
+  ctx->msgcount = j;
+}
+
+
 /* save changes to mailbox
  *
  * return values:
@@ -837,7 +904,7 @@ int mx_close_mailbox (CONTEXT *ctx)
  */
 int mx_sync_mailbox (CONTEXT *ctx)
 {
-  int rc, i, j;
+  int rc, i;
 
   if (ctx->dontwrite)
   {
@@ -896,63 +963,7 @@ int mx_sync_mailbox (CONTEXT *ctx)
       return 0;
     }
 
-    /* update memory to reflect the new state of the mailbox */
-    ctx->vcount = 0;
-    ctx->vsize = 0;
-    ctx->tagged = 0;
-    ctx->deleted = 0;
-    ctx->new = 0;
-    ctx->unread = 0;
-    ctx->changed = 0;
-    ctx->flagged = 0;
-#define this_body ctx->hdrs[j]->content
-    for (i = 0, j = 0; i < ctx->msgcount; i++)
-    {
-      if (!ctx->hdrs[i]->deleted)
-      {
-       if (i != j)
-       {
-         ctx->hdrs[j] = ctx->hdrs[i];
-         ctx->hdrs[i] = NULL;
-       }
-       ctx->hdrs[j]->msgno = j;
-       if (ctx->hdrs[j]->virtual != -1)
-       {
-         ctx->v2r[ctx->vcount] = j;
-         ctx->hdrs[j]->virtual = ctx->vcount++;
-         ctx->vsize += this_body->length + this_body->offset -
-                       this_body->hdr_offset;
-       }
-       ctx->hdrs[j]->changed = 0;
-       if (ctx->hdrs[j]->tagged)
-         ctx->tagged++;
-       if (ctx->hdrs[j]->flagged)
-         ctx->flagged++;
-       if (!ctx->hdrs[j]->read)
-       { 
-         ctx->unread++;
-         if (!ctx->hdrs[j]->old)
-           ctx->new++;
-       } 
-       j++;
-      }
-      else
-      {
-       if (ctx->magic == M_MH || ctx->magic == M_MAILDIR)
-        ctx->size -= (ctx->hdrs[i]->content->length +
-                      ctx->hdrs[i]->content->offset -
-                      ctx->hdrs[i]->content->hdr_offset);
-       /* remove message from the hash tables */
-       if (ctx->hdrs[i]->env->real_subj)
-         hash_delete (ctx->subj_hash, ctx->hdrs[i]->env->real_subj, ctx->hdrs[i], NULL);
-       if (ctx->hdrs[i]->env->message_id)
-         hash_delete (ctx->id_hash, ctx->hdrs[i]->env->message_id, ctx->hdrs[i], NULL);
-       mutt_free_header (&ctx->hdrs[i]);
-      }
-    }
-#undef this_body
-    ctx->msgcount = j;
-
+    mx_update_tables(ctx, 1);
     set_option (OPTSORTCOLLAPSE);
     mutt_sort_headers (ctx, 1); /* rethread from scratch */
     unset_option (OPTSORTCOLLAPSE);
@@ -1118,186 +1129,6 @@ MESSAGE *mx_open_new_message (CONTEXT *dest, HEADER *hdr, int flags)
   return msg;
 }
 
-int mutt_reopen_mailbox (CONTEXT *ctx, int *index_hint)
-{
-  int (*cmp_headers) (const HEADER *, const HEADER *) = NULL;
-  HEADER **old_hdrs;
-  int old_msgcount;
-  int msg_mod = 0;
-  int index_hint_set;
-  int i, j;
-  int rc = -1;
-
-  /* silent operations */
-  ctx->quiet = 1;
-  
-  mutt_message ("Reopening mailbox...");
-  
-  /* our heuristics require the old mailbox to be unsorted */
-  if (Sort != SORT_ORDER)
-  {
-    short old_sort;
-
-    old_sort = Sort;
-    Sort = SORT_ORDER;
-    mutt_sort_headers (ctx, 1);
-    Sort = old_sort;
-  }
-
-  old_hdrs = NULL;
-  old_msgcount = 0;
-  
-  /* simulate a close */
-  hash_destroy (&ctx->id_hash, NULL);
-  hash_destroy (&ctx->subj_hash, NULL);
-  safe_free ((void **) &ctx->v2r);
-  if (ctx->readonly)
-  {
-    for (i = 0; i < ctx->msgcount; i++)
-      mutt_free_header (&(ctx->hdrs[i])); /* nothing to do! */
-    safe_free ((void **) &ctx->hdrs);
-  }
-  else
-  {
-      /* save the old headers */
-    old_msgcount = ctx->msgcount;
-    old_hdrs = ctx->hdrs;
-    ctx->hdrs = NULL;
-  }
-
-  ctx->hdrmax = 0;     /* force allocation of new headers */
-  ctx->msgcount = 0;
-  ctx->vcount = 0;
-  ctx->tagged = 0;
-  ctx->deleted = 0;
-  ctx->new = 0;
-  ctx->unread = 0;
-  ctx->flagged = 0;
-  ctx->changed = 0;
-  ctx->id_hash = hash_create (257);
-  ctx->subj_hash = hash_create (257);
-
-  switch (ctx->magic)
-  {
-    case M_MBOX:
-      fseek (ctx->fp, 0, 0);
-      cmp_headers = mbox_strict_cmp_headers;
-      rc = mbox_parse_mailbox (ctx);
-      break;
-
-    case M_MMDF:
-      fseek (ctx->fp, 0, 0);
-      cmp_headers = mbox_strict_cmp_headers;
-      rc = mmdf_parse_mailbox (ctx);
-      break;
-
-    case M_MH:
-      /* cmp_headers = mh_strict_cmp_headers; */
-      rc = mh_read_dir (ctx, NULL);
-      break;
-
-    case M_MAILDIR:
-      /* cmp_headers = maildir_strict_cmp_headers; */
-      rc = maildir_read_dir (ctx);
-      break;
-
-    default:
-      rc = -1;
-      break;
-  }
-  
-  if (rc == -1)
-  {
-    /* free the old headers */
-    for (j = 0; j < old_msgcount; j++)
-      mutt_free_header (&(old_hdrs[j]));
-    safe_free ((void **) &old_hdrs);
-
-    ctx->quiet = 0;
-    return (-1);
-  }
-
-  /* now try to recover the old flags */
-
-  index_hint_set = (index_hint == NULL);
-
-  if (!ctx->readonly)
-  {
-    for (i = 0; i < ctx->msgcount; i++)
-    {
-      int found = 0;
-
-      /* some messages have been deleted, and new  messages have been
-       * appended at the end; the heuristic is that old messages have then
-       * "advanced" towards the beginning of the folder, so we begin the
-       * search at index "i"
-       */
-      for (j = i; j < old_msgcount; j++)
-      {
-       if (old_hdrs[j] == NULL)
-         continue;
-       if (cmp_headers (ctx->hdrs[i], old_hdrs[j]))
-       {
-         found = 1;
-         break;
-       }
-      }
-      if (!found)
-      {
-       for (j = 0; j < i; j++)
-       {
-         if (old_hdrs[j] == NULL)
-           continue;
-         if (cmp_headers (ctx->hdrs[i], old_hdrs[j]))
-         {
-           found = 1;
-           break;
-         }
-       }
-      }
-
-      if (found)
-      {
-       /* this is best done here */
-       if (!index_hint_set && *index_hint == j)
-         *index_hint = i;
-
-       if (old_hdrs[j]->changed)
-       {
-         /* Only update the flags if the old header was changed;
-          * otherwise, the header may have been modified externally,
-          * and we don't want to lose _those_ changes
-          */
-         mutt_set_flag (ctx, ctx->hdrs[i], M_FLAG, old_hdrs[j]->flagged);
-         mutt_set_flag (ctx, ctx->hdrs[i], M_REPLIED, old_hdrs[j]->replied);
-         mutt_set_flag (ctx, ctx->hdrs[i], M_OLD, old_hdrs[j]->old);
-         mutt_set_flag (ctx, ctx->hdrs[i], M_READ, old_hdrs[j]->read);
-       }
-       mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, old_hdrs[j]->deleted);
-       mutt_set_flag (ctx, ctx->hdrs[i], M_TAG, old_hdrs[j]->tagged);
-
-       /* we don't need this header any more */
-       mutt_free_header (&(old_hdrs[j]));
-      }
-    }
-
-    /* free the remaining old headers */
-    for (j = 0; j < old_msgcount; j++)
-    {
-      if (old_hdrs[j])
-      {
-       mutt_free_header (&(old_hdrs[j]));
-       msg_mod = 1;
-      }
-    }
-    safe_free ((void **) &old_hdrs);
-  }
-
-  ctx->quiet = 0;
-
-  return ((ctx->changed || msg_mod) ? M_REOPENED : M_NEW_MAIL);
-}
-
 /* check for new mail */
 int mx_check_mailbox (CONTEXT *ctx, int *index_hint)
 {
diff --git a/mx.h b/mx.h
index a430f1d81373435317e17e661f7d19e98b870f20..3026fa0383bae844df7382f2857fcc193189d775 100644 (file)
--- a/mx.h
+++ b/mx.h
@@ -57,6 +57,7 @@ int mutt_reopen_mailbox (CONTEXT *, int *);
 
 void mx_alloc_memory (CONTEXT *);
 void mx_update_context (CONTEXT *);
+void mx_update_tables (CONTEXT *, int);
 
 FILE *mx_open_file_lock (const char *, const char *);