diff options
Diffstat (limited to '3rdparty/Sabre/CalDAV/Plugin.php')
-rwxr-xr-x | 3rdparty/Sabre/CalDAV/Plugin.php | 579 |
1 files changed, 99 insertions, 480 deletions
diff --git a/3rdparty/Sabre/CalDAV/Plugin.php b/3rdparty/Sabre/CalDAV/Plugin.php index f3d11969c8b..c56ab384844 100755 --- a/3rdparty/Sabre/CalDAV/Plugin.php +++ b/3rdparty/Sabre/CalDAV/Plugin.php @@ -1,7 +1,5 @@ <?php -use Sabre\VObject; - /** * CalDAV plugin * @@ -27,6 +25,16 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { const NS_CALENDARSERVER = 'http://calendarserver.org/ns/'; /** + * The following constants are used to differentiate + * the various filters for the calendar-query report + */ + const FILTER_COMPFILTER = 1; + const FILTER_TIMERANGE = 3; + const FILTER_PROPFILTER = 4; + const FILTER_PARAMFILTER = 5; + const FILTER_TEXTMATCH = 6; + + /** * The hardcoded root for calendar objects. It is unfortunate * that we're stuck with it, but it will have to do for now */ @@ -164,19 +172,16 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { $server->subscribeEvent('onBrowserPostAction', array($this,'browserPostAction')); $server->subscribeEvent('beforeWriteContent', array($this, 'beforeWriteContent')); $server->subscribeEvent('beforeCreateFile', array($this, 'beforeCreateFile')); - $server->subscribeEvent('beforeMethod', array($this,'beforeMethod')); $server->xmlNamespaces[self::NS_CALDAV] = 'cal'; $server->xmlNamespaces[self::NS_CALENDARSERVER] = 'cs'; $server->propertyMap['{' . self::NS_CALDAV . '}supported-calendar-component-set'] = 'Sabre_CalDAV_Property_SupportedCalendarComponentSet'; - $server->propertyMap['{' . self::NS_CALDAV . '}schedule-calendar-transp'] = 'Sabre_CalDAV_Property_ScheduleCalendarTransp'; $server->resourceTypeMapping['Sabre_CalDAV_ICalendar'] = '{urn:ietf:params:xml:ns:caldav}calendar'; $server->resourceTypeMapping['Sabre_CalDAV_Schedule_IOutbox'] = '{urn:ietf:params:xml:ns:caldav}schedule-outbox'; $server->resourceTypeMapping['Sabre_CalDAV_Principal_ProxyRead'] = '{http://calendarserver.org/ns/}calendar-proxy-read'; $server->resourceTypeMapping['Sabre_CalDAV_Principal_ProxyWrite'] = '{http://calendarserver.org/ns/}calendar-proxy-write'; - $server->resourceTypeMapping['Sabre_CalDAV_Notifications_ICollection'] = '{' . self::NS_CALENDARSERVER . '}notification'; array_push($server->protectedProperties, @@ -200,9 +205,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { // CalendarServer extensions '{' . self::NS_CALENDARSERVER . '}getctag', '{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for', - '{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for', - '{' . self::NS_CALENDARSERVER . '}notification-URL', - '{' . self::NS_CALENDARSERVER . '}notificationtype' + '{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for' ); } @@ -223,13 +226,6 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { // unknownMethod event. return false; case 'POST' : - - // Checking if this is a text/calendar content type - $contentType = $this->server->httpRequest->getHeader('Content-Type'); - if (strpos($contentType, 'text/calendar')!==0) { - return; - } - // Checking if we're talking to an outbox try { $node = $this->server->tree->getNodeForPath($uri); @@ -239,7 +235,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { if (!$node instanceof Sabre_CalDAV_Schedule_IOutbox) return; - $this->outboxRequest($node, $uri); + $this->outboxRequest($node); return false; } @@ -352,7 +348,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { if (in_array($calProp,$requestedProperties)) { $addresses = $node->getAlternateUriSet(); - $addresses[] = $this->server->getBaseUri() . $node->getPrincipalUrl() . '/'; + $addresses[] = $this->server->getBaseUri() . $node->getPrincipalUrl(); unset($requestedProperties[$calProp]); $returnedProperties[200][$calProp] = new Sabre_DAV_Property_HrefList($addresses, false); @@ -394,31 +390,8 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { } - // notification-URL property - $notificationUrl = '{' . self::NS_CALENDARSERVER . '}notification-URL'; - if (($index = array_search($notificationUrl, $requestedProperties)) !== false) { - $principalId = $node->getName(); - $calendarHomePath = 'calendars/' . $principalId . '/notifications/'; - unset($requestedProperties[$index]); - $returnedProperties[200][$notificationUrl] = new Sabre_DAV_Property_Href($calendarHomePath); - } - } // instanceof IPrincipal - if ($node instanceof Sabre_CalDAV_Notifications_INode) { - - $propertyName = '{' . self::NS_CALENDARSERVER . '}notificationtype'; - if (($index = array_search($propertyName, $requestedProperties)) !== false) { - - $returnedProperties[200][$propertyName] = - $node->getNotificationType(); - - unset($requestedProperties[$index]); - - } - - } // instanceof Notifications_INode - if ($node instanceof Sabre_CalDAV_ICalendarObject) { // The calendar-data property is not supposed to be a 'real' @@ -451,11 +424,11 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { public function calendarMultiGetReport($dom) { $properties = array_keys(Sabre_DAV_XMLUtil::parseProperties($dom->firstChild)); - $hrefElems = $dom->getElementsByTagNameNS('DAV:','href'); + $hrefElems = $dom->getElementsByTagNameNS('urn:DAV','href'); $xpath = new DOMXPath($dom); $xpath->registerNameSpace('cal',Sabre_CalDAV_Plugin::NS_CALDAV); - $xpath->registerNameSpace('dav','DAV:'); + $xpath->registerNameSpace('dav','urn:DAV'); $expand = $xpath->query('/cal:calendar-multiget/dav:prop/cal:calendar-data/cal:expand'); if ($expand->length>0) { @@ -465,8 +438,8 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { if(!$start || !$end) { throw new Sabre_DAV_Exception_BadRequest('The "start" and "end" attributes are required for the CALDAV:expand element'); } - $start = VObject\DateTimeParser::parseDateTime($start); - $end = VObject\DateTimeParser::parseDateTime($end); + $start = Sabre_VObject_DateTimeParser::parseDateTime($start); + $end = Sabre_VObject_DateTimeParser::parseDateTime($end); if ($end <= $start) { throw new Sabre_DAV_Exception_BadRequest('The end-date must be larger than the start-date in the expand element.'); @@ -485,7 +458,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { list($objProps) = $this->server->getPropertiesForPath($uri,$properties); if ($expand && isset($objProps[200]['{' . self::NS_CALDAV . '}calendar-data'])) { - $vObject = VObject\Reader::read($objProps[200]['{' . self::NS_CALDAV . '}calendar-data']); + $vObject = Sabre_VObject_Reader::read($objProps[200]['{' . self::NS_CALDAV . '}calendar-data']); $vObject->expand($start, $end); $objProps[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize(); } @@ -494,12 +467,9 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { } - $prefer = $this->server->getHTTPPRefer(); - $this->server->httpResponse->sendStatus(207); $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); - $this->server->httpResponse->setHeader('Vary','Brief,Prefer'); - $this->server->httpResponse->sendBody($this->server->generateMultiStatus($propertyList, $prefer['return-minimal'])); + $this->server->httpResponse->sendBody($this->server->generateMultiStatus($propertyList)); } @@ -517,95 +487,54 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { $parser = new Sabre_CalDAV_CalendarQueryParser($dom); $parser->parse(); - $node = $this->server->tree->getNodeForPath($this->server->getRequestUri()); - $depth = $this->server->getHTTPDepth(0); - - // The default result is an empty array - $result = array(); + $requestedCalendarData = true; + $requestedProperties = $parser->requestedProperties; - // The calendarobject was requested directly. In this case we handle - // this locally. - if ($depth == 0 && $node instanceof Sabre_CalDAV_ICalendarObject) { + if (!in_array('{urn:ietf:params:xml:ns:caldav}calendar-data', $requestedProperties)) { - $requestedCalendarData = true; - $requestedProperties = $parser->requestedProperties; + // We always retrieve calendar-data, as we need it for filtering. + $requestedProperties[] = '{urn:ietf:params:xml:ns:caldav}calendar-data'; - if (!in_array('{urn:ietf:params:xml:ns:caldav}calendar-data', $requestedProperties)) { - - // We always retrieve calendar-data, as we need it for filtering. - $requestedProperties[] = '{urn:ietf:params:xml:ns:caldav}calendar-data'; - - // If calendar-data wasn't explicitly requested, we need to remove - // it after processing. - $requestedCalendarData = false; - } + // If calendar-data wasn't explicitly requested, we need to remove + // it after processing. + $requestedCalendarData = false; + } - $properties = $this->server->getPropertiesForPath( - $this->server->getRequestUri(), - $requestedProperties, - 0 - ); + // These are the list of nodes that potentially match the requirement + $candidateNodes = $this->server->getPropertiesForPath( + $this->server->getRequestUri(), + $requestedProperties, + $this->server->getHTTPDepth(0) + ); - // This array should have only 1 element, the first calendar - // object. - $properties = current($properties); + $verifiedNodes = array(); - // If there wasn't any calendar-data returned somehow, we ignore - // this. - if (isset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'])) { + $validator = new Sabre_CalDAV_CalendarQueryValidator(); - $validator = new Sabre_CalDAV_CalendarQueryValidator(); - $vObject = VObject\Reader::read($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']); - if ($validator->validate($vObject,$parser->filters)) { + foreach($candidateNodes as $node) { - // If the client didn't require the calendar-data property, - // we won't give it back. - if (!$requestedCalendarData) { - unset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']); - } else { - if ($parser->expand) { - $vObject->expand($parser->expand['start'], $parser->expand['end']); - $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize(); - } - } + // If the node didn't have a calendar-data property, it must not be a calendar object + if (!isset($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'])) + continue; - $result = array($properties); + $vObject = Sabre_VObject_Reader::read($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']); + if ($validator->validate($vObject,$parser->filters)) { + if (!$requestedCalendarData) { + unset($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']); } - - } - - } - // If we're dealing with a calendar, the calendar itself is responsible - // for the calendar-query. - if ($node instanceof Sabre_CalDAV_ICalendar && $depth = 1) { - - $nodePaths = $node->calendarQuery($parser->filters); - - foreach($nodePaths as $path) { - - list($properties) = - $this->server->getPropertiesForPath($this->server->getRequestUri() . '/' . $path, $parser->requestedProperties); - if ($parser->expand) { - // We need to do some post-processing - $vObject = VObject\Reader::read($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']); $vObject->expand($parser->expand['start'], $parser->expand['end']); - $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize(); + $node[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize(); } - - $result[] = $properties; - + $verifiedNodes[] = $node; } } - $prefer = $this->server->getHTTPPRefer(); - $this->server->httpResponse->sendStatus(207); $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); - $this->server->httpResponse->setHeader('Vary','Brief,Prefer'); - $this->server->httpResponse->sendBody($this->server->generateMultiStatus($result, $prefer['return-minimal'])); + $this->server->httpResponse->sendBody($this->server->generateMultiStatus($verifiedNodes)); } @@ -632,10 +561,10 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { } if ($start) { - $start = VObject\DateTimeParser::parseDateTime($start); + $start = Sabre_VObject_DateTimeParser::parseDateTime($start); } if ($end) { - $end = VObject\DateTimeParser::parseDateTime($end); + $end = Sabre_VObject_DateTimeParser::parseDateTime($end); } if (!$start && !$end) { @@ -654,33 +583,15 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { throw new Sabre_DAV_Exception_NotImplemented('The free-busy-query REPORT is only implemented on calendars'); } - // Doing a calendar-query first, to make sure we get the most - // performance. - $urls = $calendar->calendarQuery(array( - 'name' => 'VCALENDAR', - 'comp-filters' => array( - array( - 'name' => 'VEVENT', - 'comp-filters' => array(), - 'prop-filters' => array(), - 'is-not-defined' => false, - 'time-range' => array( - 'start' => $start, - 'end' => $end, - ), - ), - ), - 'prop-filters' => array(), - 'is-not-defined' => false, - 'time-range' => null, - )); - - $objects = array_map(function($url) use ($calendar) { - $obj = $calendar->getChild($url)->get(); + $objects = array_map(function($child) { + $obj = $child->get(); + if (is_resource($obj)) { + $obj = stream_get_contents($obj); + } return $obj; - }, $urls); + }, $calendar->getChildren()); - $generator = new VObject\FreeBusyGenerator(); + $generator = new Sabre_VObject_FreeBusyGenerator(); $generator->setObjects($objects); $generator->setTimeRange($start, $end); $result = $generator->getResult(); @@ -709,7 +620,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { if (!$node instanceof Sabre_CalDAV_ICalendarObject) return; - $this->validateICalendar($data, $path); + $this->validateICalendar($data); } @@ -729,52 +640,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { if (!$parentNode instanceof Sabre_CalDAV_Calendar) return; - $this->validateICalendar($data, $path); - - } - - /** - * This event is triggered before any HTTP request is handled. - * - * We use this to intercept GET calls to notification nodes, and return the - * proper response. - * - * @param string $method - * @param string $path - * @return void - */ - public function beforeMethod($method, $path) { - - if ($method!=='GET') return; - - try { - $node = $this->server->tree->getNodeForPath($path); - } catch (Sabre_DAV_Exception_NotFound $e) { - return; - } - - if (!$node instanceof Sabre_CalDAV_Notifications_INode) - return; - - if (!$this->server->checkPreconditions(true)) return false; - - $dom = new DOMDocument('1.0', 'UTF-8'); - $dom->formatOutput = true; - - $root = $dom->createElement('cs:notification'); - foreach($this->server->xmlNamespaces as $namespace => $prefix) { - $root->setAttribute('xmlns:' . $prefix, $namespace); - } - - $dom->appendChild($root); - $node->getNotificationType()->serializeBody($this->server, $root); - - $this->server->httpResponse->setHeader('Content-Type','application/xml'); - $this->server->httpResponse->setHeader('ETag',$node->getETag()); - $this->server->httpResponse->sendStatus(200); - $this->server->httpResponse->sendBody($dom->saveXML()); - - return false; + $this->validateICalendar($data); } @@ -784,10 +650,9 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { * An exception is thrown if it's not. * * @param resource|string $data - * @param string $path * @return void */ - protected function validateICalendar(&$data, $path) { + protected function validateICalendar(&$data) { // If it's a stream, we convert it to a string first. if (is_resource($data)) { @@ -799,9 +664,9 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { try { - $vobj = VObject\Reader::read($data); + $vobj = Sabre_VObject_Reader::read($data); - } catch (VObject\ParseException $e) { + } catch (Sabre_VObject_ParseException $e) { throw new Sabre_DAV_Exception_UnsupportedMediaType('This resource only supports valid iCalendar 2.0 data. Parse error: ' . $e->getMessage()); @@ -811,11 +676,6 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { throw new Sabre_DAV_Exception_UnsupportedMediaType('This collection can only support iCalendar objects.'); } - // Get the Supported Components for the target calendar - list($parentPath,$object) = Sabre_Dav_URLUtil::splitPath($path); - $calendarProperties = $this->server->getProperties($parentPath,array('{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set')); - $supportedComponents = $calendarProperties['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']->getValue(); - $foundType = null; $foundUID = null; foreach($vobj->getComponents() as $component) { @@ -827,9 +687,6 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { case 'VJOURNAL' : if (is_null($foundType)) { $foundType = $component->name; - if (!in_array($foundType, $supportedComponents)) { - throw new Sabre_CalDAV_Exception_InvalidComponentType('This calendar only supports ' . implode(', ', $supportedComponents) . '. We found a ' . $foundType); - } if (!isset($component->UID)) { throw new Sabre_DAV_Exception_BadRequest('Every ' . $component->name . ' component must have an UID'); } @@ -854,81 +711,12 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { } /** - * This method handles POST requests to the schedule-outbox. - * - * Currently, two types of requests are support: - * * FREEBUSY requests from RFC 6638 - * * Simple iTIP messages from draft-desruisseaux-caldav-sched-04 - * - * The latter is from an expired early draft of the CalDAV scheduling - * extensions, but iCal depends on a feature from that spec, so we - * implement it. + * This method handles POST requests to the schedule-outbox * * @param Sabre_CalDAV_Schedule_IOutbox $outboxNode - * @param string $outboxUri - * @return void - */ - public function outboxRequest(Sabre_CalDAV_Schedule_IOutbox $outboxNode, $outboxUri) { - - // Parsing the request body - try { - $vObject = VObject\Reader::read($this->server->httpRequest->getBody(true)); - } catch (VObject\ParseException $e) { - throw new Sabre_DAV_Exception_BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage()); - } - - // The incoming iCalendar object must have a METHOD property, and a - // component. The combination of both determines what type of request - // this is. - $componentType = null; - foreach($vObject->getComponents() as $component) { - if ($component->name !== 'VTIMEZONE') { - $componentType = $component->name; - break; - } - } - if (is_null($componentType)) { - throw new Sabre_DAV_Exception_BadRequest('We expected at least one VTODO, VJOURNAL, VFREEBUSY or VEVENT component'); - } - - // Validating the METHOD - $method = strtoupper((string)$vObject->METHOD); - if (!$method) { - throw new Sabre_DAV_Exception_BadRequest('A METHOD property must be specified in iTIP messages'); - } - - // So we support two types of requests: - // - // REQUEST with a VFREEBUSY component - // REQUEST, REPLY, ADD, CANCEL on VEVENT components - - $acl = $this->server->getPlugin('acl'); - - if ($componentType === 'VFREEBUSY' && $method === 'REQUEST') { - - $acl && $acl->checkPrivileges($outboxUri,'{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}schedule-query-freebusy'); - $this->handleFreeBusyRequest($outboxNode, $vObject); - - } elseif ($componentType === 'VEVENT' && in_array($method, array('REQUEST','REPLY','ADD','CANCEL'))) { - - $acl && $acl->checkPrivileges($outboxUri,'{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}schedule-post-vevent'); - $this->handleEventNotification($outboxNode, $vObject); - - } else { - - throw new Sabre_DAV_Exception_NotImplemented('SabreDAV supports only VFREEBUSY (REQUEST) and VEVENT (REQUEST, REPLY, ADD, CANCEL)'); - - } - - } - - /** - * This method handles the REQUEST, REPLY, ADD and CANCEL methods for - * VEVENT iTip messages. - * * @return void */ - protected function handleEventNotification(Sabre_CalDAV_Schedule_IOutbox $outboxNode, VObject\Component $vObject) { + public function outboxRequest(Sabre_CalDAV_Schedule_IOutbox $outboxNode) { $originator = $this->server->httpRequest->getHeader('Originator'); $recipients = $this->server->httpRequest->getHeader('Recipient'); @@ -972,10 +760,38 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { throw new Sabre_DAV_Exception_Forbidden('The addresses specified in the Originator header did not match any addresses in the owners calendar-user-address-set header'); } - $result = $this->iMIPMessage($originator, $recipients, $vObject, $principal); - $this->server->httpResponse->sendStatus(200); - $this->server->httpResponse->setHeader('Content-Type','application/xml'); - $this->server->httpResponse->sendBody($this->generateScheduleResponse($result)); + try { + $vObject = Sabre_VObject_Reader::read($this->server->httpRequest->getBody(true)); + } catch (Sabre_VObject_ParseException $e) { + throw new Sabre_DAV_Exception_BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage()); + } + + // Checking for the object type + $componentType = null; + foreach($vObject->getComponents() as $component) { + if ($component->name !== 'VTIMEZONE') { + $componentType = $component->name; + break; + } + } + if (is_null($componentType)) { + throw new Sabre_DAV_Exception_BadRequest('We expected at least one VTODO, VJOURNAL, VFREEBUSY or VEVENT component'); + } + + // Validating the METHOD + $method = strtoupper((string)$vObject->METHOD); + if (!$method) { + throw new Sabre_DAV_Exception_BadRequest('A METHOD property must be specified in iTIP messages'); + } + + if (in_array($method, array('REQUEST','REPLY','ADD','CANCEL')) && $componentType==='VEVENT') { + $result = $this->iMIPMessage($originator, $recipients, $vObject); + $this->server->httpResponse->sendStatus(200); + $this->server->httpResponse->setHeader('Content-Type','application/xml'); + $this->server->httpResponse->sendBody($this->generateScheduleResponse($result)); + } else { + throw new Sabre_DAV_Exception_NotImplemented('This iTIP method is currently not implemented'); + } } @@ -997,15 +813,15 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { * * @param string $originator * @param array $recipients - * @param Sabre\VObject\Component $vObject + * @param Sabre_VObject_Component $vObject * @return array */ - protected function iMIPMessage($originator, array $recipients, VObject\Component $vObject, $principal) { + protected function iMIPMessage($originator, array $recipients, Sabre_VObject_Component $vObject) { if (!$this->imipHandler) { $resultStatus = '5.2;This server does not support this operation'; } else { - $this->imipHandler->sendMessage($originator, $recipients, $vObject, $principal); + $this->imipHandler->sendMessage($originator, $recipients, $vObject); $resultStatus = '2.0;Success'; } @@ -1016,6 +832,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { return $result; + } /** @@ -1061,204 +878,6 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin { } /** - * This method is responsible for parsing a free-busy query request and - * returning it's result. - * - * @param Sabre_CalDAV_Schedule_IOutbox $outbox - * @param string $request - * @return string - */ - protected function handleFreeBusyRequest(Sabre_CalDAV_Schedule_IOutbox $outbox, VObject\Component $vObject) { - - $vFreeBusy = $vObject->VFREEBUSY; - $organizer = $vFreeBusy->organizer; - - $organizer = (string)$organizer; - - // Validating if the organizer matches the owner of the inbox. - $owner = $outbox->getOwner(); - - $caldavNS = '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}'; - - $uas = $caldavNS . 'calendar-user-address-set'; - $props = $this->server->getProperties($owner,array($uas)); - - if (empty($props[$uas]) || !in_array($organizer, $props[$uas]->getHrefs())) { - throw new Sabre_DAV_Exception_Forbidden('The organizer in the request did not match any of the addresses for the owner of this inbox'); - } - - if (!isset($vFreeBusy->ATTENDEE)) { - throw new Sabre_DAV_Exception_BadRequest('You must at least specify 1 attendee'); - } - - $attendees = array(); - foreach($vFreeBusy->ATTENDEE as $attendee) { - $attendees[]= (string)$attendee; - } - - - if (!isset($vFreeBusy->DTSTART) || !isset($vFreeBusy->DTEND)) { - throw new Sabre_DAV_Exception_BadRequest('DTSTART and DTEND must both be specified'); - } - - $startRange = $vFreeBusy->DTSTART->getDateTime(); - $endRange = $vFreeBusy->DTEND->getDateTime(); - - $results = array(); - foreach($attendees as $attendee) { - $results[] = $this->getFreeBusyForEmail($attendee, $startRange, $endRange, $vObject); - } - - $dom = new DOMDocument('1.0','utf-8'); - $dom->formatOutput = true; - $scheduleResponse = $dom->createElement('cal:schedule-response'); - foreach($this->server->xmlNamespaces as $namespace=>$prefix) { - - $scheduleResponse->setAttribute('xmlns:' . $prefix,$namespace); - - } - $dom->appendChild($scheduleResponse); - - foreach($results as $result) { - $response = $dom->createElement('cal:response'); - - $recipient = $dom->createElement('cal:recipient'); - $recipientHref = $dom->createElement('d:href'); - - $recipientHref->appendChild($dom->createTextNode($result['href'])); - $recipient->appendChild($recipientHref); - $response->appendChild($recipient); - - $reqStatus = $dom->createElement('cal:request-status'); - $reqStatus->appendChild($dom->createTextNode($result['request-status'])); - $response->appendChild($reqStatus); - - if (isset($result['calendar-data'])) { - - $calendardata = $dom->createElement('cal:calendar-data'); - $calendardata->appendChild($dom->createTextNode(str_replace("\r\n","\n",$result['calendar-data']->serialize()))); - $response->appendChild($calendardata); - - } - $scheduleResponse->appendChild($response); - } - - $this->server->httpResponse->sendStatus(200); - $this->server->httpResponse->setHeader('Content-Type','application/xml'); - $this->server->httpResponse->sendBody($dom->saveXML()); - - } - - /** - * Returns free-busy information for a specific address. The returned - * data is an array containing the following properties: - * - * calendar-data : A VFREEBUSY VObject - * request-status : an iTip status code. - * href: The principal's email address, as requested - * - * The following request status codes may be returned: - * * 2.0;description - * * 3.7;description - * - * @param string $email address - * @param DateTime $start - * @param DateTime $end - * @param Sabre_VObject_Component $request - * @return Sabre_VObject_Component - */ - protected function getFreeBusyForEmail($email, DateTime $start, DateTime $end, VObject\Component $request) { - - $caldavNS = '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}'; - - $aclPlugin = $this->server->getPlugin('acl'); - if (substr($email,0,7)==='mailto:') $email = substr($email,7); - - $result = $aclPlugin->principalSearch( - array('{http://sabredav.org/ns}email-address' => $email), - array( - '{DAV:}principal-URL', $caldavNS . 'calendar-home-set', - '{http://sabredav.org/ns}email-address', - ) - ); - - if (!count($result)) { - return array( - 'request-status' => '3.7;Could not find principal', - 'href' => 'mailto:' . $email, - ); - } - - if (!isset($result[0][200][$caldavNS . 'calendar-home-set'])) { - return array( - 'request-status' => '3.7;No calendar-home-set property found', - 'href' => 'mailto:' . $email, - ); - } - $homeSet = $result[0][200][$caldavNS . 'calendar-home-set']->getHref(); - - // Grabbing the calendar list - $objects = array(); - foreach($this->server->tree->getNodeForPath($homeSet)->getChildren() as $node) { - if (!$node instanceof Sabre_CalDAV_ICalendar) { - continue; - } - $aclPlugin->checkPrivileges($homeSet . $node->getName() ,$caldavNS . 'read-free-busy'); - - // Getting the list of object uris within the time-range - $urls = $node->calendarQuery(array( - 'name' => 'VCALENDAR', - 'comp-filters' => array( - array( - 'name' => 'VEVENT', - 'comp-filters' => array(), - 'prop-filters' => array(), - 'is-not-defined' => false, - 'time-range' => array( - 'start' => $start, - 'end' => $end, - ), - ), - ), - 'prop-filters' => array(), - 'is-not-defined' => false, - 'time-range' => null, - )); - - $calObjects = array_map(function($url) use ($node) { - $obj = $node->getChild($url)->get(); - return $obj; - }, $urls); - - $objects = array_merge($objects,$calObjects); - - } - - $vcalendar = VObject\Component::create('VCALENDAR'); - $vcalendar->VERSION = '2.0'; - $vcalendar->METHOD = 'REPLY'; - $vcalendar->CALSCALE = 'GREGORIAN'; - $vcalendar->PRODID = '-//SabreDAV//SabreDAV ' . Sabre_DAV_Version::VERSION . '//EN'; - - $generator = new VObject\FreeBusyGenerator(); - $generator->setObjects($objects); - $generator->setTimeRange($start, $end); - $generator->setBaseObject($vcalendar); - - $result = $generator->getResult(); - - $vcalendar->VFREEBUSY->ATTENDEE = 'mailto:' . $email; - $vcalendar->VFREEBUSY->UID = (string)$request->VFREEBUSY->UID; - $vcalendar->VFREEBUSY->ORGANIZER = clone $request->VFREEBUSY->ORGANIZER; - - return array( - 'calendar-data' => $result, - 'request-status' => '2.0;Success', - 'href' => 'mailto:' . $email, - ); - } - - /** * This method is used to generate HTML output for the * Sabre_DAV_Browser_Plugin. This allows us to generate an interface users * can use to create new calendars. |