⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.78
Server IP:
41.128.143.86
Server:
Linux host.raqmix.cloud 6.8.0-1025-azure #30~22.04.1-Ubuntu SMP Wed Mar 12 15:28:20 UTC 2025 x86_64
Server Software:
Apache
PHP Version:
8.3.23
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
share
/
psa-pear
/
pear
/
php
/
Horde
/
ActiveSync
/
Edit File: Device.php
<?php /** * Horde_ActiveSync_Device:: * * @license http://www.horde.org/licenses/gpl GPLv2 * * @copyright 2010-2020 Horde LLC (http://www.horde.org) * @author Michael J Rubinsky <mrubinsk@horde.org> * @package ActiveSync */ /** * Horde_ActiveSync_Device:: Wraps all functionality related to device data. * * @license http://www.horde.org/licenses/gpl GPLv2 * * @copyright 2010-2020 Horde LLC (http://www.horde.org) * @author Michael J Rubinsky <mrubinsk@horde.org> * @package ActiveSync * * @property string $id The device id. * @property string $deviceType The device type string. * @property string $clientType The client name, if available. * @property integer $rwstatus The RemoteWipe status - a * Horde_ActiveSync::RWSTATUS_* constant. * @property string $userAgent The device's user agent string. * @property string $user The userid for the current device * account. * @property array $supported The SUPPORTED data sent from this device. * @property string $policykey The current policykey, if provisioned. * @property array $properties The device properties, sent in * DEVICEINFO, along with any custom * properties set. * @property string $announcedVersion The most last EAS supported versions * announced to the device. * @property integer $multiplex Bitmask describing collections that this * device does not support user created * folders for, therefore all sources must * be multiplexed together. Masks are * the MULTIPLEX_* constants. * @property boolean $blocked True if device has been marked as * blocked. * */ class Horde_ActiveSync_Device { const MODEL = 'Settings:Model'; const IMEI = 'Settings:IMEI'; const NAME = 'Settings:FriendlyName'; const OS = 'Settings:OS'; const OS_LANGUAGE = 'Settings:OSLanguage'; const PHONE_NUMBER = 'Settings:PhoneNumber'; const OPERATOR = 'Settings:MobileOperator'; const VERSION = 'version'; const MULTIPLEX = 'multiplex'; const ANNOUNCED_VERSION = 'announcedVersion'; const BLOCKED = 'blocked'; // Bitwise constants for flagging device must use multiplexed collections. // @since 2.9.0 const MULTIPLEX_CONTACTS = 1; const MULTIPLEX_CALENDAR = 2; const MULTIPLEX_TASKS = 4; const MULTIPLEX_NOTES = 8; const TYPE_IPHONE = 'iphone'; const TYPE_IPOD = 'ipod'; const TYPE_IPAD = 'ipad'; const TYPE_WEBOS = 'webos'; const TYPE_ANDROID = 'android'; const TYPE_BLACKBERRY = 'blackberry'; const TYPE_WP = 'windowsphone'; const TYPE_TOUCHDOWN = 'touchdown'; const TYPE_UNKNOWN = 'unknown'; const TYPE_NINE = 'nine'; const TYPE_GMAIL = 'gmail'; /** * Quirk to specify if the client fails to property ghost the * POOMCONTACTS:Picture field. If this quirk is present, it means we should * add the POOMCONTACTS:Picture field to the SUPPORTED array for this client. */ const QUIRK_NEEDS_SUPPORTED_PICTURE_TAG = 1; /** * iOS sends an empty picture tag on every edit of contacts whose pictures * did not originate on the client itself. */ const QUIRK_INCORRECTLY_SENDS_EMPTY_PICTURE_TAG = 2; /** * These client can support TNEF data without decoding it first. * * @since 2.40.0 */ const QUIRK_SUPPORTS_TNEF = 3; /** * Device properties. * * @var array */ protected $_properties = array(); /** * State handler * * @var Horde_ActiveSync_State_Base */ protected $_state; /** * Dirty flag * * @var array */ protected $_dirty = array(); /** * Flag to indicate self::multiplex was set externally. * * @var boolean */ protected $_multiplexSet = false; /** * Local override/cache of detected clientType. * * @var string */ protected $_clientType; /** * Cache of OS version. * * @var string */ protected $_iOSVersion; /** * Const'r * * @param Horde_ActiveSync_State_Base $state The state driver. * @param array $data The current device data. */ public function __construct(Horde_ActiveSync_State_Base $state, array $data = array()) { $this->_state = $state; $this->_properties = $data; } /** * Getter */ public function &__get($property) { switch ($property) { case self::MULTIPLEX: if (!$this->_multiplexSet && empty($this->_properties['properties'][self::MULTIPLEX])) { $this->_sniffMultiplex(); $this->multiplex = $this->_properties['properties'][self::MULTIPLEX]; $this->save(); } case self::ANNOUNCED_VERSION: case self::BLOCKED: return $this->_properties['properties'][$property]; case 'clientType': if (!isset($this->_clientType)) { $this->_clientType = $this->_getClientType(); } return $this->_clientType; case self::VERSION: if (isset($this->_properties['properties'][self::VERSION])) { return $this->_properties['properties'][self::VERSION]; } break; case self::OS: if (isset($this->_properties['properties'][self::OS])) { return $this->_properties['properties'][self::OS]; } break; case 'properties': if (!isset($this->_properties['properties'])) { $return = array(); return $return; } // Fall through. default: if (isset($this->_properties[$property])) { return $this->_properties[$property]; } } $return = null; return $return; } /** * Setter */ public function __set($property, $value) { switch ($property) { case self::MULTIPLEX: $this->_multiplexSet = true; // fallthrough case self::ANNOUNCED_VERSION: case self::BLOCKED: case self::VERSION: case self::OS: $properties = $this->properties; if (empty($properties)) { $properties = array(); } $properties[$property] = $value; $this->setDeviceProperties($properties); break; case 'clientType': $this->_clientType = $value; break; default: if (!isset($this->_properties[$property]) || $value != $this->_properties[$property]) { $this->_dirty[$property] = true; $this->_properties[$property] = $value; } } } /** * Magic isset */ public function __isset($property) { return !empty($this->_properties[$property]); } /** * Indicates if we need to announce new EAS version string to the client. * If the property is empty, we don't send it since we are sending the * EAS-Version header anyway and this is a new device. * * @param string $supported The current EAS-Version header. * * @return boolean True if we need to send the MS-RP header, otherwise false. */ public function needsVersionUpdate($supported) { if (empty($this->properties[self::ANNOUNCED_VERSION])) { $properties = $this->properties; $properties[self::ANNOUNCED_VERSION] = $supported; $this->setDeviceProperties($properties); return false; } if ($this->properties[self::ANNOUNCED_VERSION] != $supported) { $properties = $this->properties; $properties[self::ANNOUNCED_VERSION] = $supported; $this->setDeviceProperties($properties); return true; } return false; } /** * Returns if the current device is an expected non-provisionable device. * I.e., the client does not support provisioning at all, but should still * be allowed to connect to a server that has provisioning set to Force. * Currently, this only applies to Windows Communication Apps (Outlook 2013). * * @return boolean True if the device should be allowed to connect to a * Forced provision server. False if not. */ public function isNonProvisionable() { // Outlook? The specs say that "Windows Communication Apps" should // provide the 'OS' parameter of the ITEMSETTINGS data equal to 'Windows', // but Outlook 2013 doesn't even send the ITEMSETTINGS command, so we // need to check the userAgent header. Early versions used Microsoft.Outlook, // but after some update it was changed to 'Outlook/15.0' if (strpos($this->deviceType, 'MicrosoftOutlook') !== false || strpos($this->userAgent, 'Outlook') !== false) { return true; } // Don't attempt to provision the Microsoft Connectivity Analyser if ($this->deviceType === 'TestActiveSyncConnectivity') { return true; } return false; } /** * Check if we should enforce provisioning on this device. * * @return boolean */ public function enforceProvisioning() { if (strpos($this->userAgent, 'Android') !== false) { if (preg_match('@EAS[/-]{0,1}([.0-9]{2,})@', $this->userAgent, $matches)) { return $matches[1] > 1.2; } return false; } return !$this->isNonProvisionable(); } /** * Set the device's DEVICEINFO data. * * @param array $data The data array sent from the device. */ public function setDeviceProperties(array $data) { $data = array_merge($this->properties, $data); if (empty($data['userAgent']) && !empty($this->_properties['userAgent'])) { $data['userAgent'] = $this->_properties['userAgent']; } $this->properties = $data; $this->_dirty['properties'] = true; } /** * Return an array of DEVICEINFO data, with keys suitable for displaying. * * @return array */ public function getFormattedDeviceProperties() { $data = array( _("Id") => $this->id, _("Policy Key") => $this->policykey, _("User Agent") => $this->userAgent ); if (!empty($this->properties[self::MODEL])) { $data[_("Model")] = $this->properties[self::MODEL]; } if (!empty($this->properties[self::IMEI])) { $data[_("IMEI")] = $this->properties[self::IMEI]; } if (!empty($this->properties[self::NAME])) { $data[_("Common Name")] = $this->properties[self::NAME]; } if (!empty($this->properties[self::OPERATOR])) { $data[_("Mobile Operator")] = $this->properties[self::OPERATOR]; } if (!empty($this->properties[self::OS])) { $data[_("OS")] = $this->properties[self::OS]; } if (!empty($this->properties[self::OS_LANGUAGE])) { $data[_("OS Language")] = $this->properties[self::OS_LANGUAGE]; } if (!empty($this->properties[self::PHONE_NUMBER])) { $data[_("Phone Number")] = $this->properties[self::PHONE_NUMBER]; } if (!empty($this->properties[self::VERSION])) { $data[_("EAS Version")] = $this->properties[self::VERSION]; } if (!empty($this->properties[self::MULTIPLEX])) { $data[_("Forced Multiplexed Bitmask")] = $this->properties[self::MULTIPLEX]; } return $data; } /** * Return the last time the device issued a SYNC request. * * @return integer The timestamp. */ public function getLastSyncTimestamp() { return $this->_state->getLastSyncTimestamp($this->id, $this->user); } /** * Save the dirty device info data. * * @param boolean $all If true, save all properties (deviceInfo and * deviceProperties). Otherwise, just save dirty * deviceProperties. @since 2.16.0 * @todo For 3.0, make it clearer that deviceInfo is per-user and * deviceProperties is per-device. */ public function save($all = true) { if ($all) { $this->_state->setDeviceInfo($this, $this->_dirty); } if (!empty($this->_dirty['properties'])) { $this->_state->setDeviceProperties($this->properties, $this->id); } $this->_dirty = array(); } /** * Return the major version number of the OS (or client app) as reported * by the client. * * @return integer The version number. */ public function getMajorVersion() { switch (Horde_String::lower($this->clientType)) { case self::TYPE_BLACKBERRY: if (preg_match('/(.+)\/(.+)/', $this->userAgent, $matches)) { return $matches[2]; } break; case self::TYPE_IPOD: case self::TYPE_IPAD: case self::TYPE_IPHONE: if (empty($this->_iOSVersion)) { $this->_getIosVersion(); } if (preg_match('/(\d+)\.(\d+)/', $this->_iOSVersion, $matches)) { return $matches[1]; } break; case self::TYPE_ANDROID: case self::TYPE_NINE: // Most newer Android clients send self::OS, so check that first if (!empty($this->properties[self::OS]) && preg_match('/(\d+)\.(\d+)/', $this->properties[self::OS], $matches)) { return $matches[1]; } // Some newer devices send userAgent like Android/4.3.3-EAS-1.3 if (preg_match('/Android\/(\d+)\.(\d+)/', $this->userAgent, $matches)) { return $matches[1]; } // Older Android/0.3 type userAgent strings. if (preg_match('/(.+)\/(\d+)\.(\d+)/', $this->userAgent, $matches)) { return $matches[2]; } break; case self::TYPE_TOUCHDOWN: if (preg_match('/(.+)\/(\d+)\.(\d+)/', $this->userAgent, $matches)) { return $matches[2]; } break; } return 0; } /** * Detects the iOS version in M.m format and caches locally. */ protected function _getIosVersion() { // First see if we have a newer client that sends the OS version // Newer iOS sends e.g., "iOS 8.2.2" in OS field. if (!empty($this->properties[self::OS]) && preg_match('/\d+\.\d+\.?\d?/', $this->properties[self::OS], $matches)) { if (!empty($matches[0])) { $this->_iOSVersion = $matches[0]; return; } } // Match to a known UserAgent string version. foreach (Horde_ActiveSync_Device_Ios::$VERSION_MAP as $userAgent => $version) { if (preg_match('/\w+\/(' . $userAgent . ')$/', $this->userAgent, $matches)) { $this->_iOSVersion = $version; return; } } } /** * Return the minor version number of the OS (or client app) as reported * by the client. * * @return integer The version number. */ public function getMinorVersion() { switch (Horde_String::lower($this->clientType)) { case self::TYPE_BLACKBERRY: if (preg_match('/(.+)\/(.+)/', $this->userAgent, $matches)) { return $matches[2]; } break; case self::TYPE_IPOD: case self::TYPE_IPAD: case self::TYPE_IPHONE: if (empty($this->_iOSVersion)) { $this->_getIosVersion(); } if (preg_match('/(\d+)\.(\d+)/', $this->_iOSVersion, $matches)) { return $matches[2]; } break; case self::TYPE_ANDROID: // Most newer Android clients send self::OS, so check that first if (!empty($this->properties[self::OS]) && preg_match('/(\d+)\.(\d+)/', $this->properties[self::OS], $matches)) { return $matches[2]; } // Some newer devices send userAgent like Android/4.3.3-EAS-1.3 if (preg_match('/Android\/(\d+)\.(\d+)/', $this->userAgent, $matches)) { return $matches[2]; } // Older Android/0.3 type userAgent strings. if (preg_match('/(.+)\/(\d+)\.(\d+)/', $this->userAgent, $matches)) { return $matches[3]; } break; case self::TYPE_TOUCHDOWN: if (preg_match('/(.+)\/(\d+)\.(\d+)/', $this->userAgent, $matches)) { return $matches[3]; } break; } return 0; } /** * Return the number of hours to offset a POOMCONTACTS:BIRTHDAY * or ANNIVERSARY field in an attempt to work around a bug in the * protocol - the protocol states that "the time portion SHOULD be ignored, * so that synchronizing between different timezones does not change the * date" (MS-ASCNTC 2.2.2.6). However, it appears that next to zero clients * actually honor this. * * * WP: * Devices seem to send the birthdays at the entered date, with * a time of 00:00:00 UTC during standard time and with 01:00:00 UTC * during DST if the client's configured timezone observes it. No idea * what purpose this serves since no timezone data is transmitted for * birthday values. * * iOS: * Seems different based on version. iOS 5+, at least seems to send * the birthday as midnight at the entered date in the device's timezone * then converted to UTC. Some minor issues with offsets being off an * hour or two for some timezones though. * * iOS < 5 sends the birthday time part as the time the birthday * was entered/edited on the device, converted to UTC, so it can't be * trusted at all. The best we can do here is transform the date to * midnight on date_default_timezone() converted to UTC. * * Android: * Lollipop and newer got rid of the stock "Email" app in favor of * GMail. Gmail seems to send birthdays up at 12:00:00 UTC, but doesn't * expect them at that time. It *seems* that sending them down at * 00:00:00 UTC works, but Unfortunately I don't know the version * history here as to if they always did this, so will rely on bug * reports if this is not correct :) * * For legacy android: * * For contacts originating on the SERVER, the following is true: * * Stock 4.3 Takes the down-synched bday value which is assumed to be * UTC, does some magic to it (converts to milliseconds, creates a * gregorian calendar object, then converts to YYYY-MM-DD). When * sending the bday value up, it sends it up as-is. No conversion * to/from UTC or local is done. * * Stock 4.4.x does the above, but before sending the bday value, * validates that it's in a correct format for sending to the server. * This really only affects date data originally entered on the device * for non-stock android clients. * * There is some strange bit of code in Android that adds 1 to the * DAY_OF_MONTH when HOUR_OF_DAY >= 12 in an attempt to "fix" * birthday handling for GMT+n users. See: * https://android.googlesource.com/platform/packages/apps/Exchange/+/32daacdd71b9de8fd5e3f59c37934e3e4a9fa972%5E!/exchange2/src/com/android/exchange/adapter/ContactsSyncAdapter.java * Not sure what to make of it, or why it's not just converted to * local tz when displaying but this probably breaks birthday handling * for people in a few timezones. * * For contacts originating on the CLIENT, the datetime is sent as * 08:00:00 UTC, and this seems to be regardless of the timezone set * in the Android system. * * Given all of this, it makes sense to me to ALWAYS send birthday * data as occuring at 08:00:00 UTC for *native* Android clients. * * BB 10+ expects it at 11:00:00 UTC * * @param Horde_Date $date The date. This should normally be in the local * timezone if encoding the date for the client. * If decoding the date from the client, it will * normally be in UTC. * @param boolean $toEas Convert from local to device if true. * DEFAULT: false * * @return Horde_Date The date of the birthday/anniversary, with * any fixes applied for the current device. The * timezone set in the object will depend on the * client detected, and whether the date is being * encoding or decoding. */ public function normalizePoomContactsDates($date, $toEas = false) { switch (Horde_String::lower($this->clientType)) { case self::TYPE_WP: case 'wp8': // Legacy. Remove in H6. case 'wp': // Legacy. Remove in H6. if ($toEas) { return new Horde_Date($date->format('Y-m-d'), 'UTC'); } $date = new Horde_Date($date->format('Y-m-d')); return $date->setTimezone('UTC'); case self::TYPE_GMAIL: if ($toEas) { return new Horde_Date($date->format('Y-m-d'), 'UTC'); } $date = new Horde_Date($date->format('Y-m-d')); return $date->setTimezone('UTC'); case self::TYPE_ANDROID: // Need to protect against clients that don't send the actual Android // version in the OS field. if (stripos($this->deviceType, 'samsung') === 0) { // Samsung's native Contacts app works differently than stock // Android, always sending as 00:00:00 if ($toEas) { return new Horde_Date($date->format('Y-m-d'), 'UTC'); } $date = new Horde_Date($date->format('Y-m-d')); return $date->setTimezone('UTC'); } if ($this->getMajorVersion() >= 4 && $this->getMajorVersion() <= 10) { if ($toEas) { return new Horde_Date($date->format('Y-m-d 08:00:00'), 'UTC'); } $date = new Horde_Date($date->format('Y-m-d')); return $date->setTimezone('UTC'); } // POOMCONTACTS:BIRTHDAY not really supported in early Android // versions. Return as is. return $date; case self::TYPE_IPAD: case self::TYPE_IPHONE: case self::TYPE_IPOD: if ($this->getMajorVersion() >= 5) { // iOS >= 5 handles it correctly more or less. if ($toEas) { return new Horde_Date($date->format('Y-m-d 00:00:00'), 'UTC'); } $date = new Horde_Date($date->format('Y-m-d')); return $date->setTimezone('UTC'); } if ($toEas) { return new Horde_Date($date->format('Y-m-d'), 'UTC'); } return new Horde_Date($date->format('Y-m-d')); case self::TYPE_NINE: if ($toEas) { return new Horde_Date($date->format('Y-m-d 00:00:00'), 'UTC'); } $date = new Horde_Date($date->format('Y-m-d')); return $date->setTimezone('UTC'); case self::TYPE_BLACKBERRY: if ($toEas) { return new Horde_Date($date->format('Y-m-d 11:00:00'), 'UTC'); } $date = new Horde_Date($date->format('Y-m-d')); return $date->setTimezone('UTC'); case self::TYPE_TOUCHDOWN: case self::TYPE_UNKNOWN: default: return $date; } } /** * Return if this client has the described quirk. * * @param integer $quirk The specified quirk to check for. * * @return boolean True if quirk is present. */ public function hasQuirk($quirk) { switch ($quirk) { case self::QUIRK_NEEDS_SUPPORTED_PICTURE_TAG: return ($this->_isIos() && $this->getMajorVersion() == 4); case self::QUIRK_INCORRECTLY_SENDS_EMPTY_PICTURE_TAG: return ($this->_isIos() && $this->getMajorVersion() >= 8 && $this->getMinorVersion() > 1); case self::QUIRK_SUPPORTS_TNEF: // These clients can support TNEF data naitively. return (strpos($this->deviceType, 'MicrosoftOutlook') !== false || strpos($this->deviceType, 'WindowsOutlook') != false || strpos($this->userAgent, 'Outlook') !== false); default: return false; } } /** * Attempt to determine the *client* application as opposed to the device, * which may or may not be the client. * * @return string The client name. */ protected function _getClientType() { // Differentiate between the deviceType and the client app. if ((!empty($this->properties[self::OS]) && stripos($this->properties[self::OS], 'Android') !== false) || Horde_String::lower($this->deviceType) == self::TYPE_ANDROID) { // We can detect native Android, TouchDown, and Nine. // Moxier does not distinguish itself, so we can't sniff it. if (strpos($this->userAgent, 'TouchDown') !== false) { return self::TYPE_TOUCHDOWN; } else if ($this->_isNine()) { return self::TYPE_NINE; } else if (stripos($this->userAgent, 'Android-Mail') !== false) { // Modern android OS uses GMAIL as the stock client. return self::TYPE_GMAIL; } else if (stripos($this->userAgent, 'Android') !== false) { return $this->deviceType; } else { return self::TYPE_ANDROID; } } else { return $this->deviceType; } } /** * Helper method to sniff out the 9Folders client, "Nine". * @see https://ninefolders.plan.io/track/7048/46b213 for the discussion on * how to sniff out the Nine client. Not the best solution, but it's the one * they decided to use. * * @return boolean True if client is thought to be "Nine". */ protected function _isNine() { if (!ctype_xdigit($this->id)) { return false; } return stripos(pack('H*', $this->id), 'nine') === 0; } /** * Basic sniffing for determining if devices can support non-multiplexed * collections. */ protected function _sniffMultiplex() { $clientType = Horde_String::lower($this->clientType); if ($this->_isIos()) { // iOS seems to support multiple collections for everything except Notes. $this->_properties['properties'][self::MULTIPLEX] = Horde_ActiveSync_Device::MULTIPLEX_NOTES; } else if ($clientType == self::TYPE_ANDROID) { // Special cases: These clients don't support non-multiplexed // collections. Samsung's native client and HTCOnemini2. if (stripos($this->deviceType, 'samsung') === 0 || stripos($this->model, 'HTCOnemini2') === 0 || $this->deviceType == 'HTCOnemini2') { $this->_properties['properties'][self::MULTIPLEX] = Horde_ActiveSync_Device::MULTIPLEX_CONTACTS | Horde_ActiveSync_Device::MULTIPLEX_CALENDAR | Horde_ActiveSync_Device::MULTIPLEX_NOTES | Horde_ActiveSync_Device::MULTIPLEX_TASKS; return; } // Newer GMAIL applications may not send the self::OS value. if (strpos($this->userAgent, 'Android-Mail/7.5') !== false) { $this->_properties['properties'][SELF::MULTIPLEX] = 0; return; } // All android before 4.4 KitKat requires multiplex. KitKat and // Android 5 native supports non-multiplexed calendars only. if (!empty($this->properties[self::OS]) && preg_match('/(\d+\.\d+(\.\d+)*)/', $this->properties[self::OS], $matches) && version_compare($matches[0], '4.4.0') >= 0) { $this->_properties['properties'][self::MULTIPLEX] = Horde_ActiveSync_Device::MULTIPLEX_NOTES | Horde_ActiveSync_Device::MULTIPLEX_CONTACTS | Horde_ActiveSync_Device::MULTIPLEX_TASKS; } else { $this->_properties['properties'][self::MULTIPLEX] = Horde_ActiveSync_Device::MULTIPLEX_CONTACTS | Horde_ActiveSync_Device::MULTIPLEX_CALENDAR | Horde_ActiveSync_Device::MULTIPLEX_NOTES | Horde_ActiveSync_Device::MULTIPLEX_TASKS; } } else if (strpos($this->userAgent, 'MSFT-WP/8.10') !== false) { // Windows Phone 8.10 supports multiple calendars and tasks, but // no contacts. $this->_properties['properties'][self::MULTIPLEX] = Horde_ActiveSync_Device::MULTIPLEX_CONTACTS; } else if (strpos($this->userAgent, 'MSFT-WP/8.0') !== false || $this->deviceType == 'WP8') { // Windows Phone 8.0 seems that only multiple tasklists are // supported. The rest must be multiplexed. $this->_properties['properties'][self::MULTIPLEX] = Horde_ActiveSync_Device::MULTIPLEX_CONTACTS | Horde_ActiveSync_Device::MULTIPLEX_CALENDAR; } else if (strpos($this->userAgent, 'MSFT-PPC') !== false || $this->deviceType == 'PocketPC') { // PocketPC versions seem to not support any user defined // collections at all, though I've only tested on a single HTC device. $this->_properties['properties'][self::MULTIPLEX] = Horde_ActiveSync_Device::MULTIPLEX_CONTACTS | Horde_ActiveSync_Device::MULTIPLEX_CALENDAR | Horde_ActiveSync_Device::MULTIPLEX_NOTES | Horde_ActiveSync_Device::MULTIPLEX_TASKS; } else if (strpos($this->userAgent, 'Outlook/15.0') !== false || strpos($this->userAgent, 'Outlook/16.0') !== false) { // OL2013 and OL2016 do not support multiple contact lists. $this->_properties['properties'][self::MULTIPLEX] = Horde_ActiveSync_Device::MULTIPLEX_CONTACTS; } else { $this->_properties['properties'][self::MULTIPLEX] = 0; } } /** * Return if this client is an iOS device. Different versions require * different checks. * * @return boolean [description] */ protected function _isIos() { // Compare in order of likelyhood / most recent to least recent versions. if (strpos($this->{self::OS}, 'iOS') === 0 || strpos($this->userAgent, 'iOS') === 0 || in_array(Horde_String::lower($this->clientType), array(self::TYPE_IPAD, self::TYPE_IPOD, self::TYPE_IPHONE)) || strpos($this->userAgent, 'Apple-') === 0) { return true; } return false; } public function __toString() { return serialize($this->_properties); } }
Simpan