Re: [Evolution-hackers] calendar status



> * 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);
	}
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]