/*
* 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";
int highlight;
int beep;
int snippets;
+ int show_flagged;
+ int sender_personal;
+ int sender_mbox;
};
struct option_node {
};
static clist options, patterns;
-static struct options global_options;
+static struct options global_options = {
+ .sender_personal = 1
+};
struct mbox {
cnode n;
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];
};
o->beep = -1;
o->highlight = -1;
o->snippets = -1;
+ o->show_flagged = -1;
+ o->sender_personal = -1;
+ o->sender_mbox = -1;
}
static void
MERGE(highlight);
MERGE(beep);
MERGE(snippets);
+ MERGE(show_flagged);
+ MERGE(sender_personal);
+ MERGE(sender_mbox);
}
}
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)
{
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");
}
mb_pos = pos;
}
-static int
+static void
mb_seek(uns pos)
{
lseek(mb_fd, pos, SEEK_SET);
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)
{
if (!st->st_size)
{
- b->total = b->new = 0;
+ b->total = b->new = b->flagged = 0;
b->last_pos = 0;
return;
}
if (mb_fd < 0)
{
debug("[open failed: %m] ");
- b->total = b->new = -1;
+ b->total = b->new = b->flagged = -1;
return;
}
mb_reset(0);
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(;;)
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 (;;)
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)
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))
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);
}
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)
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);
M_IDLE,
M_SCAN,
M_NEW,
+ M_FLAG,
M_BAD,
M_MAX
};
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)
;
{
attrset(attrs[cc][hi][M_IDLE]);
printw("%6d ", b->total);
+ int snip = 0;
if (b->new)
{
attrset(attrs[cc][hi][M_NEW]);
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);
}
}
}
redraw_all();
refresh();
}
- if (beeeep)
+ if (beeeep && allow_bells)
beep();
}
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++)
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));
}
}
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)
{
move_cursor(besti);
}
+#define STR2(c) #c
+#define STR(c) STR2(c)
+
static void NONRET
usage(void)
{
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);
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;
while (optind < argc)
add_pattern(argv[optind++]);
+ charset_init();
term_init();
scan_and_redraw();
next_active(0, 1);
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')
{