]> granicus.if.org Git - mutt/commitdiff
Combine the basic and extended buffy functions.
authorKevin McCarthy <kevin@8t8.us>
Fri, 17 Jun 2016 17:30:30 +0000 (10:30 -0700)
committerKevin McCarthy <kevin@8t8.us>
Fri, 17 Jun 2016 17:30:30 +0000 (10:30 -0700)
Add a check_stats parameter to the mbox, maildir, and mh buffy
functions.  Use that parameter to determine whether to also count
total, new, and flagged messages.

This makes the functions a bit more complicated, but improves
efficiency (for maildir and mh).

Also includes the following cleanup/fixes:
* Move the orig-value counter reset to the beginnining of the loop,
  (before tmp->new is set to 0).

* Change trashed maildir messages to not be counted in msg_count

* Remove an incorrect setting of mailbox->new based on msg_count in
  maildir.  (I missed this one for 1f840760e6e0)

* Change mbox to use the context->mtime for stats_last_checked,
  removing a race condition.

* Fix mh to actually count the messages in order to generate msg_count.
  mh_sequences only covers the range of messages with some sort of
  flag.

buffy.c
buffy.h
mh.c
mx.h

diff --git a/buffy.c b/buffy.c
index ffd8f36dad2c206797ac1b4d2297bf0cc6caa800..31dfcdf6130af4733208e4ef75cb162a2ffb247b 100644 (file)
--- a/buffy.c
+++ b/buffy.c
@@ -316,10 +316,16 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
   return 0;
 }
 
-/* returns 1 if the specified dir (cur or new) has new mail */
-static int buffy_maildir_dir_hasnew(BUFFY* mailbox, const char *dir_name)
+/* Checks the specified maildir subdir (cur or new) for new mail or mail counts.
+ * check_new:   if true, check for new mail.
+ * check_stats: if true, count total, new, and flagged mesages.
+ * Returns 1 if the dir has new mail.
+ */
+static int buffy_maildir_check_dir (BUFFY* mailbox, const char *dir_name, int check_new,
+                                    int check_stats)
 {
   char path[_POSIX_PATH_MAX];
+  char msgpath[_POSIX_PATH_MAX];
   DIR *dirp;
   struct dirent *de;
   char *p;
@@ -331,12 +337,18 @@ static int buffy_maildir_dir_hasnew(BUFFY* mailbox, const char *dir_name)
   /* when $mail_check_recent is set, if the new/ directory hasn't been modified since
    * the user last exited the mailbox, then we know there is no recent mail.
    */
-  if (option(OPTMAILCHECKRECENT))
+  if (check_new && option(OPTMAILCHECKRECENT))
   {
     if (stat(path, &sb) == 0 && sb.st_mtime < mailbox->last_visited)
-      return 0;
+    {
+      rc = 0;
+      check_new = 0;
+    }
   }
 
+  if (! (check_new || check_stats))
+    return rc;
+
   if ((dirp = opendir (path)) == NULL)
   {
     mailbox->magic = 0;
@@ -348,21 +360,35 @@ static int buffy_maildir_dir_hasnew(BUFFY* mailbox, const char *dir_name)
     if (*de->d_name == '.')
       continue;
 
-    if (!(p = strstr (de->d_name, ":2,")) || !(strchr (p + 3, 'T') || strchr(p + 3, 'S')))
+    p = strstr (de->d_name, ":2,");
+    if (p && strchr (p + 3, 'T'))
+      continue;
+
+    if (check_stats)
+    {
+      mailbox->msg_count++;
+      if (p && strchr (p + 3, 'F'))
+        mailbox->msg_flagged++;
+    }
+    if (!p || !strchr (p + 3, 'S'))
     {
-      if (option(OPTMAILCHECKRECENT))
+      if (check_stats)
+        mailbox->msg_unread++;
+      if (check_new)
       {
-       char msgpath[_POSIX_PATH_MAX];
-
-       snprintf(msgpath, sizeof(msgpath), "%s/%s", path, de->d_name);
-       /* ensure this message was received since leaving this mailbox */
-       if (stat(msgpath, &sb) == 0 && (sb.st_ctime <= mailbox->last_visited))
-         continue;
+        if (option(OPTMAILCHECKRECENT))
+        {
+          snprintf(msgpath, sizeof(msgpath), "%s/%s", path, de->d_name);
+          /* ensure this message was received since leaving this mailbox */
+          if (stat(msgpath, &sb) == 0 && (sb.st_ctime <= mailbox->last_visited))
+            continue;
+        }
+        mailbox->new = 1;
+        rc = 1;
+        check_new = 0;
+        if (!check_stats)
+          break;
       }
-      /* one new and undeleted message is enough */
-      mailbox->new = 1;
-      rc = 1;
-      break;
     }
   }
 
@@ -371,109 +397,48 @@ static int buffy_maildir_dir_hasnew(BUFFY* mailbox, const char *dir_name)
   return rc;
 }
 
-/* returns 1 if maildir has new mail */
-static int buffy_maildir_hasnew (BUFFY* mailbox)
-{
-  if (buffy_maildir_dir_hasnew(mailbox, "new")) {
-      return 1;
-  }
-
-  if (!option(OPTMAILDIRCHECKCUR)) {
-      return 0;
-  }
-
-  if (buffy_maildir_dir_hasnew(mailbox, "cur")) {
-      return 1;
-  }
-
-  return 0;
-}
-
-/**
- * buffy_maildir_update_dir - Update counts for one directory
- * @mailbox: BUFFY representing a maildir mailbox
- * @dir:     Which directory to search
- *
- * Look through one directory of a maildir mailbox.  The directory could
- * be either "new" or "cur".
- *
- * Count how many new, or flagged, messages there are.
+/* Checks new mail for a maildir mailbox.
+ * check_stats: if true, also count total, new, and flagged mesages.
+ * Returns 1 if the mailbox has new mail.
  */
-static void
-buffy_maildir_update_dir (BUFFY *mailbox, const char *dir)
+static int buffy_maildir_check (BUFFY* mailbox, int check_stats)
 {
-  char path[_POSIX_PATH_MAX] = "";
-  DIR *dirp = NULL;
-  struct dirent *de = NULL;
-  char *p = NULL;
-
-  snprintf (path, sizeof (path), "%s/%s", mailbox->path, dir);
+  int rc, check_new = 1;
 
-  dirp = opendir (path);
-  if (!dirp)
+  if (check_stats)
   {
-    mailbox->magic = 0;
-    return;
+    mailbox->msg_count   = 0;
+    mailbox->msg_unread  = 0;
+    mailbox->msg_flagged = 0;
   }
 
-  while ((de = readdir (dirp)) != NULL)
-  {
-    if (*de->d_name == '.')
-      continue;
+  rc = buffy_maildir_check_dir (mailbox, "new", check_new, check_stats);
 
-    /* Matches maildir_parse_flags logic */
-    mailbox->msg_count++;
-    p = strstr (de->d_name, ":2,");
-    if (p)
-    {
-      p += 3;
-      if (strchr (p, 'T'))
-        continue;
-      if (!strchr (p, 'S'))
-        mailbox->msg_unread++;
-      if (strchr (p, 'F'))
-        mailbox->msg_flagged++;
-    }
-    else
-      mailbox->msg_unread++;
-  }
+  check_new = !rc && option (OPTMAILDIRCHECKCUR);
+  if (check_new || check_stats)
+    if (buffy_maildir_check_dir (mailbox, "cur", check_new, check_stats))
+      rc = 1;
 
-  closedir (dirp);
+  return rc;
 }
 
-/**
- * buffy_maildir_update - Update messages counts for a maildir mailbox
- * @mailbox: BUFFY representing a maildir mailbox
- *
- * Open a mailbox directories and update our record of how many new, or
- * flagged, messages there are.
+/* Checks new mail for an mbox mailbox
+ * check_stats: if true, also count total, new, and flagged mesages.
+ * Returns 1 if the mailbox has new mail.
  */
-void
-buffy_maildir_update (BUFFY *mailbox)
-{
-       mailbox->msg_count   = 0;
-       mailbox->msg_unread  = 0;
-       mailbox->msg_flagged = 0;
-
-       buffy_maildir_update_dir (mailbox, "new");
-       if (mailbox->msg_count) {
-               mailbox->new = 1;
-       }
-       buffy_maildir_update_dir (mailbox, "cur");
-}
-
-/* returns 1 if mailbox has new mail */ 
-static int buffy_mbox_hasnew (BUFFY* mailbox, struct stat *sb)
+static int buffy_mbox_check (BUFFY* mailbox, struct stat *sb, int check_stats)
 {
   int rc = 0;
-  int statcheck;
+  int new_or_changed;
+  CONTEXT *ctx = NULL;
 
   if (option (OPTCHECKMBOXSIZE))
-    statcheck = sb->st_size > mailbox->size;
+    new_or_changed = sb->st_size > mailbox->size;
   else
-    statcheck = sb->st_mtime > sb->st_atime
+    new_or_changed = sb->st_mtime > sb->st_atime
       || (mailbox->newly_created && sb->st_ctime == sb->st_mtime && sb->st_ctime == sb->st_atime);
-  if (statcheck)
+
+  if (new_or_changed)
   {
     if (!option(OPTMAILCHECKRECENT) || sb->st_mtime > mailbox->last_visited)
     {
@@ -486,41 +451,32 @@ static int buffy_mbox_hasnew (BUFFY* mailbox, struct stat *sb)
     /* some other program has deleted mail from the folder */
     mailbox->size = (off_t) sb->st_size;
   }
+
   if (mailbox->newly_created &&
       (sb->st_ctime != sb->st_mtime || sb->st_ctime != sb->st_atime))
     mailbox->newly_created = 0;
 
-  return rc;
-}
-
-/**
- * buffy_mbox_update - Update messages counts for an mbox mailbox
- * @mailbox: BUFFY representing an mbox mailbox
- * @sb:      stat(2) infomation about the mailbox file
- *
- * Open a mbox file and update our record of how many new, or flagged,
- * messages there are. If the mailbox hasn't changed since the last call,
- * the function does nothing.
- */
-void
-buffy_mbox_update (BUFFY *mailbox, struct stat *sb)
-{
-  CONTEXT *ctx = NULL;
-
-  if ((mailbox->stats_last_checked > sb->st_mtime) && (mailbox->msg_count != 0))
-    return; /* no check necessary */
-
-  ctx = mx_open_mailbox (mailbox->path, MUTT_READONLY | MUTT_QUIET | MUTT_NOSORT | MUTT_PEEK, NULL);
-  if (ctx)
+  if (check_stats &&
+      (mailbox->stats_last_checked < sb->st_mtime))
   {
-    mailbox->msg_count       = ctx->msgcount;
-    mailbox->msg_unread      = ctx->unread;
-    mailbox->msg_flagged     = ctx->flagged;
-    mailbox->stats_last_checked = time (NULL);
-    mx_close_mailbox (ctx, 0);
+    if ((ctx = mx_open_mailbox (mailbox->path,
+                                MUTT_READONLY | MUTT_QUIET | MUTT_NOSORT | MUTT_PEEK,
+                                NULL)) != NULL)
+    {
+      mailbox->msg_count       = ctx->msgcount;
+      mailbox->msg_unread      = ctx->unread;
+      mailbox->msg_flagged     = ctx->flagged;
+      mailbox->stats_last_checked = ctx->mtime;
+      mx_close_mailbox (ctx, 0);
+    }
   }
+
+  return rc;
 }
 
+/* Check all Incoming for new mail and total/new/flagged messages
+ * force: if true, ignore BuffyTimeout and check for new mail anyway
+ */
 int mutt_buffy_check (int force)
 {
   BUFFY *tmp;
@@ -575,6 +531,13 @@ int mutt_buffy_check (int force)
   
   for (tmp = Incoming; tmp; tmp = tmp->next)
   {
+#ifdef USE_SIDEBAR
+    orig_new = tmp->new;
+    orig_count = tmp->msg_count;
+    orig_unread = tmp->msg_unread;
+    orig_flagged = tmp->msg_flagged;
+#endif
+
     if (tmp->magic != MUTT_IMAP)
     {
       tmp->new = 0;
@@ -595,13 +558,6 @@ int mutt_buffy_check (int force)
       }
     }
 
-#ifdef USE_SIDEBAR
-    orig_new = tmp->new;
-    orig_count = tmp->msg_count;
-    orig_unread = tmp->msg_unread;
-    orig_flagged = tmp->msg_flagged;
-#endif
-
     /* check to see if the folder is the currently selected folder
      * before polling */
     if (!Context || !Context->path ||
@@ -611,28 +567,21 @@ int mutt_buffy_check (int force)
     {
       switch (tmp->magic)
       {
-      case MUTT_MBOX:
-      case MUTT_MMDF:
-       if (check_stats)
-         buffy_mbox_update (tmp, &sb);
-       if (buffy_mbox_hasnew (tmp, &sb) > 0)
-         BuffyCount++;
-       break;
-
-      case MUTT_MAILDIR:
-       if (check_stats)
-         buffy_maildir_update (tmp);
-       if (buffy_maildir_hasnew (tmp) > 0)
-         BuffyCount++;
-       break;
-
-      case MUTT_MH:
-       if (check_stats)
-         mh_buffy_update (tmp);
-       mh_buffy(tmp);
-       if (tmp->new)
-         BuffyCount++;
-       break;
+        case MUTT_MBOX:
+        case MUTT_MMDF:
+          if (buffy_mbox_check (tmp, &sb, check_stats) > 0)
+            BuffyCount++;
+          break;
+
+        case MUTT_MAILDIR:
+          if (buffy_maildir_check (tmp, check_stats) > 0)
+            BuffyCount++;
+          break;
+
+        case MUTT_MH:
+          if (mh_buffy (tmp, check_stats) > 0)
+            BuffyCount++;
+          break;
       }
     }
     else if (option(OPTCHECKMBOXSIZE) && Context && Context->path)
diff --git a/buffy.h b/buffy.h
index d3f5454acc334aac62a157bef716152765c5be98..61e4d43446d9e3785e3b91beae52536df2436d39 100644 (file)
--- a/buffy.h
+++ b/buffy.h
@@ -48,7 +48,7 @@ typedef struct buffy_t
   short magic;                 /* mailbox type */
   short newly_created;         /* mbox or mmdf just popped into existence */
   time_t last_visited;         /* time of last exit from this mailbox */
-  time_t stats_last_checked;   /* time of last mail_check_stats calculation */
+  time_t stats_last_checked;   /* mtime of mailbox the last time stats where checked. */
 }
 BUFFY;
 
@@ -68,6 +68,6 @@ void mutt_buffy_cleanup (const char *buf, struct stat *st);
 /* mark mailbox just left as already notified */
 void mutt_buffy_setnotified (const char *path);
 
-void mh_buffy (BUFFY *);
+int mh_buffy (BUFFY *, int);
 
 #endif /* _BUFFY_H */
diff --git a/mh.c b/mh.c
index 6d00637af75dbc2c2a58e2dc6b890f325fcbc822..d15b85134bf9d8a036f5d78d4b8ad0b524c2ebeb 100644 (file)
--- a/mh.c
+++ b/mh.c
@@ -264,74 +264,86 @@ static int mh_already_notified(BUFFY *b, int msgno)
   return -1;
 }
 
-void mh_buffy(BUFFY *b)
+/* Checks new mail for a mh mailbox.
+ * check_stats: if true, also count total, new, and flagged mesages.
+ * Returns 1 if the mailbox has new mail.
+ */
+int mh_buffy (BUFFY *mailbox, int check_stats)
 {
   int i;
   struct mh_sequences mhs;
-
-  b->new = 0;
+  int check_new = 1;
+  int rc = 0;
+  DIR *dirp;
+  struct dirent *de;
 
   /* when $mail_check_recent is set and the .mh_sequences file hasn't changed
-   * since the last mailbox visit, there is nothing to do */
-  if (option(OPTMAILCHECKRECENT) && mh_sequences_changed(b) <= 0)
-      return;
+   * since the last mailbox visit, there is no "new mail" */
+  if (option(OPTMAILCHECKRECENT) && mh_sequences_changed(mailbox) <= 0)
+  {
+    rc = 0;
+    check_new = 0;
+  }
+
+  if (! (check_new || check_stats))
+    return rc;
 
   memset (&mhs, 0, sizeof (mhs));
+  if (mh_read_sequences (&mhs, mailbox->path) < 0)
+    return 0;
 
-  if (mh_read_sequences (&mhs, b->path) < 0)
-    return;
+  if (check_stats)
+  {
+    mailbox->msg_count   = 0;
+    mailbox->msg_unread  = 0;
+    mailbox->msg_flagged = 0;
+  }
 
-  /* Traverse the sequence from high to low in order to support
-   * $mail_check_recent.  Given that new messages are appended, this should
-   * also be faster when it is unset as well.
-   */
   for (i = mhs.max; i > 0; i--)
   {
+    if (check_stats &&
+        (mhs_check (&mhs, i) & MH_SEQ_FLAGGED))
+      mailbox->msg_flagged++;
     if (mhs_check (&mhs, i) & MH_SEQ_UNSEEN)
     {
-      /* if the first unseen message we encounter was in the mailbox during the last visit, don't notify about it */
-      if (!option(OPTMAILCHECKRECENT) || mh_already_notified(b, i) == 0)
-       b->new = 1;
-      break;
+      if (check_stats)
+        mailbox->msg_unread++;
+      if (check_new)
+      {
+        /* if the first unseen message we encounter was in the mailbox during the
+           last visit, don't notify about it */
+        if (!option(OPTMAILCHECKRECENT) || mh_already_notified(mailbox, i) == 0)
+        {
+          mailbox->new = 1;
+          rc = 1;
+        }
+        /* Because we are traversing from high to low, we can stop
+         * checking for new mail after the first unseen message.
+         * Whether it resulted in "new mail" or not. */
+        check_new = 0;
+        if (!check_stats)
+          break;
+      }
     }
   }
   mhs_free_sequences (&mhs);
-}
 
-/**
- * mh_buffy_update - Update messages counts for an mh mailbox
- * @mailbox: BUFFY representing a maildir mailbox
- *
- * Read through an mh mailbox and count messages.  Save the number of new,
- * flagged messages and a timestamp for now.
- */
-void
-mh_buffy_update (BUFFY *mailbox)
-{
-  int i;
-  struct mh_sequences mhs;
-
-  if (!mailbox)
-    return;
-
-  memset (&mhs, 0, sizeof (mhs));
-
-  if (mh_read_sequences (&mhs, mailbox->path) < 0)
-    return;
-
-  mailbox->msg_count   = 0;
-  mailbox->msg_unread  = 0;
-  mailbox->msg_flagged = 0;
-
-  for (i = 0; i <= mhs.max; i++)
+  if (check_stats)
   {
-    mailbox->msg_count++;
-    if (mhs_check (&mhs, i) & MH_SEQ_UNSEEN)
-      mailbox->msg_unread++;
-    if (mhs_check (&mhs, i) & MH_SEQ_FLAGGED)
-      mailbox->msg_flagged++;
+    if ((dirp = opendir (mailbox->path)) != NULL)
+    {
+      while ((de = readdir (dirp)) != NULL)
+      {
+        if (*de->d_name == '.')
+          continue;
+        if (mh_valid_message (de->d_name))
+          mailbox->msg_count++;
+      }
+      closedir (dirp);
+    }
   }
-  mhs_free_sequences (&mhs);
+
+  return rc;
 }
 
 static int mh_mkstemp (CONTEXT * dest, FILE ** fp, char **tgt)
diff --git a/mx.h b/mx.h
index 95d899461006903094ae1b3ff042afdaec42cdf0..370313aa126d0d0cff356295eee007e8121b0e96 100644 (file)
--- a/mx.h
+++ b/mx.h
@@ -53,7 +53,6 @@ int mbox_check_empty (const char *);
 void mbox_reset_atime (CONTEXT *, struct stat *);
 
 int mh_sync_mailbox (CONTEXT *, int *);
-void mh_buffy_update (BUFFY *mailbox);
 int mh_check_empty (const char *);
 
 int maildir_check_empty (const char *);