From 55f88f14fed53f67e4b3cd5337cbe92aee0ec638 Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Fri, 17 Apr 1998 19:35:43 +0000 Subject: Large number of updates. Recurrence basically works now in most of its Large number of updates. Recurrence basically works now in most of its forms (daily, weekly, month-by-position). Miguel. svn path=/trunk/; revision=148 --- calendar/cal-util/calobj.c | 212 ++++++++++++++++++++++++++++++++++++++++++--- calendar/cal-util/calobj.h | 18 +++- 2 files changed, 213 insertions(+), 17 deletions(-) (limited to 'calendar/cal-util') diff --git a/calendar/cal-util/calobj.c b/calendar/cal-util/calobj.c index c2fadad4d7..76bb488663 100644 --- a/calendar/cal-util/calobj.c +++ b/calendar/cal-util/calobj.c @@ -12,6 +12,8 @@ #include "timeutil.h" #include "versit/vcc.h" +static void ical_object_compute_end (iCalObject *ico); + iCalObject * ical_object_new (void) { @@ -35,7 +37,6 @@ default_alarm (iCalObject *ical, CalendarAlarm *alarm, char *def_mail, enum Alar alarm->count = 15; alarm->units = ALARM_MINUTES; } else { - printf ("uno!\n"); alarm->count = 1; alarm->units = ALARM_DAYS; } @@ -140,7 +141,7 @@ static void ignore_space(char **str) { while (**str && isspace (**str)) - str++; + (*str)++; } static void @@ -183,6 +184,12 @@ weekdaylist (iCalObject *o, char **str) } } } while (isalpha (**str)); + + if (o->recur->weekday == 0){ + struct tm *tm = localtime (&o->dtstart); + + o->recur->weekday = 1 << tm->tm_wday; + } } static void @@ -223,11 +230,11 @@ daynumber (iCalObject *o, char **str) while (**str && isdigit (**str)){ val = val * 10 + (**str - '0'); - str++; + (*str)++; } if (**str == '+') - str++; + (*str)++; if (**str == '-') val *= -1; @@ -245,8 +252,10 @@ daynumberlist (iCalObject *o, char **str) while (**str){ if (!isdigit (**str)) return; - while (**str && isdigit (**str)) + while (**str && isdigit (**str)){ val = 10 * val + (**str - '0'); + (*str)++; + } if (!first){ o->recur->u.month_day = val; first = 1; @@ -300,10 +309,12 @@ duration (iCalObject *o, char **str) ignore_space (str); if (**str != '#') return; - while (**str && isdigit (**str)) + (*str)++; + while (**str && isdigit (**str)){ duration = duration * 10 + (**str - '0'); - - o->recur->temp_duration = duration; + (*str)++; + } + o->recur->duration = duration; } static void @@ -311,7 +322,7 @@ enddate (iCalObject *o, char **str) { ignore_space (str); if (isdigit (**str)){ - o->recur->enddate = time_from_isodate (*str); + o->recur->_enddate = time_from_isodate (*str); *str += 16; } } @@ -335,7 +346,7 @@ load_recurrence (iCalObject *o, char *str) case 'M': if (*str == 'P') type = RECUR_MONTHLY_BY_POS; - else if (*str == 'D') + else if (*str == 'D') type = RECUR_MONTHLY_BY_DAY; str++; break; @@ -356,13 +367,18 @@ load_recurrence (iCalObject *o, char *str) ignore_space (&str); /* Get the interval */ - while (*str && isdigit (*str)) + for (;*str && isdigit (*str);str++) interval = interval * 10 + (*str-'0'); o->recur->interval = interval; + + /* this is the default per the spec */ + o->recur->duration = 2; ignore_space (&str); switch (type){ + case RECUR_DAILY: + break; case RECUR_WEEKLY: load_recur_weekly (o, &str); break; @@ -385,6 +401,17 @@ load_recurrence (iCalObject *o, char *str) duration (o, &str); enddate (o, &str); + /* Compute the enddate */ + if (o->recur->_enddate == 0){ + printf ("ENDDATE es 0, d=%d\n", o->recur->duration); + if (o->recur->duration != 0){ + ical_object_compute_end (o); + } else + o->recur->enddate = 0; + } else { + printf ("El evento termina\n"); + o->recur->enddate = o->recur->_enddate; + } return 1; } @@ -689,14 +716,173 @@ ical_foreach (GList *events, calendarfn fn, void *closure) } } +static int +generate (iCalObject *ico, time_t reference, calendarfn cb, void *closure) +{ + struct tm dt_start, dt_end, ref; + time_t s_t, e_t; + + dt_start = *localtime (&ico->dtstart); + dt_end = *localtime (&ico->dtend); + ref = *localtime (&reference); + + dt_start.tm_mday = ref.tm_mday; + dt_start.tm_mon = ref.tm_mon; + dt_start.tm_year = ref.tm_year; + + dt_end.tm_mday = ref.tm_mday; + dt_end.tm_mon = ref.tm_mon; + dt_end.tm_year = ref.tm_year; + + s_t = mktime (&dt_start); + e_t = mktime (&dt_end); + if (s_t == -1 || e_t == -1){ + g_warning ("Produced invalid dates!\n"); + return 0; + } + return (*cb)(ico, s_t, e_t, closure); +} + +#define time_in_range(x,a,b) ((x >= a) && (b ? x <= b : 1)) + +/* + * Generate every possible event. Invokes the callback routine for + * every occurrence of the event in the [START, END] time interval. + * + * If END is zero, the event is generated forever. + * The callback routine is expected to return 0 when no further event + * generation is requested. + */ void ical_object_generate_events (iCalObject *ico, time_t start, time_t end, calendarfn cb, void *closure) { + Recurrence *recur = ico->recur; + time_t current; + if (!ico->recur){ - if ((start <= ico->dtstart) && (ico->dtend <= end)) - (*cb)(ico, ico->dtstart, ico->dtend, closure); + if (time_in_range (ico->dtstart, start, end) || + time_in_range (ico->dtend, start, end)){ + time_t ev_s, ev_e; + + ev_s = ico->dtstart < start ? start : ico->dtstart; + ev_e = ico->dtend > end ? end : ico->dtend; + (*cb)(ico, ev_s, ev_e, closure); + } return; } /* The event has a recurrence rule */ + if (end != 0){ + if (ico->dtstart > end) + return; + if (!IS_INFINITE (ico->recur) && recur->enddate < start) + return; + } + + current = ico->dtstart; + switch (recur->type){ + case RECUR_DAILY: + do { + if (time_in_range (current, start, end)){ + if (!generate (ico, current, cb, closure)) + return; + } + + /* Advance */ + current = time_add_day (current, recur->interval); + + if (current == -1){ + g_warning ("RECUR_DAILY: mktime error\n"); + return; + } + } while (current < end || (end == 0)); + break; + + case RECUR_WEEKLY: + do { + struct tm *tm = localtime (¤t); + + if (time_in_range (current, start, end)){ + if (recur->weekday & (1 << tm->tm_wday)) + if (!generate (ico, current, cb, closure)) + return; + } + + /* Advance by day for scanning the week or by interval at week end */ + if (tm->tm_wday == 6) + current = time_add_day (current, recur->interval); + else + current = time_add_day (current, 1); + + if (current == -1){ + g_warning ("RECUR_WEEKLY: mktime error\n"); + return; + } + } while (current < end || (end == 0)); + break; + + case RECUR_MONTHLY_BY_POS: + g_warning ("We still do not handle MONTHLY_BY_POS\n"); + break; + + case RECUR_MONTHLY_BY_DAY: + do { + struct tm *tm = localtime (¤t); + time_t t; + int p; + + p = tm->tm_mday; + tm->tm_mday = recur->u.month_day; + t = mktime (tm); + if (time_in_range (t, start, end)) + if (!generate (ico, t, cb, closure)) + return; + + /* Advance a month */ + tm->tm_mday = p; + tm->tm_mon += recur->interval; + current = mktime (tm); + if (current == -1){ + g_warning ("RECUR_MONTHLY_BY_DAY: mktime error\n"); + return; + } + } while (current < end || (end == 0)); + + case RECUR_YEARLY_BY_MONTH: + case RECUR_YEARLY_BY_DAY: + do { + if (time_in_range (current, start, end)) + if (!generate (ico, current, cb, closure)) + return; + + /* Advance */ + current = time_add_year (current, recur->interval); + } while (current < end || (end == 0)); + } +} + +static int +duration_callback (iCalObject *ico, time_t start, time_t end, void *closure) +{ + int *count = closure; + + (*count)++; + if (ico->recur->duration == *count){ + ico->recur->enddate = end; + return 0; + } + return 1; } + +/* Computes ico->recur->enddate from ico->recur->duration */ +void +ical_object_compute_end (iCalObject *ico) +{ + int count = 0; + + g_return_if_fail (ico->recur != NULL); + + ical_object_generate_events (ico, ico->dtstart, 0, duration_callback, &count); +} + + diff --git a/calendar/cal-util/calobj.h b/calendar/cal-util/calobj.h index ab9d061956..8cbdffa484 100644 --- a/calendar/cal-util/calobj.h +++ b/calendar/cal-util/calobj.h @@ -86,16 +86,26 @@ typedef struct { enum RecurType type; int interval; - time_t enddate; + + /* Used for recur computation */ + time_t enddate; /* If the value is zero, it is an infinite event + * otherwise, it is either the _enddate value (if + * this is what got specified) or it is our computed + * ending date (computed from the duration item). + */ + int weekday; union { int month_pos; int month_day; } u; - - int temp_duration; /* Used temporarly, we compute enddate */ + + int duration; + time_t _enddate; /* As found on the vCalendar file */ + int __count; } Recurrence; +#define IS_INFINITE(r) (r->duration == 0) /* Flags to indicate what has changed in an object */ typedef enum { @@ -157,7 +167,7 @@ typedef struct { } iCalObject; /* The callback for the recurrence generator */ -typedef void (*calendarfn)(iCalObject *, time_t, time_t, void *); +typedef int (*calendarfn)(iCalObject *, time_t, time_t, void *); iCalObject *ical_new (char *comment, char *organizer, char *summary); iCalObject *ical_object_new (void); -- cgit v1.2.3