/** * Returns properties which are specific to this principal */ function PrincipalProperty($tag, $prop, &$reply, &$denied) { dbg_error_log('principal', ': RenderAsXML: Principal Property "%s"', $tag); switch ($tag) { case 'DAV::getcontenttype': $prop->NewElement('getcontenttype', 'httpd/unix-directory'); break; case 'DAV::resourcetype': $prop->NewElement('resourcetype', array(new XMLElement('principal'), new XMLElement('collection'))); break; case 'DAV::displayname': $prop->NewElement('displayname', $this->fullname); break; case 'DAV::principal-URL': $prop->NewElement('principal-URL', $reply->href($this->principal_url)); break; case 'DAV::getlastmodified': $prop->NewElement('getlastmodified', ISODateToHTTPDate($this->modified)); break; case 'DAV::creationdate': $prop->NewElement('creationdate', DateToISODate($this->created)); break; case 'DAV::getcontentlanguage': /** Use the principal's locale by preference, otherwise system default */ $locale = isset($c->current_locale) ? $c->current_locale : ''; if (isset($this->locale) && $this->locale != '') { $locale = $this->locale; } $prop->NewElement('getcontentlanguage', $locale); break; case 'DAV::group-member-set': if (!$this->_is_group) { return false; } $prop->NewElement('group-member-set', $reply->href($this->group_member_set)); break; case 'DAV::group-membership': $prop->NewElement('group-membership', $reply->href($this->GroupMembership())); break; case 'urn:ietf:params:xml:ns:caldav:schedule-inbox-URL': $reply->CalDAVElement($prop, 'schedule-inbox-URL', $reply->href($this->schedule_inbox_url)); break; case 'urn:ietf:params:xml:ns:caldav:schedule-outbox-URL': $reply->CalDAVElement($prop, 'schedule-outbox-URL', $reply->href($this->schedule_outbox_url)); break; case 'http://calendarserver.org/ns/:dropbox-home-URL': $reply->CalendarserverElement($prop, 'dropbox-home-URL', $reply->href($this->dropbox_url)); break; case 'http://calendarserver.org/ns/:xmpp-server': if (!isset($this->xmpp_uri)) { return false; } $reply->CalendarserverElement($prop, 'xmpp-server', $this->xmpp_server); break; case 'http://calendarserver.org/ns/:xmpp-uri': if (!isset($this->xmpp_uri)) { return false; } $reply->CalendarserverElement($prop, 'xmpp-uri', $this->xmpp_uri); break; case 'urn:ietf:params:xml:ns:carddav:addressbook-home-set': $reply->NSElement($prop, $tag, $reply->href($this->addressbook_home_set())); break; case 'urn:ietf:params:xml:ns:caldav:calendar-home-set': $reply->NSElement($prop, $tag, $reply->href($this->calendar_home_set())); break; case 'urn:ietf:params:xml:ns:caldav:calendar-free-busy-set': $reply->CalDAVElement($prop, 'calendar-free-busy-set', $reply->href($this->calendar_free_busy_set())); break; case 'urn:ietf:params:xml:ns:caldav:calendar-user-address-set': $reply->CalDAVElement($prop, 'calendar-user-address-set', $reply->href($this->user_address_set)); break; case 'DAV::owner': // After a careful reading of RFC3744 we see that this must be the principal-URL of the owner $reply->DAVElement($prop, 'owner', $reply->href($this->principal_url)); break; // Empty tag responses. // Empty tag responses. case 'DAV::alternate-URI-set': $prop->NewElement($reply->Tag($tag)); break; case 'SOME-DENIED-PROPERTY': /** @todo indicating the style for future expansion */ $denied[] = $reply->Tag($tag); break; default: return false; break; } return true; }
/** * Return general server-related properties for this URL */ function ResourceProperty($tag, $prop, &$reply, &$denied) { global $c, $session, $request; // dbg_error_log( 'DAVResource', 'Processing "%s" on "%s".', $tag, $this->dav_name ); if ($reply === null) { $reply = $GLOBALS['reply']; } switch ($tag) { case 'DAV::allprop': $property_list = $this->DAV_AllProperties(); $discarded = array(); foreach ($property_list as $k => $v) { $this->ResourceProperty($v, $prop, $reply, $discarded); } break; case 'DAV::href': $prop->NewElement('href', ConstructURL($this->dav_name)); break; case 'DAV::resource-id': if ($this->resource_id > 0) { $reply->DAVElement($prop, 'resource-id', $reply->href(ConstructURL('/.resources/' . $this->resource_id))); } else { return false; } break; case 'DAV::parent-set': $sql = <<<EOQRY SELECT b.parent_container FROM dav_binding b JOIN collection c ON (b.bound_source_id=c.collection_id) WHERE regexp_replace( b.dav_name, '^.*/', c.dav_name ) = :bound_from EOQRY; $qry = new AwlQuery($sql, array(':bound_from' => $this->bound_from())); $parents = array(); if ($qry->Exec('DAVResource', __LINE__, __FILE__) && $qry->rows() > 0) { while ($row = $qry->Fetch()) { $parents[$row->parent_container] = true; } } $parents[preg_replace('{(?<=/)[^/]+/?$}', '', $this->bound_from())] = true; $parents[preg_replace('{(?<=/)[^/]+/?$}', '', $this->dav_name())] = true; $parent_set = $reply->DAVElement($prop, 'parent-set'); foreach ($parents as $parent => $v) { if (preg_match('{^(.*)?/([^/]+)/?$}', $parent, $matches)) { $reply->DAVElement($parent_set, 'parent', array(new XMLElement('href', ConstructURL($matches[1])), new XMLElement('segment', $matches[2]))); } else { if ($parent == '/') { $reply->DAVElement($parent_set, 'parent', array(new XMLElement('href', '/'), new XMLElement('segment', ConstructURL('/') == '/caldav.php/' ? 'caldav.php' : ''))); } } } break; case 'DAV::getcontenttype': if (!isset($this->contenttype) && !$this->_is_collection && !isset($this->resource)) { $this->FetchResource(); } $prop->NewElement('getcontenttype', $this->contenttype); break; case 'DAV::resourcetype': $resourcetypes = $prop->NewElement('resourcetype'); if ($this->_is_collection) { $type_list = $this->GetProperty('resourcetype'); if (!is_array($type_list)) { return true; } // dbg_error_log( 'DAVResource', ':ResourceProperty: "%s" are "%s".', $tag, implode(', ',$type_list) ); foreach ($type_list as $k => $v) { if ($v == '') { continue; } $reply->NSElement($resourcetypes, $v); } if ($this->_is_binding) { $reply->NSElement($resourcetypes, 'http://xmlns.davical.org/davical:webdav-binding'); } } break; case 'DAV::getlastmodified': /** getlastmodified is HTTP Date format: i.e. the Last-Modified header in response to a GET */ $reply->NSElement($prop, $tag, ISODateToHTTPDate($this->GetProperty('modified'))); break; case 'DAV::creationdate': /** creationdate is ISO8601 format */ $reply->NSElement($prop, $tag, DateToISODate($this->GetProperty('created'), true)); break; case 'DAV::getcontentlength': if ($this->_is_collection) { return false; } if (!isset($this->resource)) { $this->FetchResource(); } if (isset($this->resource)) { $reply->NSElement($prop, $tag, strlen($this->resource->caldav_data)); } break; case 'DAV::getcontentlanguage': $locale = isset($c->current_locale) ? $c->current_locale : ''; if (isset($this->locale) && $this->locale != '') { $locale = $this->locale; } $reply->NSElement($prop, $tag, $locale); break; case 'DAV::acl-restrictions': $reply->NSElement($prop, $tag, array(new XMLElement('grant-only'), new XMLElement('no-invert'))); break; case 'DAV::inherited-acl-set': $inherited_acls = array(); if (!$this->_is_collection) { $inherited_acls[] = $reply->href(ConstructURL($this->collection->dav_name)); } $reply->NSElement($prop, $tag, $inherited_acls); break; case 'DAV::owner': // The principal-URL of the owner if ($this->IsExternal()) { $reply->DAVElement($prop, 'owner', $reply->href(ConstructURL($this->collection->bound_from))); } else { $reply->DAVElement($prop, 'owner', $reply->href(ConstructURL(DeconstructURL($this->principal_url())))); } break; case 'DAV::add-member': if (!$this->_is_collection) { return false; } if (isset($c->post_add_member) && $c->post_add_member === false) { return false; } $reply->DAVElement($prop, 'add-member', $reply->href(ConstructURL(DeconstructURL($this->url())) . '?add-member')); break; // Empty tag responses. // Empty tag responses. case 'DAV::group': case 'DAV::alternate-URI-set': $reply->NSElement($prop, $tag); break; case 'DAV::getetag': if ($this->_is_collection) { return false; } $reply->NSElement($prop, $tag, $this->unique_tag()); break; case 'http://calendarserver.org/ns/:getctag': if (!$this->_is_collection) { return false; } $reply->NSElement($prop, $tag, $this->unique_tag()); break; case 'DAV::sync-token': if (!$this->_is_collection) { return false; } $sync_token = $this->sync_token(); if (empty($sync_token)) { return false; } $reply->NSElement($prop, $tag, $sync_token); break; case 'http://calendarserver.org/ns/:calendar-proxy-read-for': $proxy_type = 'read'; case 'http://calendarserver.org/ns/:calendar-proxy-write-for': if (isset($c->disable_caldav_proxy) && $c->disable_caldav_proxy) { return false; } if (!isset($proxy_type)) { $proxy_type = 'write'; } // ProxyFor is an already constructed URL $reply->CalendarserverElement($prop, 'calendar-proxy-' . $proxy_type . '-for', $reply->href($this->principal->ProxyFor($proxy_type))); break; case 'DAV::current-user-privilege-set': if ($this->HavePrivilegeTo('DAV::read-current-user-privilege-set')) { $reply->NSElement($prop, $tag, $this->BuildPrivileges()); } else { $denied[] = $tag; } break; case 'urn:ietf:params:xml:ns:caldav:supported-calendar-data': if (!$this->IsCalendar() && !$this->IsSchedulingCollection()) { return false; } $reply->NSElement($prop, $tag, 'text/calendar'); break; case 'urn:ietf:params:xml:ns:caldav:supported-calendar-component-set': if (!$this->_is_collection) { return false; } if ($this->IsCalendar()) { if (!isset($this->dead_properties)) { $this->FetchDeadProperties(); } if (isset($this->dead_properties[$tag])) { $set_of_components = $this->dead_properties[$tag]; foreach ($set_of_components as $k => $v) { if (preg_match('{(VEVENT|VTODO|VJOURNAL|VTIMEZONE|VFREEBUSY|VPOLL|VAVAILABILITY)}', $v, $matches)) { $set_of_components[$k] = $matches[1]; } else { unset($set_of_components[$k]); } } } else { if (isset($c->default_calendar_components) && is_array($c->default_calendar_components)) { $set_of_components = $c->default_calendar_components; } else { $set_of_components = array('VEVENT', 'VTODO', 'VJOURNAL'); } } } else { if ($this->IsSchedulingCollection()) { $set_of_components = array('VEVENT', 'VTODO', 'VFREEBUSY'); } else { return false; } } $components = array(); foreach ($set_of_components as $v) { $components[] = $reply->NewXMLElement('comp', '', array('name' => $v), 'urn:ietf:params:xml:ns:caldav'); } $reply->CalDAVElement($prop, 'supported-calendar-component-set', $components); break; case 'DAV::supported-method-set': $prop->NewElement('supported-method-set', $this->BuildSupportedMethods()); break; case 'DAV::supported-report-set': $prop->NewElement('supported-report-set', $this->BuildSupportedReports($reply)); break; case 'DAV::supportedlock': $prop->NewElement('supportedlock', new XMLElement('lockentry', array(new XMLElement('lockscope', new XMLElement('exclusive')), new XMLElement('locktype', new XMLElement('write'))))); break; case 'DAV::supported-privilege-set': $prop->NewElement('supported-privilege-set', $request->BuildSupportedPrivileges($reply)); break; case 'DAV::principal-collection-set': $prop->NewElement('principal-collection-set', $reply->href(ConstructURL('/'))); break; case 'DAV::current-user-principal': $prop->NewElement('current-user-principal', $reply->href(ConstructURL(DeconstructURL($request->principal->url())))); break; case 'SOME-DENIED-PROPERTY': /** indicating the style for future expansion */ $denied[] = $reply->Tag($tag); break; case 'urn:ietf:params:xml:ns:caldav:calendar-timezone': if (!$this->_is_collection) { return false; } if (!isset($this->collection->vtimezone) || $this->collection->vtimezone == '') { return false; } $cal = new iCalComponent(); $cal->VCalendar(); $cal->AddComponent(new iCalComponent($this->collection->vtimezone)); $reply->NSElement($prop, $tag, $cal->Render()); break; case 'urn:ietf:params:xml:ns:carddav:address-data': case 'urn:ietf:params:xml:ns:caldav:calendar-data': if ($this->_is_collection) { return false; } if (!isset($c->sync_resource_data_ok) || $c->sync_resource_data_ok == false) { return false; } if (!isset($this->resource)) { $this->FetchResource(); } $reply->NSElement($prop, $tag, $this->resource->caldav_data); break; case 'urn:ietf:params:xml:ns:carddav:max-resource-size': if (!$this->_is_collection || !$this->_is_addressbook) { return false; } $reply->NSElement($prop, $tag, 65500); break; case 'urn:ietf:params:xml:ns:carddav:supported-address-data': if (!$this->_is_collection || !$this->_is_addressbook) { return false; } $address_data = $reply->NewXMLElement('address-data', false, array('content-type' => 'text/vcard', 'version' => '3.0'), 'urn:ietf:params:xml:ns:carddav'); $reply->NSElement($prop, $tag, $address_data); break; case 'DAV::acl': if ($this->HavePrivilegeTo('DAV::read-acl')) { $reply->NSElement($prop, $tag, $this->GetACL($reply)); } else { $denied[] = $tag; } break; case 'http://www.xythos.com/namespaces/StorageServer:ticketdiscovery': case 'DAV::ticketdiscovery': $reply->NSElement($prop, 'http://www.xythos.com/namespaces/StorageServer:ticketdiscovery', $this->BuildTicketinfo($reply)); break; default: $property_value = $this->GetProperty(preg_replace('{^(DAV:|urn:ietf:params:xml:ns:ca(rd|l)dav):}', '', $tag)); if (isset($property_value)) { $reply->NSElement($prop, $tag, $property_value); } else { if (!isset($this->dead_properties)) { $this->FetchDeadProperties(); } if (isset($this->dead_properties[$tag])) { $reply->NSElement($prop, $tag, $this->dead_properties[$tag]); } else { // dbg_error_log( 'DAVResource', 'Request for unsupported property "%s" of path "%s".', $tag, $this->dav_name ); return false; } } } return true; }