mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-09-19 05:59:02 +00:00
Remove case-folding of incoming XML.
This commit is contained in:
parent
a8ae3b1406
commit
5ec4c33670
@ -52,11 +52,23 @@ class CalDAVPrincipal
|
|||||||
*/
|
*/
|
||||||
var $by_email;
|
var $by_email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var RFC3744: The principals that are direct members of this group.
|
||||||
|
*/
|
||||||
|
var $group_member_set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var RFC3744: The groups in which the principal is directly a member.
|
||||||
|
*/
|
||||||
|
var $group_membership;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param mixed $parameters If null, an empty Principal is created. If it
|
* @param mixed $parameters If null, an empty Principal is created. If it
|
||||||
* is an integer then that ID is read (if possible). If it is
|
* is an integer then that ID is read (if possible). If it is
|
||||||
* an array then the Principal matching the supplied elements is read.
|
* an array then the Principal matching the supplied elements
|
||||||
|
* is read. If it is an object then it is expected to be a 'usr'
|
||||||
|
* record that was read elsewhere.
|
||||||
*
|
*
|
||||||
* @return boolean Whether we actually read data from the DB to initialise the record.
|
* @return boolean Whether we actually read data from the DB to initialise the record.
|
||||||
*/
|
*/
|
||||||
@ -65,7 +77,11 @@ class CalDAVPrincipal
|
|||||||
|
|
||||||
if ( $parameters == null ) return false;
|
if ( $parameters == null ) return false;
|
||||||
$this->by_email = false;
|
$this->by_email = false;
|
||||||
if ( is_int($parameters) ) {
|
if ( is_object($parameters) ) {
|
||||||
|
dbg_error_log( "principal", "Principal: record for %s", $parameters->username );
|
||||||
|
$usr = $parameters;
|
||||||
|
}
|
||||||
|
else if ( is_int($parameters) ) {
|
||||||
dbg_error_log( "principal", "Principal: %d", $parameters );
|
dbg_error_log( "principal", "Principal: %d", $parameters );
|
||||||
$usr = getUserByID($parameters);
|
$usr = getUserByID($parameters);
|
||||||
}
|
}
|
||||||
@ -110,17 +126,43 @@ class CalDAVPrincipal
|
|||||||
$this->url = ConstructURL( "/".$this->username."/" );
|
$this->url = ConstructURL( "/".$this->username."/" );
|
||||||
// $this->url = ConstructURL( "/__uuids__/" . $this->username . "/" );
|
// $this->url = ConstructURL( "/__uuids__/" . $this->username . "/" );
|
||||||
|
|
||||||
$this->calendar_home_set = ConstructURL( "/".$this->username."/" );
|
// $qry = new PgQuery("SELECT dav_name FROM collection WHERE user_no = ?", $this->user_no);
|
||||||
|
// // Should be only one record, but this might change in future.
|
||||||
|
// $qry = new PgQuery("SELECT DISTINCT parent_container FROM collection WHERE user_no = ?", $this->user_no);
|
||||||
|
// $this->calendar_home_set = array();
|
||||||
|
// if( $qry->Exec("CalDAVPrincipal",__LINE__,__FILE__) && $qry->rows > 0 ) {
|
||||||
|
// while( $calendar = $qry->Fetch() ) {
|
||||||
|
// $this->calendar_home_set[] = ConstructURL($calendar->dav_name);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
$this->calendar_home_set = array( $this->url );
|
||||||
|
|
||||||
$this->user_address_set = array(
|
$this->user_address_set = array(
|
||||||
|
"mailto:".$this->email,
|
||||||
ConstructURL( "/".$this->username."/" ),
|
ConstructURL( "/".$this->username."/" ),
|
||||||
// ConstructURL( "/~".$this->username."/" ),
|
// ConstructURL( "/~".$this->username."/" ),
|
||||||
// ConstructURL( "/__uuids__/".$this->username."/" ),
|
// ConstructURL( "/__uuids__/".$this->username."/" ),
|
||||||
);
|
);
|
||||||
$this->schedule_inbox_url = sprintf( "%s.in/", $this->calendar_home_set);
|
$this->schedule_inbox_url = sprintf( "%s.in/", $this->url);
|
||||||
$this->schedule_outbox_url = sprintf( "%s.out/", $this->calendar_home_set);
|
$this->schedule_outbox_url = sprintf( "%s.out/", $this->url);
|
||||||
$this->dropbox_url = sprintf( "%s.drop/", $this->calendar_home_set);
|
$this->dropbox_url = sprintf( "%s.drop/", $this->url);
|
||||||
$this->notifications_url = sprintf( "%s.notify/", $this->calendar_home_set);
|
$this->notifications_url = sprintf( "%s.notify/", $this->url);
|
||||||
|
|
||||||
|
$this->group_member_set = array();
|
||||||
|
$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 );
|
||||||
|
if ( $qry->Exec("CalDAVPrincipal") && $qry->rows > 0 ) {
|
||||||
|
while( $membership = $qry->Fetch() ) {
|
||||||
|
$this->group_member_set[] = ConstructURL( "/". $membership->username . "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$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 . "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dbg_error_log( "principal", "User: %s (%d) URL: %s, Home: %s, By Email: %d", $this->username, $this->user_no, $this->url, $this->calendar_home_set, $this->by_email );
|
dbg_error_log( "principal", "User: %s (%d) URL: %s, Home: %s, By Email: %d", $this->username, $this->user_no, $this->url, $this->calendar_home_set, $this->by_email );
|
||||||
}
|
}
|
||||||
@ -167,5 +209,189 @@ class CalDAVPrincipal
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the array of privilege names converted into XMLElements
|
||||||
|
*/
|
||||||
|
function RenderPrivileges($privilege_names, $container="privilege") {
|
||||||
|
$privileges = array();
|
||||||
|
foreach( $privilege_names AS $k => $v ) {
|
||||||
|
$privileges[] = new XMLElement($container, new XMLElement($k));
|
||||||
|
}
|
||||||
|
return $privileges;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render XML for a single Principal (user) from the DB
|
||||||
|
*
|
||||||
|
* @param array $properties The requested properties for this principal
|
||||||
|
* @param reference $reply A reference to the XMLDocument being used for the reply
|
||||||
|
* @param boolean $props_only Default false. If true will only return the fragment with the properties, not a full response fragment.
|
||||||
|
*
|
||||||
|
* @return string An XML fragment with the requested properties for this principal
|
||||||
|
*/
|
||||||
|
function RenderAsXML( $properties, &$reply, $props_only = false ) {
|
||||||
|
global $session, $c, $request;
|
||||||
|
|
||||||
|
dbg_error_log("CalDAVPrincipal",": RenderAsXML: Principal '%s'", $this->username );
|
||||||
|
|
||||||
|
$prop = new XMLElement("prop");
|
||||||
|
$denied = array();
|
||||||
|
$not_found = array();
|
||||||
|
foreach( $properties AS $k => $tag ) {
|
||||||
|
dbg_error_log("CalDAVPrincipal",": 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", $this->url );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DAV::getlastmodified':
|
||||||
|
$prop->NewElement("getlastmodified", $this->modified );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DAV::group-member-set':
|
||||||
|
$set = array();
|
||||||
|
foreach( $this->group_member_set AS $k => $url ) {
|
||||||
|
$set[] = new XMLElement('href', $url );
|
||||||
|
}
|
||||||
|
$prop->NewElement("group-member-set", $set );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DAV::group-membership':
|
||||||
|
$set = array();
|
||||||
|
foreach( $this->group_membership AS $k => $url ) {
|
||||||
|
$set[] = new XMLElement('href', $url );
|
||||||
|
}
|
||||||
|
$prop->NewElement("group-membership", $set );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'urn:ietf:params:xml:ns:caldav:schedule-inbox-URL':
|
||||||
|
$prop->NewElement($reply->Caldav("schedule-inbox-URL"), new XMLElement('href', $this->schedule_inbox_url) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'urn:ietf:params:xml:ns:caldav:schedule-outbox-URL':
|
||||||
|
$prop->NewElement($reply->Caldav("schedule-outbox-URL"), new XMLElement('href', $this->schedule_outbox_url) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://calendarserver.org/ns/:dropbox-home-URL':
|
||||||
|
$prop->NewElement($reply->Calendarserver("dropbox-home-URL"), new XMLElement('href', $this->dropbox_url) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://calendarserver.org/ns/:notifications-URL':
|
||||||
|
$prop->NewElement($reply->Calendarserver("notifications-URL"), new XMLElement('href', $this->notifications_url) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'urn:ietf:params:xml:ns:caldav:calendar-home-set':
|
||||||
|
$set = array();
|
||||||
|
foreach( $this->calendar_home_set AS $k => $url ) {
|
||||||
|
$set[] = new XMLElement('href', $url );
|
||||||
|
}
|
||||||
|
$prop->NewElement($reply->Caldav("calendar-home-set"), $set );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'urn:ietf:params:xml:ns:caldav:calendar-user-address-set':
|
||||||
|
$set = array();
|
||||||
|
foreach( $this->user_address_set AS $k => $v ) {
|
||||||
|
$set[] = new XMLElement('href', $v );
|
||||||
|
}
|
||||||
|
$prop->NewElement($reply->Caldav("calendar-user-address-set"), $set );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DAV::getcontentlanguage':
|
||||||
|
$locale = $c->current_locale;
|
||||||
|
if ( isset($this->locale) && $this->locale != "" ) $locale = $this->locale;
|
||||||
|
$prop->NewElement("getcontentlanguage", $locale );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DAV::supportedlock':
|
||||||
|
$prop->NewElement("supportedlock",
|
||||||
|
new XMLElement( "lockentry",
|
||||||
|
array(
|
||||||
|
new XMLElement("lockscope", new XMLElement("exclusive")),
|
||||||
|
new XMLElement("locktype", new XMLElement("write")),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DAV::acl':
|
||||||
|
/**
|
||||||
|
* FIXME: This information is semantically valid but presents an incorrect picture.
|
||||||
|
*/
|
||||||
|
$principal = new XMLElement("principal");
|
||||||
|
$principal->NewElement("authenticated");
|
||||||
|
$grant = new XMLElement( "grant", array($this->RenderPrivileges($request->permissions)) );
|
||||||
|
$prop->NewElement("acl", new XMLElement( "ace", array( $principal, $grant ) ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DAV::current-user-privilege-set':
|
||||||
|
$prop->NewElement("current-user-privilege-set", $this->RenderPrivileges($request->permissions) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DAV::supported-privilege-set':
|
||||||
|
$prop->NewElement("supported-privilege-set", $this->RenderPrivileges( $request->SupportedPrivileges(), "supported-privilege") );
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Empty tag responses.
|
||||||
|
case 'DAV::creationdate':
|
||||||
|
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;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dbg_error_log( 'CalDAVPrincipal', "Request for unsupported property '%s' of principal.", $item->username );
|
||||||
|
$not_found[] = $reply->Tag($tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $props_only ) return $prop;
|
||||||
|
|
||||||
|
$status = new XMLElement("status", "HTTP/1.1 200 OK" );
|
||||||
|
|
||||||
|
$propstat = new XMLElement( "propstat", array( $prop, $status) );
|
||||||
|
$href = new XMLElement("href", $this->url );
|
||||||
|
|
||||||
|
$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( strtolower($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( strtolower($v) );
|
||||||
|
}
|
||||||
|
$elements[] = new XMLElement( "propstat", array( $noprop, $status) );
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = new XMLElement( "response", $elements );
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -220,6 +220,7 @@ class CalDAVRequest
|
|||||||
$xml_parser = xml_parser_create_ns('UTF-8');
|
$xml_parser = xml_parser_create_ns('UTF-8');
|
||||||
$this->xml_tags = array();
|
$this->xml_tags = array();
|
||||||
xml_parser_set_option ( $xml_parser, XML_OPTION_SKIP_WHITE, 1 );
|
xml_parser_set_option ( $xml_parser, XML_OPTION_SKIP_WHITE, 1 );
|
||||||
|
xml_parser_set_option ( $xml_parser, XML_OPTION_CASE_FOLDING, 0 );
|
||||||
xml_parse_into_struct( $xml_parser, $this->raw_post, $this->xml_tags );
|
xml_parse_into_struct( $xml_parser, $this->raw_post, $this->xml_tags );
|
||||||
xml_parser_free($xml_parser);
|
xml_parser_free($xml_parser);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* @package rscds
|
* @package davical
|
||||||
* @author Andrew McMillan <andrew@catalyst.net.nz>
|
* @author Andrew McMillan <andrew@catalyst.net.nz>
|
||||||
* @copyright Catalyst .Net Ltd
|
* @copyright Catalyst .Net Ltd
|
||||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||||
@ -96,7 +96,7 @@ awl_set_locale($c->default_locale);
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
$c->code_version = 0;
|
$c->code_version = 0;
|
||||||
$c->version_string = '0.9.5.2'; // The actual version # is replaced into that during the build /release process
|
$c->version_string = '0.9.5.4'; // The actual version # is replaced into that during the build /release process
|
||||||
if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) {
|
if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) {
|
||||||
$c->code_major = $matches[1];
|
$c->code_major = $matches[1];
|
||||||
$c->code_minor = $matches[2];
|
$c->code_minor = $matches[2];
|
||||||
|
|||||||
@ -134,7 +134,7 @@ function getUserByName( $username, $use_cache = true ) {
|
|||||||
// Provide some basic caching in case this ends up being overused.
|
// Provide some basic caching in case this ends up being overused.
|
||||||
if ( $use_cache && isset( $_known_users_name[$username] ) ) return $_known_users_name[$username];
|
if ( $use_cache && isset( $_known_users_name[$username] ) ) return $_known_users_name[$username];
|
||||||
|
|
||||||
$qry = new PgQuery( "SELECT * FROM usr WHERE lower(username) = lower(?) ", $username );
|
$qry = new PgQuery( "SELECT *, to_char(updated at time zone 'GMT','Dy, DD Mon IYYY HH24:MI:SS \"GMT\"') AS modified FROM usr WHERE lower(username) = lower(?) ", $username );
|
||||||
if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) {
|
if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) {
|
||||||
$_known_users_name[$username] = $qry->Fetch();
|
$_known_users_name[$username] = $qry->Fetch();
|
||||||
$id = $_known_users_name[$username]->user_no;
|
$id = $_known_users_name[$username]->user_no;
|
||||||
@ -155,7 +155,7 @@ function getUserByID( $user_no, $use_cache = true ) {
|
|||||||
// Provide some basic caching in case this ends up being overused.
|
// Provide some basic caching in case this ends up being overused.
|
||||||
if ( $use_cache && isset( $_known_users_id[$user_no] ) ) return $_known_users_id[$user_no];
|
if ( $use_cache && isset( $_known_users_id[$user_no] ) ) return $_known_users_id[$user_no];
|
||||||
|
|
||||||
$qry = new PgQuery( "SELECT * FROM usr WHERE user_no = ? ", intval($user_no) );
|
$qry = new PgQuery( "SELECT *, to_char(updated at time zone 'GMT','Dy, DD Mon IYYY HH24:MI:SS \"GMT\"') AS modified FROM usr WHERE user_no = ? ", intval($user_no) );
|
||||||
if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) {
|
if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) {
|
||||||
$_known_users_id[$user_no] = $qry->Fetch();
|
$_known_users_id[$user_no] = $qry->Fetch();
|
||||||
$name = $_known_users_id[$user_no]->username;
|
$name = $_known_users_id[$user_no]->username;
|
||||||
|
|||||||
@ -18,7 +18,7 @@ foreach( $request->xml_tags AS $k => $v ) {
|
|||||||
$tag = $v['tag'];
|
$tag = $v['tag'];
|
||||||
dbg_error_log( "LOCK", " Handling Tag '%s' => '%s' ", $k, $v );
|
dbg_error_log( "LOCK", " Handling Tag '%s' => '%s' ", $k, $v );
|
||||||
switch ( $tag ) {
|
switch ( $tag ) {
|
||||||
case 'DAV::LOCKINFO':
|
case 'DAV::lockinfo':
|
||||||
dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
|
dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
|
||||||
if ( $v['type'] == "open" ) {
|
if ( $v['type'] == "open" ) {
|
||||||
$lockscope = "";
|
$lockscope = "";
|
||||||
@ -34,11 +34,11 @@ foreach( $request->xml_tags AS $k => $v ) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::OWNER':
|
case 'DAV::owner':
|
||||||
case 'DAV::LOCKTYPE':
|
case 'DAV::locktype':
|
||||||
case 'DAV::LOCKSCOPE':
|
case 'DAV::lockscope':
|
||||||
dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
|
dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
|
||||||
if ( $inside['DAV::LOCKINFO'] ) {
|
if ( $inside['DAV::lockinfo'] ) {
|
||||||
if ( $v['type'] == "open" ) {
|
if ( $v['type'] == "open" ) {
|
||||||
$inside[$tag] = true;
|
$inside[$tag] = true;
|
||||||
}
|
}
|
||||||
@ -49,25 +49,25 @@ foreach( $request->xml_tags AS $k => $v ) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/*case 'DAV::SHARED': */ /** Shared lock is not supported yet */
|
/*case 'DAV::SHARED': */ /** Shared lock is not supported yet */
|
||||||
case 'DAV::EXCLUSIVE':
|
case 'DAV::exclusive':
|
||||||
dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
|
dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
|
||||||
if ( $inside['DAV::LOCKSCOPE'] && $v['type'] == "complete" ) {
|
if ( $inside['DAV::lockscope'] && $v['type'] == "complete" ) {
|
||||||
$lockscope = strtolower(substr($tag,5));
|
$lockscope = strtolower(substr($tag,5));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* case 'DAV::READ': */ /** RFC2518 is pretty vague about read locks */
|
/* case 'DAV::READ': */ /** RFC2518 is pretty vague about read locks */
|
||||||
case 'DAV::WRITE':
|
case 'DAV::write':
|
||||||
dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
|
dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
|
||||||
if ( $inside['DAV::LOCKTYPE'] && $v['type'] == "complete" ) {
|
if ( $inside['DAV::locktype'] && $v['type'] == "complete" ) {
|
||||||
$locktype = strtolower(substr($tag,5));
|
$locktype = strtolower(substr($tag,5));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::HREF':
|
case 'DAV::href':
|
||||||
dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
|
dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag );
|
||||||
dbg_log_array( "LOCK", "DAV:HREF", $v, true );
|
dbg_log_array( "LOCK", "DAV:href", $v, true );
|
||||||
if ( $inside['DAV::OWNER'] && $v['type'] == "complete" ) {
|
if ( $inside['DAV::owner'] && $v['type'] == "complete" ) {
|
||||||
$lockowner = $v['value'];
|
$lockowner = $v['value'];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -136,4 +136,3 @@ $prop = new XMLElement( "prop", $response, array('xmlns'=>'DAV:') );
|
|||||||
$xmldoc = $prop->Render(0,'<?xml version="1.0" encoding="utf-8" ?>');
|
$xmldoc = $prop->Render(0,'<?xml version="1.0" encoding="utf-8" ?>');
|
||||||
$request->DoResponse( 200, $xmldoc, 'text/xml; charset="utf-8"' );
|
$request->DoResponse( 200, $xmldoc, 'text/xml; charset="utf-8"' );
|
||||||
|
|
||||||
?>
|
|
||||||
@ -4,8 +4,8 @@
|
|||||||
*
|
*
|
||||||
* @package davical
|
* @package davical
|
||||||
* @subpackage caldav
|
* @subpackage caldav
|
||||||
* @author Andrew McMillan <andrew@catalyst.net.nz>
|
* @author Andrew McMillan <andrew@mcmillan.net.nz>
|
||||||
* @copyright Catalyst .Net Ltd
|
* @copyright Morphoss Ltd - http://www.morphoss.com/
|
||||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||||
*/
|
*/
|
||||||
dbg_error_log("MKCALENDAR", "method handler");
|
dbg_error_log("MKCALENDAR", "method handler");
|
||||||
@ -35,10 +35,10 @@ if ( isset($request->xml_tags) ) {
|
|||||||
$position = 0;
|
$position = 0;
|
||||||
$xmltree = BuildXMLTree( $request->xml_tags, $position);
|
$xmltree = BuildXMLTree( $request->xml_tags, $position);
|
||||||
// echo $xmltree->Render();
|
// echo $xmltree->Render();
|
||||||
if ( $xmltree->GetTag() != "URN:IETF:PARAMS:XML:NS:CALDAV:MKCALENDAR" ) {
|
if ( $xmltree->GetTag() != "urn:ietf:params:xml:ns:caldav:mkcalendar" ) {
|
||||||
$request->DoResponse( 403, "XML is not a URN:IETF:PARAMS:XML:NS:CALDAV:MKCALENDAR document" );
|
$request->DoResponse( 403, "The supplied XML is not a 'urn:ietf:params:xml:ns:caldav:mkcalendar' document" );
|
||||||
}
|
}
|
||||||
$setprops = $xmltree->GetPath("/URN:IETF:PARAMS:XML:NS:CALDAV:MKCALENDAR/DAV::SET/DAV::PROP/*");
|
$setprops = $xmltree->GetPath("/urn:ietf:params:xml:ns:caldav:mkcalendar/DAV::set/DAV::prop/*");
|
||||||
|
|
||||||
$propertysql = "";
|
$propertysql = "";
|
||||||
foreach( $setprops AS $k => $setting ) {
|
foreach( $setprops AS $k => $setting ) {
|
||||||
@ -47,7 +47,7 @@ if ( isset($request->xml_tags) ) {
|
|||||||
|
|
||||||
switch( $tag ) {
|
switch( $tag ) {
|
||||||
|
|
||||||
case 'DAV::DISPLAYNAME':
|
case 'DAV::displayname':
|
||||||
$displayname = $content;
|
$displayname = $content;
|
||||||
/**
|
/**
|
||||||
* TODO: This is definitely a bug in SOHO Organizer and we probably should respond
|
* TODO: This is definitely a bug in SOHO Organizer and we probably should respond
|
||||||
@ -61,27 +61,27 @@ if ( isset($request->xml_tags) ) {
|
|||||||
$success[$tag] = 1;
|
$success[$tag] = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-COMPONENT-SET': /** Ignored, since we will support all component types */
|
case 'urn:ietf:params:xml:ns:caldav:supported-calendar-component-set': /** Ignored, since we will support all component types */
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-DATA': /** Ignored, since we will support iCalendar 2.0 */
|
case 'urn:ietf:params:xml:ns:caldav:supported-calendar-data': /** Ignored, since we will support iCalendar 2.0 */
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DATA': /** Ignored, since we will support iCalendar 2.0 */
|
case 'urn:ietf:params:xml:ns:caldav:calendar-data': /** Ignored, since we will support iCalendar 2.0 */
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-RESOURCE-SIZE': /** Ignored, since we will support arbitrary size */
|
case 'urn:ietf:params:xml:ns:caldav:max-resource-size': /** Ignored, since we will support arbitrary size */
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MIN-DATE-TIME': /** Ignored, since we will support arbitrary time */
|
case 'urn:ietf:params:xml:ns:caldav:min-date-time': /** Ignored, since we will support arbitrary time */
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-DATE-TIME': /** Ignored, since we will support arbitrary time */
|
case 'urn:ietf:params:xml:ns:caldav:max-date-time': /** Ignored, since we will support arbitrary time */
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-INSTANCES': /** Ignored, since we will support arbitrary instances */
|
case 'urn:ietf:params:xml:ns:caldav:max-instances': /** Ignored, since we will support arbitrary instances */
|
||||||
case 'DAV::RESOURCETYPE': /** Any value for resourcetype is ignored */
|
case 'DAV::resourcetype': /** Any value for resourcetype is ignored */
|
||||||
$success[$tag] = 1;
|
$success[$tag] = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The following properties are read-only, so they will cause the request to fail
|
* The following properties are read-only, so they will cause the request to fail
|
||||||
*/
|
*/
|
||||||
case 'DAV::GETETAG':
|
case 'DAV::getetag':
|
||||||
case 'DAV::GETCONTENTLENGTH':
|
case 'DAV::getcontentlength':
|
||||||
case 'DAV::GETCONTENTTYPE':
|
case 'DAV::getcontenttype':
|
||||||
case 'DAV::GETLASTMODIFIED':
|
case 'DAV::getlastmodified':
|
||||||
case 'DAV::CREATIONDATE':
|
case 'DAV::creationdate':
|
||||||
case 'DAV::LOCKDISCOVERY':
|
case 'DAV::lockdiscovery':
|
||||||
case 'DAV::SUPPORTEDLOCK':
|
case 'DAV::supportedlock':
|
||||||
$failure['set-'.$tag] = new XMLElement( 'propstat', array(
|
$failure['set-'.$tag] = new XMLElement( 'propstat', array(
|
||||||
new XMLElement( 'prop', new XMLElement($tag)),
|
new XMLElement( 'prop', new XMLElement($tag)),
|
||||||
new XMLElement( 'status', 'HTTP/1.1 409 Conflict' ),
|
new XMLElement( 'status', 'HTTP/1.1 409 Conflict' ),
|
||||||
@ -182,4 +182,3 @@ else {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
?>
|
|
||||||
|
|||||||
37
inc/caldav-POST.php
Normal file
37
inc/caldav-POST.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* CalDAV Server - handle PUT method
|
||||||
|
*
|
||||||
|
* @package davical
|
||||||
|
* @subpackage caldav
|
||||||
|
* @author Andrew McMillan <andrew@morphoss.com>
|
||||||
|
* @copyright Morphoss Ltd - http://www.morphoss.com/
|
||||||
|
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||||
|
*/
|
||||||
|
dbg_error_log("POST", "method handler");
|
||||||
|
|
||||||
|
require_once("iCalendar.php");
|
||||||
|
|
||||||
|
if ( ! $request->AllowedTo("CALDAV:schedule-send-freebusy")
|
||||||
|
&& ! $request->AllowedTo("CALDAV:schedule-send-invite")
|
||||||
|
&& ! $request->AllowedTo("CALDAV:schedule-send-reply") ) {
|
||||||
|
$request->DoResponse(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || $c->dbg['post']) ) {
|
||||||
|
$fh = fopen('/tmp/POST.txt','w');
|
||||||
|
if ( $fh ) {
|
||||||
|
fwrite($fh,$request->raw_post);
|
||||||
|
fclose($fh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$ical = new iCalendar( array('icalendar' => $request->raw_post) );
|
||||||
|
switch ( $ical->properties['METHOD'] ) {
|
||||||
|
case 'REQUEST':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dbg_error_log("POST", ": Unhandled '%s' method in request.", $ical->properties['METHOD'] );
|
||||||
|
}
|
||||||
@ -14,141 +14,28 @@ if ( ! ($request->AllowedTo('read') || $request->AllowedTo('freebusy')) ) {
|
|||||||
$request->DoResponse( 403, translate("You may not access that calendar") );
|
$request->DoResponse( 403, translate("You may not access that calendar") );
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once("XMLElement.php");
|
|
||||||
require_once("iCalendar.php");
|
require_once("iCalendar.php");
|
||||||
|
require_once("XMLDocument.php");
|
||||||
|
|
||||||
$href_list = array();
|
$href_list = array();
|
||||||
$attribute_list = array();
|
$prop_list = array();
|
||||||
$unsupported = array();
|
$unsupported = array();
|
||||||
$arbitrary = array();
|
$arbitrary = array();
|
||||||
|
|
||||||
$namespaces = array( "DAV:" => "" );
|
$reply = new XMLDocument( array( "DAV:" => "" ) );
|
||||||
$prefixes = array();
|
|
||||||
function add_namespace( $prefix, $namespace ) {
|
|
||||||
global $namespaces;
|
|
||||||
global $prefixes;
|
|
||||||
|
|
||||||
if ( !isset($namespaces[$namespace]) ) {
|
|
||||||
if ( $prefix == "" || isset($prefixes[$prefix]) ) {
|
|
||||||
dbg_error_log("ERROR", "Cannot assign the same prefix to two different namespaces");
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$prefixes[$prefix] = $prefix;
|
|
||||||
$namespaces[$namespace] = $prefix;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( $namespaces[$namespace] != $prefix ) {
|
|
||||||
dbg_error_log("ERROR", "Cannot use the same namespace with two different prefixes");
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function ns_tag( $in_tag, $namespace=null, $prefix=null ) {
|
|
||||||
global $namespaces, $prefixes;
|
|
||||||
|
|
||||||
if ( $namespace == null ) {
|
|
||||||
// Attempt to split out from namespace:tag
|
|
||||||
if ( preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) {
|
|
||||||
$namespace = $matches[1];
|
|
||||||
$tag = $matches[2];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// There is nothing we can do here
|
|
||||||
return $in_tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$tag = $in_tag;
|
|
||||||
}
|
|
||||||
$namespace = strtolower($namespace);
|
|
||||||
if ( $namespace == 'dav:' ) $namespace = 'DAV:'; // Special case for conventional naming
|
|
||||||
$tag = strtolower($tag);
|
|
||||||
|
|
||||||
if ( $prefix == null ) {
|
|
||||||
// Attempt to assign one
|
|
||||||
if ( isset($namespaces[$namespace]) ) {
|
|
||||||
$prefix = $namespaces[$namespace];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Try and build a prefix based on the first alphabetic character of the last element of the namespace
|
|
||||||
if ( preg_match('/^(.*):([^:]+)$/', $namespace, $matches) ) {
|
|
||||||
$alpha = preg_replace( '/[^a-z]/i', '', $matches[2] );
|
|
||||||
$prefix = strtoupper(substr($alpha,0,1));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$prefix = 'x';
|
|
||||||
}
|
|
||||||
$i = "";
|
|
||||||
if ( isset($prefixes[$prefix]) ) {
|
|
||||||
for ( $i=1; $i<10 && isset($prefixes["$prefix$i"]); $i++ ) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( isset($prefixes["$prefix$i"]) ) {
|
|
||||||
dbg_error_log("ERROR", "Cannot find a free prefix for this namespace");
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
$prefix = "$prefix$i";
|
|
||||||
$namespaces[$namespace] = $prefix;
|
|
||||||
$prefixes[$prefix] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !isset($namespaces[$namespace]) ) {
|
|
||||||
add_namespace( $prefix, $namespace );
|
|
||||||
}
|
|
||||||
|
|
||||||
return $prefix . ($prefix == "" ? "" : ":") . $tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function namespace_array() {
|
|
||||||
global $namespaces;
|
|
||||||
|
|
||||||
$ns = array();
|
|
||||||
foreach( $namespaces AS $n => $p ) {
|
|
||||||
if ( $p == "" ) $ns["xmlns"] = $n; else $ns["xmlns:$p"] = $n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function calendar_server_tag( $tag ) {
|
|
||||||
add_namespace("A", "http://calendarserver.org/ns/");
|
|
||||||
return ns_tag( $tag, 'http://calendarserver.org/ns/' );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function caldav_tag( $tag ) {
|
|
||||||
return ns_tag( $tag, 'urn:ietf:params:xml:ns:caldav' );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach( $request->xml_tags AS $k => $v ) {
|
foreach( $request->xml_tags AS $k => $v ) {
|
||||||
|
|
||||||
$ns_tag = $v['tag'];
|
$ns_tag = $v['tag'];
|
||||||
if ( preg_match('/^(.*):([^:]+)$/', $ns_tag, $matches) ) {
|
dbg_error_log( "PROPFIND", " Handling Tag '%s' => '%s' ", $k, $ns_tag );
|
||||||
$namespace = $matches[1];
|
|
||||||
$tag = $matches[2];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$namespace = "";
|
|
||||||
$tag = $ns_tag;
|
|
||||||
}
|
|
||||||
dbg_error_log( "PROPFIND", " Handling Tag '%s' => '%s' ", $k, $v );
|
|
||||||
|
|
||||||
switch ( $tag ) {
|
switch ( $ns_tag ) {
|
||||||
case 'PROPFIND':
|
case 'DAV::propfind':
|
||||||
case 'PROP':
|
case 'DAV::prop':
|
||||||
dbg_error_log( "PROPFIND", ":Request: %s -> %s", $v['type'], $tag );
|
dbg_error_log( "PROPFIND", ":Request: %s -> %s", $v['type'], $ns_tag );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'HREF':
|
case 'DAV::href':
|
||||||
// dbg_log_array( "PROPFIND", "HREF", $v, true );
|
|
||||||
$href_list[] = $v['value'];
|
$href_list[] = $v['value'];
|
||||||
dbg_error_log( "PROPFIND", "Adding href '%s'", $v['value'] );
|
dbg_error_log( "PROPFIND", "Adding href '%s'", $v['value'] );
|
||||||
break;
|
break;
|
||||||
@ -157,83 +44,87 @@ foreach( $request->xml_tags AS $k => $v ) {
|
|||||||
/**
|
/**
|
||||||
* Handled DAV properties
|
* Handled DAV properties
|
||||||
*/
|
*/
|
||||||
case 'ACL': /** acl - only vaguely supported */
|
case 'DAV::acl': /** Only vaguely supported as yet. Will need work.*/
|
||||||
case 'CREATIONDATE': /** creationdate - should work fine */
|
case 'DAV::creationdate': /** should work fine */
|
||||||
case 'GETLASTMODIFIED': /** getlastmodified - should work fine */
|
case 'DAV::getlastmodified': /** should work fine */
|
||||||
case 'DISPLAYNAME': /** displayname - should work fine */
|
case 'DAV::displayname': /** should work fine */
|
||||||
case 'GETCONTENTLENGTH': /** getcontentlength- should work fine */
|
case 'DAV::getcontentlength': /** should work fine */
|
||||||
case 'GETCONTENTTYPE': /** getcontenttype - should work fine */
|
case 'DAV::getcontenttype': /** should work fine */
|
||||||
case 'GETETAG': /** getetag - should work fine */
|
case 'DAV::getetag': /** should work fine */
|
||||||
case 'GETCTAG': /** Calendar Server extension like etag - should work fine (we just return etag) */
|
case 'DAV::supportedlock': /** should work fine */
|
||||||
case 'SUPPORTEDLOCK': /** supportedlock - should work fine */
|
case 'DAV::principal-URL': /** should work fine */
|
||||||
case 'PRINCIPAL-URL': /** principal-url - should work fine */
|
case 'DAV::owner': /** should work fine */
|
||||||
case 'RESOURCETYPE': /** resourcetype - should work fine */
|
case 'DAV::resourcetype': /** should work fine */
|
||||||
case 'GETCONTENTLANGUAGE': /** resourcetype - should return the user's chosen locale, or default locale */
|
case 'DAV::getcontentlanguage': /** should return the user's chosen locale, or default locale */
|
||||||
case 'SUPPORTED-PRIVILEGE-SET': /** supported-privilege-set - should work fine */
|
case 'DAV::current-user-privilege-set': /** only vaguely supported */
|
||||||
case 'CURRENT-USER-PRIVILEGE-SET': /** current-user-privilege-set - only vaguely supported */
|
case 'DAV::allprop': /** limited support, needs to be checked for correctness at some point */
|
||||||
case 'ALLPROP': /** allprop - limited support */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handled CalDAV properties
|
* Handled CalDAV properties
|
||||||
*/
|
*/
|
||||||
case 'CALENDAR-HOME-SET': /** calendar-home-set is used by iCal in Leopard - should work fine */
|
case 'urn:ietf:params:xml:ns:caldav:calendar-home-set': /** Should work fine */
|
||||||
$attribute_list[$tag] = 1;
|
case 'urn:ietf:params:xml:ns:caldav:calendar-user-address-set': /** Should work fine */
|
||||||
dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag );
|
case 'urn:ietf:params:xml:ns:caldav:schedule-inbox-URL': /** Support in development */
|
||||||
break;
|
case 'urn:ietf:params:xml:ns:caldav:schedule-outbox-URL': /** Support in development */
|
||||||
|
|
||||||
|
|
||||||
case 'SUPPORTED-COLLATION-SET': /** fixed server definition - should work fine */
|
|
||||||
case 'SUPPORTED-CALENDAR-COMPONENT-SET': /** fixed server definition - should work fine */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handled calendar-schedule properties
|
* Handled calendarserver properties
|
||||||
*/
|
*/
|
||||||
case 'CALENDAR-USER-ADDRESS-SET': /** CalDAV+s: slightly supported */
|
case 'http://calendarserver.org/ns/:getctag': /** Calendar Server extension like etag - should work fine (we just return etag) */
|
||||||
// case 'SCHEDULE-INBOX-URL': /** CalDAV+s: not supported */
|
|
||||||
// case 'SCHEDULE-OUTBOX-URL': /** CalDAV+s: not supported */
|
$prop_list[$ns_tag] = $ns_tag;
|
||||||
// case 'DROPBOX-HOME-URL': // HTTP://CALENDARSERVER.ORG/NS/
|
dbg_error_log( "PROPFIND", "Adding attribute '%s'", $ns_tag );
|
||||||
// case 'NOTIFICATIONS-URL': // HTTP://CALENDARSERVER.ORG/NS/
|
break;
|
||||||
|
|
||||||
|
/** fixed server definitions - should work fine */
|
||||||
|
case 'DAV::supported-collation-set':
|
||||||
|
case 'DAV::supported-calendar-component-set':
|
||||||
|
case 'DAV::principal-collection-set':
|
||||||
|
case 'DAV::supported-privilege-set':
|
||||||
|
|
||||||
|
// case 'dropbox-home-URL': // HTTP://CALENDARSERVER.ORG/NS/
|
||||||
|
// case 'notifications-URL': // HTTP://CALENDARSERVER.ORG/NS/
|
||||||
if ( $_SERVER['PATH_INFO'] == '/' || $_SERVER['PATH_INFO'] == '' ) {
|
if ( $_SERVER['PATH_INFO'] == '/' || $_SERVER['PATH_INFO'] == '' ) {
|
||||||
$arbitrary[$ns_tag] = $ns_tag;
|
$arbitrary[$ns_tag] = $ns_tag;
|
||||||
dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $ns_tag );
|
dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $ns_tag );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$attribute_list[$tag] = 1;
|
$prop_list[$ns_tag] = $ns_tag;
|
||||||
dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag );
|
dbg_error_log( "PROPFIND", "Adding attribute '%s'", $ns_tag );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 'CALENDAR-TIMEZONE': // CalDAV
|
case 'urn:ietf:params:xml:ns:caldav:calendar-timezone': // Ignored
|
||||||
case 'SUPPORTED-CALENDAR-DATA': // CalDAV
|
case 'urn:ietf:params:xml:ns:caldav:supported-calendar-data': // Ignored
|
||||||
case 'MAX-RESOURCE-SIZE': // CalDAV
|
case 'urn:ietf:params:xml:ns:caldav:max-resource-size': // Ignored - should be a server setting
|
||||||
case 'MIN-DATE-TIME': // CalDAV
|
case 'urn:ietf:params:xml:ns:caldav:min-date-time': // Ignored - should be a server setting
|
||||||
case 'MAX-DATE-TIME': // CalDAV
|
case 'urn:ietf:params:xml:ns:caldav:max-date-time': // Ignored - should be a server setting
|
||||||
case 'MAX-INSTANCES': // CalDAV
|
case 'urn:ietf:params:xml:ns:caldav:max-instances': // Ignored - should be a server setting
|
||||||
case 'MAX-ATTENDEES-PER-INSTANCE': // CalDAV
|
case 'urn:ietf:params:xml:ns:caldav:max-attendees-per-instance': // Ignored - should be a server setting
|
||||||
// case 'CHECKED-OUT': // DAV:
|
|
||||||
// case 'CHECKED-IN': // DAV:
|
|
||||||
// case 'SOURCE': // DAV:
|
|
||||||
// case 'LOCKDISCOVERY': // DAV:
|
|
||||||
// case 'EXECUTABLE': // HTTP://APACHE.ORG/DAV/PROPS/
|
|
||||||
/** These are ignored specifically */
|
/** These are ignored specifically */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the ones that are specifically unsupported here.
|
* Add the ones that are specifically unsupported here.
|
||||||
*/
|
*/
|
||||||
|
// case 'DAV::checked-out': // DAV:
|
||||||
|
// case 'DAV::checked-in': // DAV:
|
||||||
|
// case 'DAV::source': // DAV:
|
||||||
|
// case 'DAV::lockdiscovery': // DAV:
|
||||||
|
// case 'http://apache.org/dav/props/:executable': //
|
||||||
case 'This is not a supported property': // an impossible example
|
case 'This is not a supported property': // an impossible example
|
||||||
$unsupported[$tag] = "";
|
$unsupported[$ns_tag] = "";
|
||||||
dbg_error_log( "PROPFIND", "Unsupported tag >>%s<< in xmlns >>%s<<", $tag, $namespace);
|
dbg_error_log( "PROPFIND", "Unsupported tag >>%s<< ", $ns_tag);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arbitrary DAV properties may also be reported
|
* Arbitrary DAV properties may also be reported
|
||||||
*/
|
*/
|
||||||
case 'CALENDAR-DESCRIPTION': // CalDAV, informational
|
case 'urn:ietf:params:xml:ns:caldav:calendar-description': // Supported purely as an arbitrary property
|
||||||
default:
|
default:
|
||||||
$arbitrary[$ns_tag] = $ns_tag;
|
$arbitrary[$ns_tag] = $ns_tag;
|
||||||
dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $ns_tag );
|
dbg_error_log( "PROPFIND", "Adding arbitrary property '%s'", $ns_tag );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,146 +172,76 @@ function get_arbitrary_properties($dav_name) {
|
|||||||
* Handles any properties related to the DAV::PRINCIPAL in the request
|
* Handles any properties related to the DAV::PRINCIPAL in the request
|
||||||
*/
|
*/
|
||||||
function add_principal_properties( &$prop, &$not_found, &$denied ) {
|
function add_principal_properties( &$prop, &$not_found, &$denied ) {
|
||||||
global $attribute_list, $session, $c, $request;
|
global $prop_list, $session, $c, $request, $reply;
|
||||||
|
|
||||||
if ( isset($attribute_list['PRINCIPAL-URL'] ) ) {
|
$allprop = isset($prop_list['DAV::allprop']);
|
||||||
$prop->NewElement("principal-url", new XMLElement('href', $request->principal->url ) );
|
|
||||||
|
if ( isset($prop_list['DAV::principal-URL'] ) ) {
|
||||||
|
$prop->NewElement("principal-URL", new XMLElement('href', $request->principal->url ) );
|
||||||
|
}
|
||||||
|
if ( isset($prop_list['DAV::alternate-URI-set'] ) ) {
|
||||||
|
$prop->NewElement("alternate-URI-set" ); // Empty - there are no alternatives!
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($attribute_list['CALENDAR-HOME-SET'] ) ) {
|
if ( isset($prop_list['urn:ietf:params:xml:ns:caldav:calendar-home-set'] ) ) {
|
||||||
$prop->NewElement(caldav_tag("calendar-home-set"), new XMLElement('href', $request->principal->calendar_home_set ) );
|
$home_set = array();
|
||||||
|
$chs = $request->principal->calendar_home_set;
|
||||||
|
foreach( $chs AS $k => $url ) {
|
||||||
|
$home_set[] = new XMLElement('href', $url );
|
||||||
|
}
|
||||||
|
$prop->NewElement($reply->Caldav("calendar-home-set"), $home_set );
|
||||||
}
|
}
|
||||||
if ( isset($attribute_list['SCHEDULE-INBOX-URL'] ) ) {
|
if ( isset($prop_list['urn:ietf:params:xml:ns:caldav:schedule-inbox-URL'] ) ) {
|
||||||
$prop->NewElement(caldav_tag("schedule-inbox-url"), new XMLElement('href', $request->principal->schedule_inbox_url) );
|
$prop->NewElement($reply->Caldav("schedule-inbox-URL"), new XMLElement('href', $request->principal->schedule_inbox_url) );
|
||||||
}
|
}
|
||||||
if ( isset($attribute_list['SCHEDULE-OUTBOX-URL'] ) ) {
|
if ( isset($prop_list['urn:ietf:params:xml:ns:caldav:schedule-outbox-URL'] ) ) {
|
||||||
$prop->NewElement(caldav_tag("schedule-outbox-url"), new XMLElement('href', $request->principal->schedule_outbox_url) );
|
$prop->NewElement($reply->Caldav("schedule-outbox-URL"), new XMLElement('href', $request->principal->schedule_outbox_url) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($attribute_list['DROPBOX-HOME-URL'] ) ) {
|
if ( isset($prop_list['http://calendarserver.org/ns/:dropbox-home-URL'] ) ) {
|
||||||
$prop->NewElement(calendar_server_tag("dropbox-home-url"), new XMLElement('href', $request->principal->dropbox_url) );
|
$prop->NewElement($reply->Calendarserver("dropbox-home-URL"), new XMLElement('href', $request->principal->dropbox_url) );
|
||||||
}
|
}
|
||||||
if ( isset($attribute_list['NOTIFICATIONS-URL'] ) ) {
|
if ( isset($prop_list['http://calendarserver.org/ns/:notifications-URL'] ) ) {
|
||||||
$prop->NewElement(calendar_server_tag("notifications-url"), new XMLElement('href', $request->principal->notifications_url) );
|
$prop->NewElement($reply->Calendarserver("notifications-URL"), new XMLElement('href', $request->principal->notifications_url) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($attribute_list['CALENDAR-USER-ADDRESS-SET'] ) ) {
|
if ( isset($prop_list['urn:ietf:params:xml:ns:caldav:calendar-user-address-set'] ) ) {
|
||||||
$addr_set = array();
|
$addr_set = array();
|
||||||
foreach( $request->principal->user_address_set AS $k => $v ) {
|
$uas = $request->principal->user_address_set;
|
||||||
|
foreach( $uas AS $k => $v ) {
|
||||||
$addr_set[] = new XMLElement('href', $v );
|
$addr_set[] = new XMLElement('href', $v );
|
||||||
}
|
}
|
||||||
$prop->NewElement(caldav_tag("calendar-user-address-set"), $addr_set );
|
$prop->NewElement($reply->Caldav("calendar-user-address-set"), $addr_set );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an XML sub-tree for a single collection record from the DB
|
* Handles any properties related to the DAV::PRINCIPAL in the request
|
||||||
*/
|
*/
|
||||||
function collection_to_xml( $collection ) {
|
function add_general_properties( &$prop, &$not_found, &$denied, $record ) {
|
||||||
global $arbitrary, $attribute_list, $session, $c, $request;
|
global $prop_list, $session, $c, $request, $reply;
|
||||||
|
|
||||||
dbg_error_log("PROPFIND","Building XML Response for collection '%s'", $collection->dav_name );
|
$allprop = isset($prop_list['DAV::allprop']);
|
||||||
|
|
||||||
$arbitrary_results = get_arbitrary_properties($collection->dav_name);
|
if ( $allprop || isset($prop_list['DAV::getlastmodified']) ) {
|
||||||
$collection->properties = $arbitrary_results->found;
|
$prop->NewElement("getlastmodified", ( isset($record->modified)? $record->modified : false ));
|
||||||
|
|
||||||
$url = ConstructURL($collection->dav_name);
|
|
||||||
|
|
||||||
$resourcetypes = array( new XMLElement("collection") );
|
|
||||||
$contentlength = false;
|
|
||||||
if ( $collection->is_calendar == 't' ) {
|
|
||||||
$resourcetypes[] = new XMLElement(caldav_tag("calendar"), false);
|
|
||||||
$lqry = new PgQuery("SELECT sum(length(caldav_data)) FROM caldav_data WHERE user_no = ? AND dav_name ~ ?;", $collection->user_no, $collection->dav_name.'[^/]+$' );
|
|
||||||
if ( $lqry->Exec("PROPFIND",__LINE__,__FILE__) && $row = $lqry->Fetch() ) {
|
|
||||||
$contentlength = $row->sum;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ( $collection->is_principal == 't' ) {
|
if ( $allprop || isset($prop_list['DAV::creationdate']) ) {
|
||||||
$resourcetypes[] = new XMLElement("principal");
|
$prop->NewElement("creationdate", $record->created );
|
||||||
}
|
}
|
||||||
$prop = new XMLElement("prop");
|
if ( $allprop || isset($prop_list['DAV::getetag']) ) {
|
||||||
$not_found = new XMLElement("prop");
|
$prop->NewElement("getetag", '"'.$record->dav_etag.'"' );
|
||||||
$denied = new XMLElement("prop");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* First process any static values we do support
|
|
||||||
*/
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-COLLATION-SET']) ) {
|
|
||||||
$collations = array();
|
|
||||||
$collations[] = new XMLElement(caldav_tag("supported-collation"), 'i;ascii-casemap');
|
|
||||||
$collations[] = new XMLElement(caldav_tag("supported-collation"), 'i;octet');
|
|
||||||
$prop->NewElement(caldav_tag("supported-collation-set"), $collations );
|
|
||||||
}
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-CALENDAR-COMPONENT-SET']) ) {
|
|
||||||
$components = array();
|
|
||||||
$components[] = new XMLElement(caldav_tag("comp"), '', array("name" => "VEVENT"));
|
|
||||||
$components[] = new XMLElement(caldav_tag("comp"), '', array("name" => "VTODO"));
|
|
||||||
$prop->NewElement(caldav_tag("supported-calendar-component-set"), $components );
|
|
||||||
}
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETCONTENTTYPE']) ) {
|
|
||||||
$prop->NewElement("getcontenttype", "httpd/unix-directory" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
if ( isset($prop_list['DAV::owner']) ) {
|
||||||
* Second process any dynamic values we do support
|
$prop->NewElement("owner", new XMLElement('href', 'mailto:'.$request->principal->email ) );
|
||||||
*/
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETLASTMODIFIED']) ) {
|
|
||||||
$prop->NewElement("getlastmodified", ( isset($collection->modified)? $collection->modified : false ));
|
|
||||||
}
|
}
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETCONTENTLENGTH']) ) {
|
if ( isset($prop_list['DAV::principal-collection-set']) ) {
|
||||||
$prop->NewElement("getcontentlength", $contentlength );
|
$prop->NewElement("principal-collection-set", new XMLElement('href', ConstructURL('/') ) );
|
||||||
}
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['CREATIONDATE']) ) {
|
|
||||||
$prop->NewElement("creationdate", $collection->created );
|
|
||||||
}
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['RESOURCETYPE']) ) {
|
|
||||||
$prop->NewElement("resourcetype", $resourcetypes );
|
|
||||||
}
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['DISPLAYNAME']) ) {
|
|
||||||
$displayname = ( $collection->dav_displayname == "" ? ucfirst(trim(str_replace("/"," ", $collection->dav_name))) : $collection->dav_displayname );
|
|
||||||
$prop->NewElement("displayname", $displayname );
|
|
||||||
}
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETETAG']) ) {
|
|
||||||
$prop->NewElement("getetag", '"'.$collection->dav_etag.'"' );
|
|
||||||
}
|
|
||||||
if ( isset($attribute_list['GETCTAG']) ) {
|
|
||||||
// Calendar Server extension which only applies to collections. We return the etag, which does the needful.
|
|
||||||
$prop->NewElement(calendar_server_tag('getctag'),$collection->dav_etag );
|
|
||||||
}
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['CURRENT-USER-PRIVILEGE-SET']) ) {
|
|
||||||
$prop->NewElement("current-user-privilege-set", privileges($request->permissions) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($attribute_list['CALENDAR-FREE-BUSY-SET'] ) ) {
|
if ( isset($prop_list['DAV::acl']) ) {
|
||||||
if ( isset($collection->is_inbox) && $collection->is_inbox && $session->user_no == $collection->user_no ) {
|
|
||||||
$fb_set = array();
|
|
||||||
foreach( $collection->free_busy_set AS $k => $v ) {
|
|
||||||
$fb_set[] = new XMLElement('href', $v );
|
|
||||||
}
|
|
||||||
$prop->NewElement(caldav_tag("calendar-free-busy-set"), $fb_set );
|
|
||||||
}
|
|
||||||
else if ( $session->user_no == $collection->user_no ) {
|
|
||||||
$not_found->NewElement(caldav_tag("calendar-free-busy-set") );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$denied->NewElement(caldav_tag("calendar-free-busy-set") );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Then look at any properties related to the principal
|
|
||||||
*/
|
|
||||||
add_principal_properties( $prop, $not_found, $denied );
|
|
||||||
|
|
||||||
if ( count($collection->properties) > 0 ) {
|
|
||||||
foreach( $collection->properties AS $k => $v ) {
|
|
||||||
$prop->NewElement(ns_tag($k), $v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isset($attribute_list['ACL']) ) {
|
|
||||||
/**
|
/**
|
||||||
* FIXME: This information is semantically valid but presents an incorrect picture.
|
* FIXME: This information is semantically valid but presents an incorrect picture.
|
||||||
*/
|
*/
|
||||||
@ -430,12 +251,12 @@ function collection_to_xml( $collection ) {
|
|||||||
$prop->NewElement("acl", new XMLElement( "ace", array( $principal, $grant ) ) );
|
$prop->NewElement("acl", new XMLElement( "ace", array( $principal, $grant ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETCONTENTLANGUAGE']) ) {
|
if ( $allprop || isset($prop_list['DAV::getcontentlanguage']) ) {
|
||||||
$contentlength = strlen($item->caldav_data);
|
$contentlength = strlen($item->caldav_data);
|
||||||
$prop->NewElement("getcontentlanguage", $c->current_locale );
|
$prop->NewElement("getcontentlanguage", $c->current_locale );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($attribute_list['SUPPORTEDLOCK']) ) {
|
if ( isset($prop_list['DAV::supportedlock']) ) {
|
||||||
$prop->NewElement("supportedlock",
|
$prop->NewElement("supportedlock",
|
||||||
new XMLElement( "lockentry",
|
new XMLElement( "lockentry",
|
||||||
array(
|
array(
|
||||||
@ -446,21 +267,28 @@ function collection_to_xml( $collection ) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-PRIVILEGE-SET']) ) {
|
if ( isset($prop_list['DAV::current-user-privilege-set']) ) {
|
||||||
|
$prop->NewElement("current-user-privilege-set", privileges($request->permissions) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset($prop_list['DAV::supported-privilege-set']) ) {
|
||||||
$prop->NewElement("supported-privilege-set", privileges( $request->SupportedPrivileges(), "supported-privilege") );
|
$prop->NewElement("supported-privilege-set", privileges( $request->SupportedPrivileges(), "supported-privilege") );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the <propstat><prop></prop><status></status></propstat> part of the response
|
||||||
|
*/
|
||||||
|
function build_propstat_response( $prop, $not_found, $denied, $url ) {
|
||||||
|
|
||||||
$status = new XMLElement("status", "HTTP/1.1 200 OK" );
|
$status = new XMLElement("status", "HTTP/1.1 200 OK" );
|
||||||
|
|
||||||
$propstat = new XMLElement( "propstat", array( $prop, $status) );
|
$propstat = new XMLElement( "propstat", array( $prop, $status) );
|
||||||
$href = new XMLElement("href", $url );
|
$href = new XMLElement("href", $url );
|
||||||
$response = array($href,$propstat);
|
$response = array($href,$propstat);
|
||||||
|
|
||||||
if ( count($arbitrary_results->missing) > 0 ) {
|
|
||||||
foreach( $arbitrary_results->missing AS $k => $v ) {
|
|
||||||
$not_found->NewElement(ns_tag($k), '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( is_array($not_found->content) && count($not_found->content) > 0 ) {
|
if ( is_array($not_found->content) && count($not_found->content) > 0 ) {
|
||||||
$response[] = new XMLElement( "propstat", array( $not_found, new XMLElement("status", "HTTP/1.1 404 Not Found" )) );
|
$response[] = new XMLElement( "propstat", array( $not_found, new XMLElement("status", "HTTP/1.1 404 Not Found" )) );
|
||||||
}
|
}
|
||||||
@ -475,14 +303,134 @@ function collection_to_xml( $collection ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an XML sub-tree for a single collection record from the DB
|
||||||
|
*/
|
||||||
|
function collection_to_xml( $collection ) {
|
||||||
|
global $arbitrary, $prop_list, $session, $c, $request, $reply;
|
||||||
|
|
||||||
|
dbg_error_log("PROPFIND","Building XML Response for collection '%s'", $collection->dav_name );
|
||||||
|
|
||||||
|
$allprop = isset($prop_list['DAV::allprop']);
|
||||||
|
|
||||||
|
$arbitrary_results = get_arbitrary_properties($collection->dav_name);
|
||||||
|
$collection->properties = $arbitrary_results->found;
|
||||||
|
|
||||||
|
$url = ConstructURL($collection->dav_name);
|
||||||
|
|
||||||
|
$prop = new XMLElement("prop");
|
||||||
|
$not_found = new XMLElement("prop");
|
||||||
|
$denied = new XMLElement("prop");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First process any static values we do support
|
||||||
|
*/
|
||||||
|
if ( isset($prop_list['urn:ietf:params:xml:ns:caldav:supported-collation-set']) ) {
|
||||||
|
$collations = array();
|
||||||
|
$collations[] = new XMLElement($reply->Caldav("supported-collation"), 'i;ascii-casemap');
|
||||||
|
$collations[] = new XMLElement($reply->Caldav("supported-collation"), 'i;octet');
|
||||||
|
$prop->NewElement($reply->Caldav("supported-collation-set"), $collations );
|
||||||
|
}
|
||||||
|
if ( isset($prop_list['urn:ietf:params:xml:ns:caldav:supported-calendar-component-set']) ) {
|
||||||
|
$components = array();
|
||||||
|
$components[] = new XMLElement($reply->Caldav("comp"), '', array("name" => "VEVENT"));
|
||||||
|
$components[] = new XMLElement($reply->Caldav("comp"), '', array("name" => "VTODO"));
|
||||||
|
$prop->NewElement($reply->Caldav("supported-calendar-component-set"), $components );
|
||||||
|
}
|
||||||
|
if ( $allprop || isset($prop_list['DAV::getcontenttype']) ) {
|
||||||
|
$prop->NewElement("getcontenttype", "httpd/unix-directory" ); // Strictly text/icalendar perhaps
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process any dynamic values we do support
|
||||||
|
*/
|
||||||
|
if ( $allprop || isset($prop_list['DAV::getcontentlength'])
|
||||||
|
|| isset($prop_list['DAV::resourcetype']) ) {
|
||||||
|
$resourcetypes = array( new XMLElement("collection") );
|
||||||
|
$contentlength = false;
|
||||||
|
if ( $collection->is_calendar == 't' ) {
|
||||||
|
$resourcetypes[] = new XMLElement($reply->Caldav("calendar"), false);
|
||||||
|
$lqry = new PgQuery("SELECT sum(length(caldav_data)) FROM caldav_data WHERE user_no = ? AND dav_name ~ ?;", $collection->user_no, $collection->dav_name.'[^/]+$' );
|
||||||
|
if ( $lqry->Exec("PROPFIND",__LINE__,__FILE__) && $row = $lqry->Fetch() ) {
|
||||||
|
$contentlength = $row->sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( $collection->is_principal == 't' ) {
|
||||||
|
$resourcetypes[] = new XMLElement("principal");
|
||||||
|
}
|
||||||
|
if ( $allprop || isset($prop_list['DAV::getcontentlength']) ) {
|
||||||
|
$prop->NewElement("getcontentlength", $contentlength ); // Not strictly correct as a GET on this URL would be longer
|
||||||
|
}
|
||||||
|
if ( $allprop || isset($prop_list['DAV::resourcetype']) ) {
|
||||||
|
$prop->NewElement("resourcetype", $resourcetypes );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $allprop || isset($prop_list['DAV::displayname']) ) {
|
||||||
|
$displayname = ( $collection->dav_displayname == "" ? ucfirst(trim(str_replace("/"," ", $collection->dav_name))) : $collection->dav_displayname );
|
||||||
|
$prop->NewElement("displayname", $displayname );
|
||||||
|
}
|
||||||
|
if ( isset($prop_list['http://calendarserver.org/ns/:getctag']) ) {
|
||||||
|
// Calendar Server extension which only applies to collections. We return the etag, which does the needful.
|
||||||
|
$prop->NewElement($reply->Calendarserver('getctag'),$collection->dav_etag );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset($prop_list['urn:ietf:params:xml:ns:caldav:calendar-free-busy-set'] ) ) {
|
||||||
|
if ( isset($collection->is_inbox) && $collection->is_inbox && $session->user_no == $collection->user_no ) {
|
||||||
|
$fb_set = array();
|
||||||
|
foreach( $collection->free_busy_set AS $k => $v ) {
|
||||||
|
$fb_set[] = new XMLElement('href', $v );
|
||||||
|
}
|
||||||
|
$prop->NewElement($reply->Caldav("calendar-free-busy-set"), $fb_set );
|
||||||
|
}
|
||||||
|
else if ( $session->user_no == $collection->user_no ) {
|
||||||
|
$not_found->NewElement($reply->Caldav("calendar-free-busy-set") );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$denied->NewElement($reply->Caldav("calendar-free-busy-set") );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Then look at any properties related to the principal
|
||||||
|
*/
|
||||||
|
add_principal_properties( $prop, $not_found, $denied );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* And any properties that are server/request related, or standard fields
|
||||||
|
* from our query.
|
||||||
|
*/
|
||||||
|
add_general_properties( $prop, $not_found, $denied, $collection );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arbitrary collection properties
|
||||||
|
*/
|
||||||
|
if ( count($collection->properties) > 0 ) {
|
||||||
|
foreach( $collection->properties AS $k => $v ) {
|
||||||
|
$prop->NewElement($reply->Tag($k), $v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( count($arbitrary_results->missing) > 0 ) {
|
||||||
|
foreach( $arbitrary_results->missing AS $k => $v ) {
|
||||||
|
$not_found->NewElement($reply->Tag($k), '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return build_propstat_response( $prop, $not_found, $denied, $url );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return XML for a single data item from the DB
|
* Return XML for a single data item from the DB
|
||||||
*/
|
*/
|
||||||
function item_to_xml( $item ) {
|
function item_to_xml( $item ) {
|
||||||
global $attribute_list, $session, $c, $request;
|
global $prop_list, $session, $c, $request, $reply;
|
||||||
|
|
||||||
dbg_error_log("PROPFIND","Building XML Response for item '%s'", $item->dav_name );
|
dbg_error_log("PROPFIND","Building XML Response for item '%s'", $item->dav_name );
|
||||||
|
|
||||||
|
$allprop = isset($prop_list['DAV::allprop']);
|
||||||
|
|
||||||
$item->properties = get_arbitrary_properties($item->dav_name);
|
$item->properties = get_arbitrary_properties($item->dav_name);
|
||||||
|
|
||||||
$url = ConstructURL($item->dav_name);
|
$url = ConstructURL($item->dav_name);
|
||||||
@ -492,82 +440,35 @@ function item_to_xml( $item ) {
|
|||||||
$denied = new XMLElement("prop");
|
$denied = new XMLElement("prop");
|
||||||
|
|
||||||
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETLASTMODIFIED']) ) {
|
if ( $allprop || isset($prop_list['DAV::getcontentlength']) ) {
|
||||||
$prop->NewElement("getlastmodified", ( isset($item->modified)? $item->modified : false ));
|
|
||||||
}
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETCONTENTLENGTH']) ) {
|
|
||||||
$contentlength = strlen($item->caldav_data);
|
$contentlength = strlen($item->caldav_data);
|
||||||
$prop->NewElement("getcontentlength", $contentlength );
|
$prop->NewElement("getcontentlength", $contentlength );
|
||||||
}
|
}
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETCONTENTTYPE']) ) {
|
if ( $allprop || isset($prop_list['DAV::getcontenttype']) ) {
|
||||||
$prop->NewElement("getcontenttype", "text/calendar" );
|
$prop->NewElement("getcontenttype", "text/calendar" );
|
||||||
}
|
}
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['CREATIONDATE']) ) {
|
if ( $allprop || isset($prop_list['DAV::displayname']) ) {
|
||||||
$prop->NewElement("creationdate", $item->created );
|
$prop->NewElement("displayname", $item->dav_displayname );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Non-collections should return an empty resource type, it appears from RFC2518 8.1.2
|
* Non-collections should return an empty resource type, it appears from RFC2518 8.1.2
|
||||||
*/
|
*/
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['RESOURCETYPE']) ) {
|
if ( $allprop || isset($prop_list['DAV::resourcetype']) ) {
|
||||||
$prop->NewElement("resourcetype");
|
$prop->NewElement("resourcetype");
|
||||||
}
|
}
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['DISPLAYNAME']) ) {
|
|
||||||
$prop->NewElement("displayname", $item->dav_displayname );
|
|
||||||
}
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETETAG']) ) {
|
|
||||||
$prop->NewElement("getetag", '"'.$item->dav_etag.'"' );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Then look at any properties related to the principal
|
* Then look at any properties related to the principal
|
||||||
*/
|
*/
|
||||||
add_principal_properties( $prop, $not_found, $denied );
|
add_principal_properties( $prop, $not_found, $denied );
|
||||||
|
|
||||||
if ( isset($attribute_list['ACL']) ) {
|
/**
|
||||||
/**
|
* And any properties that are server/request related.
|
||||||
* FIXME: This information is semantically valid but presents an incorrect picture.
|
*/
|
||||||
*/
|
add_general_properties( $prop, $not_found, $denied, $item );
|
||||||
$principal = new XMLElement("principal");
|
|
||||||
$principal->NewElement("authenticated");
|
|
||||||
$grant = new XMLElement( "grant", array(privileges($request->permissions)) );
|
|
||||||
$prop->NewElement("acl", new XMLElement( "ace", array( $principal, $grant ) ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETCONTENTLANGUAGE']) ) {
|
return build_propstat_response( $prop, $not_found, $denied, $url );
|
||||||
$contentlength = strlen($item->caldav_data);
|
|
||||||
$prop->NewElement("getcontentlanguage", $c->current_locale );
|
|
||||||
}
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['CURRENT-USER-PRIVILEGE-SET']) ) {
|
|
||||||
$prop->NewElement("current-user-privilege-set", privileges($request->permissions) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTEDLOCK']) ) {
|
|
||||||
$prop->NewElement("supportedlock",
|
|
||||||
new XMLElement( "lockentry",
|
|
||||||
array(
|
|
||||||
new XMLElement("lockscope", new XMLElement("exclusive")),
|
|
||||||
new XMLElement("locktype", new XMLElement("write")),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$status = new XMLElement("status", "HTTP/1.1 200 OK" );
|
|
||||||
|
|
||||||
$propstat = new XMLElement( "propstat", array( $prop, $status) );
|
|
||||||
$href = new XMLElement("href", $url );
|
|
||||||
$response = array($href,$propstat);
|
|
||||||
|
|
||||||
if ( is_array($not_found->content) && count($not_found->content) > 0 ) {
|
|
||||||
$response[] = new XMLElement( "propstat", array( $not_found, new XMLElement("status", "HTTP/1.1 404 Not Found" )) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( is_array($denied->content) && count($denied->content) > 0 ) {
|
|
||||||
$response[] = new XMLElement( "propstat", array( $denied, new XMLElement("status", "HTTP/1.1 403 Forbidden" )) );
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = new XMLElement( "response", $response );
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -576,7 +477,7 @@ function item_to_xml( $item ) {
|
|||||||
* a list of calendars for the user which are parented by this path.
|
* a list of calendars for the user which are parented by this path.
|
||||||
*/
|
*/
|
||||||
function get_collection_contents( $depth, $user_no, $collection ) {
|
function get_collection_contents( $depth, $user_no, $collection ) {
|
||||||
global $session, $request;
|
global $session, $request, $reply, $prop_list;
|
||||||
|
|
||||||
dbg_error_log("PROPFIND","Getting collection contents: Depth %d, User: %d, Path: %s", $depth, $user_no, $collection->dav_name );
|
dbg_error_log("PROPFIND","Getting collection contents: Depth %d, User: %d, Path: %s", $depth, $user_no, $collection->dav_name );
|
||||||
|
|
||||||
@ -586,7 +487,7 @@ function get_collection_contents( $depth, $user_no, $collection ) {
|
|||||||
* Calendar collections may not contain calendar collections.
|
* Calendar collections may not contain calendar collections.
|
||||||
*/
|
*/
|
||||||
if ( $collection->dav_name == '/' ) {
|
if ( $collection->dav_name == '/' ) {
|
||||||
$sql = "SELECT user_no, user_no, '/' || username || '/' AS dav_name, md5( '/' || username || '/') AS dav_etag, ";
|
$sql = "SELECT usr.*, '/' || username || '/' AS dav_name, md5( '/' || username || '/') AS dav_etag, ";
|
||||||
$sql .= "to_char(updated at time zone 'GMT',?) AS created, ";
|
$sql .= "to_char(updated at time zone 'GMT',?) AS created, ";
|
||||||
$sql .= "to_char(updated at time zone 'GMT',?) AS modified, ";
|
$sql .= "to_char(updated at time zone 'GMT',?) AS modified, ";
|
||||||
$sql .= "fullname AS dav_displayname, FALSE AS is_calendar, TRUE AS is_principal FROM usr ";
|
$sql .= "fullname AS dav_displayname, FALSE AS is_calendar, TRUE AS is_principal FROM usr ";
|
||||||
@ -603,7 +504,13 @@ function get_collection_contents( $depth, $user_no, $collection ) {
|
|||||||
|
|
||||||
if( $qry->Exec("PROPFIND",__LINE__,__FILE__) && $qry->rows > 0 ) {
|
if( $qry->Exec("PROPFIND",__LINE__,__FILE__) && $qry->rows > 0 ) {
|
||||||
while( $subcollection = $qry->Fetch() ) {
|
while( $subcollection = $qry->Fetch() ) {
|
||||||
$responses[] = collection_to_xml( $subcollection );
|
if ( $subcollection->is_principal == "t" ) {
|
||||||
|
$principal = new CalDAVPrincipal($subcollection);
|
||||||
|
$responses[] = $principal->RenderAsXML($prop_list, &$reply);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$responses[] = collection_to_xml( $subcollection );
|
||||||
|
}
|
||||||
if ( $depth > 0 ) {
|
if ( $depth > 0 ) {
|
||||||
$responses = array_merge( $responses, get_collection_contents( $depth - 1, $user_no, $subcollection ) );
|
$responses = array_merge( $responses, get_collection_contents( $depth - 1, $user_no, $subcollection ) );
|
||||||
}
|
}
|
||||||
@ -740,7 +647,8 @@ else {
|
|||||||
$request->DoResponse( 403, translate("You do not have appropriate rights to view that resource.") );
|
$request->DoResponse( 403, translate("You do not have appropriate rights to view that resource.") );
|
||||||
}
|
}
|
||||||
|
|
||||||
$multistatus = new XMLElement( "multistatus", $responses, namespace_array() );
|
|
||||||
|
$multistatus = new XMLElement( "multistatus", $responses, $reply->GetXmlNsArray() );
|
||||||
|
|
||||||
// dbg_log_array( "PROPFIND", "XML", $multistatus, true );
|
// dbg_log_array( "PROPFIND", "XML", $multistatus, true );
|
||||||
$xmldoc = $multistatus->Render(0,'<?xml version="1.0" encoding="utf-8" ?>');
|
$xmldoc = $multistatus->Render(0,'<?xml version="1.0" encoding="utf-8" ?>');
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
*
|
*
|
||||||
* @package davical
|
* @package davical
|
||||||
* @subpackage caldav
|
* @subpackage caldav
|
||||||
* @author Andrew McMillan <andrew@catalyst.net.nz>
|
* @author Andrew McMillan <andrew@mcmillan.net.nz>
|
||||||
* @copyright Catalyst .Net Ltd
|
* @copyright Morphoss Ltd - http://www.morphoss.com/
|
||||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||||
*/
|
*/
|
||||||
dbg_error_log("PROPPATCH", "method handler");
|
dbg_error_log("PROPPATCH", "method handler");
|
||||||
@ -19,15 +19,15 @@ $xmltree = BuildXMLTree( $request->xml_tags, $position);
|
|||||||
|
|
||||||
// echo $xmltree->Render();
|
// echo $xmltree->Render();
|
||||||
|
|
||||||
if ( $xmltree->GetTag() != "DAV::PROPERTYUPDATE" ) {
|
if ( $xmltree->GetTag() != "DAV::propertyupdate" ) {
|
||||||
$request->DoResponse( 403 );
|
$request->DoResponse( 403 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the properties being set, and the properties being removed
|
* Find the properties being set, and the properties being removed
|
||||||
*/
|
*/
|
||||||
$setprops = $xmltree->GetPath("/DAV::PROPERTYUPDATE/DAV::SET/DAV::PROP/*");
|
$setprops = $xmltree->GetPath("/DAV::propertyupdate/DAV::set/DAV::prop/*");
|
||||||
$rmprops = $xmltree->GetPath("/DAV::PROPERTYUPDATE/DAV::REMOVE/DAV::PROP/*");
|
$rmprops = $xmltree->GetPath("/DAV::propertyupdate/DAV::remove/DAV::prop/*");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We build full status responses for failures. For success we just record
|
* We build full status responses for failures. For success we just record
|
||||||
@ -50,7 +50,7 @@ foreach( $setprops AS $k => $setting ) {
|
|||||||
|
|
||||||
switch( $tag ) {
|
switch( $tag ) {
|
||||||
|
|
||||||
case 'DAV::DISPLAYNAME':
|
case 'DAV::displayname':
|
||||||
/**
|
/**
|
||||||
* Can't set displayname on resources - only collections or principals
|
* Can't set displayname on resources - only collections or principals
|
||||||
*/
|
*/
|
||||||
@ -74,12 +74,12 @@ foreach( $setprops AS $k => $setting ) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::RESOURCETYPE':
|
case 'DAV::resourcetype':
|
||||||
/**
|
/**
|
||||||
* We don't allow a collection to change to/from a resource. Only collections may be CalDAV calendars.
|
* We don't allow a collection to change to/from a resource. Only collections may be CalDAV calendars.
|
||||||
*/
|
*/
|
||||||
$setcollection = count($setting->GetPath('DAV::RESOURCETYPE/DAV::COLLECTION'));
|
$setcollection = count($setting->GetPath('DAV::resourcetype/DAV::collection'));
|
||||||
$setcalendar = count($setting->GetPath('DAV::RESOURCETYPE/urn:ietf:params:xml:ns:caldav:calendar'));
|
$setcalendar = count($setting->GetPath('DAV::resourcetype/urn:ietf:params:xml:ns:caldav:calendar'));
|
||||||
if ( $request->IsCollection() && ($setcollection || $setcalendar) ) {
|
if ( $request->IsCollection() && ($setcollection || $setcalendar) ) {
|
||||||
if ( $setcalendar ) {
|
if ( $setcalendar ) {
|
||||||
$sql .= sprintf( "UPDATE collection SET is_calendar = TRUE WHERE dav_name = %s;", qpg($request->path) );
|
$sql .= sprintf( "UPDATE collection SET is_calendar = TRUE WHERE dav_name = %s;", qpg($request->path) );
|
||||||
@ -98,13 +98,19 @@ foreach( $setprops AS $k => $setting ) {
|
|||||||
/**
|
/**
|
||||||
* The following properties are read-only, so they will cause the request to fail
|
* The following properties are read-only, so they will cause the request to fail
|
||||||
*/
|
*/
|
||||||
case 'DAV::GETETAG':
|
case 'http://calendarserver.org/ns/:getctag':
|
||||||
case 'DAV::GETCONTENTLENGTH':
|
case 'DAV::owner':
|
||||||
case 'DAV::GETCONTENTTYPE':
|
case 'DAV::principal-collection-set':
|
||||||
case 'DAV::GETLASTMODIFIED':
|
case 'urn:ietf:params:xml:ns:caldav:calendar-user-address-set':
|
||||||
case 'DAV::CREATIONDATE':
|
case 'urn:ietf:params:xml:ns:caldav:schedule-inbox-URL':
|
||||||
case 'DAV::LOCKDISCOVERY':
|
case 'urn:ietf:params:xml:ns:caldav:schedule-outbox-URL':
|
||||||
case 'DAV::SUPPORTEDLOCK':
|
case 'DAV::getetag':
|
||||||
|
case 'DAV::getcontentlength':
|
||||||
|
case 'DAV::getcontenttype':
|
||||||
|
case 'DAV::getlastmodified':
|
||||||
|
case 'DAV::creationdate':
|
||||||
|
case 'DAV::lockdiscovery':
|
||||||
|
case 'DAV::supportedlock':
|
||||||
$failure['set-'.$tag] = new XMLElement( 'propstat', array(
|
$failure['set-'.$tag] = new XMLElement( 'propstat', array(
|
||||||
new XMLElement( 'prop', new XMLElement($tag)),
|
new XMLElement( 'prop', new XMLElement($tag)),
|
||||||
new XMLElement( 'status', 'HTTP/1.1 409 Conflict' ),
|
new XMLElement( 'status', 'HTTP/1.1 409 Conflict' ),
|
||||||
@ -130,12 +136,12 @@ foreach( $rmprops AS $k => $setting ) {
|
|||||||
|
|
||||||
switch( $tag ) {
|
switch( $tag ) {
|
||||||
|
|
||||||
case 'DAV::RESOURCETYPE':
|
case 'DAV::resourcetype':
|
||||||
/**
|
/**
|
||||||
* We don't allow a collection to change to/from a resource. Only collections may be CalDAV calendars.
|
* We don't allow a collection to change to/from a resource. Only collections may be CalDAV calendars.
|
||||||
*/
|
*/
|
||||||
$rmcollection = (count($setting->GetPath('DAV::RESOURCETYPE/DAV::COLLECTION')) > 0);
|
$rmcollection = (count($setting->GetPath('DAV::resourcetype/DAV::collection')) > 0);
|
||||||
$rmcalendar = (count($setting->GetPath('DAV::RESOURCETYPE/urn:ietf:params:xml:ns:caldav:calendar')) > 0);
|
$rmcalendar = (count($setting->GetPath('DAV::resourcetype/urn:ietf:params:xml:ns:caldav:calendar')) > 0);
|
||||||
if ( $request->IsCollection() && !$rmcollection ) {
|
if ( $request->IsCollection() && !$rmcollection ) {
|
||||||
dbg_error_log( 'PROPPATCH', ' RMProperty %s : IsCollection=%d, rmcoll=%d, rmcal=%d', $tag, $request->IsCollection(), $rmcollection, $rmcalendar );
|
dbg_error_log( 'PROPPATCH', ' RMProperty %s : IsCollection=%d, rmcoll=%d, rmcal=%d', $tag, $request->IsCollection(), $rmcollection, $rmcalendar );
|
||||||
if ( $rmcalendar ) {
|
if ( $rmcalendar ) {
|
||||||
@ -156,14 +162,20 @@ foreach( $rmprops AS $k => $setting ) {
|
|||||||
/**
|
/**
|
||||||
* The following properties are read-only, so they will cause the request to fail
|
* The following properties are read-only, so they will cause the request to fail
|
||||||
*/
|
*/
|
||||||
case 'DAV::GETETAG':
|
case 'http://calendarserver.org/ns/:getctag':
|
||||||
case 'DAV::GETCONTENTLENGTH':
|
case 'DAV::owner':
|
||||||
case 'DAV::GETCONTENTTYPE':
|
case 'DAV::principal-collection-set':
|
||||||
case 'DAV::GETLASTMODIFIED':
|
case 'urn:ietf:params:xml:ns:caldav:CALENDAR-USER-ADDRESS-SET':
|
||||||
case 'DAV::CREATIONDATE':
|
case 'urn:ietf:params:xml:ns:caldav:schedule-inbox-URL':
|
||||||
case 'DAV::DISPLAYNAME':
|
case 'urn:ietf:params:xml:ns:caldav:schedule-outbox-URL':
|
||||||
case 'DAV::LOCKDISCOVERY':
|
case 'DAV::getetag':
|
||||||
case 'DAV::SUPPORTEDLOCK':
|
case 'DAV::getcontentlength':
|
||||||
|
case 'DAV::getcontenttype':
|
||||||
|
case 'DAV::getlastmodified':
|
||||||
|
case 'DAV::creationdate':
|
||||||
|
case 'DAV::displayname':
|
||||||
|
case 'DAV::lockdiscovery':
|
||||||
|
case 'DAV::supportedlock':
|
||||||
$failure['rm-'.$tag] = new XMLElement( 'propstat', array(
|
$failure['rm-'.$tag] = new XMLElement( 'propstat', array(
|
||||||
new XMLElement( 'prop', new XMLElement($tag)),
|
new XMLElement( 'prop', new XMLElement($tag)),
|
||||||
new XMLElement( 'status', 'HTTP/1.1 409 Conflict' ),
|
new XMLElement( 'status', 'HTTP/1.1 409 Conflict' ),
|
||||||
@ -225,4 +237,3 @@ $request->DoResponse( 500 );
|
|||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
?>
|
|
||||||
|
|||||||
@ -3,20 +3,20 @@
|
|||||||
/**
|
/**
|
||||||
* Build the array of properties to include in the report output
|
* Build the array of properties to include in the report output
|
||||||
*/
|
*/
|
||||||
$qry_content = $xmltree->GetContent('URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-QUERY');
|
$qry_content = $xmltree->GetContent('urn:ietf:params:xml:ns:caldav:calendar-query');
|
||||||
$proptype = $qry_content[0]->GetTag();
|
$proptype = $qry_content[0]->GetTag();
|
||||||
$properties = array();
|
$properties = array();
|
||||||
switch( $proptype ) {
|
switch( $proptype ) {
|
||||||
case 'DAV::PROP':
|
case 'DAV::prop':
|
||||||
$qry_props = $xmltree->GetPath('/URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-QUERY/DAV::PROP/*');
|
$qry_props = $xmltree->GetPath('/urn:ietf:params:xml:ns:caldav:calendar-query/DAV::prop/*');
|
||||||
foreach( $qry_props AS $k => $v ) {
|
foreach( $qry_props AS $k => $v ) {
|
||||||
$propertyname = preg_replace( '/^.*:/', '', $v->GetTag() );
|
$propertyname = preg_replace( '/^.*:/', '', $v->GetTag() );
|
||||||
$properties[$propertyname] = 1;
|
$properties[$propertyname] = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::ALLPROP':
|
case 'DAV::allprop':
|
||||||
$properties['ALLPROP'] = 1;
|
$properties['allprop'] = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -30,13 +30,13 @@ switch( $proptype ) {
|
|||||||
* VCALENDAR, but perhaps there are others. In our case we strip it if that is
|
* VCALENDAR, but perhaps there are others. In our case we strip it if that is
|
||||||
* the case and leave it alone otherwise.
|
* the case and leave it alone otherwise.
|
||||||
*/
|
*/
|
||||||
$qry_filters = $xmltree->GetPath('/URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-QUERY/URN:IETF:PARAMS:XML:NS:CALDAV:FILTER/*');
|
$qry_filters = $xmltree->GetPath('/urn:ietf:params:xml:ns:caldav:calendar-query/urn:ietf:params:xml:ns:caldav:filter/*');
|
||||||
if ( count($qry_filters) == 1 ) {
|
if ( count($qry_filters) == 1 ) {
|
||||||
$qry_filters = $qry_filters[0]; // There can only be one FILTER element
|
$qry_filters = $qry_filters[0]; // There can only be one FILTER element
|
||||||
if ( $qry_filters->GetTag() == "URN:IETF:PARAMS:XML:NS:CALDAV:COMP-FILTER" && $qry_filters->GetAttribute("NAME") == "VCALENDAR" )
|
if ( $qry_filters->GetTag() == "urn:ietf:params:xml:ns:caldav:comp-filter" && $qry_filters->GetAttribute("name") == "VCALENDAR" )
|
||||||
$qry_filters = $qry_filters->GetContent(); // Everything is inside a VCALENDAR AFAICS
|
$qry_filters = $qry_filters->GetContent(); // Everything is inside a VCALENDAR AFAICS
|
||||||
else {
|
else {
|
||||||
dbg_error_log("calquery", "Got bizarre CALDAV:FILTER[%s=%s]] which does not contain COMP-FILTER = VCALENDAR!!", $qry_filters->GetTag(), $qry_filters->GetAttribute("NAME") );
|
dbg_error_log("calquery", "Got bizarre CALDAV:FILTER[%s=%s]] which does not contain comp-filter = VCALENDAR!!", $qry_filters->GetTag(), $qry_filters->GetAttribute("name") );
|
||||||
$qry_filters = false;
|
$qry_filters = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,12 +82,12 @@ function SqlFilterFragment( $filter, $components, $property = null, $parameter =
|
|||||||
|
|
||||||
$not_defined = "";
|
$not_defined = "";
|
||||||
switch( $tag ) {
|
switch( $tag ) {
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:IS-NOT-DEFINED':
|
case 'urn:ietf:params:xml:ns:caldav:is-not-defined':
|
||||||
$not_defined = "NOT "; // then fall through to IS-DEFINED case
|
$not_defined = "not-"; // then fall through to IS-DEFINED case
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:IS-DEFINED':
|
case 'urn:ietf:params:xml:ns:caldav:is-defined':
|
||||||
if ( isset( $parameter ) ) {
|
if ( isset( $parameter ) ) {
|
||||||
$need_post_filter = true;
|
$need_post_filter = true;
|
||||||
dbg_error_log("calquery", "Could not handle IS-%sDEFINED on property %s, parameter %s in SQL", $not_defined, $property, $parameter );
|
dbg_error_log("calquery", "Could not handle 'is-%sdefined' on property %s, parameter %s in SQL", $not_defined, $property, $parameter );
|
||||||
return false; // Not handled in SQL
|
return false; // Not handled in SQL
|
||||||
}
|
}
|
||||||
if ( isset( $property ) ) {
|
if ( isset( $property ) ) {
|
||||||
@ -111,14 +111,14 @@ function SqlFilterFragment( $filter, $components, $property = null, $parameter =
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:TIME-RANGE':
|
case 'urn:ietf:params:xml:ns:caldav:time-range':
|
||||||
/**
|
/**
|
||||||
* TODO: We should probably allow time range queries against other properties, since eventually some client may want to do this.
|
* TODO: We should probably allow time range queries against other properties, since eventually some client may want to do this.
|
||||||
*/
|
*/
|
||||||
$start_column = ($components[sizeof($components)-1] == 'VTODO' ? "due" : 'dtend'); // The column we compare against the START attribute
|
$start_column = ($components[sizeof($components)-1] == 'VTODO' ? "due" : 'dtend'); // The column we compare against the START attribute
|
||||||
$finish_column = 'dtstart'; // The column we compare against the END attribute
|
$finish_column = 'dtstart'; // The column we compare against the END attribute
|
||||||
$start = $v->GetAttribute("START");
|
$start = $v->GetAttribute("start");
|
||||||
$finish = $v->GetAttribute("END");
|
$finish = $v->GetAttribute("end");
|
||||||
if ( isset($start) && isset($finish) ) {
|
if ( isset($start) && isset($finish) ) {
|
||||||
$sql .= sprintf( "AND ( (%s >= %s::timestamp with time zone AND %s <= %s::timestamp with time zone) ",
|
$sql .= sprintf( "AND ( (%s >= %s::timestamp with time zone AND %s <= %s::timestamp with time zone) ",
|
||||||
$start_column, qpg($start), $finish_column, qpg($finish));
|
$start_column, qpg($start), $finish_column, qpg($finish));
|
||||||
@ -137,10 +137,10 @@ function SqlFilterFragment( $filter, $components, $property = null, $parameter =
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:TEXT-MATCH':
|
case 'urn:ietf:params:xml:ns:caldav:text-match':
|
||||||
$search = $v->GetContent();
|
$search = $v->GetContent();
|
||||||
$negate = $v->GetAttribute("NEGATE-CONDITION");
|
$negate = $v->GetAttribute("negate-condition");
|
||||||
$collation = $v->GetAttribute("COLLATION");
|
$collation = $v->GetAttribute("collation");
|
||||||
switch( strtolower($collation) ) {
|
switch( strtolower($collation) ) {
|
||||||
case 'i;octet':
|
case 'i;octet':
|
||||||
$comparison = 'LIKE';
|
$comparison = 'LIKE';
|
||||||
@ -150,12 +150,14 @@ function SqlFilterFragment( $filter, $components, $property = null, $parameter =
|
|||||||
$comparison = 'ILIKE';
|
$comparison = 'ILIKE';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$sql .= sprintf( "AND %s%s %s %s ", (isset($negate) && strtolower($negate) == "yes" ? "NOT ": ""),
|
dbg_error_log("calquery", " text-match: (%s IS NULL OR %s%s %s %s) ", $property, (isset($negate) && strtolower($negate) == "yes" ? "NOT ": ""),
|
||||||
|
$property, $comparison, qpg("%".$search."%") );
|
||||||
|
$sql .= sprintf( "AND (%s IS NULL OR %s%s %s %s) ", $property, (isset($negate) && strtolower($negate) == "yes" ? "NOT ": ""),
|
||||||
$property, $comparison, qpg("%".$search."%") );
|
$property, $comparison, qpg("%".$search."%") );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:COMP-FILTER':
|
case 'urn:ietf:params:xml:ns:caldav:comp-filter':
|
||||||
$comp_filter_name = $v->GetAttribute("NAME");
|
$comp_filter_name = $v->GetAttribute("name");
|
||||||
if ( count($components) == 0 ) {
|
if ( count($components) == 0 ) {
|
||||||
$sql .= "AND caldav_data.caldav_type = ".qpg($comp_filter_name)." ";
|
$sql .= "AND caldav_data.caldav_type = ".qpg($comp_filter_name)." ";
|
||||||
}
|
}
|
||||||
@ -167,8 +169,8 @@ function SqlFilterFragment( $filter, $components, $property = null, $parameter =
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:PROP-FILTER':
|
case 'urn:ietf:params:xml:ns:caldav:prop-filter':
|
||||||
$propertyname = $v->GetAttribute("NAME");
|
$propertyname = $v->GetAttribute("name");
|
||||||
switch( $propertyname ) {
|
switch( $propertyname ) {
|
||||||
case 'PERCENT-COMPLETE':
|
case 'PERCENT-COMPLETE':
|
||||||
$property = 'percent_complete';
|
$property = 'percent_complete';
|
||||||
@ -195,18 +197,18 @@ function SqlFilterFragment( $filter, $components, $property = null, $parameter =
|
|||||||
case 'COMPLETED': /** TODO: this should be moved into the properties supported in SQL. */
|
case 'COMPLETED': /** TODO: this should be moved into the properties supported in SQL. */
|
||||||
default:
|
default:
|
||||||
$need_post_filter = true;
|
$need_post_filter = true;
|
||||||
dbg_error_log("calquery", "Could not handle PROP-FILTER on %s in SQL", $propertyname );
|
dbg_error_log("calquery", "Could not handle 'prop-filter' on %s in SQL", $propertyname );
|
||||||
return false; // Can't handle PROP-FILTER conditions in the SQL for this property
|
continue;
|
||||||
}
|
}
|
||||||
$subfilter = $v->GetContent();
|
$subfilter = $v->GetContent();
|
||||||
$success = SqlFilterFragment( $subfilter, $components, $property, $parameter );
|
$success = SqlFilterFragment( $subfilter, $components, $property, $parameter );
|
||||||
if ( $success === false ) continue; else $sql .= $success;
|
if ( $success === false ) continue; else $sql .= $success;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:PARAM-FILTER':
|
case 'urn:ietf:params:xml:ns:caldav:param-filter':
|
||||||
$need_post_filter = true;
|
$need_post_filter = true;
|
||||||
return false; // Can't handle PARAM-FILTER conditions in the SQL
|
return false; // Can't handle PARAM-FILTER conditions in the SQL
|
||||||
$parameter = $v->GetAttribute("NAME");
|
$parameter = $v->GetAttribute("name");
|
||||||
$subfilter = $v->GetContent();
|
$subfilter = $v->GetContent();
|
||||||
$success = SqlFilterFragment( $subfilter, $components, $property, $parameter );
|
$success = SqlFilterFragment( $subfilter, $components, $property, $parameter );
|
||||||
if ( $success === false ) continue; else $sql .= $success;
|
if ( $success === false ) continue; else $sql .= $success;
|
||||||
@ -270,6 +272,6 @@ if ( $qry->Exec("calquery",__LINE__,__FILE__) && $qry->rows > 0 ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$multistatus = new XMLElement( "multistatus", $responses, array('xmlns'=>'DAV:') );
|
$multistatus = new XMLElement( "multistatus", $responses, $reply->GetXmlNsArray() );
|
||||||
|
|
||||||
$request->XMLResponse( 207, $multistatus );
|
$request->XMLResponse( 207, $multistatus );
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
include_once("iCalendar.php");
|
include_once("iCalendar.php");
|
||||||
include_once("RRule.php");
|
include_once("RRule.php");
|
||||||
|
|
||||||
$fbq_content = $xmltree->GetContent('URN:IETF:PARAMS:XML:NS:CALDAV:FREE-BUSY-QUERY');
|
$fbq_content = $xmltree->GetContent('urn:ietf:params:xml:ns:caldav:free-busy-query');
|
||||||
$fbq_start = $fbq_content[0]->GetAttribute('START');
|
$fbq_start = $fbq_content[0]->GetAttribute('start');
|
||||||
$fbq_end = $fbq_content[0]->GetAttribute('END');
|
$fbq_end = $fbq_content[0]->GetAttribute('end');
|
||||||
|
|
||||||
if ( ! ( isset($fbq_start) || isset($fbq_end) ) ) {
|
if ( ! ( isset($fbq_start) || isset($fbq_end) ) ) {
|
||||||
$request->DoResponse( 400, 'All valid freebusy requests MUST contain a time-range filter' );
|
$request->DoResponse( 400, 'All valid freebusy requests MUST contain a time-range filter' );
|
||||||
|
|||||||
@ -9,20 +9,20 @@ $responses = array();
|
|||||||
/**
|
/**
|
||||||
* Build the array of properties to include in the report output
|
* Build the array of properties to include in the report output
|
||||||
*/
|
*/
|
||||||
$mg_content = $xmltree->GetContent('URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-MULTIGET');
|
$mg_content = $xmltree->GetContent('urn:ietf:params:xml:ns:caldav:calendar-multiget');
|
||||||
$proptype = $mg_content[0]->GetTag();
|
$proptype = $mg_content[0]->GetTag();
|
||||||
$properties = array();
|
$properties = array();
|
||||||
switch( $proptype ) {
|
switch( $proptype ) {
|
||||||
case 'DAV::PROP':
|
case 'DAV::prop':
|
||||||
$mg_props = $xmltree->GetPath('/URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-MULTIGET/DAV::PROP/*');
|
$mg_props = $xmltree->GetPath('/urn:ietf:params:xml:ns:caldav:calendar-multiget/DAV::prop/*');
|
||||||
foreach( $mg_props AS $k => $v ) {
|
foreach( $mg_props AS $k => $v ) {
|
||||||
$propertyname = preg_replace( '/^.*:/', '', $v->GetTag() );
|
$propertyname = preg_replace( '/^.*:/', '', $v->GetTag() );
|
||||||
$properties[$propertyname] = 1;
|
$properties[$propertyname] = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'DAV::ALLPROP':
|
case 'DAV::allprop':
|
||||||
$properties['ALLPROP'] = 1;
|
$properties['allprop'] = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -33,7 +33,7 @@ switch( $proptype ) {
|
|||||||
/**
|
/**
|
||||||
* Build the href list for the IN ( href, href, href, ... ) clause.
|
* Build the href list for the IN ( href, href, href, ... ) clause.
|
||||||
*/
|
*/
|
||||||
$mg_hrefs = $xmltree->GetPath('/URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-MULTIGET/DAV::HREF');
|
$mg_hrefs = $xmltree->GetPath('/urn:ietf:params:xml:ns:caldav:calendar-multiget/DAV::href');
|
||||||
$href_in = '';
|
$href_in = '';
|
||||||
foreach( $mg_hrefs AS $k => $v ) {
|
foreach( $mg_hrefs AS $k => $v ) {
|
||||||
/**
|
/**
|
||||||
@ -65,6 +65,6 @@ if ( $qry->Exec("REPORT",__LINE__,__FILE__) && $qry->rows > 0 ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$multistatus = new XMLElement( "multistatus", $responses, array('xmlns'=>'DAV:') );
|
$multistatus = new XMLElement( "multistatus", $responses, $reply->GetXmlNsArray() );
|
||||||
|
|
||||||
$request->XMLResponse( 207, $multistatus );
|
$request->XMLResponse( 207, $multistatus );
|
||||||
|
|||||||
@ -2,108 +2,24 @@
|
|||||||
|
|
||||||
$responses = array();
|
$responses = array();
|
||||||
|
|
||||||
/**
|
|
||||||
* Return XML for a single Principal (user) from the DB
|
|
||||||
* TODO: Refactor this functionality into the CalDAVPrincipal object
|
|
||||||
*
|
|
||||||
* @param array $properties The requested properties for this principal
|
|
||||||
* @param string $item The user data for this calendar
|
|
||||||
*
|
|
||||||
* @return string An XML document which is the response for the principal
|
|
||||||
*/
|
|
||||||
function principal_to_xml( $properties, $item ) {
|
|
||||||
global $session, $c, $request;
|
|
||||||
|
|
||||||
dbg_error_log("REPORT","Building XML Response for principal '%s'", $item->username );
|
|
||||||
|
|
||||||
$this_url = ConstructURL( $request->dav_name );
|
|
||||||
$principal_url = ConstructURL( "/".$item->username."/");
|
|
||||||
$home_calendar = ConstructURL( "/".$item->username."/");
|
|
||||||
$prop = new XMLElement("prop");
|
|
||||||
$denied = array();
|
|
||||||
foreach( $properties AS $k => $v ) {
|
|
||||||
switch( $v ) {
|
|
||||||
case 'DAV::RESOURCETYPE':
|
|
||||||
$prop->NewElement("resourcetype", new XMLElement("principal") );
|
|
||||||
break;
|
|
||||||
case 'DAV::DISPLAYNAME':
|
|
||||||
$prop->NewElement("displayname", $item->username );
|
|
||||||
break;
|
|
||||||
case 'DAV::PRINCIPAL-URL':
|
|
||||||
$prop->NewElement("principal-url", $principal_url );
|
|
||||||
break;
|
|
||||||
case 'DAV::ALTERNATE-URI':
|
|
||||||
$prop->NewElement("alternate-uri" );
|
|
||||||
break;
|
|
||||||
case 'DAV::GROUP-MEMBER-SET':
|
|
||||||
$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';", $item->user_no );
|
|
||||||
$group = array();
|
|
||||||
if ( $qry->Exec("REPORT-principal") && $qry->rows > 0 ) {
|
|
||||||
while( $membership = $qry->Fetch() ) {
|
|
||||||
$group[] = new XMLElement("href", ConstructURL( "/". $membership->username . "/") );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$prop->NewElement("group-member-set", $group );
|
|
||||||
break;
|
|
||||||
case 'DAV::GROUP-MEMBERSHIP':
|
|
||||||
$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';", $item->user_no );
|
|
||||||
$group = array();
|
|
||||||
if ( $qry->Exec("REPORT-principal") && $qry->rows > 0 ) {
|
|
||||||
while( $membership = $qry->Fetch() ) {
|
|
||||||
$group[] = new XMLElement("href", ConstructURL( "/". $membership->username . "/") );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$prop->NewElement("group-membership", $group );
|
|
||||||
break;
|
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-HOME-SET':
|
|
||||||
$prop->NewElement("calendar-home-set", $home_calendar, array("xmlns" => "urn:ietf:params:xml:ns:caldav") );
|
|
||||||
break;
|
|
||||||
case 'SOME-DENIED-PROPERTY': /** TODO: indicating the style for future expansion */
|
|
||||||
$denied[] = $v;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dbg_error_log( 'REPORT', "Request for unsupported property '%s' of principal.", $item->username );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$status = new XMLElement("status", "HTTP/1.1 200 OK" );
|
|
||||||
|
|
||||||
$propstat = new XMLElement( "propstat", array( $prop, $status) );
|
|
||||||
$href = new XMLElement("href", $principal_url );
|
|
||||||
|
|
||||||
$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( strtolower($v) );
|
|
||||||
}
|
|
||||||
$elements[] = new XMLElement( "propstat", array( $noprop, $status) );
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = new XMLElement( "response", $elements );
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the array of properties to include in the report output
|
* Build the array of properties to include in the report output
|
||||||
*/
|
*/
|
||||||
$searches = $xmltree->GetPath('/DAV::PRINCIPAL-PROPERTY-SEARCH/DAV::PROPERTY-SEARCH');
|
$searches = $xmltree->GetPath('/DAV::principal-property-search/DAV::property-search');
|
||||||
dbg_log_array( "principal", "SEARCH", $searches, true );
|
dbg_log_array( "principal", "SEARCH", $searches, true );
|
||||||
|
|
||||||
$where = "";
|
$where = "";
|
||||||
foreach( $searches AS $k => $search ) {
|
foreach( $searches AS $k => $search ) {
|
||||||
$qry_props = $search->GetPath('/DAV::PROPERTY-SEARCH/DAV::PROP/*'); // There may be many
|
$qry_props = $search->GetPath('/DAV::property-search/DAV::prop/*'); // There may be many
|
||||||
$match = $search->GetPath('/DAV::PROPERTY-SEARCH/DAV::MATCH'); // There may only be one
|
$match = $search->GetPath('/DAV::property-search/DAV::match'); // There may only be one
|
||||||
dbg_log_array( "principal", "MATCH", $match, true );
|
dbg_log_array( "principal", "MATCH", $match, true );
|
||||||
$match = qpg($match[0]->GetContent());
|
$match = qpg($match[0]->GetContent());
|
||||||
$subwhere = "";
|
$subwhere = "";
|
||||||
foreach( $qry_props AS $k1 => $v1 ) {
|
foreach( $qry_props AS $k1 => $v1 ) {
|
||||||
if ( $subwhere != "" ) $subwhere .= " OR ";
|
if ( $subwhere != "" ) $subwhere .= " OR ";
|
||||||
switch( $v1->GetTag() ) {
|
switch( $v1->GetTag() ) {
|
||||||
case 'DAV::DISPLAYNAME':
|
case 'DAV::displayname':
|
||||||
$subwhere .= "username = ".$match;
|
$subwhere .= "username = ".$match;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -119,18 +35,19 @@ $sql = "SELECT * FROM usr $where";
|
|||||||
$qry = new PgQuery($sql);
|
$qry = new PgQuery($sql);
|
||||||
|
|
||||||
|
|
||||||
$get_props = $xmltree->GetPath('/DAV::PRINCIPAL-PROPERTY-SEARCH/DAV::PROP/*');
|
$get_props = $xmltree->GetPath('/DAV::principal-property-search/DAV::prop/*');
|
||||||
$properties = array();
|
$properties = array();
|
||||||
foreach( $get_props AS $k1 => $v1 ) {
|
foreach( $get_props AS $k1 => $v1 ) {
|
||||||
$properties[] = $v1->GetTag();
|
$properties[] = $v1->GetTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $qry->Exec("REPORT",__LINE__,__FILE__) && $qry->rows > 0 ) {
|
if ( $qry->Exec("REPORT",__LINE__,__FILE__) && $qry->rows > 0 ) {
|
||||||
while( $principal_object = $qry->Fetch() ) {
|
while( $row = $qry->Fetch() ) {
|
||||||
$responses[] = principal_to_xml( $properties, $principal_object );
|
$principal = new CalDAVPrincipal($row);
|
||||||
|
$responses[] = $principal->RenderAsXML( $properties, &$reply );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$multistatus = new XMLElement( "multistatus", $responses, array('xmlns'=>'DAV:') );
|
$multistatus = new XMLElement( "multistatus", $responses, $reply->GetXmlNsArray() );
|
||||||
|
|
||||||
$request->XMLResponse( 207, $multistatus );
|
$request->XMLResponse( 207, $multistatus );
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
*/
|
*/
|
||||||
dbg_error_log("REPORT", "method handler");
|
dbg_error_log("REPORT", "method handler");
|
||||||
|
|
||||||
|
require_once("XMLDocument.php");
|
||||||
|
|
||||||
if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || $c->dbg['report']) ) {
|
if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || $c->dbg['report']) ) {
|
||||||
$fh = fopen('/tmp/REPORT.txt','w');
|
$fh = fopen('/tmp/REPORT.txt','w');
|
||||||
if ( $fh ) {
|
if ( $fh ) {
|
||||||
@ -40,11 +42,13 @@ $denied = array();
|
|||||||
$unsupported = array();
|
$unsupported = array();
|
||||||
if ( isset($prop_filter) ) unset($prop_filter);
|
if ( isset($prop_filter) ) unset($prop_filter);
|
||||||
|
|
||||||
if ( $xmltree->GetTag() == "URN:IETF:PARAMS:XML:NS:CALDAV:FREE-BUSY-QUERY" ) {
|
if ( $xmltree->GetTag() == "urn:ietf:params:xml:ns:caldav:free-busy-query" ) {
|
||||||
include("caldav-REPORT-freebusy.php");
|
include("caldav-REPORT-freebusy.php");
|
||||||
exit; // Not that the above include should return anyway
|
exit; // Not that the above include should return anyway
|
||||||
}
|
}
|
||||||
if ( $xmltree->GetTag() == "DAV::PRINCIPAL-PROPERTY-SEARCH" ) {
|
|
||||||
|
$reply = new XMLDocument( array( "DAV:" => "" ) );
|
||||||
|
if ( $xmltree->GetTag() == "DAV::principal-property-search" ) {
|
||||||
include("caldav-REPORT-principal.php");
|
include("caldav-REPORT-principal.php");
|
||||||
exit; // Not that the above include should return anyway
|
exit; // Not that the above include should return anyway
|
||||||
}
|
}
|
||||||
@ -66,14 +70,14 @@ if ( ! ($request->AllowedTo('read') ) ) {
|
|||||||
* @return string An XML document which is the response for the calendar
|
* @return string An XML document which is the response for the calendar
|
||||||
*/
|
*/
|
||||||
function calendar_to_xml( $properties, $item ) {
|
function calendar_to_xml( $properties, $item ) {
|
||||||
global $session, $c, $request;
|
global $session, $c, $request, $reply;
|
||||||
|
|
||||||
dbg_error_log("REPORT","Building XML Response for item '%s'", $item->dav_name );
|
dbg_error_log("REPORT","Building XML Response for item '%s'", $item->dav_name );
|
||||||
|
|
||||||
$denied = array();
|
$denied = array();
|
||||||
$caldav_data = $item->caldav_data;
|
$caldav_data = $item->caldav_data;
|
||||||
$displayname = $item->summary;
|
$displayname = $item->summary;
|
||||||
if ( isset($properties['CALENDAR-DATA']) || isset($properties['DISPLAYNAME']) ) {
|
if ( isset($properties['calendar-data']) || isset($properties['displayname']) ) {
|
||||||
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
|
||||||
if ( $item->class == 'CONFIDENTIAL' ) {
|
if ( $item->class == 'CONFIDENTIAL' ) {
|
||||||
@ -108,27 +112,27 @@ function calendar_to_xml( $properties, $item ) {
|
|||||||
$prop = new XMLElement("prop");
|
$prop = new XMLElement("prop");
|
||||||
foreach( $properties AS $k => $v ) {
|
foreach( $properties AS $k => $v ) {
|
||||||
switch( $k ) {
|
switch( $k ) {
|
||||||
case 'GETCONTENTLENGTH':
|
case 'getcontentlength':
|
||||||
$contentlength = strlen($caldav_data);
|
$contentlength = strlen($caldav_data);
|
||||||
$prop->NewElement("getcontentlength", $contentlength );
|
$prop->NewElement($k, $contentlength );
|
||||||
break;
|
break;
|
||||||
case 'CALENDAR-DATA':
|
case 'calendar-data':
|
||||||
$prop->NewElement("calendar-data","$caldav_data" , array("xmlns" => "urn:ietf:params:xml:ns:caldav") );
|
$prop->NewElement($reply->Caldav($k), $caldav_data );
|
||||||
break;
|
break;
|
||||||
case 'GETCONTENTTYPE':
|
case 'getcontenttype':
|
||||||
$prop->NewElement("getcontenttype", "text/calendar" );
|
$prop->NewElement($k, "text/calendar" );
|
||||||
break;
|
break;
|
||||||
case 'RESOURCETYPE':
|
case 'resourcetype':
|
||||||
$prop->NewElement("resourcetype", new XMLElement("calendar", false, array("xmlns" => "urn:ietf:params:xml:ns:caldav")) );
|
$prop->NewElement($k, new XMLElement($reply->Caldav("calendar"), false) );
|
||||||
break;
|
break;
|
||||||
case 'DISPLAYNAME':
|
case 'displayname':
|
||||||
$prop->NewElement("displayname", $displayname );
|
$prop->NewElement($k, $displayname );
|
||||||
break;
|
break;
|
||||||
case 'GETETAG':
|
case 'getetag':
|
||||||
$prop->NewElement("getetag", '"'.$item->dav_etag.'"' );
|
$prop->NewElement($k, '"'.$item->dav_etag.'"' );
|
||||||
break;
|
break;
|
||||||
case 'CURRENT-USER-PRIVILEGE-SET':
|
case '"current-user-privilege-set"':
|
||||||
$prop->NewElement("current-user-privilege-set", privileges($request->permissions) );
|
$prop->NewElement($k, privileges($request->permissions) );
|
||||||
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[] = $v;
|
$denied[] = $v;
|
||||||
@ -158,16 +162,15 @@ function calendar_to_xml( $properties, $item ) {
|
|||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $xmltree->GetTag() == "URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-QUERY" ) {
|
if ( $xmltree->GetTag() == "urn:ietf:params:xml:ns:caldav:calendar-query" ) {
|
||||||
$calquery = $xmltree->GetPath("/URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-QUERY/*");
|
$calquery = $xmltree->GetPath("/urn:ietf:params:xml:ns:caldav:calendar-query/*");
|
||||||
include("caldav-REPORT-calquery.php");
|
include("caldav-REPORT-calquery.php");
|
||||||
}
|
}
|
||||||
elseif ( $xmltree->GetTag() == "URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-MULTIGET" ) {
|
elseif ( $xmltree->GetTag() == "urn:ietf:params:xml:ns:caldav:calendar-multiget" ) {
|
||||||
$multiget = $xmltree->GetPath("/URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-MULTIGET/*");
|
$multiget = $xmltree->GetPath("/urn:ietf:params:xml:ns:caldav:calendar-multiget/*");
|
||||||
include("caldav-REPORT-multiget.php");
|
include("caldav-REPORT-multiget.php");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$request->DoResponse( 501, "XML is not a supported REPORT query document" );
|
$request->DoResponse( 501, "XML is not a supported REPORT query document" );
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user