diff --git a/inc/DAVResource.php b/inc/DAVResource.php index 4113e7c3..c482ecc3 100644 --- a/inc/DAVResource.php +++ b/inc/DAVResource.php @@ -49,6 +49,16 @@ class DAVResource */ protected $contenttype; + /** + * @var The name which this resource is being retrieved as + */ + protected $bound_dav_name; + + /** + * @var The canonical name which this resource exists at + */ + protected $real_dav_name; + /** * @var An object which is the collection record for this resource, or for it's container */ @@ -117,7 +127,8 @@ class DAVResource */ function __construct( $parameters = null ) { $this->exists = null; - $this->dav_name = null; + $this->bound_dav_name = null; + $this->real_dav_name = null; $this->unique_tag = null; $this->resource = null; $this->collection = null; @@ -158,15 +169,16 @@ class DAVResource if ( $row == null ) return; $this->exists = true; - $this->dav_name = $row->dav_name; - $this->_is_collection = preg_match( '{/$}', $row->dav_name ); + $this->real_dav_name = $row->dav_name; + $this->bound_dav_name = (isset($row->bound_dav_name)? $row->bound_dav_name : $row->dav_name); + $this->_is_collection = preg_match( '{/$}', $this->real_dav_name ); if ( $this->_is_collection ) { $this->contenttype = 'httpd/unix-directory'; $this->collection = (object) array(); - $this->_is_principal = preg_match( '{^/[^/]+/$}', $row->dav_name ); - if ( preg_match( '#^(/principals/[^/]+/[^/]+)/?$#', $row->dav_name, $matches) ) { + $this->_is_principal = preg_match( '{^/[^/]+/$}', $this->real_dav_name ); + if ( preg_match( '#^(/principals/[^/]+/[^/]+)/?$#', $this->real_dav_name, $matches) ) { $this->collection->dav_name = $matches[1].'/'; $this->collection->type = 'principal_link'; $this->_is_principal = true; @@ -176,7 +188,7 @@ class DAVResource $this->resource = (object) array(); } - dbg_error_log( 'DAVResource', ':FromRow: Named "%s" is%s a collection.', $row->dav_name, ($this->_is_collection?'':' not') ); + dbg_error_log( 'DAVResource', ':FromRow: Named "%s" is%s a collection.', $this->real_dav_name, ($this->_is_collection?'':' not') ); foreach( $row AS $k => $v ) { if ( $this->_is_collection ) @@ -205,9 +217,9 @@ class DAVResource $this->collection->type = 'calendar'; else if ( $row->is_addressbook == 't' ) $this->collection->type = 'addressbook'; - else if ( preg_match( '#^((/[^/]+/)\.(in|out)/)[^/]*$#', $this->dav_name, $matches ) ) + else if ( preg_match( '#^((/[^/]+/)\.(in|out)/)[^/]*$#', $this->real_dav_name, $matches ) ) $this->collection->type = 'schedule-'. $matches[3]. 'box'; - else if ( $this->dav_name == '/' ) + else if ( $this->real_dav_name == '/' ) $this->collection->type = 'root'; else $this->collection->type = 'collection'; @@ -237,7 +249,7 @@ class DAVResource function FromPath($inpath) { global $c; - $this->dav_name = DeconstructURL($inpath); + $this->real_dav_name = DeconstructURL($inpath); $this->FetchCollection(); if ( $this->_is_collection ) { @@ -247,7 +259,7 @@ class DAVResource $this->FetchResource(); } dbg_error_log( 'DAVResource', ':FromPath: Path "%s" is%s a collection%s.', - $this->dav_name, ($this->_is_collection?' '.$this->resourcetypes:' not'), ($this->_is_principal?' and a principal':'') ); + $this->real_dav_name, ($this->_is_collection?' '.$this->resourcetypes:' not'), ($this->_is_principal?' and a principal':'') ); } @@ -267,7 +279,7 @@ class DAVResource * The collection URL for this request is therefore the longest row in the result, so we * can "... ORDER BY LENGTH(dav_name) DESC LIMIT 1" */ - dbg_error_log( 'DAVResource', ':FetchCollection: Looking for collection for "%s".', $this->dav_name ); + dbg_error_log( 'DAVResource', ':FetchCollection: Looking for collection for "%s".', $this->real_dav_name ); $this->collection = (object) array( 'collection_id' => -1, @@ -283,11 +295,11 @@ class DAVResource $base_sql .= 'LEFT JOIN time_zone ON (collection.timezone=time_zone.tz_id) '; $base_sql .= 'WHERE '; $sql = $base_sql .'collection.dav_name = :raw_path '; - $params = array( ':raw_path' => $this->dav_name, ':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth ); - if ( !preg_match( '#/$#', $this->dav_name ) ) { + $params = array( ':raw_path' => $this->real_dav_name, ':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth ); + if ( !preg_match( '#/$#', $this->real_dav_name ) ) { $sql .= ' OR collection.dav_name = :up_to_slash OR collection.dav_name = :plus_slash '; - $params[':up_to_slash'] = preg_replace( '#[^/]*$#', '', $this->dav_name); - $params[':plus_slash'] = $this->dav_name.'/'; + $params[':up_to_slash'] = preg_replace( '#[^/]*$#', '', $this->real_dav_name); + $params[':plus_slash'] = $this->real_dav_name.'/'; } $sql .= 'ORDER BY LENGTH(collection.dav_name) DESC LIMIT 1'; $qry = new AwlQuery( $sql, $params ); @@ -298,33 +310,34 @@ class DAVResource $this->collection->type = 'calendar'; else if ( $row->is_addressbook == 't' ) $this->collection->type = 'addressbook'; - else if ( preg_match( '#^((/[^/]+/)\.(in|out)/)[^/]*$#', $this->dav_name, $matches ) ) + else if ( preg_match( '#^((/[^/]+/)\.(in|out)/)[^/]*$#', $this->real_dav_name, $matches ) ) $this->collection->type = 'schedule-'. $matches[3]. 'box'; else $this->collection->type = 'collection'; } - else if ( preg_match( '#^((/[^/]+/)\.(in|out)/)[^/]*$#', $this->dav_name, $matches ) ) { + else if ( preg_match( '#^((/[^/]+/)\.(in|out)/)[^/]*$#', $this->real_dav_name, $matches ) ) { // The request is for a scheduling inbox or outbox (or something inside one) and we should auto-create it $params = array( ':user_no' => $session->user_no, ':parent_container' => $matches[2], ':dav_name' => $matches[1] ); - $params['displayname'] = $session->fullname . ($matches[3] == 'in' ? ' Inbox' : ' Outbox'); - $this->collection->type = 'schedule-'. $matches[3]. 'box'; - $params['resourcetypes'] = sprintf('', $this->collection->type ); + $params[':displayname'] = $session->fullname . ($matches[3] == 'in' ? ' Inbox' : ' Outbox'); + $this->collection_type = 'schedule-'. $matches[3]. 'box'; + $params[':resourcetypes'] = sprintf('', $this->collection_type ); $sql = <<Exec('DAVResource'); dbg_error_log( 'DAVResource', 'Created new collection as "$displayname".' ); - $params = array( ':raw_path' => $this->dav_name, ':session_principal' => $session->principal_id ); + $params = array( ':raw_path' => $this->real_dav_name, ':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth ); $qry = new AwlQuery( $base_sql . ' dav_name = :raw_path', $params ); if ( $qry->Exec('DAVResource') && $qry->rows() == 1 && ($row = $qry->Fetch()) ) { $this->collection = $row; $this->collection->exists = true; + $this->collection->type = $this->collection_type; } } - else if ( preg_match( '#^(/([^/]+)/calendar-proxy-(read|write))/?[^/]*$#', $this->dav_name, $matches ) ) { + else if ( preg_match( '#^(/([^/]+)/calendar-proxy-(read|write))/?[^/]*$#', $this->real_dav_name, $matches ) ) { $this->collection->type = 'proxy'; $this->_is_proxy_request = true; $this->proxy_type = $matches[3]; @@ -332,17 +345,17 @@ EOSQL; $this->collection->dav_displayname = sprintf( '%s proxy %s', $matches[2], $matches[3] ); $this->collection->exists = true; } - else if ( preg_match( '#^(/[^/]+)/?$#', $this->dav_name, $matches) ) { + else if ( preg_match( '#^(/[^/]+)/?$#', $this->real_dav_name, $matches) ) { $this->collection->dav_name = $matches[1].'/'; $this->collection->type = 'principal'; $this->_is_principal = true; } - else if ( preg_match( '#^(/principals/[^/]+/[^/]+)/?$#', $this->dav_name, $matches) ) { + else if ( preg_match( '#^(/principals/[^/]+/[^/]+)/?$#', $this->real_dav_name, $matches) ) { $this->collection->dav_name = $matches[1].'/'; $this->collection->type = 'principal_link'; $this->_is_principal = true; } - else if ( $this->dav_name == '/' ) { + else if ( $this->real_dav_name == '/' ) { $this->collection->dav_name = '/'; $this->collection->type = 'root'; $this->collection->exists = true; @@ -350,16 +363,16 @@ EOSQL; $this->collection->default_privileges = (1 | 16 | 32); } else { - dbg_error_log( 'DAVResource', 'No collection for path "%s".', $this->dav_name ); + dbg_error_log( 'DAVResource', 'No collection for path "%s".', $this->real_dav_name ); $this->collection->exists = false; - $this->collection->dav_name = preg_replace('{/[^/]*$}', '/', $this->dav_name); + $this->collection->dav_name = preg_replace('{/[^/]*$}', '/', $this->real_dav_name); } dbg_error_log( 'DAVResource', ':FetchCollection: Found collection named "%s" of type "%s".', $this->collection->dav_name, $this->collection->type ); - $this->_is_collection = ( $this->collection->dav_name == $this->dav_name || $this->collection->dav_name == $this->dav_name.'/' ); + $this->_is_collection = ( $this->collection->dav_name == $this->real_dav_name || $this->collection->dav_name == $this->real_dav_name.'/' ); if ( $this->_is_collection ) { - $this->dav_name = $this->collection->dav_name; + $this->real_dav_name = $this->collection->dav_name; $this->_is_calendar = ($this->collection->type == 'calendar'); $this->_is_addressbook = ($this->collection->type == 'addressbook'); $this->contenttype = 'httpd/unix-directory'; @@ -388,7 +401,7 @@ EOSQL; */ function FetchPrincipal() { global $c, $session; - $this->principal = new CalDAVPrincipal( array( "path" => $this->dav_name ) ); + $this->principal = new CalDAVPrincipal( array( "path" => $this->real_dav_name ) ); if ( $this->_is_principal && $this->principal->Exists() ) { // $this->contenttype = 'httpd/unix-directory'; $this->exists = true; @@ -413,7 +426,7 @@ EOSQL; SELECT * FROM caldav_data LEFT JOIN calendar_item USING (collection_id,dav_id) WHERE caldav_data.dav_name = :dav_name EOQRY; - $params = array( ':dav_name' => $this->dav_name ); + $params = array( ':dav_name' => $this->real_dav_name ); $qry = new AwlQuery( $sql, $params ); if ( $qry->Exec('DAVResource') && $qry->rows() > 0 ) { @@ -440,7 +453,7 @@ EOQRY; if ( isset($this->dead_properties) ) return; $this->dead_properties = array(); - $qry = new AwlQuery('SELECT property_name, property_value FROM property WHERE dav_name= :dav_name', array(':dav_name' => $this->dav_name) ); + $qry = new AwlQuery('SELECT property_name, property_value FROM property WHERE dav_name= :dav_name', array(':dav_name' => $this->real_dav_name) ); if ( $qry->Exec('DAVResource') ) { while ( $property = $qry->Fetch() ) { $this->dead_properties[$property->property_name] = $property->property_value; @@ -455,7 +468,7 @@ EOQRY; function FetchPrivileges() { global $session, $request; - if ( $this->dav_name == '/' || $this->dav_name == '' ) { + if ( $this->real_dav_name == '/' || $this->real_dav_name == '' ) { $this->privileges = (1 | 16 | 32); // read + read-acl + read-current-user-privilege-set dbg_error_log( 'DAVResource', 'Read permissions for user accessing /' ); return; @@ -489,7 +502,7 @@ EOQRY; $this->privileges = $this->collection->path_privs; if ( is_string($this->privileges) ) $this->privileges = bindec( $this->privileges ); - if ( isset($request->ticket) && $request->ticket->MatchesPath($this->dav_name) ) { + if ( isset($request->ticket) && $request->ticket->MatchesPath($this->real_dav_name) ) { $this->privileges |= $request->ticket->privileges(); dbg_error_log( 'DAVResource', 'Applying permissions for ticket "%s" now: %s', $request->ticket->id(), decbin($this->privileges) ); } @@ -528,7 +541,7 @@ EOQRY; if ( $this->HavePrivilegeTo($privilege) ) return; - $request->NeedPrivilege( $privilege, $this->dav_name ); + $request->NeedPrivilege( $privilege, $this->real_dav_name ); exit(0); // Unecessary, but might clarify things } @@ -764,7 +777,7 @@ EOQRY; * Find the locks that might apply and load them into an array */ $sql = 'SELECT * FROM locks WHERE :this_path::text ~ (\'^\'||dav_name||:match_end)::text'; - $qry = new AwlQuery($sql, array( ':this_path' => $this->dav_name, ':match_end' => ($depth == DEPTH_INFINITY ? '' : '$') ) ); + $qry = new AwlQuery($sql, array( ':this_path' => $this->real_dav_name, ':match_end' => ($depth == DEPTH_INFINITY ? '' : '$') ) ); if ( $qry->Exec('DAVResource',__LINE__,__FILE__) ) { while( $lock_row = $qry->Fetch() ) { $this->_locks_found[$lock_row->opaquelocktoken] = $lock_row; @@ -777,7 +790,7 @@ EOQRY; } foreach( $this->_locks_found AS $lock_token => $lock_row ) { - if ( $lock_row->depth == DEPTH_INFINITY || $lock_row->dav_name == $this->dav_name ) { + if ( $lock_row->depth == DEPTH_INFINITY || $lock_row->dav_name == $this->real_dav_name ) { return $lock_token; } } @@ -843,7 +856,7 @@ EOQRY; if ( !isset($this->resource) ) $this->FetchResource(); } } -// dbg_error_log('DAVResource',' Checking whether "%s" exists. It would appear %s.', $this->dav_name, ($this->exists ? 'so' : 'not') ); +// dbg_error_log('DAVResource',' Checking whether "%s" exists. It would appear %s.', $this->real_dav_name, ($this->exists ? 'so' : 'not') ); return $this->exists; } @@ -852,7 +865,7 @@ EOQRY; * Returns the dav_name of the resource in our internal namespace */ function dav_name() { - if ( isset($this->dav_name) ) return $this->dav_name; + if ( isset($this->real_dav_name) ) return $this->real_dav_name; return null; } @@ -913,7 +926,7 @@ EOQRY; $this->parent_container_type = 'calendar'; else if ( $parent->is_addressbook == 't' ) $this->parent_container_type = 'addressbook'; - else if ( preg_match( '#^((/[^/]+/)\.(in|out)/)[^/]*$#', $this->dav_name, $matches ) ) + else if ( preg_match( '#^((/[^/]+/)\.(in|out)/)[^/]*$#', $this->real_dav_name, $matches ) ) $this->parent_container_type = 'schedule-'. $matches[3]. 'box'; else $this->parent_container_type = 'collection'; @@ -1015,7 +1028,7 @@ EOQRY; if ( isset($this->principal->{$name}) ) return $this->principal->{$name}; if ( isset($this->collection->{$name}) ) return $this->collection->{$name}; } -// dbg_error_log( 'DAVResource', ':GetProperty: Failed to find property "%s" on "%s".', $name, $this->dav_name ); +// dbg_error_log( 'DAVResource', ':GetProperty: Failed to find property "%s" on "%s".', $name, $this->real_dav_name ); } return $value; @@ -1047,7 +1060,7 @@ EOQRY; function ResourceProperty( $tag, $prop, &$reply, &$denied ) { global $c, $session, $request; -// dbg_error_log( 'DAVResource', 'Processing "%s" on "%s".', $tag, $this->dav_name ); +// dbg_error_log( 'DAVResource', 'Processing "%s" on "%s".', $tag, $this->real_dav_name ); if ( $reply === null ) $reply = $GLOBALS['reply']; @@ -1061,7 +1074,7 @@ EOQRY; break; case 'DAV::href': - $prop->NewElement('href', ConstructURL($this->dav_name) ); + $prop->NewElement('href', ConstructURL($this->real_dav_name) ); break; case 'DAV::getcontenttype': @@ -1254,7 +1267,7 @@ EOQRY; $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 ); +// dbg_error_log( 'DAVResource', 'Request for unsupported property "%s" of path "%s".', $tag, $this->real_dav_name ); return false; } } @@ -1274,7 +1287,7 @@ EOQRY; function GetPropStat( $properties, &$reply, $props_only = false ) { global $request; - dbg_error_log('DAVResource',':GetPropStat: propstat for href "%s"', $this->dav_name ); + dbg_error_log('DAVResource',':GetPropStat: propstat for href "%s"', $this->real_dav_name ); $prop = new XMLElement('prop'); $denied = array(); @@ -1290,7 +1303,7 @@ EOQRY; $found = $this->principal->PrincipalProperty( $tag, $prop, $reply, $denied ); } if ( ! $found ) { -// dbg_error_log( 'DAVResource', 'Request for unsupported property "%s" of resource "%s".', $tag, $this->dav_name ); +// dbg_error_log( 'DAVResource', 'Request for unsupported property "%s" of resource "%s".', $tag, $this->real_dav_name ); $not_found[] = $reply->Tag($tag); } } @@ -1333,7 +1346,7 @@ EOQRY; function RenderAsXML( $properties, &$reply, $props_only = false ) { global $session, $c, $request; - dbg_error_log('DAVResource',':RenderAsXML: Resource "%s"', $this->dav_name ); + dbg_error_log('DAVResource',':RenderAsXML: Resource "%s"', $this->real_dav_name ); if ( !$this->Exists() ) return null; @@ -1343,7 +1356,7 @@ EOQRY; } $elements = $this->GetPropStat( $properties, $reply ); - array_unshift( $elements, $reply->href(ConstructURL($this->dav_name))); + array_unshift( $elements, $reply->href(ConstructURL($this->real_dav_name))); $response = new XMLElement( 'response', $elements );