static int expand_occurrences(icalcomponent *ical, icalcomponent_kind kind,
			      struct calquery_filter *calfilter)
{
    struct freebusy_array *freebusy = &calfilter->freebusy;
    icalcomponent *comp;
    icaltimezone *utc = icaltimezone_get_utc_timezone();
    icaltime_span rangespan;
    unsigned firstr, lastr;

    /* If not saving busytime, reset our array */
    if (!(calfilter->flags & BUSYTIME_QUERY)) freebusy->len = 0;

    /* Create a span for the given time-range */
    rangespan.start =
	icaltime_as_timet_with_zone(calfilter->start, utc);
    rangespan.end =
	icaltime_as_timet_with_zone(calfilter->end, utc);

    /* Mark start of where recurrences will be added */
    firstr = freebusy->len;

    /* Find the master component */
    for (comp = icalcomponent_get_first_component(ical, kind);
	 comp &&
	     icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
	 comp = icalcomponent_get_next_component(ical, kind));

    if (is_busytime(calfilter, comp)) {
	/* Add all recurring busytime in specified time-range */
	icalcomponent_foreach_recurrence(comp,
					 calfilter->start,
					 calfilter->end,
					 add_freebusy_comp, calfilter);
    }

    /* Mark end of where recurrences were added */
    lastr = freebusy->len;

    /* Sort freebusy periods by start time */
    qsort(freebusy->fb + firstr, freebusy->len - firstr,
	  sizeof(struct freebusy), compare_freebusy);

    /* Handle overridden recurrences */
    for (comp = icalcomponent_get_first_component(ical, kind);
	 comp; comp = icalcomponent_get_next_component(ical, kind)) {
	icalproperty *prop;
	struct icaltimetype recurid;
	icalparameter *param;
	struct freebusy *overridden;
	icaltime_span recurspan;

	/* The *_get_recurrenceid() functions don't appear
	   to deal with timezones properly, so we do it ourselves */
	prop =
	    icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
	if (!prop) continue;

	recurid = icalproperty_get_recurrenceid(prop);
	param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER);

	if (param) {
	    const char *tzid = icalparameter_get_tzid(param);
	    icaltimezone *tz = NULL;

	    tz = icalcomponent_get_timezone(ical, tzid);
	    if (!tz) {
		tz = icaltimezone_get_builtin_timezone_from_tzid(tzid);
	    }
	    if (tz) icaltime_set_timezone(&recurid, tz);
	}

	recurid =
	    icaltime_convert_to_zone(recurid,
				     icaltimezone_get_utc_timezone());
	recurid.is_date = 0;  /* make DATE-TIME for comparison */

	/* Check if this overridden instance is in our array */
	overridden = bsearch(&recurid, freebusy->fb + firstr, lastr - firstr,
			     sizeof(struct freebusy), compare_recurid);
	if (overridden) {
	    /* "Remove" the instance
	       by setting fbtype to NONE (we ignore these later)
	       NOTE: MUST keep period.start otherwise bsearch() breaks */
	    /* XXX  Doesn't handle the RANGE=THISANDFUTURE param */
	    overridden->type = ICAL_FBTYPE_NONE;
	}

	/* If overriding component isn't busytime, skip it */
	if (!is_busytime(calfilter, comp)) continue;

	/* Check if the new instance is in our time-range */
	recurspan = icaltime_span_new(icalcomponent_get_dtstart(comp),
				      icalcomponent_get_dtend(comp), 1);

	if (icaltime_span_overlaps(&recurspan, &rangespan)) {
	    /* Add this instance to the array */
	    add_freebusy_comp(comp, &recurspan, calfilter);
	}
    }

    return (freebusy->len - firstr);
}