From e395b30eb30bb5bb659ce63f77ec670d17c8317d Mon Sep 17 00:00:00 2001 From: Jiri Kalvoda Date: Sun, 18 Jul 2021 15:21:03 +0200 Subject: [PATCH] Add inotify --- Makefile | 7 ++ cm.c | 186 ++++++++++++++++++++++++++++++++++++++++++-- maint/check-compile | 5 ++ 3 files changed, 193 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index ca9c60f..1022e72 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,9 @@ CONFIG_WIDE_CURSES=1 # Define if you want XKB led controls and on-screen display via OSDD CONFIG_X11=1 +# Define if you want watching mail changes by inotify +CONFIG_INOTIFY=1 + #DEBUG=-ggdb CFLAGS=-O2 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Winline $(DEBUG) -std=gnu99 -DVERSION=$(VERSION) -DYEAR=$(YEAR) @@ -19,6 +22,10 @@ LDFLAGS+=-lX11 CFLAGS+=-DCONFIG_X11=1 endif +ifeq ($(CONFIG_INOTIFY),1) +CFLAGS+=-DCONFIG_INOTIFY=1 +endif + VERSION=1.11 YEAR=2018 diff --git a/cm.c b/cm.c index bec8a45..155a920 100644 --- a/cm.c +++ b/cm.c @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef CONFIG_WIDE_CURSES #include @@ -79,8 +80,16 @@ static struct options global_options = { #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; @@ -116,6 +125,12 @@ static clist osd_opts; 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) { @@ -217,6 +232,7 @@ new_mbox(char *path, char *name) { 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; @@ -776,6 +792,14 @@ scan(int notify) } 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) @@ -783,6 +807,7 @@ scan(int notify) else { debug("Lost mailbox %s\n", b->name); + inotify_delete_mbox(b); del_mbox(b); } } @@ -1539,6 +1564,142 @@ handle_incsearch(int ch) return 1; } +static void +without_inotify_wait(int timeout) +{ + timeout *= 10; + halfdelay((timeout > 255) ? 255 : timeout); +} +#ifdef CONFIG_INOTIFY + +#include + +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) @@ -1557,6 +1718,7 @@ Options:\n\ -p \t\tSet minimum priority to show\n\ -s =\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\ @@ -1670,7 +1832,7 @@ main(int argc, char **argv) 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': @@ -1699,6 +1861,9 @@ main(int argc, char **argv) case 't': simple_tab = 1; break; + case 'f': + inotify_active = 1; + break; default: usage(); } @@ -1708,9 +1873,12 @@ main(int argc, char **argv) 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) @@ -1719,13 +1887,21 @@ restart: 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)) diff --git a/maint/check-compile b/maint/check-compile index f29d79e..5b125a8 100755 --- a/maint/check-compile +++ b/maint/check-compile @@ -1,4 +1,5 @@ #!/bin/sh +make clean echo "### Normal compile ###" make make clean @@ -7,3 +8,7 @@ make CONFIG_WIDE_CURSES=0 make clean echo "### No X11 ###" make CONFIG_X11=0 +make clean +echo "### No INOTIFY ###" +make CONFIG_INOTIFY=0 +make clean -- 2.39.2