From 4bf01a885fcb080bc99db3399aa5ea0f75f42aca Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Fri, 17 Jun 2016 10:30:30 -0700 Subject: [PATCH] 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. --- buffy.c | 265 +++++++++++++++++++++++--------------------------------- buffy.h | 4 +- mh.c | 110 ++++++++++++----------- mx.h | 1 - 4 files changed, 170 insertions(+), 210 deletions(-) diff --git a/buffy.c b/buffy.c index ffd8f36d..31dfcdf6 100644 --- 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 d3f5454a..61e4d434 100644 --- 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 6d00637a..d15b8513 100644 --- 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 95d89946..370313aa 100644 --- 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 *); -- 2.40.0