/** * Convert a iCAL VTodo to ActiveSync format * @param string $data * @param ContentParameters $contentparameters */ private function _ParseVTodoToAS($data, $contentparameters) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->_ParseVTodoToAS(): Parsing VTodo")); $truncsize = Utils::GetTruncSize($contentparameters->GetTruncation()); $message = new SyncTask(); $ical = new iCalComponent($data); $vtodos = $ical->GetComponents("VTODO"); //Should only loop once foreach ($vtodos as $vtodo) { $message = $this->_ParseVTodoToSyncObject($vtodo, $message, $truncsize); } return $message; }
/** * 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; }
$ic = new iCalComponent($resource->caldav_data); /** Default deny... */ $allowed = false; if ($dav_resource->HavePrivilegeTo('all', false) || $session->user_no == $resource->user_no || $session->user_no == $resource->logged_user || $c->allow_get_email_visibility && $ic->IsAttendee($session->email)) { /** * These people get to see all of the event, and they should always * get any alarms as well. */ $allowed = true; } else { if ($resource->class != 'PRIVATE') { $allowed = true; // but we may well obfuscate it below if (!$dav_resource->HavePrivilegeTo('DAV::read') || $resource->class == 'CONFIDENTIAL' && !$request->HavePrivilegeTo('DAV::write-content')) { $ical = new iCalComponent($resource->caldav_data); $comps = $ical->GetComponents('VTIMEZONE', false); $confidential = obfuscated_event($comps[0]); $ical->SetComponents(array($confidential), $resource->caldav_type); $resource->caldav_data = $ical->Render(); } } } // else $resource->class == 'PRIVATE' and this person may not see it. if (!$allowed) { $request->DoResponse(403, translate("Forbidden")); } header('Etag: "' . $resource->dav_etag . '"'); header('Content-Length: ' . strlen($resource->caldav_data)); $contenttype = 'text/plain'; switch ($resource->caldav_type) { case 'VJOURNAL':
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(); }
$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()); handle_schedule_reply($ical);
/** * 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'; } } } } } }
/** * 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); } } }