Projects
Kolab:16
kolab-syncroton
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 3
View file
kolab-syncroton.spec
Changed
@@ -31,7 +31,7 @@ Name: kolab-syncroton Version: 2.3.3 -Release: 0.20160222.git%{?dist} +Release: 1%{?dist} Summary: ActiveSync for Kolab Groupware Group: Applications/Internet @@ -209,6 +209,9 @@ %attr(0770,%{httpd_user},%{httpd_group}) %{_var}/log/%{name} %changelog +* Tue Nov 15 2016 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 2.3.3-1 +- Release of version 2.3.3 + * Fri Mar 27 2015 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 2.3.2-1 - Release of version 2.3.2, see;
View file
debian.changelog
Changed
@@ -1,4 +1,10 @@ -kolab-syncroton (2.3.3~dev20160222-0~kolab1) unstable; urgency=low +kolab-syncroton (2.3.3-0~kolab1) unstable; urgency=low + + * Release of version 2.3.3 + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Tue, 15 Nov 2016 15:13:40 +0200 + +kolab-syncroton (2.3.3~dev20160921-0~kolab1) unstable; urgency=low * Release of version 2.3.2, see:
View file
kolab-syncroton-2.3.3.tar.gz/.arcconfig
Added
@@ -0,0 +1,3 @@ +{ + "phabricator.uri": "https://git.kolab.org" +}
View file
kolab-syncroton-2.3.3.tar.gz/config/config.inc.php.dist
Changed
@@ -83,6 +83,12 @@ // 32 - all folders in shared namespace $config['activesync_init_subscriptions'] = 0; +// Defines blacklist of devices (device type strings) that do not support folder hierarchies. +// When set to an array folder hierarchies are used on all devices not listed here. +// When set to null an old whitelist approach will be used where we do opposite +// action and enable folder hierarchies only on device types known to support it. +$config['activesync_multifolder_blacklist'] = null; + // Enables adding sender name in the From: header of send email // when a device uses email address only (e.g. iOS devices) $config['activesync_fix_from'] = false;
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Roundcube/rcube.php
Changed
@@ -199,23 +199,8 @@ return false; } - $this->memcache = new Memcache; - $this->mc_available = 0; - - // add all configured hosts to pool - $pconnect = $this->config->get('memcache_pconnect', true); - foreach ($this->config->get('memcache_hosts', array()) as $host) { - if (substr($host, 0, 7) != 'unix://') { - list($host, $port) = explode(':', $host); - if (!$port) $port = 11211; - } - else { - $port = 0; - } - - $this->mc_available += intval($this->memcache->addServer( - $host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure'))); - } + $this->memcache = new Memcache; + $this->memcache_init(); // test connection and failover (will result in $this->mc_available == 0 on complete failure) $this->memcache->increment('__CONNECTIONTEST__', 1); // NOP if key doesn't exist @@ -230,6 +215,31 @@ /** + * Get global handle for memcache access + * + * @return object Memcache + */ + protected function memcache_init() + { + $this->mc_available = 0; + + // add all configured hosts to pool + $pconnect = $this->config->get('memcache_pconnect', true); + foreach ($this->config->get('memcache_hosts', array()) as $host) { + if (substr($host, 0, 7) != 'unix://') { + list($host, $port) = explode(':', $host); + if (!$port) $port = 11211; + } + else { + $port = 0; + } + + $this->mc_available += intval($this->memcache->addServer( + $host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure'))); + } + } + + /** * Callback for memcache failure */ public function memcache_failure($host, $port) @@ -1038,6 +1048,40 @@ /** + * When you're going to sleep the script execution for a longer time + * it is good to close all external connections (sql, memcache, SMTP, IMAP). + * + * No action is required on wake up, all connections will be + * re-established automatically. + */ + public function sleep() + { + foreach ($this->caches as $cache) { + if (is_object($cache)) { + $cache->close(); + } + } + + if ($this->storage) { + $this->storage->close(); + } + + if ($this->db) { + $this->db->closeConnection(); + } + + if ($this->memcache) { + $this->memcache->close(); + // after close() need to re-init memcache + $this->memcache_init(); + } + + if ($this->smtp) { + $this->smtp->disconnect(); + } + } + + /** * Quote a given string. * Shortcut function for rcube_utils::rep_specialchars_output() *
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Roundcube/rcube_cache.php
Changed
@@ -242,6 +242,11 @@ } $this->write_index(); + + $this->index = null; + $this->cache = array(); + $this->cache_sums = array(); + $this->cache_changes = array(); } @@ -609,13 +614,15 @@ $this->max_packet = min($value, $this->max_packet) - 2000; } else if ($this->type == 'memcache') { - $stats = $this->db->getStats(); - $remaining = $stats['limit_maxbytes'] - $stats['bytes']; - $this->max_packet = min($remaining / 5, $this->max_packet); + if ($stats = $this->db->getStats()) { + $remaining = $stats['limit_maxbytes'] - $stats['bytes']; + $this->max_packet = min($remaining / 5, $this->max_packet); + } } else if ($this->type == 'apc' && function_exists('apc_sma_info')) { - $stats = apc_sma_info(); - $this->max_packet = min($stats['avail_mem'] / 5, $this->max_packet); + if ($stats = apc_sma_info()) { + $this->max_packet = min($stats['avail_mem'] / 5, $this->max_packet); + } } }
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Roundcube/rcube_cache_shared.php
Changed
@@ -236,6 +236,11 @@ } $this->write_index(); + + $this->index = null; + $this->cache = array(); + $this->cache_sums = array(); + $this->cache_changes = array(); }
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Roundcube/rcube_db.php
Changed
@@ -779,6 +779,20 @@ } /** + * Terminate database connection. + */ + public function closeConnection() + { + $this->db_connected = false; + $this->db_index = 0; + + // release statement and connection resources + $this->last_result = null; + $this->dbh = null; + $this->dbhs = array(); + } + + /** * Formats input so it can be safely used in a query * * @param mixed $input Value to quote
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Roundcube/rcube_db_oracle.php
Changed
@@ -596,4 +596,18 @@ return $this->last_result = $this->dbh->rollBack(); } + + /** + * Terminate database connection. + */ + public function closeConnection() + { + // release statement and close connection(s) + $this->last_result = null; + foreach ($this->dbhs as $dbh) { + oci_close($dbh); + } + + parent::closeConnection(); + } }
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Roundcube/rcube_imap.php
Changed
@@ -210,7 +210,9 @@ */ public function close() { + $this->connect_done = false; $this->conn->closeConnection(); + if ($this->mcache) { $this->mcache->close(); }
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Backend/ABackend.php
Changed
@@ -26,8 +26,8 @@ protected $_tablePrefix; - protected $_tableName; - + protected $_tableName; + protected $_modelClassName; protected $_modelInterfaceName; @@ -47,19 +47,19 @@ /** * create new device * - * @param Syncroton_Model_IDevice $_device - * @return Syncroton_Model_IDevice + * @param Syncroton_Model_AEntry $model + * @return Syncroton_Model_AEntry */ public function create($model) { if (! $model instanceof $this->_modelInterfaceName) { - throw new InvalidArgumentException('$model must be instanace of ' . $this->_modelInterfaceName); + throw new InvalidArgumentException('$model must be instance of ' . $this->_modelInterfaceName); } $data = $this->_convertModelToArray($model); $data['id'] = sha1(mt_rand(). microtime()); - + $this->_db->insert($this->_tablePrefix . $this->_tableName, $data); return $this->get($data['id']); @@ -68,24 +68,24 @@ /** * convert iteratable object to array * - * @param unknown $model + * @param Syncroton_Model_AEntry $model * @return array */ protected function _convertModelToArray($model) { $data = array(); - foreach ($model as $key => $value) { - if ($value instanceof DateTime) { - $value = $value->format('Y-m-d H:i:s'); - } elseif (is_object($value) && isset($value->id)) { - $value = $value->id; - } - - $data[$this->_fromCamelCase($key)] = $value; + foreach ($model as $key => $value) { + if ($value instanceof DateTime) { + $value = $value->format('Y-m-d H:i:s'); + } elseif (is_object($value) && isset($value->id)) { + $value = $value->id; + } + + $data[$this->_fromCamelCase($key)] = $value; } - return $data; + return $data; } /** @@ -97,6 +97,10 @@ { $id = $id instanceof $this->_modelInterfaceName ? $id->id : $id; + if (empty($id)) { + throw new Syncroton_Exception_NotFound('id can not be empty'); + } + $select = $this->_db->select() ->from($this->_tablePrefix . $this->_tableName) ->where('id = ?', $id); @@ -120,17 +124,17 @@ */ protected function _getObject($data) { - foreach ($data as $key => $value) { + foreach ($data as $key => $value) { unset($data[$key]); - - if (!empty($value) && preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $value)) { # 2012-08-12 07:43:26 - $value = new DateTime($value, new DateTimeZone('utc')); + + if (!empty($value) && preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $value)) { # 2012-08-12 07:43:26 + $value = new DateTime($value, new DateTimeZone('utc')); } - - $data[$this->_toCamelCase($key, false)] = $value; - } - - return new $this->_modelClassName($data); + + $data[$this->_toCamelCase($key, false)] = $value; + } + + return new $this->_modelClassName($data); } /** @@ -152,9 +156,9 @@ */ public function update($model) { - if (! $model instanceof $this->_modelInterfaceName) { - throw new InvalidArgumentException('$model must be instanace of ' . $this->_modelInterfaceName); - } + if (! $model instanceof $this->_modelInterfaceName) { + throw new InvalidArgumentException('$model must be instanace of ' . $this->_modelInterfaceName); + } $data = $this->_convertModelToArray($model); @@ -166,6 +170,18 @@ } /** + * Returns list of user accounts + * + * @param Syncroton_Model_Device $device The device + * + * @return array List of Syncroton_Model_Account objects + */ + public function userAccounts($device) + { + return array(); + } + + /** * convert from camelCase to camel_case * @param string $string * @return string
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Command/FolderCreate.php
Changed
@@ -95,8 +95,10 @@ if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " invalid synckey provided. FolderSync 0 needed."); $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_INVALID_SYNC_KEY)); - } else if (!$this->_folder) { + + } else if (!$this->_folder instanceof Syncroton_Model_Folder) { $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_UNKNOWN_ERROR)); + } else { $this->_syncState->counter++; $this->_syncState->lastsync = $this->_syncTimeStamp;
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Command/FolderSync.php
Changed
@@ -139,7 +139,10 @@ try { // retrieve all folders available in data backend $serverFolders = $dataController->getAllFolders(); - + + // retrieve all folders sent to client + $clientFolders = $this->_folderBackend->getFolderState($this->_device, $class); + if ($this->_syncState->counter > 0) { // retrieve all folders changed since last sync $changedFolders = $dataController->getChangedFolders($this->_syncState->lastsync, $this->_syncTimeStamp); @@ -147,8 +150,8 @@ $changedFolders = array(); } - // retrieve all folders sent to client - $clientFolders = $this->_folderBackend->getFolderState($this->_device, $class); + // only folders which were sent to the client already are allowed to be in $changedFolders + $changedFolders = array_intersect_key($changedFolders, $clientFolders); } catch (Exception $e) { if ($this->_logger instanceof Zend_Log)
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Command/ItemOperations.php
Changed
@@ -94,8 +94,8 @@ $fetchTag->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $fetch['serverId'])); $properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties'); - $dataController - ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch['collectionId'], 'options' => $fetch['options'])), $fetch['serverId']) + $dataController + ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch['collectionId'], 'options' => $fetch['options'])), $fetch['serverId']) ->appendXML($properties, $this->_device); $fetchTag->appendChild($properties); @@ -104,8 +104,8 @@ $fetchTag->appendChild($this->_outputDom->createElementNS('uri:Search', 'LongId', $fetch['longId'])); $properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties'); - $dataController - ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch['longId'], 'options' => $fetch['options'])), $fetch['longId']) + $dataController + ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch['longId'], 'options' => $fetch['options'])), $fetch['longId']) ->appendXML($properties, $this->_device); $fetchTag->appendChild($properties); @@ -134,6 +134,24 @@ $this->_parts[] = $partStream; $fileReference->part = count($this->_parts); + } + + /** + * the client requested a range. But we return the whole file. + * + * That's not correct, but allowed. The server is allowed to overwrite the range. + * + * @todo implement cutting $fileReference->data into pieces + */ + if (isset($fetch['options']['range'])) { + $dataSize = $this->_getDataSize($fileReference->data); + + $total = $this->_outputDom->createElementNS('uri:ItemOperations', 'Total', $dataSize); + $properties->appendChild($total); + + $rangeEnd = $dataSize > 0 ? $dataSize - 1 : 0; + $range = $this->_outputDom->createElementNS('uri:ItemOperations', 'Range', '0-' . $rangeEnd); + $properties->appendChild($range); } $fileReference->appendXML($properties, $this->_device); @@ -176,10 +194,16 @@ return $this->_outputDom; } + /** + * parse fetch request + * + * @param SimpleXMLElement $fetch + * @return array + */ protected function _handleFetch(SimpleXMLElement $fetch) { $fetchArray = array( - 'store' => (string)$fetch->Store, + 'store' => (string)$fetch->Store, 'options' => array() ); @@ -215,7 +239,7 @@ $fetchArray['options']['bodyPreferences'][$type] = array( 'type' => $type ); - + // optional if (isset($bodyPreference->TruncationSize)) { $fetchArray['options']['bodyPreferences'][$type]['truncationSize'] = (int) $bodyPreference->TruncationSize; @@ -227,11 +251,25 @@ } } } + + if (isset($fetch->Options->MIMESupport)){ + $fetchArray['options']['mimeSupport'] = (int) $fetch->Options->MIMESupport; + } + + if (isset($airSyncBase->Range)) { + $fetchArray['options']['range'] = (string) $airSyncBase->Range; + } } return $fetchArray; } + /** + * handle empty folder request + * + * @param SimpleXMLElement $emptyFolderContent + * @return array + */ protected function _handleEmptyFolderContents(SimpleXMLElement $emptyFolderContent) { $folderArray = array( @@ -250,4 +288,22 @@ return $folderArray; } + + /** + * return length of data + * + * @param string|resource $data + * @return number + */ + protected function _getDataSize($data) + { + if (is_resource($data)) { + rewind($data); + fseek($data, 0, SEEK_END); + return ftell($data); + + } else { + return strlen($data); + } + } }
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Command/Ping.php
Changed
@@ -26,6 +26,8 @@ const STATUS_FOLDER_NOT_FOUND = 7; const STATUS_GENERAL_ERROR = 8; + const MAX_PING_INTERVAL = 3540; // 59 minutes limit defined in Activesync protocol spec. + protected $_skipValidatePolicyKey = true; protected $_changesDetected = false; @@ -79,7 +81,7 @@ $this->_device->pingfolder = serialize(array_keys($folders)); } } - + $this->_device->lastping = new DateTime('now', new DateTimeZone('utc')); if ($status == self::STATUS_NO_CHANGES_FOUND) { @@ -113,10 +115,24 @@ $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " Folders to monitor($lifeTime / $intervalStart / $intervalEnd / $status): " . print_r($folders, true)); if ($status === self::STATUS_NO_CHANGES_FOUND) { + $sleepCallback = Syncroton_Registry::getSleepCallback(); + $wakeupCallback = Syncroton_Registry::getWakeupCallback(); + do { // take a break to save battery lifetime + call_user_func($sleepCallback); sleep(Syncroton_Registry::getPingTimeout()); + // make sure the connection is still alive, abort otherwise + if (connection_aborted()) { + if ($this->_logger instanceof Zend_Log) + $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " Exiting on aborted connection"); + exit; + } + + // reconnect external connections, etc. + call_user_func($wakeupCallback); + try { $device = $this->_deviceBackend->get($this->_device->id); } catch (Syncroton_Exception_NotFound $e) { @@ -207,7 +223,7 @@ // break if there are less than PingTimeout + 10 seconds left for the next loop // otherwise the response will be returned after the client has finished his Ping // request already maybe - } while ($secondsLeft > (Syncroton_Registry::getPingTimeout() + 10)); + } while (Syncroton_Server::validateSession() && $secondsLeft > (Syncroton_Registry::getPingTimeout() + 10)); } if ($this->_logger instanceof Zend_Log)
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Command/SendMail.php
Changed
@@ -6,28 +6,29 @@ * @subpackage Command * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 * @copyright Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de) + * @copyright Copyright (c) 2009-2016 Kolab Systems AG (http://kolabsystems.com) * @author Lars Kneschke <l.kneschke@metaways.de> + * @author Aleksander Machniak <machniak@kolabsystems.com> */ /** - * class to handle ActiveSync Sendmail command + * 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 $_defaultNameSpace = 'uri:ComposeMail'; + protected $_documentElement = 'SendMail'; + protected $_mime; protected $_saveInSent; - protected $_source; - protected $_replaceMime = false; - + protected $_source; + protected $_replaceMime = false; + /** - * process the XML file and add, change, delete or fetches data - * - * @return resource + * Process the XML file and add, change, delete or fetches data */ public function handle() { @@ -35,20 +36,20 @@ $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 { + + $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; @@ -61,27 +62,49 @@ } } } - - if ($this->_logger instanceof Zend_Log) - $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " saveInSent: " . (int)$this->_saveInSent); + + 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 + * + * @return void|DOMDocument */ public function getResponse() { $dataController = Syncroton_Data_Factory::factory(Syncroton_Data_Factory::CLASS_EMAIL, $this->_device, $this->_syncTimeStamp); try { - $dataController->sendEmail($this->_mime, $this->_saveInSent); + $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 = new Syncroton_Model_SendMail(array( + $response_type = 'Syncroton_Model_' . $this->_documentElement; + $response = new $response_type(array( 'status' => $ses->getCode(), )); @@ -90,4 +113,13 @@ 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); + } }
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Command/Settings.php
Changed
@@ -62,8 +62,7 @@ if (isset($xml->Oof)) { if (isset($xml->Oof->Get)) { $this->_OofGet = array('bodyType' => $xml->Oof->Get->BodyType); - } - else if (isset($xml->Oof->Set)) { + } else if (isset($xml->Oof->Set)) { $this->_OofSet = new Syncroton_Model_Oof($xml->Oof->Set); } } @@ -113,12 +112,10 @@ if (!empty($this->_OofGet)) { try { $OofGet = $this->_deviceBackend->getOOF($this->_OofGet); - } - catch (Exception $e) { + } catch (Exception $e) { if ($e instanceof Syncroton_Exception_Status) { $OofStatus = $e->getCode(); - } - else { + } else { $OofStatus = Syncroton_Exception_Status::SERVER_ERROR; } @@ -134,17 +131,14 @@ $Get = $Oof->appendChild($this->_outputDom->createElementNS('uri:Settings', 'Get')); $OofGet->appendXML($Get, $this->_device); } - } - else if (!empty($this->_OofSet)) { + } else if (!empty($this->_OofSet)) { try { $this->_deviceBackend->setOOF($this->_OofSet); $OofStatus = self::STATUS_SUCCESS; - } - catch (Exception $e) { + } catch (Exception $e) { if ($e instanceof Syncroton_Exception_Status) { $OofStatus = $e->getCode(); - } - else { + } else { $OofStatus = Syncroton_Exception_Status::SERVER_ERROR; }
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Command/SmartForward.php
Changed
@@ -21,27 +21,10 @@ protected $_documentElement = 'SmartForward'; /** - * this function generates the response for the client - * - * @return void + * Execute email sending method of data controller */ - public function getResponse() + protected function sendMail($dataController) { - $dataController = Syncroton_Data_Factory::factory(Syncroton_Data_Factory::CLASS_EMAIL, $this->_device, $this->_syncTimeStamp); - - try { - $dataController->forwardEmail($this->_source, $this->_mime, $this->_saveInSent, $this->_replaceMime); - } catch (Syncroton_Exception_Status $ses) { - if ($this->_logger instanceof Zend_Log) - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " Sending email failed: " . $ses->getMessage()); - - $response = new Syncroton_Model_SmartForward(array( - 'status' => $ses->getCode(), - )); - - $response->appendXML($this->_outputDom->documentElement, $this->_device); - - return $this->_outputDom; - } + $dataController->forwardEmail($this->_source, $this->_mime, $this->_saveInSent, $this->_replaceMime); } }
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Command/SmartReply.php
Changed
@@ -21,27 +21,10 @@ protected $_documentElement = 'SmartReply'; /** - * this function generates the response for the client - * - * @return void + * Execute email sending method of data controller */ - public function getResponse() + protected function sendMail($dataController) { - $dataController = Syncroton_Data_Factory::factory(Syncroton_Data_Factory::CLASS_EMAIL, $this->_device, $this->_syncTimeStamp); - - try { - $dataController->replyEmail($this->_source, $this->_mime, $this->_saveInSent, $this->_replaceMime); - } catch (Syncroton_Exception_Status $ses) { - if ($this->_logger instanceof Zend_Log) - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " Sending email failed: " . $ses->getMessage()); - - $response = new Syncroton_Model_SmartReply(array( - 'status' => $ses->getCode(), - )); - - $response->appendXML($this->_outputDom->documentElement, $this->_device); - - return $this->_outputDom; - } + $dataController->replyEmail($this->_source, $this->_mime, $this->_saveInSent, $this->_replaceMime); } }
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Command/Sync.php
Changed
@@ -56,7 +56,7 @@ const TRUNCATE_51200 = 6; const TRUNCATE_102400 = 7; const TRUNCATE_NOTHING = 8; - + /** * filter types */ @@ -70,7 +70,7 @@ const FILTER_6_MONTHS_BACK = 7; const FILTER_INCOMPLETE = 8; - + protected $_defaultNameSpace = 'uri:AirSync'; protected $_documentElement = 'Sync'; @@ -82,7 +82,7 @@ protected $_collections = array(); protected $_modifications = array(); - + /** * the global WindowSize * @@ -130,12 +130,12 @@ $intervalDiv = 60; $this->_heartbeatInterval = (int)$requestXML->Wait * $intervalDiv; } - + $maxInterval = Syncroton_Registry::getPingInterval(); if ($maxInterval <= 0 || $maxInterval > Syncroton_Server::MAX_HEARTBEAT_INTERVAL) { $maxInterval = Syncroton_Server::MAX_HEARTBEAT_INTERVAL; } - + if ($this->_heartbeatInterval && $this->_heartbeatInterval > $maxInterval) { $sync = $this->_outputDom->documentElement; $sync->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_WAIT_INTERVAL_OUT_OF_RANGE)); @@ -148,11 +148,11 @@ if (!$this->_globalWindowSize || $this->_globalWindowSize > 512) { $this->_globalWindowSize = 512; } - + if ($this->_globalWindowSize > $this->_maxWindowSize) { $this->_globalWindowSize = $this->_maxWindowSize; } - + // load options from lastsynccollection $lastSyncCollection = array('options' => array()); if (!empty($this->_device->lastsynccollection)) { @@ -437,11 +437,23 @@ // continue only if there are changes or no time is left if ($this->_heartbeatInterval > 0) { - $intervalStart = time(); + $intervalStart = time(); + $sleepCallback = Syncroton_Registry::getSleepCallback(); + $wakeupCallback = Syncroton_Registry::getWakeupCallback(); do { // take a break to save battery lifetime + $sleepCallback(); sleep(Syncroton_Registry::getPingTimeout()); + + // make sure the connection is still alive, abort otherwise + if (connection_aborted()) { + if ($this->_logger instanceof Zend_Log) + $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " Exiting on aborted connection"); + exit; + } + + $wakeupCallback(); $now = new DateTime(null, new DateTimeZone('utc')); @@ -520,7 +532,7 @@ // break if there are less than PingTimeout + 10 seconds left for the next loop // otherwise the response will be returned after the client has finished his Ping // request already maybe - } while (time() - $intervalStart < $this->_heartbeatInterval - (Syncroton_Registry::getPingTimeout() + 10)); + } while (Syncroton_Server::validateSession() && time() - $intervalStart < $this->_heartbeatInterval - (Syncroton_Registry::getPingTimeout() + 10)); } foreach($this->_collections as $collectionData) {
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Model/AXMLEntry.php
Changed
@@ -75,21 +75,18 @@ $element->appendChild($subElement); } $domParrent->appendChild($element); - } - else if ($elementProperties['type'] == 'container' && !empty($elementProperties['multiple'])) { + } else if ($elementProperties['type'] == 'container' && !empty($elementProperties['multiple'])) { foreach ($value as $element) { $container = $domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName)); $element->appendXML($container, $device); $domParrent->appendChild($container); } - } - else if ($elementProperties['type'] == 'none') { + } else if ($elementProperties['type'] == 'none') { if ($value) { $element = $domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName)); $domParrent->appendChild($element); } - } - else { + } else { $element = $domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName)); $this->_appendXMLElement($device, $element, $elementProperties, $value); $domParrent->appendChild($element); @@ -186,16 +183,21 @@ } } - /** - * removed control chars from string which are not allowd in XML values - * - * @param string|array $_dirty - * @return string - */ - protected function _removeControlChars($dirty) + /** + * remove control chars from a string which are not allowed in XML values + * + * @param string $dirty An input string + * @return string Cleaned up string + */ + protected function _removeControlChars($dirty) { - return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', null, $dirty); - } + // Replace non-character UTF-8 sequences that cause XML Parser to fail + // https://git.kolab.org/T1311 + $dirty = str_replace(array("\xEF\xBF\xBE", "\xEF\xBF\xBF"), '', $dirty); + + // Replace ASCII control-characters + return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', '', $dirty); + } /** * enforce >valid< utf-8 encoding @@ -255,13 +257,13 @@ case 'container': if (!empty($elementProperties['multiple'])) { $property = (array) $this->$elementName; + if (isset($elementProperties['class'])) { $property[] = new $elementProperties['class']($xmlElement); } else { $property[] = (string) $xmlElement; } - } - else if (isset($elementProperties['childElement'])) { + } else if (isset($elementProperties['childElement'])) { $property = array(); $childElement = ucfirst($elementProperties['childElement']);
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Registry.php
Changed
@@ -38,6 +38,7 @@ const PING_TIMEOUT = 'ping_timeout'; const PING_INTERVAL = 'ping_interval'; const QUIET_TIME = 'quiet_time'; + const SESSION_VALIDATOR = 'session_validator'; const DATABASE = 'database'; const TRANSACTIONMANAGER = 'transactionmanager'; @@ -47,6 +48,10 @@ const FOLDERBACKEND = 'folderbackend'; const POLICYBACKEND = 'policybackend'; const SYNCSTATEBACKEND = 'syncstatebackend'; + const LOGGERBACKEND = 'loggerBackend'; + + const SLEEP_CALLBACK = 'sleep_callback'; + const WAKEUP_CALLBACK = 'wakeup_callback'; /** * Class name of the singleton registry object. @@ -241,7 +246,7 @@ return self::get(self::FOLDERBACKEND); } - + /** * Return maximum ping interval (HeartbeatInterval) value (in seconds) * @@ -255,6 +260,21 @@ 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 @@ -306,6 +326,62 @@ } /** + * 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
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Server.php
Changed
@@ -106,8 +106,8 @@ $className = 'Syncroton_Command_' . $requestParameters['command']; if(!class_exists($className)) { - if ($this->_logger instanceof Zend_Log) - $this->_logger->crit(__METHOD__ . '::' . __LINE__ . " command not supported: " . $requestParameters['command']); + if ($this->_logger instanceof Zend_Log) + $this->_logger->crit(__METHOD__ . '::' . __LINE__ . " command not supported: " . $requestParameters['command']); header("HTTP/1.1 501 not implemented"); @@ -141,10 +141,11 @@ try { $command = new $className($requestBody, $device, $requestParameters); - $command->handle(); - - $response = $command->getResponse(); - + $response = $command->handle(); + + if (!$response) { + $response = $command->getResponse(); + } } catch (Syncroton_Exception_ProvisioningNeeded $sepn) { if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " provisioning needed"); @@ -189,7 +190,7 @@ } catch (Syncroton_Wbxml_Exception $swe) { if ($this->_logger instanceof Zend_Log) { $this->_logger->err(__METHOD__ . '::' . __LINE__ . " Could not encode output: " . $swe); - $this->_logDomDocument(Zend_Log::ERR, $response, __METHOD__, __LINE__); + $this->_logDomDocument(Zend_Log::WARN, $response, __METHOD__, __LINE__); } header("HTTP/1.1 500 Internal server error"); @@ -329,14 +330,14 @@ if ($length > 0) { $unpacked = unpack('Vstring', fread($stream, $length)); $policyKey = $unpacked['string']; - } + } - // unpack device type + // unpack device type $length = ord(fread($stream, 1)); - if ($length > 0) { + if ($length > 0) { $unpacked = unpack('A' . $length . 'string', fread($stream, $length)); $deviceType = $unpacked['string']; - } + } while (! feof($stream)) { $tag = ord(fread($stream, 1)); @@ -387,23 +388,23 @@ 'attachmentName' => isset($attachmentName) ? $attachmentName : null, 'acceptMultipart' => isset($acceptMultiPart) ? $acceptMultiPart : false ); - } else { + } else { $result = array( 'protocolVersion' => $request->getServer('HTTP_MS_ASPROTOCOLVERSION'), 'command' => $request->getQuery('Cmd'), 'deviceId' => $request->getQuery('DeviceId'), 'deviceType' => $request->getQuery('DeviceType'), 'policyKey' => $request->getServer('HTTP_X_MS_POLICYKEY'), - 'saveInSent' => $request->getQuery('SaveInSent') == 'T', - 'collectionId' => $request->getQuery('CollectionId'), + 'saveInSent' => $request->getQuery('SaveInSent') == 'T', + 'collectionId' => $request->getQuery('CollectionId'), 'itemId' => $request->getQuery('ItemId'), 'attachmentName' => $request->getQuery('AttachmentName'), - 'acceptMultipart' => $request->getServer('HTTP_MS_ASACCEPTMULTIPART') == 'T' + 'acceptMultipart' => $request->getServer('HTTP_MS_ASACCEPTMULTIPART') == 'T' ); } - - $result['userAgent'] = $request->getServer('HTTP_USER_AGENT', $result['deviceType']); - $result['contentType'] = $request->getServer('CONTENT_TYPE'); + + $result['userAgent'] = $request->getServer('HTTP_USER_AGENT', $result['deviceType']); + $result['contentType'] = $request->getServer('CONTENT_TYPE'); return $result; } @@ -437,10 +438,16 @@ 'devicetype' => $requestParameters['deviceType'], 'useragent' => $requestParameters['userAgent'], 'acsversion' => $requestParameters['protocolVersion'], - 'policyId' => Syncroton_Registry::isRegistered(Syncroton_Registry::DEFAULT_POLICY) ? Syncroton_Registry::get(Syncroton_Registry::DEFAULT_POLICY) : null + 'policyId' => Syncroton_Registry::isRegistered(Syncroton_Registry::DEFAULT_POLICY) ? Syncroton_Registry::get(Syncroton_Registry::DEFAULT_POLICY) : null ))); } return $device; } + + public static function validateSession() + { + $validatorFunction = Syncroton_Registry::getSessionValidator(); + return $validatorFunction(); + } }
View file
kolab-syncroton-2.3.3.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage18.php
Changed
@@ -62,4 +62,4 @@ 'SendDisabled' => 0x29, 'RightsManagementInformation' => 0x2b, ); -} \ No newline at end of file +}
View file
kolab-syncroton-2.3.3.tar.gz/lib/kolab_sync.php
Changed
@@ -46,7 +46,7 @@ public $password; const CHARSET = 'UTF-8'; - const VERSION = "2.3.2"; + const VERSION = "2.3.3"; /** @@ -142,8 +142,8 @@ // Save user password for Roundcube Framework $this->password = $_SERVER['PHP_AUTH_PW']; - // Register Syncroton backends - Syncroton_Registry::set('loggerBackend', $this->logger); + // Register Syncroton backends/callbacks + Syncroton_Registry::set(Syncroton_Registry::LOGGERBACKEND, $this->logger); Syncroton_Registry::set(Syncroton_Registry::DATABASE, $this->get_dbh()); Syncroton_Registry::set(Syncroton_Registry::TRANSACTIONMANAGER, kolab_sync_transaction_manager::getInstance()); Syncroton_Registry::set(Syncroton_Registry::DEVICEBACKEND, new kolab_sync_backend_device); @@ -151,6 +151,7 @@ Syncroton_Registry::set(Syncroton_Registry::SYNCSTATEBACKEND, new kolab_sync_backend_state); Syncroton_Registry::set(Syncroton_Registry::CONTENTSTATEBACKEND, new kolab_sync_backend_content); Syncroton_Registry::set(Syncroton_Registry::POLICYBACKEND, new kolab_sync_backend_policy); + Syncroton_Registry::set(Syncroton_Registry::SLEEP_CALLBACK, array($this, 'sleep')); Syncroton_Registry::setContactsDataClass('kolab_sync_data_contacts'); Syncroton_Registry::setCalendarDataClass('kolab_sync_data_calendar'); @@ -203,6 +204,11 @@ if ($auth['kolab_ldap_error']) { self::server_error(); } + + // Close LDAP connection from kolab_auth plugin + if (class_exists('kolab_auth', false)) { + kolab_auth::ldap_close(); + } } else { $auth['pass'] = $password;
View file
kolab-syncroton-2.3.3.tar.gz/lib/kolab_sync_backend.php
Changed
@@ -167,6 +167,9 @@ continue; } + // force numeric folder name to be a string (T1283) + $folder = (string) $folder; + if (!empty($type) && !in_array($folder, $folders)) { continue; } @@ -726,7 +729,9 @@ // ActiveSync expects folder identifiers to be max.64 characters // So we can't use just folder name - if ($name === '' || !is_string($name)) { + $name = (string) $name; + + if ($name === '') { return null; }
View file
kolab-syncroton-2.3.3.tar.gz/lib/kolab_sync_data.php
Changed
@@ -208,7 +208,7 @@ $list = array(); // device supports multiple folders ? - if (in_array(strtolower($this->device->devicetype), $this->ext_devices)) { + if ($this->isMultiFolder()) { // get the folders the user has access to $list = $this->listFolders(); } @@ -243,6 +243,23 @@ } /** + * Returns true if the device supports multiple folders or it was configured so + */ + protected function isMultiFolder() + { + $blacklist = rcube::get_instance()->config->get('activesync_multifolder_blacklist'); + + if (is_array($blacklist)) { + $is_multifolder = !in_array_nocase($this->device->devicetype, $blacklist); + } + else { + $is_multifolder = in_array_nocase($this->device->devicetype, $this->ext_devices); + } + + return $is_multifolder; + } + + /** * Returns default folder for current class type. */ protected function getDefaultFolder() @@ -878,6 +895,17 @@ */ public function hasChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState) { + // Try to detect change in multi-folder mode and throw exception + // so device will re-sync folders hierarchy + // @TODO: this is a temp solution until we have real hierarchy + // changes detection fort Ping/Hartbeat + $is_multifolder = $this->isMultiFolder(); + if (($is_multifolder && $folder->serverId == $this->defaultRootFolder) + || (!$is_multifolder && $folder->type >= 12) + ) { + throw new Syncroton_Exception_NotFound('Folder not found'); + } + try { if ($this->getChangedEntriesCount($folder->serverId, $syncState->lastsync, null, $folder->lastfiltertype)) { return true;
View file
kolab-syncroton-2.3.3.tar.gz/lib/kolab_sync_data_email.php
Changed
@@ -319,8 +319,18 @@ $result['nativeBodyType'] = $message->has_html_part() ? 2 : 1; // Message class - // @TODO: add messageClass suffix for encrypted messages - $result['messageClass'] = 'IPM.Note'; + if ($headers->ctype == 'multipart/signed' + && count($message->attachments) == 1 && $message->attachments[0]->mimetype == 'application/pkcs7-signature' + ) { + $result['messageClass'] = 'IPM.Note.SMIME.MultipartSigned'; + } + else if ($headers->ctype == 'application/pkcs7-mime' || $headers->ctype == 'application/x-pkcs7-mime') { + $result['messageClass'] = 'IPM.Note.SMIME'; + } + else { + $result['messageClass'] = 'IPM.Note'; + } + $result['contentClass'] = 'urn:content-classes:message'; // Categories (Tags) @@ -449,7 +459,7 @@ } // device doesn't support multiple folders - if (!in_array(strtolower($this->device->devicetype), $this->ext_devices)) { + if (!$this->isMultiFolder()) { // We'll return max. one folder of supported type $result = array(); $types = $this->folder_types; @@ -491,7 +501,7 @@ } // device supports multiple folders? - if (in_array(strtolower($this->device->devicetype), $this->ext_devices)) { + if ($this->isMultiFolder()) { if ($list[$folder_id]) { $result[] = $folder_id; }
View file
kolab-syncroton-2.3.3.tar.gz/lib/plugins/kolab_auth/kolab_auth.php
Changed
@@ -770,6 +770,17 @@ } /** + * Close LDAP connection + */ + public static function ldap_close() + { + if (self::$ldap) { + self::$ldap->close(); + self::$ldap = null; + } + } + + /** * Parses LDAP DN string with replacing supported variables. * See kolab_auth_ldap::parse_vars() *
View file
kolab-syncroton.dsc
Changed
@@ -2,7 +2,7 @@ Source: kolab-syncroton Binary: kolab-syncroton Architecture: all -Version: 2.3.3~dev20160222-0~kolab1 +Version: 2.3.3-0~kolab1 Maintainer: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Uploaders: Paul Klos <kolab@klos2day.nl> Homepage: http://www.kolab.org/
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.