> * recurrences: I've got lot of code done for this, but not finished yet,
> since I have left it apart for a few days to fix all the new-ui-branch
> problems. But I think once everything starts working correctly, I should
> be done with the recurrence stuff in 2/3 days more.

Doh. I hope we're not duplicating each other's work. I've also been
doing recurrence stuff for Connector. Here's some of what I've written
(I was planning to move these functions to cal-util.)


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:
 * @comp: a recurring #icalcomponent
 * @rid: the RECURRENCE-ID to construct a component for
 *
 * This checks that @rid indicates a valid recurrence of @comp, 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 *comp,
                             struct icaltimetype rid)
{
        struct instance_data instance;
        struct icaltimetype start, end;

        /* Make sure this is really recurring */
        if (!icalcomponent_get_first_property (comp, ICAL_RRULE_PROPERTY) &&
            !icalcomponent_get_first_property (comp, 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 (comp, start, end,
                                          check_instance, &instance);
        if (!instance.found)
                return NULL;

        /* Make the instance */
        comp = icalcomponent_clone (comp);
        icalcomponent_set_recurrenceid (comp, rid);
        return comp;
}

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;
        else
                return FALSE;
}

/**
 * cal_util_remove_instances:
 * @comp: 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
 * @comp still has any instances
 **/
void
cal_util_remove_instances (icalcomponent *comp,
                           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 (mod != CALOBJ_MOD_ALL);

        /* First remove RDATEs and EXDATEs in the indicated range. */
        for (prop = icalcomponent_get_first_property (comp, ICAL_RDATE_PROPERTY);
             prop;
             prop = icalcomponent_get_next_property (comp, ICAL_RDATE_PROPERTY)) {
                itt = icalproperty_get_rdate (prop);
                if (time_matches_rid (itt, rid, mod))
                        icalcomponent_remove_property (comp, prop);
        }
        for (prop = icalcomponent_get_first_property (comp, ICAL_EXDATE_PROPERTY);
             prop;
             prop = icalcomponent_get_next_property (comp, ICAL_EXDATE_PROPERTY)) {
                itt = icalproperty_get_exdate (prop);
                if (time_matches_rid (itt, rid, mod))
                        icalcomponent_remove_property (comp, 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 (comp, prop);
                return;
        }

        /* Otherwise, iterate through RRULEs */
        /* FIXME: this may generate duplicate EXRULEs */
        for (prop = icalcomponent_get_first_property (comp, ICAL_RRULE_PROPERTY);
             prop;
             prop = icalcomponent_get_next_property (comp, 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 (comp));
                                prop = icalproperty_new_exrule (rule);
                                icalcomponent_add_property (prop);
                        } else
                                icalcomponent_remove_property (prop);
                }

                icalrecur_iterator_free (iter);
        }
}

_______________________________________________
evolution-hackers maillist  -  [EMAIL PROTECTED]
http://lists.ximian.com/mailman/listinfo/evolution-hackers

Reply via email to