示例#1
0
 /**
  * Send a need-privileges error response.  This function will only return
  * if the $href is not supplied and the current user has the specified
  * permission for the request path.
  *
  * @param string $privilege The name of the needed privilege.
  * @param string $href The unconstructed URI where we needed the privilege.
  */
 function NeedPrivilege($privileges, $href = null)
 {
     if (is_string($privileges)) {
         $privileges = array($privileges);
     }
     if (!isset($href)) {
         if ($this->HavePrivilegeTo($privileges)) {
             return;
         }
         $href = $this->path;
     }
     $reply = new XMLDocument(array('DAV:' => ''));
     $privnodes = array($reply->href(ConstructURL($href)), new XMLElement('privilege'));
     // RFC3744 specifies that we can only respond with one needed privilege, so we pick the first.
     $reply->NSElement($privnodes[1], $privileges[0]);
     $xml = new XMLElement('need-privileges', new XMLElement('resource', $privnodes));
     $xmldoc = $reply->Render('error', $xml);
     $this->DoResponse(403, $xmldoc, 'text/xml; charset="utf-8"');
     exit(0);
     // Unecessary, but might clarify things
 }
示例#2
0
    foreach ($dav as $v) {
        header('DAV: ' . trim($v, ', '), false);
    }
}
require_once 'CalDAVRequest.php';
$request = new CalDAVRequest();
//if ( $request->method == 'OPTIONS' || $c->always_send_dav_header )
send_dav_header();
// Avoid polluting global namespace
$allowed = implode(', ', array_keys($request->supported_methods));
// header( 'Allow: '.$allowed);
if (!($request->IsPrincipal() || isset($request->collection) || $request->method == 'PUT' || $request->method == 'MKCALENDAR' || $request->method == 'MKCOL')) {
    if (preg_match('#^/principals/users(/.*/)$#', $request->path, $matches)) {
        // Although this doesn't work with the iPhone, perhaps it will with iCal...
        /** @todo integrate handling this URL into CalDAVRequest.php */
        $redirect_url = ConstructURL('/caldav.php' . $matches[1]);
        dbg_error_log('LOG WARNING', 'Redirecting %s for "%s" to "%s"', $request->method, $request->path, $redirect_url);
        header('Location: ' . $redirect_url);
        @ob_flush();
        exit(0);
    }
}
param_to_global('add_member', '.*');
$add_member = isset($add_member);
switch ($request->method) {
    case 'OPTIONS':
        include_once 'caldav-OPTIONS.php';
        break;
    case 'REPORT':
        include_once 'caldav-REPORT.php';
        break;
                    }
                }
                /** Else:
                 *    the object existed at start and we have multiple modifications,
                 *  or,
                 *    the object didn't exist at start and we have subsequent modifications,
                 *  but:
                 *    in either case we simply stick with our existing report.
                 */
            } else {
                /** The simple case: this is the first one for this dav_id */
                if ($object->sync_status == 404) {
                    $resultset = array(new XMLElement('href', ConstructURL($object->dav_name)), new XMLElement('status', display_status($object->sync_status)));
                    $first_status = 404;
                } else {
                    $dav_resource = new DAVResource($object);
                    $resultset = $dav_resource->GetPropStat($proplist, $reply);
                    array_unshift($resultset, new XMLElement('href', ConstructURL($object->dav_name)));
                    $first_status = $object->sync_status;
                }
                $responses[] = new XMLElement('response', $resultset);
                $last_dav_name = $object->dav_name;
            }
        }
        $responses[] = new XMLElement('sync-token', 'data:,' . $new_token);
    } else {
        $request->DoResponse(500, translate("Database error"));
    }
}
$multistatus = new XMLElement("multistatus", $responses, $reply->GetXmlNsArray());
$request->XMLResponse(207, $multistatus);
示例#4
0
switch ($request->path) {
    case '/.well-known/caldav':
    case '/.well-known/carddav':
        header('Location: ' . $c->protocol_server_port . ConstructURL('/', true));
        $request->DoResponse(301);
        // Moved permanently
        // does not return.
    // Moved permanently
    // does not return.
    case '/.well-known/timezone':
        $parameters = '';
        foreach ($_GET as $k => $v) {
            $parameters .= $parameters == '' ? '?' : '&';
            $parameters .= $k . '=' . rawurlencode($v);
        }
        header('Location: ' . $c->protocol_server_port . str_replace('/caldav.php', '', ConstructURL('/tz.php', true)) . $parameters);
        $request->DoResponse(301);
        // Moved permanently
        // does not return.
}
if ($c->enable_scheduling != true) {
    $request->DoResponse(404, translate('The application program does not understand that request.'));
    // Does not return
}
dbg_log_array('well-known', 'method:' . $request->method);
switch ($request->method) {
    case 'GET':
        ischedule_get();
        break;
    case 'POST':
        include 'iSchedule-POST.php';
示例#5
0
 /**
  * Return the privileges bits for the current session user to this resource
  */
 function Privileges()
 {
     global $session;
     if (!isset($this->privileges)) {
         $this->privileges = 0;
     }
     if (is_string($this->privileges)) {
         $this->privileges = bindec($this->privileges);
     }
     if ($this->_is_group && in_array(ConstructURL('/' . $session->username . '/'), $this->GroupMemberSet())) {
         $this->privileges |= privilege_to_bits(array('DAV::read', 'DAV::read-current-user-privilege-set'));
     }
     return $this->privileges;
 }
示例#6
0
/**
* Deconstruct a dav_name from the supplied URL.  The dav_name will be urldecoded.
*
* @param string $partial_path  The part of the path after the script name
*/
function DeconstructURL($url, $force_script = false)
{
    global $c;
    $dav_name = rawurldecode($url);
    /** Allow a path like .../username/calendar.ics to translate into the calendar URL */
    if (preg_match('#^(/[^/]+/[^/]+).ics$#', $dav_name, $matches)) {
        $dav_name = $matches[1] . '/';
    }
    /** remove any leading protocol/server/port/prefix... */
    if (!isset($c->deconstruction_base_path)) {
        $c->deconstruction_base_path = ConstructURL('/');
    }
    if (preg_match('%^(.*?)' . str_replace('%', '\\%', $c->deconstruction_base_path) . '(.*)$%', $dav_name, $matches)) {
        if ($matches[1] == '' || $matches[1] == $c->protocol_server_port) {
            $dav_name = $matches[2];
        }
    }
    /** strip doubled slashes */
    if (strstr($dav_name, '//')) {
        $dav_name = preg_replace('#//+#', '/', $dav_name);
    }
    if (substr($dav_name, 0, 1) != '/') {
        $dav_name = '/' . $dav_name;
    }
    return $dav_name;
}
示例#7
0
    }
    /**
     * If we have encountered any instances of failure, the whole damn thing fails.
     */
    if (count($failure) > 0) {
        $props = array();
        $status = array();
        foreach ($success as $tag => $v) {
            // Unfortunately although these succeeded, we failed overall, so they didn't happen...
            $props[] = new XMLElement($reply->Tag($tag));
        }
        $status[] = new XMLElement('propstat', array(new XMLElement('prop', $props), new XMLElement('status', 'HTTP/1.1 424 Failed Dependency')));
        if ($request_type == 'extended-mkcol') {
            $request->DoResponse($failure_code, $reply->Render('mkcol-response', array_merge($status, $failure), 'text/xml; charset="utf-8"'));
        } else {
            array_unshift($failure, $reply->href(ConstructURL($request->path)));
            $failure[] = new XMLElement('responsedescription', translate('Some properties were not able to be set.'));
            $request->DoResponse(207, $reply->Render('multistatus', new XMLElement('response', $failure)), 'text/xml; charset="utf-8"');
        }
    }
}
$sql = 'SELECT * FROM collection WHERE dav_name = :dav_name';
$qry = new AwlQuery($sql, array(':dav_name' => $request->path));
if (!$qry->Exec('MKCOL', __LINE__, __FILE__)) {
    $request->DoResponse(500, translate('Error querying database.'));
}
if ($qry->rows() != 0) {
    $request->DoResponse(405, translate('A collection already exists at that location.'));
}
$qry = new AwlQuery();
$qry->Begin();
示例#8
0
 /**
  * Return the URL for this principal
  * @param string $type The type of URL we want (the principal, by default)
  * @param boolean $internal Whether an internal reference is requested
  * @return string The principal-URL
  */
 public function url($type = 'principal', $internal = false)
 {
     global $c;
     if ($internal) {
         $result = $this->dav_name();
     } else {
         if (isset($this->original_request_url) && $type == 'principal') {
             $result = $this->original_request_url;
         } else {
             $result = $this->url;
         }
     }
     switch ($type) {
         case 'principal':
             break;
         case 'schedule-default-calendar':
             $result = $this->default_calendar();
             break;
         case 'schedule-inbox':
             $result .= '.in/';
             break;
         case 'schedule-outbox':
             $result .= '.out/';
             break;
         case 'dropbox':
             $result .= '.drop/';
             break;
         case 'notifications':
             $result .= '.notify/';
             break;
         default:
             fatal('Unknown internal URL type "' . $type . '"');
     }
     return ConstructURL(DeconstructURL($result));
 }
示例#9
0
function caldav_get_feed($request, $collection)
{
    global $c, $session;
    dbg_error_log("feed", "GET method handler");
    $collection->NeedPrivilege(array('DAV::read'));
    if (!$collection->Exists()) {
        $request->DoResponse(404, translate("Resource Not Found."));
    }
    if (!$collection->IsCollection() || !$collection->IsCalendar() && !(isset($c->get_includes_subcollections) && $c->get_includes_subcollections)) {
        $request->DoResponse(405, translate("Feeds are only supported for calendars at present."));
    }
    // Try and pull the answer out of a hat
    $cache = getCacheInstance();
    $cache_ns = 'collection-' . $collection->dav_name();
    $cache_key = 'feed' . $session->user_no;
    $response = $cache->get($cache_ns, $cache_key);
    if ($response !== false) {
        return $response;
    }
    $principal = $collection->GetProperty('principal');
    /**
     * 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.
     */
    $sql = 'SELECT caldav_data, caldav_type, caldav_data.user_no, caldav_data.dav_name,';
    $sql .= ' caldav_data.modified, caldav_data.created, ';
    $sql .= ' summary, dtstart, dtend, calendar_item.description ';
    $sql .= ' FROM collection INNER JOIN caldav_data USING(collection_id) INNER JOIN calendar_item USING ( dav_id ) WHERE ';
    if (isset($c->get_includes_subcollections) && $c->get_includes_subcollections) {
        $sql .= ' (collection.dav_name ~ :path_match ';
        $sql .= ' OR collection.collection_id IN (SELECT bound_source_id FROM dav_binding WHERE dav_binding.dav_name ~ :path_match)) ';
        $params = array(':path_match' => '^' . $request->path);
    } else {
        $sql .= ' caldav_data.collection_id = :collection_id ';
        $params = array(':collection_id' => $collection->resource_id());
    }
    $sql .= ' ORDER BY caldav_data.created DESC';
    $sql .= ' LIMIT ' . (isset($c->feed_item_limit) ? $c->feed_item_limit : 15);
    $qry = new AwlQuery($sql, $params);
    if (!$qry->Exec("GET", __LINE__, __FILE__)) {
        $request->DoResponse(500, translate("Database Error"));
    }
    /**
     * Here we are constructing the feed response for this collection, including
     * the timezones that are referred to by the events we have selected.
     * Library used: http://framework.zend.com/manual/en/zend.feed.writer.html
     */
    require_once 'AtomFeed.php';
    $feed = new AtomFeed();
    $feed->setTitle('DAViCal Atom Feed: ' . $collection->GetProperty('displayname'));
    $url = $c->protocol_server_port . $collection->url();
    $url = preg_replace('{/$}', '.ics', $url);
    $feed->setLink($url);
    $feed->setFeedLink($c->protocol_server_port_script . $request->path, 'atom');
    $feed->addAuthor(array('name' => $principal->GetProperty('displayname'), 'email' => $principal->GetProperty('email'), 'uri' => $c->protocol_server_port . $principal->url()));
    $feed_description = $collection->GetProperty('description');
    if (isset($feed_description) && $feed_description != '') {
        $feed->setDescription($feed_description);
    }
    require_once 'RRule-v2.php';
    $need_zones = array();
    $timezones = array();
    while ($event = $qry->Fetch()) {
        if ($event->caldav_type != 'VEVENT' && $event->caldav_type != 'VTODO' && $event->caldav_type != 'VJOURNAL') {
            dbg_error_log('feed', 'Skipping peculiar "%s" component in VCALENDAR', $event->caldav_type);
            continue;
        }
        $is_todo = $event->caldav_type == 'VTODO';
        $ical = new vComponent($event->caldav_data);
        $event_data = $ical->GetComponents('VTIMEZONE', false);
        $item = $feed->createEntry();
        $item->setId($c->protocol_server_port_script . ConstructURL($event->dav_name));
        $dt_created = new RepeatRuleDateTime($event->created);
        $item->setDateCreated($dt_created->epoch());
        $dt_modified = new RepeatRuleDateTime($event->modified);
        $item->setDateModified($dt_modified->epoch());
        $summary = $event->summary;
        $p_title = $summary != '' ? $summary : translate('No summary');
        if ($is_todo) {
            $p_title = "TODO: " . $p_title;
        }
        $item->setTitle($p_title);
        $content = "";
        $dt_start = new RepeatRuleDateTime($event->dtstart);
        if ($dt_start != null) {
            $p_time = '<strong>' . translate('Time') . ':</strong> ' . strftime(translate('%F %T'), $dt_start->epoch());
            $dt_end = new RepeatRuleDateTime($event->dtend);
            if ($dt_end != null) {
                $p_time .= ' - ' . ($dt_end->AsDate() == $dt_start->AsDate() ? strftime(translate('%T'), $dt_end->epoch()) : strftime(translate('%F %T'), $dt_end->epoch()));
            }
            $content .= $p_time;
        }
        $p_location = $event_data[0]->GetProperty('LOCATION');
        if ($p_location != null) {
            $content .= '<br />' . '<strong>' . translate('Location') . '</strong>: ' . hyperlink($p_location->Value());
        }
        $p_attach = $event_data[0]->GetProperty('ATTACH');
        if ($p_attach != null) {
            $content .= '<br />' . '<strong>' . translate('Attachment') . '</strong>: ' . hyperlink($p_attach->Value());
        }
        $p_url = $event_data[0]->GetProperty('URL');
        if ($p_url != null) {
            $content .= '<br />' . '<strong>' . translate('URL') . '</strong>: ' . hyperlink($p_url->Value());
        }
        $p_cat = $event_data[0]->GetProperty('CATEGORIES');
        if ($p_cat != null) {
            $content .= '<br />' . '<strong>' . translate('Categories') . '</strong>: ' . $p_cat->Value();
            $categories = explode(',', $p_cat->Value());
            foreach ($categories as $category) {
                $item->addCategory(array('term' => trim($category)));
            }
        }
        $p_description = $event->description;
        if ($p_description != '') {
            $content .= '<br />' . '<br />' . '<strong>' . translate('Description') . '</strong>:<br />' . nl2br(hyperlink($p_description));
            $item->setDescription($p_description);
        }
        $item->setContent($content);
        $feed->addEntry($item);
        //break;
    }
    $last_modified = new RepeatRuleDateTime($collection->GetProperty('modified'));
    $feed->setDateModified($last_modified->epoch());
    $response = $feed->export('atom');
    $cache->set($cache_ns, $cache_key, $response);
    return $response;
}
示例#10
0
}
/**
* If we have encountered any instances of failure, the whole damn thing fails.
*/
if (count($failure) > 0) {
    foreach ($success as $tag => $v) {
        // Unfortunately although these succeeded, we failed overall, so they didn't happen...
        $failure[] = new XMLElement('propstat', array(new XMLElement('prop', new XMLElement($tag)), new XMLElement('status', 'HTTP/1.1 424 Failed Dependency')));
    }
    $url = ConstructURL($request->path);
    array_unshift($failure, new XMLElement('href', $url));
    $failure[] = new XMLElement('responsedescription', translate("Some properties were not able to be changed."));
    $qry->Rollback();
    $multistatus = new XMLElement("multistatus", new XMLElement('response', $failure), array('xmlns' => 'DAV:'));
    $request->DoResponse(207, $multistatus->Render(0, '<?xml version="1.0" encoding="utf-8" ?>'), 'text/xml; charset="utf-8"');
}
/**
* Otherwise we will try and do the SQL. This is inside a transaction, so PostgreSQL guarantees the atomicity
*/
if ($qry->Commit()) {
    $url = ConstructURL($request->path);
    $href = new XMLElement('href', $url);
    $desc = new XMLElement('responsedescription', translate("All requested changes were made."));
    $multistatus = new XMLElement("multistatus", new XMLElement('response', array($href, $desc)), array('xmlns' => 'DAV:'));
    $request->DoResponse(200, $multistatus->Render(0, '<?xml version="1.0" encoding="utf-8" ?>'), 'text/xml; charset="utf-8"');
}
/**
* Or it was all crap.
*/
$request->DoResponse(500);
exit(0);
示例#11
0
 /**
  * Get the calendar_free_busy_set, as lazily as possible
  */
 function calendar_free_busy_set()
 {
     if (!isset($this->calendar_free_busy_set)) {
         /**
          * calendar-free-busy-set has been dropped from draft 5 of the scheduling extensions for CalDAV
          * in favour of ???
          */
         $this->calendar_free_busy_set = array();
         $qry = new AwlQuery('SELECT dav_name FROM collection WHERE is_calendar AND (schedule_transp = \'opaque\' OR schedule_transp IS NULL) AND dav_name ~ :dav_name_start ORDER BY user_no, collection_id', array(':dav_name_start' => '^' . $this->dav_name));
         if ($qry->Exec('principal', __LINE__, __FILE__)) {
             while ($calendar = $qry->Fetch()) {
                 $this->calendar_free_busy_set[] = ConstructURL($calendar->dav_name, true);
             }
         }
     }
     return $this->calendar_free_busy_set;
 }
示例#12
0
 /**
  * Render XML for this resource
  *
  * @param array $properties The requested properties for this principal
  * @param reference $reply A reference to the XMLDocument being used for the reply
  *
  * @return string An XML fragment with the requested properties for this principal
  */
 function RenderAsXML($properties, &$reply, $bound_parent_path = null)
 {
     global $session, $c, $request;
     dbg_error_log('DAVResource', ':RenderAsXML: Resource "%s" exists(%d)', $this->dav_name, $this->Exists());
     if (!$this->Exists()) {
         return null;
     }
     $elements = $this->GetPropStat($properties, $reply);
     if (isset($bound_parent_path)) {
         $dav_name = str_replace($this->parent_path(), $bound_parent_path, $this->dav_name);
     } else {
         $dav_name = $this->dav_name;
     }
     array_unshift($elements, $reply->href(ConstructURL($dav_name)));
     $response = new XMLElement('response', $elements, null, 'DAV:');
     return $response;
 }
示例#13
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');
}
示例#14
0
/**
* Return XML for a single component from the DB
*
* @param array $properties The properties for this component
* @param string $item The DB row data for this component
*
* @return string An XML document which is the response for the component
*/
function component_to_xml($properties, $item)
{
    global $session, $c, $request, $reply;
    dbg_error_log("REPORT", "Building XML Response for item '%s'", $item->dav_name);
    $denied = array();
    $unsupported = array();
    $caldav_data = $item->caldav_data;
    $displayname = preg_replace('{^.*/}', '', $item->dav_name);
    $type = 'unknown';
    $contenttype = 'text/plain';
    switch ($item->caldav_type) {
        case 'VJOURNAL':
        case 'VEVENT':
        case 'VTODO':
            $displayname = $item->summary;
            $type = 'calendar';
            $contenttype = 'text/calendar';
            break;
        case 'VCARD':
            $displayname = $item->fn;
            $type = 'vcard';
            $contenttype = 'text/vcard';
            break;
    }
    if (isset($properties['calendar-data']) || isset($properties['displayname'])) {
        if (!$request->AllowedTo('all') && $session->user_no != $item->user_no) {
            // the user is not admin / owner of this calendarlooking at his calendar and can not admin the other cal
            /** @todo We should examine the ORGANIZER and ATTENDEE fields in the event.  If this person is there then they should see this */
            if ($type == 'calendar' && $item->class == 'CONFIDENTIAL' || !$request->AllowedTo('read')) {
                $ical = new iCalComponent($caldav_data);
                $resources = $ical->GetComponents('VTIMEZONE', false);
                $first = $resources[0];
                // if the event is confidential we fake one that just says "Busy"
                $confidential = new iCalComponent();
                $confidential->SetType($first->GetType());
                $confidential->AddProperty('SUMMARY', translate('Busy'));
                $confidential->AddProperty('CLASS', 'CONFIDENTIAL');
                $confidential->SetProperties($first->GetProperties('DTSTART'), 'DTSTART');
                $confidential->SetProperties($first->GetProperties('RRULE'), 'RRULE');
                $confidential->SetProperties($first->GetProperties('DURATION'), 'DURATION');
                $confidential->SetProperties($first->GetProperties('DTEND'), 'DTEND');
                $confidential->SetProperties($first->GetProperties('UID'), 'UID');
                $ical->SetComponents(array($confidential), $confidential->GetType());
                $caldav_data = $ical->Render();
                $displayname = translate('Busy');
            }
        }
    }
    $url = ConstructURL($item->dav_name);
    $prop = new XMLElement("prop");
    foreach ($properties as $k => $v) {
        switch ($k) {
            case 'getcontentlength':
                $contentlength = strlen($caldav_data);
                $prop->NewElement($k, $contentlength);
                break;
            case 'getlastmodified':
                $prop->NewElement($k, ISODateToHTTPDate($item->modified));
                break;
            case 'calendar-data':
                if ($type == 'calendar') {
                    $reply->CalDAVElement($prop, $k, $caldav_data);
                } else {
                    $unsupported[] = $k;
                }
                break;
            case 'address-data':
                if ($type == 'vcard') {
                    $reply->CardDAVElement($prop, $k, $caldav_data);
                } else {
                    $unsupported[] = $k;
                }
                break;
            case 'getcontenttype':
                $prop->NewElement($k, $contenttype);
                break;
            case 'current-user-principal':
                $prop->NewElement("current-user-principal", $request->current_user_principal_xml);
                break;
            case 'displayname':
                $prop->NewElement($k, $displayname);
                break;
            case 'resourcetype':
                $prop->NewElement($k);
                // Just an empty resourcetype for a non-collection.
                break;
            case 'getetag':
                $prop->NewElement($k, '"' . $item->dav_etag . '"');
                break;
            case '"current-user-privilege-set"':
                $prop->NewElement($k, privileges($request->permissions));
                break;
            case 'SOME-DENIED-PROPERTY':
                /** indicating the style for future expansion */
                $denied[] = $k;
                break;
            default:
                dbg_error_log('REPORT', "Request for unsupported property '%s' of calendar item.", $v);
                $unsupported[] = $k;
        }
    }
    $status = new XMLElement("status", "HTTP/1.1 200 OK");
    $propstat = new XMLElement("propstat", array($prop, $status));
    $href = new XMLElement("href", $url);
    $elements = array($href, $propstat);
    if (count($denied) > 0) {
        $status = new XMLElement("status", "HTTP/1.1 403 Forbidden");
        $noprop = new XMLElement("prop");
        foreach ($denied as $k => $v) {
            $noprop->NewElement(strtolower($v));
        }
        $elements[] = new XMLElement("propstat", array($noprop, $status));
    }
    if (count($unsupported) > 0) {
        $status = new XMLElement("status", "HTTP/1.1 404 Not Found");
        $noprop = new XMLElement("prop");
        foreach ($unsupported as $k => $v) {
            $noprop->NewElement(strtolower($v));
        }
        $elements[] = new XMLElement("propstat", array($noprop, $status));
    }
    $response = new XMLElement("response", $elements);
    return $response;
}
示例#15
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'));
    }
}
示例#16
0
            }
            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);
$request->XMLResponse(200, $prop);
示例#17
0
/**
* Return XML for a single component from the DB
*
* @param array $properties The properties for this component
* @param string $item The DB row data for this component
*
* @return string An XML document which is the response for the component
*/
function component_to_xml($properties, $item)
{
    global $session, $c, $request, $reply;
    dbg_error_log("REPORT", "Building XML Response for item '%s'", $item->dav_name);
    $denied = array();
    $unsupported = array();
    $caldav_data = $item->caldav_data;
    $displayname = preg_replace('{^.*/}', '', $item->dav_name);
    $type = 'unknown';
    $contenttype = 'text/plain';
    switch (strtoupper($item->caldav_type)) {
        case 'VJOURNAL':
        case 'VEVENT':
        case 'VTODO':
            $displayname = $item->summary;
            $type = 'calendar';
            $contenttype = 'text/calendar';
            if (isset($properties['urn:ietf:params:xml:ns:caldav:calendar-data']) || isset($properties['DAV::displayname'])) {
                if (!$request->AllowedTo('all') && $session->user_no != $item->user_no) {
                    // the user is not admin / owner of this calendar looking at his calendar and can not admin the other cal
                    if ($item->class == 'CONFIDENTIAL' || !$request->AllowedTo('read')) {
                        dbg_error_log("REPORT", "Anonymising confidential event for: %s", $item->dav_name);
                        $vcal = new vCalendar($caldav_data);
                        $caldav_data = $vcal->Confidential()->Render();
                        $displayname = translate('Busy');
                    }
                }
            }
            if (isset($c->hide_alarm) && $c->hide_alarm) {
                $dav_resource = new DAVResource($item->dav_name);
                if (isset($properties['urn:ietf:params:xml:ns:caldav:calendar-data']) && !$dav_resource->HavePrivilegeTo('write')) {
                    dbg_error_log("REPORT", "Stripping event alarms for: %s", $item->dav_name);
                    $vcal = new vCalendar($caldav_data);
                    $vcal->ClearComponents('VALARM');
                    $caldav_data = $vcal->Render();
                }
            }
            break;
        case 'VCARD':
            $displayname = $item->fn;
            $type = 'vcard';
            $contenttype = 'text/vcard';
            break;
    }
    $url = ConstructURL($item->dav_name);
    $prop = new XMLElement("prop");
    $need_resource = false;
    foreach ($properties as $full_tag => $v) {
        $base_tag = preg_replace('{^.*:}', '', $full_tag);
        switch ($full_tag) {
            case 'DAV::getcontentlength':
                $contentlength = strlen($caldav_data);
                $prop->NewElement($base_tag, $contentlength);
                break;
            case 'DAV::getlastmodified':
                $prop->NewElement($base_tag, ISODateToHTTPDate($item->modified));
                break;
            case 'urn:ietf:params:xml:ns:caldav:calendar-data':
                if ($type == 'calendar') {
                    $reply->CalDAVElement($prop, $base_tag, $caldav_data);
                } else {
                    $unsupported[] = $base_tag;
                }
                break;
            case 'urn:ietf:params:xml:ns:carddav:address-data':
                if ($type == 'vcard') {
                    $reply->CardDAVElement($prop, $base_tag, $caldav_data);
                } else {
                    $unsupported[] = $base_tag;
                }
                break;
            case 'DAV::getcontenttype':
                $prop->NewElement($base_tag, $contenttype);
                break;
            case 'DAV::current-user-principal':
                $prop->NewElement("current-user-principal", $request->current_user_principal_xml);
                break;
            case 'DAV::displayname':
                $prop->NewElement($base_tag, $displayname);
                break;
            case 'DAV::resourcetype':
                $prop->NewElement($base_tag);
                // Just an empty resourcetype for a non-collection.
                break;
            case 'DAV::getetag':
                $prop->NewElement($base_tag, '"' . $item->dav_etag . '"');
                break;
            case '"current-user-privilege-set"':
                $prop->NewElement($base_tag, privileges($request->permissions));
                break;
            default:
                // It's harder.  We need the DAVResource() to get this one.
                $need_resource = true;
        }
        if ($need_resource) {
            break;
        }
    }
    $href = new XMLElement("href", $url);
    if ($need_resource) {
        if (!isset($dav_resource)) {
            $dav_resource = new DAVResource($item->dav_name);
        }
        $elements = $dav_resource->GetPropStat(array_keys($properties), $reply);
        array_unshift($elements, $href);
    } else {
        $elements = array($href);
        $status = new XMLElement("status", "HTTP/1.1 200 OK");
        $elements[] = new XMLElement("propstat", array($prop, $status));
        if (count($denied) > 0) {
            $status = new XMLElement("status", "HTTP/1.1 403 Forbidden");
            $noprop = new XMLElement("prop");
            foreach ($denied as $k => $v) {
                $reply->NSElement($noprop, $v);
            }
            $elements[] = new XMLElement("propstat", array($noprop, $status));
        }
        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;
}