/** * 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)); } }
/** * 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))); } }
/** * 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'); 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])); } }
/** * 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() . DAV\URLUtil::encodePath($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); } } }
/** * 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-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; } }
/** * 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); } }