From fb1cdc02878ea1c6a37671fc326145f8a20ded81 Mon Sep 17 00:00:00 2001 From: Damon Chaplin Date: Sun, 24 Sep 2000 16:22:07 +0000 Subject: set the height of the scrolled window for the description field, since the 2000-09-24 Damon Chaplin * gui/dialogs/task-editor-dialog.glade: set the height of the scrolled window for the description field, since the default window height doesn't seem to be working. * cal-util/cal-component.h: added functions to get the actual icalproperty lists for RRULE and EXRULE properties. * cal-util/cal-recur.[hc]: added support for COUNT, though I need to test it a bit. Also fixed the call to generate_instances_for_year() so it uses the chunk dates. 2000-09-20 Damon Chaplin * gui/event-editor.c: got rid of 1 '_' in '__Formatting'. svn path=/trunk/; revision=5562 --- calendar/cal-util/cal-component.c | 46 ++++ calendar/cal-util/cal-component.h | 2 + calendar/cal-util/cal-recur.c | 536 ++++++++++++++++++++++++++++---------- calendar/cal-util/cal-recur.h | 21 +- 4 files changed, 453 insertions(+), 152 deletions(-) (limited to 'calendar/cal-util') diff --git a/calendar/cal-util/cal-component.c b/calendar/cal-util/cal-component.c index 4ddec62159..cf7e3f358a 100644 --- a/calendar/cal-util/cal-component.c +++ b/calendar/cal-util/cal-component.c @@ -2192,6 +2192,29 @@ cal_component_get_exrule_list (CalComponent *comp, GSList **recur_list) get_recur_list (priv->exrule_list, icalproperty_get_exrule, recur_list); } +/** + * cal_component_get_exrule_property_list: + * @comp: A calendar component object. + * @recur_list: Returns a list of exception rule properties. + * + * Returns a list of exception rule properties of a calendar component + * object. + **/ +void +cal_component_get_exrule_property_list (CalComponent *comp, GSList **recur_list) +{ + CalComponentPrivate *priv; + + g_return_if_fail (comp != NULL); + g_return_if_fail (IS_CAL_COMPONENT (comp)); + g_return_if_fail (recur_list != NULL); + + priv = comp->priv; + g_return_if_fail (priv->icalcomp != NULL); + + *recur_list = priv->exrule_list; +} + /** * cal_component_set_exrule_list: * @comp: A calendar component object. @@ -2590,6 +2613,29 @@ cal_component_get_rrule_list (CalComponent *comp, GSList **recur_list) get_recur_list (priv->rrule_list, icalproperty_get_rrule, recur_list); } +/** + * cal_component_get_rrule_property_list: + * @comp: A calendar component object. + * @recur_list: Returns a list of recurrence rule properties. + * + * Returns a list of recurrence rule properties of a calendar component + * object. + **/ +void +cal_component_get_rrule_property_list (CalComponent *comp, GSList **recur_list) +{ + CalComponentPrivate *priv; + + g_return_if_fail (comp != NULL); + g_return_if_fail (IS_CAL_COMPONENT (comp)); + g_return_if_fail (recur_list != NULL); + + priv = comp->priv; + g_return_if_fail (priv->icalcomp != NULL); + + *recur_list = priv->rrule_list; +} + /** * cal_component_set_rrule_list: * @comp: A calendar component object. diff --git a/calendar/cal-util/cal-component.h b/calendar/cal-util/cal-component.h index 253d7b411f..749f268fcd 100644 --- a/calendar/cal-util/cal-component.h +++ b/calendar/cal-util/cal-component.h @@ -203,6 +203,7 @@ void cal_component_set_exdate_list (CalComponent *comp, GSList *exdate_list); gboolean cal_component_has_exdates (CalComponent *comp); void cal_component_get_exrule_list (CalComponent *comp, GSList **recur_list); +void cal_component_get_exrule_property_list (CalComponent *comp, GSList **recur_list); void cal_component_set_exrule_list (CalComponent *comp, GSList *recur_list); gboolean cal_component_has_exrules (CalComponent *comp); @@ -225,6 +226,7 @@ void cal_component_set_rdate_list (CalComponent *comp, GSList *period_list); gboolean cal_component_has_rdates (CalComponent *comp); void cal_component_get_rrule_list (CalComponent *comp, GSList **recur_list); +void cal_component_get_rrule_property_list (CalComponent *comp, GSList **recur_list); void cal_component_set_rrule_list (CalComponent *comp, GSList *recur_list); gboolean cal_component_has_rrules (CalComponent *comp); diff --git a/calendar/cal-util/cal-recur.c b/calendar/cal-util/cal-recur.c index fe8ec8d682..38394d2bfb 100644 --- a/calendar/cal-util/cal-recur.c +++ b/calendar/cal-util/cal-recur.c @@ -117,7 +117,8 @@ struct _RecurData { guint8 seconds[61]; }; - +/* The paramter we use to store the enddate in RRULE and EXRULE properties. */ +#define EVOLUTION_END_DATE_PARAMETER "X-EVOLUTION-ENDDATE" typedef gboolean (*CalObjFindStartFn) (CalObjTime *event_start, CalObjTime *event_end, @@ -159,6 +160,19 @@ typedef enum { CALOBJ_SECOND } CalObjTimeComparison; +static void cal_recur_generate_instances_of_rule (CalComponent *comp, + icalproperty *prop, + time_t start, + time_t end, + CalRecurInstanceFn cb, + gpointer cb_data); + +static CalRecurrence * cal_recur_from_icalproperty (icalproperty *prop, + gboolean exception); +static gint cal_recur_ical_weekday_to_weekday (enum icalrecurrencetype_weekday day); +static void cal_recur_free (CalRecurrence *r); + + static void cal_object_compute_duration (CalObjTime *start, CalObjTime *end, gint *days, @@ -196,7 +210,7 @@ static GArray* cal_obj_generate_set_default (RecurData *recur_data, CalObjTime *occ); -static CalRecurVTable* cal_obj_get_vtable (CalRecurType recur_type); +static CalRecurVTable* cal_obj_get_vtable (icalrecurrencetype_frequency recur_type); static void cal_obj_initialize_recur_data (RecurData *recur_data, CalRecurrence *recur, CalObjTime *event_start); @@ -353,6 +367,24 @@ static gint cal_obj_date_only_compare_func (const void *arg1, const void *arg2); + +static gboolean cal_recur_ensure_end_dates (CalComponent *comp, + gboolean refresh); +static gboolean cal_recur_ensure_rule_end_date (CalComponent *comp, + icalproperty *prop, + gboolean exception, + gboolean refresh); +static gboolean cal_recur_ensure_rule_end_date_cb (CalComponent *comp, + time_t instance_start, + time_t instance_end, + gpointer data); +static time_t cal_recur_get_rule_end_date (icalproperty *prop); +static void cal_recur_set_rule_end_date (icalproperty *prop, + time_t end_date); + + + + CalRecurVTable cal_obj_yearly_vtable = { cal_obj_yearly_find_start_position, cal_obj_yearly_find_next_position, @@ -463,10 +495,39 @@ cal_recur_generate_instances (CalComponent *comp, time_t end, CalRecurInstanceFn cb, gpointer cb_data) +{ + cal_recur_generate_instances_of_rule (comp, NULL, start, end, + cb, cb_data); +} + + +/* + * Calls the given callback function for each occurrence of the given + * recurrence rule between the given start and end times. If the rule is NULL + * it uses all the rules from the component. + * If end is 0 it continues until the event ends or forever if the event has + * an infinite recurrence rule. + * If the callback routine return 0 the occurrence generation stops. + * + * The use of the specific rule is for determining the end of a rule when + * COUNT is set. The callback will count instances and store the enddata + * when COUNT is reached. + * + * Both start and end can be -1, in which case we start at the events first + * instance and continue until it ends, or forever if it has no enddate. + */ +void +cal_recur_generate_instances_of_rule (CalComponent *comp, + icalproperty *prop, + time_t start, + time_t end, + CalRecurInstanceFn cb, + gpointer cb_data) { CalComponentDateTime dtstart, dtend; time_t dtstart_time, dtend_time; - GSList *rrules, *rdates, *exrules, *exdates; + GSList *rrules = NULL, *rdates = NULL, elem; + GSList *exrules = NULL, *exdates = NULL; CalObjTime interval_start, interval_end, event_start, event_end; CalObjTime chunk_start, chunk_end; gint days, seconds, year; @@ -486,6 +547,10 @@ cal_recur_generate_instances (CalComponent *comp, } dtstart_time = icaltime_as_timet (*dtstart.value); + if (start == -1) + start = dtstart_time; + + /* FIXME: DURATION could be used instead, couldn't it? - Damon */ if (dtend.value) dtend_time = icaltime_as_timet (*dtend.value); else @@ -495,23 +560,34 @@ cal_recur_generate_instances (CalComponent *comp, intersects the given interval. */ if (!(cal_component_has_recurrences (comp) || cal_component_has_exceptions (comp))) { - if ((end && dtstart_time < end && dtend_time > start) - || (end == 0 && dtend_time > start)) { + if ((end == -1 || dtstart_time < end) && dtend_time > start) { (* cb) (comp, dtstart_time, dtend_time, cb_data); } goto out; } - /* Get the recurrence rules */ - cal_component_get_rrule_list (comp, &rrules); - cal_component_get_rdate_list (comp, &rdates); - cal_component_get_exrule_list (comp, &exrules); - cal_component_get_exdate_list (comp, &exdates); + /* If a specific recurrence rule is being used, set up a simple list, + else get the recurrence rules from the component. */ + if (prop) { + elem.data = prop; + elem.next = NULL; + rrules = &elem; + } else { + /* Make sure all the enddates for the rules are set. */ + cal_recur_ensure_end_dates (comp, FALSE); + + cal_component_get_rrule_property_list (comp, &rrules); + cal_component_get_rdate_list (comp, &rdates); + cal_component_get_exrule_property_list (comp, &exrules); + cal_component_get_exdate_list (comp, &exdates); + } - /* Convert the interval start & end to CalObjTime. */ + /* Convert the interval start & end to CalObjTime. Note that if end + is -1 interval_end won't be set, so don't use it! */ cal_object_time_from_time (&interval_start, start); - cal_object_time_from_time (&interval_end, end); + if (end != -1) + cal_object_time_from_time (&interval_end, end); cal_object_time_from_time (&event_start, dtstart_time); cal_object_time_from_time (&event_end, dtend_time); @@ -526,10 +602,13 @@ cal_recur_generate_instances (CalComponent *comp, /* Expand the recurrence for each year between start & end, or until the callback returns 0 if end is 0. */ - for (year = interval_start.year; year <= interval_end.year; year++) { + for (year = interval_start.year; + end == -1 || year <= interval_end.year; + year++) { chunk_start = interval_start; chunk_start.year = year; - chunk_end = interval_end; + if (end != -1) + chunk_end = interval_end; chunk_end.year = year; if (year != interval_start.year) { @@ -539,7 +618,7 @@ cal_recur_generate_instances (CalComponent *comp, chunk_start.minute = 0; chunk_start.second = 0; } - if (year != interval_end.year) { + if (end == -1 || year != interval_end.year) { chunk_end.year++; chunk_end.month = 0; chunk_end.day = 0; @@ -552,18 +631,17 @@ cal_recur_generate_instances (CalComponent *comp, rrules, rdates, exrules, exdates, &event_start, - &interval_start, - &interval_end, + &chunk_start, &chunk_end, start, end, days, seconds, cb, cb_data)) break; } - cal_component_free_recur_list (rrules); - cal_component_free_period_list (rdates); - cal_component_free_recur_list (exrules); - cal_component_free_exdate_list (exdates); + if (!prop) { + cal_component_free_period_list (rdates); + cal_component_free_exdate_list (exdates); + } out: cal_component_free_datetime (&dtstart); @@ -587,140 +665,135 @@ array_to_list (short *array, int max_elements) } /** - * cal_recur_from_icalrecurrencetype: - * @ir: A struct #icalrecurrencetype. + * cal_recur_from_icalproperty: + * @ir: An RRULE or EXRULE #icalproperty. * - * Converts a struct #icalrecurrencetype to a #CalRecurrence. This should be + * Converts an #icalproperty to a #CalRecurrence. This should be * freed using the cal_recur_free() function. * * Return value: #CalRecurrence structure. **/ -CalRecurrence * -cal_recur_from_icalrecurrencetype (struct icalrecurrencetype *ir) +static CalRecurrence * +cal_recur_from_icalproperty (icalproperty *prop, gboolean exception) { + struct icalrecurrencetype ir; CalRecurrence *r; + gint max_elements, i; - g_return_val_if_fail (ir != NULL, NULL); + g_return_val_if_fail (prop != NULL, NULL); r = g_new (CalRecurrence, 1); - switch (ir->freq) { - case ICAL_SECONDLY_RECURRENCE: - r->type = CAL_RECUR_SECONDLY; - break; + if (exception) + ir = icalproperty_get_exrule (prop); + else + ir = icalproperty_get_rrule (prop); - case ICAL_MINUTELY_RECURRENCE: - r->type = CAL_RECUR_MINUTELY; - break; + r->freq = ir.freq; + r->interval = ir.interval; - case ICAL_HOURLY_RECURRENCE: - r->type = CAL_RECUR_HOURLY; - break; + if (ir.count != 0) { + r->enddate = cal_recur_get_rule_end_date (prop); + } else { + /* FIXME: Does this work for never-ending events? */ + r->enddate = icaltime_as_timet (ir.until); + if (r->enddate == (time_t)-1) + r->enddate = 0; + } - case ICAL_DAILY_RECURRENCE: - r->type = CAL_RECUR_DAILY; - break; + r->week_start_day = cal_recur_ical_weekday_to_weekday (ir.week_start); - case ICAL_WEEKLY_RECURRENCE: - r->type = CAL_RECUR_WEEKLY; - break; + r->bymonth = array_to_list (ir.by_month, + sizeof (ir.by_month) / sizeof (ir.by_month[0])); - case ICAL_MONTHLY_RECURRENCE: - r->type = CAL_RECUR_MONTHLY; - break; + r->byweekno = array_to_list (ir.by_week_no, + sizeof (ir.by_week_no) / sizeof (ir.by_week_no[0])); - case ICAL_YEARLY_RECURRENCE: - r->type = CAL_RECUR_YEARLY; - break; + r->byyearday = array_to_list (ir.by_year_day, + sizeof (ir.by_year_day) / sizeof (ir.by_year_day[0])); - default: - g_message ("cal_recur_from_icalrecurrencetype(): Unknown recurrence frequency %d", - (int) ir->freq); - g_free (r); - return NULL; + r->bymonthday = array_to_list (ir.by_month_day, + sizeof (ir.by_month_day) / sizeof (ir.by_month_day[0])); + + /* FIXME: libical only supports 8 values, out of possible 107 * 7. */ + r->byday = NULL; + max_elements = sizeof (ir.by_day) / sizeof (ir.by_day[0]); + for (i = 0; i < max_elements && ir.by_day[i] != ICAL_RECURRENCE_ARRAY_MAX; i++) { + enum icalrecurrencetype_weekday day; + gint weeknum, weekday; + + day = icalrecurrencetype_day_day_of_week (ir.by_day[i]); + weeknum = icalrecurrencetype_day_position (ir.by_day[i]); + + weekday = cal_recur_ical_weekday_to_weekday (day); + + r->byday = g_list_prepend (r->byday, + GINT_TO_POINTER (weeknum)); + r->byday = g_list_prepend (r->byday, + GINT_TO_POINTER (weekday)); } - r->interval = ir->interval; + r->byhour = array_to_list (ir.by_hour, + sizeof (ir.by_hour) / sizeof (ir.by_hour[0])); + + r->byminute = array_to_list (ir.by_minute, + sizeof (ir.by_minute) / sizeof (ir.by_minute[0])); + + r->bysecond = array_to_list (ir.by_second, + sizeof (ir.by_second) / sizeof (ir.by_second[0])); + + r->bysetpos = array_to_list (ir.by_set_pos, + sizeof (ir.by_set_pos) / sizeof (ir.by_set_pos[0])); + + return r; +} + - /* FIXME: we don't deal with ir->count. Also, how does libical - * distinguish between n-occurrences and until-some-date rules? - */ - r->enddate = icaltime_as_timet (ir->until); - if (r->enddate == (time_t)-1) - r->enddate = 0; +static gint +cal_recur_ical_weekday_to_weekday (enum icalrecurrencetype_weekday day) +{ + gint weekday; - switch (ir->week_start) { + switch (day) { + case ICAL_NO_WEEKDAY: /* Monday is the default in RFC2445. */ case ICAL_MONDAY_WEEKDAY: - r->week_start_day = 0; + weekday = 0; break; - case ICAL_TUESDAY_WEEKDAY: - r->week_start_day = 1; + weekday = 1; break; - case ICAL_WEDNESDAY_WEEKDAY: - r->week_start_day = 2; + weekday = 2; break; - case ICAL_THURSDAY_WEEKDAY: - r->week_start_day = 3; + weekday = 3; break; - case ICAL_FRIDAY_WEEKDAY: - r->week_start_day = 4; + weekday = 4; break; - case ICAL_SATURDAY_WEEKDAY: - r->week_start_day = 5; + weekday = 5; break; - case ICAL_SUNDAY_WEEKDAY: - r->week_start_day = 6; + weekday = 6; break; - default: - g_message ("cal_recur_from_icalrecurrencetype(): Unknown week day %d", - ir->week_start); - g_free (r); - return NULL; + g_warning ("cal_recur_ical_weekday_to_weekday(): Unknown week day %d", + day); + weekday = 0; } - r->bymonth = array_to_list (ir->by_month, - sizeof (ir->by_month) / sizeof (ir->by_month[0])); - - r->byweekno = array_to_list (ir->by_week_no, - sizeof (ir->by_week_no) / sizeof (ir->by_week_no[0])); - - r->byyearday = array_to_list (ir->by_year_day, - sizeof (ir->by_year_day) / sizeof (ir->by_year_day[0])); - - r->bymonthday = array_to_list (ir->by_month_day, - sizeof (ir->by_month_day) / sizeof (ir->by_month_day[0])); - - r->byday = NULL; /* FIXME: libical sucks in this respect */ - - r->byhour = array_to_list (ir->by_hour, - sizeof (ir->by_hour) / sizeof (ir->by_hour[0])); - - r->byminute = array_to_list (ir->by_minute, - sizeof (ir->by_minute) / sizeof (ir->by_minute[0])); - - r->bysecond = array_to_list (ir->by_second, - sizeof (ir->by_second) / sizeof (ir->by_second[0])); - - r->bysetpos = array_to_list (ir->by_set_pos, - sizeof (ir->by_set_pos) / sizeof (ir->by_set_pos[0])); - - return r; + return weekday; } + /** * cal_recur_free: * @r: A #CalRecurrence structure. * * Frees a #CalRecurrence structure. **/ -void +static void cal_recur_free (CalRecurrence *r) { g_return_if_fail (r != NULL); @@ -771,11 +844,11 @@ generate_instances_for_year (CalComponent *comp, /* Expand each of the recurrence rules. */ for (elem = rrules; elem; elem = elem->next) { - struct icalrecurrencetype *ir; + icalproperty *prop; CalRecurrence *r; - ir = elem->data; - r = cal_recur_from_icalrecurrencetype (ir); + prop = elem->data; + r = cal_recur_from_icalproperty (prop, FALSE); tmp_occs = cal_obj_expand_recurrence (event_start, r, interval_start, @@ -791,7 +864,11 @@ generate_instances_for_year (CalComponent *comp, struct icaltimetype *it; time_t t; - /* FIXME we should only be dealing with dates, not times too */ + /* FIXME we should only be dealing with dates, not times too. + + No, I think it is supposed to be dates & times - Damon. + I'm not sure what the semantics of just a date would be, + since the event could recur several times each day. */ it = elem->data; t = icaltime_as_timet (*it); cal_object_time_from_time (&cotime, t); @@ -813,11 +890,11 @@ generate_instances_for_year (CalComponent *comp, /* Expand each of the exception rules. */ for (elem = exrules; elem; elem = elem->next) { - struct icalrecurrencetype *ir; + icalproperty *prop; CalRecurrence *r; - ir = elem->data; - r = cal_recur_from_icalrecurrencetype (ir); + prop = elem->data; + r = cal_recur_from_icalproperty (prop, FALSE); tmp_occs = cal_obj_expand_recurrence (event_start, r, interval_start, @@ -833,7 +910,11 @@ generate_instances_for_year (CalComponent *comp, struct icaltimetype *it; time_t t; - /* FIXME we should only be dealing with dates, not times too */ + /* FIXME we should only be dealing with dates, not times too. + + No, I think it is supposed to be dates & times - Damon. + I'm not sure what the semantics of just a date would be, + since the event could recur several times each day. */ it = elem->data; t = icaltime_as_timet (*it); cal_object_time_from_time (&cotime, t); @@ -940,11 +1021,13 @@ cal_obj_expand_recurrence (CalObjTime *event_start, GArray *all_occs, *occs; gint len; - vtable = cal_obj_get_vtable (recur->type); - /* This is the resulting array of CalObjTime elements. */ all_occs = g_array_new (FALSE, FALSE, sizeof (CalObjTime)); + vtable = cal_obj_get_vtable (recur->freq); + if (!vtable) + return all_occs; + /* Calculate some useful data such as some fast lookup tables. */ cal_obj_initialize_recur_data (&recur_data, recur, event_start); @@ -967,12 +1050,12 @@ cal_obj_expand_recurrence (CalObjTime *event_start, interval. */ for (;;) { /* Generate the set of occurrences for this period. */ - switch (recur->type) { - case CAL_RECUR_YEARLY: + switch (recur->freq) { + case ICAL_YEARLY_RECURRENCE: occs = cal_obj_generate_set_yearly (&recur_data, vtable, &occ); break; - case CAL_RECUR_MONTHLY: + case ICAL_MONTHLY_RECURRENCE: occs = cal_obj_generate_set_monthly (&recur_data, vtable, &occ); break; @@ -1213,26 +1296,38 @@ cal_obj_generate_set_default (RecurData *recur_data, /* Returns the function table corresponding to the recurrence frequency. */ -static CalRecurVTable* -cal_obj_get_vtable (CalRecurType recur_type) +static CalRecurVTable* cal_obj_get_vtable (icalrecurrencetype_frequency recur_type) { + CalRecurVTable* vtable; + switch (recur_type) { - case CAL_RECUR_YEARLY: - return &cal_obj_yearly_vtable; - case CAL_RECUR_MONTHLY: - return &cal_obj_monthly_vtable; - case CAL_RECUR_WEEKLY: - return &cal_obj_weekly_vtable; - case CAL_RECUR_DAILY: - return &cal_obj_daily_vtable; - case CAL_RECUR_HOURLY: - return &cal_obj_hourly_vtable; - case CAL_RECUR_MINUTELY: - return &cal_obj_minutely_vtable; - case CAL_RECUR_SECONDLY: - return &cal_obj_secondly_vtable; + case ICAL_YEARLY_RECURRENCE: + vtable = &cal_obj_yearly_vtable; + break; + case ICAL_MONTHLY_RECURRENCE: + vtable = &cal_obj_monthly_vtable; + break; + case ICAL_WEEKLY_RECURRENCE: + vtable = &cal_obj_weekly_vtable; + break; + case ICAL_DAILY_RECURRENCE: + vtable = &cal_obj_daily_vtable; + break; + case ICAL_HOURLY_RECURRENCE: + vtable = &cal_obj_hourly_vtable; + break; + case ICAL_MINUTELY_RECURRENCE: + vtable = &cal_obj_minutely_vtable; + break; + case ICAL_SECONDLY_RECURRENCE: + vtable = &cal_obj_secondly_vtable; + break; + default: + g_warning ("Unknown recurrence frequenct"); + vtable = NULL; } - return NULL; + + return vtable; } @@ -3095,3 +3190,168 @@ cal_object_time_from_time (CalObjTime *cotime, cotime->minute = tmp_tm->tm_min; cotime->second = tmp_tm->tm_sec; } + + +/* This recalculates the end dates for recurrence & exception rules which use + the COUNT property. If refresh is TRUE it will recalculate all enddates + for rules which use COUNT. If refresh is FALSE, it will only calculate + the enddate if it hasn't already been set. It returns TRUE if the component + was changed, i.e. if the component should be saved at some point. + We store the enddate in the "X-EVOLUTION-ENDDATE" parameter of the RRULE + or EXRULE. */ +static gboolean +cal_recur_ensure_end_dates (CalComponent *comp, + gboolean refresh) +{ + GSList *rrules, *exrules, *elem; + gboolean changed = FALSE; + + /* Do the RRULEs. */ + cal_component_get_rrule_property_list (comp, &rrules); + for (elem = rrules; elem; elem = elem->next) { + changed |= cal_recur_ensure_rule_end_date (comp, elem->data, + FALSE, refresh); + } + + /* Do the EXRULEs. */ + cal_component_get_exrule_property_list (comp, &exrules); + for (elem = exrules; elem; elem = elem->next) { + changed |= cal_recur_ensure_rule_end_date (comp, elem->data, + TRUE, refresh); + } + + return changed; +} + + +typedef struct _CalRecurEnsureEndDateData CalRecurEnsureEndDateData; +struct _CalRecurEnsureEndDateData { + gint count; + gint instances; + time_t end_date; +}; + + +static gboolean +cal_recur_ensure_rule_end_date (CalComponent *comp, + icalproperty *prop, + gboolean exception, + gboolean refresh) +{ + struct icalrecurrencetype rule; + CalRecurEnsureEndDateData cb_data; + + if (exception) + rule = icalproperty_get_exrule (prop); + else + rule = icalproperty_get_rrule (prop); + + /* If the rule doesn't use COUNT just return. */ + if (rule.count == 0) + return FALSE; + + /* If refresh is FALSE, we check if the enddate is already set, and + if it is we just return. */ + if (!refresh) { + if (cal_recur_get_rule_end_date (prop) != -1) + return FALSE; + } + + /* Calculate the end date. */ + cb_data.count = rule.count; + cb_data.instances = 0; + cal_recur_generate_instances_of_rule (comp, prop, -1, -1, + cal_recur_ensure_rule_end_date_cb, + &cb_data); + + /* Store the end date in the "X-EVOLUTION-ENDDATE" parameter of the + rule. */ + cal_recur_set_rule_end_date (prop, cb_data.end_date); + + return TRUE; +} + + +static gboolean +cal_recur_ensure_rule_end_date_cb (CalComponent *comp, + time_t instance_start, + time_t instance_end, + gpointer data) +{ + CalRecurEnsureEndDateData *cb_data; + + cb_data = (CalRecurEnsureEndDateData*) data; + + cb_data->instances++; + if (cb_data->instances == cb_data->count) { + cb_data->end_date = instance_start; + return FALSE; + } + + return TRUE; +} + + +static time_t +cal_recur_get_rule_end_date (icalproperty *prop) +{ + icalparameter *param; + char *xname, *xvalue; + icalvalue *value; + struct icaltimetype icaltime; + + param = icalproperty_get_first_parameter (prop, ICAL_X_PARAMETER); + while (param) { + xname = icalparameter_get_xname (param); + if (!strcmp (xname, EVOLUTION_END_DATE_PARAMETER)) { + xvalue = icalparameter_get_xvalue (param); + value = icalvalue_new_from_string (ICAL_DATETIME_VALUE, + xvalue); + if (value) { + icaltime = icalvalue_get_datetime (value); + icalvalue_free (value); + + return icaltime_as_timet (icaltime); + } + } + + param = icalproperty_get_next_parameter (prop, + ICAL_X_PARAMETER); + } + + return -1; +} + + +static void +cal_recur_set_rule_end_date (icalproperty *prop, + time_t end_date) +{ + icalparameter *param; + icalvalue *value; + struct icaltimetype icaltime; + char *end_date_string, *xname; + + icaltime = icaltime_from_timet (end_date, FALSE, FALSE); + value = icalvalue_new_datetime (icaltime); + end_date_string = icalvalue_as_ical_string (value); + icalvalue_free (value); + + /* If we already have an X-EVOLUTION-ENDDATE parameter, set the value + to the new date-time. */ + param = icalproperty_get_first_parameter (prop, ICAL_X_PARAMETER); + while (param) { + xname = icalparameter_get_xname (param); + if (!strcmp (xname, EVOLUTION_END_DATE_PARAMETER)) { + icalparameter_set_x (param, end_date_string); + return; + } + param = icalproperty_get_next_parameter (prop, ICAL_X_PARAMETER); + } + + /* Create a new X-EVOLUTION-ENDDATE and add it to the property. */ + param = icalparameter_new_x (EVOLUTION_END_DATE_PARAMETER); + icalparameter_set_x (param, end_date_string); + icalproperty_add_parameter (prop, param); +} + diff --git a/calendar/cal-util/cal-recur.h b/calendar/cal-util/cal-recur.h index 621985b71b..5adc235573 100644 --- a/calendar/cal-util/cal-recur.h +++ b/calendar/cal-util/cal-recur.h @@ -30,18 +30,8 @@ BEGIN_GNOME_DECLS -typedef enum { - CAL_RECUR_YEARLY, - CAL_RECUR_MONTHLY, - CAL_RECUR_WEEKLY, - CAL_RECUR_DAILY, - CAL_RECUR_HOURLY, - CAL_RECUR_MINUTELY, - CAL_RECUR_SECONDLY -} CalRecurType; - typedef struct { - CalRecurType type; + icalrecurrencetype_frequency freq; int interval; @@ -103,15 +93,18 @@ typedef gboolean (* CalRecurInstanceFn) (CalComponent *comp, time_t instace_end, gpointer data); +/* + * Calls the given callback function for each occurrence of the event between + * the given start and end times. If end is 0 it continues until the event + * ends or forever if the event has an infinite recurrence rule. + * If the callback routine return 0 the occurrence generation stops. + */ void cal_recur_generate_instances (CalComponent *comp, time_t start, time_t end, CalRecurInstanceFn cb, gpointer cb_data); -CalRecurrence *cal_recur_from_icalrecurrencetype (struct icalrecurrencetype *ir); -void cal_recur_free (CalRecurrence *r); - END_GNOME_DECLS #endif -- cgit v1.2.3