Esempio n. 1
0
/**
 * 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());
    }
}
Esempio n. 2
0
                $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);
Esempio n. 3
0
$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;
Esempio n. 4
0
     $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])) {
Esempio n. 5
0
        }
        $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();
}
Esempio n. 7
0
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();
}
Esempio n. 10
0
    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'));
    }
}
Esempio n. 11
0
    $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;
Esempio n. 12
0
/**
* 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');
}
Esempio n. 13
0
                $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);
Esempio n. 14
0
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);
Esempio n. 15
0
    }
    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.
Esempio n. 16
0
     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))';