#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;
};
while (ev) {
struct alarm_ev *n = ev->next;
free(ev->mesg);
+ ical_dates_free(&ev->idate);
free(ev);
ev = n;
}
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)
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;
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)
#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;
int render(struct list_entry *i, int selected, GtkWidget *d)
{
- PangoRectangle ink, log;
struct list_entry_text *item = (void*)i;
int x;
GdkColor col;
return 0;
}
-
-
void set_cal(time_t then);
void set_date(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,
gtk_widget_show(*blist);
gtk_widget_set_size_request(*blist, -1, 80);
}
-
+
l = *blist;
b = gtk_button_new_with_label(name);
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);
/********************************************************************/
-
void event_free(struct event *ev)
{
while (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)
*/
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)))
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)
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);
gtk_label_set_text(GTK_LABEL(timers_list), buf);
}
-
struct list_entry *alarms_item(void *list, int n)
{
struct event *ev;
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);
return &alarm_entries[n].head;
}
-
void events_delete(void)
{
struct event **evp;
{
struct event *e;
-
if (s < 0 || s >= evcnt)
return;
e = evlist;
.selected = alarms_selected,
};
-
GtkWidget *create_cal_window(void)
{
GtkWidget *v, *t, *l;
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);
gtk_widget_show(l);
gtk_widget_set(l, "can-focus", 0, NULL);
-
t = gtk_table_new(7, 7, FALSE);
gtk_widget_show(t);
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);
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];
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;
then -= 22*3600;
tm = localtime(&then);
}
- first = *tm;
if (abs(dlist[0] - then) > 48*3600) {
strftime(buf, 40, "%B %Y", &now);
g_signal_emit_by_name(alarm_selector->drawing, "configure-event",
NULL, alarm_selector);
-
gtk_widget_show(today_btn);
gtk_widget_hide(undelete_btn);
}
}
}
-
void add_nums(GtkWidget *f, int radius, int start, int end, int step,
int div, int scale,
char *colour, PangoFontDescription *desc)
gtk_fixed_put(GTK_FIXED(f), l, x, y);
}
}
-
+
GtkWidget *create_clock_window(void)
{
PangoFontDescription *desc;
GtkWidget *blist = NULL;
desc = pango_font_description_new();
-
+
v = gtk_vbox_new(FALSE, 0);
gtk_widget_show(v);
{
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);
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)
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);
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);
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);
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;
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;
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);
{
gtk_widget_ref(timerw);
set_cal(time(0));
-
-
gtk_main();
+ exit(0);
}