static int deliver_merge_request(const char *attendee,
				 icalcomponent *ical, icalcomponent *request)
{
    int deliver_inbox = 0;
    struct hash_table comp_table;
    icalcomponent *comp, *itip;
    icalcomponent_kind kind = ICAL_NO_COMPONENT;
    icalproperty *prop;
    icalparameter *param;
    const char *tzid, *recurid;

    /* Add each VTIMEZONE of old object to hash table for comparison */
    construct_hash_table(&comp_table, 10, 1);
    for (comp =
	     icalcomponent_get_first_component(ical, ICAL_VTIMEZONE_COMPONENT);
	 comp;
	 comp =
	     icalcomponent_get_next_component(ical, ICAL_VTIMEZONE_COMPONENT)) {
	prop = icalcomponent_get_first_property(comp, ICAL_TZID_PROPERTY);
	tzid = icalproperty_get_tzid(prop);

	hash_insert(tzid, comp, &comp_table);
    }

    /* Process each VTIMEZONE in the iTIP request */
    for (itip = icalcomponent_get_first_component(request,
						  ICAL_VTIMEZONE_COMPONENT);
	 itip;
	 itip = icalcomponent_get_next_component(request,
						 ICAL_VTIMEZONE_COMPONENT)) {
	/* Lookup this TZID in the hash table */
	prop = icalcomponent_get_first_property(itip, ICAL_TZID_PROPERTY);
	tzid = icalproperty_get_tzid(prop);

	comp = hash_lookup(tzid, &comp_table);
	if (comp) {
	    /* Remove component from old object */
	    icalcomponent_remove_component(ical, comp);
	    icalcomponent_free(comp);
	}

	/* Add new/modified component from iTIP request */
	icalcomponent_add_component(ical, icalcomponent_new_clone(itip));
    }

    free_hash_table(&comp_table, NULL);

    /* Add each component of old object to hash table for comparison */
    construct_hash_table(&comp_table, 10, 1);
    comp = icalcomponent_get_first_real_component(ical);
    if (comp) kind = icalcomponent_isa(comp);
    for (; comp; comp = icalcomponent_get_next_component(ical, kind)) {
	prop =
	    icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
	if (prop) recurid = icalproperty_get_value_as_string(prop);
	else recurid = "";

	hash_insert(recurid, comp, &comp_table);
    }

    /* Process each component in the iTIP request */
    itip = icalcomponent_get_first_real_component(request);
    if (kind == ICAL_NO_COMPONENT) kind = icalcomponent_isa(itip);
    for (; itip; itip = icalcomponent_get_next_component(request, kind)) {
	icalcomponent *new_comp = icalcomponent_new_clone(itip);

	/* Lookup this comp in the hash table */
	prop =
	    icalcomponent_get_first_property(itip, ICAL_RECURRENCEID_PROPERTY);
	if (prop) recurid = icalproperty_get_value_as_string(prop);
	else recurid = "";

	comp = hash_lookup(recurid, &comp_table);
	if (comp) {
	    int old_seq, new_seq;

	    /* Check if this is something more than an update */
	    /* XXX  Probably need to check PARTSTAT=NEEDS-ACTION
	       and RSVP=TRUE as well */
	    old_seq = icalcomponent_get_sequence(comp);
	    new_seq = icalcomponent_get_sequence(itip);
	    if (new_seq > old_seq) deliver_inbox = 1;

	    /* Copy over any COMPLETED, PERCENT-COMPLETE,
	       or TRANSP properties */
	    prop =
		icalcomponent_get_first_property(comp, ICAL_COMPLETED_PROPERTY);
	    if (prop) {
		icalcomponent_add_property(new_comp,
					   icalproperty_new_clone(prop));
	    }
	    prop =
		icalcomponent_get_first_property(comp,
						 ICAL_PERCENTCOMPLETE_PROPERTY);
	    if (prop) {
		icalcomponent_add_property(new_comp,
					   icalproperty_new_clone(prop));
	    }
	    prop =
		icalcomponent_get_first_property(comp, ICAL_TRANSP_PROPERTY);
	    if (prop) {
		icalcomponent_add_property(new_comp,
					   icalproperty_new_clone(prop));
	    }

	    /* Copy over any ORGANIZER;SCHEDULE-STATUS */
	    /* XXX  Do we only do this iff PARTSTAT!=NEEDS-ACTION */
	    prop =
		icalcomponent_get_first_property(comp, ICAL_ORGANIZER_PROPERTY);
	    param = icalproperty_get_schedulestatus_parameter(prop);
	    if (param) {
		param = icalparameter_new_clone(param);
		prop =
		    icalcomponent_get_first_property(new_comp,
						     ICAL_ORGANIZER_PROPERTY);
		icalproperty_add_parameter(prop, param);
	    }

	    /* Remove component from old object */
	    icalcomponent_remove_component(ical, comp);
	    icalcomponent_free(comp);
	}
	else {
	    /* New component */
	    deliver_inbox = 1;
	}

	if (config_allowsched == IMAP_ENUM_CALDAV_ALLOWSCHEDULING_APPLE &&
	    kind == ICAL_VEVENT_COMPONENT) {
	    /* Make VEVENT component transparent if recipient ATTENDEE
	       PARTSTAT=NEEDS-ACTION (for compatibility with CalendarServer) */
	    for (prop =
		     icalcomponent_get_first_property(new_comp,
						      ICAL_ATTENDEE_PROPERTY);
		 prop && strcmp(icalproperty_get_attendee(prop), attendee);
		 prop =
		     icalcomponent_get_next_property(new_comp,
						     ICAL_ATTENDEE_PROPERTY));
	    param =
		icalproperty_get_first_parameter(prop, ICAL_PARTSTAT_PARAMETER);
	    if (param &&
		icalparameter_get_partstat(param) ==
		ICAL_PARTSTAT_NEEDSACTION) {
		prop = 
		    icalcomponent_get_first_property(new_comp,
						     ICAL_TRANSP_PROPERTY);
		if (prop)
		    icalproperty_set_transp(prop, ICAL_TRANSP_TRANSPARENT);
		else {
		    prop = icalproperty_new_transp(ICAL_TRANSP_TRANSPARENT);
		    icalcomponent_add_property(new_comp, prop);
		}
	    }
	}

	/* Add new/modified component from iTIP request */
	icalcomponent_add_component(ical, new_comp);
    }

    free_hash_table(&comp_table, NULL);

    return deliver_inbox;
}