X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=buffy.cpkg;fp=buffy.cpkg;h=5ea41888fdd2e6e8cc2c8ec34d90d2f4feee081e;hp=0000000000000000000000000000000000000000;hb=c9f72ab0cd65f517a2047feb942ad85025c1b7e8;hpb=9f817787be195b0065d0ffb9d8f2d0ef3595538b diff --git a/buffy.cpkg b/buffy.cpkg new file mode 100644 index 0000000..5ea4188 --- /dev/null +++ b/buffy.cpkg @@ -0,0 +1,422 @@ +/* + * 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 + +#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 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, count = 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 < Buffy.mail_check) + && (now - ImapBuffyTime < ImapBuffyTimeout)) + return BuffyCount; + + last1 = BuffyTime; + if (force == 1 || now - BuffyTime >= Buffy.mail_check) + BuffyTime = now; + last2 = ImapBuffyTime; + if (force == 1 || now - ImapBuffyTime >= ImapBuffyTimeout) + ImapBuffyTime = now; + BuffyCount = 0; + BuffyNotify = 0; + + count = sidebar_need_count(); + + 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: + case M_MMDF: + /* only check on force or $mail_check reached */ + if (force == 1 || (now - last1 >= Buffy.mail_check)) { + if (!count) { + 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 >= 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 (!count) { + /* if sidebar invisible -> done */ + tmp->new = 1; + break; + } + } + tmp->msgcount++; + tmp->msg_unread++; + tmp->new++; + } + } + closedir (dirp); + + if (count) { + /* 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 >= Buffy.mail_check)) { + if ((tmp->new = mh_buffy (tmp->path)) > 0) + BuffyCount++; + if (count) { + 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: */