Page MenuHomePhorge

No OneTemporary

diff --git a/lib/kolab_sync_data_calendar.php b/lib/kolab_sync_data_calendar.php
index 9432b17..a7f1e8e 100644
--- a/lib/kolab_sync_data_calendar.php
+++ b/lib/kolab_sync_data_calendar.php
@@ -1,507 +1,524 @@
<?php
/**
*
*/
class kolab_sync_data_calendar extends kolab_sync_data
{
const MODEL = 'Syncroton_Model_Event';
/**
* Mapping from ActiveSync Calendar namespace fields
*/
protected $mapping = array(
'AllDayEvent' => 'allday',
//'Attendee' => 'attendee', // Attendees member
//'Attendees' => 'attendees',
//'AttendeeStatus' => 'attendeestatus', // Attendee member
//'AttendeeType' => 'attendeetype', // Attendee member
'Body' => 'description',
//'BodyTruncated' => 'bodytruncated',
//'BusyStatus' => 'busystatus', // @TODO ?
//'Categories' => 'categories',
//'Category' => 'category', // Categories member
//'DayOfMonth' => 'dayofmonth', // Recurrence member
//'DayOfWeek' => 'dayofweek', // Recurrence member
//'Deleted' => 'deleted', // Exception member
'DtStamp' => 'changed',
//'Email' => 'email', // Attendee member
'EndTime' => 'end',
//'Exception' => 'exception', // recurrence pattern exception, Exceptions member
//'Exceptions' => 'exceptions',
//'ExceptionStartTime' => 'exceptionstarttime', // Exception member
//'FirstDayOfWeek' => 'firstdayofweek', // Recurrence member
//'Interval' => 'interval', // Recurrence member
//'IsLeapMonth' => 'isleapmonth', // Recurrence member
'Location' => 'location',
//'MeetingStatus' => 'meetingstatus',
//'MonthOfYear' => 'monthofyear', // Recurrence member
//'Name' => 'name', // Attendee member
//'Occurrences' => 'occurences', // Recurrence member
//'OrganizerEmail' => 'organizeremail',
//'OrganizerName' => 'organizername',
//'Recurrence' => 'recurrence',
//'Reminder' => 'reminder',
//'ResponseRequested' => 'responserequested',
//'ResponseType' => 'responsetype',
'Sensitivity' => 'sensitivity',
'StartTime' => 'start',
'Subject' => 'title',
//'Timezone' => 'timezone',
//'Type' => 'type', // Recurrence member
'UID' => 'uid',
//'Until' => 'until', // Recurrence member
//'WeekOfMonth' => 'weekofmonth', // Recurrence member
);
/**
* Kolab object type
*
* @var string
*/
protected $modelName = 'event';
/**
* Type of the default folder
*
* @var int
*/
protected $defaultFolderType = Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR;
/**
* Default container for new entries
*
* @var string
*/
protected $defaultFolder = 'Calendar';
/**
* Type of user created folders
*
* @var int
*/
protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR_USER_CREATED;
/**
* Default namespace
*
* @var string
*/
protected $defaultNS = 'Calendar';
/**
* Field to sort search results by
*
* @var string
*/
protected $sortField = 'n_fileas';
/**
* attendee status
*/
const ATTENDEE_STATUS_UNKNOWN = 0;
const ATTENDEE_STATUS_TENTATIVE = 2;
const ATTENDEE_STATUS_ACCEPTED = 3;
const ATTENDEE_STATUS_DECLINED = 4;
const ATTENDEE_STATUS_NOTRESPONDED = 5;
/**
* attendee types
*/
const ATTENDEE_TYPE_REQUIRED = 1;
const ATTENDEE_TYPE_OPTIONAL = 2;
const ATTENDEE_TYPE_RESOURCE = 3;
/**
* busy status constants
*/
const BUSY_STATUS_FREE = 0;
const BUSY_STATUS_TENATTIVE = 1;
const BUSY_STATUS_BUSY = 2;
const BUSY_STATUS_OUTOFOFFICE = 3;
/**
* Sensitivity values
*/
const SENSITIVITY_NORMAL = 0;
const SENSITIVITY_PERSONAL = 1;
const SENSITIVITY_PRIVATE = 2;
const SENSITIVITY_CONFIDENTIAL = 3;
/**
* Mapping of attendee status
*
* @var array
*/
protected $attendeeStatusMap = array(
'UNKNOWN' => self::ATTENDEE_STATUS_UNKNOWN,
'TENTATIVE' => self::ATTENDEE_STATUS_TENTATIVE,
'ACCEPTED' => self::ATTENDEE_STATUS_ACCEPTED,
'DECLINED' => self::ATTENDEE_STATUS_DECLINED,
'DELEGATED' => self::ATTENDEE_STATUS_UNKNOWN,
'NEEDS-ACTION' => self::ATTENDEE_STATUS_UNKNOWN,
//self::ATTENDEE_STATUS_NOTRESPONDED,
);
/**
* Mapping of attendee type
*
* NOTE: recurrences need extra handling!
* @var array
*/
protected $attendeeTypeMap = array(
'REQ-PARTICIPANT' => self::ATTENDEE_TYPE_REQUIRED,
'OPT-PARTICIPANT' => self::ATTENDEE_TYPE_OPTIONAL,
// 'NON-PARTICIPANT' => self::ATTENDEE_TYPE_RESOURCE,
// 'CHAIR' => self::ATTENDEE_TYPE_RESOURCE,
);
/**
* Mapping of busy status
*
* @var array
*/
protected $busyStatusMap = array(
'DECLINED' => self::BUSY_STATUS_FREE,
'TENTATIVE' => self::BUSY_STATUS_TENATTIVE,
'ACCEPTED' => self::BUSY_STATUS_BUSY,
);
/**
* mapping of sensitivity
*
* @var array
*/
protected $sensitivityMap = array(
'public' => self::SENSITIVITY_PERSONAL,
'private' => self::SENSITIVITY_PRIVATE,
'confidential' => self::SENSITIVITY_CONFIDENTIAL,
);
/**
* Appends contact data to xml element
*
* @param Syncroton_Model_SyncCollection $collection Collection data
* @param string $serverId Local entry identifier
*/
public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId)
{
$event = is_array($serverId) ? $serverId : $this->getObject($collection->collectionId, $serverId);
$config = $this->getFolderConfig($event['_mailbox']);
$result = array();
// Timezone
// Kolab Format 3.0 and xCal does support timezone per-date, but ActiveSync allows
// only one timezone per-event. We'll use timezone of the start date
if ($event['start'] instanceof DateTime) {
$timezone = $event['start']->getTimezone();
if ($timezone && ($tz_name = $timezone->getName()) != 'UTC') {
$tzc = kolab_sync_timezone_converter::getInstance();
if ($tz_name = $tzc->encodeTimezone($tz_name)) {
$result['Timezone'] = $tz_name;
}
}
}
// Calendar namespace fields
foreach ($this->mapping as $key => $name) {
$value = $this->getKolabDataItem($event, $name);
switch ($name) {
case 'changed':
case 'end':
case 'start':
+ // For all-day events Kolab uses different times
+ // At least Android doesn't display such event as all-day event
+ if ($value && $event['allday']) {
+ if ($name == 'start') {
+ $value->setTime(0, 0, 0);
+ }
+ else if ($name == 'end') {
+ $value->setTime(0, 0, 0);
+ $value->modify('+1 day');
+ }
+ }
$value = self::date_from_kolab($value);
+
break;
case 'sensitivity':
$value = intval($this->sesnsitivityMap[$value]);
break;
case 'description':
$value = $this->setBody($value);
break;
}
if (empty($value) || is_array($value)) {
continue;
}
$result[$key] = $value;
}
// Event status, always "is a meeting"?
$result['MeetingStatus'] = 1;
// Event reminder time
if ($config['ALARMS'] && ($minutes = $this->from_kolab_alarm($event['alarms']))) {
$result['Reminder'] = $minutes;
}
// Categories, Roundcube Calendar plugin supports only one category at a time
if (!empty($event['categories'])) {
$result['Categories'] = (array) $event['categories'];
}
// Organizer
if (!empty($event['attendees'])) {
foreach ($event['attendees'] as $idx => $attendee) {
if ($attendee['role'] == 'ORGANIZER') {
$organizer = $attendee;
if ($name = self::quote($attendee['name'])) {
$result['OrganizerName'] = $name;
}
if ($email = self::quote($attendee['email'])) {
$result['OrganizerEmail'] = $email;
}
unset($event['attendees'][$idx]);
break;
}
}
}
// Attendees
if (!empty($event['attendees'])) {
$result['Attendees'] = array();
foreach ($event['attendees'] as $idx => $attendee) {
$att = array();
if ($attendee['name']) {
$att['Name'] = $name;
}
if ($attendee['email']) {
$att['Email'] = $email;
}
if ($this->asversion >= 12) {
$type = isset($attendee['role']) ? $this->attendeeTypeMap[$attendee['role']] : null;
$status = isset($attendee['status']) ? $this->attendeeStatusMap[$attende['status']] : null;
$att['AttendeeType'] = $type ? $type : self::ATTENDEE_TYPE_REQUIRED;
$att['AttendeeStatus'] = $status ? $status : self::ATTENDEE_STATUS_UNKNOWN;
}
$result['Attendees'][] = new Syncroton_Model_EventAttendee($att);
}
/*
// set own status
if (($ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee)) !== null
&& ($busyType = array_search($ownAttendee->status, $this->_busyStatusMapping)) !== false
) {
$result['BusyStatus'] = $busyType;
}
*/
}
// Recurrence
$result['Recurrence'] = $this->recurrence_from_kolab($event);
return new Syncroton_Model_Event($result);
}
/**
* convert contact from xml to libkolab array
*
* @param Syncroton_Model_IEntry $data Contact to convert
* @param string $folderid Folder identifier
* @param array $entry Existing entry
*
* @return array
*/
public function toKolab(Syncroton_Model_IEntry $data, $folderid, $entry = null)
{
$foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid);
$event = !empty($entry) ? $entry : array();
$config = $this->getFolderConfig($foldername);
$event['allday'] = 0;
// Timezone
if (isset($data->Timezone)) {
$tzc = kolab_sync_timezone_converter::getInstance();
$expected = kolab_format::$timezone->getName();
if (!empty($event['start']) && ($event['start'] instanceof DateTime)) {
$expected = $event['start']->getTimezone()->getName();
}
$timezone = $tzc->getTimezone($data->Timezone, $expected);
try {
$timezone = new DateTimeZone($timezone);
}
catch (Exception $e) {
$timezone = null;
}
}
if (empty($timezone)) {
$timezone = new DateTimeZone('UTC');
}
// Calendar namespace fields
foreach ($this->mapping as $key => $name) {
$value = $data->$key;
switch ($name) {
case 'changed':
$value = null;
break;
case 'end':
case 'start':
if ($timezone && $value) {
$value->setTimezone($timezone);
}
+ // In ActiveSync all-day event ends on 00:00:00 next day
+ if ($value && $data->AllDayEvent && $name == 'end') {
+ $value->modify('-1 second');
+ }
+
break;
case 'sensitivity':
$map = array_flip($this->sensitivityMap);
$value = $map[$value];
break;
case 'description':
$value = $this->getBody($value);
break;
}
$this->setKolabDataItem($event, $name, $value);
}
// Reminder
// @TODO: should alarms be used when importing event from phone?
if ($config['ALARMS']) {
$event['alarms'] = $this->to_kolab_alarm($data->Reminder, $event);
}
$event['attendees'] = array();
$event['categories'] = array();
// Categories
if (isset($data->Categories)) {
foreach ($data->Categories as $category) {
$event['categories'][] = $category;
}
}
// Organizer
$name = $data->OrganizerName;
$email = $data->OrganizerEmail;
if ($name || $email) {
$event['attendees'][] = array(
'role' => 'ORGANIZER',
'name' => $name,
'email' => $email,
);
}
// Attendees
if (isset($data->Attendees)) {
foreach ($data->Attendees as $attendee) {
$role = false;
if (isset($attendee->AttendeeType)) {
$role = array_search($attendee->AttendeeType, $this->attendeeTypeMap);
}
if ($role === false) {
$role = array_search(self::ATTENDEE_TYPE_REQUIRED, $this->attendeeTypeMap);
}
// AttendeeStatus send only on repsonse (?)
$event['attendees'][] = array(
'role' => $role,
'name' => $attendee->Name,
'email' => $attendee->Email,
);
}
}
// recurrence
$event['recurrence'] = $this->recurrence_to_kolab($data, $timezone);
return $event;
}
/**
* Returns filter query array according to specified ActiveSync FilterType
*
* @param int $filter_type Filter type
*
* @param array Filter query
*/
protected function filter($filter_type = 0)
{
$filter = array();
switch ($filter_type) {
case Syncroton_Command_Sync::FILTER_2_WEEKS_BACK:
$mod = '-2 weeks';
break;
case Syncroton_Command_Sync::FILTER_1_MONTH_BACK:
$mod = '-1 month';
break;
case Syncroton_Command_Sync::FILTER_3_MONTHS_BACK:
$mod = '-3 months';
break;
case Syncroton_Command_Sync::FILTER_6_MONTHS_BACK:
$mod = '-6 months';
break;
}
if (!empty($mod)) {
$dt = new DateTime('now', new DateTimeZone('UTC'));
$dt->modify($mod);
$filter[] = array('dtend', '>', $dt);
}
return $filter;
}
/**
* Converts libkolab alarms string into number of minutes
*/
protected function from_kolab_alarm($value)
{
// e.g. '-15M:DISPLAY'
// Ignore EMAIL alarms
if (preg_match('/^-([0-9]+)([WDHMS]):(DISPLAY|AUDIO)$/', $value, $matches)) {
$value = intval($matches[1]);
switch ($matches[2]) {
case 'S': $value = 1; break;
case 'H': $value *= 60; break;
case 'D': $value *= 24 * 60; break;
case 'W': $value *= 7 * 24 * 60; break;
}
return $value;
}
}
/**
* Converts ActiveSync libkolab alarms string into number of minutes
*/
protected function to_kolab_alarm($value, $event)
{
// Get alarm type from old event object if exists
if (!empty($event['alarms']) && preg_match('/:(.*)$/', $event['alarms'], $matches)) {
$type = $matches[1];
}
if ($value) {
return sprintf('-%dM:%s', $value, $type ? $type : 'DISPLAY');
}
if ($type == 'DISPLAY' || $type == 'AUDIO') {
return null;
}
return $event['alarms'];
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Sep 15, 6:47 AM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
287494
Default Alt Text
(17 KB)

Event Timeline