From: Andy Spencer Date: Sun, 11 Jun 2017 02:25:02 +0000 (+0000) Subject: Add simple notification daemon mode X-Git-Url: http://pileus.org/git/?p=lackey;a=commitdiff_plain;h=d45541aeb31a0e34a2a43df0e112f1f720f80abf;hp=7edd7d3a9f0bdaaa8df9f68a73f7c84e2b514ce6 Add simple notification daemon mode --- diff --git a/makefile b/makefile index b249a27..ce82c84 100644 --- a/makefile +++ b/makefile @@ -15,9 +15,9 @@ LDFLAGS ?= -lncursesw -lical # Sources PROG ?= lackey -PROG_SRC ?= main util args conf date cal view print +PROG_SRC ?= main util args conf date cal view print daemon TEST ?= test -TEST_SRC ?= test util conf date cal +TEST_SRC ?= test util conf date cal daemon VIEWS ?= day week month year events todo settings help edit CALS ?= dummy ical diff --git a/src/args.c b/src/args.c index 49fe2f1..0390e0f 100644 --- a/src/args.c +++ b/src/args.c @@ -26,6 +26,7 @@ /* Global data */ int PRINT = 0; +int DAEMON = 0; /* Local data */ char **calendars = NULL; @@ -36,6 +37,7 @@ static char *short_options = "hp::d"; struct option long_options[] = { {"help", 0, NULL, 'h'}, {"print", 2, NULL, 'p'}, + {"daemon", 0, NULL, 'd'}, }; /* Usage */ @@ -47,6 +49,7 @@ static void usage(char *name) printf("Options:\n"); printf(" -h, --help Print usage information\n"); printf(" -p, --print=[dw] Show upcomming events\n"); + printf(" -d, --daemon Run in daemon mode\n"); } /* Initialize */ @@ -70,6 +73,9 @@ void args_setup(int argc, char **argv) match(optarg, "w") ? 7 : match(optarg, "week") ? 7 : -1; break; + case 'd': + DAEMON = 1; + break; } } @@ -79,6 +85,8 @@ void args_setup(int argc, char **argv) /* Validate arguments */ if (PRINT < 0) error("Unknown print: %s\n", optarg); + if (PRINT && DAEMON) + error("Cannot print and run as daemon"); /* Load calendars */ for (int i = 0; calendars[i]; i++) diff --git a/src/args.h b/src/args.h index c62c9c2..af7f09d 100644 --- a/src/args.h +++ b/src/args.h @@ -17,6 +17,7 @@ /* Global data */ extern int PRINT; +extern int DAEMON; /* Functions */ void args_setup(int argc, char **argv); diff --git a/src/daemon.c b/src/daemon.c new file mode 100644 index 0000000..ea61afb --- /dev/null +++ b/src/daemon.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2017 Andy Spencer + * + * 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 . + */ + +#define _POSIX_C_SOURCE 200112L + +#include +#include +#include + +#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(); +} diff --git a/src/daemon.h b/src/daemon.h new file mode 100644 index 0000000..b1ab1f7 --- /dev/null +++ b/src/daemon.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 Andy Spencer + * + * 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 . + */ + +/* Functions */ +void daemon_init(void); +void daemon_main(void); +void daemon_exit(void); +void daemon_config(const char *group, const char *name, const char *key, const char *value); diff --git a/src/date.c b/src/date.c index 4371dff..182d5aa 100644 --- a/src/date.c +++ b/src/date.c @@ -159,6 +159,11 @@ int get_mins(date_t *start, date_t *end) return (get_stamp(*end)-get_stamp(*start))/60; } +int get_secs(date_t *start, date_t *end) +{ + return (get_stamp(*end)-get_stamp(*start)); +} + int compare(date_t *a, date_t *b) { int rval = a->year < b->year ? -1 : a->year > b->year ? 1 : diff --git a/src/date.h b/src/date.h index ccd2252..85fb805 100644 --- a/src/date.h +++ b/src/date.h @@ -83,6 +83,7 @@ void add_months(year_t *year, month_t *month, int months); date_t get_date(stamp_t stamp); stamp_t get_stamp(date_t date); int get_mins(date_t *start, date_t *end); +int get_secs(date_t *start, date_t *end); int compare(date_t *a, date_t *b); int same_day(date_t *a, date_t *b); int before(date_t *start, int year, int month, int day, int hour, int min); diff --git a/src/main.c b/src/main.c index bf518ff..4c701df 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,7 @@ #include "cal.h" #include "view.h" #include "print.h" +#include "daemon.h" /* Config parser */ static void on_config(const char *group, const char *name, const char *key, const char *value) @@ -33,6 +34,7 @@ static void on_config(const char *group, const char *name, const char *key, cons date_config(group, name, key, value); cal_config(group, name, key, value); view_config(group, name, key, value); + daemon_config(group, name, key, value); } /* Control-C handler, so we don't hose the therminal */ @@ -40,6 +42,8 @@ static void on_sigint(int signum) { if (PRINT) print_exit(); + else if (DAEMON) + daemon_exit(); else view_exit(); exit(0); @@ -70,6 +74,11 @@ int main(int argc, char **argv) print_main(); print_exit(); } + else if (DAEMON) { + daemon_init(); + daemon_main(); + daemon_exit(); + } else { view_init(); view_main(); diff --git a/src/test.c b/src/test.c index 96f7f8c..9152b70 100644 --- a/src/test.c +++ b/src/test.c @@ -23,6 +23,7 @@ void date_test(void); void conf_test(void); void ical_test(void *path); +void daemon_test(); int main(int argc, char **argv) { @@ -30,6 +31,7 @@ int main(int argc, char **argv) if (match(argv[i], "date")) date_test(); if (match(argv[i], "conf")) conf_test(); if (match(argv[i], "ical")) ical_test(argv[++i]); + if (match(argv[i], "daemon")) daemon_test(); } return 0; }