/** * 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()); }
/** * 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'); } }
/** * 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(); }