/** * CalDAV Server - handle GET method * * @package davical * @subpackage caldav * @author Andrew McMillan <*****@*****.**> * @copyright Catalyst .Net Ltd, Morphoss Ltd <http://www.morphoss.com/> * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later */ dbg_error_log("get", "GET method handler"); require "caldav-GET-functions.php"; $dav_resource = new DAVResource($request->path); $dav_resource->NeedPrivilege(array('urn:ietf:params:xml:ns:caldav:read-free-busy', 'DAV::read')); if ($dav_resource->IsExternal()) { require_once "external-fetch.php"; update_external($dav_resource); } if (!$dav_resource->Exists()) { $request->DoResponse(404, translate("Resource Not Found.")); } if ($dav_resource->IsCollection()) { $response = export_iCalendar($dav_resource); header('Etag: ' . $dav_resource->unique_tag()); $request->DoResponse(200, $request->method == 'HEAD' ? '' : $response, 'text/calendar; charset="utf-8"'); } // Just a single event then $resource = $dav_resource->resource(); $ic = new iCalComponent($resource->caldav_data); $resource->caldav_data = preg_replace('{(?<!\\r)\\n}', "\r\n", $resource->caldav_data); /** Default deny... */ $allowed = false;
/** * Get XML response for items in the collection * If '/' is requested, a list of visible users is given, otherwise * a list of calendars for the user which are parented by this path. */ function get_collection_contents($depth, $collection, $parent_path = null) { global $c, $session, $request, $reply, $property_list; $bound_from = $collection->bound_from(); $bound_to = $collection->dav_name(); if (!isset($parent_path)) { $parent_path = $collection->dav_name(); } dbg_error_log('PROPFIND', 'Getting collection contents: Depth %d, Path: %s, Bound from: %s, Bound to: %s', $depth, $collection->dav_name(), $bound_from, $bound_to); $date_format = AwlDatabase::HttpDateFormat; $responses = array(); if (!$collection->IsCalendar() && !$collection->IsAddressbook()) { /** * Calendar/Addressbook collections may not contain collections, so we are only looking in the other ones */ $params = array(':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth); if ($bound_from == '/') { $sql = "SELECT usr.*, '/' || username || '/' AS dav_name, md5(username || updated::text) AS dav_etag, "; $sql .= "to_char(joined at time zone 'GMT',{$date_format}) AS created, "; $sql .= "to_char(updated at time zone 'GMT',{$date_format}) AS modified, "; $sql .= 'FALSE AS is_calendar, TRUE AS is_principal, FALSE AS is_addressbook, \'principal\' AS type, '; $sql .= 'principal_id AS collection_id, '; $sql .= 'principal.* '; $sql .= 'FROM usr JOIN principal USING (user_no) '; $sql .= "WHERE (pprivs(:session_principal::int8,principal.principal_id,:scan_depth::int) & 1::BIT(24))::INT4::BOOLEAN "; $sql .= 'ORDER BY usr.user_no'; } else { $qry = new AwlQuery('SELECT * FROM dav_binding WHERE dav_binding.parent_container = :this_dav_name ORDER BY bind_id', array(':this_dav_name' => $bound_from)); if ($qry->Exec('PROPFIND', __LINE__, __FILE__) && $qry->rows() > 0) { while ($binding = $qry->Fetch()) { $resource = new DAVResource($binding->dav_name); if ($resource->IsExternal()) { require_once "external-fetch.php"; update_external($resource); } if ($resource->HavePrivilegeTo('DAV::read', false)) { $resource->set_bind_location(str_replace($bound_from, $bound_to, $binding->dav_name)); $responses[] = $resource->RenderAsXML($property_list, $reply); if ($depth > 0) { $responses = array_merge($responses, get_collection_contents($depth - 1, $resource, $binding->dav_name)); } } } } $sql = 'SELECT principal.*, collection.*, \'collection\' AS type '; $sql .= 'FROM collection LEFT JOIN principal USING (user_no) '; $sql .= 'WHERE parent_container = :this_dav_name '; $sql .= ' ORDER BY collection_id'; $params[':this_dav_name'] = $bound_from; unset($params[':session_principal']); unset($params[':scan_depth']); } $qry = new AwlQuery($sql, $params); if ($qry->Exec('PROPFIND', __LINE__, __FILE__) && $qry->rows() > 0) { while ($subcollection = $qry->Fetch()) { $resource = new DAVResource($subcollection); if (!$resource->HavePrivilegeTo('DAV::read')) { continue; } $resource->set_bind_location(str_replace($bound_from, $bound_to, $subcollection->dav_name)); $responses[] = $resource->RenderAsXML($property_list, $reply); if ($depth > 0) { $responses = array_merge($responses, get_collection_contents($depth - 1, $resource, str_replace($resource->parent_path(), $parent_path, $resource->dav_name()))); } } } if ((!isset($c->disable_caldav_proxy) || $c->disable_caldav_proxy == false) && $collection->IsPrincipal()) { // Caldav Proxy: 5.1 par. 2: Add child resources calendar-proxy-(read|write) dbg_error_log('PROPFIND', 'Adding calendar-proxy-read and write. Path: %s', $bound_from); $response = add_proxy_response('read', $bound_from); if (isset($response)) { $responses[] = $response; } $response = add_proxy_response('write', $bound_from); if (isset($response)) { $responses[] = $response; } } } /** * freebusy permission is not allowed to see the items in a collection. Must have at least read permission. */ if ($collection->HavePrivilegeTo('DAV::read', false)) { dbg_error_log('PROPFIND', 'Getting collection items: Depth %d, Path: %s', $depth, $bound_from); $privacy_clause = ' '; $todo_clause = ' '; $time_limit_clause = ' '; if ($collection->IsCalendar()) { if (!$collection->HavePrivilegeTo('all', false)) { $privacy_clause = " AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL) "; } if (isset($c->hide_TODO) && ($c->hide_TODO === true || is_string($c->hide_TODO) && preg_match($c->hide_TODO, $_SERVER['HTTP_USER_AGENT'])) && !$collection->HavePrivilegeTo('all')) { $todo_clause = " AND caldav_data.caldav_type NOT IN ('VTODO') "; } if (isset($c->hide_older_than) && intval($c->hide_older_than > 0)) { $time_limit_clause = " AND (CASE WHEN caldav_data.caldav_type<>'VEVENT' OR calendar_item.dtstart IS NULL THEN true ELSE calendar_item.dtstart > (now() - interval '" . intval($c->hide_older_than) . " days') END) "; } } $sql = 'SELECT collection.*, principal.*, calendar_item.*, caldav_data.*, '; $sql .= "to_char(coalesce(calendar_item.created, caldav_data.created) at time zone 'GMT',{$date_format}) AS created, "; $sql .= "to_char(coalesce(calendar_item.last_modified, caldav_data.modified) at time zone 'GMT',{$date_format}) AS modified, "; $sql .= 'summary AS dav_displayname '; $sql .= 'FROM caldav_data LEFT JOIN calendar_item USING( dav_id, user_no, dav_name, collection_id) '; $sql .= 'LEFT JOIN collection USING(collection_id,user_no) LEFT JOIN principal USING(user_no) '; $sql .= 'WHERE collection.dav_name = :collection_dav_name ' . $time_limit_clause . ' ' . $todo_clause . ' ' . $privacy_clause; if (isset($c->strict_result_ordering) && $c->strict_result_ordering) { $sql .= " ORDER BY caldav_data.dav_id"; } $qry = new AwlQuery($sql, array(':collection_dav_name' => $bound_from)); if ($qry->Exec('PROPFIND', __LINE__, __FILE__) && $qry->rows() > 0) { while ($item = $qry->Fetch()) { if ($bound_from != $bound_to) { $item->bound_from = $item->dav_name; $item->dav_name = str_replace($bound_from, $bound_to, $item->dav_name); } $resource = new DAVResource($item); $responses[] = $resource->RenderAsXML($property_list, $reply, $parent_path); } } } return $responses; }
} if (!$request->PreferMinimal() && count($unsupported) > 0) { $status = new XMLElement("status", "HTTP/1.1 404 Not Found"); $noprop = new XMLElement("prop"); foreach ($unsupported as $k => $v) { $reply->NSElement($noprop, $v); } $elements[] = new XMLElement("propstat", array($noprop, $status)); } } $response = new XMLElement("response", $elements); return $response; } if ($target->IsExternal()) { require_once "external-fetch.php"; update_external($target); } // These reports are always allowed to see the resource_data because they are special $c->sync_resource_data_ok = true; if ($xmltree->GetNSTag() == "urn:ietf:params:xml:ns:caldav:calendar-query") { $calquery = $xmltree->GetPath("/urn:ietf:params:xml:ns:caldav:calendar-query/*"); include "caldav-REPORT-calquery.php"; } elseif ($xmltree->GetNSTag() == "urn:ietf:params:xml:ns:caldav:calendar-multiget") { $mode = 'caldav'; $qry_content = $xmltree->GetContent('urn:ietf:params:xml:ns:caldav:calendar-multiget'); include "caldav-REPORT-multiget.php"; } elseif ($xmltree->GetNSTag() == "urn:ietf:params:xml:ns:carddav:addressbook-multiget") { $mode = 'carddav'; $qry_content = $xmltree->GetContent('urn:ietf:params:xml:ns:carddav:addressbook-multiget'); include "caldav-REPORT-multiget.php"; } elseif ($xmltree->GetNSTag() == "urn:ietf:params:xml:ns:carddav:addressbook-query") {