Beispiel #1
0
 /**
  * Initialise from a database row
  * @param object $row The row from the DB.
  */
 function FromRow($row)
 {
     global $c;
     if ($row == null) {
         return;
     }
     $this->exists = true;
     $this->dav_name = $row->dav_name;
     $this->bound_from = isset($row->bound_from) ? $row->bound_from : $row->dav_name;
     $this->_is_collection = preg_match('{/$}', $this->dav_name);
     if ($this->_is_collection) {
         $this->contenttype = 'httpd/unix-directory';
         $this->collection = (object) array();
         $this->resource_id = $row->collection_id;
         $this->_is_principal = preg_match('{^/[^/]+/$}', $this->dav_name);
         if (preg_match('#^(/principals/[^/]+/[^/]+)/?$#', $this->dav_name, $matches)) {
             $this->collection->dav_name = $matches[1] . '/';
             $this->collection->type = 'principal_link';
             $this->_is_principal = true;
         }
     } else {
         $this->resource = (object) array();
         if (isset($row->dav_id)) {
             $this->resource_id = $row->dav_id;
         }
     }
     dbg_error_log('DAVResource', ':FromRow: Named "%s" is%s a collection.', $this->dav_name, $this->_is_collection ? '' : ' not');
     foreach ($row as $k => $v) {
         if ($this->_is_collection) {
             $this->collection->{$k} = $v;
         } else {
             $this->resource->{$k} = $v;
         }
         switch ($k) {
             case 'created':
             case 'modified':
                 $this->{$k} = $v;
                 break;
             case 'resourcetypes':
                 if ($this->_is_collection) {
                     $this->{$k} = $v;
                 }
                 break;
             case 'dav_etag':
                 $this->unique_tag = '"' . $v . '"';
                 break;
         }
     }
     if ($this->_is_collection) {
         if (!isset($this->collection->type) || $this->collection->type == 'collection') {
             if ($this->_is_principal) {
                 $this->collection->type = 'principal';
             } else {
                 if ($row->is_calendar == 't') {
                     $this->collection->type = 'calendar';
                 } else {
                     if ($row->is_addressbook == 't') {
                         $this->collection->type = 'addressbook';
                     } else {
                         if (isset($row->is_proxy) && $row->is_proxy == 't') {
                             $this->collection->type = 'proxy';
                         } else {
                             if (preg_match('#^((/[^/]+/)\\.(in|out)/)[^/]*$#', $this->dav_name, $matches)) {
                                 $this->collection->type = 'schedule-' . $matches[3] . 'box';
                             } else {
                                 if ($this->dav_name == '/') {
                                     $this->collection->type = 'root';
                                 } else {
                                     $this->collection->type = 'collection';
                                 }
                             }
                         }
                     }
                 }
             }
         }
         $this->_is_calendar = $this->collection->is_calendar == 't';
         $this->_is_addressbook = $this->collection->is_addressbook == 't';
         $this->_is_proxy_request = $this->collection->type == 'proxy';
         if ($this->_is_principal && !isset($this->resourcetypes)) {
             $this->resourcetypes = '<DAV::collection/><DAV::principal/>';
         } else {
             if ($this->_is_proxy_request) {
                 $this->resourcetypes = $this->collection->resourcetypes;
             }
         }
         if (isset($this->collection->dav_displayname)) {
             $this->collection->displayname = $this->collection->dav_displayname;
         }
     } else {
         $this->resourcetypes = '';
         if (isset($this->resource->caldav_data)) {
             if (isset($this->resource->summary)) {
                 $this->resource->displayname = $this->resource->summary;
             }
             if (strtoupper(substr($this->resource->caldav_data, 0, 15)) == 'BEGIN:VCALENDAR') {
                 $this->contenttype = 'text/calendar';
                 if (!$this->HavePrivilegeTo('read') && $this->HavePrivilegeTo('read-free-busy')) {
                     $vcal = new iCalComponent($this->resource->caldav_data);
                     $confidential = $vcal->CloneConfidential();
                     $this->resource->caldav_data = $confidential->Render();
                     $this->resource->displayname = $this->resource->summary = translate('Busy');
                     $this->resource->description = null;
                     $this->resource->location = null;
                     $this->resource->url = null;
                 } else {
                     if (isset($c->hide_alarm) && $c->hide_alarm && !$this->HavePrivilegeTo('write')) {
                         $vcal1 = new iCalComponent($this->resource->caldav_data);
                         $comps = $vcal1->GetComponents();
                         $vcal2 = new iCalComponent();
                         $vcal2->VCalendar();
                         foreach ($comps as $comp) {
                             $comp->ClearComponents('VALARM');
                             $vcal2->AddComponent($comp);
                         }
                         $this->resource->displayname = $this->resource->summary = $vcal2->GetPValue('SUMMARY');
                         $this->resource->caldav_data = $vcal2->Render();
                     }
                 }
             } else {
                 if (strtoupper(substr($this->resource->caldav_data, 0, 11)) == 'BEGIN:VCARD') {
                     $this->contenttype = 'text/vcard';
                 } else {
                     if (strtoupper(substr($this->resource->caldav_data, 0, 11)) == 'BEGIN:VLIST') {
                         $this->contenttype = 'text/x-vlist';
                     }
                 }
             }
         }
     }
 }
Beispiel #2
0
    }
    $response = $reply->NewXMLElement("schedule-response", $responses, $reply->GetXmlNsArray(), 'urn:ietf:params:xml:ns:caldav');
    $request->XMLResponse(200, $response);
}
function handle_cancel_request($ic)
{
    global $c, $session, $request;
    $reply = new XMLDocument(array("DAV:" => "", "urn:ietf:params:xml:ns:caldav" => "C"));
    $response = $reply->NewXMLElement("response", false, false, 'urn:ietf:params:xml:ns:caldav');
    $reply->CalDAVElement($response, "request-status", "2.0;Success");
    // Cargo-cult setting
    $response = $reply->NewXMLElement("schedule-response", $response, $reply->GetXmlNsArray());
    $request->XMLResponse(200, $response);
}
$ical = new iCalComponent($request->raw_post);
$method = $ical->GetPValue('METHOD');
$resources = $ical->GetComponents('VTIMEZONE', false);
$first = $resources[0];
switch ($method) {
    case 'REQUEST':
        dbg_error_log('POST', 'Handling iTIP "REQUEST" method with "%s" component.', $method, $first->GetType());
        if ($first->GetType() == 'VFREEBUSY') {
            handle_freebusy_request($first);
        } elseif ($first->GetType() == 'VEVENT') {
            handle_schedule_request($ical);
        } else {
            dbg_error_log('POST', 'Ignoring iTIP "REQUEST" with "%s" component.', $first->GetType());
        }
        break;
    case 'REPLY':
        dbg_error_log('POST', 'Handling iTIP "REPLY" with "%s" component.', $first->GetType());
/**
* This function will import a whole calendar
* @param string $ics_content the ics file to import
* @param int $user_no the user wich will receive this ics file
* @param string $path the $path where it will be store such as /user_foo/home/
* @param boolean $caldav_context Whether we are responding via CalDAV or interactively
*
* Any VEVENTs with the same UID will be concatenated together
*/
function import_collection($ics_content, $user_no, $path, $caldav_context, $appending = false)
{
    global $c, $session, $tz_regex;
    if (!ini_get('open_basedir') && (isset($c->dbg['ALL']) || isset($c->dbg['put']))) {
        $fh = fopen('/tmp/PUT-2.txt', 'w');
        if ($fh) {
            fwrite($fh, $ics_content);
            fclose($fh);
        }
    }
    $calendar = new iCalComponent($ics_content);
    $timezones = $calendar->GetComponents('VTIMEZONE', true);
    $components = $calendar->GetComponents('VTIMEZONE', false);
    $displayname = $calendar->GetPValue('X-WR-CALNAME');
    if (!$appending && isset($displayname)) {
        $sql = 'UPDATE collection SET dav_displayname = :displayname WHERE dav_name = :dav_name';
        $qry = new AwlQuery($sql, array(':displayname' => $displayname, ':dav_name' => $path));
        if (!$qry->Exec('PUT', __LINE__, __FILE__)) {
            rollback_on_error($caldav_context, $user_no, $path);
        }
    }
    $tz_ids = array();
    foreach ($timezones as $k => $tz) {
        $tz_ids[$tz->GetPValue('TZID')] = $k;
    }
    /** Build an array of resources.  Each resource is an array of iCalComponent */
    $resources = array();
    foreach ($components as $k => $comp) {
        $uid = $comp->GetPValue('UID');
        if ($uid == null || $uid == '') {
            continue;
        }
        if (!isset($resources[$uid])) {
            $resources[$uid] = array();
        }
        $resources[$uid][] = $comp;
        /** Ensure we have the timezone component for this in our array as well */
        $tzid = $comp->GetPParamValue('DTSTART', 'TZID');
        if (!isset($tzid) || $tzid == '') {
            $tzid = $comp->GetPParamValue('DUE', 'TZID');
        }
        if (!isset($resources[$uid][$tzid]) && isset($tz_ids[$tzid])) {
            $resources[$uid][$tzid] = $timezones[$tz_ids[$tzid]];
        }
    }
    $sql = 'SELECT * FROM collection WHERE dav_name = :dav_name';
    $qry = new AwlQuery($sql, array(':dav_name' => $path));
    if (!$qry->Exec('PUT', __LINE__, __FILE__)) {
        rollback_on_error($caldav_context, $user_no, $path);
    }
    if (!$qry->rows() == 1) {
        dbg_error_log('ERROR', ' PUT: Collection does not exist at "%s" for user %d', $path, $user_no);
        rollback_on_error($caldav_context, $user_no, $path);
    }
    $collection = $qry->Fetch();
    if (!(isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import)) {
        $qry->Begin();
    }
    $base_params = array(':collection_id' => $collection->collection_id);
    if (!$appending) {
        if (!$qry->QDo('DELETE FROM calendar_item WHERE collection_id = :collection_id', $base_params) || !$qry->QDo('DELETE FROM caldav_data WHERE collection_id = :collection_id', $base_params)) {
            rollback_on_error($caldav_context, $user_no, $collection->collection_id);
        }
    }
    $dav_data_insert = <<<EOSQL
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, :caldav_type, :session_user, current_timestamp, current_timestamp, :collection_id )
EOSQL;
    $calitem_insert = <<<EOSQL
INSERT INTO calendar_item (user_no, dav_name, dav_id, dav_etag, uid, dtstamp, dtstart, dtend, summary, location, class, transp,
                    description, rrule, tz_id, last_modified, url, priority, created, due, percent_complete, status, collection_id )
    VALUES ( :user_no, :dav_name, currval('dav_id_seq'), :etag, :uid, :dtstamp, :dtstart, ##dtend##, :summary, :location, :class, :transp,
                :description, :rrule, :tzid, :modified, :url, :priority, :created, :due, :percent_complete, :status, :collection_id)
EOSQL;
    $last_tz_locn = '';
    foreach ($resources as $uid => $resource) {
        if (isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import) {
            $qry->Begin();
        }
        /** Construct the VCALENDAR data */
        $vcal = new iCalComponent();
        $vcal->VCalendar();
        $vcal->SetComponents($resource);
        create_scheduling_requests($vcal);
        $icalendar = $vcal->Render();
        /** As ever, we mostly deal with the first resource component */
        $first = $resource[0];
        $dav_data_params = $base_params;
        $dav_data_params[':user_no'] = $user_no;
        $dav_data_params[':dav_name'] = sprintf('%s%s.ics', $path, $uid);
        $dav_data_params[':etag'] = md5($icalendar);
        $calitem_params = $dav_data_params;
        $dav_data_params[':dav_data'] = $icalendar;
        $dav_data_params[':caldav_type'] = $first->GetType();
        $dav_data_params[':session_user'] = $session->user_no;
        if (!$qry->QDo($dav_data_insert, $dav_data_params)) {
            rollback_on_error($caldav_context, $user_no, $path);
        }
        $qry->QDo('SELECT dav_id FROM caldav_data WHERE dav_name = :dav_name ', array(':dav_name' => $dav_data_params[':dav_name']));
        if ($qry->rows() == 1 && ($row = $qry->Fetch())) {
            $dav_id = $row->dav_id;
        }
        $dtstart = $first->GetPValue('DTSTART');
        $calitem_params[':dtstart'] = $dtstart;
        if ((!isset($dtstart) || $dtstart == '') && $first->GetPValue('DUE') != '') {
            $dtstart = $first->GetPValue('DUE');
        }
        $dtend = $first->GetPValue('DTEND');
        if (isset($dtend) && $dtend != '') {
            dbg_error_log('PUT', ' DTEND: "%s", DTSTART: "%s", DURATION: "%s"', $dtend, $dtstart, $first->GetPValue('DURATION'));
            $calitem_params[':dtend'] = $dtend;
            $dtend = ':dtend';
        } else {
            $dtend = 'NULL';
            if ($first->GetPValue('DURATION') != '' and $dtstart != '') {
                $duration = trim(preg_replace('#[PT]#', ' ', $first->GetPValue('DURATION')));
                if ($duration == '') {
                    $duration = '0 seconds';
                }
                $dtend = '(:dtstart::timestamp with time zone + :duration::interval)';
                $calitem_params[':duration'] = $duration;
            } elseif ($first->GetType() == 'VEVENT') {
                /**
                 * From RFC2445 4.6.1:
                 * For cases where a "VEVENT" calendar component specifies a "DTSTART"
                 * property with a DATE data type but no "DTEND" property, the events
                 * non-inclusive end is the end of the calendar date specified by the
                 * "DTSTART" property. For cases where a "VEVENT" calendar component specifies
                 * a "DTSTART" property with a DATE-TIME data type but no "DTEND" property,
                 * the event ends on the same calendar date and time of day specified by the
                 * "DTSTART" property.
                 *
                 * So we're looking for 'VALUE=DATE', to identify the duration, effectively.
                 *
                 */
                $value_type = $first->GetPParamValue('DTSTART', 'VALUE');
                dbg_error_log('PUT', 'DTSTART without DTEND. DTSTART value type is %s', $value_type);
                if (isset($value_type) && $value_type == 'DATE') {
                    $dtend = '(:dtstart::timestamp with time zone::date + \'1 day\'::interval)';
                } else {
                    $dtend = ':dtstart';
                }
            }
        }
        $last_modified = $first->GetPValue('LAST-MODIFIED');
        if (!isset($last_modified) || $last_modified == '') {
            $last_modified = gmdate('Ymd\\THis\\Z');
        }
        $calitem_params[':modified'] = $last_modified;
        $dtstamp = $first->GetPValue('DTSTAMP');
        if (!isset($dtstamp) || $dtstamp == '') {
            $dtstamp = $last_modified;
        }
        $calitem_params[':dtstamp'] = $dtstamp;
        /** RFC2445, 4.8.1.3: Default is PUBLIC, or also if overridden by the collection settings */
        $class = $collection->public_events_only == 't' ? 'PUBLIC' : $first->GetPValue('CLASS');
        if (!isset($class) || $class == '') {
            $class = 'PUBLIC';
        }
        $calitem_params[':class'] = $class;
        /** Calculate what timezone to set, first, if possible */
        $tzid = $first->GetPParamValue('DTSTART', 'TZID');
        if (!isset($tzid) || $tzid == '') {
            $tzid = $first->GetPParamValue('DUE', 'TZID');
        }
        if (isset($tzid) && $tzid != '') {
            if (isset($resource[$tzid])) {
                $tz = $resource[$tzid];
                $tz_locn = $tz->GetPValue('X-LIC-LOCATION');
            } else {
                unset($tz);
                unset($tz_locn);
            }
            if (!isset($tz_locn) || !preg_match($tz_regex, $tz_locn)) {
                if (preg_match('#([^/]+/[^/]+)$#', $tzid, $matches)) {
                    $tz_locn = $matches[1];
                }
            }
            dbg_error_log('PUT', ' Using TZID[%s] and location of [%s]', $tzid, isset($tz_locn) ? $tz_locn : '');
            if (isset($tz_locn) && $tz_locn != $last_tz_locn && preg_match($tz_regex, $tz_locn)) {
                dbg_error_log('PUT', ' Setting timezone to %s', $tz_locn);
                if ($tz_locn != '') {
                    $qry->QDo('SET TIMEZONE TO \'' . $tz_locn . "'");
                }
                $last_tz_locn = $tz_locn;
            }
            $params = array(':tzid' => $tzid);
            $qry = new AwlQuery('SELECT tz_locn FROM time_zone WHERE tz_id = :tzid', $params);
            if ($qry->Exec('PUT', __LINE__, __FILE__) && $qry->rows() == 0) {
                $params[':tzlocn'] = $tz_locn;
                $params[':tzspec'] = isset($tz) ? $tz->Render() : null;
                $qry->QDo('INSERT INTO time_zone (tz_id, tz_locn, tz_spec) VALUES(:tzid,:tzlocn,:tzspec)', $params);
            }
            if (!isset($tz_locn) || $tz_locn == '') {
                $tz_locn = $tzid;
            }
        } else {
            $tzid = null;
        }
        $sql = str_replace('##dtend##', $dtend, $calitem_insert);
        $calitem_params[':tzid'] = $tzid;
        $calitem_params[':uid'] = $first->GetPValue('UID');
        $calitem_params[':summary'] = $first->GetPValue('SUMMARY');
        $calitem_params[':location'] = $first->GetPValue('LOCATION');
        $calitem_params[':transp'] = $first->GetPValue('TRANSP');
        $calitem_params[':description'] = $first->GetPValue('DESCRIPTION');
        $calitem_params[':rrule'] = $first->GetPValue('RRULE');
        $calitem_params[':url'] = $first->GetPValue('URL');
        $calitem_params[':priority'] = $first->GetPValue('PRIORITY');
        $calitem_params[':due'] = $first->GetPValue('DUE');
        $calitem_params[':percent_complete'] = $first->GetPValue('PERCENT-COMPLETE');
        $calitem_params[':status'] = $first->GetPValue('STATUS');
        $created = $first->GetPValue('CREATED');
        if ($created == '00001231T000000Z') {
            $created = '20001231T000000Z';
        }
        $calitem_params[':created'] = $created;
        if (!$qry->QDo($sql, $calitem_params)) {
            rollback_on_error($caldav_context, $user_no, $path);
        }
        write_alarms($dav_id, $first);
        write_attendees($dav_id, $first);
        create_scheduling_requests($vcal);
        if (isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import) {
            $qry->Commit();
        }
    }
    if (!(isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import)) {
        if (!$qry->Commit()) {
            rollback_on_error($caldav_context, $user_no, $path);
        }
    }
}