REPORT namespace output uses declaration defined on top
[citadel.git] / webcit-ng / server / caldav_reports.c
index 374d50ee5f754842dadd2fadce83e81e40641a8b..49d1fe8d03f4ca7a07d892e7a5864f337cdaa10b 100644 (file)
@@ -260,33 +260,47 @@ 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) {
 
-       // syslog(LOG_DEBUG, "caldav_time_range_filter_matches() comparing:\n\033[35m%s\033[0m", icalcomponent_as_ical_string(cal));
-
-       // NOTE TO ME:
-       // Recurrence info is available at this level.  We can handle it here.
-
-       // 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!
+       struct icaltimetype search_start = icaltime_from_string(start_str);             // time range being searched
+       struct icaltimetype search_end = icaltime_from_string(end_str);
 
-       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));
+       struct icaltimetype dtstart = icalcomponent_get_dtstart(cal);                   // time of event
+       struct icaltimetype dtend = icalcomponent_get_dtend(cal);
+       if (icaltime_is_null_time(dtend)) {
+               dtend = dtstart;
+       }
 
-       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));
+       // If it is a recurring event, RRULE is available at this level.  We can handle it here.
+       icalproperty *rrule = icalcomponent_get_first_property(cal, ICAL_RRULE_PROPERTY);
+       if (rrule) {
+               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
+               while (dtstart = icalrecur_iterator_next(ritr), !icaltime_is_null_time(dtstart)) {
+                       dtend = icaltime_add(dtstart, dur);
+
+                       // Does THIS recurrence match the query?  If so, free the memory we used and stop iterating.
+                       if (ical_ctdl_is_overlap(dtstart, dtend, search_start, search_end)) {
+                               icalrecur_iterator_free(ritr);
+                               return(1);
+                       }
+               }
 
-       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.
+       return(ical_ctdl_is_overlap(dtstart, dtend, search_start, search_end)); // We have a convenience function for this.
 }
 
 
@@ -405,23 +419,23 @@ int caldav_apply_filters(void *cal, Array *filters, int apply_at_level) {
                }
 
                else if (!strcasecmp(t[1], "time-range")) {                     // RFC4791 9.9
-                       syslog(LOG_DEBUG, "time range filter at level %d FIXME add recurrence", this_rule_level);
+                       syslog(LOG_DEBUG, "time range filter at level %d", this_rule_level);
+                       char *tr_start  = (char *)the_beginning_of_time;        // default if not specified
+                       char *tr_end    = (char *)the_end_of_time;              // default if not specified
                        for (int i=2; (i+1)<num_tokens; i+=2) {
-                               char *tr_start  = (char *)the_beginning_of_time;        // default if not specified
-                               char *tr_end    = (char *)the_end_of_time;              // default if not specified
                                if (!strcasecmp(t[i], "start")) {
                                        tr_start = t[i+1];
                                }
                                else if (!strcasecmp(t[i], "end")) {
                                        tr_end = t[i+1];
                                }
-                               if (caldav_time_range_filter_matches(cal, tr_start, tr_end)) {
-                                       syslog(LOG_DEBUG, "time range matches");
-                               }
-                               else {
-                                       syslog(LOG_DEBUG, "time range does not match -- rejecting");
-                                       qual = 0;
-                               }
+                       }
+                       if (caldav_time_range_filter_matches(cal, tr_start, tr_end)) {
+                               syslog(LOG_DEBUG, "time range matches");
+                       }
+                       else {
+                               syslog(LOG_DEBUG, "time range does not match -- rejecting");
+                               qual = 0;
                        }
                }
 
@@ -470,11 +484,8 @@ void caldav_report(struct http_transaction *h, struct ctdlsession *c) {
        syslog(LOG_DEBUG, "CalDAV REPORT type is: %d", crp.report_type);
        StrBuf *ReportOut = NewStrBuf();
        StrBufAppendPrintf(ReportOut,
-               "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
-               "<D:multistatus "
-               "xmlns:D=\"DAV:\" "
-               "xmlns:C=\"urn:ietf:params:xml:ns:caldav\""
-               ">"
+               "<?xml version=\"1.0\" encoding=\"utf-8\"?><D:multistatus xmlns:D=\"DAV:\" xmlns:C=\"%s\">",
+               CALDAV
        );
 
        // RFC4791 7.8 "calendar-query" REPORT - Client will send a lot of search criteria.
@@ -493,12 +504,12 @@ void caldav_report(struct http_transaction *h, struct ctdlsession *c) {
                                // Does this calendar item qualify for output?  Run this calendar item through the filters.
                                syslog(LOG_DEBUG, "Evaluating message \033[33m%ld\033[0m...", m);
                                if (caldav_apply_filters(cal, crp.filters, 0)) {
-                                       syslog(LOG_DEBUG, "Message %ld \033[32mQUALIFIES\033[0m");
+                                       syslog(LOG_DEBUG, "Message %ld \033[32mQUALIFIES\033[0m", m);
                                        // FIXME need to populate the Href instead of NULL
                                        cal_multiget_out(m, NULL, one_item, ReportOut);
                                }
                                else {
-                                       syslog(LOG_DEBUG, "Message %ld \033[31mDOES NOT QUALIFY\033[0m");
+                                       syslog(LOG_DEBUG, "Message %ld \033[31mDOES NOT QUALIFY\033[0m", m);
                                }
                                syslog(LOG_DEBUG, "");