]> git.neil.brown.name Git - plato.git/commitdiff
cal / alarm: convert to use ical date info.
authorNeilBrown <neilb@suse.de>
Wed, 1 Jan 2014 00:43:17 +0000 (11:43 +1100)
committerNeilBrown <neilb@suse.de>
Wed, 1 Jan 2014 00:43:17 +0000 (11:43 +1100)
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
alarm/cal.c

index ea90c0143592975f0a44531461297335104f0a1d..3f4cbefd4019b90fdfcd208bc9c6985ac2914433 100644 (file)
 #include <time.h>
 #include <string.h>
 #include <stdio.h>
+#include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <linux/rtc.h>
 #include <sys/dir.h>
 #include <event.h>
 #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)
index 3eeff79b2383b5501743d2ad028c003c1c17ae43..9ee8903f67efb6e2a87a1ccbc943065740a6d4e2 100644 (file)
 #include <gtk/gtk.h>
 
 #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);
 }