]> git.llucax.com Git - software/mutt-debian.git/blobdiff - buffy.c
a better way of closing 603186 (sidebar-{sorted,dotted} documentation)
[software/mutt-debian.git] / buffy.c
diff --git a/buffy.c b/buffy.c
index 40c229ec611e39817dac2b0eb5cac1a99a5a08ba..fd54dd2dca3be2c28e04161eb4041308abeeaf3d 100644 (file)
--- a/buffy.c
+++ b/buffy.c
@@ -45,6 +45,8 @@ time_t BuffyDoneTime = 0;     /* last time we knew for sure how much mail there was.
 static short BuffyCount = 0;   /* how many boxes with new mail */
 static short BuffyNotify = 0;  /* # of unnotified new boxes */
 
+static BUFFY* buffy_get (const char *path);
+
 /* Find the last message in the file. 
  * upon success return 0. If no message found - return -1 */
 
@@ -191,6 +193,23 @@ void mutt_update_mailbox (BUFFY * b)
   return;
 }
 
+static BUFFY *buffy_new (const char *path)
+{
+  BUFFY* buffy;
+
+  buffy = (BUFFY *) safe_calloc (1, sizeof (BUFFY));
+  strfcpy (buffy->path, path, sizeof (buffy->path));
+  buffy->next = NULL;
+  buffy->magic = 0;
+
+  return buffy;
+}
+
+static void buffy_free (BUFFY **mailbox)
+{
+  FREE (mailbox); /* __FREE_CHECKED__ */
+}
+
 int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *err)
 {
   BUFFY **tmp,*tmp1;
@@ -209,7 +228,7 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
       for (tmp = &Incoming; *tmp;)
       {
         tmp1=(*tmp)->next;
-        FREE (tmp);            /* __FREE_CHECKED__ */
+        buffy_free (tmp);
         *tmp=tmp1;
       }
       return 0;
@@ -236,23 +255,15 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
     {
       if(*tmp)
       {
-        FREE (&((*tmp)->path));
         tmp1=(*tmp)->next;
-        FREE (tmp);            /* __FREE_CHECKED__ */
+        buffy_free (tmp);
         *tmp=tmp1;
       }
       continue;
     }
 
     if (!*tmp)
-    {
-      *tmp = (BUFFY *) safe_calloc (1, sizeof (BUFFY));
-      strfcpy ((*tmp)->path, buf, sizeof ((*tmp)->path));
-      (*tmp)->next = NULL;
-      /* it is tempting to set magic right here */
-      (*tmp)->magic = 0;
-      
-    }
+      *tmp = buffy_new (buf);
 
     (*tmp)->new = 0;
     (*tmp)->notified = 1;
@@ -274,20 +285,96 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
   return 0;
 }
 
-/* people use check_mbox_size on systems where modified time attributes are 
- * BADLY broken. Ignore them.
- */
-#define STAT_CHECK_SIZE (sb.st_size > tmp->size)
-#define STAT_CHECK_TIME (sb.st_mtime > sb.st_atime || (tmp->newly_created && sb.st_ctime == sb.st_mtime && sb.st_ctime == sb.st_atime))
-#define STAT_CHECK (option(OPTCHECKMBOXSIZE) ? STAT_CHECK_SIZE : STAT_CHECK_TIME)
+/* returns 1 if maildir has new mail */
+static int buffy_maildir_hasnew (BUFFY* mailbox)
+{
+  char path[_POSIX_PATH_MAX];
+  DIR *dirp;
+  struct dirent *de;
+  char *p;
+  int rc = 0;
+  struct stat sb;
+
+  snprintf (path, sizeof (path), "%s/new", mailbox->path);
+
+  /* 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 (stat(path, &sb) == 0 && sb.st_mtime < mailbox->last_visited)
+      return 0;
+  }
+
+  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'))
+    {
+      if (option(OPTMAILCHECKRECENT))
+      {
+       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;
+      }
+      /* one new and undeleted message is enough */
+      mailbox->new = 1;
+      rc = 1;
+      break;
+    }
+  }
+
+  closedir (dirp);
+
+  return rc;
+}
+
+/* returns 1 if mailbox has new mail */ 
+static int buffy_mbox_hasnew (BUFFY* mailbox, struct stat *sb)
+{
+  int rc = 0;
+  int statcheck;
+
+  if (option (OPTCHECKMBOXSIZE))
+    statcheck = sb->st_size > mailbox->size;
+  else
+    statcheck = sb->st_mtime > sb->st_atime
+      || (mailbox->newly_created && sb->st_ctime == sb->st_mtime && sb->st_ctime == sb->st_atime);
+  if (statcheck)
+  {
+    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;
+
+  return rc;
+}
 
 int mutt_buffy_check (int force)
 {
   BUFFY *tmp;
   struct stat sb;
-  struct dirent *de;
-  DIR *dirp;
-  char path[_POSIX_PATH_MAX];
   struct stat contex_sb;
   time_t t;
 
@@ -314,14 +401,11 @@ int mutt_buffy_check (int force)
 
 #ifdef USE_IMAP
   BuffyCount += imap_buffy_check (force);
-
-  if (!Context || Context->magic != M_IMAP)
-#endif
-#ifdef USE_POP
-  if (!Context || Context->magic != M_POP)
 #endif
+
   /* check device ID and serial number instead of comparing paths */
-  if (!Context || !Context->path || stat (Context->path, &contex_sb) != 0)
+  if (!Context || Context->magic == M_IMAP || Context->magic == M_POP
+      || stat (Context->path, &contex_sb) != 0)
   {
     contex_sb.st_dev=0;
     contex_sb.st_ino=0;
@@ -329,99 +413,44 @@ int mutt_buffy_check (int force)
   
   for (tmp = Incoming; tmp; tmp = tmp->next)
   {
-#ifdef USE_IMAP
-    if (tmp->magic != M_IMAP)
-#endif
-    tmp->new = 0;
-
-#ifdef USE_IMAP
     if (tmp->magic != M_IMAP)
     {
-#endif
+      tmp->new = 0;
 #ifdef USE_POP
-    if (mx_is_pop (tmp->path))
-      tmp->magic = M_POP;
-    else
+      if (mx_is_pop (tmp->path))
+       tmp->magic = M_POP;
+      else
 #endif
-    if (stat (tmp->path, &sb) != 0 || (S_ISREG(sb.st_mode) && sb.st_size == 0) ||
-       (!tmp->magic && (tmp->magic = mx_get_magic (tmp->path)) <= 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 = 0;
-      tmp->size = 0;
-      continue;
-    }
-#ifdef USE_IMAP
+      if (stat (tmp->path, &sb) != 0 || (S_ISREG(sb.st_mode) && sb.st_size == 0) ||
+         (!tmp->magic && (tmp->magic = mx_get_magic (tmp->path)) <= 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 = 0;
+       tmp->size = 0;
+       continue;
+      }
     }
-#endif
 
     /* check to see if the folder is the currently selected folder
      * before polling */
     if (!Context || !Context->path ||
-#if defined USE_IMAP || defined USE_POP
-       ((
-#ifdef USE_IMAP
-       tmp->magic == M_IMAP
-#endif
-#ifdef USE_POP
-#ifdef USE_IMAP
-       ||
-#endif
-       tmp->magic == M_POP
-#endif
-       ) ? mutt_strcmp (tmp->path, Context->path) :
-#endif
-        (sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino)
-#if defined USE_IMAP || defined USE_POP         
-           )
-#endif
-       )
-       
+       (( tmp->magic == M_IMAP || tmp->magic == M_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 M_MBOX:
       case M_MMDF:
-
-       if (STAT_CHECK)
-       {
+       if (buffy_mbox_hasnew (tmp, &sb) > 0)
          BuffyCount++;
-         tmp->new = 1;
-       }
-       else if (option(OPTCHECKMBOXSIZE))
-       {
-         /* some other program has deleted mail from the folder */
-         tmp->size = (off_t) sb.st_size;
-       }
-       if (tmp->newly_created &&
-           (sb.st_ctime != sb.st_mtime || sb.st_ctime != sb.st_atime))
-         tmp->newly_created = 0;
-
        break;
 
       case M_MAILDIR:
-
-       snprintf (path, sizeof (path), "%s/new", tmp->path);
-       if ((dirp = opendir (path)) == NULL)
-       {
-         tmp->magic = 0;
-         break;
-       }
-       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 */
-           BuffyCount++;
-           tmp->new = 1;
-           break;
-         }
-       }
-       closedir (dirp);
+       if (buffy_maildir_hasnew (tmp) > 0)
+         BuffyCount++;
        break;
 
       case M_MH:
@@ -448,13 +477,11 @@ int mutt_buffy_list (void)
   BUFFY *tmp;
   char path[_POSIX_PATH_MAX];
   char buffylist[2*STRING];
-  int pos;
-  int first;
+  size_t pos = 0;
+  int first = 1;
 
   int have_unnotified = BuffyNotify;
   
-  pos = 0;
-  first = 1;
   buffylist[0] = 0;
   pos += strlen (strncat (buffylist, _("New mail in "), sizeof (buffylist) - 1 - pos)); /* __STRNCAT_CHECKED__ */
   for (tmp = Incoming; tmp; tmp = tmp->next)
@@ -466,7 +493,7 @@ int mutt_buffy_list (void)
     strfcpy (path, tmp->path, sizeof (path));
     mutt_pretty_mailbox (path, sizeof (path));
     
-    if (!first && pos + strlen (path) >= COLS - 7)
+    if (!first && (COLS - 7 >= 0) && (pos + strlen (path) >= (size_t)COLS - 7))
       break;
     
     if (!first)
@@ -498,6 +525,18 @@ int mutt_buffy_list (void)
   return (0);
 }
 
+void mutt_buffy_setnotified (const char *path)
+{
+  BUFFY *buffy;
+
+  buffy = buffy_get(path);
+  if (!buffy)
+    return;
+
+  buffy->notified = 1;
+  time(&buffy->last_visited);
+}
+
 int mutt_buffy_notify (void)
 {
   if (mutt_buffy_check (0) && BuffyNotify)
@@ -542,3 +581,30 @@ void mutt_buffy (char *s, size_t slen)
   /* no folders with new mail */
   *s = '\0';
 }
+
+/* fetch buffy object for given path, if present */
+static BUFFY* buffy_get (const char *path)
+{
+  BUFFY *cur;
+  char *epath;
+
+  if (!path)
+    return NULL;
+
+  epath = safe_strdup(path);
+  mutt_expand_path(epath, mutt_strlen(epath));
+
+  for (cur = Incoming; cur; cur = cur->next)
+  {
+    /* must be done late because e.g. IMAP delimiter may change */
+    mutt_expand_path (cur->path, sizeof (cur->path));
+    if (!mutt_strcmp(cur->path, path))
+    {
+      FREE (&epath);
+      return cur;
+    }
+  }
+
+  FREE (&epath);
+  return NULL;
+}