Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117888314
kolab_sync_data_calendar.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
16 KB
Referenced Files
None
Subscribers
None
kolab_sync_data_calendar.php
View Options
<?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'
=>
'free_busy'
,
//'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_TENTATIVE
=
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
(
'free'
=>
self
::
BUSY_STATUS_FREE
,
'tentative'
=>
self
::
BUSY_STATUS_TENTATIVE
,
'busy'
=>
self
::
BUSY_STATUS_BUSY
,
'outofoffice'
=>
self
::
BUSY_STATUS_OUTOFOFFICE
,
);
/**
* 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
->
sensitivityMap
[
$value
]);
break
;
case
'free_busy'
:
$value
=
$this
->
busyStatusMap
[
$value
];
break
;
case
'description'
:
$value
=
$this
->
setBody
(
$value
);
break
;
}
if
(
empty
(
$value
)
||
is_array
(
$value
))
{
continue
;
}
$result
[
$key
]
=
$value
;
}
// 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;
}
*/
}
// Event meeting status
$result
[
'MeetingStatus'
]
=
intval
(!
empty
(
$result
[
'Attendees'
]));
// 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
'free_busy'
:
$map
=
array_flip
(
$this
->
busyStatusMap
);
$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
Details
Attached
Mime Type
text/x-php
Expires
Mon, Apr 6, 3:17 AM (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18832160
Default Alt Text
kolab_sync_data_calendar.php (16 KB)
Attached To
Mode
rS syncroton
Attached
Detach File
Event Timeline