/** * the singleton pattern * * @return ActiveSync_TimezoneConverter */ public static function getInstance($_logger = null, $_cache = null) { if (self::$_instance === NULL) { self::$_instance = new ActiveSync_TimezoneConverter($_logger, $_cache); } return self::$_instance; }
/** * (non-PHPdoc) * @see ActiveSync_Frontend_Abstract::toTineModel() */ public function toTineModel(Syncroton_Model_IEntry $data, $entry = null) { if ($entry instanceof Calendar_Model_Event) { $event = $entry; } else { $event = new Calendar_Model_Event(array(), true); } if ($data instanceof Syncroton_Model_Event) { $data->copyFieldsFromParent(); } // Update seq to entries seq to prevent concurrent update $event->seq = $entry['seq']; if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " Event before mapping: " . print_r($event->toArray(), true)); } foreach ($this->_mapping as $syncrotonProperty => $tine20Property) { if (!isset($data->{$syncrotonProperty})) { if ($tine20Property === 'description' && $this->_device->devicetype == Syncroton_Model_Device::TYPE_IPHONE) { // @see #8230: added alarm to event on iOS 6.1 -> description removed // this should be removed when Tine 2.0 / Syncroton supports ghosted properties if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Unsetting description'); } unset($event->{$tine20Property}); } else { if ($tine20Property === 'attendee' && $entry && $this->_device->devicetype === Syncroton_Model_Device::TYPE_IPHONE && $entry->container_id !== $this->_getDefaultContainerId()) { // keep attendees as the are / they were not sent to the device before } else { if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Removing ' . $tine20Property); } $event->{$tine20Property} = null; } } continue; } switch ($tine20Property) { case 'alarms': // handled after switch statement break; case 'attendee': if ($entry && $this->_device->devicetype === Syncroton_Model_Device::TYPE_IPHONE && $entry->container_id !== $this->_getDefaultContainerId()) { // keep attendees as the are / they were not sent to the device before continue; } $newAttendees = array(); foreach ($data->{$syncrotonProperty} as $attendee) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " attendee email " . $attendee->email); } if (isset($attendee->attendeeType) && (isset($this->_attendeeTypeMapping[$attendee->attendeeType]) || array_key_exists($attendee->attendeeType, $this->_attendeeTypeMapping))) { $role = $this->_attendeeTypeMapping[$attendee->attendeeType]; } else { $role = Calendar_Model_Attender::ROLE_REQUIRED; } // AttendeeStatus send only on repsonse if (preg_match('/(?P<firstName>\\S*) (?P<lastNameName>\\S*)/', $attendee->name, $matches)) { $firstName = $matches['firstName']; $lastName = $matches['lastNameName']; } else { $firstName = null; $lastName = $attendee->name; } // @todo handle resources $newAttendees[] = array('userType' => Calendar_Model_Attender::USERTYPE_USER, 'firstName' => $firstName, 'lastName' => $lastName, 'role' => $role, 'email' => $attendee->email); } Calendar_Model_Attender::emailsToAttendee($event, $newAttendees); break; case 'class': $event->{$tine20Property} = $data->{$syncrotonProperty} == 2 ? Calendar_Model_Event::CLASS_PRIVATE : Calendar_Model_Event::CLASS_PUBLIC; break; case 'exdate': // handle exceptions from recurrence $exdates = new Tinebase_Record_RecordSet('Calendar_Model_Event'); foreach ($data->{$syncrotonProperty} as $exception) { if ($exception->deleted == 0) { $eventException = $this->toTineModel($exception); $eventException->last_modified_time = new Tinebase_DateTime($this->_syncTimeStamp); $eventException->recurid = new Tinebase_DateTime($exception->exceptionStartTime); $eventException->is_deleted = false; } else { $eventException = new Calendar_Model_Event(array('recurid' => new Tinebase_DateTime($exception->exceptionStartTime), 'is_deleted' => true)); } $eventException->seq = $entry['seq']; $exdates->addRecord($eventException); } $event->{$tine20Property} = $exdates; break; case 'description': // @todo check $data->$fieldName->Type and convert to/from HTML if needed if ($data->{$syncrotonProperty} instanceof Syncroton_Model_EmailBody) { $event->{$tine20Property} = $data->{$syncrotonProperty}->data; } else { if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Removing description.'); } $event->{$tine20Property} = null; } break; case 'rrule': // handle recurrence if ($data->{$syncrotonProperty} instanceof Syncroton_Model_EventRecurrence && isset($data->{$syncrotonProperty}->type)) { $rrule = new Calendar_Model_Rrule(); switch ($data->{$syncrotonProperty}->type) { case Syncroton_Model_EventRecurrence::TYPE_DAILY: $rrule->freq = Calendar_Model_Rrule::FREQ_DAILY; break; case Syncroton_Model_EventRecurrence::TYPE_WEEKLY: $rrule->freq = Calendar_Model_Rrule::FREQ_WEEKLY; $rrule->byday = $this->_convertBitMaskToDay($data->{$syncrotonProperty}->dayOfWeek); break; case Syncroton_Model_EventRecurrence::TYPE_MONTHLY: $rrule->freq = Calendar_Model_Rrule::FREQ_MONTHLY; $rrule->bymonthday = $data->{$syncrotonProperty}->dayOfMonth; break; case Syncroton_Model_EventRecurrence::TYPE_MONTHLY_DAYN: $rrule->freq = Calendar_Model_Rrule::FREQ_MONTHLY; $week = $data->{$syncrotonProperty}->weekOfMonth; $day = $data->{$syncrotonProperty}->dayOfWeek; $byDay = $week == 5 ? -1 : $week; $byDay .= $this->_convertBitMaskToDay($day); $rrule->byday = $byDay; break; case Syncroton_Model_EventRecurrence::TYPE_YEARLY: $rrule->freq = Calendar_Model_Rrule::FREQ_YEARLY; $rrule->bymonth = $data->{$syncrotonProperty}->monthOfYear; $rrule->bymonthday = $data->{$syncrotonProperty}->dayOfMonth; break; case Syncroton_Model_EventRecurrence::TYPE_YEARLY_DAYN: $rrule->freq = Calendar_Model_Rrule::FREQ_YEARLY; $rrule->bymonth = $data->{$syncrotonProperty}->monthOfYear; $week = $data->{$syncrotonProperty}->weekOfMonth; $day = $data->{$syncrotonProperty}->dayOfWeek; $byDay = $week == 5 ? -1 : $week; $byDay .= $this->_convertBitMaskToDay($day); $rrule->byday = $byDay; break; } $rrule->interval = isset($data->{$syncrotonProperty}->interval) ? $data->{$syncrotonProperty}->interval : 1; if (isset($data->{$syncrotonProperty}->occurrences)) { $rrule->count = $data->{$syncrotonProperty}->occurrences; $rrule->until = null; } else { if (isset($data->{$syncrotonProperty}->until)) { $rrule->count = null; $rrule->until = new Tinebase_DateTime($data->{$syncrotonProperty}->until); } else { $rrule->count = null; $rrule->until = null; } } $event->rrule = $rrule; } break; default: if ($data->{$syncrotonProperty} instanceof DateTime) { $event->{$tine20Property} = new Tinebase_DateTime($data->{$syncrotonProperty}); } else { $event->{$tine20Property} = $data->{$syncrotonProperty}; } break; } } // whole day events ends at 23:59:59 in Tine 2.0 but 00:00 the next day in AS if (isset($event->is_all_day_event) && $event->is_all_day_event == 1) { $event->dtend->subSecond(1); } // decode timezone data if (isset($data->timezone)) { $timeZoneConverter = ActiveSync_TimezoneConverter::getInstance(Tinebase_Core::getLogger(), Tinebase_Core::get(Tinebase_Core::CACHE)); try { $timezone = $timeZoneConverter->getTimezone($data->timezone, Tinebase_Core::getUserTimezone()); $event->originator_tz = $timezone; } catch (ActiveSync_TimezoneNotFoundException $e) { Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . " timezone data not found " . $data->timezone); $event->originator_tz = Tinebase_Core::getUserTimezone(); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " timezone data " . $event->originator_tz); } } $this->_handleAlarms($data, $event); $this->_handleBusyStatus($data, $event); // event should be valid now $event->isValid(); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " eventData " . print_r($event->toArray(), true)); } return $event; }
public function setUp() { $this->_uit = ActiveSync_TimezoneConverter::getInstance(Tinebase_Core::getLogger()); }
public static function getVtimezone($tzName) { $tzinfo = ActiveSync_TimezoneConverter::getInstance()->getOffsetsForTimezone($tzName); $standardOffset = (-1 * $tzinfo['bias'] > 0 ? '+' : '-') . str_pad((string) floor(-1 * $tzinfo['bias'] / 60), 2, 0, STR_PAD_LEFT) . str_pad((string) floor(-1 * $tzinfo['bias'] % 60), 2, 0, STR_PAD_LEFT); $daylightOffset = (-1 * ($tzinfo['bias'] + $tzinfo['daylightBias']) > 0 ? '+' : '-') . str_pad((string) floor(-1 * ($tzinfo['bias'] + $tzinfo['daylightBias']) / 60), 2, 0, STR_PAD_LEFT) . str_pad((string) floor(-1 * ($tzinfo['bias'] + $tzinfo['daylightBias']) % 60), 2, 0, STR_PAD_LEFT); return new qCal_Component_Vtimezone(array('tzid' => $tzName), array(new qCal_Component_Daylight(array('tzoffsetfrom' => $standardOffset, 'tzoffsetto' => $daylightOffset, 'rrule' => "FREQ=YEARLY;BYMONTH={$tzinfo['daylightMonth']};BYDAY=" . ($tzinfo['daylightDay'] < 5 ? $tzinfo['daylightDay'] : '-1') . array_search($tzinfo['daylightDayOfWeek'], Calendar_Model_Rrule::$WEEKDAY_DIGIT_MAP))), new qCal_Component_Standard(array('tzoffsetfrom' => $daylightOffset, 'tzoffsetto' => $standardOffset, 'rrule' => "FREQ=YEARLY;BYMONTH={$tzinfo['standardMonth']};BYDAY=" . ($tzinfo['daylightDay'] < 5 ? $tzinfo['daylightDay'] : '-1') . array_search($tzinfo['standardDayOfWeek'], Calendar_Model_Rrule::$WEEKDAY_DIGIT_MAP))))); }
function getASTimezone($_timezone, $_startDate = null) { $TZconverter = ActiveSync_TimezoneConverter::getInstance(); return $TZconverter->encodeTimezone($_timezone, $_startDate = null); }
/** * convert contact from xml to Calendar_Model_Event * * @todo handle BusyStatus * @param SimpleXMLElement $_data * @return Calendar_Model_Event */ public function toTineModel(SimpleXMLElement $_data, $_entry = null) { if ($_entry instanceof Calendar_Model_Event) { $event = $_entry; } else { $event = new Calendar_Model_Event(array(), true); } $xmlData = $_data->children('uri:Calendar'); $airSyncBase = $_data->children('uri:AirSyncBase'); foreach ($this->_mapping as $fieldName => $value) { switch ($value) { case 'dtend': case 'dtstart': if (isset($xmlData->{$fieldName})) { $event->{$value} = new Tinebase_DateTime((string) $xmlData->{$fieldName}); } else { $event->{$value} = null; } break; default: if (isset($xmlData->{$fieldName})) { $event->{$value} = (string) $xmlData->{$fieldName}; } else { $event->{$value} = null; } break; } } // get body if (version_compare($this->_device->acsversion, '12.0', '>=') === true) { $event->description = isset($airSyncBase->Body) ? (string) $airSyncBase->Body->Data : null; } else { $event->description = isset($xmlData->Body) ? (string) $xmlData->Body : null; } // whole day events ends at 23:59:59 in Tine 2.0 but 00:00 the next day in AS if (isset($xmlData->AllDayEvent) && $xmlData->AllDayEvent == 1) { $event->dtend->subSecond(1); } if (isset($xmlData->Reminder)) { $alarm = clone $event->dtstart; $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(array('alarm_time' => $alarm->subMinute((int) $xmlData->Reminder), 'minutes_before' => (int) $xmlData->Reminder, 'model' => 'Calendar_Model_Event'))); } // decode timezone data if (isset($xmlData->Timezone)) { $timeZoneConverter = ActiveSync_TimezoneConverter::getInstance(Tinebase_Core::getLogger(), Tinebase_Core::get(Tinebase_Core::CACHE)); try { $timezone = $timeZoneConverter->getTimezone((string) $xmlData->Timezone, Tinebase_Core::get(Tinebase_Core::USERTIMEZONE)); $event->originator_tz = $timezone; } catch (ActiveSync_TimezoneNotFoundException $e) { Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . " timezone data not found " . (string) $xmlData->Timezone); $event->originator_tz = Tinebase_Core::get(Tinebase_Core::USERTIMEZONE); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " timezone data " . $event->originator_tz); } } if (!$event->attendee instanceof Tinebase_Record_RecordSet) { $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender'); } if (isset($xmlData->Attendees)) { $newAttendees = array(); foreach ($xmlData->Attendees->Attendee as $attendee) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " attendee email " . $attendee->Email); } if (isset($attendee->AttendeeType) && array_key_exists((int) $attendee->AttendeeType, $this->_attendeeTypeMapping)) { $role = $this->_attendeeTypeMapping[(int) $attendee->AttendeeType]; } else { $role = Calendar_Model_Attender::ROLE_REQUIRED; } // AttendeeStatus send only on repsonse if (preg_match('/(?P<firstName>\\S*) (?P<lastNameName>\\S*)/', (string) $attendee->Name, $matches)) { $firstName = $matches['firstName']; $lastName = $matches['lastNameName']; } else { $firstName = null; $lastName = $attendee->Name; } // @todo handle resources $newAttendees[] = array('userType' => Calendar_Model_Attender::USERTYPE_USER, 'firstName' => $firstName, 'lastName' => $lastName, 'role' => $role, 'email' => (string) $attendee->Email); } Calendar_Model_Attender::emailsToAttendee($event, $newAttendees); } // new event, add current user as participant if ($event->getId() == null) { $selfContactId = Tinebase_Core::getUser()->contact_id; $selfAttender = $event->attendee->filter('user_type', Calendar_Model_Attender::USERTYPE_USER)->filter('user_id', $selfContactId); if (count($selfAttender) == 0) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " added current user as attender for new event "); } $newAttender = new Calendar_Model_Attender(array('user_id' => $selfContactId, 'user_type' => Calendar_Model_Attender::USERTYPE_USER, 'status' => Calendar_Model_Attender::STATUS_ACCEPTED, 'role' => Calendar_Model_Attender::ROLE_REQUIRED)); $event->attendee->addRecord($newAttender); } } if (isset($xmlData->BusyStatus) && ($ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee)) !== null) { if (isset($this->_busyStatusMapping[(string) $xmlData->BusyStatus])) { $ownAttendee->status = $this->_busyStatusMapping[(string) $xmlData->BusyStatus]; } else { $ownAttendee->status = Calendar_Model_Attender::STATUS_NEEDSACTION; } } // handle recurrence if (isset($xmlData->Recurrence) && isset($xmlData->Recurrence->Type)) { $rrule = new Calendar_Model_Rrule(); switch ((int) $xmlData->Recurrence->Type) { case self::RECUR_TYPE_DAILY: $rrule->freq = Calendar_Model_Rrule::FREQ_DAILY; break; case self::RECUR_TYPE_WEEKLY: $rrule->freq = Calendar_Model_Rrule::FREQ_WEEKLY; $rrule->byday = $this->_convertBitMaskToDay((int) $xmlData->Recurrence->DayOfWeek); break; case self::RECUR_TYPE_MONTHLY: $rrule->freq = Calendar_Model_Rrule::FREQ_MONTHLY; $rrule->bymonthday = (int) $xmlData->Recurrence->DayOfMonth; break; case self::RECUR_TYPE_MONTHLY_DAYN: $rrule->freq = Calendar_Model_Rrule::FREQ_MONTHLY; $week = (int) $xmlData->Recurrence->WeekOfMonth; $day = (int) $xmlData->Recurrence->DayOfWeek; $byDay = $week == 5 ? -1 : $week; $byDay .= $this->_convertBitMaskToDay($day); $rrule->byday = $byDay; break; case self::RECUR_TYPE_YEARLY: $rrule->freq = Calendar_Model_Rrule::FREQ_YEARLY; $rrule->bymonth = (int) $xmlData->Recurrence->MonthOfYear; $rrule->bymonthday = (int) $xmlData->Recurrence->DayOfMonth; break; case self::RECUR_TYPE_YEARLY_DAYN: $rrule->freq = Calendar_Model_Rrule::FREQ_YEARLY; $rrule->bymonth = (int) $xmlData->Recurrence->MonthOfYear; $week = (int) $xmlData->Recurrence->WeekOfMonth; $day = (int) $xmlData->Recurrence->DayOfWeek; $byDay = $week == 5 ? -1 : $week; $byDay .= $this->_convertBitMaskToDay($day); $rrule->byday = $byDay; break; } $rrule->interval = isset($xmlData->Recurrence->Interval) ? (int) $xmlData->Recurrence->Interval : 1; if (isset($xmlData->Recurrence->Until)) { $rrule->until = new Tinebase_DateTime((string) $xmlData->Recurrence->Until); // until ends at 23:59:59 in Tine 2.0 but at 00:00:00 in Windows CE (local user time) if ($rrule->until->format('s') == '00') { $rrule->until->addHour(23)->addMinute(59)->addSecond(59); } } else { $rrule->until = null; } $event->rrule = $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; } } else { $event->rrule = null; $event->exdate = null; } if (empty($event->organizer)) { $event->organizer = Tinebase_Core::getUser()->contact_id; } // event should be valid now $event->isValid(); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " eventData " . print_r($event->toArray(), true)); } return $event; }