PageRenderTime 51ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/inc/caldav-REPORT.php

https://gitlab.com/tiggerben/davical
PHP | 250 lines | 184 code | 25 blank | 41 comment | 45 complexity | 26e483a50a4403e38002711d07454416 MD5 | raw file
  1. <?php
  2. /**
  3. * CalDAV Server - handle REPORT method
  4. *
  5. * @package davical
  6. * @subpackage caldav
  7. * @author Andrew McMillan <andrew@morphoss.com>
  8. * @copyright Catalyst .Net Ltd, Morphoss Ltd
  9. * @license http://gnu.org/copyleft/gpl.html GNU GPL v2
  10. */
  11. dbg_error_log("REPORT", "method handler");
  12. require_once("XMLDocument.php");
  13. require_once('DAVResource.php');
  14. require_once('RRule-v2.php');
  15. if ( ! ini_get('open_basedir') && (isset($c->dbg['ALL']) || (isset($c->dbg['report']) && $c->dbg['report'])) ) {
  16. $fh = fopen('/var/log/davical/REPORT.debug','w');
  17. if ( $fh ) {
  18. fwrite($fh,$request->raw_post);
  19. fclose($fh);
  20. }
  21. }
  22. if ( !isset($request->xml_tags) ) {
  23. $request->DoResponse( 406, translate("REPORT body contains no XML data!") );
  24. }
  25. $position = 0;
  26. $xmltree = BuildXMLTree( $request->xml_tags, $position);
  27. if ( !is_object($xmltree) ) {
  28. $request->DoResponse( 406, translate("REPORT body is not valid XML data!") );
  29. }
  30. $target = new DAVResource($request->path);
  31. if ( $xmltree->GetNSTag() != 'DAV::principal-property-search'
  32. && $xmltree->GetNSTag() != 'DAV::principal-property-search-set' ) {
  33. $target->NeedPrivilege( array('DAV::read', 'urn:ietf:params:xml:ns:caldav:read-free-busy'), true ); // They may have either
  34. }
  35. require_once("vCalendar.php");
  36. $reportnum = -1;
  37. $report = array();
  38. $denied = array();
  39. $unsupported = array();
  40. if ( isset($prop_filter) ) unset($prop_filter);
  41. if ( $xmltree->GetNSTag() == 'urn:ietf:params:xml:ns:caldav:free-busy-query' ) {
  42. include("caldav-REPORT-freebusy.php");
  43. exit; // Not that the above include should return anyway
  44. }
  45. $reply = new XMLDocument( array( "DAV:" => "" ) );
  46. switch( $xmltree->GetNSTag() ) {
  47. case 'DAV::principal-property-search':
  48. include("caldav-REPORT-principal.php");
  49. exit; // Not that it should return anyway.
  50. case 'DAV::principal-search-property-set':
  51. include("caldav-REPORT-pps-set.php");
  52. exit; // Not that it should return anyway.
  53. case 'DAV::sync-collection':
  54. if ( $target->IsExternal() ) {
  55. require_once("external-fetch.php");
  56. update_external ( $target );
  57. }
  58. include("caldav-REPORT-sync-collection.php");
  59. exit; // Not that it should return anyway.
  60. case 'DAV::expand-property':
  61. if ( $target->IsExternal() ) {
  62. require_once("external-fetch.php");
  63. update_external ( $target );
  64. }
  65. include("caldav-REPORT-expand-property.php");
  66. exit; // Not that it should return anyway.
  67. case 'DAV::principal-match':
  68. include("caldav-REPORT-principal-match.php");
  69. exit; // Not that it should return anyway.
  70. }
  71. /**
  72. * Return XML for a single component from the DB
  73. *
  74. * @param array $properties The properties for this component
  75. * @param string $item The DB row data for this component
  76. *
  77. * @return string An XML document which is the response for the component
  78. */
  79. function component_to_xml( $properties, $item ) {
  80. global $session, $c, $request, $reply;
  81. dbg_error_log("REPORT","Building XML Response for item '%s'", $item->dav_name );
  82. $denied = array();
  83. $unsupported = array();
  84. $caldav_data = $item->caldav_data;
  85. $displayname = preg_replace( '{^.*/}', '', $item->dav_name );
  86. $type = 'unknown';
  87. $contenttype = 'text/plain';
  88. switch( strtoupper($item->caldav_type) ) {
  89. case 'VJOURNAL':
  90. case 'VEVENT':
  91. case 'VTODO':
  92. $displayname = $item->summary;
  93. $type = 'calendar';
  94. $contenttype = 'text/calendar';
  95. if ( isset($properties['urn:ietf:params:xml:ns:caldav:calendar-data']) || isset($properties['DAV::displayname']) ) {
  96. if ( !$request->AllowedTo('all') && $session->user_no != $item->user_no ) {
  97. // the user is not admin / owner of this calendar looking at his calendar and can not admin the other cal
  98. if ( $item->class == 'CONFIDENTIAL' || !$request->AllowedTo('read') ) {
  99. dbg_error_log("REPORT","Anonymising confidential event for: %s", $item->dav_name );
  100. $vcal = new vCalendar( $caldav_data );
  101. $caldav_data = $vcal->Confidential()->Render();
  102. $displayname = translate('Busy');
  103. }
  104. }
  105. }
  106. if ( isset($c->hide_alarm) && $c->hide_alarm ) {
  107. $dav_resource = new DAVResource($item->dav_name);
  108. if ( isset($properties['urn:ietf:params:xml:ns:caldav:calendar-data']) && !$dav_resource->HavePrivilegeTo('write') ) {
  109. dbg_error_log("REPORT","Stripping event alarms for: %s", $item->dav_name );
  110. $vcal = new vCalendar($caldav_data);
  111. $vcal->ClearComponents('VALARM');
  112. $caldav_data = $vcal->Render();
  113. }
  114. }
  115. break;
  116. case 'VCARD':
  117. $displayname = $item->fn;
  118. $type = 'vcard';
  119. $contenttype = 'text/vcard';
  120. break;
  121. }
  122. $url = ConstructURL($item->dav_name);
  123. $prop = new XMLElement("prop");
  124. $need_resource = false;
  125. foreach( $properties AS $full_tag => $v ) {
  126. $base_tag = preg_replace('{^.*:}', '', $full_tag );
  127. switch( $full_tag ) {
  128. case 'DAV::getcontentlength':
  129. $contentlength = strlen($caldav_data);
  130. $prop->NewElement($base_tag, $contentlength );
  131. break;
  132. case 'DAV::getlastmodified':
  133. $prop->NewElement($base_tag, ISODateToHTTPDate($item->modified) );
  134. break;
  135. case 'urn:ietf:params:xml:ns:caldav:calendar-data':
  136. if ( $type == 'calendar' ) $reply->CalDAVElement($prop, $base_tag, $caldav_data );
  137. else $unsupported[] = $base_tag;
  138. break;
  139. case 'urn:ietf:params:xml:ns:carddav:address-data':
  140. if ( $type == 'vcard' ) $reply->CardDAVElement($prop, $base_tag, $caldav_data );
  141. else $unsupported[] = $base_tag;
  142. break;
  143. case 'DAV::getcontenttype':
  144. $prop->NewElement($base_tag, $contenttype );
  145. break;
  146. case 'DAV::current-user-principal':
  147. $prop->NewElement("current-user-principal", $request->current_user_principal_xml);
  148. break;
  149. case 'DAV::displayname':
  150. $prop->NewElement($base_tag, $displayname );
  151. break;
  152. case 'DAV::resourcetype':
  153. $prop->NewElement($base_tag); // Just an empty resourcetype for a non-collection.
  154. break;
  155. case 'DAV::getetag':
  156. $prop->NewElement($base_tag, '"'.$item->dav_etag.'"' );
  157. break;
  158. case '"current-user-privilege-set"':
  159. $prop->NewElement($base_tag, privileges($request->permissions) );
  160. break;
  161. default:
  162. // It's harder. We need the DAVResource() to get this one.
  163. $need_resource = true;
  164. }
  165. if ( $need_resource ) break;
  166. }
  167. $href = new XMLElement("href", $url );
  168. if ( $need_resource ) {
  169. if ( !isset($dav_resource) ) $dav_resource = new DAVResource($item->dav_name);
  170. $elements = $dav_resource->GetPropStat(array_keys($properties), $reply);
  171. array_unshift($elements, $href);
  172. }
  173. else {
  174. $elements = array($href);
  175. $status = new XMLElement("status", "HTTP/1.1 200 OK" );
  176. $elements[] = new XMLElement( "propstat", array( $prop, $status) );
  177. if ( count($denied) > 0 ) {
  178. $status = new XMLElement("status", "HTTP/1.1 403 Forbidden" );
  179. $noprop = new XMLElement("prop");
  180. foreach( $denied AS $k => $v ) {
  181. $reply->NSElement($noprop, $v);
  182. }
  183. $elements[] = new XMLElement( "propstat", array( $noprop, $status) );
  184. }
  185. if ( ! $request->PreferMinimal() && count($unsupported) > 0 ) {
  186. $status = new XMLElement("status", "HTTP/1.1 404 Not Found" );
  187. $noprop = new XMLElement("prop");
  188. foreach( $unsupported AS $k => $v ) {
  189. $reply->NSElement($noprop, $v);
  190. }
  191. $elements[] = new XMLElement( "propstat", array( $noprop, $status) );
  192. }
  193. }
  194. $response = new XMLElement( "response", $elements );
  195. return $response;
  196. }
  197. if ( $target->IsExternal() ) {
  198. require_once("external-fetch.php");
  199. update_external ( $target );
  200. }
  201. // These reports are always allowed to see the resource_data because they are special
  202. $c->sync_resource_data_ok = true;
  203. if ( $xmltree->GetNSTag() == "urn:ietf:params:xml:ns:caldav:calendar-query" ) {
  204. $calquery = $xmltree->GetPath("/urn:ietf:params:xml:ns:caldav:calendar-query/*");
  205. include("caldav-REPORT-calquery.php");
  206. }
  207. elseif ( $xmltree->GetNSTag() == "urn:ietf:params:xml:ns:caldav:calendar-multiget" ) {
  208. $mode = 'caldav';
  209. $qry_content = $xmltree->GetContent('urn:ietf:params:xml:ns:caldav:calendar-multiget');
  210. include("caldav-REPORT-multiget.php");
  211. }
  212. elseif ( $xmltree->GetNSTag() == "urn:ietf:params:xml:ns:carddav:addressbook-multiget" ) {
  213. $mode = 'carddav';
  214. $qry_content = $xmltree->GetContent('urn:ietf:params:xml:ns:carddav:addressbook-multiget');
  215. include("caldav-REPORT-multiget.php");
  216. }
  217. elseif ( $xmltree->GetNSTag() == "urn:ietf:params:xml:ns:carddav:addressbook-query" ) {
  218. $cardquery = $xmltree->GetPath("/urn:ietf:params:xml:ns:carddav:addressbook-query/*");
  219. include("caldav-REPORT-cardquery.php");
  220. }
  221. else {
  222. dbg_error_log( 'ERROR', "Request for unsupported report type '%s'.", $xmltree->GetNSTag() );
  223. $request->PreconditionFailed( 403, 'DAV::supported-report', sprintf( '"%s" is not a supported report type', $xmltree->GetNSTag()) );
  224. }