]> Pileus Git - lackey/blobdiff - src/daemon.c
Add simple notification daemon mode
[lackey] / src / daemon.c
diff --git a/src/daemon.c b/src/daemon.c
new file mode 100644 (file)
index 0000000..ea61afb
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 Andy Spencer <andy753421@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define _POSIX_C_SOURCE 200112L
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "conf.h"
+#include "date.h"
+#include "cal.h"
+#include "daemon.h"
+
+/* Config data */
+static int   reminder = 15*60;
+static char *command  = NULL;
+
+/* Local data */
+static date_t old;
+static date_t new;
+
+/* Local functions */
+static void date_str(char *str, size_t size, date_t *date)
+{
+       snprintf(str, size, "%04d-%02d-%02d %02d:%02d:%02d",
+                       date->year+1, date->month+1, date->day,
+                       date->hour,   date->min,     date->sec);
+}
+
+static void notify(event_t *event)
+{
+       static char start_str[32];
+       static char end_str[32];
+
+       date_t start = event->start;
+       date_t end   = event->end;
+       wday_t wday  = day_of_week(start.year, start.month, start.day);
+
+       if (command) {
+               date_str(start_str, sizeof(start_str), &event->start);
+               date_str(end_str, sizeof(end_str), &event->end);
+
+               setenv("EVENT_NAME",  event->name ?: "", 1);
+               setenv("EVENT_DESC",  event->desc ?: "", 1);
+               setenv("EVENT_LOC",   event->loc  ?: "", 1);
+               setenv("EVENT_START", start_str, 1);
+               setenv("EVENT_END",   end_str,   1);
+
+               system(command);
+
+               unsetenv("EVENT_NAME");
+               unsetenv("EVENT_DESC");
+               unsetenv("EVENT_LOC");
+               unsetenv("EVENT_START");
+               unsetenv("EVENT_END");
+       } else {
+               printf("%s, %s %d, %d, %02d:%02d-%02d:%02d\n",
+                       day_to_string(wday),
+                       month_to_string(start.month),
+                       start.day+1,
+                       start.year,
+                       start.hour, start.min,
+                       end.hour,   end.min);
+
+               if (event->name)
+                       printf("    Name:     %s\n", event->name);
+               if (event->loc)
+                       printf("    Location: %s\n", event->loc);
+               if (event->desc)
+                       printf("    Details:  %s\n", event->desc);
+       }
+}
+
+static int step(void)
+{
+       int delay = 24*60*60;
+
+       debug("Polling: %02dh %02dm %02ds",
+               NOW.hour, NOW.min, NOW.sec);
+
+       /* Bump timestamps */
+       old = new;
+       new = NOW;
+
+       /* Print notifications */
+       for (event_t *cur = EVENTS; cur; cur = cur->next) {
+               if (compare(&cur->start, &old) < 0)
+                       continue;
+
+               int old_until = get_secs(&old, &cur->start);
+               int new_until = get_secs(&new, &cur->start);
+
+               if (old_until > reminder && new_until <= reminder) {
+                       debug("Notify: %s", cur->name);
+                       notify(cur);
+               }
+               if (new_until > reminder) {
+                       delay = new_until - reminder;
+                       break;
+               }
+       }
+
+       /* Return delay */
+       return delay;
+}
+
+/* Initialize */
+void daemon_init(void)
+{
+       old = NOW;
+       new = NOW;
+}
+
+void daemon_main(void)
+{
+       int delay = 0;
+       while (1) {
+               date_sync();
+               delay = step();
+               fflush(stdout);
+               sleep(delay);
+       }
+}
+
+void daemon_exit(void)
+{
+}
+
+/* Config parser */
+void daemon_config(const char *group, const char *name, const char *key, const char *value)
+{
+       if (match(group, "daemon")) {
+               if (match(key, "reminder")) {
+                       reminder = get_number(value);
+               } else if (match(key, "notify")) {
+                       command = get_string(value);
+               }
+       }
+}
+
+/* Test */
+void daemon_test(void)
+{
+       static event_t event0 = {
+               .name   = "test event",
+               .desc   = "this event is random and does not exist",
+       };
+       static event_t event1 = {
+               .name   = "test event",
+               .desc   = "this event is random and does not exist",
+       };
+       static todo_t todo = {
+               .name   = "test todo",
+               .desc   = "this todo is random and does not exist",
+               .status = 50,
+       };
+
+       EVENTS = &event0;
+       EVENTS->next = &event1;
+       TODOS = &todo;
+
+       date_sync();
+
+       NOW.hour    = 0;
+       NOW.min     = 0;
+       NOW.sec     = 0;
+
+       event0.start = ((date_t){NOW.year, NOW.month, NOW.day, 12, 0});
+       event0.end   = ((date_t){NOW.year, NOW.month, NOW.day, 13, 0});
+       event1.start = ((date_t){NOW.year, NOW.month, NOW.day, 14, 0});
+       event1.end   = ((date_t){NOW.year, NOW.month, NOW.day, 15, 0});
+       todo.due     = ((date_t){NOW.year, NOW.month, NOW.day, 16, 0});
+
+       util_init();
+
+       daemon_config("daemon", NULL, "reminder", "15");
+       daemon_config("daemon", NULL, "notify", "lackey-notify");
+
+       daemon_init();
+       while (NOW.day == EVENTS->start.day) {
+               int delay = step();
+               delay = MIN(delay, rand() % (60*60));
+               NOW = get_date(get_stamp(NOW)+delay);
+       }
+       daemon_exit();
+}