Move principal rendering into principal.

This commit is contained in:
Andrew McMillan 2009-06-14 21:20:36 +12:00
parent ba67df4d1f
commit 1f8b3a2af9
3 changed files with 157 additions and 66 deletions

View File

@ -148,6 +148,8 @@ class CalDAVPrincipal
foreach( $usr AS $k => $v ) {
$this->{$k} = $v;
}
if ( !isset($this->modified) ) $this->modified = ISODateToHTTPDate($this->updated);
if ( !isset($this->created) ) $this->created = ISODateToHTTPDate($this->joined);
$this->by_email = false;
$this->url = ConstructURL( "/".$this->username."/" );
@ -247,27 +249,20 @@ class CalDAVPrincipal
$path_split = explode('/', $path );
@dbg_error_log( "principal", "Path split into at least /// %s /// %s /// %s", $path_split[1], $path_split[2], $path_split[3] );
if ( substr($path,0,1) == '~' ) {
// URL is for a principal, by name
$username = substr($path_split[1],1);
$user = getUserByID($username);
$user_no = $user->user_no;
}
else {
$username = $path_split[1];
$username = $path_split[1];
if ( substr($username,0,1) == '~' ) $username = substr($username,1);
if ( isset($options['allow_by_email']) && preg_match( '#/(\S+@\S+[.]\S+)$#', $path, $matches) ) {
$email = $matches[1];
$qry = new PgQuery("SELECT user_no, username FROM usr WHERE email = ?;", $email );
if ( $qry->Exec("principal") && $user = $qry->Fetch() ) {
$user_no = $user->user_no;
$username = $user->username;
}
}
elseif( $user = getUserByName( $username, 'caldav') ) {
if ( isset($options['allow_by_email']) && preg_match( '#/(\S+@\S+[.]\S+)$#', $path, $matches) ) {
$email = $matches[1];
$qry = new PgQuery("SELECT user_no, username FROM usr WHERE email = ?;", $email );
if ( $qry->Exec("principal") && $user = $qry->Fetch() ) {
$user_no = $user->user_no;
$username = $user->username;
}
}
elseif( $user = getUserByName( $username, 'caldav') ) {
$user_no = $user->user_no;
}
return $username;
}
@ -287,6 +282,26 @@ class CalDAVPrincipal
}
/**
* Returns a representation of the principal as a collection
*/
function AsCollection() {
$collection = (object) array(
'collection_id' => (isset($this->collection_id) ? $this->collection_id : 0),
'is_calendar' => 'f',
'is_principal' => 't',
'user_no' => (isset($this->user_no) ? $this->user_no : 0),
'username' => (isset($this->username) ? $this->username : 0),
'email' => (isset($this->email) ? $this->email : ''),
'created' => (isset($this->created) ? $this->created : date('Ymd\THis'))
);
$collection->dav_name = (isset($this->dav_name) ? $this->dav_name : '/' . $this->username . '/');
$collection->dav_etag = (isset($this->dav_etag) ? $this->dav_etag : md5($this->username . $this->updated));
$collection->dav_displayname = (isset($this->dav_displayname) ? $this->dav_displayname : (isset($this->fullname) ? $this->fullname : $this->username));
return $collection;
}
/**
* Returns the array of privilege names converted into XMLElements
*/
@ -336,27 +351,19 @@ class CalDAVPrincipal
break;
case 'DAV::getlastmodified':
$prop->NewElement("getlastmodified", ISODateToHTTPDate($this->updated) );
$prop->NewElement("getlastmodified", $this->modified );
break;
case 'DAV::creationdate':
$prop->NewElement("creationdate", ISODateToHTTPDate($this->joined) );
$prop->NewElement("creationdate", $this->created );
break;
case 'DAV::group-member-set':
$set = array();
foreach( $this->group_member_set AS $k => $url ) {
$set[] = $reply->href($url );
}
$prop->NewElement("group-member-set", $set );
$prop->NewElement("group-member-set", $reply->href($this->group_member_set) );
break;
case 'DAV::group-membership':
$set = array();
foreach( $this->group_membership AS $k => $url ) {
$set[] = $reply->href($url );
}
$prop->NewElement("group-membership", $set );
$prop->NewElement("group-membership", $reply->href($this->group_membership) );
break;
case 'urn:ietf:params:xml:ns:caldav:schedule-inbox-URL':
@ -376,11 +383,7 @@ class CalDAVPrincipal
break;
case 'urn:ietf:params:xml:ns:caldav:calendar-home-set':
$set = array();
foreach( $this->calendar_home_set AS $k => $url ) {
$set[] = $reply->href( $url );
}
$reply->CalDAVElement($prop, "calendar-home-set", $set );
$reply->CalDAVElement($prop, "calendar-home-set", $reply->href( $this->calendar_home_set ) );
break;
case 'urn:ietf:params:xml:ns:caldav:calendar-user-address-set':

View File

@ -177,6 +177,7 @@ class CalDAVRequest
if ( preg_match( $bad_chars_regex, $this->path ) ) {
$this->DoResponse( 400, translate("The calendar path contains illegal characters.") );
}
if ( strstr($this->path,'//') ) $this->path = preg_replace( '#//+#', '/', $this->path);
$this->user_no = $session->user_no;
$this->username = $session->username;
@ -234,10 +235,23 @@ EOSQL;
$this->collection = $row;
}
}
else if ( preg_match( '#/(\S+@\S+[.]\S+)/?$#', $this->path) ) {
else if ( preg_match( '#^((/[^/]+/)calendar-proxy-(read|write))/?[^/]*$#', $this->path, $matches ) ) {
$this->collection_type = 'proxy';
$this->_is_proxy_request = true;
$this->proxy_type = $matches[3];
$this->collection_path = $matches[1].'/'; // Enforce trailling '/'
if ( $this->collection_path == $this->path."/" ) {
$this->path .= '/';
dbg_error_log( "caldav", "Path is actually a (proxy) collection - sending Content-Location header." );
header( "Content-Location: ".ConstructURL($this->path) );
}
}
else if ( preg_match( '#^/(\S+@\S+[.]\S+)/?$#', $this->path) ) {
/** @TODO: we should deprecate this now that Evolution 2.27 can do scheduling extensions */
$this->collection_id = -1;
$this->collection_type = 'email';
$this->collection_path = $this->path;
$this->_is_principal = true;
}
else if ( preg_match( '#^(/[^/]+)/?$#', $this->path, $matches) ) {
$this->collection_id = -1;
@ -267,6 +281,38 @@ EOSQL;
if ( isset($this->principal->username)) $this->username = $this->principal->username;
if ( isset($this->principal->by_email)) $this->by_email = true;
if ( $this->collection_type == 'principal' || $this->collection_type == 'email' ) {
$this->collection = $this->principal->AsCollection();
}
elseif( $this->collection_type == 'root' ) {
$this->collection = (object) array(
'collection_id' => 0,
'dav_name' => '/',
'dav_etag' => md5($c->system_name),
'is_calendar' => 'f',
'is_principal' => 'f',
'user_no' => 0,
'dav_displayname' => $c->system_name,
'created' => date('Ymd\THis')
);
}
elseif( $this->collection_type == 'proxy' ) {
$this->collection = (object) array(
'dav_name' => $this->collection_path,
'is_calendar' => 'f',
'is_principal' => 't',
'is_proxy' => 't',
'proxy_type' => $this->proxy_type,
'dav_displayname' => sprintf('Proxy %s for %s', $this->proxy_type, $this->principal->username),
'collection_id' => 0,
'user_no' => $this->principal->user_no,
'username' => $this->principal->username,
'email' => $this->principal->email,
'created' => $this->principal->created,
'dav_etag' => $this->principal->created
);
}
/**
* Evaluate our permissions for accessing the target
*/
@ -582,6 +628,17 @@ EOSQL;
}
/**
* Returns true if the URL referenced by this request is within a proxy URL
*/
function IsProxyRequest( ) {
if ( !isset($this->_is_proxy_request) ) {
$this->_is_proxy_request = preg_match( '#^/[^/]+/calendar-proxy-(read|write)/?[^/]*$#', $this->path );
}
return $this->_is_proxy_request;
}
/**
* Returns true if the request asked for infinite depth
*/

View File

@ -70,13 +70,13 @@ foreach( $request->xml_tags AS $k => $v ) {
case 'urn:ietf:params:xml:ns:caldav:schedule-inbox-URL': /** Support in development */
case 'urn:ietf:params:xml:ns:caldav:schedule-outbox-URL': /** Support in development */
case 'urn:ietf:params:xml:ns:caldav:calendar-free-busy-set': /** Deprecated, but should work fine */
case 'urn:ietf:params:xml:ns:caldav:supported-calendar-component-set':
case 'urn:ietf:params:xml:ns:caldav:supported-calendar-component-set': /** Should work fine */
/**
* Handled calendarserver properties
*/
case 'http://calendarserver.org/ns/:getctag': /** Calendar Server extension like etag - should work fine (we just return etag) */
case 'http://calendarserver.org/ns/:calendar-proxy-read-for': /** Calendar Server Delegation readonly */
case 'http://calendarserver.org/ns/:calendar-proxy-read-for': /** Calendar Server Delegation readonly */
case 'http://calendarserver.org/ns/:calendar-proxy-write-for': /** Calendar Server Delegation read-write */
case 'http://calendarserver.org/ns/:dropbox-home-URL':
case 'http://calendarserver.org/ns/:notifications-URL':
@ -202,10 +202,6 @@ function add_principal_properties( &$prop, &$denied ) {
$reply->DAVElement( $prop, "alternate-URI-set" ); // Empty - there are no alternatives!
}
if (isset($prop_list['DAV::group-membership'])) {
$reply->DAVElement($prop, "group-membership", href_set_from_paths( $request->principal->group_membership ));
}
if ( isset($prop_list['urn:ietf:params:xml:ns:caldav:calendar-home-set'] ) ) {
$reply->CalDAVElement( $prop, "calendar-home-set", href_set_from_paths( $request->principal->calendar_home_set ) );
}
@ -223,14 +219,6 @@ function add_principal_properties( &$prop, &$denied ) {
$reply->CalendarserverElement($prop, "notifications-URL", $reply->href( $request->principal->notifications_url) );
}
// Caldav proxy (not described in rfc, but CalendarServer has it)
if ( isset($prop_list['http://calendarserver.org/ns/:calendar-proxy-read-for'] ) ) {
$reply->CalendarserverElement($prop, "calendar-proxy-read-for", href_set_from_paths( $request->principal->read_proxy_for ) );
}
if ( isset($prop_list['http://calendarserver.org/ns/:calendar-proxy-write-for'] ) ) {
$reply->CalendarserverElement($prop, "calendar-proxy-write-for", href_set_from_paths( $request->principal->write_proxy_for ) );
}
if ( isset($prop_list['urn:ietf:params:xml:ns:caldav:calendar-user-address-set'] ) ) {
$reply->CalDAVElement( $prop, "calendar-user-address-set", href_set_from_paths( $request->principal->user_address_set ) );
}
@ -374,18 +362,23 @@ function add_proxy_response( &$responses, $which, $parent_path ) {
} else if ( $which == "write" ) {
$proxy_group = $request->principal->write_proxy_group;
}
if ( !isset($proxy_group) || !is_array($proxy_group) || count($proxy_group) < 1 ) {
if ($parent_path != '/'.$request->principal->username.'/') {
return; // Nothing to proxy for
}
$collection->dav_name = $parent_path."calendar-proxy-".$which."/";
$collection->is_calendar = 'f';
$collection->is_calendar = 'f';
$collection->is_principal = 't';
$collection->is_proxy = 't';
$collection->proxy_type = $which;
$collection->dav_displayname = $collection->dav_name;
$collection->collection_id = 0;
$collection->user_no = $session->user_no;
$collection->username = $session->username;
$collection->email = $session->email;
$collection->created = date('Ymd\THis');
$collection->dav_etag = md5($c->system_name . $collection->dav_name . implode($proxy_group) );
$collection->proxy_for = $proxy_group;
$responses[] = collection_to_xml( $collection );
}
@ -458,9 +451,9 @@ function collection_to_xml( $collection ) {
$resourcetypes[] = $reply->NewXMLElement( "principal", false, false, 'DAV:');
}
// As per Caldav Proxy 5.1 par. 3
if (preg_match('#(calendar-proxy-(read|write))#', $collection->dav_displayname, $matches) && isset($prop_list['DAV::resourcetype'])) {
$resourcetypes[] = $reply->NewXMLElement($matches[1], false, false, 'http://calendarserver.org/ns/');
if ( isset($collection->is_proxy) && $collection->is_proxy == 't' ) {
// As per Caldav Proxy 5.1 par. 3
$resourcetypes[] = $reply->NewXMLElement('calendar-proxy-'.$collection->proxy_type, false, false, 'http://calendarserver.org/ns/');
}
if ( $allprop || isset($prop_list['DAV::getcontentlength']) ) {
@ -471,6 +464,33 @@ function collection_to_xml( $collection ) {
}
}
if ( isset($collection->is_proxy) && $collection->is_proxy == 't' ) {
// Caldav proxy (not described in rfc, but CalendarServer has it)
if ( isset($prop_list['http://calendarserver.org/ns/:calendar-proxy-'.$collection->proxy_type.'-for'] ) ) {
if ( $collection->proxy_type == "read" ) {
$proxy_group = $request->principal->read_proxy_for;
} else if ( $collection->proxy_type == "write" ) {
$proxy_group = $request->principal->write_proxy_for;
}
$reply->CalendarserverElement($prop, 'calendar-proxy-'.$collection->proxy_type.'-for', $reply->href( $proxy_group ) );
}
if ( isset($prop_list['DAV::group-member-set']) ) {
if ( $collection->proxy_type == "read" ) {
$proxy_group = $request->principal->read_proxy_group;
} else if ( $collection->proxy_type == "write" ) {
$proxy_group = $request->principal->write_proxy_group;
}
$reply->DAVElement($prop, "group-member-set", $reply->href( $proxy_group ) );
}
if (isset($prop_list['DAV::group-membership'])) {
$reply->DAVElement($prop, "group-membership", $reply->href( $request->principal->group_membership ));
}
}
if ( $allprop || isset($prop_list['DAV::displayname']) ) {
$displayname = ( $collection->dav_displayname == "" ? ucfirst(trim(str_replace("/"," ", $collection->dav_name))) : $collection->dav_displayname );
$reply->DAVElement( $prop, "displayname", $displayname );
@ -578,8 +598,8 @@ function get_collection_contents( $depth, $user_no, $collection ) {
* Calendar collections may not contain calendar collections.
*/
if ( $collection->dav_name == '/' ) {
$sql = "SELECT usr.*, '/' || username || '/' AS dav_name, md5( '/' || username || '/') AS dav_etag, ";
$sql .= "to_char(updated at time zone 'GMT',?) AS created, ";
$sql = "SELECT usr.*, '/' || username || '/' AS dav_name, md5(username || updated::text) AS dav_etag, ";
$sql .= "to_char(joined at time zone 'GMT',?) AS created, ";
$sql .= "to_char(updated at time zone 'GMT',?) AS modified, ";
$sql .= "fullname AS dav_displayname, FALSE AS is_calendar, TRUE AS is_principal, ";
$sql .= "0 AS collection_id ";
@ -613,6 +633,12 @@ function get_collection_contents( $depth, $user_no, $collection ) {
}
}
}
if ( $collection->is_principal == "t" ) {
// Caldav Proxy: 5.1 par. 2: Add child resources calendar-proxy-(read|write)
dbg_error_log("PROPFIND","Adding calendar-proxy-read and write. Path: %s", $collection->dav_name);
add_proxy_response($responses, "read", $collection->dav_name);
add_proxy_response($responses, "write", $collection->dav_name);
}
}
/**
@ -674,8 +700,8 @@ function get_collection( $depth, $user_no, $collection_path ) {
else {
$user_no = intval($user_no);
if ( preg_match( '#^/[^/]+/$#', $collection_path) ) {
$sql = "SELECT usr.*, '/' || username || '/' AS dav_name, md5( '/' || username || '/') AS dav_etag, ";
$sql .= "to_char(updated at time zone 'GMT',?) AS created, ";
$sql = "SELECT usr.*, '/' || username || '/' AS dav_name, md5( username || updated::text ) AS dav_etag, ";
$sql .= "to_char(joined at time zone 'GMT',?) AS created, ";
$sql .= "to_char(updated at time zone 'GMT',?) AS modified, ";
$sql .= "fullname AS dav_displayname, FALSE AS is_calendar, TRUE AS is_principal, 0 AS collection_id ";
$sql .= "FROM usr WHERE user_no = $user_no ";
@ -700,13 +726,6 @@ function get_collection( $depth, $user_no, $collection_path ) {
$responses[] = collection_to_xml( $collection );
}
// Caldav Proxy: 5.1 par. 2: Add child resources calendar-proxy-(read|write)
if (($collection->is_principal && isset($prop_list['DAV::resourcetype'])) ) { // atm, only users/resources/groups are principals, so it's ok to add these.
// this is added when /<principal>/ is queried for resourcetype
dbg_error_log("PROPFIND","Adding calendar-proxy-read and write. Path: %s", $collection->dav_name);
add_proxy_response($responses, "read", $collection->dav_name);
add_proxy_response($responses, "write", $collection->dav_name);
}
}
elseif ( $c->collections_always_exist && preg_match( "#^/$session->username/#", $collection_path) ) {
dbg_error_log("PROPFIND","Using $c->collections_always_exist setting is deprecated" );
@ -763,7 +782,19 @@ $request->UnsupportedRequest($unsupported); // Won't return if there was unsuppo
*/
$url = ConstructURL( $request->path );
$url = preg_replace( '#/$#', '', $url);
if ( $request->IsCollection() ) {
$responses = array();
if ( $request->IsPrincipal() ) {
$responses[] = $request->principal->RenderAsXML(array_merge($prop_list,$arbitrary), &$reply);
if ( $request->depth > 0 ) {
$collection = (object) array( 'dav_name' => '/'.$request->username.'/', 'is_calendar' => 'f', 'is_principal' => 't' );
$responses = array_merge($responses, get_collection_contents( $request->depth - 1, $request->user_no, $collection ) );
}
}
if ( $request->IsProxyRequest() ) {
add_proxy_response($responses, $request->proxy_type, '/' . $request->principal->username . '/' );
/** Nothing inside these, as yet. */
}
elseif ( $request->IsCollection() ) {
$responses = get_collection( $request->depth, $request->user_no, $request->path );
}
elseif ( $request->AllowedTo('read') ) {