diff --git a/lib/ext/Syncroton/Command/SendMail.php b/lib/ext/Syncroton/Command/SendMail.php index 3674c1c..e025c97 100644 --- a/lib/ext/Syncroton/Command/SendMail.php +++ b/lib/ext/Syncroton/Command/SendMail.php @@ -1,125 +1,126 @@ * @author Aleksander Machniak */ /** * class to handle ActiveSync SendMail command * * @package Syncroton * @subpackage Command */ class Syncroton_Command_SendMail extends Syncroton_Command_Wbxml { protected $_defaultNameSpace = 'uri:ComposeMail'; protected $_documentElement = 'SendMail'; protected $_mime; protected $_saveInSent; protected $_source; protected $_replaceMime = false; /** * Process the XML file and add, change, delete or fetches data */ public function handle() { - if (!empty($this->_requestParameters['contentType']) && $this->_requestParameters['contentType'] == 'message/rfc822') { + if (isset($this->_requestParameters['contentType']) && + $this->_requestParameters['contentType'] === 'message/rfc822') { $this->_mime = $this->_requestBody; $this->_saveInSent = $this->_requestParameters['saveInSent']; $this->_replaceMime = false; $this->_source = array( 'collectionId' => $this->_requestParameters['collectionId'], 'itemId' => $this->_requestParameters['itemId'], 'instanceId' => null ); } else if ($this->_requestBody) { $xml = simplexml_import_dom($this->_requestBody); $this->_mime = (string) $xml->Mime; $this->_saveInSent = isset($xml->SaveInSentItems); $this->_replaceMime = isset($xml->ReplaceMime); if (isset ($xml->Source)) { if ($xml->Source->LongId) { $this->_source = (string)$xml->Source->LongId; } else { $this->_source = array( 'collectionId' => (string)$xml->Source->FolderId, 'itemId' => (string)$xml->Source->ItemId, 'instanceId' => isset($xml->Source->InstanceId) ? (string)$xml->Source->InstanceId : null ); } } } if (empty($this->_mime)) { if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " Sending email failed: Empty input"); if (version_compare($this->_device->acsversion, '14.0', '<')) { header("HTTP/1.1 400 Invalid content"); die; } $response_type = 'Syncroton_Model_' . $this->_documentElement; $response = new $response_type(array( 'status' => Syncroton_Exception_Status::INVALID_CONTENT, )); $response->appendXML($this->_outputDom->documentElement, $this->_device); return $this->_outputDom; } if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " saveInSent: " . (int)$this->_saveInSent); } /** * this function generates the response for the client * * @return void|DOMDocument */ public function getResponse() { $dataController = Syncroton_Data_Factory::factory(Syncroton_Data_Factory::CLASS_EMAIL, $this->_device, $this->_syncTimeStamp); try { $this->sendMail($dataController); } catch (Syncroton_Exception_Status $ses) { if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " Sending email failed: " . $ses->getMessage()); $response_type = 'Syncroton_Model_' . $this->_documentElement; $response = new $response_type(array( 'status' => $ses->getCode(), )); $response->appendXML($this->_outputDom->documentElement, $this->_device); return $this->_outputDom; } } /** * Execute email sending method of data controller * To be overwritten by SmartForward and SmartReply command handlers */ protected function sendMail($dataController) { $dataController->sendEmail($this->_mime, $this->_saveInSent); } } diff --git a/lib/ext/Syncroton/Command/Wbxml.php b/lib/ext/Syncroton/Command/Wbxml.php index 37819f8..cb36d13 100644 --- a/lib/ext/Syncroton/Command/Wbxml.php +++ b/lib/ext/Syncroton/Command/Wbxml.php @@ -1,222 +1,222 @@ */ /** * abstract class for all commands using wbxml encoded content * * @package Syncroton * @subpackage Command */ abstract class Syncroton_Command_Wbxml implements Syncroton_Command_ICommand { /** * informations about the currently device * * @var Syncroton_Model_Device */ protected $_device; /** * informations about the currently device * * @var Syncroton_Backend_IDevice */ protected $_deviceBackend; /** * informations about the currently device * * @var Syncroton_Backend_IFolder */ protected $_folderBackend; /** * @var Syncroton_Backend_ISyncState */ protected $_syncStateBackend; /** * @var Syncroton_Backend_IContent */ protected $_contentStateBackend; /** * * @var Syncroton_Backend_IPolicy */ protected $_policyBackend; /** * the domDocument containing the xml response from the server * * @var DOMDocument */ protected $_outputDom; /** * the domDocucment containing the xml request from the client * * @var DOMDocument */ protected $_requestBody; /** * the default namespace * * @var string */ protected $_defaultNameSpace; /** * the main xml tag * * @var string */ protected $_documentElement; /** * @var array */ protected $_requestParameters; /** * @var Syncroton_Model_SyncState */ protected $_syncState; protected $_skipValidatePolicyKey = false; /** * timestamp to use for all sync requests * * @var DateTime */ protected $_syncTimeStamp; /** * @var string */ protected $_transactionId; /** * @var string */ protected $_policyKey; /** * @var Zend_Log */ protected $_logger; /** * list of part streams * * @var array */ protected $_parts = array(); /** * list of headers * * @var array */ protected $_headers = array(); /** * the constructor * * @param mixed $requestBody * @param Syncroton_Model_Device $device * @param array $requestParameters */ public function __construct($requestBody, Syncroton_Model_IDevice $device, $requestParameters) { $this->_requestBody = $requestBody; $this->_device = $device; $this->_requestParameters = $requestParameters; $this->_policyKey = isset($requestParameters['policyKey']) ? $requestParameters['policyKey'] : null; $this->_deviceBackend = Syncroton_Registry::getDeviceBackend(); $this->_folderBackend = Syncroton_Registry::getFolderBackend(); $this->_syncStateBackend = Syncroton_Registry::getSyncStateBackend(); $this->_contentStateBackend = Syncroton_Registry::getContentStateBackend(); $this->_policyBackend = Syncroton_Registry::getPolicyBackend(); if (Syncroton_Registry::isRegistered('loggerBackend')) { $this->_logger = Syncroton_Registry::get('loggerBackend'); } $this->_syncTimeStamp = new DateTime(null, new DateTimeZone('UTC')); // set default content type $this->_headers['Content-Type'] = 'application/vnd.ms-sync.wbxml'; if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " sync timestamp: " . $this->_syncTimeStamp->format('Y-m-d H:i:s')); if (isset($this->_defaultNameSpace) && isset($this->_documentElement)) { // Creates an instance of the DOMImplementation class $imp = new DOMImplementation(); // Creates a DOMDocumentType instance $dtd = $imp->createDocumentType('AirSync', "-//AIRSYNC//DTD AirSync//EN", "http://www.microsoft.com/"); // Creates a DOMDocument instance $this->_outputDom = $imp->createDocument($this->_defaultNameSpace, $this->_documentElement, $dtd); $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Syncroton', 'uri:Syncroton'); $this->_outputDom->formatOutput = false; $this->_outputDom->encoding = 'utf-8'; } if ($this->_skipValidatePolicyKey != true) { if (!empty($this->_device->policyId)) { $policy = $this->_policyBackend->get($this->_device->policyId); if((int)$policy->policyKey != (int)$this->_policyKey) { - $this->_outputDom->documentElement->appendChild($this->_outputDom->createElementNS($this->_defaultNameSpace, 'Status', 142)); - - $sepn = new Syncroton_Exception_ProvisioningNeeded(); - $sepn->domDocument = $this->_outputDom; - - throw $sepn; + $this->_outputDom->documentElement->appendChild($this->_outputDom->createElementNS($this->_defaultNameSpace, 'Status', 142)); + + $sepn = new Syncroton_Exception_ProvisioningNeeded(); + $sepn->domDocument = $this->_outputDom; + + throw $sepn; } // should we wipe the mobile phone? if ($this->_device->remotewipe >= Syncroton_Command_Provision::REMOTEWIPE_REQUESTED) { $this->_outputDom->documentElement->appendChild($this->_outputDom->createElementNS($this->_defaultNameSpace, 'Status', 140)); $sepn = new Syncroton_Exception_ProvisioningNeeded(); $sepn->domDocument = $this->_outputDom; throw $sepn; } } } } /** * (non-PHPdoc) * @see Syncroton_Command_ICommand::getHeaders() */ public function getHeaders() { return $this->_headers; } /** * return array of part streams * * @return array */ public function getParts() { return $this->_parts; } } diff --git a/lib/ext/Syncroton/Registry.php b/lib/ext/Syncroton/Registry.php index ae9fe02..0ad94f1 100644 --- a/lib/ext/Syncroton/Registry.php +++ b/lib/ext/Syncroton/Registry.php @@ -1,532 +1,520 @@ offsetExists($index)) { require_once 'Zend/Exception.php'; throw new Zend_Exception("No entry is registered for key '$index'"); } return $instance->offsetGet($index); } /** * returns content state backend * * creates Syncroton_Backend_Content on the fly if not before via * Syncroton_Registry::set(self::CONTENTSTATEBACKEND, $backend); * * @return Syncroton_Backend_IContent */ public static function getContentStateBackend() { if (!self::isRegistered(self::CONTENTSTATEBACKEND)) { self::set(self::CONTENTSTATEBACKEND, new Syncroton_Backend_Content(self::getDatabase())); } return self::get(self::CONTENTSTATEBACKEND); } /** * returns device backend * * creates Syncroton_Backend_Device on the fly if not before via * Syncroton_Registry::set(self::DEVICEBACKEND, $backend); * * @return Syncroton_Backend_IDevice */ public static function getDeviceBackend() { if (!self::isRegistered(self::DEVICEBACKEND)) { self::set(self::DEVICEBACKEND, new Syncroton_Backend_Device(self::getDatabase())); } return self::get(self::DEVICEBACKEND); } /** * returns folder backend * * creates Syncroton_Backend_Folder on the fly if not before via * Syncroton_Registry::set(self::FOLDERBACKEND, $backend); * * @return Syncroton_Backend_IFolder */ public static function getFolderBackend() { if (!self::isRegistered(self::FOLDERBACKEND)) { self::set(self::FOLDERBACKEND, new Syncroton_Backend_Folder(self::getDatabase())); } return self::get(self::FOLDERBACKEND); } /** * Return maximum ping interval (HeartbeatInterval) value (in seconds) * * @return int */ public static function getPingInterval() { if (!self::isRegistered(self::PING_INTERVAL)) { return 3540; // 59 minutes limit defined in Activesync protocol spec. } return self::get(self::PING_INTERVAL); } /** /** * Return maximum ping interval (HeartbeatInterval) value (in seconds) * * @return int */ public static function getMaxPingInterval() { if (!self::isRegistered(self::MAX_PING_INTERVAL)) { return Syncroton_Command_Ping::MAX_PING_INTERVAL; } return self::get(self::MAX_PING_INTERVAL); } /** * return ping timeout * * sleep "ping timeout" seconds between folder checks in Ping and Sync command * * @return int */ public static function getPingTimeout() { if (!self::isRegistered(self::PING_TIMEOUT)) { return 60; } return self::get(self::PING_TIMEOUT); } /** * Return maximum number of collections in Sync/Ping request * * @return int */ public static function getMaxCollections() { return self::get(self::MAX_COLLECTIONS); } /** * returns policy backend * * creates Syncroton_Backend_Policy on the fly if not set before via * Syncroton_Registry::set(self::POLICYBACKEND, $backend); * * @return Syncroton_Backend_ISyncState */ public static function getPolicyBackend() { if (!self::isRegistered(self::POLICYBACKEND)) { self::set(self::POLICYBACKEND, new Syncroton_Backend_Policy(self::getDatabase())); } return self::get(self::POLICYBACKEND); } /** * return quiet time * * don't check folders if last sync was "quiet time" seconds ago * * @return int */ public static function getQuietTime() { if (!self::isRegistered(self::QUIET_TIME)) { return 180; } return self::get(self::QUIET_TIME); } /** * Returns sleep callback function * * This function is used in long running requests like ping & sync to * close connections to external sources (e.g. database) before we * call sleep() to wait some time for next iteration. * Callback should throw exceptions on errors. * * @return callable */ public static function getSleepCallback() { if (!self::isRegistered(self::SLEEP_CALLBACK)) { self::set(self::SLEEP_CALLBACK, function() {}); } return self::get(self::SLEEP_CALLBACK); } /** * Returns wakeup callback function * * This function is used in long running requests like ping & sync to * re-connect to external sources (e.g. database) closed by sleep callback. * Callback should throw exceptions on errors. * * @return callable */ public static function getWakeupCallback() { if (!self::isRegistered(self::WAKEUP_CALLBACK)) { self::set(self::WAKEUP_CALLBACK, function() {}); } return self::get(self::WAKEUP_CALLBACK); } /** * return session validation function * * This function is used in long running requests like ping & sync to * validate user session. Returns false if session is not valid any longer * * @return callable */ public static function getSessionValidator() { if (!self::isRegistered(self::SESSION_VALIDATOR)) { self::set(self::SESSION_VALIDATOR, function() { return true; }); } return self::get(self::SESSION_VALIDATOR); } /** * returns syncstate backend * * creates Syncroton_Backend_SyncState on the fly if not before via * Syncroton_Registry::set(self::SYNCSTATEBACKEND, $backend); * * @return Syncroton_Backend_ISyncState */ public static function getSyncStateBackend() { if (!self::isRegistered(self::SYNCSTATEBACKEND)) { self::set(self::SYNCSTATEBACKEND, new Syncroton_Backend_SyncState(self::getDatabase())); } return self::get(self::SYNCSTATEBACKEND); } /** * setter method, basically same as offsetSet(). * * This method can be called from an object of type Syncroton_Registry, or it * can be called statically. In the latter case, it uses the default * static instance stored in the class. * * @param string $index The location in the ArrayObject in which to store * the value. * @param mixed $value The object to store in the ArrayObject. * @return void */ public static function set($index, $value) { $instance = self::getInstance(); $instance->offsetSet($index, $value); } public static function setDatabase(Zend_Db_Adapter_Abstract $db) { self::set(self::DATABASE, $db); } public static function setCalendarDataClass($className) { if (!class_exists($className)) { throw new InvalidArgumentException('invalid $_className provided'); } self::set(self::CALENDAR_DATA_CLASS, $className); } public static function setContactsDataClass($className) { if (!class_exists($className)) { throw new InvalidArgumentException('invalid $_className provided'); } self::set(self::CONTACTS_DATA_CLASS, $className); } public static function setEmailDataClass($className) { if (!class_exists($className)) { throw new InvalidArgumentException('invalid $_className provided'); } self::set(self::EMAIL_DATA_CLASS, $className); } public static function setNotesDataClass($className) { if (!class_exists($className)) { throw new InvalidArgumentException('invalid $_className provided'); } self::set(self::NOTES_DATA_CLASS, $className); } public static function setTasksDataClass($className) { if (!class_exists($className)) { throw new InvalidArgumentException('invalid $_className provided'); } self::set(self::TASKS_DATA_CLASS, $className); } public static function setGALDataClass($className) { if (!class_exists($className)) { throw new InvalidArgumentException('invalid $_className provided'); } self::set(self::GAL_DATA_CLASS, $className); } public static function setTransactionManager($manager) { self::set(self::TRANSACTIONMANAGER, $manager); } /** * Returns TRUE if the $index is a named value in the registry, * or FALSE if $index was not found in the registry. * * @param string $index * @return boolean */ public static function isRegistered($index) { if (self::$_registry === null) { return false; } return self::$_registry->offsetExists($index); } /** * Constructs a parent ArrayObject with default * ARRAY_AS_PROPS to allow acces as an object * * @param array $array data array * @param integer $flags ArrayObject flags */ public function __construct($array = array(), $flags = parent::ARRAY_AS_PROPS) { parent::__construct($array, $flags); } - - /** - * @param string $index - * @returns mixed - * - * Workaround for http://bugs.php.net/bug.php?id=40442 (ZF-960). - */ - public function offsetExists($index) - { - return array_key_exists($index, $this); - } - }