diff --git a/inc/DAVResource.php b/inc/DAVResource.php
index c36edf83..fbdbcdf4 100644
--- a/inc/DAVResource.php
+++ b/inc/DAVResource.php
@@ -627,11 +627,37 @@ EOQRY;
$qry = new AwlQuery('SELECT property_name, property_value FROM property WHERE dav_name= :dav_name', array(':dav_name' => $this->dav_name) );
if ( $qry->Exec('DAVResource') ) {
while ( $property = $qry->Fetch() ) {
- $this->dead_properties[$property->property_name] = $property->property_value;
+ $this->dead_properties[$property->property_name] = self::BuildDeadPropertyXML($property->property_name,$property->property_value);
}
}
}
+ public static function BuildDeadPropertyXML($property_name, $raw_string) {
+ if ( !preg_match('{^\s*<.*>\s*$}s', $raw_string) ) return $raw_string;
+ $xmlns = null;
+ if ( preg_match( '{^(.*):([^:]+)$}', $property_name, $matches) ) {
+ $xmlns = $matches[1];
+ $property_name = $matches[2];
+ }
+ $xml = sprintf('<%s%s>%s%s>', $property_name, (isset($xmlns)?' xmlns="'.$xmlns.'"':''), $raw_string, $property_name);
+ $xml_parser = xml_parser_create_ns('UTF-8');
+ $xml_tags = array();
+ xml_parser_set_option ( $xml_parser, XML_OPTION_SKIP_WHITE, 1 );
+ xml_parser_set_option ( $xml_parser, XML_OPTION_CASE_FOLDING, 0 );
+ $rc = xml_parse_into_struct( $xml_parser, $xml, $xml_tags );
+ if ( $rc == false ) {
+ dbg_error_log( 'ERROR', 'XML parsing error: %s at line %d, column %d',
+ xml_error_string(xml_get_error_code($xml_parser)),
+ xml_get_current_line_number($xml_parser), xml_get_current_column_number($xml_parser) );
+ dbg_error_log( 'ERROR', "Error occurred in:\n%s\n",$xml);
+ return $raw_string;
+ }
+ xml_parser_free($xml_parser);
+ $position = 0;
+ $xmltree = BuildXMLTree( $xml_tags, $position);
+ $content = $xmltree->GetContent();
+ return $content[0];
+ }
/**
* Build permissions for this URL
diff --git a/inc/Principal.php b/inc/Principal.php
index aeb25230..b40b7699 100644
--- a/inc/Principal.php
+++ b/inc/Principal.php
@@ -398,7 +398,7 @@ class Principal {
$qry = new AwlQuery('SELECT property_name, property_value FROM property WHERE dav_name= :dav_name', array(':dav_name' => $this->dav_name()) );
if ( $qry->Exec('Principal') ) {
while ( $property = $qry->Fetch() ) {
- $this->dead_properties[$property->property_name] = $property->property_value;
+ $this->dead_properties[$property->property_name] = DAVResource::BuildDeadPropertyXML($property->property_value);
}
}
}
diff --git a/inc/caldav-MKCOL.php b/inc/caldav-MKCOL.php
index ea82aef1..261f3d86 100644
--- a/inc/caldav-MKCOL.php
+++ b/inc/caldav-MKCOL.php
@@ -65,8 +65,8 @@ if ( isset($request->xml_tags) ) {
foreach( $setprops AS $k => $setting ) {
$tag = $setting->GetNSTag();
- $content = $setting->RenderContent();
-
+ $content = $setting->RenderContent(0,null,true);
+
dbg_error_log( 'MKCOL', 'Processing tag "%s"', $tag);
switch( $tag ) {
diff --git a/inc/caldav-PROPPATCH.php b/inc/caldav-PROPPATCH.php
index a6ddb5de..1daebb8c 100644
--- a/inc/caldav-PROPPATCH.php
+++ b/inc/caldav-PROPPATCH.php
@@ -79,7 +79,7 @@ $qry->Begin();
$setcalendar = count($xmltree->GetPath('/DAV::propertyupdate/DAV::set/DAV::prop/DAV::resourcetype/urn:ietf:params:xml:ns:caldav:calendar'));
foreach( $setprops AS $k => $setting ) {
$tag = $setting->GetNSTag();
- $content = $setting->RenderContent();
+ $content = $setting->RenderContent(0,null,true);
switch( $tag ) {
@@ -113,18 +113,39 @@ foreach( $setprops AS $k => $setting ) {
* We only allow resourcetype setting on a normal collection, and not on a resource, a principal or a bind.
* Only collections may be CalDAV calendars or addressbooks, and they may not be both.
*/
- $setcollection = count($setting->GetPath('DAV::resourcetype/DAV::collection'));
- $setaddressbook = count($setting->GetPath('DAV::resourcetype/urn:ietf:params:xml:ns:carddav:addressbook'));
- if ( $dav_resource->IsCollection() && $setcollection && ! $dav_resource->IsPrincipal()
- && ! $dav_resource->IsBinding() && ! ($setaddressbook && $setcalendar) ) {
- $resourcetypes = $setting->GetPath('DAV::resourcetype/*');
- $resourcetypes = str_replace( "\n", "", implode('',$resourcetypes));
+ $resourcetypes = $setting->GetPath('DAV::resourcetype/*');
+ $setcollection = false;
+ $setcalendar = false;
+ $setaddressbook = false;
+ $setother = false;
+ foreach( $resourcetypes AS $xnode ) {
+ switch( $xnode->GetNSTag() ) {
+ case 'urn:ietf:params:xml:ns:caldav:calendar': $setcalendar = true; break;
+ case 'urn:ietf:params:xml:ns:carddav:addressbook': $setaddressbook = true; break;
+ case 'DAV::collection': $setcollection = true; break;
+ default:
+ $setother = true;
+ }
+ }
+ if ( $dav_resource->IsCollection() && $setcollection && ! $dav_resource->IsPrincipal() && ! $dav_resource->IsBinding()
+ && !($setcalendar && $setaddressbook) && !$setother ) {
+ $resourcetypes = '';
+ if ( $setcalendar ) $resourcetypes .= '';
+ else if ( $setaddressbook ) $resourcetypes .= '';
$qry->QDo('UPDATE collection SET is_calendar = :is_calendar::boolean, is_addressbook = :is_addressbook::boolean,
resourcetypes = :resourcetypes WHERE dav_name = :dav_name',
array( ':dav_name' => $dav_resource->dav_name(), ':resourcetypes' => $resourcetypes,
':is_calendar' => $setcalendar, ':is_addressbook' => $setaddressbook ) );
$success[$tag] = 1;
}
+ else if ( $setcalendar && $setaddressbook ) {
+ add_failure('set', $tag, 'HTTP/1.1 409 Conflict',
+ translate("A collection may not be both a calendar and an addressbook."));
+ }
+ else if ( $setother ) {
+ add_failure('set', $tag, 'HTTP/1.1 403 Forbidden',
+ translate("Unsupported resourcetype modification."), 'cannot-modify-protected-property');
+ }
else {
add_failure('set', $tag, 'HTTP/1.1 403 Forbidden',
translate("Resources may not be changed to / from collections."), 'cannot-modify-protected-property');