/** * Entry point for scheduling on DELETE, for which there are thee outcomes: * - We don't do scheduling (disabled, no organizer, ...) * - We are an ATTENDEE declining the meeting. * - We are the ORGANIZER canceling the meeting. * * @param DAVResource $deleted_resource The resource which has already been deleted */ function do_scheduling_for_delete(DAVResource $deleted_resource) { // By the time we arrive here the resource *has* actually been deleted from disk // we can only fail to (de-)schedule the activity... global $request, $c; if (!isset($request) || isset($c->enable_auto_schedule) && !$c->enable_auto_schedule) { return true; } if ($deleted_resource->IsInSchedulingCollection()) { return true; } $caldav_data = $deleted_resource->GetProperty('dav-data'); if (empty($caldav_data)) { return true; } $vcal = new vCalendar($caldav_data); $organizer = $vcal->GetOrganizer(); if ($organizer === false || empty($organizer)) { dbg_error_log('schedule', 'Event has no organizer - no scheduling required.'); return true; } if ($vcal->GetScheduleAgent() != 'SERVER') { dbg_error_log('schedule', 'SCHEDULE-AGENT=%s - no scheduling required.', $vcal->GetScheduleAgent()); return true; } $organizer_email = preg_replace('/^mailto:/i', '', $organizer->Value()); if ($request->principal->email() == $organizer_email) { return doItipOrganizerCancel($vcal); } else { if (isset($_SERVER['HTTP_SCHEDULE_REPLY']) && $_SERVER['HTTP_SCHEDULE_REPLY'] == 'F') { dbg_error_log('schedule', 'Schedule-Reply header set to "F" - no scheduling required.'); return true; } return doItipAttendeeReply($vcal, 'DECLINED', $request->principal->email()); } }
$ticket_privileges |= privilege_to_bits('schedule-query-freebusy'); } break; } } if ($ticket_timeout == 'infinity') { $sql_timeout = null; } else { if (preg_match('{^([a-z]+)-(\\d+)$}i', $ticket_timeout, $matches)) { /** It isn't specified, but timeout seems to be 'unit-number' like 'Seconds-3600', so we make it '3600 Seconds' which PostgreSQL understands */ $sql_timeout = $matches[2] . ' ' . $matches[1]; } else { $sql_timeout = $ticket_timeout; } } $collection_id = $target->GetProperty('collection_id'); $resource_id = $target->GetProperty('dav_id'); $i = 0; do { $ticket_id = substr(str_replace('/', '', str_replace('+', '', base64_encode(sha1(date('r') . rand(0, 2100000000) . microtime(true), true)))), 7, 8); $qry = new AwlQuery('INSERT INTO access_ticket ( ticket_id, dav_owner_id, privileges, target_collection_id, target_resource_id, expires ) VALUES( :ticket_id, :owner, :privs::INT::BIT(24), :collection, :resource, (current_timestamp + :expires::interval) )', array(':ticket_id' => $ticket_id, ':owner' => $session->principal_id, ':privs' => $ticket_privileges, ':collection' => $collection_id, ':resource' => $resource_id, ':expires' => $sql_timeout)); $result = $qry->Exec('MKTICKET', __LINE__, __FILE__); } while (!$result && $i++ < 2); $privs = new XMLElement('privilege'); foreach (bits_to_privilege($ticket_privileges) as $k => $v) { $reply->NSElement($privs, $v); } $ticketinfo = new XMLElement('T:ticketinfo', array(new XMLElement('T:id', $ticket_id), new XMLElement('owner', $reply->href(ConstructURL('/' . $session->username . '/'))), $privs, new XMLElement('T:timeout', $ticket_timeout), new XMLElement('T:visits', 'infinity'))); $prop = new XMLElement("prop", new XMLElement('T:ticketdiscovery', $ticketinfo), $reply->GetXmlNsArray()); header('Ticket: ' . $ticket_id);
$dav_resource = new DAVResource($request->path); if (!$dav_resource->HavePrivilegeTo('DAV::write-content')) { $request->DoResponse(403); } if (!$dav_resource->Exists() && !$dav_resource->HavePrivilegeTo('DAV::bind')) { $request->DoResponse(403); } if (!ini_get('open_basedir') && (isset($c->dbg['ALL']) || isset($c->dbg['put']) && $c->dbg['put'])) { $fh = fopen('/tmp/PUT.txt', 'w'); if ($fh) { fwrite($fh, $request->raw_post); fclose($fh); } } include_once 'caldav-PUT-functions.php'; controlRequestContainer($dav_resource->GetProperty('username'), $dav_resource->GetProperty('user_no'), $dav_resource->bound_from(), true); $lock_opener = $request->FailIfLocked(); if ($dav_resource->IsCollection()) { if ($dav_resource->IsPrincipal() || $dav_resource->IsBinding() || !isset($c->readonly_webdav_collections) || $c->readonly_webdav_collections == true) { $request->DoResponse(405); // Method not allowed return; } $appending = isset($_GET['mode']) && $_GET['mode'] == 'append'; /** * CalDAV does not define the result of a PUT on a collection. We treat that * as an import. The code is in caldav-PUT-functions.php */ import_collection($request->raw_post, $request->user_no, $request->path, true, $appending); $request->DoResponse(200); return;
$params = array(':collection_id' => $dav_resource->resource_id()); } if (isset($c->strict_result_ordering) && $c->strict_result_ordering) { $sql .= ' ORDER BY dav_id'; } $qry = new AwlQuery($sql, $params); if (!$qry->Exec("GET", __LINE__, __FILE__)) { $request->DoResponse(500, translate("Database Error")); } /** * Here we are constructing a whole calendar response for this collection, including * the timezones that are referred to by the events we have selected. */ $vcal = new iCalComponent(); $vcal->VCalendar(); $displayname = $dav_resource->GetProperty('displayname'); if (isset($displayname)) { $vcal->AddProperty("X-WR-CALNAME", $displayname); } $need_zones = array(); $timezones = array(); while ($event = $qry->Fetch()) { $ical = new iCalComponent($event->caldav_data); /** Save the timezone component(s) into a minimal set for inclusion later */ $event_zones = $ical->GetComponents('VTIMEZONE', true); foreach ($event_zones as $k => $tz) { $tzid = $tz->GetPValue('TZID'); if (!isset($tzid)) { continue; } if ($tzid != '' && !isset($timezones[$tzid])) {
} $request->DoResponse(403, translate('PUT on a collection is only allowed for text/calendar content against a calendar collection')); } $dest->NeedPrivilege('DAV::write-content'); } if (isset($request->etag_none_match) && $request->etag_none_match != '*' && $dest->Exists()) { $request->PreconditionFailed(412, 'if-none-match', translate('A resource already exists at the destination.')); } if (isset($request->etag_if_match) && $request->etag_if_match != $dest->unique_tag()) { $request->PreconditionFailed(412, 'if-match', sprintf('Existing resource ETag of "%s" does not match "%s"', $dest->unique_tag(), $request->etag_if_match)); } $collection_id = $container->GetProperty('collection_id'); $qry = new AwlQuery(); $qry->Begin(); $etag = md5($request->raw_post); $params = array(':user_no' => $dest->GetProperty('user_no'), ':dav_name' => $dest->bound_from(), ':etag' => $etag, ':dav_data' => $request->raw_post, ':session_user' => $session->user_no); if ($dest->Exists()) { $sql = 'UPDATE caldav_data SET caldav_data=:dav_data, dav_etag=:etag, logged_user=:session_user, modified=current_timestamp, user_no=:user_no, caldav_type=\'VCARD\' WHERE dav_name=:dav_name'; $response_code = 200; $qry->QDo($sql, $params); $qry->QDo("SELECT dav_id FROM caldav_data WHERE dav_name = :dav_name ", array(':dav_name' => $params[':dav_name'])); } else { $sql = 'INSERT INTO caldav_data ( user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user, created, modified, collection_id ) VALUES( :user_no, :dav_name, :etag, :dav_data, \'VCARD\', :session_user, current_timestamp, current_timestamp, :collection_id )'; $params[':collection_id'] = $collection_id; $response_code = 201; $qry->QDo($sql, $params); $qry->QDo("SELECT currval('dav_id_seq') AS dav_id"); } $row = $qry->Fetch();
foreach ($props as $k => $v) { $proplist[] = $v->GetNSTag(); } } function display_status($status_code) { return sprintf('HTTP/1.1 %03d %s', intval($status_code), getStatusMessage($status_code)); } $collection = new DAVResource($request->path); if (!$collection->Exists()) { $request->DoResponse(404); } $bound_from = $collection->bound_from(); $collection_path = $collection->dav_name(); $request_via_binding = $bound_from != $collection_path; $params = array(':collection_id' => $collection->GetProperty('collection_id'), ':sync_token' => $sync_token); $sql = "SELECT new_sync_token( :sync_token, :collection_id)"; $qry = new AwlQuery($sql, $params); if (!$qry->Exec("REPORT", __LINE__, __FILE__) || $qry->rows() <= 0) { $request->DoResponse(500, translate("Database error")); } $row = $qry->Fetch(); if (!isset($row->new_sync_token)) { /** If we got a null back then they gave us a sync token we know not of, so provide a full sync */ $sync_token = 0; $params[':sync_token'] = $sync_token; if (!$qry->QDo($sql, $params) || $qry->rows() <= 0) { $request->DoResponse(500, translate("Database error")); } $row = $qry->Fetch(); }
function rollback($response_code = 412) { global $request; $qry = new AwlQuery('ROLLBACK'); $qry->Exec('move'); // Just in case $request->DoResponse($response_code); // And we don't return from that. } $qry = new AwlQuery('BEGIN'); if (!$qry->Exec('move')) { rollback(500); } $src_name = $src->dav_name(); $dst_name = $dest->IsBinding() ? $dest->bound_from() : $dest->dav_name(); $src_collection = $src->GetProperty('collection_id'); $dst_collection = $dest->GetProperty('collection_id'); $src_user_no = $src->GetProperty('user_no'); $dst_user_no = $dest->GetProperty('user_no'); $cache = getCacheInstance(); $cachekeys = array(); if ($src->IsCollection()) { $cachekeys[] = ($src->ContainerType() == 'principal' ? 'principal' : 'collection') . '-' . $src->parent_path(); $cachekeys[] = ($src->IsPrincipal() == 'principal' ? 'principal' : 'collection') . '-' . $src->dav_name(); $cachekeys[] = ($src->IsPrincipal() ? 'principal' : 'collection') . '-' . $dest->dav_name(); if ($dest->Exists()) { $qry = new AwlQuery('DELETE FROM collection WHERE dav_name = :dst_name', array(':dst_name' => $dst_name)); if (!$qry->Exec('move')) { rollback(500); } }
/** * Deliver scheduling requests to attendees * @param vComponent $ical the VCALENDAR to deliver */ function handle_schedule_request($ical) { global $c, $session, $request; $resources = $ical->GetComponents('VTIMEZONE', false); $ic = $resources[0]; $etag = md5($request->raw_post); $reply = new XMLDocument(array("DAV:" => "", "urn:ietf:params:xml:ns:caldav" => "C")); $responses = array(); $attendees = $ic->GetProperties('ATTENDEE'); $wr_attendees = $ic->GetProperties('X-WR-ATTENDEE'); if (count($wr_attendees) > 0) { dbg_error_log("PUT", "Non-compliant iCal request. Using X-WR-ATTENDEE property"); foreach ($wr_attendees as $k => $v) { $attendees[] = $v; } } dbg_error_log("PUT", "Attempting to deliver scheduling request for %d attendees", count($attendees)); foreach ($attendees as $k => $attendee) { $attendee_email = preg_replace('/^mailto:/', '', $attendee->Value()); if ($attendee_email == $request->principal->email()) { dbg_error_log("PUT", "not delivering to owner"); continue; } if ($attendee->GetParameterValue('PARTSTAT') != 'NEEDS-ACTION' || preg_match('/^[35]\\.[3-9]/', $attendee->GetParameterValue('SCHEDULE-STATUS'))) { dbg_error_log("PUT", "attendee %s does not need action", $attendee_email); continue; } if (isset($c->enable_auto_schedule) && !$c->enable_auto_schedule) { // In this case we're being asked not to do auto-scheduling, so we build // a response back for the client saying we can't... $attendee->SetParameterValue('SCHEDULE-STATUS', '5.3;No scheduling support for user'); continue; } dbg_error_log("PUT", "Delivering to %s", $attendee_email); $attendee_principal = new DAVPrincipal(array('email' => $attendee_email, 'options' => array('allow_by_email' => true))); if ($attendee_principal == false) { $attendee->SetParameterValue('SCHEDULE-STATUS', '5.3;No scheduling support for user'); continue; } $deliver_path = $attendee_principal->internal_url('schedule-inbox'); $ar = new DAVResource($deliver_path); $priv = $ar->HavePrivilegeTo('schedule-deliver-invite'); if (!$ar->HavePrivilegeTo('schedule-deliver-invite')) { $reply = new XMLDocument(array('DAV:' => '')); $privnodes = array($reply->href($attendee_principal->url('schedule_inbox')), new XMLElement('privilege')); // RFC3744 specifies that we can only respond with one needed privilege, so we pick the first. $reply->NSElement($privnodes[1], 'schedule-deliver-invite'); $xml = new XMLElement('need-privileges', new XMLElement('resource', $privnodes)); $xmldoc = $reply->Render('error', $xml); $request->DoResponse(403, $xmldoc, 'text/xml; charset="utf-8"'); } $attendee->SetParameterValue('SCHEDULE-STATUS', '1.2;Scheduling message has been delivered'); $ncal = new vCalendar(array('METHOD' => 'REQUEST')); $ncal->AddComponent(array_merge($ical->GetComponents('VEVENT', false), array($ic))); $content = $ncal->Render(); $cid = $ar->GetProperty('collection_id'); dbg_error_log('DELIVER', 'to user: %s, to path: %s, collection: %s, from user: %s, caldata %s', $attendee_principal->user_no(), $deliver_path, $cid, $request->user_no, $content); $item_etag = md5($content); write_resource(new DAVResource($deliver_path . $etag . '.ics'), $content, $ar, $request->user_no, $item_etag, $put_action_type = 'INSERT', $caldav_context = true, $log_action = true, $etag); $attendee->SetParameterValue('SCHEDULE-STATUS', '1.2;Scheduling message has been delivered'); } // don't write an entry in the out box, ical doesn't delete it or ever read it again $ncal = new vCalendar(array('METHOD' => 'REQUEST')); $ncal->AddComponent(array_merge($ical->GetComponents('VEVENT', false), array($ic))); $content = $ncal->Render(); $deliver_path = $request->principal->internal_url('schedule-inbox'); $ar = new DAVResource($deliver_path); $item_etag = md5($content); write_resource(new DAVResource($deliver_path . $etag . '.ics'), $content, $ar, $request->user_no, $item_etag, $put_action_type = 'INSERT', $caldav_context = true, $log_action = true, $etag); //$etag = md5($content); header('ETag: "' . $etag . '"'); header('Schedule-Tag: "' . $etag . '"'); $request->DoResponse(201, 'Created'); }
function export_iCalendar(DAVResource $dav_resource) { global $session, $c, $request; if (!$dav_resource->IsCalendar() && !(isset($c->get_includes_subcollections) && $c->get_includes_subcollections)) { /** RFC2616 says we must send an Allow header if we send a 405 */ header("Allow: PROPFIND,PROPPATCH,OPTIONS,MKCOL,REPORT,DELETE"); $request->DoResponse(405, translate("GET requests on collections are only supported for calendars.")); } /** * The CalDAV specification does not define GET on a collection, but typically this is * used as a .ics download for the whole collection, which is what we do also. */ if (isset($c->get_includes_subcollections) && $c->get_includes_subcollections) { $where = 'caldav_data.collection_id IN '; $where .= '(SELECT bound_source_id FROM dav_binding WHERE dav_binding.dav_name ~ :path_match '; $where .= 'UNION '; $where .= 'SELECT collection_id FROM collection WHERE collection.dav_name ~ :path_match) '; $params = array(':path_match' => '^' . $dav_resource->dav_name()); $distinct = 'DISTINCT ON (calendar_item.uid) '; } else { $where = 'caldav_data.collection_id = :collection_id '; $params = array(':collection_id' => $dav_resource->resource_id()); $distinct = ''; } $sql = 'SELECT ' . $distinct . ' caldav_data, class, caldav_type, calendar_item.user_no, logged_user '; $sql .= 'FROM collection INNER JOIN caldav_data USING(collection_id) '; $sql .= 'INNER JOIN calendar_item USING ( dav_id ) WHERE ' . $where; if (isset($c->strict_result_ordering) && $c->strict_result_ordering) { $sql .= ' ORDER BY calendar_item.uid, calendar_item.dav_id'; } $qry = new AwlQuery($sql, $params); if (!$qry->Exec("GET", __LINE__, __FILE__)) { $request->DoResponse(500, translate("Database Error")); } /** * Here we are constructing a whole calendar response for this collection, including * the timezones that are referred to by the events we have selected. */ $vcal = new iCalComponent(); $vcal->VCalendar(); $displayname = $dav_resource->GetProperty('displayname'); if (isset($displayname)) { $vcal->AddProperty("X-WR-CALNAME", $displayname); } if (!empty($c->auto_refresh_duration)) { $vcal->AddProperty("X-APPLE-AUTO-REFRESH-INTERVAL", $c->auto_refresh_duration); $vcal->AddProperty("AUTO-REFRESH", $c->auto_refresh_duration); $vcal->AddProperty("X-PUBLISHED-TTL", $c->auto_refresh_duration); } $need_zones = array(); $timezones = array(); while ($event = $qry->Fetch()) { $ical = new iCalComponent($event->caldav_data); /** Save the timezone component(s) into a minimal set for inclusion later */ $event_zones = $ical->GetComponents('VTIMEZONE', true); foreach ($event_zones as $k => $tz) { $tzid = $tz->GetPValue('TZID'); if (!isset($tzid)) { continue; } if ($tzid != '' && !isset($timezones[$tzid])) { $timezones[$tzid] = $tz; } } /** Work out which ones are actually used here */ $comps = $ical->GetComponents('VTIMEZONE', false); foreach ($comps as $k => $comp) { $tzid = $comp->GetPParamValue('DTSTART', 'TZID'); if (isset($tzid) && !isset($need_zones[$tzid])) { $need_zones[$tzid] = 1; } $tzid = $comp->GetPParamValue('DUE', 'TZID'); if (isset($tzid) && !isset($need_zones[$tzid])) { $need_zones[$tzid] = 1; } $tzid = $comp->GetPParamValue('DTEND', 'TZID'); if (isset($tzid) && !isset($need_zones[$tzid])) { $need_zones[$tzid] = 1; } if ($dav_resource->HavePrivilegeTo('all', false) || $session->user_no == $event->user_no || $session->user_no == $event->logged_user || isset($session->email) && $c->allow_get_email_visibility && $comp->IsAttendee($session->email)) { /** * These people get to see all of the event, and they should always * get any alarms as well. */ $vcal->AddComponent($comp); continue; } /** No visibility even of the existence of these events if they aren't admin/owner/attendee */ if ($event->class == 'PRIVATE') { continue; } if (!$dav_resource->HavePrivilegeTo('DAV::read') || $event->class == 'CONFIDENTIAL') { $vcal->AddComponent(obfuscated_event($comp)); } elseif (isset($c->hide_alarm) && $c->hide_alarm) { // Otherwise we hide the alarms (if configured to) $comp->ClearComponents('VALARM'); $vcal->AddComponent($comp); } else { $vcal->AddComponent($comp); } } } /** Put the timezones on there that we need */ foreach ($need_zones as $tzid => $v) { if (isset($timezones[$tzid])) { $vcal->AddComponent($timezones[$tzid]); } } return $vcal->Render(); }
if ($source->IsPrincipal() || !$source->IsCollection()) { $request->PreconditionFailed(403, 'DAV::binding-allowed', translate('DAViCal only allows BIND requests for collections at present.')); } if ($source->IsBinding()) { $source = new DAVResource($source->bound_from()); } /* bind_id INT8 DEFAULT nextval('dav_id_seq') PRIMARY KEY, bound_source_id INT8 REFERENCES collection(collection_id) ON UPDATE CASCADE ON DELETE CASCADE, access_ticket_id TEXT REFERENCES access_ticket(ticket_id) ON UPDATE CASCADE ON DELETE SET NULL, parent_container TEXT NOT NULL, dav_name TEXT UNIQUE NOT NULL, dav_displayname TEXT, external_url TEXT, type TEXT */ $sql = 'INSERT INTO dav_binding ( bound_source_id, access_ticket_id, dav_owner_id, parent_container, dav_name, dav_displayname ) VALUES( :target_id, :ticket_id, :session_principal, :parent_container, :dav_name, :displayname )'; $params = array(':target_id' => $source->GetProperty('collection_id'), ':ticket_id' => isset($request->ticket) ? $request->ticket->id() : null, ':parent_container' => $parent->dav_name(), ':session_principal' => $session->principal_id, ':dav_name' => $destination_path, ':displayname' => $source->GetProperty('displayname')); $qry = new AwlQuery($sql, $params); if ($qry->Exec('BIND', __LINE__, __FILE__)) { header('Location: ' . ConstructURL($destination_path)); // Uncache anything to do with the target $cache = getCacheInstance(); $cache_ns = 'collection-' . $destination_path; $cache->delete($cache_ns, null); $request->DoResponse(201); } else { $request->DoResponse(500, translate('Database Error')); } }
$dav_resource = new DAVResource($request->path); } if (!$dav_resource->HavePrivilegeTo('DAV::write-content')) { $request->DoResponse(403, 'No write permission'); } if (!$dav_resource->Exists() && !$dav_resource->HavePrivilegeTo('DAV::bind')) { $request->DoResponse(403, 'No bind permission.'); } if (!ini_get('open_basedir') && (isset($c->dbg['ALL']) || isset($c->dbg['put']) && $c->dbg['put'])) { $fh = fopen('/var/log/davical/PUT.debug', 'w'); if ($fh) { fwrite($fh, $request->raw_post); fclose($fh); } } controlRequestContainer($dav_resource->GetProperty('username'), $dav_resource->GetProperty('user_no'), $dav_resource->bound_from(), true); $lock_opener = $request->FailIfLocked(); if ($dav_resource->IsCollection()) { if ($dav_resource->IsPrincipal() || $dav_resource->IsBinding() || !isset($c->readonly_webdav_collections) || $c->readonly_webdav_collections == true) { $request->DoResponse(405); // Method not allowed return; } $appending = isset($_GET['mode']) && $_GET['mode'] == 'append'; /** * CalDAV does not define the result of a PUT on a collection. We treat that * as an import. The code is in caldav-PUT-functions.php */ import_collection($request->raw_post, $request->user_no, $request->path, true, $appending); $request->DoResponse(200); return;
/** * Deliver scheduling replies to organizer and other attendees * @param iCalComponent $ical the VCALENDAR to deliver * @return false on error */ function handle_schedule_reply($ical) { global $c, $session, $request; $resources = $ical->GetComponents('VTIMEZONE', false); $ic = $resources[0]; $etag = md5($request->raw_post); $organizer = $ic->GetProperties('ORGANIZER'); // for now we treat events with out organizers as an error if (count($organizer) < 1) { return false; } $attendees = array_merge($organizer, $ic->GetProperties('ATTENDEE')); $wr_attendees = $ic->GetProperties('X-WR-ATTENDEE'); if (count($wr_attendees) > 0) { dbg_error_log("POST", "Non-compliant iCal request. Using X-WR-ATTENDEE property"); foreach ($wr_attendees as $k => $v) { $attendees[] = $v; } } dbg_error_log("POST", "Attempting to deliver scheduling request for %d attendees", count($attendees)); foreach ($attendees as $k => $attendee) { $attendee_email = preg_replace('/^mailto:/', '', $attendee->Value()); dbg_error_log("POST", "Delivering to %s", $attendee_email); $attendee_principal = new CalDAVPrincipal(array('email' => $attendee_email, 'options' => array('allow_by_email' => true))); $deliver_path = preg_replace('/^.*caldav.php/', '', $attendee_principal->schedule_inbox_url); $attendee_email = preg_replace('/^mailto:/', '', $attendee->Value()); if ($attendee_email == $request->principal->email) { dbg_error_log("POST", "not delivering to owner"); continue; } $ar = new DAVResource($deliver_path); if (!$ar->HavePrivilegeTo('schedule-deliver-reply')) { $reply = new XMLDocument(array('DAV:' => '')); $privnodes = array($reply->href(ConstructURL($attendee_principal->schedule_inbox_url)), new XMLElement('privilege')); // RFC3744 specifies that we can only respond with one needed privilege, so we pick the first. $reply->NSElement($privnodes[1], 'schedule-deliver-reply'); $xml = new XMLElement('need-privileges', new XMLElement('resource', $privnodes)); $xmldoc = $reply->Render('error', $xml); $request->DoResponse(403, $xmldoc, 'text/xml; charset="utf-8"'); continue; } $ncal = new iCalComponent(); $ncal->VCalendar(); $ncal->AddProperty('METHOD', 'REPLY'); $ncal->AddComponent(array_merge($ical->GetComponents('VEVENT', false), array($ic))); $content = $ncal->Render(); write_resource($attendee_principal->user_no, $deliver_path . $etag . '.ics', $content, $ar->GetProperty('collection_id'), $request->user_no, md5($content), $ncal, $put_action_type = 'INSERT', $caldav_context = true, $log_action = true, $etag); } $request->DoResponse(201, 'Created'); }
$sql = 'UPDATE collection SET default_privileges=:privileges::INT::BIT(24) WHERE collection_id=:by_collection'; $sqlparms[':by_collection'] = $by_collection; } else { $sql = 'UPDATE principal SET default_privileges=:privileges::INT::BIT(24) WHERE principal_id=:by_principal'; $sqlparms[':by_principal'] = $by_principal; } $qry = new AwlQuery($sql, $sqlparms); if ($qry->Exec('ACL', __LINE__, __FILE__)) { /** * Basically this has changed everyone's permissions now, so... */ Principal::cacheFlush('TRUE'); } break; case 'DAV::all': // $principal_type = 'all'; $request->PreconditionFailed(403, 'allowed-principal', 'May not set privileges for unauthenticated users'); break; default: $request->PreconditionFailed(403, 'recognized-principal'); break; } } $by_principal = $grantor->IsPrincipal() ? $grantor->GetProperty('principal_id') : null; $by_collection = $grantor->IsPrincipal() ? null : $grantor->GetProperty('collection_id'); foreach ($aces as $k => $ace) { process_ace($grantor, $by_principal, $by_collection, $ace); } $qry = new AwlQuery('COMMIT'); $qry->Exec('ACL', __LINE__, __FILE__); $request->DoResponse(200);
if (!($dav_resource->resource_id() > 0)) { $request->DoResponse(403); } $qry = new AwlQuery(); $qry->Begin(); if ($dav_resource->IsBinding()) { $params = array(':dav_name' => $dav_resource->dav_name()); if ($qry->QDo("DELETE FROM dav_binding WHERE dav_name = :dav_name", $params) && $qry->Commit()) { @dbg_error_log("DELETE", "DELETE: Binding: %d, ETag: %s, Path: %s", $session->user_no, $request->etag_if_match, $request->path); $request->DoResponse(204); } } else { if ($dav_resource->IsCollection()) { if (delete_collection($dav_resource->resource_id()) && $qry->Commit()) { $request->DoResponse(204); } } else { if (isset($request->etag_if_match) && $request->etag_if_match != $dav_resource->unique_tag()) { $request->DoResponse(412, translate("Resource has changed on server - not deleted")); } $params = array(':dav_id' => $dav_resource->resource_id()); if ($qry->QDo("SELECT write_sync_change(collection_id, 404, caldav_data.dav_name) FROM caldav_data WHERE dav_id = :dav_id", $params) && $qry->QDo("DELETE FROM property WHERE dav_name = (SELECT dav_name FROM caldav_data WHERE dav_id = :dav_id)", $params) && $qry->QDo("DELETE FROM locks WHERE dav_name = (SELECT dav_name FROM caldav_data WHERE dav_id = :dav_id)", $params) && $qry->QDo("DELETE FROM caldav_data WHERE dav_id = :dav_id", $params) && $qry->Commit()) { @dbg_error_log("DELETE", "DELETE: User: %d, ETag: %s, Path: %s", $session->user_no, $request->etag_if_match, $request->path); if (function_exists('log_caldav_action')) { log_caldav_action('DELETE', $dav_resource->GetProperty('uid'), $dav_resource->GetProperty('user_no'), $dav_resource->GetProperty('collection_id'), $request->path); } $request->DoResponse(204); } } } $request->DoResponse(500);
} if (!$container->Exists()) { $request->PreconditionFailed(409, 'collection-must-exist', translate('The destination collection does not exist')); } $container->NeedPrivilege('DAV::bind'); } else { if ($dest->IsCollection()) { if (!isset($c->readonly_webdav_collections) || $c->readonly_webdav_collections) { $request->PreconditionFailed(405, 'method-not-allowed', translate('You may not PUT to a collection URL')); } $request->DoResponse(403, translate('PUT on a collection is only allowed for text/vcard content against an addressbook collection')); } $dest->NeedPrivilege('DAV::write-content'); } $request->CheckEtagMatch($dest->Exists(), $dest->unique_tag()); $user_no = $dest->GetProperty('user_no'); $collection_id = $container->GetProperty('collection_id'); $original_etag = md5($request->raw_post); $qry = new AwlQuery(); $qry->Begin(); $uid = $vcard->GetPValue('UID'); if (empty($uid)) { $uid = uuid(); $vcard->AddProperty('UID', $uid); } $last_modified = $vcard->GetPValue('REV'); if (empty($last_modified)) { $last_modified = gmdate('Ymd\\THis\\Z'); $vcard->AddProperty('REV', $last_modified); } elseif (stripos($last_modified, 'TZ')) { // At least one of my examples has this crap.
if (privilege_to_bits('all') != $privileges) { $request->PreconditionFailed(403, 'no-protected-ace-conflict', 'Owner must always have all permissions'); } continue; // and then we ignore it, since it's protected break; case 'DAV::unauthenticated': $request->PreconditionFailed(403, 'allowed-principal', 'May not set privileges for unauthenticated users'); break; case 'DAV::href': $principal_type = 'href'; $principal = new DAVResource(DeconstructURL($principal_content->GetContent())); if (!$principal->Exists() || !$principal->IsPrincipal()) { $request->PreconditionFailed(403, 'recognized-principal', 'Principal "' + $principal_content->GetContent() + '" not found.'); } $sqlparms = array(':to_principal' => $principal->GetProperty('principal_id')); $where = 'WHERE to_principal=:to_principal AND '; if (isset($by_principal)) { $sqlparms[':by_principal'] = $by_principal; $where .= 'by_principal = :by_principal'; } else { $sqlparms[':by_collection'] = $by_collection; $where .= 'by_collection = :by_collection'; } $qry = new AwlQuery('SELECT privileges FROM grants ' . $where, $sqlparms); if ($qry->Exec('ACL', __LINE__, __FILE__) && $qry->rows() == 1 && ($current = $qry->Fetch())) { $sql = 'UPDATE grants SET privileges=:privileges::INT::BIT(24) ' . $where; } else { $sqlparms[':by_principal'] = $by_principal; $sqlparms[':by_collection'] = $by_collection; $sql = 'INSERT INTO grants (by_principal, by_collection, to_principal, privileges) VALUES(:by_principal, :by_collection, :to_principal, :privileges::INT::BIT(24))';