/* * Copyright notice from original mutt: * Copyright (C) 1996-2000 Michael R. Elkins * * Parts were written/modified by: * Rocco Rutte * * This file is part of mutt-ng, see http://www.muttng.org/. * It's licensed under the GNU General Public License, * please see the file GPL in the top level source directory. */ #include #include #include #include #include #include #include #include #include "mutt.h" #include "buffy.h" @import "lib-lua/base.cpkg" static time_t BuffyTime = 0; /* last time we started checking for mail */ static time_t ImapBuffyTime = 0; /* last time we started checking for mail */ static short BuffyCount = 0; /* how many boxes with new mail */ static short BuffyNotify = 0; /* # of unnotified new boxes */ buffy_array Incoming; @package mod_buffy { /* ** .pp ** This variable configures how often (in seconds) Madmutt should look for ** new mail. ** .pp ** \fBNote:\fP This does not apply to IMAP mailboxes, see $$imap_mail_check. */ int mail_check = 5; void mailboxes(const string_t s) { buffy_do_mailboxes(s, 1); RETURN(); }; void unmailboxes(const string_t s) { buffy_do_mailboxes(s, 0); RETURN(); }; }; void buffy_do_mailboxes(const char *s, int add) { char buf[_POSIX_PATH_MAX]; BUFFY *tmp; int i; if (!m_strcmp(s, "*")) { buffy_array_wipe(&Incoming); return; } if (m_strisempty(s)) return; _mutt_expand_path(buf, sizeof(buf), s, 0); i = buffy_lookup(buf); if (!add) { tmp = buffy_array_take(&Incoming, i); buffy_delete(&tmp); return; } if (i < 0) { tmp = p_new(BUFFY, 1); tmp->path = m_strdup(buf); buffy_array_append(&Incoming, tmp); } else { tmp = Incoming.arr[i]; } tmp->new = 0; tmp->notified = 1; tmp->newly_created = 0; } /* Return the index number of path in Incoming list */ int buffy_lookup(const char* path) { int i; if (m_strisempty(path)) return -1; for (i = 0; i < Incoming.len; i++) { if (!m_strcmp(Incoming.arr[i]->path, path)) return i; } return -1; } #define STAT_CHECK (sb.st_mtime > sb.st_atime || (tmp->newly_created && sb.st_ctime == sb.st_mtime && sb.st_ctime == sb.st_atime)) /* values for force: * 0 don't force any checks + update sidebar * 1 force all checks + update sidebar * 2 don't force any checks + _don't_ update sidebar */ int buffy_check(int force) { struct stat sb; struct dirent *de; DIR *dirp; char path[_POSIX_PATH_MAX]; struct stat contex_sb; time_t now, last1, last2; CONTEXT *ctx; int i = 0, local = 0; /* update postponed count as well, on force */ if (force == 1) mutt_update_num_postponed (); /* fastest return if there are no mailboxes */ if (!Incoming.len) return 0; now = time (NULL); if (force == 0 && (now - BuffyTime < mod_buffy.mail_check) && (now - ImapBuffyTime < ImapBuffyTimeout)) return BuffyCount; last1 = BuffyTime; if (force == 1 || now - BuffyTime >= mod_buffy.mail_check) BuffyTime = now; last2 = ImapBuffyTime; if (force == 1 || now - ImapBuffyTime >= ImapBuffyTimeout) ImapBuffyTime = now; BuffyCount = 0; BuffyNotify = 0; if (!Context || !Context->path || (mx_is_local (Context->magic-1) && stat (Context->path, &contex_sb) != 0)) { /* check device ID and serial number instead of comparing paths */ contex_sb.st_dev = 0; contex_sb.st_ino = 0; } for (i = 0; i < Incoming.len; i++) { BUFFY *tmp = Incoming.arr[i]; tmp->magic = mx_get_magic (tmp->path); local = mx_is_local (tmp->magic-1); if ((tmp->magic <= 0 || local) && (stat (tmp->path, &sb) != 0 || sb.st_size == 0)) { /* if the mailbox still doesn't exist, set the newly created flag to * be ready for when it does. */ tmp->newly_created = 1; tmp->magic = -1; continue; } /* check to see if the folder is the currently selected folder * before polling */ if (!Context || !Context->path || (local ? (sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino) : m_strcmp(tmp->path, Context->path))) { switch (tmp->magic) { case M_MBOX: /* only check on force or $mail_check reached */ if (force == 1 || (now - last1 >= mod_buffy.mail_check)) { if (!sidebar_w) { if (STAT_CHECK) { BuffyCount++; tmp->new = 1; } } else if (STAT_CHECK || tmp->msgcount == 0) { /* sidebar visible */ BuffyCount++; if ((ctx = mx_open_mailbox (tmp->path, M_READONLY | M_QUIET | M_NOSORT | M_COUNT, NULL)) != NULL) { tmp->msgcount = ctx->msgcount; tmp->new = ctx->new; tmp->msg_unread = ctx->new; /* for sidebar, wtf? */ tmp->msg_flagged = ctx->flagged; mx_close_mailbox (ctx, 0); } } if (tmp->newly_created && (sb.st_ctime != sb.st_mtime || sb.st_ctime != sb.st_atime)) tmp->newly_created = 0; } else if (tmp->new > 0) BuffyCount++; break; case M_MAILDIR: /* only check on force or $mail_check reached */ if (force == 1 || (now - last1 >= mod_buffy.mail_check)) { snprintf (path, sizeof (path), "%s/new", tmp->path); if ((dirp = opendir (path)) == NULL) { tmp->magic = 0; break; } tmp->new = 0; tmp->msg_unread = 0; tmp->msgcount = 0; while ((de = readdir (dirp)) != NULL) { char *p; if (*de->d_name != '.' && (!(p = strstr (de->d_name, ":2,")) || !strchr (p + 3, 'T'))) { /* one new and undeleted message is enough */ if (tmp->new == 0) { BuffyCount++; if (!sidebar_w) { /* if sidebar invisible -> done */ tmp->new = 1; break; } } tmp->msgcount++; tmp->msg_unread++; tmp->new++; } } closedir (dirp); if (sidebar_w) { /* only count total mail if sidebar visible */ snprintf (path, sizeof (path), "%s/cur", tmp->path); if ((dirp = opendir (path)) == NULL) { tmp->magic = 0; break; } tmp->msg_flagged = 0; while ((de = readdir (dirp)) != NULL) { char *p; if (*de->d_name != '.' && (p = strstr (de->d_name, ":2,")) != NULL) { if (!strchr (p + 3, 'T')) tmp->msgcount++; if (strchr (p + 3, 'F')) tmp->msg_flagged++; } } closedir (dirp); } } else if (tmp->new > 0) /* keep current stats if !force and !$mail_check reached */ BuffyCount++; break; case M_MH: /* only check on force or $mail_check reached */ if (force == 1 || (now - last1 >= mod_buffy.mail_check)) { if ((tmp->new = mh_buffy (tmp->path)) > 0) BuffyCount++; if (sidebar_w) { DIR *dp; if ((dp = opendir (path)) == NULL) break; tmp->new = 0; tmp->msgcount = 0; tmp->msg_unread = 0; while ((de = readdir (dp))) { if (mh_valid_message (de->d_name)) { tmp->msgcount++; tmp->msg_unread++; tmp->new++; } } closedir (dp); } } else if (tmp->new > 0) /* keep current stats if !force and !$mail_check reached */ BuffyCount++; break; case M_IMAP: /* only check on force or $imap_mail_check reached */ if (force == 1 || (now - last2 >= ImapBuffyTimeout)) { tmp->msgcount = imap_mailbox_check (tmp->path, 0); tmp->new = imap_mailbox_check (tmp->path, 1); tmp->msg_unread = imap_mailbox_check (tmp->path, 2); if (tmp->new > 0) BuffyCount++; else tmp->new = 0; if (tmp->msg_unread < 0) tmp->msg_unread = 0; } else if (tmp->new > 0) /* keep current stats if !force and !$imap_mail_check reached */ BuffyCount++; break; } } if (tmp->new <= 0) tmp->notified = 0; else if (!tmp->notified) BuffyNotify++; tmp->has_new = tmp->new > 0; } if (BuffyCount > 0 && force != 2) sidebar_draw (); return BuffyCount; } int buffy_list (void) { char buffylist[LONG_STRING]; int have_unnotified = BuffyNotify; int pos = 0, first = 1, i; pos = m_strcpy(buffylist, sizeof(buffylist), _("New mail in ")); for (i = 0; i < Incoming.len; i++) { char path[_POSIX_PATH_MAX]; BUFFY *tmp = Incoming.arr[i]; /* Is there new mail in this mailbox? */ if (tmp->new <= 0 || (have_unnotified && tmp->notified)) continue; m_strcpy(path, sizeof(path), tmp->path); mutt_pretty_mailbox(path); if (!first) { if (pos + m_strlen(path) >= COLS - 7) break; pos += m_strcpy(buffylist + pos, sizeof(buffylist) - pos, ", "); } tmp->notified = 1; BuffyNotify--; pos += m_strcpy(buffylist + pos, sizeof(buffylist) - pos, path); first = 0; } if (!first) { /* on new mail: redraw sidebar */ sidebar_draw(); if (i < Incoming.len) { mutt_message("%s, ...", buffylist); } else { mutt_message("%s", buffylist); } return 1; } /* there were no mailboxes needing to be notified, so clean up since BuffyNotify has somehow gotten out of sync */ BuffyNotify = 0; return 0; } int buffy_notify(void) { return buffy_check(0) && BuffyNotify ? buffy_list() : 0; } /* * buffy_next() -- incoming folders completion routine * * given a folder name, this routine gives the next incoming folder with new * new mail. */ void buffy_next(char *s, size_t slen) { int l = 0; int c = 0, i = 0; mutt_expand_path(s, _POSIX_PATH_MAX); if (!buffy_check(0)) { *s = '\0'; return; } /* * buffy_lookup returns the index, * or -1 if not found (-1..Incoming.len-1); * plus one --> (0..Incoming.len). * Modulo mapps it into the correct range. */ i = 1 + buffy_lookup(s); for (l = 0; l < Incoming.len; l++) { c = (l+i) % Incoming.len; if (m_strcmp(Incoming.arr[c]->path, s) && Incoming.arr[c]->new > 0) break; } if (l >= Incoming.len) { *s = '\0'; /* something went wrong since we're here when buffy_check * reported new mail */ buffy_check(1); } else { m_strcpy(s, slen, Incoming.arr[c]->path); mutt_pretty_mailbox(s); } } /* vim:set ft=c: */