commit 1680ee952c1c2a4082ec77dcf5298d7b7ccf86b3
Author: Michael Skec
Date: Thu, 16 Nov 2023 10:07:45 +1100
Initial commit
Diffstat:
5 files changed, 226 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1 @@
+mailstatus
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright © 2023
+
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the “Software”), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+\ No newline at end of file
diff --git a/Makefile b/Makefile
@@ -0,0 +1,18 @@
+OUT=mailstatus
+SRC=mailstatus.c
+
+CFLAGS+=-O2
+LDFLAGS+=
+
+all: $(OUT)
+
+debug: all
+ @gdb $(OUT)
+
+clean:
+ rm -f $(OUT)
+
+$(OUT): $(SRC)
+ gcc $(CFLAGS) $(LDFLAGS) $(SRC) -o $(OUT)
+
+.PHONY: all debug
diff --git a/README b/README
@@ -0,0 +1,6 @@
+tint2-mailstatus
+----------------
+
+Mail status information, for my own desktop setup. The program watches the
+given mailbox's 'new' directory for new mail files and outputs this information
+accordingly.
diff --git a/mailstatus.c b/mailstatus.c
@@ -0,0 +1,178 @@
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* Maximum bytes that can be displayed. */
+#define MAX_DISPLAY_LEN 25
+
+const char *_maildir_inbox;
+char _maildir_inbox_new[FILENAME_MAX];
+
+/* The display buffer */
+static char _buffer[256];
+static int _buffer_len = 0;
+
+/* Current mail info */
+static int _unread_count = 0;
+
+static int _inotify = -1, _watch = -1;
+static volatile sig_atomic_t _sigint = 0;
+
+static void
+sigint_handler(int param)
+{
+ (void)param;
+ _sigint = 1;
+ fprintf(stdout, "caught SIGINT\n");
+}
+
+static void
+update_status(void)
+{
+ DIR *d;
+ struct dirent *de;
+
+ d = opendir(_maildir_inbox_new);
+ if (d == NULL)
+ {
+ fprintf(stderr, "update failed (%d): %s", errno, strerror(errno));
+ return;
+ }
+
+ _unread_count = 0;
+ for (; (de = readdir(d)) != NULL;)
+ {
+ if (de->d_type == DT_REG)
+ ++_unread_count;
+ }
+ closedir(d);
+
+ if (_unread_count == 0)
+ {
+ _buffer_len = snprintf(_buffer, sizeof(_buffer),
+ "No new mail.");
+ }
+ else
+ {
+ _buffer_len = snprintf(_buffer, sizeof(_buffer),
+ "(%d) new mail.", _unread_count);
+ }
+}
+
+static void
+print_status(void)
+{
+ int p, pad;
+
+ fputs(_buffer, stdout);
+
+ pad = MAX_DISPLAY_LEN - _buffer_len;
+
+ for (p = 0; p < pad; ++p)
+ fputc(' ', stdout);
+
+ fputs("\n", stdout);
+ fflush(stdout);
+}
+
+int
+main(int argc, char **argv)
+{
+ int rc = 0;
+
+ /* Get maildir from command line */
+ if (argc < 2)
+ {
+ fprintf(stderr, "usage: mailstatus <mailbox>\n");
+ rc = -1;
+ goto exit;
+ }
+
+ _maildir_inbox = argv[1];
+ snprintf(_maildir_inbox_new, sizeof(_maildir_inbox_new),
+ "%s/new", _maildir_inbox);
+
+ //fprintf(stdout, "Watch directory: %s\n", _maildir_inbox_new);
+
+ _inotify = inotify_init1(IN_NONBLOCK);
+ if (_inotify == -1)
+ {
+ fprintf(stderr, "failed to initialise inotify instance (%d): %s\n",
+ errno, strerror(errno));
+ rc = -1;
+ goto exit;
+ }
+
+ /* Register inotify watch on the mail directory */
+ _watch = inotify_add_watch(_inotify,
+ _maildir_inbox_new,
+ IN_CREATE | IN_DELETE);
+ if (_watch == -1)
+ {
+ fprintf(stderr, "failed to add inotify watch (%d): %s\n",
+ errno, strerror(errno));
+ rc = -1;
+ goto exit;
+ }
+
+ struct sigaction sigact = { sigint_handler };
+ sigaction(SIGINT, &sigact, NULL);
+
+ /* Print initial mail status */
+ update_status();
+ print_status();
+
+ for (;!_sigint;)
+ {
+ /* Check for inotify updates */
+ char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
+ int n;
+ n = read(_inotify, buf, sizeof(buf));
+ if (n == -1)
+ {
+ if (errno != EAGAIN)
+ {
+ fprintf(stderr, "read failed (%d): %s\n",
+ errno, strerror(errno));
+ }
+ }
+ else if (n > 0)
+ {
+ char *p;
+ const struct inotify_event *e;
+ int count = 0;
+
+ for (p = buf;
+ p < buf + n;
+ p += sizeof(struct inotify_event) + e->len)
+ {
+ e = (const struct inotify_event *)p;
+
+ if (e->mask & (IN_CREATE | IN_DELETE))
+ ++count;
+ }
+
+ if (count > 0)
+ {
+ /* Update mail status */
+ update_status();
+ print_status();
+ }
+ }
+
+ sleep(1);
+ }
+
+exit:
+ if (_inotify > -1)
+ close(_inotify);
+
+ return rc;
+}