/** * PropFind * * This method handler is invoked before any after properties for a * resource are fetched. This allows us to add in any CalDAV specific * properties. * * @param DAV\PropFind $propFind * @param DAV\INode $node * @return void */ function propFind(DAV\PropFind $propFind, DAV\INode $node) { $ns = '{' . self::NS_CALDAV . '}'; if ($node instanceof ICalendarObjectContainer) { $propFind->handle($ns . 'max-resource-size', $this->maxResourceSize); $propFind->handle($ns . 'supported-calendar-data', function () { return new Xml\Property\SupportedCalendarData(); }); $propFind->handle($ns . 'supported-collation-set', function () { return new Xml\Property\SupportedCollationSet(); }); } if ($node instanceof DAVACL\IPrincipal) { $principalUrl = $node->getPrincipalUrl(); $propFind->handle('{' . self::NS_CALDAV . '}calendar-home-set', function () use($principalUrl) { $calendarHomePath = $this->getCalendarHomeForPrincipal($principalUrl) . '/'; return new Href($calendarHomePath); }); // The calendar-user-address-set property is basically mapped to // the {DAV:}alternate-URI-set property. $propFind->handle('{' . self::NS_CALDAV . '}calendar-user-address-set', function () use($node) { $addresses = $node->getAlternateUriSet(); $addresses[] = $this->server->getBaseUri() . $node->getPrincipalUrl() . '/'; return new Href($addresses, false); }); // For some reason somebody thought it was a good idea to add // another one of these properties. We're supporting it too. $propFind->handle('{' . self::NS_CALENDARSERVER . '}email-address-set', function () use($node) { $addresses = $node->getAlternateUriSet(); $emails = []; foreach ($addresses as $address) { if (substr($address, 0, 7) === 'mailto:') { $emails[] = substr($address, 7); } } return new Xml\Property\EmailAddressSet($emails); }); // These two properties are shortcuts for ical to easily find // other principals this principal has access to. $propRead = '{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for'; $propWrite = '{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for'; if ($propFind->getStatus($propRead) === 404 || $propFind->getStatus($propWrite) === 404) { $aclPlugin = $this->server->getPlugin('acl'); $membership = $aclPlugin->getPrincipalMembership($propFind->getPath()); $readList = []; $writeList = []; foreach ($membership as $group) { $groupNode = $this->server->tree->getNodeForPath($group); $listItem = Uri\split($group)[0] . '/'; // If the node is either ap proxy-read or proxy-write // group, we grab the parent principal and add it to the // list. if ($groupNode instanceof Principal\IProxyRead) { $readList[] = $listItem; } if ($groupNode instanceof Principal\IProxyWrite) { $writeList[] = $listItem; } } $propFind->set($propRead, new Href($readList)); $propFind->set($propWrite, new Href($writeList)); } } // instanceof IPrincipal if ($node instanceof ICalendarObject) { // The calendar-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. $propFind->handle('{' . self::NS_CALDAV . '}calendar-data', function () use($node) { $val = $node->get(); if (is_resource($val)) { $val = stream_get_contents($val); } // Taking out \r to not screw up the xml output return str_replace("\r", "", $val); }); } }
/** * serialize * * @param DAV\Server $server * @param \DOMElement $dom * @return void */ public function serialize(DAV\Server $server, \DOMElement $dom) { $document = $dom->ownerDocument; $properties = $this->responseProperties; $xresponse = $document->createElement('d:response'); $dom->appendChild($xresponse); $uri = DAV\URLUtil::encodePath($this->href); // Adding the baseurl to the beginning of the url $uri = $server->getBaseUri() . $uri; $xresponse->appendChild($document->createElement('d:href', $uri)); // The properties variable is an array containing properties, grouped by // HTTP status foreach ($properties as $httpStatus => $propertyGroup) { // The 'href' is also in this array, and it's special cased. // We will ignore it if ($httpStatus == 'href') { continue; } // If there are no properties in this group, we can also just carry on if (!count($propertyGroup)) { continue; } $xpropstat = $document->createElement('d:propstat'); $xresponse->appendChild($xpropstat); $xprop = $document->createElement('d:prop'); $xpropstat->appendChild($xprop); $nsList = $server->xmlNamespaces; foreach ($propertyGroup as $propertyName => $propertyValue) { $propName = null; preg_match('/^{([^}]*)}(.*)$/', $propertyName, $propName); // special case for empty namespaces if ($propName[1] == '') { $currentProperty = $document->createElement($propName[2]); $xprop->appendChild($currentProperty); $currentProperty->setAttribute('xmlns', ''); } else { if (!isset($nsList[$propName[1]])) { $nsList[$propName[1]] = 'x' . count($nsList); } // If the namespace was defined in the top-level xml namespaces, it means // there was already a namespace declaration, and we don't have to worry about it. if (isset($server->xmlNamespaces[$propName[1]])) { $currentProperty = $document->createElement($nsList[$propName[1]] . ':' . $propName[2]); } else { $currentProperty = $document->createElementNS($propName[1], $nsList[$propName[1]] . ':' . $propName[2]); } $xprop->appendChild($currentProperty); } if (is_scalar($propertyValue)) { $text = $document->createTextNode($propertyValue); $currentProperty->appendChild($text); } elseif ($propertyValue instanceof DAV\PropertyInterface) { $propertyValue->serialize($server, $currentProperty); } elseif (!is_null($propertyValue)) { throw new DAV\Exception('Unknown property value type: ' . gettype($propertyValue) . ' for property: ' . $propertyName); } } $xpropstat->appendChild($document->createElement('d:status', $server->httpResponse->getStatusMessage($httpStatus))); } }
/** * serialize * * @param DAV\Server $server * @param \DOMElement $prop * @return void */ public function serialize(DAV\Server $server, \DOMElement $prop) { $doc = $prop->ownerDocument; foreach ($this->locks as $lock) { $activeLock = $doc->createElementNS('DAV:', 'd:activelock'); $prop->appendChild($activeLock); $lockScope = $doc->createElementNS('DAV:', 'd:lockscope'); $activeLock->appendChild($lockScope); $lockScope->appendChild($doc->createElementNS('DAV:', 'd:' . ($lock->scope == DAV\Locks\LockInfo::EXCLUSIVE ? 'exclusive' : 'shared'))); $lockType = $doc->createElementNS('DAV:', 'd:locktype'); $activeLock->appendChild($lockType); $lockType->appendChild($doc->createElementNS('DAV:', 'd:write')); /* {DAV:}lockroot */ if (!self::$hideLockRoot) { $lockRoot = $doc->createElementNS('DAV:', 'd:lockroot'); $activeLock->appendChild($lockRoot); $href = $doc->createElementNS('DAV:', 'd:href'); $href->appendChild($doc->createTextNode($server->getBaseUri() . $lock->uri)); $lockRoot->appendChild($href); } $activeLock->appendChild($doc->createElementNS('DAV:', 'd:depth', $lock->depth == DAV\Server::DEPTH_INFINITY ? 'infinity' : $lock->depth)); $activeLock->appendChild($doc->createElementNS('DAV:', 'd:timeout', 'Second-' . $lock->timeout)); if ($this->revealLockToken) { $lockToken = $doc->createElementNS('DAV:', 'd:locktoken'); $activeLock->appendChild($lockToken); $lockToken->appendChild($doc->createElementNS('DAV:', 'd:href', 'opaquelocktoken:' . $lock->token)); } $activeLock->appendChild($doc->createElementNS('DAV:', 'd:owner', $lock->owner)); } }
/** * REPORT operations to look for comments * * @param string $reportName * @param [] $report * @param string $uri * @return bool * @throws NotFound * @throws ReportNotSupported */ public function onReport($reportName, $report, $uri) { $node = $this->server->tree->getNodeForPath($uri); if (!$node instanceof EntityCollection || $reportName !== self::REPORT_NAME) { throw new ReportNotSupported(); } $args = ['limit' => 0, 'offset' => 0, 'datetime' => null]; $acceptableParameters = [$this::REPORT_PARAM_LIMIT, $this::REPORT_PARAM_OFFSET, $this::REPORT_PARAM_TIMESTAMP]; $ns = '{' . $this::NS_OWNCLOUD . '}'; foreach ($report as $parameter) { if (!in_array($parameter['name'], $acceptableParameters) || empty($parameter['value'])) { continue; } $args[str_replace($ns, '', $parameter['name'])] = $parameter['value']; } if (!is_null($args['datetime'])) { $args['datetime'] = new \DateTime($args['datetime']); } $results = $node->findChildren($args['limit'], $args['offset'], $args['datetime']); $responses = []; foreach ($results as $node) { $nodePath = $this->server->getRequestUri() . '/' . $node->comment->getId(); $resultSet = $this->server->getPropertiesForPath($nodePath, CommentNode::getPropertyNames()); if (isset($resultSet[0]) && isset($resultSet[0][200])) { $responses[] = new Response($this->server->getBaseUri() . $nodePath, [200 => $resultSet[0][200]], 200); } } $xml = $this->server->xml->write('{DAV:}multistatus', new MultiStatus($responses)); $this->server->httpResponse->setStatus(207); $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8'); $this->server->httpResponse->setBody($xml); return false; }
/** * This event is triggered before the usual GET request handler. * * We use this to intercept GET calls to notification nodes, and return the * proper response. * * @param RequestInterface $request * @param ResponseInterface $response * @return void */ function httpGet(RequestInterface $request, ResponseInterface $response) { $path = $request->getPath(); try { $node = $this->server->tree->getNodeForPath($path); } catch (DAV\Exception\NotFound $e) { return; } if (!$node instanceof INode) return; $writer = $this->server->xml->getWriter(); $writer->contextUri = $this->server->getBaseUri(); $writer->openMemory(); $writer->startDocument('1.0', 'UTF-8'); $writer->startElement('{http://calendarserver.org/ns/}notification'); $node->getNotificationType()->xmlSerializeFull($writer); $writer->endElement(); $response->setHeader('Content-Type', 'application/xml'); $response->setHeader('ETag', $node->getETag()); $response->setStatus(200); $response->setBody($writer->outputMemory()); // Return false to break the event chain. return false; }
/** * Serializes this property. * * It will additionally prepend the href property with the server's base uri. * * @param DAV\Server $server * @param \DOMElement $dom * @return void */ public function serialize(DAV\Server $server, \DOMElement $dom) { $prefix = $server->xmlNamespaces['DAV:']; $elem = $dom->ownerDocument->createElement($prefix . ':href'); $elem->nodeValue = ($this->autoPrefix ? $server->getBaseUri() : '') . $this->href; $dom->appendChild($elem); }
/** * Sends the response to a sync-collection request. * * @param string $syncToken * @param string $collectionUrl * @param array $added * @param array $modified * @param array $deleted * @param array $properties * @return void */ protected function sendSyncCollectionResponse($syncToken, $collectionUrl, array $added, array $modified, array $deleted, array $properties) { $fullPaths = []; // Pre-fetching children, if this is possible. foreach (array_merge($added, $modified) as $item) { $fullPath = $collectionUrl . '/' . $item; $fullPaths[] = $fullPath; } $responses = []; foreach ($this->server->getPropertiesForMultiplePaths($fullPaths, $properties) as $fullPath => $props) { // The 'Property_Response' class is responsible for generating a // single {DAV:}response xml element. $responses[] = new DAV\Xml\Element\Response($fullPath, $props); } // Deleted items also show up as 'responses'. They have no properties, // and a single {DAV:}status element set as 'HTTP/1.1 404 Not Found'. foreach ($deleted as $item) { $fullPath = $collectionUrl . '/' . $item; $responses[] = new DAV\Xml\Element\Response($fullPath, [], 404); } $multiStatus = new DAV\Xml\Response\MultiStatus($responses, self::SYNCTOKEN_PREFIX . $syncToken); $this->server->httpResponse->setStatus(207); $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8'); $this->server->httpResponse->setBody($this->server->xml->write('{DAV:}multistatus', $multiStatus, $this->server->getBaseUri())); }
/** * returns a reference to the comments node * * @param Node $node * @return mixed|string */ public function getCommentsLink(Node $node) { $href = $this->server->getBaseUri(); $entryPoint = strrpos($href, '/webdav/'); if ($entryPoint === false) { // in case we end up somewhere else, unexpectedly. return null; } $href = substr_replace($href, '/dav/', $entryPoint); $href .= 'comments/files/' . rawurldecode($node->getId()); return $href; }
/** * returns a reference to the comments node * * @param Node $node * @return mixed|string */ public function getCommentsLink(Node $node) { $href = $this->server->getBaseUri(); $entryPoint = strpos($href, '/remote.php/'); if ($entryPoint === false) { // in case we end up somewhere else, unexpectedly. return null; } $commentsPart = 'dav/comments/files/' . rawurldecode($node->getId()); $href = substr_replace($href, $commentsPart, $entryPoint + strlen('/remote.php/')); return $href; }
/** * Serializes this property. * * It will additionally prepend the href property with the server's base uri. * * @param DAV\Server $server * @param \DOMElement $dom * @return void */ function serialize(DAV\Server $server, \DOMElement $dom) { $prefix = $server->xmlNamespaces['DAV:']; $elem = $dom->ownerDocument->createElement($prefix . ':href'); if ($this->autoPrefix) { $value = $server->getBaseUri() . DAV\URLUtil::encodePath($this->href); } else { $value = $this->href; } $elem->appendChild($dom->ownerDocument->createTextNode($value)); $dom->appendChild($elem); }
/** * Adds in extra information in the xml response. * * This method adds the {DAV:}need-privileges element as defined in rfc3744 * * @param DAV\Server $server * @param \DOMElement $errorNode * @return void */ public function serialize(DAV\Server $server, \DOMElement $errorNode) { $doc = $errorNode->ownerDocument; $np = $doc->createElementNS('DAV:', 'd:need-privileges'); $errorNode->appendChild($np); foreach ($this->privileges as $privilege) { $resource = $doc->createElementNS('DAV:', 'd:resource'); $np->appendChild($resource); $resource->appendChild($doc->createElementNS('DAV:', 'd:href', $server->getBaseUri() . $this->uri)); $priv = $doc->createElementNS('DAV:', 'd:privilege'); $resource->appendChild($priv); preg_match('/^{([^}]*)}(.*)$/', $privilege, $privilegeParts); $priv->appendChild($doc->createElementNS($privilegeParts[1], 'd:' . $privilegeParts[2])); } }
/** * Prepare propfind response for the given nodes * * @param string[] $requestedProps requested properties * @param Node[] nodes nodes for which to fetch and prepare responses * @return Response[] */ public function prepareResponses($requestedProps, $nodes) { $responses = []; foreach ($nodes as $node) { $propFind = new PropFind($node->getPath(), $requestedProps); $this->server->getPropertiesByNode($propFind, $node); // copied from Sabre Server's getPropertiesForPath $result = $propFind->getResultForMultiStatus(); $result['href'] = $propFind->getPath(); $resourceType = $this->server->getResourceTypeForNode($node); if (in_array('{DAV:}collection', $resourceType) || in_array('{DAV:}principal', $resourceType)) { $result['href'] .= '/'; } $responses[] = new Response(rtrim($this->server->getBaseUri(), '/') . $node->getPath(), $result, 200); } return $responses; }
/** * This method serializes the entire notification, as it is used in the * response body. * * @param DAV\Server $server * @param \DOMElement $node * @return void */ function serializeBody(DAV\Server $server, \DOMElement $node) { $doc = $node->ownerDocument; $dt = $doc->createElement('cs:dtstamp'); $this->dtStamp->setTimezone(new \DateTimezone('GMT')); $dt->appendChild($doc->createTextNode($this->dtStamp->format('Ymd\\THis\\Z'))); $node->appendChild($dt); $prop = $doc->createElement('cs:invite-reply'); $node->appendChild($prop); $uid = $doc->createElement('cs:uid'); $uid->appendChild($doc->createTextNode($this->id)); $prop->appendChild($uid); $inReplyTo = $doc->createElement('cs:in-reply-to'); $inReplyTo->appendChild($doc->createTextNode($this->inReplyTo)); $prop->appendChild($inReplyTo); $href = $doc->createElement('d:href'); $href->appendChild($doc->createTextNode($this->href)); $prop->appendChild($href); $nodeName = null; switch ($this->type) { case SharingPlugin::STATUS_ACCEPTED: $nodeName = 'cs:invite-accepted'; break; case SharingPlugin::STATUS_DECLINED: $nodeName = 'cs:invite-declined'; break; } $prop->appendChild($doc->createElement($nodeName)); $hostHref = $doc->createElement('d:href', $server->getBaseUri() . $this->hostUrl); $hostUrl = $doc->createElement('cs:hosturl'); $hostUrl->appendChild($hostHref); $prop->appendChild($hostUrl); if ($this->summary) { $summary = $doc->createElement('cs:summary'); $summary->appendChild($doc->createTextNode($this->summary)); $prop->appendChild($summary); } }
/** * Serializes the property into a DOMElement. * * @param DAV\Server $server * @param \DOMElement $node * @return void */ public function serialize(DAV\Server $server, \DOMElement $node) { $prefix = $server->xmlNamespaces['DAV:']; switch ($this->type) { case self::UNAUTHENTICATED: $node->appendChild($node->ownerDocument->createElement($prefix . ':unauthenticated')); break; case self::AUTHENTICATED: $node->appendChild($node->ownerDocument->createElement($prefix . ':authenticated')); break; case self::HREF: $href = $node->ownerDocument->createElement($prefix . ':href'); $href->nodeValue = $server->getBaseUri() . DAV\URLUtil::encodePath($this->href); $node->appendChild($href); break; } }
/** * Serializes a single access control entry. * * @param \DOMDocument $doc * @param \DOMElement $node * @param array $ace * @param DAV\Server $server * @return void */ private function serializeAce($doc, $node, $ace, DAV\Server $server) { $xace = $doc->createElementNS('DAV:', 'd:ace'); $node->appendChild($xace); $principal = $doc->createElementNS('DAV:', 'd:principal'); $xace->appendChild($principal); switch ($ace['principal']) { case '{DAV:}authenticated': $principal->appendChild($doc->createElementNS('DAV:', 'd:authenticated')); break; case '{DAV:}unauthenticated': $principal->appendChild($doc->createElementNS('DAV:', 'd:unauthenticated')); break; case '{DAV:}all': $principal->appendChild($doc->createElementNS('DAV:', 'd:all')); break; default: $principal->appendChild($doc->createElementNS('DAV:', 'd:href', ($this->prefixBaseUrl ? $server->getBaseUri() : '') . $ace['principal'] . '/')); } $grant = $doc->createElementNS('DAV:', 'd:grant'); $xace->appendChild($grant); $privParts = null; preg_match('/^{([^}]*)}(.*)$/', $ace['privilege'], $privParts); $xprivilege = $doc->createElementNS('DAV:', 'd:privilege'); $grant->appendChild($xprivilege); $xprivilege->appendChild($doc->createElementNS($privParts[1], 'd:' . $privParts[2])); if (isset($ace['protected']) && $ace['protected']) { $xace->appendChild($doc->createElement('d:protected')); } }
/** * This method serializes the entire notification, as it is used in the * response body. * * @param DAV\Server $server * @param \DOMElement $node * @return void */ public function serializeBody(DAV\Server $server, \DOMElement $node) { $doc = $node->ownerDocument; $dt = $doc->createElement('cs:dtstamp'); $this->dtStamp->setTimezone(new \DateTimezone('GMT')); $dt->appendChild($doc->createTextNode($this->dtStamp->format('Ymd\\THis\\Z'))); $node->appendChild($dt); $prop = $doc->createElement('cs:invite-notification'); $node->appendChild($prop); $uid = $doc->createElement('cs:uid'); $uid->appendChild($doc->createTextNode($this->id)); $prop->appendChild($uid); $href = $doc->createElement('d:href'); $href->appendChild($doc->createTextNode($this->href)); $prop->appendChild($href); $nodeName = null; switch ($this->type) { case SharingPlugin::STATUS_ACCEPTED: $nodeName = 'cs:invite-accepted'; break; case SharingPlugin::STATUS_DECLINED: $nodeName = 'cs:invite-declined'; break; case SharingPlugin::STATUS_DELETED: $nodeName = 'cs:invite-deleted'; break; case SharingPlugin::STATUS_NORESPONSE: $nodeName = 'cs:invite-noresponse'; break; } $prop->appendChild($doc->createElement($nodeName)); $hostHref = $doc->createElement('d:href', $server->getBaseUri() . $this->hostUrl); $hostUrl = $doc->createElement('cs:hosturl'); $hostUrl->appendChild($hostHref); $prop->appendChild($hostUrl); $access = $doc->createElement('cs:access'); if ($this->readOnly) { $access->appendChild($doc->createElement('cs:read')); } else { $access->appendChild($doc->createElement('cs:read-write')); } $prop->appendChild($access); $organizerUrl = $doc->createElement('cs:organizer'); // If the organizer contains a 'mailto:' part, it means it should be // treated as absolute. if (strtolower(substr($this->organizer, 0, 7)) === 'mailto:') { $organizerHref = new DAV\Property\Href($this->organizer, false); } else { $organizerHref = new DAV\Property\Href($this->organizer, true); } $organizerHref->serialize($server, $organizerUrl); if ($this->commonName) { $commonName = $doc->createElement('cs:common-name'); $commonName->appendChild($doc->createTextNode($this->commonName)); $organizerUrl->appendChild($commonName); $commonNameOld = $doc->createElement('cs:organizer-cn'); $commonNameOld->appendChild($doc->createTextNode($this->commonName)); $prop->appendChild($commonNameOld); } if ($this->firstName) { $firstName = $doc->createElement('cs:first-name'); $firstName->appendChild($doc->createTextNode($this->firstName)); $organizerUrl->appendChild($firstName); $firstNameOld = $doc->createElement('cs:organizer-first'); $firstNameOld->appendChild($doc->createTextNode($this->firstName)); $prop->appendChild($firstNameOld); } if ($this->lastName) { $lastName = $doc->createElement('cs:last-name'); $lastName->appendChild($doc->createTextNode($this->lastName)); $organizerUrl->appendChild($lastName); $lastNameOld = $doc->createElement('cs:organizer-last'); $lastNameOld->appendChild($doc->createTextNode($this->lastName)); $prop->appendChild($lastNameOld); } $prop->appendChild($organizerUrl); if ($this->summary) { $summary = $doc->createElement('cs:summary'); $summary->appendChild($doc->createTextNode($this->summary)); $prop->appendChild($summary); } if ($this->supportedComponents) { $xcomp = $doc->createElement('cal:supported-calendar-component-set'); $this->supportedComponents->serialize($server, $xcomp); $prop->appendChild($xcomp); } }
/** * beforeGetProperties * * This method handler is invoked before any after properties for a * resource are fetched. This allows us to add in any CalDAV specific * properties. * * @param string $path * @param DAV\INode $node * @param array $requestedProperties * @param array $returnedProperties * @return void */ public function beforeGetProperties($path, DAV\INode $node, &$requestedProperties, &$returnedProperties) { if ($node instanceof DAVACL\IPrincipal) { // calendar-home-set property $calHome = '{' . self::NS_CALDAV . '}calendar-home-set'; if (in_array($calHome, $requestedProperties)) { $principalId = $node->getName(); $calendarHomePath = self::CALENDAR_ROOT . '/' . $principalId . '/'; unset($requestedProperties[array_search($calHome, $requestedProperties)]); $returnedProperties[200][$calHome] = new DAV\Property\Href($calendarHomePath); } // schedule-outbox-URL property $scheduleProp = '{' . self::NS_CALDAV . '}schedule-outbox-URL'; if (in_array($scheduleProp, $requestedProperties)) { $principalId = $node->getName(); $outboxPath = self::CALENDAR_ROOT . '/' . $principalId . '/outbox'; unset($requestedProperties[array_search($scheduleProp, $requestedProperties)]); $returnedProperties[200][$scheduleProp] = new DAV\Property\Href($outboxPath); } // calendar-user-address-set property $calProp = '{' . self::NS_CALDAV . '}calendar-user-address-set'; if (in_array($calProp, $requestedProperties)) { $addresses = $node->getAlternateUriSet(); $addresses[] = $this->server->getBaseUri() . $node->getPrincipalUrl() . '/'; unset($requestedProperties[array_search($calProp, $requestedProperties)]); $returnedProperties[200][$calProp] = new DAV\Property\HrefList($addresses, false); } // These two properties are shortcuts for ical to easily find // other principals this principal has access to. $propRead = '{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for'; $propWrite = '{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for'; if (in_array($propRead, $requestedProperties) || in_array($propWrite, $requestedProperties)) { $aclPlugin = $this->server->getPlugin('acl'); $membership = $aclPlugin->getPrincipalMembership($path); $readList = array(); $writeList = array(); foreach ($membership as $group) { $groupNode = $this->server->tree->getNodeForPath($group); // If the node is either ap proxy-read or proxy-write // group, we grab the parent principal and add it to the // list. if ($groupNode instanceof Principal\IProxyRead) { list($readList[]) = DAV\URLUtil::splitPath($group); } if ($groupNode instanceof Principal\IProxyWrite) { list($writeList[]) = DAV\URLUtil::splitPath($group); } } if (in_array($propRead, $requestedProperties)) { unset($requestedProperties[$propRead]); $returnedProperties[200][$propRead] = new DAV\Property\HrefList($readList); } if (in_array($propWrite, $requestedProperties)) { unset($requestedProperties[$propWrite]); $returnedProperties[200][$propWrite] = new DAV\Property\HrefList($writeList); } } // 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 DAV\Property\Href($calendarHomePath); } } // instanceof IPrincipal if ($node instanceof 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 ICalendarObject) { // The calendar-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. $calDataProp = '{' . Plugin::NS_CALDAV . '}calendar-data'; if (in_array($calDataProp, $requestedProperties)) { unset($requestedProperties[$calDataProp]); $val = $node->get(); if (is_resource($val)) { $val = stream_get_contents($val); } // Taking out \r to not screw up the xml output $returnedProperties[200][$calDataProp] = str_replace("\r", "", $val); } } }