static void process_attendees(icalcomponent *comp, unsigned ncomp,
			      const char *organizer, const char *att_update,
			      struct hash_table *att_table,
			      icalcomponent *itip, unsigned needs_action)
{
    icalcomponent *copy;
    icalproperty *prop;
    icalparameter *param;
    icalcomponent_kind kind = icalcomponent_isa(comp);
    icalproperty_kind recip_kind;
    const char *(*get_recipient)(const icalproperty *);

    if (kind == ICAL_VPOLL_COMPONENT) {
	recip_kind = ICAL_VOTER_PROPERTY;
	get_recipient = &icalproperty_get_voter;
    }
    else {
	recip_kind = ICAL_ATTENDEE_PROPERTY;
	get_recipient = &icalproperty_get_attendee;
    }

    /* Strip SCHEDULE-STATUS from each attendee
       and optionally set PROPSTAT=NEEDS-ACTION */
    for (prop = icalcomponent_get_first_property(comp, recip_kind);
	 prop;
	 prop = icalcomponent_get_next_property(comp, recip_kind)) {

	const char *attendee = get_recipient(prop);

	/* Don't modify attendee == organizer */
	if (!strcmp(attendee, organizer)) continue;

	icalproperty_remove_parameter_by_name(prop, "SCHEDULE-STATUS");

	if (needs_action) {
	    /* Set PARTSTAT */
	    param = icalparameter_new_partstat(ICAL_PARTSTAT_NEEDSACTION);
	    icalproperty_set_parameter(prop, param);
	}
    }

    /* Clone a working copy of the component */
    copy = icalcomponent_new_clone(comp);

    clean_component(copy, 0);

    /* Process each attendee */
    for (prop = icalcomponent_get_first_property(copy, recip_kind);
	 prop;
	 prop = icalcomponent_get_next_property(copy, recip_kind)) {
	unsigned do_sched = 1;
	icalparameter_scheduleforcesend force_send =
	    ICAL_SCHEDULEFORCESEND_NONE;
	const char *attendee = get_recipient(prop);

	/* Don't schedule attendee == organizer */
	if (!strcmp(attendee, organizer)) continue;

	/* Don't send an update to the attendee that just sent a reply */
	if (att_update && !strcmp(attendee, att_update)) continue;

	/* Check CalDAV Scheduling parameters */
	param = icalproperty_get_scheduleagent_parameter(prop);
	if (param) {
	    icalparameter_scheduleagent agent =
		icalparameter_get_scheduleagent(param);

	    if (agent != ICAL_SCHEDULEAGENT_SERVER) do_sched = 0;
	    icalproperty_remove_parameter_by_ref(prop, param);
	}

	param = icalproperty_get_scheduleforcesend_parameter(prop);
	if (param) {
	    force_send = icalparameter_get_scheduleforcesend(param);
	    icalproperty_remove_parameter_by_ref(prop, param);
	}

	/* Create/update iTIP request for this attendee */
	if (do_sched) {
	    struct sched_data *sched_data;
	    icalcomponent *new_comp;

	    sched_data = hash_lookup(attendee, att_table);
	    if (!sched_data) {
		/* New attendee - add it to the hash table */
		sched_data = xzmalloc(sizeof(struct sched_data));
		sched_data->itip = icalcomponent_new_clone(itip);
		sched_data->force_send = force_send;
		hash_insert(attendee, sched_data, att_table);
	    }
	    new_comp = icalcomponent_new_clone(copy);
	    icalcomponent_add_component(sched_data->itip, new_comp);
	    sched_data->comp_mask |= (1 << ncomp);

	    /* XXX  We assume that the master component is always first */
	    if (!ncomp) sched_data->master = new_comp;
	}
    }

    /* XXX  We assume that the master component is always first */
    if (ncomp) {
	/* Handle attendees that are excluded from this recurrence */
	struct exclude_rock erock = { ncomp, copy };

	hash_enumerate(att_table, sched_exclude, &erock);
    }

    icalcomponent_free(copy);
}