/** * This method is responsible for parsing a free-busy query request and * returning it's result. * * @param Sabre_DAV_INode $node * @param string $request * @return string */ protected function handleFreeBusyRequest(Sabre_CalDAV_Schedule_IOutbox $outbox, $request) { $vObject = Sabre_VObject_Reader::read($request); $method = (string) $vObject->method; if ($method !== 'REQUEST') { throw new Sabre_DAV_Exception_BadRequest('The iTip object must have a METHOD:REQUEST property'); } $vFreeBusy = $vObject->VFREEBUSY; if (!$vFreeBusy) { throw new Sabre_DAV_Exception_BadRequest('The iTip object must have a VFREEBUSY component'); } $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 $k => $attendee) { $results[] = $this->getFreeBusyForEmailTine20($attendee, $startRange, $endRange, $vObject); } $dom = new DOMDocument('1.0', 'utf-8'); $dom->formatOutput = true; $scheduleResponse = $dom->createElementNS(Sabre_CalDAV_Plugin::NS_CALDAV, 'cal:schedule-response'); $dom->appendChild($scheduleResponse); foreach ($results as $result) { $response = $dom->createElement('cal:response'); $recipient = $dom->createElement('cal:recipient'); $recipient->appendChild($dom->createTextNode($result['href'])); $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); } return $dom->saveXML(); }
function testResourceType() { $tree = array(new Sabre_CardDAV_DirectoryMock('directory')); $server = new Sabre_DAV_Server($tree); $plugin = new Sabre_CardDAV_Plugin(); $server->addPlugin($plugin); $props = $server->getProperties('directory', array('{DAV:}resourcetype')); $this->assertTrue($props['{DAV:}resourcetype']->is('{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}directory')); }
/** * 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()); }
function testSupportedReportSet() { $fakeServer = new Sabre_DAV_Server(new Sabre_DAV_ObjectTree(new Sabre_DAV_SimpleDirectory('bla'))); $plugin = new Sabre_DAV_Auth_Plugin(new Sabre_DAV_Auth_MockBackend(), 'realm'); $fakeServer->addPlugin($plugin); $props = $fakeServer->getProperties('', array('{DAV:}supported-report-set')); $this->assertArrayHasKey('{DAV:}supported-report-set', $props); $this->assertTrue($props['{DAV:}supported-report-set'] instanceof Sabre_DAV_Property_SupportedReportSet); $this->assertEquals(array('{DAV:}expand-property'), $props['{DAV:}supported-report-set']->getValue()); }
/** * Adds all CardDAV-specific properties * * @param string $path * @param Sabre_DAV_INode $node * @param array $requestedProperties * @param array $returnedProperties * @return void */ public function beforeGetProperties($path, Sabre_DAV_INode $node, array &$requestedProperties, array &$returnedProperties) { if ($node instanceof Sabre_DAVACL_IPrincipal) { // calendar-home-set property $addHome = '{' . self::NS_CARDDAV . '}addressbook-home-set'; if (in_array($addHome, $requestedProperties)) { $principalId = $node->getName(); $addressbookHomePath = self::ADDRESSBOOK_ROOT . '/' . $principalId . '/'; unset($requestedProperties[array_search($addHome, $requestedProperties)]); $returnedProperties[200][$addHome] = new Sabre_DAV_Property_Href($addressbookHomePath); } $directories = '{' . self::NS_CARDDAV . '}directory-gateway'; if ($this->directories && in_array($directories, $requestedProperties)) { unset($requestedProperties[array_search($directories, $requestedProperties)]); $returnedProperties[200][$directories] = new Sabre_DAV_Property_HrefList($this->directories); } } if ($node instanceof Sabre_CardDAV_ICard) { // The address-data property is not supposed to be a 'real' // property, but in large chunks of the spec it does act as such. // Therefore we simply expose it as a property. $addressDataProp = '{' . self::NS_CARDDAV . '}address-data'; if (in_array($addressDataProp, $requestedProperties)) { unset($requestedProperties[$addressDataProp]); $val = $node->get(); if (is_resource($val)) { $val = stream_get_contents($val); } // Taking out \r to not screw up the xml output $returnedProperties[200][$addressDataProp] = str_replace("\r", "", $val); // The stripping of \r breaks the Mail App in OSX Mountain Lion // this is fixed in master, but not backported. /Tanghus $returnedProperties[200][$addressDataProp] = $val; } } if ($node instanceof Sabre_CardDAV_UserAddressBooks) { $meCardProp = '{http://calendarserver.org/ns/}me-card'; if (in_array($meCardProp, $requestedProperties)) { $props = $this->server->getProperties($node->getOwner(), array('{http://sabredav.org/ns}vcard-url')); if (isset($props['{http://sabredav.org/ns}vcard-url'])) { $returnedProperties[200][$meCardProp] = new Sabre_DAV_Property_Href($props['{http://sabredav.org/ns}vcard-url']); $pos = array_search($meCardProp, $requestedProperties); unset($requestedProperties[$pos]); } } } }
/** * This method handles POST requests to the schedule-outbox * * @param Sabre_CalDAV_Schedule_IOutbox $outboxNode * @return void */ public function outboxRequest(Sabre_CalDAV_Schedule_IOutbox $outboxNode) { $originator = $this->server->httpRequest->getHeader('Originator'); $recipients = $this->server->httpRequest->getHeader('Recipient'); if (!$originator) { throw new Sabre_DAV_Exception_BadRequest('The Originator: header must be specified when making POST requests'); } if (!$recipients) { throw new Sabre_DAV_Exception_BadRequest('The Recipient: header must be specified when making POST requests'); } if (!preg_match('/^mailto:(.*)@(.*)$/', $originator)) { throw new Sabre_DAV_Exception_BadRequest('Originator must start with mailto: and must be valid email address'); } $originator = substr($originator, 7); $recipients = explode(',', $recipients); foreach ($recipients as $k => $recipient) { $recipient = trim($recipient); if (!preg_match('/^mailto:(.*)@(.*)$/', $recipient)) { throw new Sabre_DAV_Exception_BadRequest('Recipients must start with mailto: and must be valid email address'); } $recipient = substr($recipient, 7); $recipients[$k] = $recipient; } // We need to make sure that 'originator' matches one of the email // addresses of the selected principal. $principal = $outboxNode->getOwner(); $props = $this->server->getProperties($principal, array('{' . self::NS_CALDAV . '}calendar-user-address-set')); $addresses = array(); if (isset($props['{' . self::NS_CALDAV . '}calendar-user-address-set'])) { $addresses = $props['{' . self::NS_CALDAV . '}calendar-user-address-set']->getHrefs(); } if (!in_array('mailto:' . $originator, $addresses)) { 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'); } 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') { $this->iMIPMessage($originator, $recipients, $vObject, $principal); $this->server->httpResponse->sendStatus(200); $this->server->httpResponse->sendBody('Messages sent'); } else { throw new Sabre_DAV_Exception_NotImplemented('This iTIP method is currently not implemented'); } }