diff options
Diffstat (limited to 'calendar/cal-util/cal-util.c')
-rw-r--r-- | calendar/cal-util/cal-util.c | 926 |
1 files changed, 0 insertions, 926 deletions
diff --git a/calendar/cal-util/cal-util.c b/calendar/cal-util/cal-util.c deleted file mode 100644 index f6ad0d4007..0000000000 --- a/calendar/cal-util/cal-util.c +++ /dev/null @@ -1,926 +0,0 @@ -/* Evolution calendar utilities and types - * - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 2000 Ximian, Inc. - * - * Author: Federico Mena-Quintero <federico@ximian.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <config.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> -#include <glib/gstrfuncs.h> -#include <libgnome/gnome-i18n.h> -#include <libgnome/gnome-util.h> -#include "cal-util.h" - - - -/** - * cal_obj_instance_list_free: - * @list: List of #CalObjInstance structures. - * - * Frees a list of #CalObjInstance structures. - **/ -void -cal_obj_instance_list_free (GList *list) -{ - CalObjInstance *i; - GList *l; - - for (l = list; l; l = l->next) { - i = l->data; - - g_assert (i != NULL); - g_assert (i->uid != NULL); - - g_free (i->uid); - g_free (i); - } - - g_list_free (list); -} - -/** - * cal_obj_uid_list_free: - * @list: List of strings with unique identifiers. - * - * Frees a list of unique identifiers for calendar objects. - **/ -void -cal_obj_uid_list_free (GList *list) -{ - GList *l; - - for (l = list; l; l = l->next) { - char *uid; - - uid = l->data; - - g_assert (uid != NULL); - g_free (uid); - } - - g_list_free (list); -} - -icalcomponent * -cal_util_new_top_level (void) -{ - icalcomponent *icalcomp; - icalproperty *prop; - - icalcomp = icalcomponent_new (ICAL_VCALENDAR_COMPONENT); - - /* RFC 2445, section 4.7.1 */ - prop = icalproperty_new_calscale ("GREGORIAN"); - icalcomponent_add_property (icalcomp, prop); - - /* RFC 2445, section 4.7.3 */ - prop = icalproperty_new_prodid ("-//Ximian//NONSGML Evolution Calendar//EN"); - icalcomponent_add_property (icalcomp, prop); - - /* RFC 2445, section 4.7.4. This is the iCalendar spec version, *NOT* - * the product version! Do not change this! - */ - prop = icalproperty_new_version ("2.0"); - icalcomponent_add_property (icalcomp, prop); - - return icalcomp; -} - -static char * -get_line_fn (char *buf, size_t size, void *file) -{ - return fgets (buf, size, file); -} - -icalcomponent * -cal_util_parse_ics_file (const char *filename) -{ - icalparser *parser; - icalcomponent *icalcomp; - FILE *file; - - file = fopen (filename, "r"); - if (!file) - return NULL; - - parser = icalparser_new (); - icalparser_set_gen_data (parser, file); - - icalcomp = icalparser_parse (parser, get_line_fn); - icalparser_free (parser); - fclose (file); - - return icalcomp; -} - -/* Computes the range of time in which recurrences should be generated for a - * component in order to compute alarm trigger times. - */ -static void -compute_alarm_range (CalComponent *comp, GList *alarm_uids, time_t start, time_t end, - time_t *alarm_start, time_t *alarm_end) -{ - GList *l; - time_t repeat_time; - - *alarm_start = start; - *alarm_end = end; - - repeat_time = 0; - - for (l = alarm_uids; l; l = l->next) { - const char *auid; - CalComponentAlarm *alarm; - CalAlarmTrigger trigger; - struct icaldurationtype *dur; - time_t dur_time; - CalAlarmRepeat repeat; - - auid = l->data; - alarm = cal_component_get_alarm (comp, auid); - g_assert (alarm != NULL); - - cal_component_alarm_get_trigger (alarm, &trigger); - cal_component_alarm_get_repeat (alarm, &repeat); - cal_component_alarm_free (alarm); - - switch (trigger.type) { - case CAL_ALARM_TRIGGER_NONE: - case CAL_ALARM_TRIGGER_ABSOLUTE: - break; - - case CAL_ALARM_TRIGGER_RELATIVE_START: - case CAL_ALARM_TRIGGER_RELATIVE_END: - dur = &trigger.u.rel_duration; - dur_time = icaldurationtype_as_int (*dur); - - if (repeat.repetitions != 0) { - int rdur; - - rdur = repeat.repetitions * icaldurationtype_as_int (repeat.duration); - repeat_time = MAX (repeat_time, rdur); - } - - if (dur->is_neg) - /* If the duration is negative then dur_time - * will be negative as well; that is why we - * subtract to expand the range. - */ - *alarm_end = MAX (*alarm_end, end - dur_time); - else - *alarm_start = MIN (*alarm_start, start - dur_time); - - break; - - default: - g_assert_not_reached (); - } - } - - *alarm_start -= repeat_time; - - g_assert (*alarm_start <= *alarm_end); -} - -/* Closure data to generate alarm occurrences */ -struct alarm_occurrence_data { - /* These are the info we have */ - GList *alarm_uids; - time_t start; - time_t end; - CalAlarmAction *omit; - - /* This is what we compute */ - GSList *triggers; - int n_triggers; -}; - -static void -add_trigger (struct alarm_occurrence_data *aod, const char *auid, time_t trigger, - time_t occur_start, time_t occur_end) -{ - CalAlarmInstance *instance; - - instance = g_new (CalAlarmInstance, 1); - instance->auid = auid; - instance->trigger = trigger; - instance->occur_start = occur_start; - instance->occur_end = occur_end; - - aod->triggers = g_slist_prepend (aod->triggers, instance); - aod->n_triggers++; -} - -/* Callback used from cal_recur_generate_instances(); generates triggers for all - * of a component's RELATIVE alarms. - */ -static gboolean -add_alarm_occurrences_cb (CalComponent *comp, time_t start, time_t end, gpointer data) -{ - struct alarm_occurrence_data *aod; - GList *l; - - aod = data; - - for (l = aod->alarm_uids; l; l = l->next) { - const char *auid; - CalComponentAlarm *alarm; - CalAlarmAction action; - CalAlarmTrigger trigger; - CalAlarmRepeat repeat; - struct icaldurationtype *dur; - time_t dur_time; - time_t occur_time, trigger_time; - int i; - - auid = l->data; - alarm = cal_component_get_alarm (comp, auid); - g_assert (alarm != NULL); - - cal_component_alarm_get_action (alarm, &action); - cal_component_alarm_get_trigger (alarm, &trigger); - cal_component_alarm_get_repeat (alarm, &repeat); - cal_component_alarm_free (alarm); - - for (i = 0; aod->omit[i] != -1; i++) { - if (aod->omit[i] == action) - break; - } - if (aod->omit[i] != -1) - continue; - - if (trigger.type != CAL_ALARM_TRIGGER_RELATIVE_START - && trigger.type != CAL_ALARM_TRIGGER_RELATIVE_END) - continue; - - dur = &trigger.u.rel_duration; - dur_time = icaldurationtype_as_int (*dur); - - if (trigger.type == CAL_ALARM_TRIGGER_RELATIVE_START) - occur_time = start; - else - occur_time = end; - - /* If dur->is_neg is true then dur_time will already be - * negative. So we do not need to test for dur->is_neg here; we - * can simply add the dur_time value to the occur_time and get - * the correct result. - */ - - trigger_time = occur_time + dur_time; - - /* Add repeating alarms */ - - if (repeat.repetitions != 0) { - int i; - time_t repeat_time; - - repeat_time = icaldurationtype_as_int (repeat.duration); - - for (i = 0; i < repeat.repetitions; i++) { - time_t t; - - t = trigger_time + (i + 1) * repeat_time; - - if (t >= aod->start && t < aod->end) - add_trigger (aod, auid, t, start, end); - } - } - - /* Add the trigger itself */ - - if (trigger_time >= aod->start && trigger_time < aod->end) - add_trigger (aod, auid, trigger_time, start, end); - } - - return TRUE; -} - -/* Generates the absolute triggers for a component */ -static void -generate_absolute_triggers (CalComponent *comp, struct alarm_occurrence_data *aod, - CalRecurResolveTimezoneFn resolve_tzid, - gpointer user_data, - icaltimezone *default_timezone) -{ - GList *l; - CalComponentDateTime dt_start, dt_end; - - cal_component_get_dtstart (comp, &dt_start); - cal_component_get_dtend (comp, &dt_end); - - for (l = aod->alarm_uids; l; l = l->next) { - const char *auid; - CalComponentAlarm *alarm; - CalAlarmAction action; - CalAlarmRepeat repeat; - CalAlarmTrigger trigger; - time_t abs_time; - time_t occur_start, occur_end; - icaltimezone *zone; - int i; - - auid = l->data; - alarm = cal_component_get_alarm (comp, auid); - g_assert (alarm != NULL); - - cal_component_alarm_get_action (alarm, &action); - cal_component_alarm_get_trigger (alarm, &trigger); - cal_component_alarm_get_repeat (alarm, &repeat); - cal_component_alarm_free (alarm); - - for (i = 0; aod->omit[i] != -1; i++) { - if (aod->omit[i] == action) - break; - } - if (aod->omit[i] != -1) - continue; - - if (trigger.type != CAL_ALARM_TRIGGER_ABSOLUTE) - continue; - - /* Absolute triggers are always in UTC; see RFC 2445 section 4.8.6.3 */ - zone = icaltimezone_get_utc_timezone (); - - abs_time = icaltime_as_timet_with_zone (trigger.u.abs_time, zone); - - /* No particular occurrence, so just use the times from the component */ - - if (dt_start.value) { - if (dt_start.tzid && !dt_start.value->is_date) - zone = (* resolve_tzid) (dt_start.tzid, user_data); - else - zone = default_timezone; - - occur_start = icaltime_as_timet_with_zone (*dt_start.value, zone); - } else - occur_start = -1; - - if (dt_end.value) { - if (dt_end.tzid && !dt_end.value->is_date) - zone = (* resolve_tzid) (dt_end.tzid, user_data); - else - zone = default_timezone; - - occur_end = icaltime_as_timet_with_zone (*dt_end.value, zone); - } else - occur_end = -1; - - /* Add repeating alarms */ - - if (repeat.repetitions != 0) { - int i; - time_t repeat_time; - - repeat_time = icaldurationtype_as_int (repeat.duration); - - for (i = 0; i < repeat.repetitions; i++) { - time_t t; - - t = abs_time + (i + 1) * repeat_time; - - if (t >= aod->start && t < aod->end) - add_trigger (aod, auid, t, occur_start, occur_end); - } - } - - /* Add the trigger itself */ - - if (abs_time >= aod->start && abs_time < aod->end) - add_trigger (aod, auid, abs_time, occur_start, occur_end); - } - - cal_component_free_datetime (&dt_start); - cal_component_free_datetime (&dt_end); -} - -/* Compares two alarm instances; called from g_slist_sort() */ -static gint -compare_alarm_instance (gconstpointer a, gconstpointer b) -{ - const CalAlarmInstance *aia, *aib; - - aia = a; - aib = b; - - if (aia->trigger < aib->trigger) - return -1; - else if (aia->trigger > aib->trigger) - return 1; - else - return 0; -} - -/** - * cal_util_generate_alarms_for_comp - * @comp: the CalComponent to generate alarms from - * @start: start time - * @end: end time - * @resolve_tzid: callback for resolving timezones - * @user_data: data to be passed to the resolve_tzid callback - * @default_timezone: the timezone used to resolve DATE and floating DATE-TIME - * values. - * - * Generates alarm instances for a calendar component. Returns the instances - * structure, or NULL if no alarm instances occurred in the specified time - * range. - */ -CalComponentAlarms * -cal_util_generate_alarms_for_comp (CalComponent *comp, - time_t start, - time_t end, - CalAlarmAction *omit, - CalRecurResolveTimezoneFn resolve_tzid, - gpointer user_data, - icaltimezone *default_timezone) -{ - GList *alarm_uids; - time_t alarm_start, alarm_end; - struct alarm_occurrence_data aod; - CalComponentAlarms *alarms; - - if (!cal_component_has_alarms (comp)) - return NULL; - - alarm_uids = cal_component_get_alarm_uids (comp); - compute_alarm_range (comp, alarm_uids, start, end, &alarm_start, &alarm_end); - - aod.alarm_uids = alarm_uids; - aod.start = start; - aod.end = end; - aod.omit = omit; - aod.triggers = NULL; - aod.n_triggers = 0; - - cal_recur_generate_instances (comp, alarm_start, alarm_end, - add_alarm_occurrences_cb, &aod, - resolve_tzid, user_data, - default_timezone); - - /* We add the ABSOLUTE triggers separately */ - generate_absolute_triggers (comp, &aod, resolve_tzid, user_data, default_timezone); - - if (aod.n_triggers == 0) - return NULL; - - /* Create the component alarm instances structure */ - - alarms = g_new (CalComponentAlarms, 1); - alarms->comp = comp; - g_object_ref (G_OBJECT (alarms->comp)); - alarms->alarms = g_slist_sort (aod.triggers, compare_alarm_instance); - - return alarms; -} - -/** - * cal_util_generate_alarms_for_list - * @comps: list of CalComponent's - * @start: start time - * @end: end time - * @comp_alarms: list to be returned - * @resolve_tzid: callback for resolving timezones - * @user_data: data to be passed to the resolve_tzid callback - * @default_timezone: the timezone used to resolve DATE and floating DATE-TIME - * values. - * - * Iterates through all the components in the comps list and generates alarm - * instances for them; putting them in the comp_alarms list. - * - * Returns: the number of elements it added to that list. - */ -int -cal_util_generate_alarms_for_list (GList *comps, - time_t start, - time_t end, - CalAlarmAction *omit, - GSList **comp_alarms, - CalRecurResolveTimezoneFn resolve_tzid, - gpointer user_data, - icaltimezone *default_timezone) -{ - GList *l; - int n; - - n = 0; - - for (l = comps; l; l = l->next) { - CalComponent *comp; - CalComponentAlarms *alarms; - - comp = CAL_COMPONENT (l->data); - alarms = cal_util_generate_alarms_for_comp (comp, start, end, omit, resolve_tzid, user_data, default_timezone); - - if (alarms) { - *comp_alarms = g_slist_prepend (*comp_alarms, alarms); - n++; - } - } - - return n; -} - - -/* Converts an iCalendar PRIORITY value to a translated string. Any unknown - priority value (i.e. not 0-9) will be returned as "" (undefined). */ -char * -cal_util_priority_to_string (int priority) -{ - char *retval; - - if (priority <= 0) - retval = ""; - else if (priority <= 4) - retval = _("High"); - else if (priority == 5) - retval = _("Normal"); - else if (priority <= 9) - retval = _("Low"); - else - retval = ""; - - return retval; -} - - -/* Converts a translated priority string to an iCalendar priority value. - Returns -1 if the priority string is not valid. */ -int -cal_util_priority_from_string (const char *string) -{ - int priority; - - /* An empty string is the same as 'None'. */ - if (!string || !string[0] || !g_strcasecmp (string, _("Undefined"))) - priority = 0; - else if (!g_strcasecmp (string, _("High"))) - priority = 3; - else if (!g_strcasecmp (string, _("Normal"))) - priority = 5; - else if (!g_strcasecmp (string, _("Low"))) - priority = 7; - else - priority = -1; - - return priority; -} - -char * -cal_util_expand_uri (char *uri, gboolean tasks) -{ - return g_strdup (uri); -} - -/* callback for icalcomponent_foreach_tzid */ -typedef struct { - icalcomponent *vcal_comp; - icalcomponent *icalcomp; -} ForeachTzidData; - -static void -add_timezone_cb (icalparameter *param, void *data) -{ - icaltimezone *tz; - const char *tzid; - icalcomponent *vtz_comp; - ForeachTzidData *f_data = (ForeachTzidData *) data; - - tzid = icalparameter_get_tzid (param); - if (!tzid) - return; - - tz = icalcomponent_get_timezone (f_data->vcal_comp, tzid); - if (tz) - return; - - tz = icalcomponent_get_timezone (f_data->icalcomp, tzid); - if (!tz) { - tz = icaltimezone_get_builtin_timezone_from_tzid (tzid); - if (!tz) - return; - } - - vtz_comp = icaltimezone_get_component (tz); - if (!vtz_comp) - return; - - icalcomponent_add_component (f_data->vcal_comp, - icalcomponent_new_clone (vtz_comp)); -} - -/* Adds VTIMEZONE components to a VCALENDAR for all tzid's - * in the given CalComponent. */ -void -cal_util_add_timezones_from_component (icalcomponent *vcal_comp, - icalcomponent *icalcomp) -{ - ForeachTzidData f_data; - - g_return_if_fail (vcal_comp != NULL); - g_return_if_fail (icalcomp != NULL);; - - f_data.vcal_comp = vcal_comp; - f_data.icalcomp = icalcomp; - icalcomponent_foreach_tzid (icalcomp, add_timezone_cb, &f_data); -} - -gboolean -cal_util_component_is_instance (icalcomponent *icalcomp) -{ - icalproperty *prop; - - g_return_val_if_fail (icalcomp != NULL, FALSE); - - prop = icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY); - return prop ? TRUE : FALSE; -} - -gboolean -cal_util_component_has_alarms (icalcomponent *icalcomp) -{ - icalcomponent *alarm; - - g_return_val_if_fail (icalcomp != NULL, FALSE); - - alarm = icalcomponent_get_first_component (icalcomp, ICAL_VALARM_COMPONENT); - return alarm ? TRUE : FALSE; -} - -gboolean -cal_util_component_has_organizer (icalcomponent *icalcomp) -{ - icalproperty *prop; - - g_return_val_if_fail (icalcomp != NULL, FALSE); - - prop = icalcomponent_get_first_property (icalcomp, ICAL_ORGANIZER_PROPERTY); - return prop ? TRUE : FALSE; -} - -gboolean -cal_util_component_has_recurrences (icalcomponent *icalcomp) -{ - g_return_val_if_fail (icalcomp != NULL, FALSE); - - return cal_util_component_has_rdates (icalcomp) || cal_util_component_has_rrules (icalcomp); -} - -gboolean -cal_util_component_has_rdates (icalcomponent *icalcomp) -{ - icalproperty *prop; - - g_return_val_if_fail (icalcomp != NULL, FALSE); - - prop = icalcomponent_get_first_property (icalcomp, ICAL_RDATE_PROPERTY); - return prop ? TRUE : FALSE; -} - -gboolean -cal_util_component_has_rrules (icalcomponent *icalcomp) -{ - icalproperty *prop; - - g_return_val_if_fail (icalcomp != NULL, FALSE); - - prop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY); - return prop ? TRUE : FALSE; -} - -gboolean -cal_util_event_dates_match (icalcomponent *icalcomp1, icalcomponent *icalcomp2) -{ - struct icaltimetype c1_dtstart, c1_dtend, c2_dtstart, c2_dtend; - - g_return_val_if_fail (icalcomp1 != NULL, FALSE); - g_return_val_if_fail (icalcomp2 != NULL, FALSE); - - c1_dtstart = icalcomponent_get_dtstart (icalcomp1); - c1_dtend = icalcomponent_get_dtend (icalcomp1); - c2_dtstart = icalcomponent_get_dtstart (icalcomp2); - c2_dtend = icalcomponent_get_dtend (icalcomp2); - - /* if either value is NULL, they must both be NULL to match */ - if (icaltime_is_valid_time (c1_dtstart) || icaltime_is_valid_time (c2_dtstart)) { - if (!(icaltime_is_valid_time (c1_dtstart) && icaltime_is_valid_time (c2_dtstart))) - return FALSE; - } else { - if (icaltime_compare (c1_dtstart, c2_dtstart)) - return FALSE; - } - - if (icaltime_is_valid_time (c1_dtend) || icaltime_is_valid_time (c2_dtend)) { - if (!(icaltime_is_valid_time (c1_dtend) && icaltime_is_valid_time (c2_dtend))) - return FALSE; - } else { - if (icaltime_compare (c1_dtend, c2_dtend)) - return FALSE; - } - - - - /* now match the timezones */ - if (!(!c1_dtstart.zone && !c2_dtstart.zone) || - (c1_dtstart.zone && c2_dtstart.zone && - !strcmp (icaltimezone_get_tzid ((icaltimezone *) c1_dtstart.zone), - icaltimezone_get_tzid ((icaltimezone *) c2_dtstart.zone)))) - return FALSE; - - if (!(!c1_dtend.zone && !c2_dtend.zone) || - (c1_dtend.zone && c2_dtend.zone && - !strcmp (icaltimezone_get_tzid ((icaltimezone *) c1_dtend.zone), - icaltimezone_get_tzid ((icaltimezone *) c2_dtend.zone)))) - return FALSE; - - return TRUE; -} - -/* Individual instances management */ - -struct instance_data { - time_t start; - gboolean found; -}; - -static void -check_instance (icalcomponent *comp, struct icaltime_span span, void *data) -{ - struct instance_data *instance = data; - - if (span.start == instance->start) - instance->found = TRUE; -} - -/** - * cal_util_construct_instance: - * @icalcomp: a recurring #icalcomponent - * @rid: the RECURRENCE-ID to construct a component for - * - * This checks that @rid indicates a valid recurrence of @icalcomp, and - * if so, generates a copy of @comp containing a RECURRENCE-ID of @rid. - * - * Return value: the instance, or %NULL - **/ -icalcomponent * -cal_util_construct_instance (icalcomponent *icalcomp, - struct icaltimetype rid) -{ - struct instance_data instance; - struct icaltimetype start, end; - - g_return_val_if_fail (icalcomp != NULL, NULL); - - /* Make sure this is really recurring */ - if (!icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY) && - !icalcomponent_get_first_property (icalcomp, ICAL_RDATE_PROPERTY)) - return NULL; - - /* Make sure the specified instance really exists */ - /* FIXME: does the libical recurrence code work correctly now? */ - start = icaltime_convert_to_zone (rid, icaltimezone_get_utc_timezone ()); - end = start; - icaltime_adjust (&end, 0, 0, 0, 1); - - instance.start = icaltime_as_timet (start); - instance.found = FALSE; - icalcomponent_foreach_recurrence (icalcomp, start, end, - check_instance, &instance); - if (!instance.found) - return NULL; - - /* Make the instance */ - icalcomp = icalcomponent_new_clone (icalcomp); - icalcomponent_set_recurrenceid (icalcomp, rid); - - return icalcomp; -} - -static inline gboolean -time_matches_rid (struct icaltimetype itt, struct icaltimetype rid, CalObjModType mod) -{ - int compare; - - compare = icaltime_compare (itt, rid); - if (compare == 0) - return TRUE; - else if (compare < 0 && (mod & CALOBJ_MOD_THISANDPRIOR)) - return TRUE; - else if (compare > 0 && (mod & CALOBJ_MOD_THISANDFUTURE)) - return TRUE; - - return FALSE; -} - -/** - * cal_util_remove_instances: - * @icalcomp: a (recurring) #icalcomponent - * @rid: the base RECURRENCE-ID to remove - * @mod: how to interpret @rid - * - * Removes one or more instances from @comp according to @rid and @mod. - * - * FIXME: should probably have a return value indicating whether or not - * @icalcomp still has any instances - **/ -void -cal_util_remove_instances (icalcomponent *icalcomp, - struct icaltimetype rid, - CalObjModType mod) -{ - icalproperty *prop; - struct icaltimetype itt, recur; - struct icalrecurrencetype rule; - icalrecur_iterator *iter; - struct instance_data instance; - - g_return_if_fail (icalcomp != NULL); - g_return_if_fail (mod != CALOBJ_MOD_ALL); - - /* First remove RDATEs and EXDATEs in the indicated range. */ - for (prop = icalcomponent_get_first_property (icalcomp, ICAL_RDATE_PROPERTY); - prop; - prop = icalcomponent_get_next_property (icalcomp, ICAL_RDATE_PROPERTY)) { - struct icaldatetimeperiodtype period; - - period = icalproperty_get_rdate (prop); - if (time_matches_rid (period.time, rid, mod)) - icalcomponent_remove_property (icalcomp, prop); - } - for (prop = icalcomponent_get_first_property (icalcomp, ICAL_EXDATE_PROPERTY); - prop; - prop = icalcomponent_get_next_property (icalcomp, ICAL_EXDATE_PROPERTY)) { - itt = icalproperty_get_exdate (prop); - if (time_matches_rid (itt, rid, mod)) - icalcomponent_remove_property (icalcomp, prop); - } - - /* If we're only removing one instance, just add an EXDATE. */ - if (mod == CALOBJ_MOD_THIS) { - prop = icalproperty_new_exdate (rid); - icalcomponent_add_property (icalcomp, prop); - return; - } - - /* Otherwise, iterate through RRULEs */ - /* FIXME: this may generate duplicate EXRULEs */ - for (prop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY); - prop; - prop = icalcomponent_get_next_property (icalcomp, ICAL_RRULE_PROPERTY)) { - rule = icalproperty_get_rrule (prop); - - iter = icalrecur_iterator_new (rule, rid); - recur = icalrecur_iterator_next (iter); - - if (mod & CALOBJ_MOD_THISANDFUTURE) { - /* If there is a recurrence on or after rid, - * use the UNTIL parameter to truncate the rule - * at rid. - */ - if (!icaltime_is_null_time (recur)) { - rule.count = 0; - rule.until = rid; - icaltime_adjust (&rule.until, 0, 0, 0, -1); - icalproperty_set_rrule (prop, rule); - } - } else { - /* (If recur == rid, skip to the next occurrence) */ - if (icaltime_compare (recur, rid) == 0) - recur = icalrecur_iterator_next (iter); - - /* If there is a recurrence after rid, add - * an EXRULE to block instances up to rid. - * Otherwise, just remove the RRULE. - */ - if (!icaltime_is_null_time (recur)) { - rule.count = 0; - /* iCalendar says we should just use rid - * here, but Outlook/Exchange handle - * UNTIL incorrectly. - */ - rule.until = icaltime_add (rid, icalcomponent_get_duration (icalcomp)); - prop = icalproperty_new_exrule (rule); - icalcomponent_add_property (icalcomp, prop); - } else - icalcomponent_remove_property (icalcomp, prop); - } - - icalrecur_iterator_free (iter); - } -} |