From 9c7360bbd9c7ca32f1e9db994d6e489bebe602a9 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 1 Jan 2014 11:43:17 +1100 Subject: [PATCH] cal / alarm: convert to use ical date info. This is an incompatible change. alarm files need to be rebuilt Format now allows for RRULE recurrences. So this should be DST-proof now. --- alarm/alarm.c | 78 ++++++++++++------- alarm/cal.c | 206 ++++++++++++++++++++++++++------------------------ 2 files changed, 160 insertions(+), 124 deletions(-) diff --git a/alarm/alarm.c b/alarm/alarm.c index ea90c01..3f4cbef 100644 --- a/alarm/alarm.c +++ b/alarm/alarm.c @@ -28,16 +28,18 @@ #include #include #include +#include #include #include #include #include #include "libsus.h" +#include "ical-dates.h" struct alarm_ev { struct alarm_ev *next; time_t when; - long recur; + struct ical_dates idate; char *mesg; }; @@ -46,6 +48,7 @@ void alarm_free(struct alarm_ev *ev) while (ev) { struct alarm_ev *n = ev->next; free(ev->mesg); + ical_dates_free(&ev->idate); free(ev); ev = n; } @@ -54,37 +57,59 @@ void alarm_free(struct alarm_ev *ev) void update_event(struct alarm_ev *ev, time_t now) { /* make sure 'when' is in the future if possible */ - while (ev->when < now && ev->recur > 0) - ev->when += ev->recur; + struct ical_time inow; + struct ical_timelist rv = {0}; + ical_localtime(&inow, &now); + ical_rr_dates(&ev->idate.start, &ev->idate.rr, &inow, 1, &rv); + if (rv.cnt >= 1) + ev->when = ical_mktime(rv.v); + else + ev->when = ical_mktime(&ev->idate.start); + ical_timelist_free(&rv); +/* FIXME what if it is a date, not a time*/ } struct alarm_ev *event_parse(char *line) { + /* Space separated ical lines, except that SUMMARY: is the last + * and can hold spaces, and provides the message. + */ struct alarm_ev *rv; - char *recur, *mesg; - struct tm tm; - long rsec; - recur = strchr(line, ':'); - if (!recur) - return NULL; - *recur++ = 0; - mesg = strchr(recur, ':'); - if (!mesg) - return NULL; - *mesg++ = 0; - line = strptime(line, "%Y-%m-%d-%H-%M-%S", &tm); - if (!line) - return NULL; - rsec = atoi(recur); - if (rsec < 0) - return NULL; + char *mesg = NULL; + struct ical_dates dt = {{0}}; + + while (*line) { + char *w = line; + int l, err; + if (strncmp(line, "SUMMARY:", 8) == 0) + l = strlen(line); + else + l = strcspn(line, " "); + if (line[l]) + line[l++] = 0; + line += l; + + err = ical_parse_dates_line(&dt, w); + if (err == 1) + continue; + if (err == 0) + goto abort; + if (strncmp(w, "SUMMARY:", 8) != 0 || mesg) + goto abort; + mesg = strdup(w+8); + } + if (dt.start.mon == 0 || dt.start.time_set == 0) + goto abort; rv = malloc(sizeof(*rv)); rv->next = NULL; - tm.tm_isdst = -1; - rv->when = mktime(&tm); - rv->recur = rsec; - rv->mesg = strdup(mesg); + rv->idate = dt; + rv->when = ical_mktime(&dt.start); + rv->mesg = mesg; return rv; +abort: + free(mesg); + ical_dates_free(&dt); + return NULL; } struct alarm_ev *event_load_soonest(char *file, time_t now) @@ -185,7 +210,7 @@ void event_deliver(struct alarm_ev *ev) tm = localtime(&ev->when); strftime(line+strlen(line), 1024, " ALARM %Y%m%d-%H%M%S", tm); z = line + strlen(line); - sprintf(z, "%+03d alarm ", tm->tm_gmtoff/60/15); + sprintf(z, "%+03d alarm ", (int)tm->tm_gmtoff/60/15); z = line + strlen(line); m = ev->mesg; @@ -252,10 +277,9 @@ static void check_alarms(int fd, short ev, void *vp) fcntl(efd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_RENAME); } -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { struct event ev; - sigset_t set; efd = open("/data/alarms", O_DIRECTORY|O_RDONLY); if (efd < 0) diff --git a/alarm/cal.c b/alarm/cal.c index 3eeff79..9ee8903 100644 --- a/alarm/cal.c +++ b/alarm/cal.c @@ -12,15 +12,15 @@ #include #include "listsel.h" +#include "ical-dates.h" struct event { struct event *next; - time_t when, first; - long recur; + time_t when; + struct ical_dates idate; char *mesg; }; - char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; GtkWidget *calblist[42], *month, *date_display, *date_time_display; @@ -69,7 +69,6 @@ int size(struct list_entry *i, int *width, int*height) int render(struct list_entry *i, int selected, GtkWidget *d) { - PangoRectangle ink, log; struct list_entry_text *item = (void*)i; int x; GdkColor col; @@ -104,8 +103,6 @@ int render(struct list_entry *i, int selected, GtkWidget *d) return 0; } - - void set_cal(time_t then); void set_date(GtkButton *button, int num) @@ -132,34 +129,16 @@ void set_time(GtkButton *button, int num) struct tm now; time_t then; char buf[100]; - int hr24, hr12; - char m = 'A'; if (num >= 100) hour = num/100; else minute = num; - hr24 = hour; - if (hour == 24) - hr24 = 0; - hr12 = hour; - if (hr12 > 12) { - hr12 -= 12; - m = 'P'; - } - if (hr12 == 12) - m = 'P' + 'A' - m; - then = chosen_date + hour * 3600 + minute * 60; localtime_r(&then, &now); strftime(buf, sizeof(buf), "%a, %d %B %Y, %H:%M", &now); gtk_label_set_text(GTK_LABEL(date_display), buf); gtk_label_set_text(GTK_LABEL(date_time_display), buf); -#if 0 - sprintf(buf, "%02d:%02dhrs\n%2d:%02d%cM", hr24, minute, - hr12, minute, m); - gtk_label_set_text(GTK_LABEL(time_label), buf); -#endif } GtkWidget *add_button(GtkWidget **blist, char *name, @@ -172,7 +151,7 @@ GtkWidget *add_button(GtkWidget **blist, char *name, gtk_widget_show(*blist); gtk_widget_set_size_request(*blist, -1, 80); } - + l = *blist; b = gtk_button_new_with_label(name); @@ -238,7 +217,11 @@ void events_move(void) return; moving = 1; - freq = active_event->recur; + freq = 0; + if (active_event->idate.rr.unit == Daily) + freq = active_event->idate.rr.step * 24 * 3600; + if (active_event->idate.rr.unit == Weekly) + freq = active_event->idate.rr.step * 7 * 24 * 3600; set_cal(active_event->when); gtk_widget_hide(event_buttons); @@ -364,7 +347,6 @@ void set_daily(void) /********************************************************************/ - void event_free(struct event *ev) { while (ev) { @@ -378,9 +360,15 @@ void event_free(struct event *ev) void update_event(struct event *ev, time_t now) { /* make sure 'when' is in the future if possible */ - ev->when = ev->first; - while (ev->when < now && ev->recur > 0) - ev->when += ev->recur; + struct ical_time inow; + struct ical_timelist rv = {0}; + ical_localtime(&inow, &now); + ical_rr_dates(&ev->idate.start, &ev->idate.rr, &inow, 1, &rv); + if (rv.cnt >= 1) + ev->when = ical_mktime(rv.v); + else + ev->when = ical_mktime(&ev->idate.start); + ical_timelist_free(&rv); } void update_events(struct event *ev, time_t now) @@ -419,7 +407,7 @@ void sort_events(struct event **evtp) */ while (e[0] || e[1]) { if (e[next] == NULL || - (e[1-next] != NULL && + (e[1-next] != NULL && !((prev <= e[1-next]->when) ^(e[1-next]->when <= e[next]->when) ^(e[next]->when <= prev))) @@ -444,32 +432,45 @@ void sort_events(struct event **evtp) struct event *event_parse(char *line) { + /* Space separated ical lines, except that SUMMARY: is the last + * and can hold spaces, and provides the message. + */ struct event *rv; - char *recur, *mesg; - struct tm tm; - long rsec; - recur = strchr(line, ':'); - if (!recur) - return NULL; - *recur++ = 0; - mesg = strchr(recur, ':'); - if (!mesg) - return NULL; - *mesg++ = 0; - line = strptime(line, "%Y-%m-%d-%H-%M-%S", &tm); - if (!line) - return NULL; - rsec = atoi(recur); - if (rsec < 0) - return NULL; + char *mesg = NULL; + struct ical_dates dt = {{0}}; + + while (*line) { + char *w = line; + int l, err; + if (strncmp(line, "SUMMARY:", 8) == 0) + l = strlen(line); + else + l = strcspn(line, " "); + if (line[l]) + line[l++] = 0; + line += l; + + err = ical_parse_dates_line(&dt, w); + if (err == 1) + continue; + if (err == 0) + goto abort; + if (strncmp(w, "SUMMARY:", 8) != 0 || mesg) + goto abort; + mesg = strdup(w+8); + } + if (dt.start.mon == 0 || dt.start.time_set == 0) + goto abort; rv = malloc(sizeof(*rv)); rv->next = NULL; - tm.tm_isdst = -1; - rv->when = mktime(&tm); - rv->first = rv->when; - rv->recur = rsec; - rv->mesg = strdup(mesg); + rv->idate = dt; + rv->when = ical_mktime(&dt.start); + rv->mesg = mesg; return rv; +abort: + free(mesg); + ical_dates_free(&dt); + return NULL; } struct event *event_load_all(char *file) @@ -508,23 +509,32 @@ void event_save_all(char *file, struct event *list) if (*c) *c = '.'; f = fopen(tmp, "w"); + if (!f) { + free(tmp); + return; + } while (list) { struct event *ev = list; - struct tm *tm; char buf[100]; list = ev->next; - tm = localtime(&ev->first); - strftime(buf, sizeof(buf), "%Y-%m-%d-%H-%M-%S", tm); - fprintf(f, "%s:%d:%s\n", buf, ev->recur, ev->mesg); + ical_fmt_time(buf, sizeof(buf), &ev->idate.start); + if (ev->idate.rr.unit == BadInterval) + fprintf(f, "DTSTART:%s SUMMARY:%s\n", buf, ev->mesg); + else { + char buf2[200]; + ical_fmt_rr(buf2, sizeof(buf2), &ev->idate.rr); + fprintf(f, "DTSTART:%s RRULE:%s SUMMARY:%s\n", + buf, buf2, ev->mesg); + } } fflush(f); fsync(fileno(f)); fclose(f); rename(tmp, file); + free(tmp); } - void load_timers(void) { time_t now = time(0); @@ -548,7 +558,6 @@ void load_timers(void) gtk_label_set_text(GTK_LABEL(timers_list), buf); } - struct list_entry *alarms_item(void *list, int n) { struct event *ev; @@ -600,20 +609,22 @@ struct list_entry *alarms_item(void *list, int n) o = '('; c = ')'; } - if (ev->recur == 0) + if (ev->idate.rr.unit == BadInterval) r = ' '; - else if (ev->recur == 3600*24*1) - r = '1'; /* daily */ - else if (ev->recur == 3600*24*2) - r = '2'; /* 2-daily */ - else if (ev->recur == 3600*24*3) - r = '3'; /* 3-daily */ - else if (ev->recur == 3600*24*7) - r = '+'; /* weekly */ - else if (ev->recur == 3600*24*14) - r = '*'; /* fortnightly */ - else - r = '#'; /* other period */ + else if (ev->idate.rr.unit == Daily) { + if (ev->idate.rr.step < 10) + r = '0' + ev->idate.rr.step; + else + r = '#'; + } else if (ev->idate.rr.unit == Weekly) { + if (ev->idate.rr.step == 1) + r = '+'; + else if (ev->idate.rr.step == 2) + r = '*'; + else + r = '#'; + } else + r = '#'; asprintf(&alarm_entries[i].text, "%c%c %s %s%c", o, r, buf, ev->mesg, c); @@ -629,7 +640,6 @@ struct list_entry *alarms_item(void *list, int n) return &alarm_entries[n].head; } - void events_delete(void) { struct event **evp; @@ -670,7 +680,6 @@ void alarms_selected(void *list, int s) { struct event *e; - if (s < 0 || s >= evcnt) return; e = evlist; @@ -693,7 +702,6 @@ struct list_handlers alarms_han = { .selected = alarms_selected, }; - GtkWidget *create_cal_window(void) { GtkWidget *v, *t, *l; @@ -728,7 +736,6 @@ GtkWidget *create_cal_window(void) gtk_widget_show(l); month = l; - l = gtk_button_new_with_label(" >> "); gtk_widget_modify_font(GTK_BIN(l)->child, desc); gtk_button_set_relief(GTK_BUTTON(l), GTK_RELIEF_NONE); @@ -738,7 +745,6 @@ GtkWidget *create_cal_window(void) gtk_widget_show(l); gtk_widget_set(l, "can-focus", 0, NULL); - t = gtk_table_new(7, 7, FALSE); gtk_widget_show(t); @@ -780,7 +786,6 @@ GtkWidget *create_cal_window(void) gtk_container_add(GTK_CONTAINER(v), l); move_event = l; - add_button(&blist, "timer", desc, select_timer); add_button(&blist, "new", desc, events_new); today_btn = add_button(&blist, "today", desc, cal_today); @@ -817,7 +822,7 @@ GtkWidget *create_cal_window(void) void set_cal(time_t then) { - struct tm now, first, today, *tm; + struct tm now, today, *tm; int d, x; time_t today_s; char buf[400]; @@ -837,7 +842,7 @@ void set_cal(time_t then) strftime(buf, sizeof(buf), "%a, %d %B %Y", &now); gtk_label_set_text(GTK_LABEL(date_display), buf); - + /* previous month */ while (tm->tm_mon == now.tm_mon) { then -= 22*3600; @@ -848,7 +853,6 @@ void set_cal(time_t then) then -= 22*3600; tm = localtime(&then); } - first = *tm; if (abs(dlist[0] - then) > 48*3600) { strftime(buf, 40, "%B %Y", &now); @@ -892,7 +896,6 @@ void set_cal(time_t then) g_signal_emit_by_name(alarm_selector->drawing, "configure-event", NULL, alarm_selector); - gtk_widget_show(today_btn); gtk_widget_hide(undelete_btn); } @@ -920,7 +923,6 @@ void center_me(GtkWidget *label, void *xx, int pos) } } - void add_nums(GtkWidget *f, int radius, int start, int end, int step, int div, int scale, char *colour, PangoFontDescription *desc) @@ -953,7 +955,7 @@ void add_nums(GtkWidget *f, int radius, int start, int end, int step, gtk_fixed_put(GTK_FIXED(f), l, x, y); } } - + GtkWidget *create_clock_window(void) { PangoFontDescription *desc; @@ -961,7 +963,7 @@ GtkWidget *create_clock_window(void) GtkWidget *blist = NULL; desc = pango_font_description_new(); - + v = gtk_vbox_new(FALSE, 0); gtk_widget_show(v); @@ -1036,17 +1038,30 @@ void reason_confirm(void) { struct event *ev; GtkTextIter start, finish; + int days; if (!active_event) { ev = malloc(sizeof(*ev)); ev->next = evlist; evlist = ev; + memset(&ev->idate, 0, sizeof(ev->idate)); } else { ev = active_event; + ical_rrule_free(&ev->idate.rr); free(ev->mesg); } - ev->recur = freq; - ev->when = ev->first = chosen_date + hour*3600 + minute*60; + ev->when = chosen_date + hour*3600 + minute*60; + ical_localtime(&ev->idate.start, &ev->when); + days = freq/(24*3600); + ical_parse_rrule(&ev->idate.rr, "", NULL); + + if (days >= 1 && days < 7) { + ev->idate.rr.unit = Daily; + ev->idate.rr.step = days; + } else if (days >= 7) { + ev->idate.rr.unit = Weekly; + ev->idate.rr.step = days/7; + } gtk_text_buffer_get_bounds(reason_buffer, &start, &finish); ev->mesg = gtk_text_buffer_get_text(reason_buffer, &start, &finish, FALSE); @@ -1166,6 +1181,7 @@ int show_time(void *d) tm = localtime(&now); strftime(buf, sizeof(buf), "%H:%M:%S", tm); gtk_label_set_text(GTK_LABEL(time_display), buf); + return 1; } void to_cal(void) @@ -1181,7 +1197,7 @@ void set_timer(void) time_t now = time(0) + delay*60; struct tm *tm = localtime(&now); - strftime(buf, sizeof(buf), "%Y-%m-%d-%H-%M-%S::TIMER\n", tm); + strftime(buf, sizeof(buf), "DTSTART:%Y%m%dT%H%M%S SUMMARY:TIMER\n", tm); if (f) { fputs(buf, f); fclose(f); @@ -1214,7 +1230,7 @@ GtkWidget *create_timer_window(void) gtk_widget_modify_font(l, desc); gtk_widget_show(l); gtk_container_add_with_properties(GTK_CONTAINER(v), l, "expand", 0, NULL); - + l = gtk_label_new(" 99:99:99 "); pango_font_description_set_size(desc, 40 * PANGO_SCALE); gtk_widget_modify_font(l, desc); @@ -1229,7 +1245,6 @@ GtkWidget *create_timer_window(void) gtk_container_add_with_properties(GTK_CONTAINER(v), l, "expand", 1, NULL); timers_list = l; - /* now from the bottom up */ blist = NULL; pango_font_description_set_size(desc, 10 * PANGO_SCALE); @@ -1245,12 +1260,11 @@ GtkWidget *create_timer_window(void) add_button(&blist, "-1m", desc, del_time_1); gtk_box_pack_end(GTK_BOX(v), blist, FALSE, FALSE, 0); - l = gtk_label_new("+1:34 - 99:99 "); pango_font_description_set_size(desc, 15 * PANGO_SCALE); gtk_widget_modify_font(l, desc); gtk_widget_show(l); - + gtk_box_pack_end(GTK_BOX(v), l, FALSE, FALSE, 0); timer_display = l; @@ -1262,9 +1276,9 @@ GtkWidget *create_timer_window(void) gtk_box_pack_end(GTK_BOX(v), blist, FALSE, FALSE, 0); return v; -} +} -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { GtkSettings *set; @@ -1274,7 +1288,6 @@ main(int argc, char *argv[]) set = gtk_settings_get_default(); gtk_settings_set_long_property(set, "gtk-xft-dpi", 151 * PANGO_SCALE, "code"); - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(window), 480, 640); { @@ -1303,7 +1316,6 @@ main(int argc, char *argv[]) gtk_widget_ref(timerw); set_cal(time(0)); - - gtk_main(); + exit(0); } -- 2.43.0