]> mj.ucw.cz Git - checkmail.git/blobdiff - cm.c
Better rules for coloring of flagged messages.
[checkmail.git] / cm.c
diff --git a/cm.c b/cm.c
index 50f70717ebfe8f5320bec6b095122d3c474b5042..a3bba1853305c46e21b595475157a6ec37ff5b0a 100644 (file)
--- a/cm.c
+++ b/cm.c
@@ -1,12 +1,9 @@
 /*
  *     Incoming Mail Checker
  *
- *     (c) 2005 Martin Mares <mj@ucw.cz>
+ *     (c) 2005--2007 Martin Mares <mj@ucw.cz>
  */
 
-#define VERSION "0.2"
-#define YEAR "2005"
-
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 #include "util.h"
 #include "clists.h"
+#include "charset.h"
 
 static int check_interval = 30;
 static int force_refresh;
+static int allow_bells = 1;
 static int minimum_priority;
 static time_t last_scan_time;
 static char *run_cmd = "mutt -f %s";
@@ -37,6 +36,9 @@ struct options {
   int highlight;
   int beep;
   int snippets;
+  int show_flagged;
+  int sender_personal;
+  int sender_mbox;
 };
 
 struct option_node {
@@ -52,7 +54,9 @@ struct pattern_node {
 };
 
 static clist options, patterns;
-static struct options global_options;
+static struct options global_options = {
+  .sender_personal = 1
+};
 
 struct mbox {
   cnode n;
@@ -64,10 +68,11 @@ struct mbox {
   int seen;
   time_t last_time;
   int last_size, last_pos;
-  int total, new;
-  int last_total, last_new;
+  int total, new, flagged;
+  int last_total, last_new, last_flagged;
   int last_beep_new;
   int force_refresh;
+  int snippet_is_new;
   char snippet[256];
 };
 
@@ -113,6 +118,9 @@ init_options(struct options *o)
   o->beep = -1;
   o->highlight = -1;
   o->snippets = -1;
+  o->show_flagged = -1;
+  o->sender_personal = -1;
+  o->sender_mbox = -1;
 }
 
 static void
@@ -130,6 +138,9 @@ setup_options(struct mbox *b)
        MERGE(highlight);
        MERGE(beep);
        MERGE(snippets);
+       MERGE(show_flagged);
+       MERGE(sender_personal);
+       MERGE(sender_mbox);
       }
 }
 
@@ -201,15 +212,6 @@ mbox_visible_p(struct mbox *b)
   return 1;
 }
 
-static void
-add_snippet(char **ppos, char *term, char *add)
-{
-  char *pos = *ppos;
-  while (*add && pos < term)
-    *pos++ = *add++;
-  *ppos = pos;
-}
-
 static void
 prepare_snippet(struct mbox *b, char *sender, char *subject)
 {
@@ -220,13 +222,13 @@ prepare_snippet(struct mbox *b, char *sender, char *subject)
 
   char *pos = b->snippet;
   char *term = b->snippet + sizeof(b->snippet) - 1;
-  if (sender[0])
+  if (sender[0] && (b->o.sender_mbox || b->o.sender_personal))
     {
-      add_snippet(&pos, term, sender);
+      add_addr_snippet(&pos, term, sender, b->o.sender_mbox, b->o.sender_personal);
       add_snippet(&pos, term, ": ");
     }
   if (subject[0])
-    add_snippet(&pos, term, subject);
+    add_subject_snippet(&pos, term, subject);
   else
     add_snippet(&pos, term, "No subject");
 }
@@ -241,7 +243,7 @@ mb_reset(int pos)
   mb_pos = pos;
 }
 
-static int
+static void
 mb_seek(uns pos)
 {
   lseek(mb_fd, pos, SEEK_SET);
@@ -278,6 +280,13 @@ mb_get(void)
   return (mb_cc < mb_end) ? *mb_cc++ : mb_ll_get();
 }
 
+static void
+mb_unget(int c)
+{
+  if (c >= 0)
+    mb_cc--;
+}
+
 static int
 mb_check(const char *p, int len)
 {
@@ -298,7 +307,7 @@ scan_mbox(struct mbox *b, struct stat *st)
 
   if (!st->st_size)
     {
-      b->total = b->new = 0;
+      b->total = b->new = b->flagged = 0;
       b->last_pos = 0;
       return;
     }
@@ -309,7 +318,7 @@ scan_mbox(struct mbox *b, struct stat *st)
   if (mb_fd < 0)
     {
       debug("[open failed: %m] ");
-      b->total = b->new = -1;
+      b->total = b->new = b->flagged = -1;
       return;
     }
   mb_reset(0);
@@ -334,16 +343,18 @@ scan_mbox(struct mbox *b, struct stat *st)
       if (!mb_check(from+1, 5))
        {
          debug("[inconsistent] ");
-         b->total = b->new = -1;
+         b->total = b->new = b->flagged = -1;
          goto done;
        }
-      b->total = b->new = 0;
-      b->last_total = b->last_new = 0;
+      b->total = b->new = b->flagged = 0;
+      b->last_total = b->last_new = b->last_flagged = 0;
+      b->snippet_is_new = 0;
     }
   else
     {
       b->total = b->last_total;
       b->new = b->last_new;
+      b->flagged = b->last_flagged;
     }
 
   for(;;)
@@ -353,10 +364,12 @@ scan_mbox(struct mbox *b, struct stat *st)
        b->last_pos--;          // last_pos should be the previous \n character
       b->last_total = b->total;
       b->last_new = b->new;
+      b->last_flagged = b->flagged;
       while ((c = mb_get()) >= 0 && c != '\n')
        ;
 
       int new = 1;
+      int flagged = 0;
       sender[0] = 0;
       subject[0] = 0;
       for (;;)
@@ -371,7 +384,19 @@ scan_mbox(struct mbox *b, struct stat *st)
                  goto done;
                }
              if (c == '\n')
-               break;
+               {
+                 int fold = -1;
+                 do
+                   {
+                     fold++;
+                     c = mb_get();
+                   }
+                 while (c == ' ' || c == '\t');
+                 mb_unget(c);
+                 if (!fold)
+                   break;
+                 c = ' ';
+               }
              if (c == '\r')
                continue;
              if (i < sizeof(buf) - 1)
@@ -382,6 +407,8 @@ scan_mbox(struct mbox *b, struct stat *st)
            break;
          if (!strncasecmp(buf, "Status:", 7))
            new = 0;
+         else if (!strncasecmp(buf, "X-Status:", 9) && strchr(buf+9, 'F'))
+           flagged = 1;
          else if (!strncasecmp(buf, "From:", 5))
            strcpy(sender, buf+5);
          else if (!strncasecmp(buf, "Subject:", 8))
@@ -390,8 +417,12 @@ scan_mbox(struct mbox *b, struct stat *st)
 
       b->total++;
       if (new)
+       b->new++;
+      if (flagged)
+       b->flagged++;
+      if (new || (flagged && !b->snippet_is_new))
        {
-         b->new++;
+         b->snippet_is_new = new;
          prepare_snippet(b, sender, subject);
        }
 
@@ -466,7 +497,7 @@ scan(void)
        b->force_refresh = 1;
       if (stat(b->path, &st) < 0)
        {
-         b->total = b->new = -1;
+         b->total = b->new = b->flagged = -1;
          debug("%m\n");
        }
       else if (!b->last_time || st.st_mtime != b->last_time || st.st_size != b->last_size || b->force_refresh)
@@ -478,7 +509,7 @@ scan(void)
          scan_mbox(b, &st);
          b->last_time = st.st_mtime;
          b->last_size = st.st_size;
-         debug("%d %d (stopped at %d of %d)\n", b->total, b->new, b->last_pos, b->last_size);
+         debug("%d %d %d (stopped at %d of %d)\n", b->total, b->new, b->flagged, b->last_pos, b->last_size);
 
          b->scanning = 0;
          redraw_line(b->index);
@@ -501,6 +532,7 @@ enum {
   M_IDLE,
   M_SCAN,
   M_NEW,
+  M_FLAG,
   M_BAD,
   M_MAX
 };
@@ -523,6 +555,8 @@ redraw_line(int i)
        printw("  ");
       if (b->new)
        attrset(attrs[cc][hi][M_NEW]);
+      else if (b->flagged)
+       attrset(attrs[cc][hi][M_FLAG]);
       printw("%-20s ", b->name);
       if (b->scanning < 0)
        ;
@@ -540,6 +574,7 @@ redraw_line(int i)
        {
          attrset(attrs[cc][hi][M_IDLE]);
          printw("%6d ", b->total);
+         int snip = 0;
          if (b->new)
            {
              attrset(attrs[cc][hi][M_NEW]);
@@ -554,14 +589,24 @@ redraw_line(int i)
                printw("%2d hrs  ", age/3600);
              else
                printw("        ");
-             if (b->o.snippets && b->snippet[0])
-               {
-                 int xx, yy;
-                 getyx(stdscr, yy, xx);
-                 int remains = COLS-1-xx;
-                 if (remains > 2)
-                   printw("%-.*s", remains, b->snippet);
-               }
+             snip = 1;
+           }
+         else if (b->flagged)
+           {
+             attrset(attrs[cc][hi][M_FLAG]);
+             printw("%6d  ", b->flagged);
+             attrset(attrs[cc][hi][M_IDLE]);
+             printw("        ");
+             attrset(attrs[cc][0][M_FLAG]);    /* We avoid the highlight intentionally */
+             snip = b->o.show_flagged;
+           }
+         if (snip && b->o.snippets && b->snippet[0])
+           {
+             int xx, yy;
+             getyx(stdscr, yy, xx);
+             int remains = COLS-1-xx;
+             if (remains > 2)
+               printw("%-.*s", remains, b->snippet);
            }
        }
     }
@@ -626,7 +671,7 @@ rethink_display(void)
       redraw_all();
       refresh();
     }
-  if (beeeep)
+  if (beeeep && allow_bells)
     beep();
 }
 
@@ -642,8 +687,8 @@ term_init(void)
   curs_set(0);
 
   static const int attrs_mono[2][M_MAX] = {
-    [0] = { [M_IDLE] = 0, [M_SCAN] = A_BOLD, [M_NEW] = A_BOLD, [M_BAD] = A_DIM },
-    [1] = { [M_IDLE] = 0, [M_SCAN] = A_BOLD, [M_NEW] = A_REVERSE | A_BOLD, [M_BAD] = A_DIM },
+    [0] = { [M_IDLE] = 0, [M_SCAN] = A_BOLD, [M_NEW] = A_BOLD, [M_FLAG] = 0, [M_BAD] = A_DIM },
+    [1] = { [M_IDLE] = 0, [M_SCAN] = A_BOLD, [M_NEW] = A_REVERSE | A_BOLD, [M_FLAG] = A_REVERSE, [M_BAD] = A_DIM },
   };
   for (int i=0; i<2; i++)
     for (int j=0; j<M_MAX; j++)
@@ -662,11 +707,13 @@ term_init(void)
          init_pair(3, COLOR_WHITE, COLOR_BLUE);
          init_pair(4, COLOR_YELLOW, COLOR_BLUE);
          init_pair(5, COLOR_RED, COLOR_BLUE);
+         init_pair(6, COLOR_GREEN, COLOR_BLACK);
+         init_pair(7, COLOR_GREEN, COLOR_BLUE);
          static const int attrs_color[2][2][M_MAX] = {
-           [0][0] = { [M_IDLE] = 0, [M_SCAN] = COLOR_PAIR(1), [M_NEW] = COLOR_PAIR(1), [M_BAD] = COLOR_PAIR(2) },
-           [0][1] = { [M_IDLE] = A_BOLD, [M_SCAN] = COLOR_PAIR(1), [M_NEW] = COLOR_PAIR(1) | A_BOLD, [M_BAD] = COLOR_PAIR(2) | A_BOLD },
-           [1][0] = { [M_IDLE] = COLOR_PAIR(3), [M_SCAN] = COLOR_PAIR(4), [M_NEW] = COLOR_PAIR(4), [M_BAD] = COLOR_PAIR(5) },
-           [1][1] = { [M_IDLE] = COLOR_PAIR(3) | A_BOLD, [M_SCAN] = COLOR_PAIR(4), [M_NEW] = COLOR_PAIR(4) | A_BOLD, [M_BAD] = COLOR_PAIR(5) | A_BOLD },
+           [0][0] = { [M_IDLE] = 0, [M_SCAN] = COLOR_PAIR(1), [M_NEW] = COLOR_PAIR(1), [M_FLAG] = COLOR_PAIR(6), [M_BAD] = COLOR_PAIR(2) },
+           [0][1] = { [M_IDLE] = A_BOLD, [M_SCAN] = COLOR_PAIR(1), [M_NEW] = COLOR_PAIR(1) | A_BOLD, [M_FLAG] = COLOR_PAIR(6) | A_BOLD, [M_BAD] = COLOR_PAIR(2) | A_BOLD },
+           [1][0] = { [M_IDLE] = COLOR_PAIR(3), [M_SCAN] = COLOR_PAIR(4), [M_NEW] = COLOR_PAIR(4), [M_FLAG] = COLOR_PAIR(7), [M_BAD] = COLOR_PAIR(5) },
+           [1][1] = { [M_IDLE] = COLOR_PAIR(3) | A_BOLD, [M_SCAN] = COLOR_PAIR(4), [M_NEW] = COLOR_PAIR(4) | A_BOLD, [M_FLAG] = COLOR_PAIR(7) | A_BOLD, [M_BAD] = COLOR_PAIR(5) | A_BOLD },
          };
          memcpy(attrs, attrs_color, sizeof(attrs));
        }
@@ -680,17 +727,23 @@ term_cleanup(void)
 }
 
 static void
-scan_and_redraw(void)
+print_status(char *status)
 {
   move(LINES-1, 0);
-  printw("Busy...");
-  refresh();
-  scan();
-  move(LINES-1, 0);
+  if (status)
+    printw("%s", status);
   clrtoeol();
   refresh();
 }
 
+static void
+scan_and_redraw(void)
+{
+  print_status("Busy...");
+  scan();
+  print_status(NULL);
+}
+
 static void
 move_cursor(int i)
 {
@@ -728,6 +781,9 @@ next_active(int since, int step)
     move_cursor(besti);
 }
 
+#define STR2(c) #c
+#define STR(c) STR2(c)
+
 static void NONRET
 usage(void)
 {
@@ -746,11 +802,14 @@ Mailbox options (set with `-o', use upper case to negate):\n\
 0-9\t\t\tSet mailbox priority (0=default)\n\
 b\t\t\tBeep when a message arrives\n\
 e\t\t\tHide from display if empty\n\
+f\t\t\tShow flagged messages if there are no new ones\n\
 h\t\t\tHide from display\n\
+m\t\t\tShow mailbox name of the sender\n\
+p\t\t\tShow personal info (full name) of the sender\n\
 s\t\t\tShow message snippets\n\
 t\t\t\tHighlight the entry\n\
 \n\
-CheckMail " VERSION ", (c) " YEAR " Martin Mares <mj@ucw.cz>\n\
+CheckMail " STR(VERSION) ", (c) " STR(YEAR) " Martin Mares <mj@ucw.cz>\n\
 It can be freely distributed and used according to the GNU GPL v2.\n\
 ");
   exit(1);
@@ -789,9 +848,18 @@ parse_options(char *c)
          case 'e':
            o->hide_if_empty = value;
            break;
+         case 'f':
+           o->show_flagged = value;
+           break;
          case 'h':
            o->hide = value;
            break;
+         case 'm':
+           o->sender_mbox = value;
+           break;
+         case 'p':
+           o->sender_personal = value;
+           break;
          case 's':
            o->snippets = value;
            break;
@@ -842,6 +910,7 @@ main(int argc, char **argv)
   while (optind < argc)
     add_pattern(argv[optind++]);
 
+  charset_init();
   term_init();
   scan_and_redraw();
   next_active(0, 1);
@@ -903,9 +972,22 @@ main(int argc, char **argv)
                  scan_and_redraw();
                }
              break;
+           case 'l' & 0x1f:
+             clearok(stdscr, TRUE);
+             redraw_all();
+             refresh();
+             break;
            case 'r' & 0x1f:
              force_refresh = 1;
              break;
+           case 'b':
+             allow_bells = 1;
+             print_status("Bells and whistles are now enabled. Toot!");
+             break;
+           case 'B':
+             allow_bells = 0;
+             print_status("Bells and whistles are now disabled. Pssst!");
+             break;
            default:
              if (ch >= '0' && ch <= '9')
                {