/* * 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(); }