#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
+#include <errno.h>
#ifdef CONFIG_WIDE_CURSES
#include <ncurses.h>
#define MDIR_MAX_NAME_LEN 128
+enum inotify_status
+{
+ INOTIFY_OFF,
+ INOTIFY_ON,
+ INOTIFY_ERROR,
+};
+
struct mbox {
cnode n;
+ enum inotify_status inotify_status;
struct options o;
char *name;
char *path;
static void redraw_line(int i);
static void rethink_display(int notify);
+static int inotify_fd;
+static bool inotify_active;
+static void inotify_cm_init(void);
+static void inotify_add_mbox(struct mbox * b);
+static void inotify_delete_mbox(struct mbox * b);
+
static void
add_pattern(char *patt)
{
{
struct mbox *b = xmalloc(sizeof(*b));
bzero(b, sizeof(*b));
+ b->inotify_status = INOTIFY_OFF;
b->path = xstrdup(path);
b->name = xstrdup(name);
return b;
}
struct mbox *tmp;
+ if(inotify_active)
+ CLIST_FOR_EACH_DELSAFE(struct mbox *, b, mboxes, tmp)
+ {
+ if(b->inotify_status != INOTIFY_ON)
+ inotify_add_mbox(b);
+ }
+
+
CLIST_FOR_EACH_DELSAFE(struct mbox *, b, mboxes, tmp)
{
if (b->seen)
else
{
debug("Lost mailbox %s\n", b->name);
+ inotify_delete_mbox(b);
del_mbox(b);
}
}
return 1;
}
+static void
+without_inotify_wait(int timeout)
+{
+ timeout *= 10;
+ halfdelay((timeout > 255) ? 255 : timeout);
+}
+#ifdef CONFIG_INOTIFY
+
+#include <sys/inotify.h>
+
+static void
+inotify_cm_init(void)
+{
+ if (!inotify_active) return;
+ inotify_fd = inotify_init();
+ if (inotify_fd < 0)
+ die("Inotify init faild.\n");
+}
+
+static void
+inotify_add_mbox(struct mbox * b)
+{
+ if (!inotify_active) return;
+ b->inotify_status = INOTIFY_ON;
+ char *path = xmalloc(strlen(b->path)+100);
+ struct stat st;
+ if (stat(b->path, &st) < 0)
+ {
+ debug("Get stat of %s faild\n", b->path);
+ return;
+ }
+ if (S_ISREG(st.st_mode))
+ {
+ // Regular mailbox
+ sprintf(path, "%s", b->path);
+ if (inotify_add_watch(inotify_fd, path, IN_MOVED_TO | IN_MOVED_FROM | IN_DELETE | IN_CLOSE_WRITE ) < 0)
+ {
+ debug("Inotify add %s faild\n", path);
+ b->inotify_status = INOTIFY_ERROR;
+ }
+ else
+ debug("Inotify add %s OK\n", path);
+ }
+ else if (S_ISDIR(st.st_mode))
+ {
+ // Maildir
+ char *watch_dir[] = {"cur", "new"};
+ for (int i=0; i < (int)(sizeof(watch_dir)/sizeof(*watch_dir)); i++)
+ {
+ sprintf(path, "%s/%s", b->path, watch_dir[i]);
+ if (inotify_add_watch(inotify_fd, path, IN_MOVED_TO | IN_MOVED_FROM | IN_DELETE | IN_CLOSE_WRITE ) < 0)
+ {
+ debug("Inotify add %s faild\n", path);
+ b->inotify_status = INOTIFY_ERROR;
+ }
+ }
+ }
+ else
+ {
+ debug("neither file nor directory\n");
+ b->inotify_status = INOTIFY_ERROR;
+ return;
+ }
+ free(path);
+}
+
+static void
+inotify_delete_mbox(struct mbox * b)
+{
+ (void)b;
+ // TODO
+}
+
+static bool // true if inotify change detected
+inotify_wait(int timeout)
+{
+ if(!inotify_active)
+ {
+ without_inotify_wait(timeout);
+ return 0;
+ }
+
+ bool inotify_change = 0;
+
+ struct timeval tv;
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ while (true)
+ {
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(0, &rfds);
+ FD_SET(inotify_fd, &rfds);
+
+ debug("Select begin (timeout %d %d)\n", tv.tv_sec, tv.tv_usec);
+ int ret = select(1+inotify_fd, &rfds, NULL, NULL, &tv);
+ debug("Select end\n");
+ if (ret>0 && FD_ISSET(0, &rfds))
+ return inotify_change;
+ if (ret>0 && FD_ISSET(inotify_fd, &rfds))
+ {
+ debug("Read notify begin\n");
+ char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event))));
+ ssize_t len = read(inotify_fd, buf, sizeof(buf));
+ if (len == -1 && errno != EAGAIN)
+ perror ("read inotify faild");
+ inotify_change = 1;
+ debug("Read notify end\n");
+ }
+ else
+ return inotify_change;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ }
+}
+
+#else
+
+static void
+inotify_cm_init(void){}
+
+static void
+inotify_add_mbox(struct mbox *){}
+
+static void
+inotify_delete_mbox(struct mbox *){}
+
+static bool
+inotify_wait(int timeout)
+{
+ without_inotify_wait(timeout);
+ return 0;
+}
+
+#endif
+
#define STR2(c) #c
#define STR(c) STR2(c)
-p <pri>\t\tSet minimum priority to show\n\
-s <key>=<val>\t\tSet on-screen display options (consult OSDD docs)\n\
-t\t\t\tLet TAB select the next mailbox with new mail, no matter what priority it has\n\
+-f\t\t\tEnable inotify (wait for file system changes)\n\
\n\
On-screen display replacement (in all OSD values and notification lines):\n\
%%%%\t\t%%\n\
clist_init(&osd_opts);
int c;
- while ((c = getopt(argc, argv, "c:dim:o:p:s:t")) >= 0)
+ while ((c = getopt(argc, argv, "c:dim:o:p:s:tif")) >= 0)
switch (c)
{
case 'c':
case 't':
simple_tab = 1;
break;
+ case 'f':
+ inotify_active = 1;
+ break;
default:
usage();
}
charset_init();
term_init();
x11_init();
+ inotify_cm_init();
scan_and_redraw(0);
next_active(0, 1);
+
+ int inotify_rescan = 0;
int should_exit = 0;
restart:
while (!should_exit)
int remains = last_scan_time + check_interval - now;
if (force_refresh)
scan_and_redraw(0);
- if (remains <= 0)
- scan_and_redraw(1);
+ if (remains <= 0 || inotify_rescan)
+ {
+ if (inotify_rescan) debug("Inotify rescan\n");
+ inotify_rescan = 0;
+ scan_and_redraw(1);
+ }
else
{
- remains *= 10;
- halfdelay((remains > 255) ? 255 : remains);
+ nodelay(stdscr,1);
int ch = getch();
+ if (ch < 0)
+ {
+ inotify_rescan |= inotify_wait(remains);
+ ch = getch();
+ }
if (ch < 0)
continue;
if (is_active && handle_incsearch(ch))