Completed time range search of recurring events.
[citadel.git] / webcit-ng / server / caldav_reports.c
index 374d50ee5f754842dadd2fadce83e81e40641a8b..8930bfb328b325d626323b586498c67aef3eeab1 100644 (file)
@@ -260,33 +260,60 @@ void caldav_report_one_item(struct http_transaction *h, struct ctdlsession *c, S
 
 // Compare function for "time-range" tests (RFC4791 section 9.9)
 // Returns nonzero if the supplied icalcomponent occurs within the specified time range
+//
+// IMPLEMENTATION NOTE:
+// ical_ctdl_is_overlap() works because icaltime_compare() is really smart.
+// It looks at the time zone of the dtstart/dtend and can apparently go back up the icalcomponent
+// hierarchy to find its time zone data.  I tested this by creating an event with a fictional
+// time zone and it did the right thing.  It even showed the fictional name to me.  This saves us
+// from having to convert everything to UTC before comparing.  Nice!
+//
 int caldav_time_range_filter_matches(icalcomponent *cal, char *start_str, char *end_str) {
+       struct icaltimetype dtstart = icalcomponent_get_dtstart(cal);
+       struct icaltimetype dtend = icalcomponent_get_dtend(cal);
 
-       // syslog(LOG_DEBUG, "caldav_time_range_filter_matches() comparing:\n\033[35m%s\033[0m", icalcomponent_as_ical_string(cal));
+       struct icaltimetype search_start = icaltime_from_string(start_str);
+       syslog(LOG_DEBUG, "   search start: \033[36m%-16s\033[0m (%s)", icaltime_as_ical_string_r(search_start), icaltime_get_tzid(search_start));
 
-       // NOTE TO ME:
-       // Recurrence info is available at this level.  We can handle it here.
+       struct icaltimetype search_end = icaltime_from_string(end_str);
+       syslog(LOG_DEBUG, "   search   end: \033[36m%-16s\033[0m (%s)", icaltime_as_ical_string_r(search_end), icaltime_get_tzid(search_end));
 
-       // IMPLEMENTATION NOTE:
-       // ical_ctdl_is_overlap() works because icaltime_compare() is really smart.
-       // It looks at the time zone of the dtstart/dtend and can apparently go back up the icalcomponent
-       // hierarchy to find its time zone data.  I tested this by creating an event with a fictional
-       // time zone and it did the right thing.  It even showed the fictional name to me.  This saves us
-       // from having to convert everything to UTC before comparing.  Nice!
+       // If it is a recurring event, RRULE is available at this level.  We can handle it here.
 
-       icaltimetype dts = icalcomponent_get_dtstart(cal);
-       syslog(LOG_DEBUG, "component start: \033[36m%-16s\033[0m (%s)", icaltime_as_ical_string_r(dts), icaltime_get_tzid(dts));
-
-       icaltimetype dte = icalcomponent_get_dtend(cal);
-       syslog(LOG_DEBUG, "component   end: \033[36m%-16s\033[0m (%s)", icaltime_as_ical_string_r(dte), icaltime_get_tzid(dte));
+       icalproperty *rrule;                                                                                                          
+       rrule = icalcomponent_get_first_property(cal, ICAL_RRULE_PROPERTY);
+       if (rrule) {
+               if (icaltime_is_null_time(dtend)) {
+                       dtend = dtstart;
+               }
+               struct icaldurationtype dur = icaltime_subtract(dtend, dtstart);        // recurrences need duration to find dtend
+               struct icalrecurrencetype recur = icalproperty_get_rrule(rrule);
+
+               icalrecur_iterator *ritr = icalrecur_iterator_new(recur, dtstart);      // iterate through recurrences
+               int rcount = 0;
+               syslog(LOG_DEBUG, "\033[7m RECURRENCE: \033[0m");
+               while (dtstart = icalrecur_iterator_next(ritr), !icaltime_is_null_time(dtstart)) {
+                       dtend = icaltime_add(dtstart, dur);
+                       syslog(LOG_DEBUG, "recurrence %3d start: \033[36m%-16s\033[0m (%s)", rcount, icaltime_as_ical_string_r(dtstart), icaltime_get_tzid(dtstart));
+                       syslog(LOG_DEBUG, "recurrence %3d   end: \033[36m%-16s\033[0m (%s)", rcount, icaltime_as_ical_string_r(dtend), icaltime_get_tzid(dtend));
+
+                       // Does THIS recurrence match the query?
+                       if (ical_ctdl_is_overlap(dtstart, dtend, search_start, search_end)) {
+                               icalrecur_iterator_free(ritr);
+                               return(1);
+                       }
 
-       struct icaltimetype start = icaltime_from_string(start_str);
-       syslog(LOG_DEBUG, "   search start: \033[36m%-16s\033[0m (%s)", icaltime_as_ical_string_r(start), icaltime_get_tzid(start));
+                       ++rcount;
+               }
 
-       struct icaltimetype end = icaltime_from_string(end_str);
-       syslog(LOG_DEBUG, "   search   end: \033[36m%-16s\033[0m (%s)", icaltime_as_ical_string_r(end), icaltime_get_tzid(end));
+               icalrecur_iterator_free(ritr);
+               return(0);                              // compared all recurrences, no match was found for any of them
+       }
 
-       return(ical_ctdl_is_overlap(dts, dte, start, end));     // We have a convenience function for this.
+       // For non recurring events, do a simple time range compare.
+       syslog(LOG_DEBUG, "event start: \033[36m%-16s\033[0m (%s)", icaltime_as_ical_string_r(dtstart), icaltime_get_tzid(dtstart));
+       syslog(LOG_DEBUG, "event   end: \033[36m%-16s\033[0m (%s)", icaltime_as_ical_string_r(dtend), icaltime_get_tzid(dtend));
+       return(ical_ctdl_is_overlap(dtstart, dtend, search_start, search_end)); // We have a convenience function for this.
 }