[This is the part-4 I mentioned earlier].

Combine the basic and extended buffy functions.

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.

-- 
Kevin J. McCarthy
GPG Fingerprint: 8975 A9B3 3AA3 7910 385C  5308 ADEF 7684 8031 6BDA
# HG changeset patch
# User Kevin McCarthy <ke...@8t8.us>
# Date 1465939600 25200
#      Tue Jun 14 14:26:40 2016 -0700
# Node ID 701510f2f5b131aeba0f6ba64a6e158f6802258c
# Parent  5ad82360c6ea610199803a31786a175a8add63fa
Combine the basic and extended buffy functions.

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.

diff --git a/buffy.c b/buffy.c
--- a/buffy.c
+++ b/buffy.c
@@ -311,221 +311,177 @@
       (*tmp)->size = (off_t) sb.st_size;
     }
     else
       (*tmp)->size = 0;
   }
   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;
   int rc = 0;
   struct stat sb;
 
   snprintf (path, sizeof (path), "%s/%s", mailbox->path, 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;
     return 0;
   }
 
   while ((de = readdir (dirp)) != NULL)
   {
     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)
     {
-      if (option(OPTMAILCHECKRECENT))
+      mailbox->msg_count++;
+      if (p && strchr (p + 3, 'F'))
+        mailbox->msg_flagged++;
+    }
+    if (!p || !strchr (p + 3, 'S'))
+    {
+      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;
     }
   }
 
   closedir (dirp);
 
   return rc;
 }
 
-/* returns 1 if maildir has new mail */
-static int buffy_maildir_hasnew (BUFFY* mailbox)
+/* 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 int buffy_maildir_check (BUFFY* mailbox, int check_stats)
 {
-  if (buffy_maildir_dir_hasnew(mailbox, "new")) {
-      return 1;
+  int rc, check_new = 1;
+
+  if (check_stats)
+  {
+    mailbox->msg_count   = 0;
+    mailbox->msg_unread  = 0;
+    mailbox->msg_flagged = 0;
   }
 
-  if (!option(OPTMAILDIRCHECKCUR)) {
-      return 0;
-  }
+  rc = buffy_maildir_check_dir (mailbox, "new", check_new, check_stats);
 
-  if (buffy_maildir_dir_hasnew(mailbox, "cur")) {
-      return 1;
-  }
+  check_new = !rc && option (OPTMAILDIRCHECKCUR);
+  if (check_new || check_stats)
+    if (buffy_maildir_check_dir (mailbox, "cur", check_new, check_stats))
+      rc = 1;
 
-  return 0;
+  return rc;
 }
 
-/**
- * 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 an mbox 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)
-{
-  char path[_POSIX_PATH_MAX] = "";
-  DIR *dirp = NULL;
-  struct dirent *de = NULL;
-  char *p = NULL;
-
-  snprintf (path, sizeof (path), "%s/%s", mailbox->path, dir);
-
-  dirp = opendir (path);
-  if (!dirp)
-  {
-    mailbox->magic = 0;
-    return;
-  }
-
-  while ((de = readdir (dirp)) != NULL)
-  {
-    if (*de->d_name == '.')
-      continue;
-
-    /* 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++;
-  }
-
-  closedir (dirp);
-}
-
-/**
- * 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.
- */
-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)
     {
       rc = 1;
       mailbox->new = 1;
     }
   }
   else if (option(OPTCHECKMBOXSIZE))
   {
     /* 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;
 
+  if (check_stats &&
+      (mailbox->stats_last_checked < sb->st_mtime))
+  {
+    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;
 }
 
-/**
- * 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.
+/* Check all Incoming for new mail and total/new/flagged messages
+ * force: if true, ignore BuffyTimeout and check for new mail anyway
  */
-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)
-  {
-    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);
-  }
-}
-
 int mutt_buffy_check (int force)
 {
   BUFFY *tmp;
   struct stat sb;
   struct stat contex_sb;
   time_t t;
   int check_stats = 0;
 #ifdef USE_SIDEBAR
@@ -570,16 +526,23 @@
       || stat (Context->path, &contex_sb) != 0)
   {
     contex_sb.st_dev=0;
     contex_sb.st_ino=0;
   }
   
   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;
 #ifdef USE_POP
       if (mx_is_pop (tmp->path))
        tmp->magic = MUTT_POP;
       else
 #endif
@@ -590,54 +553,40 @@
         * be ready for when it does. */
        tmp->newly_created = 1;
        tmp->magic = 0;
        tmp->size = 0;
        continue;
       }
     }
 
-#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 ||
        (( tmp->magic == MUTT_IMAP || tmp->magic == MUTT_POP )
            ? mutt_strcmp (tmp->path, Context->path) :
              (sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino)))
     {
       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_MBOX:
+        case MUTT_MMDF:
+          if (buffy_mbox_check (tmp, &sb, check_stats) > 0)
+            BuffyCount++;
+          break;
 
-      case MUTT_MAILDIR:
-       if (check_stats)
-         buffy_maildir_update (tmp);
-       if (buffy_maildir_hasnew (tmp) > 0)
-         BuffyCount++;
-       break;
+        case MUTT_MAILDIR:
+          if (buffy_maildir_check (tmp, check_stats) > 0)
+            BuffyCount++;
+          break;
 
-      case MUTT_MH:
-       if (check_stats)
-         mh_buffy_update (tmp);
-       mh_buffy(tmp);
-       if (tmp->new)
-         BuffyCount++;
-       break;
+        case MUTT_MH:
+          if (mh_buffy (tmp, check_stats) > 0)
+            BuffyCount++;
+          break;
       }
     }
     else if (option(OPTCHECKMBOXSIZE) && Context && Context->path)
       tmp->size = (off_t) sb.st_size;  /* update the size of current folder */
 
 #ifdef USE_SIDEBAR
     if ((orig_new != tmp->new) ||
         (orig_count != tmp->msg_count) ||
diff --git a/buffy.h b/buffy.h
--- a/buffy.h
+++ b/buffy.h
@@ -43,17 +43,17 @@
 
 #ifdef USE_SIDEBAR
   short is_hidden;             /* is hidden from the sidebar */
 #endif
   short notified;              /* user has been notified */
   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;
 
 WHERE BUFFY *Incoming INITVAL (0);
 WHERE short BuffyTimeout INITVAL (3);
 WHERE short BuffyCheckStatsInterval INITVAL (60);
 
 extern time_t BuffyDoneTime;   /* last time we knew for sure how much mail 
there was */
@@ -63,11 +63,11 @@
 
 /* fixes up atime + mtime after mbox/mmdf mailbox was modified
    according to stat() info taken before a modification */
 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
--- a/mh.c
+++ b/mh.c
@@ -259,84 +259,96 @@
   struct stat sb;
 
   if ((snprintf(path, sizeof(path), "%s/%d", b->path, msgno) < sizeof(path)) &&
       (stat(path, &sb) == 0))
     return (sb.st_mtime <= b->last_visited);
   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 (check_stats)
+  {
+    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);
+    }
+  }
 
-  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++)
-  {
-    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++;
-  }
-  mhs_free_sequences (&mhs);
+  return rc;
 }
 
 static int mh_mkstemp (CONTEXT * dest, FILE ** fp, char **tgt)
 {
   int fd;
   char path[_POSIX_PATH_MAX];
   mode_t omask;
 

Attachment: signature.asc
Description: PGP signature

Reply via email to