diff --git a/inc/caldav-REPORT.php b/inc/caldav-REPORT.php index 8401d344..83d5e1fd 100644 --- a/inc/caldav-REPORT.php +++ b/inc/caldav-REPORT.php @@ -221,7 +221,8 @@ function calendar_to_xml( $properties, $item ) { if ( $free_busy_query ) { include_once("iCalendar.php"); - // Won't return from that... + include_once("RRule.php"); + if ( ! ( isset($report[0]['start']) || isset($report[0]['end']) ) ) { $request->DoResponse( 400, 'All valid freebusy requests MUST contain a time-range filter' ); } @@ -237,20 +238,20 @@ if ( $free_busy_query ) { $busy = array(); $busy_tentative = array(); - $sql = "SELECT caldav_data.caldav_data, "; - $sql .= "to_char(calendar_item.dtstart at time zone 'GMT',".iCalendar::SqlUTCFormat().") AS start, "; - $sql .= "to_char(calendar_item.dtend at time zone 'GMT',".iCalendar::SqlUTCFormat().") AS finish "; + $sql = "SELECT caldav_data.caldav_data, calendar_item.rrule, "; + $sql .= "to_char(calendar_item.dtstart at time zone 'GMT',".iCalendar::SqlDateFormat().") AS start, "; + $sql .= "to_char(calendar_item.dtend at time zone 'GMT',".iCalendar::SqlDateFormat().") AS finish "; $sql .= "FROM caldav_data INNER JOIN calendar_item USING(user_no, dav_name)".$where." ORDER BY dtstart, dtend"; $qry = new PgQuery( $sql, "^".$request->path.$request->DepthRegexTail() ); if ( $qry->Exec("REPORT",__LINE__,__FILE__) && $qry->rows > 0 ) { while( $calendar_object = $qry->Fetch() ) { if ( ! preg_match( '/^TRANSP.*TRANSPARENT/im', $calendar_object->caldav_data ) ) { if ( preg_match( '/^STATUS.*:.*TENTATIVE/im', $calendar_object->caldav_data ) ) { - $busy_tenantive[$calendar_object->start] = $calendar_object->finish; + $busy_tenantive[] = $calendar_object; } else if ( ! preg_match( '/STATUS.*:.*CANCELLED/m', $calendar_object->caldav_data ) ) { dbg_error_log( "REPORT", " FreeBusy: Not transparent, tentative or cancelled: %s, %s", $calendar_object->start, $calendar_object->finish ); - $busy[$calendar_object->start] = $calendar_object->finish; + $busy[] = $calendar_object; } } } @@ -259,16 +260,41 @@ if ( $free_busy_query ) { $freebusy .= sprintf("BEGIN:VFREEBUSY\nDTSTAMP:%s\nDTSTART:%s\nDTEND:%s\n", date('Ymd\THis\Z'), $report[0]['start'], $report[0]['end']); foreach( $busy_tentative AS $k => $v ) { - $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $v['start'], iCalendar::Duration($v['start'],$v['end']) ); + $start = new iCalDate($v->start); + $duration = $start->DateDifference($v->finish); + if ( $v->rrule != "" ) { + $rrule = new RRule( $start, $v->rrule ); + while ( $date = $rrule->GetNext() ) { + if ( ! $date->GreaterThan($report[0]['start']) ) continue; + if ( $date->GreaterThan($report[0]['end']) ) break; + $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $date->Render('Ymd\THis'), $duration ); + } + } + else { + $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $start->Render('Ymd\THis'), $duration ); + } } foreach( $busy AS $k => $v ) { - $freebusy .= sprintf("FREEBUSY:%s/%s\n", $k, iCalendar::Duration($k,$v) ); + $start = new iCalDate($v->start); + $duration = $start->DateDifference($v->finish); + if ( $v->rrule != "" ) { + $rrule = new RRule( $start, $v->rrule ); + while ( $date = $rrule->GetNext() ) { + if ( ! $date->GreaterThan($report[0]['start']) ) continue; + if ( $date->GreaterThan($report[0]['end']) ) break; + $freebusy .= sprintf("FREEBUSY:%s/%s\n", $date->Render('Ymd\THis'), $duration ); + } + } + else { + $freebusy .= sprintf("FREEBUSY:%s/%s\n", $start->Render('Ymd\THis'), $duration ); + } } $freebusy .= "END:VFREEBUSY\n"; $freebusy .= iCalendar::iCalFooter(); $request->DoResponse( 200, $freebusy, 'text/calendar' ); + // Won't return from that } else { // Must have read privilege for other reports