Page MenuHomePhorge

kolab_sync_data_calendar.php
No OneTemporary

Size
27 KB
Referenced Files
None
Subscribers
None

kolab_sync_data_calendar.php

<?php
/**
*
*/
class kolab_sync_data_calendar extends kolab_sync_data
{
/**
* 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' => 'body', // handled separately
//'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;
/**
* recur types
*/
const RECUR_TYPE_DAILY = 0; // Recurs daily.
const RECUR_TYPE_WEEKLY = 1; // Recurs weekly
const RECUR_TYPE_MONTHLY = 2; // Recurs monthly
const RECUR_TYPE_MONTHLY_DAYN = 3; // Recurs monthly on the nth day
const RECUR_TYPE_YEARLY = 5; // Recurs yearly
const RECUR_TYPE_YEARLY_DAYN = 6; // Recurs yearly on the nth day
/**
* day of week constants
*/
const RECUR_DOW_SUNDAY = 1;
const RECUR_DOW_MONDAY = 2;
const RECUR_DOW_TUESDAY = 4;
const RECUR_DOW_WEDNESDAY = 8;
const RECUR_DOW_THURSDAY = 16;
const RECUR_DOW_FRIDAY = 32;
const RECUR_DOW_SATURDAY = 64;
const RECUR_DOW_LAST = 127; // The last day of the month. Used as a special value in monthly or yearly recurrences.
/**
* 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 recur types
*
* @var array
*/
protected $recurTypeMap = array(
'DAILY' => self::RECUR_TYPE_DAILY,
'WEEKLY' => self::RECUR_TYPE_WEEKLY,
'MONTHLY' => self::RECUR_TYPE_MONTHLY,
'MONTHLY' => self::RECUR_TYPE_MONTHLY_DAYN,
'YEARLY' => self::RECUR_TYPE_YEARLY,
'YEARLY' => self::RECUR_TYPE_YEARLY_DAYN,
);
/**
* mapping of weekdays
*
* NOTE: ActiveSync uses a bitmask
* @var array
*/
protected $recurDayMap = array(
'SU' => self::RECUR_DOW_SUNDAY,
'MO' => self::RECUR_DOW_MONDAY,
'TU' => self::RECUR_DOW_TUESDAY,
'WE' => self::RECUR_DOW_WEDNESDAY,
'TH' => self::RECUR_DOW_THURSDAY,
'FR' => self::RECUR_DOW_FRIDAY,
'SA' => self::RECUR_DOW_SATURDAY,
);
/**
* 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 DOMElement $domParent Parent xml node
* @param array $collectionData Collection data
* @param string $serverId Local entry identifier
*/
public function appendXML(DOMElement $domParent, $collectionData, $serverId)
{
$domParent->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Calendar', 'uri:Calendar');
$event = is_array($serverId) ? $serverId : $this->getObject($collectionData['folder'], $serverId);
$config = $this->getFolderConfig($event['_mailbox']);
// 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 ($object['start'] instanceof DateTime) {
$timezone = $object['start']->getTimezone();
if ($timezone && ($tz_name = $timezone->getName()) != 'UTC') {
$tzc = kolab_sync_timezone_converter::getInstance();
if ($tz_name = $tzc->encodeTimezone($tz_name)) {
$domParent->appendChild(new DOMElement('Timezone', $tz_name, 'uri:Calendar'));
}
}
}
// Calendar namespace fields
foreach ($this->mapping as $key => $name) {
$value = $this->getKolabDataItem($event, $name);
switch ($name) {
case 'changed':
case 'end':
case 'start':
$value = self::date_from_kolab($value);
break;
case 'sensitivity':
$value = intval($this->sesnsitivityMap[$value]);
break;
}
if (empty($value) || is_array($value)) {
continue;
}
// strip off any non printable control characters
$value = self::quote($value);
$node = $domParent->ownerDocument->createElementNS('uri:Calendar', $key);
$node->appendChild($domParent->ownerDocument->createTextNode($value));
$domParent->appendChild($node);
}
// Event status, always "is a meeting"?
$domParent->appendChild(new DOMElement('MeetingStatus', 1, 'uri:Calendar'));
// Event reminder time
if ($config['ALARMS'] && ($minutes = $this->from_kolab_alarm($event['alarms']))) {
$domParent->appendChild(new DOMElement('Reminder', $minutes, 'uri:Calendar'));
}
// Event description
$this->setBody($domParent, $event['description']);
// Categories, Roundcube Calendar plugin supports only one category at a time
if (!empty($event['categories'])) {
$categories = $domParent->appendChild(new DOMElement('Categories', null, 'uri:Calendar'));
foreach ((array)$event['categories'] as $tag) {
$categories->appendChild(new DOMElement('Category', $tag, 'uri:Calendar'));
}
}
// Organizer
if (!empty($event['attendees'])) {
foreach ($event['attendees'] as $idx => $attendee) {
if ($attendee['role'] == 'ORGANIZER') {
$organizer = $attendee;
if ($name = self::quote($attendee['name'])) {
$domParent->appendChild(new DOMElement('OrganizerName', $name, 'uri:Calendar'));
}
if ($email = self::quote($attendee['email'])) {
$domParent->appendChild(new DOMElement('OrganizerEmail', $email, 'uri:Calendar'));
}
unset($event['attendees'][$idx]);
break;
}
}
}
// Attendees
if (!empty($event['attendees'])) {
$attendees = $domParent->ownerDocument->createElementNS('uri:Calendar', 'Attendees');
foreach ($event['attendees'] as $idx => $attendee) {
$att = $attendees->appendChild(new DOMElement('Attendee', null, 'uri:Calendar'));
if ($name = self::quote($attendee['name'])) {
$att->appendChild(new DOMElement('Name', $name, 'uri:Calendar'));
}
if ($email = self::quote($attendee['email'])) {
$att->appendChild(new DOMElement('Email', $email, 'uri:Calendar'));
}
if ($this->asversion >= 12) {
$type = isset($attendee['role']) ? $this->attendeeTypeMap[$attendee['role']] : null;
$status = isset($attendee['status']) ? $this->attendeeStatusMap[$attende['status']] : null;
$att->appendChild(new DOMElement('AttendeeType', $type ? $type : self::ATTENDEE_TYPE_REQUIRED, 'uri:Calendar'));
$att->appendChild(new DOMElement('AttendeeStatus', $status ? $status : self::ATTENDEE_STATUS_UNKNOWN, 'uri:Calendar'));
}
}
$domParent->appendChild($attendees);
/*
// set own status
if (($ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee)) !== null
&& ($busyType = array_search($ownAttendee->status, $this->_busyStatusMapping)) !== false
) {
$domParent->appendChild(new DOMElement('BusyStatus', $busyType, 'uri:Calendar'));
}
*/
}
// Recurrence
if (!empty($event['recurrence'])) {
$recurrence = $domParent->appendChild(new DOMElement('Recurrence', null, 'uri:Calendar'));
$r = $event['recurrence'];
// required fields
switch($r['FREQ']) {
case 'DAILY':
$recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_DAILY, 'uri:Calendar'));
break;
case 'WEEKLY':
$recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_WEEKLY, 'uri:Calendar'));
$recurrence->appendChild(new DOMElement('DayOfWeek', $this->day2bitmask($r['BYDAY']), 'uri:Calendar'));
break;
case 'MONTHLY':
if (!empty($r['BYMONTHDAY'])) {
// @TODO: ActiveSync doesn't support multi-valued month days,
// should we replicate the recurrence element for each day of month?
$month_day = array_shift(explode(',', $r['BYMONTHDAY']));
$recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_MONTHLY, 'uri:Calendar'));
$recurrence->appendChild(new DOMElement('DayOfMonth', $month_day, 'uri:Calendar'));
}
else {
$week = (int) substr($r['BYDAY'], 0, -2);
$week = ($week == -1) ? 5 : $week;
$day = substr($r['BYDAY'], -2);
$recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_MONTHLY_DAYN, 'uri:Calendar'));
$recurrence->appendChild(new DOMElement('WeekOfMonth', $week, 'uri:Calendar'));
$recurrence->appendChild(new DOMElement('DayOfWeek', $this->day2bitmask($day), 'uri:Calendar'));
}
break;
case 'YEARLY':
// @TODO: ActiveSync doesn't support multi-valued months,
// should we replicate the recurrence element for each month?
$month = array_shift(explode(',', $r['BYMONTH']));
if (!empty($r['BYDAY'])) {
$week = (int) substr($r['BYDAY'], 0, -2);
$week = ($week == -1) ? 5 : $week;
$day = substr($r['BYDAY'], -2);
$recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_YEARLY_DAYN, 'uri:Calendar'));
$recurrence->appendChild(new DOMElement('WeekOfMonth', $week, 'uri:Calendar'));
$recurrence->appendChild(new DOMElement('DayOfWeek', $this->day2bitmask($day), 'uri:Calendar'));
$recurrence->appendChild(new DOMElement('MonthOfYear', $month, 'uri:Calendar'));
}
else if (!empty($r['BYMONTHDAY'])) {
// @TODO: ActiveSync doesn't support multi-valued month days,
// should we replicate the recurrence element for each day of month?
$month_day = array_shift(explode(',', $r['BYMONTHDAY']));
$recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_YEARLY, 'uri:Calendar'));
$recurrence->appendChild(new DOMElement('DayOfMonth', $month_day, 'uri:Calendar'));
$recurrence->appendChild(new DOMElement('MonthOfYear', $month, 'uri:Calendar'));
}
else {
$recurrence->appendChild(new DOMElement('Type', self::RECUR_TYPE_YEARLY, 'uri:Calendar'));
$recurrence->appendChild(new DOMElement('MonthOfYear', $month, 'uri:Calendar'));
}
break;
}
// required field
$recurrence->appendChild(new DOMElement('Interval', $r['INTERVAL'] ? $r['INTERVAL'] : 1, 'uri:Calendar'));
if ($r['UNTIL']) {
$recurrence->appendChild(new DOMElement('Until', $this->date_from_kolab($r['UNTIL']), 'uri:Calendar'));
}
/*
// handle exceptions of repeating events
if($data->exdate && $data->exdate->count() > 0) {
$exceptionsTag = $_domParent->appendChild(new DOMElement('Exceptions', null, 'uri:Calendar'));
foreach ($data->exdate as $exception) {
$exceptionTag = $exceptionsTag->appendChild(new DOMElement('Exception', null, 'uri:Calendar'));
$exceptionTag->appendChild(new DOMElement('Deleted', (int)$exception->is_deleted, 'uri:Calendar'));
$exceptionTag->appendChild(new DOMElement('ExceptionStartTime', $exception->getOriginalDtStart()->format('Ymd\THis') . 'Z', 'uri:Calendar'));
if ((int)$exception->is_deleted === 0) {
$this->appendXML($exceptionTag, $_collectionData, $exception);
}
}
}
*/
}
}
/**
* convert contact from xml to libkolab array
*
* @param SimpleXMLElement $data Contact to convert
* @param string $folderid Folder identifier
* @param array $entry Existing entry
*
* @return array
*/
public function toKolab(SimpleXMLElement $data, $folderid, $entry = null)
{
$foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid);
$event = !empty($entry) ? $entry : array();
$config = $this->getFolderConfig($foldername);
$xmlData = $data->children('uri:Calendar');
$event['allday'] = 0;
// Timezone
if (isset($xmlData->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((string)$xmlData->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 = (string) $xmlData->$key;
switch ($name) {
case 'changed':
$value = null;
break;
case 'end':
case 'start':
$value = self::date_to_kolab($value, $timezone);
break;
case 'sensitivity':
$map = array_flip($this->sensitivityMap);
$value = $map[$value];
break;
}
$this->setKolabDataItem($event, $name, $value);
}
// Event description
$event['description'] = $this->getBody($data, $xmlData);
// Reminder
// @TODO: should alarms be used when importing event from phone?
if ($config['ALARMS']) {
$event['alarms'] = $this->to_kolab_alarm((string)$xmlData->Reminder, $event);
}
$event['attendees'] = array();
$event['categories'] = array();
// Categories
if (isset($xmlData->Categories)) {
foreach ($xmlData->Categories->children as $category) {
$event['categories'][] = (string) $category;
}
}
// Organizer
$name = (string) $xmlData->OrganizerName;
$email = (string) $xmlData->OrganizerEmail;
if ($name || $email) {
$event['attendees'][] = array(
'role' => 'ORGANIZER',
'name' => (string) $name,
'email' => (string) $email,
);
}
// Attendees
if (isset($xmlData->Attendees)) {
foreach ($xmlData->Attendees->children 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' => (string) $attendee->Name,
'email' => (string) $attendee->Email,
);
}
}
// recurrence
$event['recurrence'] = array();
if (isset($xmlData->Recurrence) && isset($xmlData->Recurrence->Type)) {
$type = (int)$xmlData->Recurrence->Type;
$rrule['FREQ'] = array_search($type, $this->recurTypeMap);
switch ($type) {
case self::RECUR_TYPE_DAILY:
break;
case self::RECUR_TYPE_WEEKLY:
$rrule['BYDAY'] = $this->bitmask2day((int)$xmlData->Recurrence->DayOfWeek);
break;
case self::RECUR_TYPE_MONTHLY:
$rrule['BYMONTHDAY'] = (int)$xmlData->Recurrence->DayOfMonth;
break;
case self::RECUR_TYPE_MONTHLY_DAYN:
$week = (int)$xmlData->Recurrence->WeekOfMonth;
$day = (int)$xmlData->Recurrence->DayOfWeek;
$byDay = $week == 5 ? -1 : $week;
$byDay .= $this->bitmask2day($day);
$rrule['BYDAY'] = $byDay;
break;
case self::RECUR_TYPE_YEARLY:
$rrule['BYMONTH'] = (int)$xmlData->Recurrence->MonthOfYear;
$rrule['BYMONTHDAY'] = (int)$xmlData->Recurrence->DayOfMonth;
break;
case self::RECUR_TYPE_YEARLY_DAYN:
$rrule['BYMONTH'] = (int)$xmlData->Recurrence->MonthOfYear;
$week = (int)$xmlData->Recurrence->WeekOfMonth;
$day = (int)$xmlData->Recurrence->DayOfWeek;
$byDay = $week == 5 ? -1 : $week;
$byDay .= $this->bitmask2day($day);
$rrule['BYDAY'] = $byDay;
break;
}
$rrule['INTERVAL'] = isset($xmlData->Recurrence->Interval) ? (int)$xmlData->Recurrence->Interval : 1;
if (isset($xmlData->Recurrence->Until)) {
$rrule['UNTIL'] = $this->date_to_kolab((string)$xmlData->Recurrence->Until, $timezone);
}
$event['recurrence'] = $rrule;
/*
// handle exceptions from recurrence
if (isset($xmlData->Exceptions)) {
$exdates = new Tinebase_Record_RecordSet('Calendar_Model_Event');
foreach ($xmlData->Exceptions->Exception as $exception) {
$eventException = new Calendar_Model_Event(array(
'recurid' => new Tinebase_DateTime((string)$exception->ExceptionStartTime)
));
if ((int)$exception->Deleted === 0) {
$eventException->is_deleted = false;
$this->toTineModel($exception, $eventException);
} else {
$eventException->is_deleted = true;
}
$exdates->addRecord($eventException);
}
$event->exdate = $exdates;
}
*/
}
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'];
}
/**
* Converts string of days (TU,TH) to bitmask used by ActiveSync
*
* @param string $days
*
* @return int
*/
protected function day2bitmask($days)
{
$days = explode(',', $days);
$result = 0;
foreach ($days as $day) {
$result = $result + $this->recurDayMap[$day];
}
return $result;
}
/**
* Convert bitmask used by ActiveSync to string of days (TU,TH)
*
* @param int $days
*
* @return string
*/
protected function bitmask2day($days)
{
$days_arr = array();
for ($bitmask = 1; $bitmask <= self::RECUR_DOW_SATURDAY; $bitmask = $bitmask << 1) {
$dayMatch = $days & $bitmask;
if ($dayMatch === $bitmask) {
$days_arr[] = array_search($bitmask, $this->recurDayMap);
}
}
$result = implode(',', $days_arr);
return $result;
}
}

File Metadata

Mime Type
text/x-php
Expires
Wed, Jul 8, 11:32 PM (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1052246
Default Alt Text
kolab_sync_data_calendar.php (27 KB)

Event Timeline