mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-05-30 03:24:47 +00:00
Various changes preparing to switch PROPFIND implementation.
This commit is contained in:
parent
c83873c32a
commit
865a2e499c
@ -417,7 +417,7 @@ class AwlQuery
|
|||||||
|
|
||||||
if ( ! $success ) {
|
if ( ! $success ) {
|
||||||
// query failed
|
// query failed
|
||||||
$this->errorstring = sprintf( 'SQL error "%s" - %s"', $this->error_info[0], $this->error_info[2]);
|
$this->errorstring = sprintf( 'SQL error "%s" - %s"', $this->error_info[0], (isset($this->error_info[2]) ? $this->error_info[2] : ''));
|
||||||
$this->_log_query( $this->location, 'QF', $this->errorstring, $line, $file );
|
$this->_log_query( $this->location, 'QF', $this->errorstring, $line, $file );
|
||||||
}
|
}
|
||||||
elseif ( $this->execution_time > $this->query_time_warning ) {
|
elseif ( $this->execution_time > $this->query_time_warning ) {
|
||||||
|
|||||||
@ -60,7 +60,12 @@ class CalDAVPrincipal
|
|||||||
/**
|
/**
|
||||||
* @var RFC3744: The principals that are direct members of this group.
|
* @var RFC3744: The principals that are direct members of this group.
|
||||||
*/
|
*/
|
||||||
var $group_member_set;
|
protected $_is_group;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var RFC3744: The principals that are direct members of this group.
|
||||||
|
*/
|
||||||
|
protected $group_member_set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var RFC3744: The groups in which the principal is directly a member.
|
* @var RFC3744: The groups in which the principal is directly a member.
|
||||||
@ -160,11 +165,13 @@ class CalDAVPrincipal
|
|||||||
foreach( $usr AS $k => $v ) {
|
foreach( $usr AS $k => $v ) {
|
||||||
$this->{$k} = $v;
|
$this->{$k} = $v;
|
||||||
}
|
}
|
||||||
if ( !isset($this->modified) ) $this->modified = ISODateToHTTPDate($this->updated);
|
if ( !isset($this->modified) ) $this->modified = $this->updated;
|
||||||
if ( !isset($this->created) ) $this->created = ISODateToHTTPDate($this->joined);
|
if ( !isset($this->created) ) $this->created = $this->joined;
|
||||||
|
|
||||||
$this->dav_etag = md5($this->username . $this->updated);
|
$this->dav_etag = md5($this->username . $this->updated);
|
||||||
|
|
||||||
|
$this->_is_group = (isset($usr->type_id) && $usr->type_id == 3);
|
||||||
|
|
||||||
$this->by_email = false;
|
$this->by_email = false;
|
||||||
$this->principal_url = ConstructURL( '/'.$this->username.'/', true );
|
$this->principal_url = ConstructURL( '/'.$this->username.'/', true );
|
||||||
$this->url = $this->principal_url;
|
$this->url = $this->principal_url;
|
||||||
@ -188,15 +195,24 @@ class CalDAVPrincipal
|
|||||||
$this->xmpp_server = $c->notifications_server['host'];
|
$this->xmpp_server = $c->notifications_server['host'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->group_member_set = array();
|
if ( $this->_is_group ) {
|
||||||
$qry = new PgQuery('SELECT * FROM relationship LEFT JOIN usr ON (from_user = usr.user_no) LEFT JOIN role_member ON (to_user = role_member.user_no) LEFT JOIN roles USING (role_no) WHERE to_user = ? AND role_name = '."'Group'", $this->user_no );
|
$this->group_member_set = array();
|
||||||
if ( $qry->Exec('CalDAVPrincipal') && $qry->rows > 0 ) {
|
$qry = new PgQuery('SELECT * FROM group_member JOIN principal ON (principal_id=member_id) JOIN usr USING(user_no) WHERE group_id = ?', $this->principal_id );
|
||||||
while( $membership = $qry->Fetch() ) {
|
if ( $qry->Exec('CalDAVPrincipal') && $qry->rows > 0 ) {
|
||||||
$this->group_member_set[] = ConstructURL( '/'. $membership->username . '/', true);
|
while( $member = $qry->Fetch() ) {
|
||||||
|
$this->group_member_set[] = ConstructURL( '/'. $member->username . '/', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->group_membership = array();
|
||||||
|
$qry = new PgQuery('SELECT * FROM group_member JOIN principal ON (principal_id=group_id) JOIN usr USING(user_no) WHERE member_id = ?', $this->principal_id );
|
||||||
|
if ( $qry->Exec('CalDAVPrincipal') && $qry->rows > 0 ) {
|
||||||
|
while( $group = $qry->Fetch() ) {
|
||||||
|
$this->group_membership[] = ConstructURL( '/'. $group->username . '/', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->group_membership = null;
|
|
||||||
$this->read_proxy_group = null;
|
$this->read_proxy_group = null;
|
||||||
$this->write_proxy_group = null;
|
$this->write_proxy_group = null;
|
||||||
$this->write_proxy_for = null;
|
$this->write_proxy_for = null;
|
||||||
@ -206,7 +222,7 @@ class CalDAVPrincipal
|
|||||||
* calendar-free-busy-set has been dropped from draft 5 of the scheduling extensions for CalDAV
|
* calendar-free-busy-set has been dropped from draft 5 of the scheduling extensions for CalDAV
|
||||||
* but we'll keep replying to it for a while longer since iCal appears to want it...
|
* but we'll keep replying to it for a while longer since iCal appears to want it...
|
||||||
*/
|
*/
|
||||||
$qry = new PgQuery('SELECT dav_name FROM collection WHERE user_no = ? AND is_calendar', $this->user_no);
|
$qry = new PgQuery('SELECT dav_name FROM collection WHERE user_no = ? AND is_calendar ORDER BY user_no, collection_id', $this->user_no);
|
||||||
$this->calendar_free_busy_set = array();
|
$this->calendar_free_busy_set = array();
|
||||||
if( $qry->Exec('CalDAVPrincipal',__LINE__,__FILE__) && $qry->rows > 0 ) {
|
if( $qry->Exec('CalDAVPrincipal',__LINE__,__FILE__) && $qry->rows > 0 ) {
|
||||||
while( $calendar = $qry->Fetch() ) {
|
while( $calendar = $qry->Fetch() ) {
|
||||||
@ -224,14 +240,6 @@ class CalDAVPrincipal
|
|||||||
function FetchProxyGroups() {
|
function FetchProxyGroups() {
|
||||||
global $c;
|
global $c;
|
||||||
|
|
||||||
$this->group_membership = array();
|
|
||||||
$qry = new PgQuery('SELECT * FROM relationship LEFT JOIN usr ON (to_user = user_no) LEFT JOIN role_member USING (user_no) LEFT JOIN roles USING (role_no) WHERE from_user = ? AND role_name = '."'Group'", $this->user_no );
|
|
||||||
if ( $qry->Exec('CalDAVPrincipal') && $qry->rows > 0 ) {
|
|
||||||
while( $membership = $qry->Fetch() ) {
|
|
||||||
$this->group_membership[] = ConstructURL( '/'. $membership->username . '/', true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->read_proxy_group = array();
|
$this->read_proxy_group = array();
|
||||||
$this->write_proxy_group = array();
|
$this->write_proxy_group = array();
|
||||||
$this->write_proxy_for = array();
|
$this->write_proxy_for = array();
|
||||||
@ -252,14 +260,12 @@ class CalDAVPrincipal
|
|||||||
if ($relationship->confers == 'R') {
|
if ($relationship->confers == 'R') {
|
||||||
if ($relationship->from_user_no == $this->user_no) {
|
if ($relationship->from_user_no == $this->user_no) {
|
||||||
// spec says without trailing slash, CalServ does it with slash, and so do we.
|
// spec says without trailing slash, CalServ does it with slash, and so do we.
|
||||||
$this->group_membership[] = ConstructURL( '/'. $relationship->to_username . '/calendar-proxy-read/', true);
|
|
||||||
$this->read_proxy_for[] = ConstructURL( '/'. $relationship->to_username . '/', true);
|
$this->read_proxy_for[] = ConstructURL( '/'. $relationship->to_username . '/', true);
|
||||||
} else /* ($relationship->to_user_no == $this->user_no) */ {
|
} else /* ($relationship->to_user_no == $this->user_no) */ {
|
||||||
$this->read_proxy_group[] = ConstructURL( '/'. $relationship->from_username . '/', true);
|
$this->read_proxy_group[] = ConstructURL( '/'. $relationship->from_username . '/', true);
|
||||||
}
|
}
|
||||||
} else if (preg_match('/[WA]/', $relationship->confers)) {
|
} else if (preg_match('/[WA]/', $relationship->confers)) {
|
||||||
if ($relationship->from_user_no == $this->user_no) {
|
if ($relationship->from_user_no == $this->user_no) {
|
||||||
$this->group_membership[] = ConstructURL( '/'. $relationship->to_username . '/calendar-proxy-write/', true);
|
|
||||||
$this->write_proxy_for[] = ConstructURL( '/'. $relationship->to_username . '/', true);
|
$this->write_proxy_for[] = ConstructURL( '/'. $relationship->to_username . '/', true);
|
||||||
}
|
}
|
||||||
else /* ($relationship->to_user_no == $this->user_no) */ {
|
else /* ($relationship->to_user_no == $this->user_no) */ {
|
||||||
@ -291,29 +297,30 @@ class CalDAVPrincipal
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accessor for the read proxy for
|
* Accessor for read or write proxy
|
||||||
|
* @param string read/write - which sort of proxy list is requested.
|
||||||
*/
|
*/
|
||||||
function ReadProxyFor() {
|
function ProxyFor( $type ) {
|
||||||
if ( !isset($this->read_proxy_for) ) $this->FetchProxyGroups();
|
if ( !isset($this->read_proxy_for) ) $this->FetchProxyGroups();
|
||||||
|
if ( $type == 'write' ) return $this->write_proxy_for;
|
||||||
return $this->read_proxy_for;
|
return $this->read_proxy_for;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accessor for the write proxy for
|
* Accessor for the group membership - the groups this principal is a member of
|
||||||
*/
|
*/
|
||||||
function WriteProxyFor() {
|
function GroupMembership() {
|
||||||
if ( !isset($this->write_proxy_for) ) $this->FetchProxyGroups();
|
return $this->group_membership;
|
||||||
return $this->write_proxy_for;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accessor for the group membership
|
* Accessor for the group member set - the members of this group
|
||||||
*/
|
*/
|
||||||
function GroupMembership() {
|
function GroupMemberSet() {
|
||||||
if ( !isset($this->group_membership) ) $this->FetchProxyGroups();
|
if ( ! $this->_is_group ) return null;
|
||||||
return $this->group_membership;
|
return $this->group_member_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -345,7 +352,7 @@ class CalDAVPrincipal
|
|||||||
$username = $user->username;
|
$username = $user->username;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif( $user = getUserByName( $username, 'principal') ) {
|
elseif( $user = getUserByName( $username) ) {
|
||||||
$user_no = $user->user_no;
|
$user_no = $user->user_no;
|
||||||
}
|
}
|
||||||
return $username;
|
return $username;
|
||||||
@ -376,6 +383,15 @@ class CalDAVPrincipal
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a group principal?
|
||||||
|
* @return boolean Whether this is a group principal
|
||||||
|
*/
|
||||||
|
function IsGroup() {
|
||||||
|
return $this->_is_group;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the privileges bits for the current session user to this resource
|
* Return the privileges bits for the current session user to this resource
|
||||||
*/
|
*/
|
||||||
@ -391,6 +407,7 @@ class CalDAVPrincipal
|
|||||||
$collection = (object) array(
|
$collection = (object) array(
|
||||||
'collection_id' => (isset($this->collection_id) ? $this->collection_id : 0),
|
'collection_id' => (isset($this->collection_id) ? $this->collection_id : 0),
|
||||||
'is_calendar' => 'f',
|
'is_calendar' => 'f',
|
||||||
|
'is_addressbook' => 'f',
|
||||||
'is_principal' => 't',
|
'is_principal' => 't',
|
||||||
'user_no' => (isset($this->user_no) ? $this->user_no : 0),
|
'user_no' => (isset($this->user_no) ? $this->user_no : 0),
|
||||||
'username' => (isset($this->username) ? $this->username : 0),
|
'username' => (isset($this->username) ? $this->username : 0),
|
||||||
@ -405,6 +422,117 @@ class CalDAVPrincipal
|
|||||||
return $collection;
|
return $collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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/:notifications-URL':
|
||||||
|
$reply->CalendarserverElement($prop, 'notifications-URL', $reply->href($this->notifications_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:caldav:calendar-home-set':
|
||||||
|
$reply->CalDAVElement($prop, 'calendar-home-set', $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;
|
||||||
|
|
||||||
|
case 'DAV::principal-collection-set':
|
||||||
|
$reply->DAVElement( $prop, 'principal-collection-set', $reply->href( ConstructURL('/') ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render XML for a single Principal (user) from the DB
|
* Render XML for a single Principal (user) from the DB
|
||||||
@ -416,7 +544,7 @@ class CalDAVPrincipal
|
|||||||
* @return string An XML fragment with the requested properties for this principal
|
* @return string An XML fragment with the requested properties for this principal
|
||||||
*/
|
*/
|
||||||
function RenderAsXML( $properties, &$reply, $props_only = false ) {
|
function RenderAsXML( $properties, &$reply, $props_only = false ) {
|
||||||
global $session, $c, $request;
|
global $request;
|
||||||
|
|
||||||
dbg_error_log('principal',': RenderAsXML: Principal "%s"', $this->username );
|
dbg_error_log('principal',': RenderAsXML: Principal "%s"', $this->username );
|
||||||
|
|
||||||
@ -424,117 +552,9 @@ class CalDAVPrincipal
|
|||||||
$denied = array();
|
$denied = array();
|
||||||
$not_found = array();
|
$not_found = array();
|
||||||
foreach( $properties AS $k => $tag ) {
|
foreach( $properties AS $k => $tag ) {
|
||||||
dbg_error_log('principal',': RenderAsXML: Principal Property "%s"', $tag );
|
if ( ! $this->PrincipalProperty( $tag, $prop, $reply, $denied ) && ! $request->ServerProperty( $tag, $prop, $reply ) ) {
|
||||||
switch( $tag ) {
|
dbg_error_log( 'principal', 'Request for unsupported property "%s" of principal "%s".', $tag, $this->username );
|
||||||
case 'DAV::getcontenttype':
|
$not_found[] = $reply->Tag($tag);
|
||||||
$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', $this->modified );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'DAV::creationdate':
|
|
||||||
$prop->NewElement('creationdate', $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':
|
|
||||||
$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/:notifications-URL':
|
|
||||||
$reply->CalendarserverElement($prop, 'notifications-URL', $reply->href($this->notifications_url) );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'http://calendarserver.org/ns/:xmpp-server':
|
|
||||||
if ( isset ( $this->xmpp_uri ) )
|
|
||||||
$reply->CalendarserverElement($prop, 'xmpp-server', $this->xmpp_server );
|
|
||||||
else
|
|
||||||
$not_found[] = $reply->Tag($tag);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'http://calendarserver.org/ns/:xmpp-uri':
|
|
||||||
if ( isset ( $this->xmpp_uri ) )
|
|
||||||
$reply->CalendarserverElement($prop, 'xmpp-uri', $this->xmpp_uri );
|
|
||||||
else
|
|
||||||
$not_found[] = $reply->Tag($tag);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'urn:ietf:params:xml:ns:caldav:calendar-home-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':
|
|
||||||
$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;
|
|
||||||
|
|
||||||
case 'DAV::principal-collection-set':
|
|
||||||
$reply->DAVElement( $prop, 'principal-collection-set', $reply->href( ConstructURL('/') ) );
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Empty tag responses.
|
|
||||||
case 'DAV::alternate-URI-set':
|
|
||||||
case 'DAV::getcontentlength':
|
|
||||||
$prop->NewElement( $reply->Tag($tag));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'SOME-DENIED-PROPERTY': /** @todo indicating the style for future expansion */
|
|
||||||
$denied[] = $reply->Tag($tag);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'http://calendarserver.org/ns/:getctag':
|
|
||||||
case 'DAV::getetag':
|
|
||||||
case 'urn:ietf:params:xml:ns:caldav:supported-calendar-component-set':
|
|
||||||
// These will 404 on a Principal, since they don't apply
|
|
||||||
$not_found[] = $reply->Tag($tag);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if ( ! $request->ServerProperty( $tag, $prop, $reply ) ) {
|
|
||||||
dbg_error_log( 'principal', 'Request for unsupported property "%s" of principal "%s".', $tag, $this->username );
|
|
||||||
$not_found[] = $reply->Tag($tag);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -940,7 +940,7 @@ EOSQL;
|
|||||||
/**
|
/**
|
||||||
* Return general server-related properties for this URL
|
* Return general server-related properties for this URL
|
||||||
*/
|
*/
|
||||||
function ServerProperty( $tag, $prop, $reply = null ) {
|
function ServerProperty( $tag, $prop, &$reply = null ) {
|
||||||
global $c, $session;
|
global $c, $session;
|
||||||
|
|
||||||
if ( $reply === null ) $reply = $GLOBALS['reply'];
|
if ( $reply === null ) $reply = $GLOBALS['reply'];
|
||||||
|
|||||||
@ -63,37 +63,43 @@ function privilege_to_bits( $raw_privs ) {
|
|||||||
function bits_to_privilege( $raw_bits ) {
|
function bits_to_privilege( $raw_bits ) {
|
||||||
$out_priv = array();
|
$out_priv = array();
|
||||||
|
|
||||||
|
if ( is_string($raw_bits) ) {
|
||||||
|
$raw_bits = bindec($raw_bits);
|
||||||
|
}
|
||||||
|
|
||||||
if ( ($raw_bits & 16777215) == 16777215 ) $out_priv[] = 'all';
|
if ( ($raw_bits & 16777215) == 16777215 ) $out_priv[] = 'all';
|
||||||
|
|
||||||
if ( (in_bits & 1) != 0 ) $out_priv[] = 'DAV::read';
|
if ( ($raw_bits & 1) != 0 ) $out_priv[] = 'DAV::read';
|
||||||
if ( (in_bits & 8) != 0 ) $out_priv[] = 'DAV::unlock';
|
if ( ($raw_bits & 8) != 0 ) $out_priv[] = 'DAV::unlock';
|
||||||
if ( (in_bits & 16) != 0 ) $out_priv[] = 'DAV::read-acl';
|
if ( ($raw_bits & 16) != 0 ) $out_priv[] = 'DAV::read-acl';
|
||||||
if ( (in_bits & 32) != 0 ) $out_priv[] = 'DAV::read-current-user-privilege-set';
|
if ( ($raw_bits & 32) != 0 ) $out_priv[] = 'DAV::read-current-user-privilege-set';
|
||||||
if ( (in_bits & 256) != 0 ) $out_priv[] = 'DAV::write-acl';
|
if ( ($raw_bits & 256) != 0 ) $out_priv[] = 'DAV::write-acl';
|
||||||
if ( (in_bits & 512) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:read-free-busy';
|
if ( ($raw_bits & 512) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:read-free-busy';
|
||||||
|
|
||||||
if ( (in_bits & 198) != 0 ) {
|
if ( ($raw_bits & 198) != 0 ) {
|
||||||
if ( (in_bits & 198) == 198 ) $out_priv[] = 'DAV::write';
|
if ( ($raw_bits & 198) == 198 ) $out_priv[] = 'DAV::write';
|
||||||
if ( (in_bits & 2) != 0 ) $out_priv[] = 'DAV::write-properties';
|
if ( ($raw_bits & 2) != 0 ) $out_priv[] = 'DAV::write-properties';
|
||||||
if ( (in_bits & 4) != 0 ) $out_priv[] = 'DAV::write-content';
|
if ( ($raw_bits & 4) != 0 ) $out_priv[] = 'DAV::write-content';
|
||||||
if ( (in_bits & 64) != 0 ) $out_priv[] = 'DAV::bind';
|
if ( ($raw_bits & 64) != 0 ) $out_priv[] = 'DAV::bind';
|
||||||
if ( (in_bits & 128) != 0 ) $out_priv[] = 'DAV::unbind';
|
if ( ($raw_bits & 128) != 0 ) $out_priv[] = 'DAV::unbind';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (in_bits & 7168) != 0 ) {
|
if ( ($raw_bits & 7168) != 0 ) {
|
||||||
if ( (in_bits & 7168) == 7168 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-deliver';
|
if ( ($raw_bits & 7168) == 7168 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-deliver';
|
||||||
if ( (in_bits & 1024) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-deliver-invite';
|
if ( ($raw_bits & 1024) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-deliver-invite';
|
||||||
if ( (in_bits & 2048) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-deliver-reply';
|
if ( ($raw_bits & 2048) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-deliver-reply';
|
||||||
if ( (in_bits & 4096) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-query-freebusy';
|
if ( ($raw_bits & 4096) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-query-freebusy';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (in_bits & 57344) != 0 ) {
|
if ( ($raw_bits & 57344) != 0 ) {
|
||||||
if ( (in_bits & 57344) == 57344 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send';
|
if ( ($raw_bits & 57344) == 57344 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send';
|
||||||
if ( (in_bits & 8192) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send-invite';
|
if ( ($raw_bits & 8192) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send-invite';
|
||||||
if ( (in_bits & 16384) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send-reply';
|
if ( ($raw_bits & 16384) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send-reply';
|
||||||
if ( (in_bits & 32768) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send-freebusy';
|
if ( ($raw_bits & 32768) != 0 ) $out_priv[] = 'urn:ietf:params:xml:ns:caldav:schedule-send-freebusy';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dbg_error_log( 'DAVResource', ' Privilege bit "%s" is "%s".', $raw_bits, implode(', ', $out_priv) );
|
||||||
|
|
||||||
return $out_priv;
|
return $out_priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,9 +132,9 @@ class DAVResource
|
|||||||
protected $resource;
|
protected $resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var The type of the resource, possibly multiple
|
* @var The types of the resource, possibly multiple
|
||||||
*/
|
*/
|
||||||
protected $resourcetype;
|
protected $resourcetypes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var The type of the content
|
* @var The type of the content
|
||||||
@ -170,6 +176,11 @@ class DAVResource
|
|||||||
*/
|
*/
|
||||||
private $_is_addressbook;
|
private $_is_addressbook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var True if this resource is, or is in, a proxy collection
|
||||||
|
*/
|
||||||
|
private $_is_proxy_request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var An array of the methods we support on this resource.
|
* @var An array of the methods we support on this resource.
|
||||||
*/
|
*/
|
||||||
@ -180,6 +191,11 @@ class DAVResource
|
|||||||
*/
|
*/
|
||||||
private $supported_reports;
|
private $supported_reports;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var An array of the dead properties held for this resource
|
||||||
|
*/
|
||||||
|
private $dead_properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var An array of the component types we support on this resource.
|
* @var An array of the component types we support on this resource.
|
||||||
*/
|
*/
|
||||||
@ -198,14 +214,16 @@ class DAVResource
|
|||||||
$this->resource = null;
|
$this->resource = null;
|
||||||
$this->collection = null;
|
$this->collection = null;
|
||||||
$this->principal = null;
|
$this->principal = null;
|
||||||
$this->resourcetype = null;
|
$this->resourcetypes = null;
|
||||||
$this->contenttype = null;
|
$this->contenttype = null;
|
||||||
$this->privileges = null;
|
$this->privileges = null;
|
||||||
|
$this->dead_properties = null;
|
||||||
|
|
||||||
$this->_is_collection = false;
|
$this->_is_collection = false;
|
||||||
$this->_is_principal = false;
|
$this->_is_principal = false;
|
||||||
$this->_is_calendar = false;
|
$this->_is_calendar = false;
|
||||||
$this->_is_addressbook = false;
|
$this->_is_addressbook = false;
|
||||||
|
$this->_is_proxy = false;
|
||||||
if ( isset($parameters) && is_object($parameters) ) {
|
if ( isset($parameters) && is_object($parameters) ) {
|
||||||
$this->FromRow($parameters);
|
$this->FromRow($parameters);
|
||||||
}
|
}
|
||||||
@ -230,19 +248,73 @@ class DAVResource
|
|||||||
if ( $row == null ) return;
|
if ( $row == null ) return;
|
||||||
|
|
||||||
$this->exists = true;
|
$this->exists = true;
|
||||||
|
$this->dav_name = $row->dav_name;
|
||||||
$this->_is_collection = preg_match( '{/$}', $row->dav_name );
|
$this->_is_collection = preg_match( '{/$}', $row->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->collection->dav_name = $matches[1].'/';
|
||||||
|
$this->collection->type = 'principal_link';
|
||||||
|
$this->_is_principal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->resource = (object) array();
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg_error_log( 'DAVResource', ':FromRow: Named "%s" is%s a collection.', $row->dav_name, ($this->_is_collection?'':' not') );
|
||||||
|
|
||||||
foreach( $row AS $k => $v ) {
|
foreach( $row AS $k => $v ) {
|
||||||
dbg_error_log( 'DAVResource', 'Processing resource property "%s" has "%s".', $row->dav_name, $k );
|
if ( $this->_is_collection )
|
||||||
$this->resource->{$k} = $v;
|
$this->collection->{$k} = $v;
|
||||||
|
else
|
||||||
|
$this->resource->{$k} = $v;
|
||||||
switch ( $k ) {
|
switch ( $k ) {
|
||||||
|
case 'created':
|
||||||
|
case 'modified':
|
||||||
|
case 'resourcetypes':
|
||||||
|
$this->{$k} = $v;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'dav_etag':
|
case 'dav_etag':
|
||||||
$this->unique_tag = '"'.$v.'"';
|
$this->unique_tag = '"'.$v.'"';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'is_calendar': if ( $this->_is_collection) $this->_is_calendar = ($v == 't'); break;
|
}
|
||||||
case 'is_addressbook': if ( $this->_is_collection) $this->_is_addressbook = ($v == 't'); break;
|
}
|
||||||
case 'is_principal': if ( $this->_is_collection) $this->_is_principal = ($v == 't'); break;
|
|
||||||
|
if ( $this->_is_collection ) {
|
||||||
|
if ( !isset( $this->collection->type ) || $this->collection->type == 'collection' ) {
|
||||||
|
if ( $this->_is_principal )
|
||||||
|
$this->collection->type = 'principal';
|
||||||
|
else if ( $row->is_calendar == 't' )
|
||||||
|
$this->collection->type = 'calendar';
|
||||||
|
else if ( $row->is_addressbook == 't' )
|
||||||
|
$this->collection->type = 'addressbook';
|
||||||
|
else if ( preg_match( '#^((/[^/]+/)\.(in|out)/)[^/]*$#', $this->dav_name, $matches ) )
|
||||||
|
$this->collection->type = 'schedule-'. $matches[3]. 'box';
|
||||||
|
else if ( $this->dav_name == '/' )
|
||||||
|
$this->collection->type = 'root';
|
||||||
|
else
|
||||||
|
$this->collection->type = 'collection';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_is_calendar = ($this->collection->is_calendar == 't');
|
||||||
|
$this->_is_addressbook = ($this->collection->is_addressbook == 't');
|
||||||
|
if ( $this->_is_principal && !isset($this->resourcetypes) ) {
|
||||||
|
$this->resourcetypes = '<DAV::collection/><DAV::principal/>';
|
||||||
|
}
|
||||||
|
if ( isset($this->collection->dav_displayname) ) $this->collection->displayname = $this->collection->dav_displayname;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->resourcetypes = '';
|
||||||
|
if ( isset($this->resource->caldav_data) ) {
|
||||||
|
if ( substr($this->resource->caldav_data,0,15) == 'BEGIN:VCALENDAR' ) $this->contenttype = 'text/calendar';
|
||||||
|
$this->resource->displayname = $this->resource->summary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,6 +348,16 @@ class DAVResource
|
|||||||
if ( substr($ourpath,0,1) != '/' ) $ourpath = '/'.$ourpath;
|
if ( substr($ourpath,0,1) != '/' ) $ourpath = '/'.$ourpath;
|
||||||
|
|
||||||
$this->dav_name = $ourpath;
|
$this->dav_name = $ourpath;
|
||||||
|
|
||||||
|
$this->FetchCollection();
|
||||||
|
if ( $this->_is_collection ) {
|
||||||
|
if ( $this->_is_principal ) $this->FetchPrincipal();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$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':'') );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -295,10 +377,12 @@ class DAVResource
|
|||||||
* The collection URL for this request is therefore the longest row in the result, so we
|
* 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"
|
* can "... ORDER BY LENGTH(dav_name) DESC LIMIT 1"
|
||||||
*/
|
*/
|
||||||
|
dbg_error_log( 'DAVResource', ':FetchCollection: Looking for collection for "%s".', $this->dav_name );
|
||||||
|
|
||||||
$this->collection = (object) array(
|
$this->collection = (object) array(
|
||||||
'collection_id' => -1,
|
'collection_id' => -1,
|
||||||
'type' => 'nonexistent',
|
'type' => 'nonexistent',
|
||||||
'is_calendar' => false, 'is_principal' => false, 'is_addressbook' => false, 'resourcetypes' => '<DAV::collection/>',
|
'is_calendar' => false, 'is_principal' => false, 'is_addressbook' => false
|
||||||
);
|
);
|
||||||
|
|
||||||
$base_sql = 'SELECT collection.*, path_privileges(:session_principal, collection.dav_name), ';
|
$base_sql = 'SELECT collection.*, path_privileges(:session_principal, collection.dav_name), ';
|
||||||
@ -316,6 +400,7 @@ class DAVResource
|
|||||||
$qry = new AwlQuery( $sql, $params );
|
$qry = new AwlQuery( $sql, $params );
|
||||||
if ( $qry->Exec('DAVResource') && $qry->rows() == 1 && ($row = $qry->Fetch()) ) {
|
if ( $qry->Exec('DAVResource') && $qry->rows() == 1 && ($row = $qry->Fetch()) ) {
|
||||||
$this->collection = $row;
|
$this->collection = $row;
|
||||||
|
$this->collection->exists = true;
|
||||||
if ( $row->is_calendar == 't' )
|
if ( $row->is_calendar == 't' )
|
||||||
$this->collection->type = 'calendar';
|
$this->collection->type = 'calendar';
|
||||||
else if ( $row->is_addressbook == 't' )
|
else if ( $row->is_addressbook == 't' )
|
||||||
@ -343,13 +428,16 @@ EOSQL;
|
|||||||
$qry = new AwlQuery( $base_sql . ' dav_name = :raw_path', $params );
|
$qry = new AwlQuery( $base_sql . ' dav_name = :raw_path', $params );
|
||||||
if ( $qry->Exec('DAVResource') && $qry->rows() == 1 && ($row = $qry->Fetch()) ) {
|
if ( $qry->Exec('DAVResource') && $qry->rows() == 1 && ($row = $qry->Fetch()) ) {
|
||||||
$this->collection = $row;
|
$this->collection = $row;
|
||||||
|
$this->collection->exists = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( preg_match( '#^((/[^/]+/)calendar-proxy-(read|write))/?[^/]*$#', $this->dav_name, $matches ) ) {
|
else if ( preg_match( '#^(/([^/]+)/calendar-proxy-(read|write))/?[^/]*$#', $this->dav_name, $matches ) ) {
|
||||||
$this->collection->type = 'proxy';
|
$this->collection->type = 'proxy';
|
||||||
$this->_is_proxy_request = true;
|
$this->_is_proxy_request = true;
|
||||||
$this->proxy_type = $matches[3];
|
$this->proxy_type = $matches[3];
|
||||||
$this->collection->dav_name = $matches[1].'/';
|
$this->collection->dav_name = $matches[1].'/';
|
||||||
|
$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->dav_name, $matches) ) {
|
||||||
$this->collection->dav_name = $matches[1].'/';
|
$this->collection->dav_name = $matches[1].'/';
|
||||||
@ -364,6 +452,8 @@ EOSQL;
|
|||||||
else if ( $this->dav_name == '/' ) {
|
else if ( $this->dav_name == '/' ) {
|
||||||
$this->collection->dav_name = '/';
|
$this->collection->dav_name = '/';
|
||||||
$this->collection->type = 'root';
|
$this->collection->type = 'root';
|
||||||
|
$this->collection->exists = true;
|
||||||
|
$this->collection->displayname = $c->system_name;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dbg_error_log( 'DAVResource', 'No collection for path "%s".', $this->dav_name );
|
dbg_error_log( 'DAVResource', 'No collection for path "%s".', $this->dav_name );
|
||||||
@ -371,24 +461,29 @@ EOSQL;
|
|||||||
$this->collection->dav_name = preg_replace('{/[^/]*$}', '/', $this->dav_name);
|
$this->collection->dav_name = preg_replace('{/[^/]*$}', '/', $this->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->dav_name || $this->collection->dav_name == $this->dav_name.'/' );
|
||||||
if ( $this->_is_collection ) {
|
if ( $this->_is_collection ) {
|
||||||
$this->dav_name = $this->collection->dav_name;
|
$this->dav_name = $this->collection->dav_name;
|
||||||
$this->_is_calendar = ($this->collection->type == 'calendar');
|
$this->_is_calendar = ($this->collection->type == 'calendar');
|
||||||
$this->_is_addressbook = ($this->collection->type == 'addressbook');
|
$this->_is_addressbook = ($this->collection->type == 'addressbook');
|
||||||
$this->contenttype = 'httpd/unix-directory';
|
$this->contenttype = 'httpd/unix-directory';
|
||||||
if ( isset($this->collection->dav_etag) ) $this->unique_tag = $this->collection->dav_etag;
|
if ( !isset($this->exists) && isset($this->collection->exists) ) {
|
||||||
if ( isset($this->collection->created) ) $this->created = $this->collection->created;
|
// If this seems peculiar it's because we only set it to false above...
|
||||||
if ( isset($this->collection->modified) ) $this->modified = $this->collection->modified;
|
$this->exists = $this->collection->exists;
|
||||||
if ( isset($this->collection->resourcetype) )
|
}
|
||||||
$this->resourcetype = $this->collection->resourcetype;
|
if ( $this->exists ) {
|
||||||
|
if ( isset($this->collection->dav_etag) ) $this->unique_tag = '"'.$this->collection->dav_etag.'"';
|
||||||
|
if ( isset($this->collection->created) ) $this->created = $this->collection->created;
|
||||||
|
if ( isset($this->collection->modified) ) $this->modified = $this->collection->modified;
|
||||||
|
if ( isset($this->collection->dav_displayname) ) $this->collection->displayname = $this->collection->dav_displayname;
|
||||||
|
}
|
||||||
|
if ( isset($this->collection->resourcetypes) )
|
||||||
|
$this->resourcetypes = $this->collection->resourcetypes;
|
||||||
else {
|
else {
|
||||||
$this->resourcetype = '<DAV::collection/>';
|
$this->resourcetypes = '<DAV::collection/>';
|
||||||
if ( $this->_is_principal )
|
if ( $this->_is_principal ) $this->resourcetypes .= '<DAV::principal/>';
|
||||||
$this->resourcetype .= '<DAV::principal/>';
|
|
||||||
else {
|
|
||||||
$this->exists = (!isset($this->collection->exists) || $this->collection->exists);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,12 +495,13 @@ EOSQL;
|
|||||||
function FetchPrincipal() {
|
function FetchPrincipal() {
|
||||||
global $c, $session;
|
global $c, $session;
|
||||||
$this->principal = new CalDAVPrincipal( array( "path" => $this->dav_name ) );
|
$this->principal = new CalDAVPrincipal( array( "path" => $this->dav_name ) );
|
||||||
if ( $this->IsPrincipal() ) {
|
if ( $this->_is_principal && $this->principal->Exists() ) {
|
||||||
$this->contenttype = 'httpd/unix-directory';
|
// $this->contenttype = 'httpd/unix-directory';
|
||||||
|
$this->exists = true;
|
||||||
$this->unique_tag = $this->principal->dav_etag;
|
$this->unique_tag = $this->principal->dav_etag;
|
||||||
$this->created = $this->principal->created;
|
$this->created = $this->principal->created;
|
||||||
$this->modified = $this->principal->modified;
|
$this->modified = $this->principal->modified;
|
||||||
$this->resourcetype = '<DAV::principal/>';
|
$this->resourcetypes = '<DAV::collection/><DAV::principal/>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +513,6 @@ EOSQL;
|
|||||||
global $c, $session;
|
global $c, $session;
|
||||||
|
|
||||||
if ( isset($this->exists) ) return; // True or false, we've got what we can already
|
if ( isset($this->exists) ) return; // True or false, we've got what we can already
|
||||||
if ( !isset($this->collection) ) $this->FetchCollection();
|
|
||||||
if ( $this->_is_collection ) return; // We have all we're going to read
|
if ( $this->_is_collection ) return; // We have all we're going to read
|
||||||
|
|
||||||
$sql = <<<EOQRY
|
$sql = <<<EOQRY
|
||||||
@ -433,8 +528,10 @@ EOQRY;
|
|||||||
$this->unique_tag = $this->resource->dav_etag;
|
$this->unique_tag = $this->resource->dav_etag;
|
||||||
$this->created = $this->resource->created;
|
$this->created = $this->resource->created;
|
||||||
$this->modified = $this->resource->modified;
|
$this->modified = $this->resource->modified;
|
||||||
$this->contenttype = 'text/calendar';
|
if ( substr($this->resource->caldav_data,0,15) == 'BEGIN:VCALENDAR' ) {
|
||||||
$this->resourcetype = '';
|
$this->contenttype = 'text/calendar';
|
||||||
|
}
|
||||||
|
$this->resourcetypes = '';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$this->exists = false;
|
$this->exists = false;
|
||||||
@ -442,6 +539,22 @@ EOQRY;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch any dead properties for this URL
|
||||||
|
*/
|
||||||
|
function FetchDeadProperties() {
|
||||||
|
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) );
|
||||||
|
if ( $qry->Exec('DAVResource') ) {
|
||||||
|
while ( $property = $qry->Fetch() ) {
|
||||||
|
$this->dead_properties[$property->property_name] = $property->property_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build permissions for this URL
|
* Build permissions for this URL
|
||||||
*/
|
*/
|
||||||
@ -450,32 +563,32 @@ EOQRY;
|
|||||||
|
|
||||||
if ( $this->dav_name == '/' || $this->dav_name == '' ) {
|
if ( $this->dav_name == '/' || $this->dav_name == '' ) {
|
||||||
$this->privileges = 1; // read
|
$this->privileges = 1; // read
|
||||||
// dbg_error_log( 'DAVResource', 'Read permissions for user accessing /' );
|
dbg_error_log( 'DAVResource', 'Read permissions for user accessing /' );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $session->AllowedTo('Admin') ) {
|
if ( $session->AllowedTo('Admin') ) {
|
||||||
$this->privileges = privilege_to_bits('all');
|
$this->privileges = privilege_to_bits('all');
|
||||||
// dbg_error_log( 'DAVResource', 'Full permissions for an administrator.' );
|
dbg_error_log( 'DAVResource', 'Full permissions for an administrator.' );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $this->IsPrincipal() ) {
|
if ( $this->IsPrincipal() ) {
|
||||||
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
||||||
$this->privileges = $this->principal->Privileges();
|
$this->privileges = $this->principal->Privileges();
|
||||||
// dbg_error_log( 'DAVResource', 'Privileges of "%s" for user accessing principal "%s"', $this->privileges, $this->principal->username );
|
dbg_error_log( 'DAVResource', 'Privileges of "%s" for user accessing principal "%s"', $this->privileges, $this->principal->username );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$this->privileges = 0;
|
$this->privileges = 0;
|
||||||
if ( !isset($this->collection) ) $this->FetchCollection();
|
|
||||||
if ( !isset($this->collection->path_privileges) ) {
|
if ( !isset($this->collection->path_privileges) ) {
|
||||||
$parent_path = preg_replace('{/[^/]*/$}', '/', $this->collection->dav_name );
|
$parent_path = preg_replace('{/[^/]*/$}', '/', $this->collection->dav_name );
|
||||||
// dbg_error_log( 'DAVResource', 'Checking privileges of "%s" - parent of "%s"', $parent_path, $this->collection->dav_name );
|
dbg_error_log( 'DAVResource', 'Checking privileges of "%s" - parent of "%s"', $parent_path, $this->collection->dav_name );
|
||||||
$parent = new DAVResource( $parent_path );
|
$parent = new DAVResource( $parent_path );
|
||||||
|
|
||||||
$this->collection->path_privileges = $parent->Privileges();
|
$this->collection->path_privileges = $parent->Privileges();
|
||||||
|
$this->collection->user_no = $parent->GetProperty('user_no');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->privileges = $this->collection->path_privileges;
|
$this->privileges = $this->collection->path_privileges;
|
||||||
@ -505,7 +618,7 @@ EOQRY;
|
|||||||
/**
|
/**
|
||||||
* Returns the array of privilege names converted into XMLElements
|
* Returns the array of privilege names converted into XMLElements
|
||||||
*/
|
*/
|
||||||
function BuildPrivileges( $privilege_names=null, $xmldoc=null ) {
|
function BuildPrivileges( $privilege_names=null, &$xmldoc=null ) {
|
||||||
if ( $privilege_names == null ) {
|
if ( $privilege_names == null ) {
|
||||||
if ( !isset($this->privileges) ) $this->FetchPrivileges();
|
if ( !isset($this->privileges) ) $this->FetchPrivileges();
|
||||||
$privilege_names = bits_to_privilege($this->privileges);
|
$privilege_names = bits_to_privilege($this->privileges);
|
||||||
@ -530,7 +643,6 @@ EOQRY;
|
|||||||
*/
|
*/
|
||||||
function FetchSupportedMethods( ) {
|
function FetchSupportedMethods( ) {
|
||||||
if ( isset($this->supported_methods) ) return $this->supported_methods;
|
if ( isset($this->supported_methods) ) return $this->supported_methods;
|
||||||
if ( !isset($this->collection) ) $this->FetchCollection();
|
|
||||||
|
|
||||||
$this->supported_methods = array(
|
$this->supported_methods = array(
|
||||||
'OPTIONS' => '',
|
'OPTIONS' => '',
|
||||||
@ -643,7 +755,7 @@ EOQRY;
|
|||||||
* Checks whether this resource is a principal
|
* Checks whether this resource is a principal
|
||||||
*/
|
*/
|
||||||
function IsPrincipal() {
|
function IsPrincipal() {
|
||||||
return $this->_is_collection;
|
return $this->_is_collection && $this->_is_principal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -651,7 +763,19 @@ EOQRY;
|
|||||||
* Checks whether this resource is a calendar
|
* Checks whether this resource is a calendar
|
||||||
*/
|
*/
|
||||||
function IsCalendar() {
|
function IsCalendar() {
|
||||||
return $this->_is_calendar;
|
return $this->_is_collection && $this->_is_calendar;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether this resource is a calendar
|
||||||
|
* @param string $type The type of scheduling collection, 'read', 'write' or 'any'
|
||||||
|
*/
|
||||||
|
function IsSchedulingCollection( $type = 'any' ) {
|
||||||
|
if ( $this->_is_collection && preg_match( '{schedule-(inbox|outbox)}', $this->collection->type, $matches ) ) {
|
||||||
|
return ($type == 'any' || $type == $matches[1]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -659,7 +783,7 @@ EOQRY;
|
|||||||
* Checks whether this resource is an addressbook
|
* Checks whether this resource is an addressbook
|
||||||
*/
|
*/
|
||||||
function IsAddressbook() {
|
function IsAddressbook() {
|
||||||
return $this->_is_addressbook;
|
return $this->_is_collection && $this->_is_addressbook;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -672,10 +796,7 @@ EOQRY;
|
|||||||
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
||||||
$this->exists = $this->principal->Exists();
|
$this->exists = $this->principal->Exists();
|
||||||
}
|
}
|
||||||
else if ( $this->IsCollection() ) {
|
else if ( ! $this->IsCollection() ) {
|
||||||
if ( !isset($this->collection) ) $this->FetchCollection();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( !isset($this->resource) ) $this->FetchResource();
|
if ( !isset($this->resource) ) $this->FetchResource();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -710,11 +831,8 @@ EOQRY;
|
|||||||
*/
|
*/
|
||||||
function unique_tag() {
|
function unique_tag() {
|
||||||
if ( isset($this->unique_tag) ) return $this->unique_tag;
|
if ( isset($this->unique_tag) ) return $this->unique_tag;
|
||||||
if ( $this->IsCollection() && !isset($this->collection) ) {
|
if ( $this->IsPrincipal() && !isset($this->principal) ) $this->FetchPrincipal();
|
||||||
$this->FetchCollection();
|
else if ( !$this->_is_collection && !isset($this->resource) ) $this->FetchResource();
|
||||||
if ( $this->IsPrincipal() && !isset($this->principal) ) $this->FetchPrincipal();
|
|
||||||
}
|
|
||||||
else if ( !isset($this->resource) ) $this->FetchResource();
|
|
||||||
|
|
||||||
if ( $this->exists !== true || !isset($this->unique_tag) ) $this->unique_tag = '';
|
if ( $this->exists !== true || !isset($this->unique_tag) ) $this->unique_tag = '';
|
||||||
|
|
||||||
@ -726,7 +844,6 @@ EOQRY;
|
|||||||
* Checks whether the target collection is publicly_readable
|
* Checks whether the target collection is publicly_readable
|
||||||
*/
|
*/
|
||||||
function IsPublic() {
|
function IsPublic() {
|
||||||
if ( !isset($this->collection) ) $this->FetchCollection();
|
|
||||||
return ( isset($this->collection->publicly_readable) && $this->collection->publicly_readable == 't' );
|
return ( isset($this->collection->publicly_readable) && $this->collection->publicly_readable == 't' );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -735,7 +852,6 @@ EOQRY;
|
|||||||
* Return the type of whatever contains this resource, or would if it existed.
|
* Return the type of whatever contains this resource, or would if it existed.
|
||||||
*/
|
*/
|
||||||
function ContainerType() {
|
function ContainerType() {
|
||||||
if ( !isset($this->collection) ) $this->FetchCollection();
|
|
||||||
if ( $this->IsPrincipal() ) return 'root';
|
if ( $this->IsPrincipal() ) return 'root';
|
||||||
if ( !$this->IsCollection() ) return $this->collection->type;
|
if ( !$this->IsCollection() ) return $this->collection->type;
|
||||||
|
|
||||||
@ -772,15 +888,21 @@ EOQRY;
|
|||||||
function GetProperty( $name ) {
|
function GetProperty( $name ) {
|
||||||
global $c, $session;
|
global $c, $session;
|
||||||
|
|
||||||
// dbg_error_log( 'DAVResource', 'Processing "%s".', $name );
|
// dbg_error_log( 'DAVResource', ':GetProperty: Fetching "%s".', $name );
|
||||||
$value = null;
|
$value = null;
|
||||||
|
|
||||||
switch( $name ) {
|
switch( $name ) {
|
||||||
case 'collection_id':
|
case 'collection_id':
|
||||||
if ( !isset($this->collection) ) $this->FetchCollection();
|
|
||||||
return $this->collection->collection_id;
|
return $this->collection->collection_id;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'resourcetype':
|
||||||
|
if ( isset($this->resourcetypes) ) {
|
||||||
|
$this->resourcetypes = preg_replace('{^<(.*)/>$}', '$1', $this->resourcetypes);
|
||||||
|
$type_list = explode('/><', $this->resourcetypes);
|
||||||
|
return $type_list;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if ( $this->_is_principal ) {
|
if ( $this->_is_principal ) {
|
||||||
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
||||||
@ -788,7 +910,6 @@ EOQRY;
|
|||||||
if ( isset($this->collection->{$name}) ) return $this->collection->{$name};
|
if ( isset($this->collection->{$name}) ) return $this->collection->{$name};
|
||||||
}
|
}
|
||||||
else if ( $this->_is_collection ) {
|
else if ( $this->_is_collection ) {
|
||||||
if ( !isset($this->collection) ) $this->FetchCollection();
|
|
||||||
if ( isset($this->collection->{$name}) ) return $this->collection->{$name};
|
if ( isset($this->collection->{$name}) ) return $this->collection->{$name};
|
||||||
if ( isset($this->principal->{$name}) ) return $this->principal->{$name};
|
if ( isset($this->principal->{$name}) ) return $this->principal->{$name};
|
||||||
}
|
}
|
||||||
@ -797,55 +918,89 @@ EOQRY;
|
|||||||
if ( isset($this->resource->{$name}) ) return $this->resource->{$name};
|
if ( isset($this->resource->{$name}) ) return $this->resource->{$name};
|
||||||
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
||||||
if ( isset($this->principal->{$name}) ) return $this->principal->{$name};
|
if ( isset($this->principal->{$name}) ) return $this->principal->{$name};
|
||||||
if ( !isset($this->collection) ) $this->FetchCollection();
|
|
||||||
if ( isset($this->collection->{$name}) ) return $this->collection->{$name};
|
if ( isset($this->collection->{$name}) ) return $this->collection->{$name};
|
||||||
}
|
}
|
||||||
dbg_error_log( 'ERROR', 'Request for property "%s" which is not understood.', $name );
|
dbg_error_log( 'DAVResource', ':GetProperty: Failed to find property "%s" on "%s".', $name, $this->dav_name );
|
||||||
}
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array which is an expansion of the DAV::allprop
|
||||||
|
*/
|
||||||
|
function DAV_AllProperties() {
|
||||||
|
if ( isset($this->dead_properties) ) $this->FetchDeadProperties();
|
||||||
|
$allprop = array_merge( (isset($this->dead_properties)?$this->dead_properties:array()), array(
|
||||||
|
'DAV::getcontenttype', 'DAV::resourcetype', 'DAV::getcontentlength', 'DAV::displayname', 'DAV::getlastmodified',
|
||||||
|
'DAV::creationdate', 'DAV::getetag', 'DAV::getcontentlanguage', 'DAV::supportedlock', 'DAV::lockdiscovery',
|
||||||
|
'DAV::owner', 'DAV::principal-URL', 'DAV::current-user-principal'
|
||||||
|
) );
|
||||||
|
|
||||||
|
return $allprop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return general server-related properties for this URL
|
* Return general server-related properties for this URL
|
||||||
*/
|
*/
|
||||||
function ResourceProperty( $tag, $prop, $reply = null, &$denied ) {
|
function ResourceProperty( $tag, $prop, &$reply, &$denied ) {
|
||||||
global $c, $session;
|
global $c, $session;
|
||||||
|
|
||||||
|
// dbg_error_log( 'DAVResource', 'Processing "%s" on "%s".', $tag, $this->dav_name );
|
||||||
|
|
||||||
if ( $reply === null ) $reply = $GLOBALS['reply'];
|
if ( $reply === null ) $reply = $GLOBALS['reply'];
|
||||||
|
|
||||||
dbg_error_log( 'DAVResource', 'Processing "%s" on "%s".', $tag, $this->dav_name );
|
|
||||||
|
|
||||||
switch( $tag ) {
|
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':
|
case 'DAV::href':
|
||||||
$prop->NewElement('href', ConstructURL($this->dav_name) );
|
$prop->NewElement('href', ConstructURL($this->dav_name) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::getcontenttype':
|
case 'DAV::getcontenttype':
|
||||||
if ( isset($this->contenttype) ) $prop->NewElement('getcontenttype', $this->contenttype );
|
if ( !isset($this->contenttype) && !$this->_is_collection && !isset($this->resource) ) $this->FetchResource();
|
||||||
|
$prop->NewElement('getcontenttype', $this->contenttype );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::resourcetype':
|
case 'DAV::resourcetype':
|
||||||
$prop->NewElement('resourcetype', $this->resourcetype );
|
$resourcetypes = $prop->NewElement('resourcetype' );
|
||||||
break;
|
$type_list = $this->GetProperty('resourcetype');
|
||||||
|
if ( !is_array($type_list) ) return true;
|
||||||
case 'DAV::displayname':
|
dbg_error_log( 'DAVResource', ':ResourceProperty: "%s" are "%s".', $tag, implode(', ',$type_list) );
|
||||||
if ( isset($this->displayname) ) $prop->NewElement('displayname', $this->displayname );
|
foreach( $type_list AS $k => $v ) {
|
||||||
|
if ( $v == '' ) continue;
|
||||||
|
$reply->NSElement( $resourcetypes, $v );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::getlastmodified':
|
case 'DAV::getlastmodified':
|
||||||
$prop->NewElement('getlastmodified', $this->modified );
|
/** peculiarly, it seems that getlastmodified is HTTP Date format! */
|
||||||
|
$reply->NSElement($prop, $tag, ISODateToHTTPDate($this->GetProperty('modified')) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::creationdate':
|
case 'DAV::creationdate':
|
||||||
$prop->NewElement('creationdate', $this->created );
|
/** bizarrely, it seems that creationdate is ISO8601 format */
|
||||||
|
$reply->NSElement($prop, $tag, DateToISODate($this->GetProperty('created')) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DAV::getcontentlength':
|
||||||
|
if ( $this->_is_collection ) return false;
|
||||||
|
if ( !isset($this->resource) ) $this->FetchResource();
|
||||||
|
$reply->NSElement($prop, $tag, strlen($this->resource->caldav_data) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::getcontentlanguage':
|
case 'DAV::getcontentlanguage':
|
||||||
$locale = (isset($c->current_locale) ? $c->current_locale : '');
|
$locale = (isset($c->current_locale) ? $c->current_locale : '');
|
||||||
if ( isset($this->locale) && $this->locale != '' ) $locale = $this->locale;
|
if ( isset($this->locale) && $this->locale != '' ) $locale = $this->locale;
|
||||||
$prop->NewElement('getcontentlanguage', $locale );
|
$reply->NSElement($prop, $tag, $locale );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::owner':
|
case 'DAV::owner':
|
||||||
@ -855,46 +1010,77 @@ EOQRY;
|
|||||||
|
|
||||||
// Empty tag responses.
|
// Empty tag responses.
|
||||||
case 'DAV::alternate-URI-set':
|
case 'DAV::alternate-URI-set':
|
||||||
case 'DAV::getcontentlength':
|
$reply->NSElement($prop, $tag );
|
||||||
$prop->NewElement( $reply->Tag($tag));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::getetag':
|
case 'DAV::getetag':
|
||||||
if ( $this->_is_collection ) {
|
if ( $this->_is_collection ) return false;
|
||||||
return false;
|
$reply->NSElement($prop, $tag, $this->unique_tag() );
|
||||||
}
|
break;
|
||||||
else {
|
|
||||||
$prop->NewElement('getetag', $this->unique_tag );
|
case 'http://calendarserver.org/ns/:getctag':
|
||||||
|
if ( ! $this->_is_collection ) return false;
|
||||||
|
$reply->NSElement($prop, $tag, $this->unique_tag() );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://calendarserver.org/ns/:calendar-proxy-read-for':
|
||||||
|
$proxy_type = 'read';
|
||||||
|
case 'http://calendarserver.org/ns/:calendar-proxy-write-for':
|
||||||
|
if ( ! $this->_is_proxy_request ) return true;
|
||||||
|
if ( !isset($proxy_type) ) $proxy_type = 'write';
|
||||||
|
$reply->CalendarserverElement($prop, 'calendar-proxy-'.$proxy_type.'-for', $reply->href( $this->principal->ProxyFor($proxy_type) ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DAV::current-user-privilege-set':
|
||||||
|
$reply->NSElement($prop, $tag, $this->BuildPrivileges() );
|
||||||
|
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() )
|
||||||
|
$set_of_components = array( 'VEVENT', 'VTODO', 'VJOURNAL', 'VTIMEZONE', 'VFREEBUSY' );
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
case 'SOME-DENIED-PROPERTY': /** @todo indicating the style for future expansion */
|
case 'SOME-DENIED-PROPERTY': /** @todo indicating the style for future expansion */
|
||||||
$denied[] = $reply->Tag($tag);
|
$denied[] = $reply->Tag($tag);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'http://calendarserver.org/ns/:getctag':
|
|
||||||
if ( $this->_is_collection ) {
|
|
||||||
$prop->NewElement('http://calendarserver.org/ns/:getctag', $this->unique_tag );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'urn:ietf:params:xml:ns:caldav:calendar-data':
|
case 'urn:ietf:params:xml:ns:caldav:calendar-data':
|
||||||
if ( $this->_is_collection ) {
|
if ( $this->_is_collection ) return false;
|
||||||
if ( !isset($this->resource) ) $this->FetchResource();
|
if ( !isset($this->resource) ) $this->FetchResource();
|
||||||
$reply->CalDAVElement($prop, $k, $this->resource->caldav_data );
|
$reply->NSElement($prop, $tag, $this->resource->caldav_data );
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dbg_error_log( 'DAVResource', 'Request for unsupported property "%s" of path "%s".', $tag, $this->dav_name );
|
$property_value = $this->GetProperty(preg_replace('{^.*:}', '', $tag));
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,25 +1088,35 @@ EOQRY;
|
|||||||
/**
|
/**
|
||||||
* Construct XML propstat fragment for this resource
|
* Construct XML propstat fragment for this resource
|
||||||
*
|
*
|
||||||
* @param array $properties The requested properties for this resource
|
* @param array of string $properties The requested properties for this resource
|
||||||
*
|
*
|
||||||
* @return string An XML fragment with the requested properties for this resource
|
* @return string An XML fragment with the requested properties for this resource
|
||||||
*/
|
*/
|
||||||
function GetPropStat( $properties ) {
|
function GetPropStat( $properties, &$reply, $props_only = false ) {
|
||||||
global $session, $c, $request, $reply;
|
global $request;
|
||||||
|
|
||||||
dbg_error_log('DAVResource',': GetPropStat: href "%s"', $this->dav_name );
|
dbg_error_log('DAVResource',':GetPropStat: propstat for href "%s"', $this->dav_name );
|
||||||
|
|
||||||
$prop = new XMLElement('prop');
|
$prop = new XMLElement('prop');
|
||||||
$denied = array();
|
$denied = array();
|
||||||
$not_found = array();
|
$not_found = array();
|
||||||
foreach( $properties AS $k => $tag ) {
|
foreach( $properties AS $k => $tag ) {
|
||||||
// dbg_error_log( 'DAVResource', 'Looking at resource "%s" for property [%s]"%s".', $this->dav_name, $k, $tag );
|
if ( is_object($tag) ) {
|
||||||
if ( ! $this->ResourceProperty($tag, $prop, $reply, $denied ) ) {
|
dbg_error_log( 'DAVResource', ':GetPropStat: "$properties" should be an array of text. Assuming this object is an XMLElement!.' );
|
||||||
|
$tag = $tag->GetTag();
|
||||||
|
}
|
||||||
|
$found = $this->ResourceProperty($tag, $prop, $reply, $denied );
|
||||||
|
if ( !$found ) {
|
||||||
|
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
||||||
|
$found = $this->principal->PrincipalProperty( $tag, $prop, $reply, $denied );
|
||||||
|
}
|
||||||
|
if ( ! $found && ! $request->ServerProperty($tag, $prop, $reply) ) {
|
||||||
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->dav_name );
|
||||||
$not_found[] = $reply->Tag($tag);
|
$not_found[] = $reply->Tag($tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( $props_only ) return $prop;
|
||||||
|
|
||||||
$status = new XMLElement('status', 'HTTP/1.1 200 OK' );
|
$status = new XMLElement('status', 'HTTP/1.1 200 OK' );
|
||||||
|
|
||||||
$elements = array( new XMLElement( 'propstat', array($prop,$status) ) );
|
$elements = array( new XMLElement( 'propstat', array($prop,$status) ) );
|
||||||
@ -958,44 +1154,17 @@ EOQRY;
|
|||||||
function RenderAsXML( $properties, &$reply, $props_only = false ) {
|
function RenderAsXML( $properties, &$reply, $props_only = false ) {
|
||||||
global $session, $c, $request;
|
global $session, $c, $request;
|
||||||
|
|
||||||
dbg_error_log('DAVResource',': RenderAsXML: Principal "%s"', $this->username );
|
dbg_error_log('DAVResource',':RenderAsXML: Resource "%s"', $this->dav_name );
|
||||||
|
|
||||||
$prop = new XMLElement('prop');
|
if ( !$this->Exists() ) return null;
|
||||||
$denied = array();
|
|
||||||
$not_found = array();
|
if ( $props_only ) {
|
||||||
foreach( $properties AS $k => $tag ) {
|
dbg_error_log('LOG WARNING','DAVResource::RenderAsXML Called misguidedly - should be to DAVResource::GetPropStat' );
|
||||||
if ( ! $this->ResourceProperty($tag, $prop, $reply) ) {
|
return $this->GetPropStat( $properties, $reply, true );
|
||||||
dbg_error_log( 'DAVResource', 'Request for unsupported property "%s" of principal "%s".', $tag, $this->username );
|
|
||||||
$not_found[] = $reply->Tag($tag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $props_only ) return $prop;
|
$elements = $this->GetPropStat( $properties, $reply );
|
||||||
|
array_unshift( $elements, $reply->href(ConstructURL($this->dav_name)));
|
||||||
$status = new XMLElement('status', 'HTTP/1.1 200 OK' );
|
|
||||||
|
|
||||||
$propstat = new XMLElement( 'propstat', array( $prop, $status) );
|
|
||||||
$href = $reply->href( ConstructURL($this->dav_name) ); /** @TODO: make ::href() into an accessor */
|
|
||||||
|
|
||||||
$elements = array($href,$propstat);
|
|
||||||
|
|
||||||
if ( count($denied) > 0 ) {
|
|
||||||
$status = new XMLElement('status', 'HTTP/1.1 403 Forbidden' );
|
|
||||||
$noprop = new XMLElement('prop');
|
|
||||||
foreach( $denied AS $k => $v ) {
|
|
||||||
$noprop->NewElement( $v );
|
|
||||||
}
|
|
||||||
$elements[] = new XMLElement( 'propstat', array( $noprop, $status) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( count($not_found) > 0 ) {
|
|
||||||
$status = new XMLElement('status', 'HTTP/1.1 404 Not Found' );
|
|
||||||
$noprop = new XMLElement('prop');
|
|
||||||
foreach( $not_found AS $k => $v ) {
|
|
||||||
$noprop->NewElement( $v );
|
|
||||||
}
|
|
||||||
$elements[] = new XMLElement( 'propstat', array( $noprop, $status) );
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = new XMLElement( 'response', $elements );
|
$response = new XMLElement( 'response', $elements );
|
||||||
|
|
||||||
|
|||||||
@ -298,3 +298,12 @@ function ISODateToHTTPDate( $isodate ) {
|
|||||||
// Use strtotime since strptime is not available on Windows platform.
|
// Use strtotime since strptime is not available on Windows platform.
|
||||||
return( gmstrftime('%a, %d %b %Y %T GMT', strtotime($isodate)) );
|
return( gmstrftime('%a, %d %b %Y %T GMT', strtotime($isodate)) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a date into ISO format into the sparkly new ISO format.
|
||||||
|
* @param string $indate The date to convert
|
||||||
|
*/
|
||||||
|
function DateToISODate( $indate ) {
|
||||||
|
// Use strtotime since strptime is not available on Windows platform.
|
||||||
|
return( date('c', strtotime($indate)) );
|
||||||
|
}
|
||||||
|
|||||||
@ -298,3 +298,12 @@ function ISODateToHTTPDate( $isodate ) {
|
|||||||
// Use strtotime since strptime is not available on Windows platform.
|
// Use strtotime since strptime is not available on Windows platform.
|
||||||
return( gmstrftime('%a, %d %b %Y %T GMT', strtotime($isodate)) );
|
return( gmstrftime('%a, %d %b %Y %T GMT', strtotime($isodate)) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a date into ISO format into the sparkly new ISO format.
|
||||||
|
* @param string $indate The date to convert
|
||||||
|
*/
|
||||||
|
function DateToISODate( $indate ) {
|
||||||
|
// Use strtotime since strptime is not available on Windows platform.
|
||||||
|
return( date('c', strtotime($indate)) );
|
||||||
|
}
|
||||||
|
|||||||
@ -120,7 +120,7 @@ if ( $src->IsCollection() ) {
|
|||||||
$sql = 'UPDATE collection SET dav_name = :dst_name ';
|
$sql = 'UPDATE collection SET dav_name = :dst_name ';
|
||||||
$params = array(':dst_name' => $dst_name);
|
$params = array(':dst_name' => $dst_name);
|
||||||
if ( $src_user_no != $dst_user_no ) {
|
if ( $src_user_no != $dst_user_no ) {
|
||||||
$sql .= ', user_no = :dst_user_no';
|
$sql .= ', user_no = :dst_user_no ';
|
||||||
$params[':dst_user_no'] = $dst_user_no;
|
$params[':dst_user_no'] = $dst_user_no;
|
||||||
}
|
}
|
||||||
$sql .= 'WHERE collection_id = :src_collection';
|
$sql .= 'WHERE collection_id = :src_collection';
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
* return true if it's a whole calendar
|
* return true if it's a whole calendar
|
||||||
*/
|
*/
|
||||||
|
|
||||||
include_once('iCalendar.php');
|
require_once('iCalendar.php');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A regex which will match most reasonable timezones acceptable to PostgreSQL.
|
* A regex which will match most reasonable timezones acceptable to PostgreSQL.
|
||||||
|
|||||||
@ -39,7 +39,7 @@ foreach( $searches AS $k => $search ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( $where != "" ) $where = "WHERE $where";
|
if ( $where != "" ) $where = "WHERE $where";
|
||||||
$sql = "SELECT * FROM usr $where";
|
$sql = "SELECT * FROM usr JOIN principal USING(user_no) $where";
|
||||||
$qry = new PgQuery($sql);
|
$qry = new PgQuery($sql);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -103,7 +103,7 @@ if ( $qry->Exec("REPORT",__LINE__,__FILE__) ) {
|
|||||||
);
|
);
|
||||||
if ( $object->sync_status != 404 ) {
|
if ( $object->sync_status != 404 ) {
|
||||||
$dav_resource = new DAVResource($object);
|
$dav_resource = new DAVResource($object);
|
||||||
$resultset = array_merge( $resultset, $dav_resource->GetPropStat($proplist) );
|
$resultset = array_merge( $resultset, $dav_resource->GetPropStat($proplist,$reply) );
|
||||||
}
|
}
|
||||||
$responses[] = new XMLElement( 'sync-response', $resultset );
|
$responses[] = new XMLElement( 'sync-response', $resultset );
|
||||||
$first_status = $object->sync_status;
|
$first_status = $object->sync_status;
|
||||||
|
|||||||
@ -60,13 +60,6 @@ switch( $xmltree->GetTag() ) {
|
|||||||
exit; // Not that it should return anyway.
|
exit; // Not that it should return anyway.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must have read privilege for all other reports
|
|
||||||
if ( ! ($request->AllowedTo('read') ) ) {
|
|
||||||
// If they got this far they *do* have freebusy access, so can know the
|
|
||||||
// calendar really exists. Informing them is therefore OK.
|
|
||||||
$request->DoResponse( 404, translate("You may not access that calendar") );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return XML for a single calendar (or todo) entry from the DB
|
* Return XML for a single calendar (or todo) entry from the DB
|
||||||
@ -88,7 +81,7 @@ function calendar_to_xml( $properties, $item ) {
|
|||||||
if ( !$request->AllowedTo('all') && $session->user_no != $item->user_no ){
|
if ( !$request->AllowedTo('all') && $session->user_no != $item->user_no ){
|
||||||
// the user is not admin / owner of this calendarlooking at his calendar and can not admin the other cal
|
// the user is not admin / owner of this calendarlooking at his calendar and can not admin the other cal
|
||||||
/** @todo We should examine the ORGANIZER and ATTENDEE fields in the event. If this person is there then they should see this */
|
/** @todo We should examine the ORGANIZER and ATTENDEE fields in the event. If this person is there then they should see this */
|
||||||
if ( $item->class == 'CONFIDENTIAL' ) {
|
if ( $item->class == 'CONFIDENTIAL' || !$request->AllowedTo('read') ) {
|
||||||
$ical = new iCalComponent( $caldav_data );
|
$ical = new iCalComponent( $caldav_data );
|
||||||
$resources = $ical->GetComponents('VTIMEZONE',false);
|
$resources = $ical->GetComponents('VTIMEZONE',false);
|
||||||
$first = $resources[0];
|
$first = $resources[0];
|
||||||
@ -106,6 +99,7 @@ function calendar_to_xml( $properties, $item ) {
|
|||||||
$ical->SetComponents(array($confidential),$confidential->GetType());
|
$ical->SetComponents(array($confidential),$confidential->GetType());
|
||||||
|
|
||||||
$caldav_data = $ical->Render();
|
$caldav_data = $ical->Render();
|
||||||
|
$displayname = translate('Busy');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user