Projects
Kolab:16
kolab-syncroton-old
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 2
View file
kolab-syncroton.spec
Changed
@@ -17,12 +17,6 @@ %{!?php_inidir: %global php_inidir %{_sysconfdir}/php.d} -%if 0%{?suse_version} < 1 && 0%{?fedora} < 1 && 0%{?rhel} < 7 -%global with_systemd 0 -%else -%global with_systemd 1 -%endif - %if 0%{?suse_version} %global httpd_group www %global httpd_name apache2 @@ -40,10 +34,9 @@ %endif %global _ap_sysconfdir %{_sysconfdir}/%{httpd_name} -%global upstream_version 2.4.2 Name: kolab-syncroton -Version: 2.4.2.36 +Version: 2.3.22 Release: 1%{?dist} Summary: ActiveSync for Kolab Groupware @@ -51,32 +44,49 @@ License: LGPLv2 URL: http://www.syncroton.org -Source0: %{name}-%{upstream_version}.tar.gz +Source0: https://mirror.kolabenterprise.com/pub/releases/%{name}-%{version}.tar.gz Source1: kolab-syncroton.logrotate Source2: plesk.kolab_syncroton.inc.php +Patch0: 0002-Report-INVALID_SOURCE-if-the-move-fails.patch BuildArch: noarch +# Use this build requirement to make sure we are using +# up to date vendorized copies of the plugins. +%if 0%{?plesk} < 1 +BuildRequires: roundcubemail-plugin-kolab_auth >= 3.2 +%endif +BuildRequires: roundcubemail-plugin-kolab_folders >= 3.2 +BuildRequires: roundcubemail-plugin-libcalendaring >= 3.2 +BuildRequires: roundcubemail-plugin-libkolab >= 3.2 + %if 0%{?rhel} < 8 %if 0%{?suse_version} BuildRequires: roundcubemail Requires: php Requires: php-pear-Auth_SASL Requires: php-pear-MDB2_Driver_mysqli +Requires: php-pear-Net_IDNA2 Requires: php-pear-Net_SMTP Requires: php-pear-Net_Socket %else -BuildRequires: roundcubemail >= 1.5 Requires: php-common >= 5.3 Requires: php-pear-Auth-SASL Requires: php-pear-MDB2-Driver-mysqli +Requires: php-pear-Net-IDNA2 Requires: php-pear-Net-SMTP Requires: php-pear-Net-Socket %endif %endif -Requires: roundcubemail Requires: logrotate +Requires: roundcubemail(core) +%if 0%{?plesk} < 1 +Requires: roundcubemail-plugin-kolab_auth >= 3.2 +%endif +Requires: roundcubemail-plugin-kolab_folders >= 3.2 +Requires: roundcubemail-plugin-libcalendaring >= 3.2 +Requires: roundcubemail-plugin-libkolab >= 3.2 %if 0%{?rhel} < 8 Requires: php-kolabformat Requires: php-pear-MDB2 @@ -89,8 +99,8 @@ and Tasks though this package - based on Syncroton technology. %prep -%setup -q -n %{name}-%{upstream_version} -#%patch0 -p1 +%setup -q -n %{name}-%{version} +%patch0 -p1 %build @@ -112,7 +122,6 @@ cp -a lib %{buildroot}/%{_datadir}/%{name}/. cp -a index.php %{buildroot}/%{_datadir}/%{name}/. -cp -a bin %{buildroot}/%{_datadir}/%{name}/. %if 0%{?plesk} cp -a %SOURCE2 %{buildroot}/%{_sysconfdir}/roundcubemail/kolab_syncroton.inc.php @@ -171,7 +180,7 @@ %post if -f "%{php_inidir}/apc.ini" -o -f "%{php_inidir}/apcu.ini" ; then if ! -z "`grep ^apc.enabled=1 %{php_inidir}/apc{,u}.ini 2>/dev/null`" ; then -%if 0%{?with_systemd} +%if 0%{?fedora} > 15 /bin/systemctl condrestart %{httpd_name}.service %else /sbin/service %{httpd_name} condrestart @@ -179,40 +188,8 @@ fi fi -if -f "/usr/lib/systemd/system/php-fpm.service" ; then - /bin/systemctl reload php-fpm.service || : -fi - -if -f "/usr/lib/systemd/system/plesk-php74-fpm.service" ; then - /bin/systemctl reload plesk-php74-fpm.service || : -fi - -if -f "/usr/lib/systemd/system/plesk-php80-fpm.service" ; then - /bin/systemctl reload plesk-php80-fpm.service || : -fi - -if -f "/usr/lib/systemd/system/plesk-php81-fpm.service" ; then - /bin/systemctl reload plesk-php81-fpm.service || : -fi - -if -f "/usr/lib/systemd/system/plesk-php82-fpm.service" ; then - /bin/systemctl reload plesk-php82-fpm.service || : -fi - -if -f "/usr/lib/systemd/system/plesk-php83-fpm.service" ; then - /bin/systemctl reload plesk-php83-fpm.service || : -fi - - - -%if 0%{?plesk} > 0 && 0%{?rhel} == 7 -php="/opt/plesk/php/7.4/bin/php" -%else -php="/usr/bin/php" -%endif - -${php} /usr/share/roundcubemail/bin/updatedb.sh \ - --dir /usr/share/doc/kolab-syncroton/SQL/ \ +/usr/share/roundcubemail/bin/updatedb.sh \ + --dir /usr/share/doc/kolab-syncroton-%{version}/SQL/ \ --package syncroton \ >/dev/null 2>&1 || : @@ -233,15 +210,6 @@ %attr(0770,%{httpd_user},%{httpd_group}) %{_var}/log/%{name} %changelog -* Thu Jul 27 2023 Christian Mollekopf <mollekopf@apheleia-it.ch> - 2.4.2-1 -- Release version 2.4.2 - -* Mon Jul 17 2023 Christian Mollekopf <mollekopf@apheleia-it.ch> - 2.4.1-1 -- Release version 2.4.1 - -* Wed May 10 2023 Christian Mollekopf <mollekopf@apheleia-it.ch> - 2.4.0-1 -- Release version 2.4.0 - * Fri Feb 04 2022 Jeroen van Meeuwen <vanmeeuwen@apheleia-it.ch> - 2.3.22-1 - Release version 2.3.22
View file
0002-Report-INVALID_SOURCE-if-the-move-fails.patch
Added
@@ -0,0 +1,36 @@ +From 0a8e797ea62be331a2530440e45cc1c9edc786ee Mon Sep 17 00:00:00 2001 +From: Christian Mollekopf <mollekopf@apheleia-it.ch> +Date: Tue, 30 Aug 2022 16:21:45 +0200 +Subject: PATCH 2/2 Report INVALID_SOURCE if the move fails + +A nonexistent source message is at least one reason for the failure, +and returning SUCCESS without a destination msgid is clearly not +correct. +May fix an iphone issue where it keeps sending the same move command +over and over. +--- + lib/ext/Syncroton/Command/MoveItems.php | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/lib/ext/Syncroton/Command/MoveItems.php b/lib/ext/Syncroton/Command/MoveItems.php +index 73e57dd..3f89b34 100644 +--- a/lib/ext/Syncroton/Command/MoveItems.php ++++ b/lib/ext/Syncroton/Command/MoveItems.php +@@ -79,9 +79,12 @@ class Syncroton_Command_MoveItems extends Syncroton_Command_Wbxml + $dataController = Syncroton_Data_Factory::factory($sourceFolder->class, $this->_device, $this->_syncTimeStamp); + $newId = $dataController->moveItem($move'srcFldId', $move'srcMsgId', $move'dstFldId'); + ++ if (!$newId) { ++ throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE); ++ } ++ + $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', Syncroton_Command_MoveItems::STATUS_SUCCESS)); +- if ($newId) +- $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'DstMsgId', $newId)); ++ $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'DstMsgId', $newId)); + } catch (Syncroton_Exception_Status $e) { + $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', $e->getCode())); + } catch (Exception $e) { +-- +2.37.1 +
View file
buildtarball.sh
Deleted
@@ -1,22 +0,0 @@ -#!/bin/bash - -set -e - -VERSION=2.4.2 -GIT_REF=master -NAME=kolab-syncroton-$VERSION - -ROOT_DIR=$(pwd) - -rm -Rf /tmp/$NAME -mkdir /tmp/$NAME -cd /tmp/$NAME - -rm -f $NAME.tar.gz - -d "$NAME" && rm -rf "$NAME" -git clone --branch master ssh://git@git.kolab.org/diffusion/S/syncroton.git $NAME -pushd $NAME -git reset --hard $GIT_REF -git archive --prefix=$NAME/ -o "$ROOT_DIR/$NAME.tar.gz" HEAD - -cd "$PWD"
View file
debian.changelog
Changed
@@ -1,33 +1,3 @@ -kolab-syncroton (2.4.2.36-0~kolab1) unstable; urgency=low - - * Release version 2.4.2 - - -- Christian Mollekopf <mollekopf@apheleia-it.ch> Thu, 27 July 2023 15:13:40 +0200 - -kolab-syncroton (2.4.1-0~kolab1) unstable; urgency=low - - * Release version 2.4.1 - - -- Christian Mollekopf <mollekopf@apheleia-it.ch> Mon, 17 July 2023 15:13:40 +0200 - -kolab-syncroton (2.4.0-0~kolab1) unstable; urgency=low - - * Release version 2.4.0 - - -- Christian Mollekopf <mollekopf@apheleia-it.ch> Wed, 10 May 2023 15:13:40 +0200 - -kolab-syncroton (2.3.23-0~kolab1) unstable; urgency=low - - * Release version 2.3.23 - - -- Christian Mollekopf <mollekopf@apheleia-it.ch> Wed, 19 Apr 2023 15:13:40 +0200 - -kolab-syncroton (2.3.22-1~kolab1) unstable; urgency=low - - * Fixed timezone issue - - -- Christian Mollekopf <mollekopf@apheleia-it.ch> Mon, 19 Dec 2022 15:13:40 +0200 - kolab-syncroton (2.3.22-0~kolab1) unstable; urgency=low * Release version 2.3.22
View file
debian.control
Changed
@@ -10,7 +10,19 @@ Package: kolab-syncroton Architecture: all -Depends: roundcubemail-core, +Depends: php-auth-sasl, + php-mail-mime, + php-mdb2 (>= 2.5.0), + php-net-idna2, + php-net-smtp, + php-net-socket, + php-cli | php5-cli, + php-mysql | php5-mysql, + roundcubemail-core, + roundcubemail-plugin-kolab-folders (>= 3.1.12), + roundcubemail-plugin-libcalendaring (>= 3.1.12), + roundcubemail-plugin-libkolab (>= 3.1.12), + zendframework | zend-framework, ${misc:Depends} Description: ActiveSync for Kolab Groupware Kolab Groupware provides ActiveSync for Calendars,
View file
debian.tar.gz/dirs
Changed
@@ -1,6 +1,5 @@ usr/share/kolab-syncroton/config usr/share/kolab-syncroton/lib -usr/share/kolab-syncroton/bin usr/share/kolab-syncroton/lib/ext usr/share/kolab-syncroton/lib/plugins var/lib/kolab-syncroton
View file
debian.tar.gz/install
Changed
@@ -2,7 +2,6 @@ index.php usr/share/kolab-syncroton/ lib/.htaccess usr/share/kolab-syncroton/lib/ lib/*.php usr/share/kolab-syncroton/lib/ -bin/*.php usr/share/kolab-syncroton/bin/ lib/ext/ usr/share/kolab-syncroton/lib/ logs/.htaccess var/log/kolab-syncroton/ temp/.htaccess var/lib/kolab-syncroton/
View file
kolab-syncroton-2.4.2.tar.gz/README.md -> kolab-syncroton-2.3.22.tar.gz/README.md
Changed
@@ -41,33 +41,5 @@ package as document root as well as the /Microsoft-Server-ActiveSync alias. See docs/kolab-syncroton.conf for an example Apache config. - -FOR DEVELOPERS (TESTING) -======================== - -Steps 1-5 from the installation procedure need to be done. - -To check code quality run: `vendor/bin/phpstan analyse` - -To check code style run: `vendor/bin/php-cs-fixer fix --dry-run --diff --verbose` - -To run the Unit test suite goto `tests/` and run `../vendor/bin/phpunit --testsuite=Unit` - -To run the integration tests you have to follow these steps: - -1. Prepare a test account on the Kolab server and add this to config/config.inc.php: -``` -$config'activesync_test_username' = 'user@domain.tld'; -$config'activesync_test_password' = 'password'; -``` - - Don't forget to configure also `imap_host`, `activesync_dav_server` and `activesync_storage`. - All other options should use the default values. - -2. Start the syncroton server: `php -S localhost:8000` - -3. Goto `tests/` and run `../vendor/bin/phpunit --testsuite=Sync` - - 1: http://getcomposer.org 2: https://github.com/roundcube/roundcubemail/blob/master/program/lib/Roundcube/README.md)
View file
kolab-syncroton-2.4.2.tar.gz/composer.json-dist -> kolab-syncroton-2.3.22.tar.gz/composer.json-dist
Changed
@@ -2,28 +2,27 @@ "name": "kolab/syncroton", "description": "The ActiveSync Service for Kolab", "license": "AGPL-3.0+", + "repositories": + { + "type": "vcs", + "url": "https://git.kolab.org/diffusion/PNL/php-net_ldap.git" + } + , "require": { - "php": ">=7.2.0", - "kolab/net_ldap3": "dev-master", + "php": ">=5.4.0", "pear/pear-core-minimal": "~1.10.1", "pear/net_socket": "~1.2.1", "pear/auth_sasl": "~1.1.0", - "pear/http_request2": "~2.5.0", "pear/net_idna2": "~0.2.0", "pear/mail_mime": "~1.10.0", "pear/net_smtp": "~1.7.1", "pear/net_ldap2": "~2.2.0", "pear/net_sieve": "~1.4.0", - "roundcube/rtf-html-php": "~2.1", - "sabre/vobject": "~4.5.1", - "zf1s/zend-controller": "~1.12.20", + "kolab/net_ldap3": "dev-master", "zf1s/zend-json": "~1.12.20", "zf1s/zend-log": "~1.12.20" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.0", - "guzzlehttp/guzzle": "^7.3.0", - "phpstan/phpstan": "^1.2", - "phpunit/phpunit": "^8 || ^9" + "phpunit/phpunit": "^4.8 || ^5.7 || ^6 || ^7" } }
View file
kolab-syncroton-2.4.2.tar.gz/config/config.inc.php.dist -> kolab-syncroton-2.3.22.tar.gz/config/config.inc.php.dist
Changed
@@ -27,7 +27,7 @@ // List of global addressbooks (GAL) // Note: If empty 'autocomplete_addressbooks' setting will be used -$config'activesync_addressbooks' = ; +$config'activesync_addressbooks' = array(); // ActiveSync => Roundcube contact fields map for GAL search /* Default: array( @@ -67,10 +67,10 @@ // List of Roundcube plugins // WARNING: Not all plugins used in Roundcube can be listed here -$config'activesync_plugins' = +$config'activesync_plugins' = array( 'libcalendaring', - 'libkolab', -; + 'libkolab' +); // Defines for how many seconds we'll sleep between every // action for detecting changes in folders. Default: 60 @@ -106,7 +106,7 @@ // 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' = ; +$config'activesync_multifolder_blacklist' = array(); // Blacklist overwrites for specified object type. If set to an array // it will have a precedence over 'activesync_multifolder_blacklist' list only for that type. @@ -114,7 +114,7 @@ // in that case use $config'activesync_multifolder_blacklist_contact' = array('windowsoutlook'); $config'activesync_multifolder_blacklist_mail' = null; $config'activesync_multifolder_blacklist_event' = null; -$config'activesync_multifolder_blacklist_contact' = 'windowsoutlook'; +$config'activesync_multifolder_blacklist_contact' = array('windowsoutlook'); $config'activesync_multifolder_blacklist_note' = null; $config'activesync_multifolder_blacklist_task' = null;
View file
kolab-syncroton-2.4.2.tar.gz/docs/SQL/mysql.initial.sql -> kolab-syncroton-2.3.22.tar.gz/docs/SQL/mysql.initial.sql
Changed
@@ -44,10 +44,8 @@ `displayname` varchar(254) NOT NULL, `type` int(11) NOT NULL, `creation_time` datetime NOT NULL, - `creation_synckey` int(11) NOT NULL DEFAULT '0', `lastfiltertype` int(11) DEFAULT NULL, `supportedfields` longblob DEFAULT NULL, - `resync` tinyint(1) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `device_id--class--folderid` (`device_id`(40),`class`(40),`folderid`(40)), KEY `folderstates::device_id--devices::id` (`device_id`), @@ -61,8 +59,6 @@ `counter` int(11) NOT NULL DEFAULT '0', `lastsync` datetime DEFAULT NULL, `pendingdata` longblob, - `client_id_map` longblob DEFAULT NULL, - `extra_data` longblob DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `device_id--type--counter` (`device_id`,`type`,`counter`), CONSTRAINT `syncroton_synckey::device_id--syncroton_device::id` FOREIGN KEY (`device_id`) REFERENCES `syncroton_device` (`id`) ON DELETE CASCADE ON UPDATE CASCADE @@ -99,6 +95,16 @@ PRIMARY KEY (`id`) ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; +CREATE TABLE IF NOT EXISTS `syncroton_modseq` ( + `device_id` varchar(40) NOT NULL, + `folder_id` varchar(40) NOT NULL, + `synctime` datetime NOT NULL, + `data` longblob, + PRIMARY KEY (`device_id`,`folder_id`,`synctime`), + KEY `syncroton_modseq::device_id` (`device_id`), + CONSTRAINT `syncroton_modseq::device_id--syncroton_device::id` FOREIGN KEY (`device_id`) REFERENCES `syncroton_device` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + CREATE TABLE IF NOT EXISTS `syncroton_relations_state` ( `device_id` varchar(40) NOT NULL, `folder_id` varchar(40) NOT NULL, @@ -117,4 +123,4 @@ PRIMARY KEY(`name`) ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; -INSERT INTO `system` (`name`, `value`) VALUES ('syncroton-version', '2024102300'); +INSERT INTO `system` (`name`, `value`) VALUES ('syncroton-version', '2014101300');
View file
kolab-syncroton-2.3.22.tar.gz/docs/SQL/oracle
Added
+(directory)
View file
kolab-syncroton-2.3.22.tar.gz/docs/SQL/oracle.initial.sql
Added
@@ -0,0 +1,113 @@ +CREATE TABLE "syncroton_policy" ( + "id" varchar(40) NOT NULL PRIMARY KEY, + "name" varchar(255) NOT NULL, + "description" varchar(255) DEFAULT NULL, + "policy_key" varchar(64) NOT NULL, + "json_policy" clob DEFAULT NULL +); + +CREATE TABLE "syncroton_device" ( + "id" varchar(40) NOT NULL PRIMARY KEY, + "deviceid" varchar(64) NOT NULL, + "devicetype" varchar(64) NOT NULL, + "owner_id" varchar(40) NOT NULL, + "acsversion" varchar(40) NOT NULL, + "policykey" varchar(64) DEFAULT NULL, + "policy_id" varchar(40) DEFAULT NULL, + "useragent" varchar(255) DEFAULT NULL, + "imei" varchar(255) DEFAULT NULL, + "model" varchar(255) DEFAULT NULL, + "friendlyname" varchar(255) DEFAULT NULL, + "os" varchar(255) DEFAULT NULL, + "oslanguage" varchar(255) DEFAULT NULL, + "phonenumber" varchar(255) DEFAULT NULL, + "pinglifetime" integer DEFAULT NULL, + "remotewipe" integer DEFAULT 0, + "pingfolder" clob DEFAULT NULL, + "lastsynccollection" clob DEFAULT NULL, + "lastping" timestamp DEFAULT NULL, + "contactsfilter_id" varchar(40) DEFAULT NULL, + "calendarfilter_id" varchar(40) DEFAULT NULL, + "tasksfilter_id" varchar(40) DEFAULT NULL, + "emailfilter_id" varchar(40) DEFAULT NULL +); + +CREATE UNIQUE INDEX "syncroton_device_owner_id_idx" ON "syncroton_device" ("owner_id", "deviceid"); + + +CREATE TABLE "syncroton_folder" ( + "id" varchar(40) NOT NULL PRIMARY KEY, + "device_id" varchar(40) NOT NULL + REFERENCES "syncroton_device" ("id") ON DELETE CASCADE, + "class" varchar(64) NOT NULL, + "folderid" varchar(254) NOT NULL, + "parentid" varchar(254) DEFAULT NULL, + "displayname" varchar(254) NOT NULL, + "type" integer NOT NULL, + "creation_time" timestamp NOT NULL, + "lastfiltertype" integer DEFAULT NULL, + "supportedfields" clob DEFAULT NULL +); + +CREATE UNIQUE INDEX "syncroton_folder_device_id_idx" ON "syncroton_folder" ("device_id", "class", "folderid"); + + +CREATE TABLE "syncroton_synckey" ( + "id" varchar(40) NOT NULL PRIMARY KEY, + "device_id" varchar(40) NOT NULL + REFERENCES "syncroton_device" ("id") ON DELETE CASCADE, + "type" varchar(64) DEFAULT NULL, + "counter" integer DEFAULT 0 NOT NULL, + "lastsync" timestamp DEFAULT NULL, + "pendingdata" clob +); + +CREATE UNIQUE INDEX "syncroton_synckey_device_idx" ON "syncroton_synckey" ("device_id", "type", "counter"); + +CREATE TABLE "syncroton_content" ( + "id" varchar(40) NOT NULL PRIMARY KEY, + "device_id" varchar(40) NOT NULL + REFERENCES "syncroton_device" ("id") ON DELETE CASCADE, + "folder_id" varchar(40) NOT NULL, + "contentid" varchar(128) NOT NULL, + "creation_time" timestamp DEFAULT NULL, + "creation_synckey" integer NOT NULL, + "is_deleted" smallint DEFAULT 0 +); + +CREATE UNIQUE INDEX "syncroton_content_device_idx" ON "syncroton_content" ("device_id", "folder_id", "contentid"); + +CREATE TABLE "syncroton_data" ( + "id" varchar(40) NOT NULL PRIMARY KEY, + "class" varchar(40) NOT NULL, + "folder_id" varchar(40) NOT NULL, + "data" clob +); + +CREATE TABLE "syncroton_data_folder" ( + "id" varchar(40) NOT NULL PRIMARY KEY, + "type" integer NOT NULL, + "name" varchar(255) NOT NULL, + "owner_id" varchar(40) NOT NULL, + "parent_id" varchar(40) DEFAULT NULL +); + +CREATE TABLE "syncroton_modseq" ( + "device_id" varchar(40) NOT NULL + REFERENCES "syncroton_device" ("id") ON DELETE CASCADE, + "folder_id" varchar(40) NOT NULL, + "synctime" timestamp NOT NULL, + "data" clob, + PRIMARY KEY ("device_id", "folder_id", "synctime") +); + +CREATE TABLE "syncroton_relations_state" ( + "device_id" varchar(40) NOT NULL + REFERENCES "syncroton_device" ("id") ON DELETE CASCADE, + "folder_id" varchar(40) NOT NULL, + "synctime" timestamp NOT NULL, + "data" clob, + PRIMARY KEY ("device_id", "folder_id", "synctime") +); + +INSERT INTO "system" ("name", "value") VALUES ('syncroton-version', '2014101300');
View file
kolab-syncroton-2.3.22.tar.gz/docs/SQL/oracle/2014101300.sql
Added
@@ -0,0 +1,8 @@ +CREATE TABLE "syncroton_relations_state" ( + "device_id" varchar(40) NOT NULL + REFERENCES "syncroton_device" ("id") ON DELETE CASCADE, + "folder_id" varchar(40) NOT NULL, + "synctime" timestamp NOT NULL, + "data" clob, + PRIMARY KEY ("device_id", "folder_id", "synctime") +);
View file
kolab-syncroton-2.4.2.tar.gz/index.php -> kolab-syncroton-2.3.22.tar.gz/index.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | |
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/ABackend.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/ABackend.php
Changed
@@ -19,22 +19,22 @@ { /** * the database adapter - * + * * @var Zend_Db_Adapter_Abstract */ protected $_db; - + protected $_tablePrefix; - + protected $_tableName; - + protected $_modelClassName; - + protected $_modelInterfaceName; - + /** * the constructor - * + * * @param Zend_Db_Adapter_Abstract $_db * @param string $_tablePrefix */ @@ -46,7 +46,7 @@ /** * create new device - * + * * @param Syncroton_Model_AEntry $model * @return Syncroton_Model_AEntry */ @@ -55,71 +55,70 @@ if (! $model instanceof $this->_modelInterfaceName) { throw new InvalidArgumentException('$model must be instance of ' . $this->_modelInterfaceName); } - + $data = $this->_convertModelToArray($model); - - $data'id' = sha1(mt_rand() . microtime()); + + $data'id' = sha1(mt_rand(). microtime()); $this->_db->insert($this->_tablePrefix . $this->_tableName, $data); - + return $this->get($data'id'); } - + /** * convert iteratable object to array - * + * * @param Syncroton_Model_AEntry $model * @return array */ protected function _convertModelToArray($model) { - $data = ; - + $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; } - + return $data; } - + /** - * @param string $id - * + * @param string $_id * @throws Syncroton_Exception_NotFound - * @return Syncroton_Model_AEntry + * @return Syncroton_Model_IDevice */ public function get($id) { $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); - + $stmt = $this->_db->query($select); $data = $stmt->fetch(); $stmt = null; # see https://bugs.php.net/bug.php?id=44081 - + if ($data === false) { throw new Syncroton_Exception_NotFound('id not found'); } return $this->_getObject($data); } - + /** * convert array to object - * + * * @param array $data * @return object */ @@ -127,30 +126,30 @@ { 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')); + $value = new DateTime($value, new DateTimeZone('utc')); } - + $data$this->_toCamelCase($key, false) = $value; } - + return new $this->_modelClassName($data); } - + /** * (non-PHPdoc) * @see Syncroton_Backend_IBackend::delete() */ public function delete($id) { - $id = $id instanceof $this->_modelInterfaceName ? $id->id : $id; // @phpstan-ignore-line - - $result = $this->_db->delete($this->_tablePrefix . $this->_tableName, 'id = ?' => $id); - + $id = $id instanceof $this->_modelInterfaceName ? $id->id : $id; + + $result = $this->_db->delete($this->_tablePrefix . $this->_tableName, array('id = ?' => $id)); + return (bool) $result; } - + /** * (non-PHPdoc) * @see Syncroton_Backend_IBackend::update() @@ -160,14 +159,14 @@ if (! $model instanceof $this->_modelInterfaceName) { throw new InvalidArgumentException('$model must be instanace of ' . $this->_modelInterfaceName); } - + $data = $this->_convertModelToArray($model); - - $this->_db->update($this->_tablePrefix . $this->_tableName, $data, - 'id = ?' => $model->id, // @phpstan-ignore-line - ); - - return $this->get($model->id); // @phpstan-ignore-line + + $this->_db->update($this->_tablePrefix . $this->_tableName, $data, array( + 'id = ?' => $model->id + )); + + return $this->get($model->id); } /** @@ -179,7 +178,7 @@ */ public function userAccounts($device) { - return ; + return array(); } /** @@ -190,13 +189,13 @@ protected function _fromCamelCase($string) { $string = lcfirst($string); - + return preg_replace_callback('/(A-Z)/', function ($string) {return '_' . strtolower($string0);}, $string); } - + /** * convert from camel_case to camelCase - * + * * @param string $string * @param bool $ucFirst * @return string @@ -206,7 +205,7 @@ if ($ucFirst === true) { $string = ucfirst($string); } - + return preg_replace_callback('/_(a-z)/', function ($string) {return strtoupper($string1);}, $string); } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/Content.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/Content.php
Changed
@@ -7,7 +7,7 @@ * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 * @author Lars Kneschke <l.kneschke@metaways.de> * @copyright Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de) - * + * */ /** @@ -18,87 +18,83 @@ */ class Syncroton_Backend_Content extends Syncroton_Backend_ABackend implements Syncroton_Backend_IContent { - protected $_tableName = 'content'; - - protected $_modelClassName = 'Syncroton_Model_Content'; - - protected $_modelInterfaceName = 'Syncroton_Model_IContent'; - + protected $_tableName = 'content'; + + protected $_modelClassName = 'Syncroton_Model_Content'; + + protected $_modelInterfaceName = 'Syncroton_Model_IContent'; + /** - * mark state as deleted. The state gets removed finally, + * mark state as deleted. The state gets removed finally, * when the synckey gets validated during next sync. - * - * @param Syncroton_Model_IContent|string $id - * - * @return bool + * + * @param Syncroton_Model_IContent|string $_id */ public function delete($id) { $id = $id instanceof $this->_modelInterfaceName ? $id->id : $id; - - $this->_db->update($this->_tablePrefix . 'content', - 'is_deleted' => 1, - , - 'id = ?' => $id, - ); - - return true; + + $this->_db->update($this->_tablePrefix . 'content', array( + 'is_deleted' => 1 + ), array( + 'id = ?' => $id + )); + } - + /** * @param Syncroton_Model_IDevice|string $deviceId * @param Syncroton_Model_IFolder|string $folderId - * @param string $contentId + * @param string $_contentId * @return Syncroton_Model_IContent */ public function getContentState($deviceId, $folderId, $contentId) { $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId; $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId; - + $select = $this->_db->select() ->from($this->_tablePrefix . 'content') - ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId) - ->where($this->_db->quoteIdentifier('folder_id') . ' = ?', $folderId) - ->where($this->_db->quoteIdentifier('contentid') . ' = ?', $contentId) + ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId) + ->where($this->_db->quoteIdentifier('folder_id') . ' = ?', $folderId) + ->where($this->_db->quoteIdentifier('contentid') . ' = ?', $contentId) ->where($this->_db->quoteIdentifier('is_deleted') . ' = ?', 0); - - $stmt = $this->_db->query($select); - $data = $stmt->fetch(); - $stmt = null; # see https://bugs.php.net/bug.php?id=44081 - - if ($data === false) { - throw new Syncroton_Exception_NotFound('id not found'); - } - - return $this->_getObject($data); + + $stmt = $this->_db->query($select); + $data = $stmt->fetch(); + $stmt = null; # see https://bugs.php.net/bug.php?id=44081 + + if ($data === false) { + throw new Syncroton_Exception_NotFound('id not found'); + } + + return $this->_getObject($data); } - + /** * get array of ids which got send to the client for a given class * * @param Syncroton_Model_IDevice|string $deviceId * @param Syncroton_Model_IFolder|string $folderId - * @param int $syncKey * @return array */ - public function getFolderState($deviceId, $folderId, $syncKey = null) + public function getFolderState($deviceId, $folderId) { $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId; $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId; - + $select = $this->_db->select() ->from($this->_tablePrefix . 'content', 'contentid') - ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId) - ->where($this->_db->quoteIdentifier('folder_id') . ' = ?', $folderId) + ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId) + ->where($this->_db->quoteIdentifier('folder_id') . ' = ?', $folderId) ->where($this->_db->quoteIdentifier('is_deleted') . ' = ?', 0); - + $stmt = $this->_db->query($select); $result = $stmt->fetchAll(Zend_Db::FETCH_COLUMN); - + return $result; } - + /** * reset list of stored id * @@ -109,12 +105,12 @@ { $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId; $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId; - - $where = + + $where = array( $this->_db->quoteInto($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId), - $this->_db->quoteInto($this->_db->quoteIdentifier('folder_id') . ' = ?', $folderId), - ; - + $this->_db->quoteInto($this->_db->quoteIdentifier('folder_id') . ' = ?', $folderId) + ); + $this->_db->delete($this->_tablePrefix . 'content', $where); } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/Device.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/Device.php
Changed
@@ -18,15 +18,15 @@ class Syncroton_Backend_Device extends Syncroton_Backend_ABackend implements Syncroton_Backend_IDevice { protected $_tableName = 'device'; - + protected $_modelClassName = 'Syncroton_Model_Device'; - + protected $_modelInterfaceName = 'Syncroton_Model_IDevice'; - + /** * return device for this user - * - * @param string $ownerId + * + * @param string $userId * @param string $deviceId * @throws Syncroton_Exception_NotFound * @return Syncroton_Model_Device @@ -37,10 +37,10 @@ ->from($this->_tablePrefix . $this->_tableName) ->where('owner_id = ?', $ownerId) ->where('deviceid = ?', $deviceId); - + $stmt = $this->_db->query($select); $data = $stmt->fetch(); - + if ($data === false) { throw new Syncroton_Exception_NotFound('id not found'); } @@ -49,9 +49,9 @@ unset($data$key); $data$this->_toCamelCase($key, false) = $value; } - + $model = new $this->_modelClassName($data); - + return $model; } @@ -64,7 +64,7 @@ */ public function userAccounts($device) { - return ; + return array(); } /** @@ -72,7 +72,7 @@ * * @param array $request Oof/Get request data * - * @return Syncroton_Model_Oof|null Response object or NULL if OOF is not supported + * @return Syncroton_Model_Oof Response object or NULL if OOF is not supported * @throws Syncroton_Exception_Status */ public function getOOF($request)
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/Folder.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/Folder.php
Changed
@@ -7,7 +7,7 @@ * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 * @author Lars Kneschke <l.kneschke@metaways.de> * @copyright Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de) - * + * */ /** @@ -19,11 +19,11 @@ class Syncroton_Backend_Folder extends Syncroton_Backend_ABackend implements Syncroton_Backend_IFolder { protected $_tableName = 'folder'; - + protected $_modelClassName = 'Syncroton_Model_Folder'; - + protected $_modelInterfaceName = 'Syncroton_Model_IFolder'; - + /** * (non-PHPdoc) * @see Syncroton_Backend_IFolder::getFolder() @@ -31,22 +31,22 @@ public function getFolder($deviceId, $folderId) { $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId; - + $select = $this->_db->select() ->from($this->_tablePrefix . $this->_tableName) ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId) - ->where($this->_db->quoteIdentifier('folderid') . ' = ?', $folderId); - + ->where($this->_db->quoteIdentifier('folderid') . ' = ?', $folderId); + $stmt = $this->_db->query($select); $data = $stmt->fetch(); if ($data === false) { throw new Syncroton_Exception_NotFound('id not found'); } - + return $this->_getObject($data); } - + /** * (non-PHPdoc) * @see Syncroton_Backend_IFolder::getFolderState() @@ -54,22 +54,22 @@ public function getFolderState($deviceId, $class) { $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId; - + $select = $this->_db->select() ->from($this->_tablePrefix . $this->_tableName) ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId) - ->where($this->_db->quoteIdentifier('class') . ' = ?', $class); - - $result = ; - + ->where($this->_db->quoteIdentifier('class') . ' = ?', $class); + + $result = array(); + $stmt = $this->_db->query($select); while ($data = $stmt->fetch()) { - $result$data'folderid' = $this->_getObject($data); + $result$data'folderid' = $this->_getObject($data); } - + return $result; } - + /** * (non-PHPdoc) * @see Syncroton_Backend_IFolder::resetState() @@ -77,11 +77,11 @@ public function resetState($deviceId) { $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId; - - $where = - $this->_db->quoteInto($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId), - ; - + + $where = array( + $this->_db->quoteInto($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId) + ); + $this->_db->delete($this->_tablePrefix . $this->_tableName, $where); } @@ -104,15 +104,19 @@ case 'displayName': case 'parentId': return strtolower($string); - + break; + case 'serverId': return 'folderid'; - + break; + default: return parent::_fromCamelCase($string); + + break; } } - + /** * (non-PHPdoc) * @see Syncroton_Backend_ABackend::_toCamelCase() @@ -122,15 +126,20 @@ switch ($string) { case 'displayname': return 'displayName'; - + break; + case 'parentid': return 'parentId'; - + break; + case 'folderid': return 'serverId'; - + break; + default: return parent::_toCamelCase($string, $ucFirst); + + break; } } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/IBackend.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/IBackend.php
Changed
@@ -20,32 +20,32 @@ /** * Create a new device * - * @param Syncroton_Model_IEntry $model - * @return Syncroton_Model_IEntry + * @param Syncroton_Model_IDevice $device + * @return Syncroton_Model_IDevice */ public function create($model); - + /** * Deletes one or more existing devices * - * @param string|Syncroton_Model_IEntry $id - * @return bool + * @param string|array $_id + * @return void */ public function delete($id); - + /** * Return a single device * - * @param string $id - * @return Syncroton_Model_IEntry + * @param string $_id + * @return Syncroton_Model_IDevice */ public function get($id); - + /** * Upates an existing persistent record * - * @param Syncroton_Model_IEntry $model - * @return Syncroton_Model_IEntry + * @param Syncroton_Model_IDevice $_device + * @return Syncroton_Model_IDevice */ public function update($model); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/IContent.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/IContent.php
Changed
@@ -31,10 +31,9 @@ * * @param Syncroton_Model_IDevice|string $_deviceId * @param Syncroton_Model_IFolder|string $_folderId - * @param int $_syncKey * @return array */ - public function getFolderState($_deviceId, $_folderId, $_syncKey = null); + public function getFolderState($_deviceId, $_folderId); /** * reset list of stored id
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/IDevice.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/IDevice.php
Changed
@@ -20,9 +20,8 @@ interface Syncroton_Backend_IDevice extends Syncroton_Backend_IBackend { /** - * @param string $userId - * @param string $deviceId - * + * @param unknown_type $userId + * @param unknown_type $deviceId * @return Syncroton_Model_IDevice */ public function getUserDevice($userId, $deviceId); @@ -41,7 +40,7 @@ * * @param array $request Oof/Get request data * - * @return Syncroton_Model_Oof|null Response object or NULL if OOF is not supported + * @return Syncroton_Model_Oof Response object or NULL if OOF is not supported * @throws Syncroton_Exception_Status */ public function getOOF($request);
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/IFolder.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/IFolder.php
Changed
@@ -32,10 +32,9 @@ * * @param Syncroton_Model_Device|string $deviceId * @param string $class - * @param int $syncKey * @return array */ - public function getFolderState($deviceId, $class, $syncKey); + public function getFolderState($deviceId, $class); /** * delete all stored folderId's for given device
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/ISyncState.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/ISyncState.php
Changed
@@ -19,6 +19,14 @@ interface Syncroton_Backend_ISyncState extends Syncroton_Backend_IBackend { /** + * create new sync state + * + * @param Syncroton_Model_IDevice $model + * @param boolean $keepPreviousSyncState + */ + #public function create($model, $keepPreviousSyncState = true); + + /** * always returns the latest syncstate * * @param Syncroton_Model_IDevice|string $deviceId @@ -27,18 +35,14 @@ */ public function getSyncState($deviceId, $folderId); - public function haveNext($deviceId, $folderId, $syncKey); - - public function resetState($deviceId, $type); + public function resetState($_deviceId, $_type); /** * get array of ids which got send to the client for a given class * - * @param Syncroton_Model_IDevice|string $deviceId - * @param Syncroton_Model_IFolder|string $folderId - * @param int $syncKey - * - * @return Syncroton_Model_SyncState|false + * @param Syncroton_Model_Device $_deviceId + * @param string $_class + * @return array */ - public function validate($deviceId, $folderId, $syncKey); + public function validate($_deviceId, $_syncKey, $_type); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/Policy.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/Policy.php
Changed
@@ -15,57 +15,57 @@ * @package Syncroton * @subpackage Backend */ -class Syncroton_Backend_Policy extends Syncroton_Backend_ABackend +class Syncroton_Backend_Policy extends Syncroton_Backend_ABackend #implements Syncroton_Backend_IDevice { protected $_tableName = 'policy'; - + protected $_modelClassName = 'Syncroton_Model_Policy'; - + protected $_modelInterfaceName = 'Syncroton_Model_IPolicy'; - + /** * convert iteratable object to array - * - * @param Syncroton_Model_IXMLEntry $model + * + * @param unknown $model * @return array */ protected function _convertModelToArray($model) { $policyValues = $model->getProperties('Provision'); - - $policy = ; - + + $policy = array(); + foreach ($policyValues as $policyName) { - if ($model->$policyName !== null) { + if ($model->$policyName !== NULL) { $policy$policyName = $model->$policyName; } - + unset($model->$policyName); } $data = parent::_convertModelToArray($model); - + $data'json_policy' = Zend_Json::encode($policy); - + return $data; } - + /** * convert array to object - * + * * @param array $data * @return object */ protected function _getObject($data) { $policy = Zend_Json::decode($data'json_policy'); - + foreach ($policy as $policyKey => $policyValue) { $data$policyKey = $policyValue; } - + unset($data'json_policy'); - + return parent::_getObject($data); } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Backend/SyncState.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Backend/SyncState.php
Changed
@@ -7,7 +7,7 @@ * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 * @author Lars Kneschke <l.kneschke@metaways.de> * @copyright Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de) - * + * */ /** @@ -18,12 +18,12 @@ */ class Syncroton_Backend_SyncState extends Syncroton_Backend_ABackend implements Syncroton_Backend_ISyncState { - protected $_tableName = 'synckey'; - - protected $_modelClassName = 'Syncroton_Model_SyncState'; - - protected $_modelInterfaceName = 'Syncroton_Model_ISyncState'; + protected $_tableName = 'synckey'; + + protected $_modelClassName = 'Syncroton_Model_SyncState'; + protected $_modelInterfaceName = 'Syncroton_Model_ISyncState'; + /** * (non-PHPdoc) * @see Syncroton_Backend_ISyncState::create() @@ -31,15 +31,15 @@ public function create($model, $keepPreviousSyncState = true) { $state = parent::create($model); - + if ($keepPreviousSyncState !== true) { // remove all other synckeys $this->_deleteOtherStates($state); } - + return $state; } - + /** * (non-PHPdoc) * @see Syncroton_Backend_ABackend::_convertModelToArray() @@ -47,46 +47,46 @@ protected function _convertModelToArray($model) { $model = parent::_convertModelToArray($model); - + $model'pendingdata' = isset($model'pendingdata') && is_array($model'pendingdata') ? Zend_Json::encode($model'pendingdata') : null; - + return $model; } - + /** - * + * * @param Syncroton_Model_ISyncState $state */ protected function _deleteOtherStates(Syncroton_Model_ISyncState $state) { // remove all other synckeys - $where = + $where = array( 'device_id = ?' => $state->deviceId, 'type = ?' => $state->type, - 'counter != ?' => $state->counter, - ; - + 'counter != ?' => $state->counter + ); + $this->_db->delete($this->_tablePrefix . $this->_tableName, $where); - + return true; - + } - + /** * (non-PHPdoc) * @see Syncroton_Backend_ABackend::_getObject() */ - protected function _getObject($data) + protected function _getObject($data) { $model = parent::_getObject($data); - - if ($model->pendingdata !== null) { - $model->pendingdata = Zend_Json::decode($model->pendingdata); + + if ($model->pendingdata !== NULL) { + $model->pendingdata = Zend_Json::decode($model->pendingdata); } - - return $model; + + return $model; } - + /** * (non-PHPdoc) * @see Syncroton_Backend_ISyncState::getSyncState() @@ -95,25 +95,25 @@ { $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId; $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId; - + $select = $this->_db->select() ->from($this->_tablePrefix . $this->_tableName) ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId) - ->where($this->_db->quoteIdentifier('type') . ' = ?', $folderId) + ->where($this->_db->quoteIdentifier('type') . ' = ?', $folderId) ->order('counter DESC') ->limit(1); - - $stmt = $this->_db->query($select); + + $stmt = $this->_db->query($select); $data = $stmt->fetch(); - $stmt = null; # see https://bugs.php.net/bug.php?id=44081 - - if ($data === false) { - throw new Syncroton_Exception_NotFound('id not found'); - } - + $stmt = null; # see https://bugs.php.net/bug.php?id=44081 + + if ($data === false) { + throw new Syncroton_Exception_NotFound('id not found'); + } + return $this->_getObject($data); } - + /** * delete all stored synckeys for given type * @@ -124,92 +124,85 @@ { $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId; $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId; - - $where = + + $where = array( $this->_db->quoteInto($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId), - $this->_db->quoteInto($this->_db->quoteIdentifier('type') . ' = ?', $folderId), - ; - + $this->_db->quoteInto($this->_db->quoteIdentifier('type') . ' = ?', $folderId) + ); + $this->_db->delete($this->_tablePrefix . $this->_tableName, $where); } - + /** * get array of ids which got send to the client for a given class * - * @param Syncroton_Model_IDevice|string $deviceId - * @param Syncroton_Model_IFolder|string $folderId - * @param int $syncKey - * - * @return Syncroton_Model_SyncState|false + * @param Syncroton_Model_IDevice|string $deviceId + * @param Syncroton_Model_IFolder|string $folderId + * @return Syncroton_Model_SyncState */ public function validate($deviceId, $folderId, $syncKey) { $deviceId = $deviceId instanceof Syncroton_Model_IDevice ? $deviceId->id : $deviceId; $folderId = $folderId instanceof Syncroton_Model_IFolder ? $folderId->id : $folderId; - + $select = $this->_db->select() ->from($this->_tablePrefix . $this->_tableName) ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId) - ->where($this->_db->quoteIdentifier('counter') . ' = ?', $syncKey) - ->where($this->_db->quoteIdentifier('type') . ' = ?', $folderId); - + ->where($this->_db->quoteIdentifier('counter') . ' = ?', $syncKey) + ->where($this->_db->quoteIdentifier('type') . ' = ?', $folderId); + $stmt = $this->_db->query($select); $data = $stmt->fetch(); $stmt = null; # see https://bugs.php.net/bug.php?id=44081 - + if ($data === false) { return false; } $state = $this->_getObject($data); - + // check if this was the latest syncKey $select = $this->_db->select() ->from($this->_tablePrefix . $this->_tableName) ->where($this->_db->quoteIdentifier('device_id') . ' = ?', $deviceId) - ->where($this->_db->quoteIdentifier('counter') . ' = ?', $syncKey + 1) - ->where($this->_db->quoteIdentifier('type') . ' = ?', $folderId); - + ->where($this->_db->quoteIdentifier('counter') . ' = ?', $syncKey + 1) + ->where($this->_db->quoteIdentifier('type') . ' = ?', $folderId); + $stmt = $this->_db->query($select); $moreRecentStateData = $stmt->fetch(); $stmt = null; # see https://bugs.php.net/bug.php?id=44081 - + // found more recent synckey => the last sync repsone got not received by the client if ($moreRecentStateData !== false) { // undelete entries marked as deleted in Syncroton_content table - $this->_db->update($this->_tablePrefix . 'content', + $this->_db->update($this->_tablePrefix . 'content', array( 'is_deleted' => 0, - , + ), array( 'device_id = ?' => $deviceId, 'folder_id = ?' => $folderId, 'creation_synckey = ?' => $state->counter, - 'is_deleted = ?' => 1, - ); - + 'is_deleted = ?' => 1 + )); + } else { - // finally delete all entries marked for removal in Syncroton_content table - $this->_db->delete($this->_tablePrefix . 'content', + // finally delete all entries marked for removal in Syncroton_content table + $this->_db->delete($this->_tablePrefix . 'content', array( 'device_id = ?' => $deviceId, 'folder_id = ?' => $folderId, - 'is_deleted = ?' => 1, - ); + 'is_deleted = ?' => 1 + )); } - + // remove all other synckeys $this->_deleteOtherStates($state); - + // remove entries from Syncroton_content table with an creation_synckey bigger than current one - $this->_db->delete($this->_tablePrefix . 'content', + $this->_db->delete($this->_tablePrefix . 'content', array( 'device_id = ?' => $deviceId, 'folder_id = ?' => $folderId, 'creation_synckey > ?' => $state->counter, - ); - + )); + return $state; } - - public function haveNext($deviceid, $folderid, $sync_key) - { - return false; // not implemented - } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/AutoDiscover.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/AutoDiscover.php
Changed
@@ -15,7 +15,7 @@ * @package Syncroton * @subpackage Command */ -class Syncroton_Command_AutoDiscover extends Syncroton_Command_Wbxml +class Syncroton_Command_AutoDiscover implements Syncroton_Command_ICommand { /** * the domDocucment containing the xml request from the client @@ -23,105 +23,104 @@ * @var DOMDocument */ protected $requestBody; - + protected $emailAddress; - - public $mobileSyncUrl; - - public $certEnrollUrl; - + + public $mobileSyncUrl; + + public $certEnrollUrl; + /** * constructor of this class - * - * @param DOMDocument $requestBody - * @param Syncroton_Model_IDevice $device - * @param array $requestParams + * + * @param DOMDocument $_requestBody + * @param Syncroton_Model_IDevice $_device + * @param string $_policyKey */ - // @phpstan-ignore-next-line - public function __construct($requestBody, Syncroton_Model_IDevice $device, $requestParams = ) + public function __construct($requestBody, Syncroton_Model_IDevice $device = null, $policyKey = null) { $this->requestBody = $requestBody; } - + /** - * process the incoming data + * process the incoming data */ public function handle() { $xpath = new DomXPath($this->requestBody); $xpath->registerNamespace('2006', 'http://schemas.microsoft.com/exchange/autodiscover/mobilesync/requestschema/2006'); - + $nodes = $xpath->query('//2006:Autodiscover/2006:Request/2006:EMailAddress'); if ($nodes->length === 0) { throw new Syncroton_Exception(); } - + $this->emailAddress = $nodes->item(0)->nodeValue; } - + /** * create the response - * + * * @return DOMDocument */ public function getResponse() { // Creates an instance of the DOMImplementation class $imp = new DOMImplementation(); - + // Creates a DOMDocument instance $document = $imp->createDocument("http://schemas.microsoft.com/exchange/autodiscover/mobilesync/requestschema/2006", 'Autodiscover'); $document->xmlVersion = '1.0'; $document->encoding = 'UTF-8'; $document->formatOutput = false; - + $response = $document->documentElement->appendChild($document->createElement('Response')); - + $user = $response->appendChild($document->createElement('User')); $user->appendChild($document->createElement('EMailAddress', $this->emailAddress)); - + $settings = $document->createElement('Settings'); - + if (!empty($this->mobileSyncUrl)) { $server = $document->createElement('Server'); - + $server->appendChild($document->createElement('Type', 'MobileSync')); - - $server->appendChild($document->createElement('Url', $this->mobileSyncUrl)); + + $server->appendChild($document->createElement('Url', $this->mobileSyncUrl)); $server->appendChild($document->createElement('Name', $this->mobileSyncUrl)); - + $settings->appendChild($server); } - + if (!empty($this->certEnrollUrl)) { $server = $document->createElement('Server'); - + $server->appendChild($document->createElement('Type', 'CertEnroll')); - - $server->appendChild($document->createElement('Url', $this->certEnrollUrl)); + + $server->appendChild($document->createElement('Url', $this->certEnrollUrl)); $server->appendChild($document->createElement('Name')); $server->appendChild($document->createElement('ServerData', 'CertEnrollTemplate')); - + $settings->appendChild($server); } - + if ($settings->hasChildNodes()) { $action = $response->appendChild($document->createElement('Action')); $action->appendChild($settings); } - + return $document; } - + /** * return headers of command - * + * * @return array list of headers */ public function getHeaders() { - return - 'Content-Type' => 'text/xml;charset=utf-8', - ; + return array( + 'Content-Type' => 'text/xml;charset=utf-8' + ); } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/FolderCreate.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/FolderCreate.php
Changed
@@ -19,9 +19,9 @@ { protected $_defaultNameSpace = 'uri:FolderHierarchy'; protected $_documentElement = 'FolderCreate'; - + /** - * @var Syncroton_Model_IFolder + * @var Syncroton_Model_Folder */ protected $_folder; @@ -29,49 +29,46 @@ * @var int */ protected $_status; - + /** * parse FolderCreate request */ public function handle() { $xml = simplexml_import_dom($this->_requestBody); - + $syncKey = (int)$xml->SyncKey; - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $syncKey"); - } - + if (!($this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $syncKey)) instanceof Syncroton_Model_SyncState) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " invalid synckey provided. FolderSync 0 needed."); - } $this->_status = Syncroton_Command_FolderSync::STATUS_INVALID_SYNC_KEY; return; } - + $folder = new Syncroton_Model_Folder($xml); - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " parentId: {$folder->parentId} displayName: {$folder->displayName}"); - } if (!strlen($folder->displayName)) { $this->_status = Syncroton_Command_FolderSync::STATUS_MISFORMATTED; return; } - + switch($folder->type) { case Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR_USER_CREATED: $folder->class = Syncroton_Data_Factory::CLASS_CALENDAR; break; - + case Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED: $folder->class = Syncroton_Data_Factory::CLASS_CONTACTS; break; - + case Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED: $folder->class = Syncroton_Data_Factory::CLASS_EMAIL; break; @@ -79,11 +76,11 @@ case Syncroton_Command_FolderSync::FOLDERTYPE_NOTE_USER_CREATED: $folder->class = Syncroton_Data_Factory::CLASS_NOTES; break; - + case Syncroton_Command_FolderSync::FOLDERTYPE_TASK_USER_CREATED: $folder->class = Syncroton_Data_Factory::CLASS_TASKS; break; - + default: // unsupported type return; @@ -98,66 +95,46 @@ $this->_status = Syncroton_Command_FolderSync::STATUS_UNKNOWN_ERROR; } else { $this->_folder->class = $folder->class; - $this->_folder->deviceId = $this->_device->id; + $this->_folder->deviceId = $this->_device; $this->_folder->creationTime = $this->_syncTimeStamp; - $this->_folder->creationSynckey = $this->_syncState->counter; - - // Check if the folder already exists to avoid a duplicate insert attempt in db - try { - $this->_folderBackend->getFolder($this->_device, $this->_folder->serverId); - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " Attempted to create a folder that already exists. parentId: {$folder->parentId} displayName: {$folder->displayName}"); - } - - // The folder already exists - $this->_status = Syncroton_Command_FolderSync::STATUS_FOLDER_EXISTS; - } catch (Syncroton_Exception_NotFound $e) { - // This is the normal case - if ($this->_logger instanceof Zend_Log) { - $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); - } - - $this->_folderBackend->create($this->_folder); - } + $this->_folderBackend->create($this->_folder); } } catch (Syncroton_Exception_Status $e) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); - } + if ($this->_logger instanceof Zend_Log) + $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); $this->_status = $e->getCode(); } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); - } + if ($this->_logger instanceof Zend_Log) + $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); $this->_status = Syncroton_Command_FolderSync::STATUS_UNKNOWN_ERROR; } } - + /** * generate FolderCreate response */ public function getResponse() { $folderCreate = $this->_outputDom->documentElement; - + if ($this->_status) { $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', $this->_status)); } else { $this->_syncState->counter++; $this->_syncState->lastsync = $this->_syncTimeStamp; - + // store folder in state backend $this->_syncStateBackend->update($this->_syncState); - + // create xml output - $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_SUCCESS)); - $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'SyncKey', $this->_syncState->counter)); + $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_SUCCESS)); + $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'SyncKey', $this->_syncState->counter)); $folderCreate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'ServerId', $this->_folder->serverId)); } - + return $this->_outputDom; } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/FolderDelete.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/FolderDelete.php
Changed
@@ -15,57 +15,60 @@ * @package Syncroton * @subpackage Command */ -class Syncroton_Command_FolderDelete extends Syncroton_Command_Wbxml -{ +class Syncroton_Command_FolderDelete extends Syncroton_Command_Wbxml +{ protected $_defaultNameSpace = 'uri:FolderHierarchy'; protected $_documentElement = 'FolderDelete'; - + /** - * @var Syncroton_Model_IFolder + * @var Syncroton_Model_SyncState */ protected $_folder; - + + /** + * @var Syncroton_Model_ISyncState + */ + protected $_syncState; + /** * parse FolderDelete request */ public function handle() { $xml = simplexml_import_dom($this->_requestBody); - + // parse xml request $syncKey = (int)$xml->SyncKey; - $serverId = (string)$xml->ServerId; - - if ($this->_logger instanceof Zend_Log) { + $serverId = (string)$xml->ServerId; + + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $syncKey"); - } - + if (!($this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $syncKey)) instanceof Syncroton_Model_SyncState) { - return; + return; } - + try { $folder = $this->_folderBackend->getFolder($this->_device, $serverId); - + $dataController = Syncroton_Data_Factory::factory($folder->class, $this->_device, $this->_syncTimeStamp); - + // delete folder in data backend $dataController->deleteFolder($folder); - + } catch (Syncroton_Exception_NotFound $senf) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $senf->getMessage()); - } - + return; } - + // delete folder in syncState backend $this->_folderBackend->delete($folder); - + $this->_folder = $folder; } - + /** * generate FolderDelete response * @@ -74,28 +77,27 @@ public function getResponse() { $folderDelete = $this->_outputDom->documentElement; - + if (!$this->_syncState instanceof Syncroton_Model_SyncState) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " invalid synckey provided. FolderSync 0 needed."); - } $folderDelete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_INVALID_SYNC_KEY)); - + } elseif (!$this->_folder instanceof Syncroton_Model_IFolder) { $folderDelete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_FOLDER_NOT_FOUND)); - + } else { $this->_syncState->counter++; $this->_syncState->lastsync = $this->_syncTimeStamp; - + // store folder in state backend $this->_syncStateBackend->update($this->_syncState); - + // create xml output $folderDelete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_SUCCESS)); $folderDelete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'SyncKey', $this->_syncState->counter)); } - + return $this->_outputDom; } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/FolderSync.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/FolderSync.php
Changed
@@ -15,106 +15,102 @@ * @package Syncroton * @subpackage Command */ -class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml +class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml { - public const STATUS_SUCCESS = 1; - public const STATUS_FOLDER_EXISTS = 2; - public const STATUS_IS_SPECIAL_FOLDER = 3; - public const STATUS_FOLDER_NOT_FOUND = 4; - public const STATUS_PARENT_FOLDER_NOT_FOUND = 5; - public const STATUS_SERVER_ERROR = 6; - public const STATUS_ACCESS_DENIED = 7; - public const STATUS_REQUEST_TIMED_OUT = 8; - public const STATUS_INVALID_SYNC_KEY = 9; - public const STATUS_MISFORMATTED = 10; - public const STATUS_UNKNOWN_ERROR = 11; + const STATUS_SUCCESS = 1; + const STATUS_FOLDER_EXISTS = 2; + const STATUS_IS_SPECIAL_FOLDER = 3; + const STATUS_FOLDER_NOT_FOUND = 4; + const STATUS_PARENT_FOLDER_NOT_FOUND = 5; + const STATUS_SERVER_ERROR = 6; + const STATUS_ACCESS_DENIED = 7; + const STATUS_REQUEST_TIMED_OUT = 8; + const STATUS_INVALID_SYNC_KEY = 9; + const STATUS_MISFORMATTED = 10; + const STATUS_UNKNOWN_ERROR = 11; /** * some usefull constants for working with the xml files */ - public const FOLDERTYPE_GENERIC_USER_CREATED = 1; - public const FOLDERTYPE_INBOX = 2; - public const FOLDERTYPE_DRAFTS = 3; - public const FOLDERTYPE_DELETEDITEMS = 4; - public const FOLDERTYPE_SENTMAIL = 5; - public const FOLDERTYPE_OUTBOX = 6; - public const FOLDERTYPE_TASK = 7; - public const FOLDERTYPE_CALENDAR = 8; - public const FOLDERTYPE_CONTACT = 9; - public const FOLDERTYPE_NOTE = 10; - public const FOLDERTYPE_JOURNAL = 11; - public const FOLDERTYPE_MAIL_USER_CREATED = 12; - public const FOLDERTYPE_CALENDAR_USER_CREATED = 13; - public const FOLDERTYPE_CONTACT_USER_CREATED = 14; - public const FOLDERTYPE_TASK_USER_CREATED = 15; - public const FOLDERTYPE_JOURNAL_USER_CREATED = 16; - public const FOLDERTYPE_NOTE_USER_CREATED = 17; - public const FOLDERTYPE_UNKOWN = 18; - + const FOLDERTYPE_GENERIC_USER_CREATED = 1; + const FOLDERTYPE_INBOX = 2; + const FOLDERTYPE_DRAFTS = 3; + const FOLDERTYPE_DELETEDITEMS = 4; + const FOLDERTYPE_SENTMAIL = 5; + const FOLDERTYPE_OUTBOX = 6; + const FOLDERTYPE_TASK = 7; + const FOLDERTYPE_CALENDAR = 8; + const FOLDERTYPE_CONTACT = 9; + const FOLDERTYPE_NOTE = 10; + const FOLDERTYPE_JOURNAL = 11; + const FOLDERTYPE_MAIL_USER_CREATED = 12; + const FOLDERTYPE_CALENDAR_USER_CREATED = 13; + const FOLDERTYPE_CONTACT_USER_CREATED = 14; + const FOLDERTYPE_TASK_USER_CREATED = 15; + const FOLDERTYPE_JOURNAL_USER_CREATED = 16; + const FOLDERTYPE_NOTE_USER_CREATED = 17; + const FOLDERTYPE_UNKOWN = 18; + protected $_defaultNameSpace = 'uri:FolderHierarchy'; protected $_documentElement = 'FolderSync'; - - protected $_classes = + + protected $_classes = array( Syncroton_Data_Factory::CLASS_CALENDAR, Syncroton_Data_Factory::CLASS_CONTACTS, Syncroton_Data_Factory::CLASS_EMAIL, Syncroton_Data_Factory::CLASS_NOTES, - Syncroton_Data_Factory::CLASS_TASKS, - ; + Syncroton_Data_Factory::CLASS_TASKS + ); /** * @var string */ protected $_syncKey; - + /** - * Parse FolderSync request + * parse FolderSync request + * */ public function handle() { $xml = simplexml_import_dom($this->_requestBody); $syncKey = (int)$xml->SyncKey; - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $syncKey"); - } - + if ($syncKey === 0) { - $this->_syncState = new Syncroton_Model_SyncState( + $this->_syncState = new Syncroton_Model_SyncState(array( 'device_id' => $this->_device, 'counter' => 0, 'type' => 'FolderSync', - 'lastsync' => $this->_syncTimeStamp, - ); - + 'lastsync' => $this->_syncTimeStamp + )); + // reset state of foldersync $this->_syncStateBackend->resetState($this->_device, 'FolderSync'); - + return; - } - + } + if (!($this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $syncKey)) instanceof Syncroton_Model_SyncState) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " invalidating sync state"); - } $this->_syncStateBackend->resetState($this->_device, 'FolderSync'); } } - + /** * generate FolderSync response - * + * * @todo changes are missing in response (folder got renamed for example) */ public function getResponse() { $folderSync = $this->_outputDom->documentElement; - + // invalid synckey provided if (!$this->_syncState instanceof Syncroton_Model_SyncState) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " invalid synckey provided. FolderSync 0 needed."); - } $folderSync->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', self::STATUS_INVALID_SYNC_KEY)); return $this->_outputDom; @@ -125,46 +121,43 @@ $optionsCommand = new Syncroton_Command_Options(); $this->_headers = array_merge($this->_headers, $optionsCommand->getHeaders()); } - - $adds = ; - $updates = ; - $deletes = ; + + $adds = array(); + $updates = array(); + $deletes = array(); foreach($this->_classes as $class) { try { $dataController = Syncroton_Data_Factory::factory($class, $this->_device, $this->_syncTimeStamp); } catch (Exception $e) { // backend not defined - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " no data backend defined for class: " . $class); - } continue; } try { // retrieve all folders available in data backend $serverFolders = $dataController->getAllFolders(); - + // retrieve all folders sent to client - $clientFolders = $this->_folderBackend->getFolderState($this->_device, $class, $this->_syncState->counter); - + $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); } else { - $changedFolders = ; + $changedFolders = array(); } - + // 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) { + if ($this->_logger instanceof Zend_Log) $this->_logger->crit(__METHOD__ . '::' . __LINE__ . " Syncing folder hierarchy failed: " . $e->getMessage()); - } - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " Syncing folder hierarchy failed: " . $e->getTraceAsString()); - } // The Status element is global for all collections. If one collection fails, // a failure status MUST be returned for all collections. @@ -183,7 +176,7 @@ // is this the first sync? if ($this->_syncState->counter == 0) { - $clientFoldersIds = ; + $clientFoldersIds = array(); } else { $clientFoldersIds = array_keys($clientFolders); } @@ -197,8 +190,7 @@ } else { $add = $serverFolders$serverFolderId; $add->creationTime = $this->_syncTimeStamp; - $add->creationSynckey = $this->_syncState->counter + 1; - $add->deviceId = $this->_device->id; + $add->deviceId = $this->_device; unset($add->id); } $add->class = $class; @@ -209,11 +201,11 @@ // calculate changed entries foreach ($changedFolders as $changedFolder) { $change = $clientFolders$changedFolder->serverId; - + $change->displayName = $changedFolder->displayName; $change->parentId = $changedFolder->parentId; $change->type = $changedFolder->type; - + $updates = $change; } @@ -238,12 +230,6 @@ } } - // Handle folders set for forced re-sync, we'll send a delete action to the client, - // but because the folder is still existing and subscribed on the backend it should - // "immediately" be added again (and re-synced). - $forceDeleteIds = array_keys(array_filter($clientFolders, function ($f) { return !empty($f->resync); })); - $serverFoldersIds = array_diff($serverFoldersIds, $forceDeleteIds); - // calculate deleted entries $serverDiff = array_diff($clientFoldersIds, $serverFoldersIds); foreach ($serverDiff as $serverFolderId) { @@ -258,50 +244,45 @@ $this->_syncState->counter++; $this->_syncState->lastsync = $this->_syncTimeStamp; } - + // create xml output $folderSync->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'SyncKey', $this->_syncState->counter)); - - $changes = $folderSync->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Changes')); + + $changes = $folderSync->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Changes')); $changes->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Count', $count)); - + foreach($adds as $folder) { $add = $changes->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Add')); - + $folder->appendXML($add, $this->_device); // store folder in backend if (empty($folder->id)) { - try { - $this->_folderBackend->create($folder); - } catch(Exception $zdse) { - //This can happen if we rerun a previous sync-key - $this->_folderBackend->update($folder); - } + $this->_folderBackend->create($folder); } } - + foreach($updates as $folder) { $update = $changes->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Update')); - + $folder->appendXML($update, $this->_device); - + $this->_folderBackend->update($folder); } - + foreach($deletes as $folder) { $delete = $changes->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Delete')); $delete->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'ServerId', $folder->serverId)); - + $this->_folderBackend->delete($folder); } - - // Only create this syncstate if it isn't already existing (which happens if we a sync key is re-sent) - if (!$this->_syncStateBackend->haveNext($this->_device, 'FolderSync', $this->_syncState->counter - 1)) { - // Keep previous sync states in case a sync key is re-sent - $this->_syncStateBackend->create($this->_syncState, true); + + if (empty($this->_syncState->id)) { + $this->_syncStateBackend->create($this->_syncState); + } else { + $this->_syncStateBackend->update($this->_syncState); } - + return $this->_outputDom; - } + } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/FolderUpdate.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/FolderUpdate.php
Changed
@@ -15,22 +15,22 @@ * @package Syncroton * @subpackage Command */ -class Syncroton_Command_FolderUpdate extends Syncroton_Command_Wbxml -{ +class Syncroton_Command_FolderUpdate extends Syncroton_Command_Wbxml +{ protected $_defaultNameSpace = 'uri:FolderHierarchy'; protected $_documentElement = 'FolderUpdate'; - + /** - * @var Syncroton_Model_IFolder + * @var Syncroton_Model_SyncState */ protected $_folder; - + /** - * + * * @var Syncroton_Model_Folder */ protected $_folderUpdate; - + /** * parse FolderUpdate request * @@ -38,76 +38,72 @@ public function handle() { $xml = simplexml_import_dom($this->_requestBody); - + $syncKey = (int)$xml->SyncKey; - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " synckey is $syncKey"); - } if (!($this->_syncState = $this->_syncStateBackend->validate($this->_device, 'FolderSync', $syncKey)) instanceof Syncroton_Model_SyncState) { return; } - + $updatedFolder = new Syncroton_Model_Folder($xml); - - if ($this->_logger instanceof Zend_Log) { - $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " parentId: {$updatedFolder->parentId} displayName: {$updatedFolder->displayName}"); - } - + + if ($this->_logger instanceof Zend_Log) + $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " parentId: {$updatedFolder->parentId} displayName: {$updatedFolder->displayName}"); + try { $folder = $this->_folderBackend->getFolder($this->_device, $updatedFolder->serverId); - + $folder->displayName = $updatedFolder->displayName; $folder->parentId = $updatedFolder->parentId; - + $dataController = Syncroton_Data_Factory::factory($folder->class, $this->_device, $this->_syncTimeStamp); - + // update folder in data backend $dataController->updateFolder($folder); - + } catch (Syncroton_Exception_NotFound $senf) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $senf->getMessage()); - } - + return; } - + // update folder status in Syncroton backend - $this->_folder = $this->_folderBackend->update($folder); // @phpstan-ignore-line + $this->_folder = $this->_folderBackend->update($folder); } - + /** * generate FolderUpdate response * * @todo currently we support only the main folder which contains all contacts/tasks/events/notes per class */ - public function getResponse($_keepSession = false) + public function getResponse($_keepSession = FALSE) { $folderUpdate = $this->_outputDom->documentElement; - + if (!$this->_syncState instanceof Syncroton_Model_SyncState) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " invalid synckey provided. FolderSync 0 needed."); - } - $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_INVALID_SYNC_KEY)); - - } elseif (!$this->_folder instanceof Syncroton_Model_IFolder) { - $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_FOLDER_NOT_FOUND)); - + $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_INVALID_SYNC_KEY)); + + } elseif (!$this->_folder instanceof Syncroton_Model_IFolder) { + $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_FOLDER_NOT_FOUND)); + } else { $this->_syncState->counter++; $this->_syncState->lastsync = $this->_syncTimeStamp; - + // store folder in state backend $this->_syncStateBackend->update($this->_syncState); - + // create xml output - $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_SUCCESS)); + $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', Syncroton_Command_FolderSync::STATUS_SUCCESS)); $folderUpdate->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'SyncKey', $this->_syncState->counter)); } - + return $this->_outputDom; - } + } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/GetAttachment.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/GetAttachment.php
Changed
@@ -22,42 +22,44 @@ * @var string */ protected $_attachmentName; - + protected $_skipValidatePolicyKey = true; - + /** - * process the XML file and add, change, delete or fetches data + * process the XML file and add, change, delete or fetches data + * + * @return resource */ public function handle() { $this->_attachmentName = $this->_requestParameters'attachmentName'; } - + /** * this function generates the response for the client - * + * * @return void */ public function getResponse() { $dataController = Syncroton_Data_Factory::factory(Syncroton_Data_Factory::CLASS_EMAIL, $this->_device, $this->_syncTimeStamp); - + $attachment = $dataController->getFileReference($this->_attachmentName); - + if (PHP_SAPI !== 'cli') { - // cache for 3600 seconds + // cache for 3600 seconds $maxAge = 3600; - $now = new DateTime('now', new DateTimeZone('UTC')); - header('Cache-Control: private, max-age=' . $maxAge); - header("Expires: " . gmdate('D, d M Y H:i:s', $now->modify("+{$maxAge} sec")->getTimestamp()) . " GMT"); - - // overwrite Pragma header from session - header("Pragma: cache"); - - #header('Content-Disposition: attachment; filename="' . $filename . '"'); - header("Content-Type: " . $attachment->contentType); + $now = new DateTime(null, new DateTimeZone('UTC')); + header('Cache-Control: private, max-age=' . $maxAge); + header("Expires: " . gmdate('D, d M Y H:i:s', $now->modify("+{$maxAge} sec")->getTimestamp()) . " GMT"); + + // overwrite Pragma header from session + header("Pragma: cache"); + + #header('Content-Disposition: attachment; filename="' . $filename . '"'); + header("Content-Type: " . $attachment->contentType); } - + if (is_resource($attachment->data)) { fpassthru($attachment->data); } else {
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/GetItemEstimate.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/GetItemEstimate.php
Changed
@@ -15,75 +15,73 @@ * @package Syncroton * @subpackage Command */ -class Syncroton_Command_GetItemEstimate extends Syncroton_Command_Wbxml +class Syncroton_Command_GetItemEstimate extends Syncroton_Command_Wbxml { - public const STATUS_SUCCESS = 1; - public const STATUS_INVALID_COLLECTION = 2; - public const STATUS_SYNC_STATE_NOT_PRIMED = 3; - public const STATUS_INVALID_SYNC_KEY = 4; - + const STATUS_SUCCESS = 1; + const STATUS_INVALID_COLLECTION = 2; + const STATUS_SYNC_STATE_NOT_PRIMED = 3; + const STATUS_INVALID_SYNC_KEY = 4; + protected $_defaultNameSpace = 'uri:ItemEstimate'; protected $_documentElement = 'GetItemEstimate'; - + /** * list of collections * * @var array */ - protected $_collections = ; - + protected $_collections = array(); + /** */ public function handle() { $xml = simplexml_import_dom($this->_requestBody); - + foreach ($xml->Collections->Collection as $xmlCollection) { - + // fetch values from a different namespace $airSyncValues = $xmlCollection->children('uri:AirSync'); - - $collectionData = + + $collectionData = array( 'syncKey' => (int)$airSyncValues->SyncKey, 'collectionId' => (string) $xmlCollection->CollectionId, 'class' => isset($xmlCollection->Class) ? (string) $xmlCollection->Class : null, - 'filterType' => isset($airSyncValues->Options) && isset($airSyncValues->Options->FilterType) ? (int)$airSyncValues->Options->FilterType : 0, - ; - - if ($this->_logger instanceof Zend_Log) { + 'filterType' => isset($airSyncValues->Options) && isset($airSyncValues->Options->FilterType) ? (int)$airSyncValues->Options->FilterType : 0 + ); + + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " synckey is {$collectionData'syncKey'} class: {$collectionData'class'} collectionid: {$collectionData'collectionId'} filtertype: {$collectionData'filterType'}"); - } - + try { // does the folder exist? $collectionData'folder' = $this->_folderBackend->getFolder($this->_device, $collectionData'collectionId'); $collectionData'folder'->lastfiltertype = $collectionData'filterType'; - + if($collectionData'syncKey' === 0) { - $collectionData'syncState' = new Syncroton_Model_SyncState( + $collectionData'syncState' = new Syncroton_Model_SyncState(array( 'device_id' => $this->_device, 'counter' => 0, 'type' => $collectionData'folder', - 'lastsync' => $this->_syncTimeStamp, - ); - + 'lastsync' => $this->_syncTimeStamp + )); + // reset sync state for this folder $this->_syncStateBackend->resetState($this->_device, $collectionData'folder'); $this->_contentStateBackend->resetState($this->_device, $collectionData'folder'); - + } else { $collectionData'syncState' = $this->_syncStateBackend->validate($this->_device, $collectionData'folder', $collectionData'syncKey'); } } catch (Syncroton_Exception_NotFound $senf) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $senf->getMessage()); - } } - + $this->_collections$collectionData'collectionId' = $collectionData; } - } - + } + /** * (non-PHPdoc) * @see Syncroton_Command_Wbxml::getResponse() @@ -91,43 +89,41 @@ public function getResponse() { $itemEstimate = $this->_outputDom->documentElement; - + foreach($this->_collections as $collectionData) { $response = $itemEstimate->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Response')); // invalid collectionid provided if (empty($collectionData'folder')) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " folder does not exist"); - } - + $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Status', self::STATUS_INVALID_COLLECTION)); $collection = $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Collection')); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'CollectionId', $collectionData'collectionId')); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Estimate', 0)); - + } elseif (! ($collectionData'syncState' instanceof Syncroton_Model_ISyncState)) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " invalid synckey ${collectionData'syncKey'} provided"); - } /* * Android phones (and maybe others) don't take care about status 4(INVALID_SYNC_KEY) * To solve the problem we always return status 1(SUCCESS) even the sync key is invalid with Estimate set to 1. * This way the phone gets forced to sync. Handling invalid synckeys during sync command works without any problems. - * + * $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Status', self::STATUS_INVALID_SYNC_KEY)); $collection = $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Collection')); - $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'CollectionId', $collectionData'collectionId')); + $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'CollectionId', $collectionData'collectionId')); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Estimate', 0)); */ - + $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Status', self::STATUS_SUCCESS)); $collection = $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Collection')); - $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'CollectionId', $collectionData'collectionId')); - $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Estimate', 1)); + $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'CollectionId', $collectionData'collectionId')); + $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Estimate', 1)); } else { $dataController = Syncroton_Data_Factory::factory($collectionData'folder'->class, $this->_device, $this->_syncTimeStamp); - + $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Status', self::STATUS_SUCCESS)); $collection = $response->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Collection')); $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'CollectionId', $collectionData'collectionId')); @@ -139,13 +135,13 @@ } $collection->appendChild($this->_outputDom->createElementNS('uri:ItemEstimate', 'Estimate', $count)); } - + // folderState can be NULL in case of not existing folder if (isset($collectionData'folder') && $collectionData'folder'->isDirty()) { $this->_folderBackend->update($collectionData'folder'); } } - + return $this->_outputDom; } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/ICommand.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/ICommand.php
Changed
@@ -15,19 +15,19 @@ * @package Syncroton * @subpackage Command */ -interface Syncroton_Command_ICommand +interface Syncroton_Command_ICommand { /** * constructor of this class - * + * * @param resource $_requestBody * @param Syncroton_Model_IDevice $_device - * @param array $_requestParams + * @param string $_policyKey */ - public function __construct($_requestBody, Syncroton_Model_IDevice $_device, $_requestParams = ); - + public function __construct($_requestBody, Syncroton_Model_IDevice $_device, $_policyKey); + /** - * process the incoming data + * process the incoming data */ public function handle(); @@ -35,10 +35,10 @@ * create the response */ public function getResponse(); - + /** * return headers of command - * + * * @return array list of headers */ public function getHeaders();
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/ItemOperations.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/ItemOperations.php
Changed
@@ -15,31 +15,31 @@ * @package Syncroton * @subpackage Command */ -class Syncroton_Command_ItemOperations extends Syncroton_Command_Wbxml -{ - public const STATUS_SUCCESS = 1; - public const STATUS_PROTOCOL_ERROR = 2; - public const STATUS_SERVER_ERROR = 3; - - public const STATUS_ITEM_FAILED_CONVERSION = 14; - +class Syncroton_Command_ItemOperations extends Syncroton_Command_Wbxml +{ + const STATUS_SUCCESS = 1; + const STATUS_PROTOCOL_ERROR = 2; + const STATUS_SERVER_ERROR = 3; + + const STATUS_ITEM_FAILED_CONVERSION = 14; + protected $_defaultNameSpace = 'uri:ItemOperations'; protected $_documentElement = 'ItemOperations'; - + /** * list of items to move - * + * * @var array */ - protected $_fetches = ; - + protected $_fetches = array(); + /** * list of folder to empty - * + * * @var array */ - protected $_emptyFolderContents = ; - + protected $_emptyFolderContents = array(); + /** * parse MoveItems request * @@ -47,112 +47,112 @@ public function handle() { $xml = simplexml_import_dom($this->_requestBody); - + if (isset($xml->Fetch)) { foreach ($xml->Fetch as $fetch) { $this->_fetches = $this->_handleFetch($fetch); } } - + if (isset($xml->EmptyFolderContents)) { foreach ($xml->EmptyFolderContents as $emptyFolderContents) { $this->_emptyFolderContents = $this->_handleEmptyFolderContents($emptyFolderContents); } } } - + /** * generate ItemOperations response - * + * * @todo add multipart support to all types of fetches */ public function getResponse() { // add aditional namespaces - $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:AirSyncBase', 'uri:AirSyncBase'); - $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:AirSync', 'uri:AirSync'); - $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Search', 'uri:Search'); - + $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:AirSyncBase' , 'uri:AirSyncBase'); + $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:AirSync' , 'uri:AirSync'); + $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Search' , 'uri:Search'); + $itemOperations = $this->_outputDom->documentElement; - + $itemOperations->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SUCCESS)); - + $response = $itemOperations->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Response')); - + foreach ($this->_fetches as $fetch) { $fetchTag = $response->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Fetch')); - + try { $dataController = Syncroton_Data_Factory::factory($fetch'store', $this->_device, $this->_syncTimeStamp); - + if (isset($fetch'collectionId')) { $fetchTag->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SUCCESS)); $fetchTag->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $fetch'collectionId')); - $fetchTag->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $fetch'serverId')); - + $fetchTag->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $fetch'serverId')); + $properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties'); $dataController - ->getEntry(new Syncroton_Model_SyncCollection('collectionId' => $fetch'collectionId', 'options' => $fetch'options'), $fetch'serverId') + ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch'collectionId', 'options' => $fetch'options')), $fetch'serverId') ->appendXML($properties, $this->_device); $fetchTag->appendChild($properties); - + } elseif (isset($fetch'longId')) { $fetchTag->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SUCCESS)); $fetchTag->appendChild($this->_outputDom->createElementNS('uri:Search', 'LongId', $fetch'longId')); - + $properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties'); $dataController - ->getEntry(new Syncroton_Model_SyncCollection('collectionId' => $fetch'longId', 'options' => $fetch'options'), $fetch'longId') + ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch'longId', 'options' => $fetch'options')), $fetch'longId') ->appendXML($properties, $this->_device); $fetchTag->appendChild($properties); - + } elseif (isset($fetch'fileReference')) { $fetchTag->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SUCCESS)); $fetchTag->appendChild($this->_outputDom->createElementNS('uri:AirSyncBase', 'FileReference', $fetch'fileReference')); $properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties'); - + $fileReference = $dataController->getFileReference($fetch'fileReference'); - + // unset data field and move content to stream if (!empty($this->_requestParameters'acceptMultipart')) { $this->_headers'Content-Type' = 'application/vnd.ms-sync.multipart'; - + $partStream = fopen("php://temp", 'r+'); - + if (is_resource($fileReference->data)) { stream_copy_to_stream($fileReference->data, $partStream); } else { fwrite($partStream, $fileReference->data); } - + unset($fileReference->data); - + $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; + + $rangeEnd = $dataSize > 0 ? $dataSize - 1 : 0; $range = $this->_outputDom->createElementNS('uri:ItemOperations', 'Range', '0-' . $rangeEnd); $properties->appendChild($range); } - + $fileReference->appendXML($properties, $this->_device); - + $fetchTag->appendChild($properties); } } catch (Syncroton_Exception_NotFound $e) { @@ -162,9 +162,9 @@ $response->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SERVER_ERROR)); } } - + foreach ($this->_emptyFolderContents as $emptyFolderContents) { - + try { $folder = $this->_folderBackend->getFolder($this->_device, $emptyFolderContents'collectionId'); @@ -172,74 +172,76 @@ $dataController->emptyFolderContents($emptyFolderContents'collectionId', $emptyFolderContents'options'); $status = Syncroton_Command_ItemOperations::STATUS_SUCCESS; - } catch (Syncroton_Exception_Status_ItemOperations $e) { + } + catch (Syncroton_Exception_Status_ItemOperations $e) { $status = $e->getCode(); - } catch (Exception $e) { + } + catch (Exception $e) { $status = Syncroton_Exception_Status_ItemOperations::ITEM_SERVER_ERROR; } $emptyFolderContentsTag = $this->_outputDom->createElementNS('uri:ItemOperations', 'EmptyFolderContents'); - + $emptyFolderContentsTag->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', $status)); $emptyFolderContentsTag->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $emptyFolderContents'collectionId')); - + $response->appendChild($emptyFolderContentsTag); } - + return $this->_outputDom; } - + /** * parse fetch request - * + * * @param SimpleXMLElement $fetch * @return array */ protected function _handleFetch(SimpleXMLElement $fetch) { - $fetchArray = + $fetchArray = array( 'store' => (string)$fetch->Store, - 'options' => , - ; - + 'options' => array() + ); + // try to fetch element from namespace AirSync $airSync = $fetch->children('uri:AirSync'); - + if (isset($airSync->CollectionId)) { $fetchArray'collectionId' = (string)$airSync->CollectionId; $fetchArray'serverId' = (string)$airSync->ServerId; } - + // try to fetch element from namespace Search $search = $fetch->children('uri:Search'); - + if (isset($search->LongId)) { $fetchArray'longId' = (string)$search->LongId; } - + // try to fetch element from namespace AirSyncBase $airSyncBase = $fetch->children('uri:AirSyncBase'); - + if (isset($airSyncBase->FileReference)) { $fetchArray'fileReference' = (string)$airSyncBase->FileReference; } - + if (isset($fetch->Options)) { // try to fetch element from namespace AirSyncBase $airSyncBase = $fetch->Options->children('uri:AirSyncBase'); - + if (isset($airSyncBase->BodyPreference)) { foreach ($airSyncBase->BodyPreference as $bodyPreference) { $type = (int) $bodyPreference->Type; - $fetchArray'options''bodyPreferences'$type = - 'type' => $type, - ; - + $fetchArray'options''bodyPreferences'$type = array( + 'type' => $type + ); + // optional if (isset($bodyPreference->TruncationSize)) { $fetchArray'options''bodyPreferences'$type'truncationSize' = (int) $bodyPreference->TruncationSize; } - + // optional if (isset($bodyPreference->AllOrNone)) { $fetchArray'options''bodyPreferences'$type'allOrNone' = (int) $bodyPreference->AllOrNone; @@ -247,47 +249,46 @@ } } - $airSync = $fetch->Options->children('uri:AirSync'); - if (isset($airSync->MIMESupport)) { - $fetchArray'options''mimeSupport' = (int) $airSync->MIMESupport; + if (isset($fetch->Options->MIMESupport)){ + $fetchArray'options''mimeSupport' = (int) $fetch->Options->MIMESupport; } - - if (isset($fetch->Options->Range)) { - $fetchArray'options''range' = (string) $fetch->Options->Range; + + 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 = + $folderArray = array( 'collectiondId' => null, - 'options' => 'deleteSubFolders' => false, - ; - + 'options' => array('deleteSubFolders' => FALSE) + ); + // try to fetch element from namespace AirSync $airSync = $emptyFolderContent->children('uri:AirSync'); - + $folderArray'collectionId' = (string)$airSync->CollectionId; - + if (isset($emptyFolderContent->Options)) { - $folderArray'options''deleteSubFolders' = isset($emptyFolderContent->Options->DeleteSubFolders); + $folderArray'options''deleteSubFolders' = isset($emptyFolderContent->Options->DeleteSubFolders); } - + return $folderArray; } /** * return length of data - * + * * @param string|resource $data * @return number */
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/MeetingResponse.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/MeetingResponse.php
Changed
@@ -17,10 +17,9 @@ */ class Syncroton_Command_MeetingResponse extends Syncroton_Command_Wbxml { - protected $_results = ; - + protected $_results = array(); + protected $_defaultNameSpace = 'uri:MeetingResponse'; - protected $_documentElement = 'MeetingResponse'; /** @@ -28,28 +27,27 @@ */ public function handle() { - /** @var Syncroton_Data_IDataCalendar $dataController */ $dataController = Syncroton_Data_Factory::factory(Syncroton_Data_Factory::CLASS_CALENDAR, $this->_device, $this->_syncTimeStamp); - + $xml = simplexml_import_dom($this->_requestBody); foreach ($xml as $meetingResponse) { $request = new Syncroton_Model_MeetingResponse($meetingResponse); - + try { $calendarId = $dataController->setAttendeeStatus($request); - - $this->_results = + + $this->_results = array( 'calendarId' => $calendarId, 'request' => $request, - 'status' => 1, - ; - + 'status' => 1 + ); + } catch (Syncroton_Exception_Status_MeetingResponse $sesmr) { - $this->_results = + $this->_results = array( 'request' => $request, - 'status' => $sesmr->getCode(), - ; + 'status' => $sesmr->getCode() + ); } } } @@ -60,27 +58,27 @@ public function getResponse() { $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Search', 'uri:Search'); - + $meetingResponse = $this->_outputDom->documentElement; foreach ($this->_results as $result) { $resultElement = $this->_outputDom->createElementNS('uri:MeetingResponse', 'Result'); - + if (isset($result'request'->requestId)) { $resultElement->appendChild($this->_outputDom->createElementNS('uri:MeetingResponse', 'RequestId', $result'request'->requestId)); } elseif (isset($result'request'->longId)) { $resultElement->appendChild($this->_outputDom->createElementNS('uri:Search', 'LongId', $result'request'->longId)); } - + $resultElement->appendChild($this->_outputDom->createElementNS('uri:MeetingResponse', 'Status', $result'status')); - + if (isset($result'calendarId')) { $resultElement->appendChild($this->_outputDom->createElementNS('uri:MeetingResponse', 'CalendarId', $result'calendarId')); } - + $meetingResponse->appendChild($resultElement); - } - + } + return $this->_outputDom; } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/MoveItems.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/MoveItems.php
Changed
@@ -20,7 +20,7 @@ */ class Syncroton_Command_MoveItems extends Syncroton_Command_Wbxml { - public const STATUS_SUCCESS = 3; + const STATUS_SUCCESS = 3; protected $_defaultNameSpace = 'uri:Move'; protected $_documentElement = 'MoveItems'; @@ -30,7 +30,7 @@ * * @var array */ - protected $_moves = ; + protected $_moves = array(); /** * parse MoveItems request @@ -40,11 +40,11 @@ $xml = simplexml_import_dom($this->_requestBody); foreach ($xml->Move as $move) { - $this->_moves = + $this->_moves = array( 'srcMsgId' => (string)$move->SrcMsgId, 'srcFldId' => (string)$move->SrcFldId, - 'dstFldId' => (string)$move->DstFldId, - ; + 'dstFldId' => (string)$move->DstFldId + ); } } @@ -59,11 +59,11 @@ $response = $moves->appendChild($this->_outputDom->createElementNS('uri:Move', 'Response')); $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'SrcMsgId', $move'srcMsgId')); - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " Moving from " . $move'srcFldId' . " to " . $move'dstFldId'); - } - try { + if ($move'srcFldId' === $move'dstFldId') { + throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::SAME_FOLDER); + } + try { $sourceFolder = $this->_folderBackend->getFolder($this->_device, $move'srcFldId'); } catch (Syncroton_Exception_NotFound $e) { @@ -76,30 +76,16 @@ throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_DESTINATION); } - if ($move'srcFldId' === $move'dstFldId') { - throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::SAME_FOLDER); - } - $dataController = Syncroton_Data_Factory::factory($sourceFolder->class, $this->_device, $this->_syncTimeStamp); $newId = $dataController->moveItem($move'srcFldId', $move'srcMsgId', $move'dstFldId'); - if (!$newId) { - // We don't actually know what the reason was that this failed, but from the resolution description this error seems to make the most sense, - // and we rule out most other reasons before. - throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE); - } $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', Syncroton_Command_MoveItems::STATUS_SUCCESS)); - $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'DstMsgId', $newId)); - } catch (Syncroton_Exception_Status_MoveItems $e) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " Move failed: " . $e->getMessage()); - } + if ($newId) + $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'DstMsgId', $newId)); + } catch (Syncroton_Exception_Status $e) { $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', $e->getCode())); } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " Move failed: " . $e->getMessage()); - } - $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', Syncroton_Exception_Status_MoveItems::FOLDER_LOCKED)); + $response->appendChild($this->_outputDom->createElementNS('uri:Move', 'Status', Syncroton_Exception_Status::SERVER_ERROR)); } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/Options.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/Options.php
Changed
@@ -20,15 +20,15 @@ /** * this function generates the response for the client * - * @return array + * @return void */ public function getHeaders() { // same header like Exchange 2xxx??? - return + return array( 'MS-Server-ActiveSync' => '14.00.0536.000', 'MS-ASProtocolVersions' => '2.5,12.0,12.1,14.0,14.1', - 'MS-ASProtocolCommands' => 'FolderCreate,FolderDelete,FolderSync,FolderUpdate,GetAttachment,GetItemEstimate,ItemOperations,MeetingResponse,MoveItems,Provision,ResolveRecipients,Ping,SendMail,Search,Settings,SmartForward,SmartReply,Sync,ValidateCert', - ; + 'MS-ASProtocolCommands' => 'FolderCreate,FolderDelete,FolderSync,FolderUpdate,GetAttachment,GetItemEstimate,ItemOperations,MeetingResponse,MoveItems,Provision,ResolveRecipients,Ping,SendMail,Search,Settings,SmartForward,SmartReply,Sync,ValidateCert' + ); } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/Ping.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/Ping.php
Changed
@@ -15,38 +15,45 @@ * @package Syncroton * @subpackage Command */ -class Syncroton_Command_Ping extends Syncroton_Command_Wbxml +class Syncroton_Command_Ping extends Syncroton_Command_Wbxml { - public const STATUS_NO_CHANGES_FOUND = 1; - public const STATUS_CHANGES_FOUND = 2; - public const STATUS_MISSING_PARAMETERS = 3; - public const STATUS_REQUEST_FORMAT_ERROR = 4; - public const STATUS_INTERVAL_TO_GREAT_OR_SMALL = 5; - public const STATUS_TOO_MANY_FOLDERS = 6; - public const STATUS_FOLDER_NOT_FOUND = 7; - public const STATUS_GENERAL_ERROR = 8; - - public const MAX_PING_INTERVAL = 3540; // 59 minutes limit defined in Activesync protocol spec. - - protected $_defaultNameSpace = 'uri:Ping'; - - protected $_documentElement = 'Ping'; - + const STATUS_NO_CHANGES_FOUND = 1; + const STATUS_CHANGES_FOUND = 2; + const STATUS_MISSING_PARAMETERS = 3; + const STATUS_REQUEST_FORMAT_ERROR = 4; + const STATUS_INTERVAL_TO_GREAT_OR_SMALL = 5; + const STATUS_TOO_MANY_FOLDERS = 6; + 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; - protected $_foldersWithChanges = ; + + /** + * @var Syncroton_Backend_StandAlone_Abstract + */ + protected $_dataBackend; + protected $_defaultNameSpace = 'uri:Ping'; + protected $_documentElement = 'Ping'; + + protected $_foldersWithChanges = array(); + /** - * process the XML file and add, change, delete or fetches data + * process the XML file and add, change, delete or fetches data * * @todo can we get rid of LIBXML_NOWARNING * @todo we need to stored the initial data for folders and lifetime as the phone is sending them only when they change + * @return resource */ public function handle() { $intervalStart = time(); $status = self::STATUS_NO_CHANGES_FOUND; - + // the client does not send a wbxml document, if the Ping parameters did not change compared with the last request if ($this->_requestBody instanceof DOMDocument) { $xml = simplexml_import_dom($this->_requestBody); @@ -55,7 +62,7 @@ if(isset($xml->HeartbeatInterval)) { $this->_device->pinglifetime = (int)$xml->HeartbeatInterval; } - + if (isset($xml->Folders->Folder)) { $maxCollections = Syncroton_Registry::getMaxCollections(); if ($maxCollections && count($xml->Folders->Folder) > $maxCollections) { @@ -65,21 +72,16 @@ return; } - $folders = ; + $folders = array(); foreach ($xml->Folders->Folder as $folderXml) { try { - if (empty((string)$folderXml->Id)) { - // Ignore empty folder ids - continue; - } // does the folder exist? $folder = $this->_folderBackend->getFolder($this->_device, (string)$folderXml->Id); - + $folders$folder->id = $folder; } catch (Syncroton_Exception_NotFound $senf) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $senf->getMessage()); - } $status = self::STATUS_FOLDER_NOT_FOUND; break; } @@ -87,13 +89,13 @@ $this->_device->pingfolder = serialize(array_keys($folders)); } } - - $this->_device->lastping = new DateTime('now', new DateTimeZone('UTC')); + + $this->_device->lastping = new DateTime('now', new DateTimeZone('utc')); if ($status == self::STATUS_NO_CHANGES_FOUND) { - $this->_device = $this->_deviceBackend->update($this->_device); // @phpstan-ignore-line + $this->_device = $this->_deviceBackend->update($this->_device); } - + $lifeTime = $this->_device->pinglifetime; $maxInterval = Syncroton_Registry::getPingInterval(); @@ -107,20 +109,19 @@ $ping->appendChild($this->_outputDom->createElementNS('uri:Ping', 'HeartbeatInterval', $maxInterval)); return; } - + $intervalEnd = $intervalStart + $lifeTime; $secondsLeft = $intervalEnd; - - $folders = $this->_device->pingfolder ? unserialize($this->_device->pingfolder) : ; - + + $folders = unserialize($this->_device->pingfolder); + if ($status === self::STATUS_NO_CHANGES_FOUND && (!is_array($folders) || count($folders) == 0)) { $status = self::STATUS_MISSING_PARAMETERS; } - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $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(); @@ -128,13 +129,12 @@ do { // take a break to save battery lifetime call_user_func($sleepCallback); - sleep(min(Syncroton_Registry::getPingTimeout(), $lifeTime)); + sleep(Syncroton_Registry::getPingTimeout()); // make sure the connection is still alive, abort otherwise if (connection_aborted()) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " Exiting on aborted connection"); - } exit; } @@ -146,151 +146,132 @@ $secondsLeft = $intervalEnd - time(); try { - /** @var Syncroton_Model_Device $device */ $device = $this->_deviceBackend->get($this->_device->id); } catch (Syncroton_Exception_NotFound $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); - } $status = self::STATUS_FOLDER_NOT_FOUND; break; } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->err(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); - } // do nothing, maybe temporal issue, should we stop? continue; } // if another Ping command updated lastping property, we can stop processing this Ping command request - if ((isset($device->lastping) && - $device->lastping instanceof DateTime) && + if ((isset($device->lastping) && $device->lastping instanceof DateTime) && $device->pingfolder === $this->_device->pingfolder && - $device->lastping->getTimestamp() > $this->_device->lastping->getTimestamp() - ) { + $device->lastping->getTimestamp() > $this->_device->lastping->getTimestamp() ) { break; } // If folders hierarchy changed, break the loop and ask the client for FolderSync try { if ($this->_folderBackend->hasHierarchyChanges($this->_device)) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' Detected changes in folders hierarchy'); - } $status = self::STATUS_FOLDER_NOT_FOUND; break; } } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->err(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); - } // do nothing, maybe temporal issue, should we stop? continue; } - $now = new DateTime('now', new DateTimeZone('UTC')); - + $now = new DateTime('now', new DateTimeZone('utc')); + foreach ($folders as $folderId) { - if (empty($folderId)) { - // Ignore empty folder ids - continue; - } try { - /** @var Syncroton_Model_Folder $folder */ $folder = $this->_folderBackend->get($folderId); $dataController = Syncroton_Data_Factory::factory($folder->class, $this->_device, $this->_syncTimeStamp); - + } catch (Syncroton_Exception_NotFound $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); - } $status = self::STATUS_FOLDER_NOT_FOUND; - + break; - + } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->err(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); - } - + // do nothing, maybe temporal issue, should we stop? continue; } try { $syncState = $this->_syncStateBackend->getSyncState($this->_device, $folder); - + // another process synchronized data of this folder already. let's skip it if ($syncState->lastsync > $this->_syncTimeStamp) { continue; } - + // safe battery time by skipping folders which got synchronied less than Syncroton_Registry::getQuietTime() seconds ago if (($now->getTimestamp() - $syncState->lastsync->getTimestamp()) < Syncroton_Registry::getQuietTime()) { continue; } - + $foundChanges = $dataController->hasChanges($this->_contentStateBackend, $folder, $syncState); - + } catch (Syncroton_Exception_NotFound $e) { // folder got never synchronized to client - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " " . $e->getMessage()); - } - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' syncstate not found. enforce sync for folder: ' . $folder->serverId); - } - + $foundChanges = true; } - + if ($foundChanges == true) { $this->_foldersWithChanges = $folder; $status = self::STATUS_CHANGES_FOUND; } } - + if ($status != self::STATUS_NO_CHANGES_FOUND) { break; } // Update secondsLeft (again) $secondsLeft = $intervalEnd - time(); - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " DeviceId: " . $this->_device->deviceid . " seconds left: " . $secondsLeft); - } - - // See: http://www.tine20.org/forum/viewtopic.php?f=12&t=12146 - // - // 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 + + // See: http://www.tine20.org/forum/viewtopic.php?f=12&t=12146 + // + // 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 (Syncroton_Server::validateSession() && $secondsLeft > (Syncroton_Registry::getPingTimeout() + 10)); } - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " DeviceId: " . $this->_device->deviceid . " Lifetime: $lifeTime SecondsLeft: $secondsLeft Status: $status)"); - } - + $ping = $this->_outputDom->documentElement; $ping->appendChild($this->_outputDom->createElementNS('uri:Ping', 'Status', $status)); if($status === self::STATUS_CHANGES_FOUND) { $folders = $ping->appendChild($this->_outputDom->createElementNS('uri:Ping', 'Folders')); - + foreach($this->_foldersWithChanges as $changedFolder) { $folder = $folders->appendChild($this->_outputDom->createElementNS('uri:Ping', 'Folder', $changedFolder->serverId)); - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " DeviceId: " . $this->_device->deviceid . " changes in folder: " . $changedFolder->serverId); - } } } } - + /** * generate ping command response *
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/Provision.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/Provision.php
Changed
@@ -19,65 +19,67 @@ { protected $_defaultNameSpace = 'uri:Provision'; protected $_documentElement = 'Provision'; - - public const POLICYTYPE_WBXML = 'MS-EAS-Provisioning-WBXML'; - - public const STATUS_SUCCESS = 1; - public const STATUS_PROTOCOL_ERROR = 2; - public const STATUS_GENERAL_SERVER_ERROR = 3; - public const STATUS_DEVICE_MANAGED_EXTERNALLY = 4; - - public const STATUS_POLICY_SUCCESS = 1; - public const STATUS_POLICY_NOPOLICY = 2; - public const STATUS_POLICY_UNKNOWNTYPE = 3; - public const STATUS_POLICY_CORRUPTED = 4; - public const STATUS_POLICY_WRONGPOLICYKEY = 5; - - public const REMOTEWIPE_REQUESTED = 1; - public const REMOTEWIPE_CONFIRMED = 2; - + + const POLICYTYPE_WBXML = 'MS-EAS-Provisioning-WBXML'; + + const STATUS_SUCCESS = 1; + const STATUS_PROTOCOL_ERROR = 2; + const STATUS_GENERAL_SERVER_ERROR = 3; + const STATUS_DEVICE_MANAGED_EXTERNALLY = 4; + + const STATUS_POLICY_SUCCESS = 1; + const STATUS_POLICY_NOPOLICY = 2; + const STATUS_POLICY_UNKNOWNTYPE = 3; + const STATUS_POLICY_CORRUPTED = 4; + const STATUS_POLICY_WRONGPOLICYKEY = 5; + + const REMOTEWIPE_REQUESTED = 1; + const REMOTEWIPE_CONFIRMED = 2; + protected $_skipValidatePolicyKey = true; - + protected $_policyType; protected $_sendPolicyKey; - + /** * @var Syncroton_Model_DeviceInformation */ protected $_deviceInformation; - + /** - * process the XML file and add, change, delete or fetches data + * process the XML file and add, change, delete or fetches data + * + * @return resource */ public function handle() { $xml = simplexml_import_dom($this->_requestBody); - + $this->_policyType = isset($xml->Policies->Policy->PolicyType) ? (string) $xml->Policies->Policy->PolicyType : null; - $this->_sendPolicyKey = isset($xml->Policies->Policy->PolicyKey) ? (int) $xml->Policies->Policy->PolicyKey : null; - + $this->_sendPolicyKey = isset($xml->Policies->Policy->PolicyKey) ? (int) $xml->Policies->Policy->PolicyKey : null; + if ($this->_device->remotewipe == self::REMOTEWIPE_REQUESTED && isset($xml->RemoteWipe->Status) && (int)$xml->RemoteWipe->Status == self::STATUS_SUCCESS) { $this->_device->remotewipe = self::REMOTEWIPE_CONFIRMED; } - - // try to fetch element from Settings namespace + + // try to fetch element from Settings namespace $settings = $xml->children('uri:Settings'); if (isset($settings->DeviceInformation) && isset($settings->DeviceInformation->Set)) { $this->_deviceInformation = new Syncroton_Model_DeviceInformation($settings->DeviceInformation->Set); - - $this->_device->model = $this->_deviceInformation->model; - $this->_device->imei = $this->_deviceInformation->iMEI; - $this->_device->friendlyname = $this->_deviceInformation->friendlyName; - $this->_device->os = $this->_deviceInformation->oS; - $this->_device->oslanguage = $this->_deviceInformation->oSLanguage; - $this->_device->phonenumber = $this->_deviceInformation->phoneNumber; + + $this->_device->model = $this->_deviceInformation->model; + $this->_device->imei = $this->_deviceInformation->iMEI; + $this->_device->friendlyname = $this->_deviceInformation->friendlyName; + $this->_device->os = $this->_deviceInformation->oS; + $this->_device->oslanguage = $this->_deviceInformation->oSLanguage; + $this->_device->phonenumber = $this->_deviceInformation->phoneNumber; } if ($this->_device->isDirty()) { - $this->_device = $this->_deviceBackend->update($this->_device); // @phpstan-ignore-line + $this->_device = $this->_deviceBackend->update($this->_device); } } - + /** * generate search command response * @@ -85,28 +87,27 @@ public function getResponse() { $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Settings', 'uri:Settings'); - + // should we wipe the device if ($this->_device->remotewipe >= self::REMOTEWIPE_REQUESTED) { $this->_sendRemoteWipe(); } else { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' PolicyType: ' . $this->_policyType . ' PolicyKey: ' . $this->_sendPolicyKey); - } - + if (!$this->_sendPolicyKey) { $this->_sendPolicy(); } elseif ($this->_sendPolicyKey == $this->_device->policykey) { $this->_acknowledgePolicy(); - } - } - + } + } + return $this->_outputDom; } - + /** * function the send policy to client - * + * * 4131 (Enforce password on device) 0: enabled 1: disabled * 4133 (Unlock from computer) 0: disabled 1: enabled * AEFrequencyType 0: no inactivity time 1: inactivity time is set @@ -119,10 +120,9 @@ */ protected function _sendPolicy() { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' send policy to device'); - } - + $provision = $sync = $this->_outputDom->documentElement; $provision->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', 1)); @@ -131,65 +131,61 @@ $deviceInformation = $provision->appendChild($this->_outputDom->createElementNS('uri:Settings', 'DeviceInformation')); $deviceInformation->appendChild($this->_outputDom->createElementNS('uri:Settings', 'Status', 1)); } - + // policies $policies = $provision->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Policies')); $policy = $policies->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Policy')); $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'PolicyType', $this->_policyType)); - + if ($this->_policyType != self::POLICYTYPE_WBXML) { $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', self::STATUS_POLICY_UNKNOWNTYPE)); } elseif (empty($this->_device->policyId)) { $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', self::STATUS_POLICY_NOPOLICY)); } else { $this->_device->policykey = $this->generatePolicyKey(); - + $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', self::STATUS_POLICY_SUCCESS)); $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'PolicyKey', $this->_device->policykey)); - + $data = $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Data')); $easProvisionDoc = $data->appendChild($this->_outputDom->createElementNS('uri:Provision', 'EASProvisionDoc')); - - /** @var Syncroton_Model_Policy $_policy */ - $_policy = $this->_policyBackend->get($this->_device->policyId); - $_policy->appendXML($easProvisionDoc, $this->_device); - + $this->_policyBackend + ->get($this->_device->policyId) + ->appendXML($easProvisionDoc, $this->_device); + $this->_deviceBackend->update($this->_device); } } - + /** * function the send remote wipe command */ protected function _sendRemoteWipe() { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . ' send remote wipe to device'); - } - + $provision = $sync = $this->_outputDom->documentElement; $provision->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', 1)); $provision->appendChild($this->_outputDom->createElementNS('uri:Provision', 'RemoteWipe')); } - + protected function _acknowledgePolicy() { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' acknowledge policy'); - } - - /** @var Syncroton_Model_Policy $_policy */ - $_policy = $this->_policyBackend->get($this->_device->policyId); - + + $policykey = $this->_policyBackend->get($this->_device->policyId)->policyKey; + $provision = $sync = $this->_outputDom->documentElement; $provision->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', 1)); $policies = $provision->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Policies')); $policy = $policies->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Policy')); $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'PolicyType', $this->_policyType)); $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'Status', 1)); - $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'PolicyKey', $_policy->policyKey)); + $policy->appendChild($this->_outputDom->createElementNS('uri:Provision', 'PolicyKey', $policykey)); - $this->_device->policykey = $_policy->policyKey; + $this->_device->policykey = $policykey; $this->_deviceBackend->update($this->_device); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/Search.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/Search.php
Changed
@@ -17,8 +17,8 @@ */ class Syncroton_Command_Search extends Syncroton_Command_Wbxml { - public const STATUS_SUCCESS = 1; - public const STATUS_SERVER_ERROR = 3; + const STATUS_SUCCESS = 1; + const STATUS_SERVER_ERROR = 3; protected $_defaultNameSpace = 'uri:Search'; protected $_documentElement = 'Search'; @@ -33,16 +33,9 @@ /** * parse search command request * - * @throws Syncroton_Exception_UnexpectedValue */ public function handle() { - if (! $this->_requestBody instanceof DOMDocument) { - throw new Syncroton_Exception_UnexpectedValue( - 'request body is no DOMDocument. got: ' . print_r($this->_requestBody, true) - ); - } - $xml = simplexml_import_dom($this->_requestBody); $this->_store = new Syncroton_Model_StoreRequest($xml->Store); @@ -55,26 +48,24 @@ public function getResponse() { $dataController = Syncroton_Data_Factory::factory($this->_store->name, $this->_device, new DateTime()); - - if (! $dataController instanceof Syncroton_Data_IDataSearch) { - throw new RuntimeException('class must be instanceof Syncroton_Data_IDataSearch'); + + if (! $dataController instanceof Syncroton_Data_IDataSearch) { + throw new RuntimeException('class must be instanceof Syncroton_Data_IDataSearch'); } - + try { // Search $storeResponse = $dataController->search($this->_store); $storeResponse->status = self::STATUS_SUCCESS; } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " search exception: " . $e->getMessage()); - } - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " saerch exception trace : " . $e->getTraceAsString()); - } - - $storeResponse = new Syncroton_Model_StoreResponse( - 'status' => self::STATUS_SERVER_ERROR, - ); + + $storeResponse = new Syncroton_Model_StoreResponse(array( + 'status' => self::STATUS_SERVER_ERROR + )); } $search = $this->_outputDom->documentElement;
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/SendMail.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/SendMail.php
Changed
@@ -38,36 +38,35 @@ $this->_saveInSent = $this->_requestParameters'saveInSent'; $this->_replaceMime = false; - $this->_source = + $this->_source = array( 'collectionId' => $this->_requestParameters'collectionId', 'itemId' => $this->_requestParameters'itemId', - 'instanceId' => null, - ; + 'instanceId' => null + ); - } elseif ($this->_requestBody) { + } 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 (isset ($xml->Source)) { if ($xml->Source->LongId) { $this->_source = (string)$xml->Source->LongId; } else { - $this->_source = + $this->_source = array( 'collectionId' => (string)$xml->Source->FolderId, 'itemId' => (string)$xml->Source->ItemId, - 'instanceId' => isset($xml->Source->InstanceId) ? (string)$xml->Source->InstanceId : null, - ; + 'instanceId' => isset($xml->Source->InstanceId) ? (string)$xml->Source->InstanceId : null + ); } } } if (empty($this->_mime)) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " Sending email failed: Empty input"); - } if (version_compare($this->_device->acsversion, '14.0', '<')) { @@ -76,9 +75,9 @@ } $response_type = 'Syncroton_Model_' . $this->_documentElement; - $response = new $response_type( + $response = new $response_type(array( 'status' => Syncroton_Exception_Status::INVALID_CONTENT, - ); + )); $response->appendXML($this->_outputDom->documentElement, $this->_device); @@ -86,9 +85,8 @@ } - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " saveInSent: " . (int)$this->_saveInSent); - } } /** @@ -103,14 +101,13 @@ try { $this->sendMail($dataController); } catch (Syncroton_Exception_Status $ses) { - if ($this->_logger instanceof Zend_Log) { + 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( + $response = new $response_type(array( 'status' => $ses->getCode(), - ); + )); $response->appendXML($this->_outputDom->documentElement, $this->_device);
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/Settings.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/Settings.php
Changed
@@ -15,13 +15,13 @@ * @package Syncroton * @subpackage Command */ -class Syncroton_Command_Settings extends Syncroton_Command_Wbxml +class Syncroton_Command_Settings extends Syncroton_Command_Wbxml { - public const STATUS_SUCCESS = 1; - + const STATUS_SUCCESS = 1; + protected $_defaultNameSpace = 'uri:Settings'; protected $_documentElement = 'Settings'; - + /** * @var Syncroton_Model_DeviceInformation */ @@ -30,45 +30,44 @@ protected $_userInformationRequested = false; protected $_OofGet; protected $_OofSet; - - + + /** - * process the XML file and add, change, delete or fetches data + * process the XML file and add, change, delete or fetches data * */ public function handle() { $xml = simplexml_import_dom($this->_requestBody); - - if (isset($xml->DeviceInformation->Set)) { - $this->_deviceInformation = new Syncroton_Model_DeviceInformation($xml->DeviceInformation->Set); - - $this->_device->model = $this->_deviceInformation->model; - $this->_device->imei = $this->_deviceInformation->iMEI; - $this->_device->friendlyname = $this->_deviceInformation->friendlyName; - $this->_device->os = $this->_deviceInformation->oS; - $this->_device->oslanguage = $this->_deviceInformation->oSLanguage; - $this->_device->phonenumber = $this->_deviceInformation->phoneNumber; + + if(isset($xml->DeviceInformation->Set)) { + $this->_deviceInformation = new Syncroton_Model_DeviceInformation($xml->DeviceInformation->Set); + + $this->_device->model = $this->_deviceInformation->model; + $this->_device->imei = $this->_deviceInformation->iMEI; + $this->_device->friendlyname = $this->_deviceInformation->friendlyName; + $this->_device->os = $this->_deviceInformation->oS; + $this->_device->oslanguage = $this->_deviceInformation->oSLanguage; + $this->_device->phonenumber = $this->_deviceInformation->phoneNumber; if ($this->_device->isDirty()) { - // @phpstan-ignore-next-line $this->_device = $this->_deviceBackend->update($this->_device); } } - - if (isset($xml->UserInformation->Get)) { + + if(isset($xml->UserInformation->Get)) { $this->_userInformationRequested = true; } if (isset($xml->Oof)) { if (isset($xml->Oof->Get)) { - $this->_OofGet = 'bodyType' => $xml->Oof->Get->BodyType; - } elseif (isset($xml->Oof->Set)) { + $this->_OofGet = array('bodyType' => $xml->Oof->Get->BodyType); + } else if (isset($xml->Oof->Set)) { $this->_OofSet = new Syncroton_Model_Oof($xml->Oof->Set); } } } - + /** * this function generates the response for the client * @@ -76,29 +75,29 @@ public function getResponse() { $settings = $this->_outputDom->documentElement; - + $settings->appendChild($this->_outputDom->createElementNS('uri:Settings', 'Status', self::STATUS_SUCCESS)); - + if ($this->_deviceInformation instanceof Syncroton_Model_DeviceInformation) { $deviceInformation = $settings->appendChild($this->_outputDom->createElementNS('uri:Settings', 'DeviceInformation')); $set = $deviceInformation->appendChild($this->_outputDom->createElementNS('uri:Settings', 'Set')); $set->appendChild($this->_outputDom->createElementNS('uri:Settings', 'Status', self::STATUS_SUCCESS)); } - + if ($this->_userInformationRequested === true) { $userInformation = $settings->appendChild($this->_outputDom->createElementNS('uri:Settings', 'UserInformation')); $userInformation->appendChild($this->_outputDom->createElementNS('uri:Settings', 'Status', self::STATUS_SUCCESS)); $get = $userInformation->appendChild($this->_outputDom->createElementNS('uri:Settings', 'Get')); - /* - $smtpAddresses = array(); - if (!empty($smtpAddresses)) { - $emailAddresses = $get->appendChild($this->_outputDom->createElementNS('uri:Settings', 'EmailAddresses')); - foreach($smtpAddresses as $smtpAddress) { - $emailAddresses->appendChild($this->_outputDom->createElementNS('uri:Settings', 'SMTPAddress', $smtpAddress)); - } - } - */ +/* + $smtpAddresses = array(); + if (!empty($smtpAddresses)) { + $emailAddresses = $get->appendChild($this->_outputDom->createElementNS('uri:Settings', 'EmailAddresses')); + foreach($smtpAddresses as $smtpAddress) { + $emailAddresses->appendChild($this->_outputDom->createElementNS('uri:Settings', 'SMTPAddress', $smtpAddress)); + } + } +*/ $userAccounts = $this->_deviceBackend->userAccounts($this->_device); if (!empty($userAccounts)) { $accounts = $get->appendChild($this->_outputDom->createElementNS('uri:Settings', 'Accounts')); @@ -111,10 +110,8 @@ // Out-of-Office if (!empty($this->_OofGet)) { - $OofGet = null; try { $OofGet = $this->_deviceBackend->getOOF($this->_OofGet); - $OofStatus = self::STATUS_SUCCESS; } catch (Exception $e) { if ($e instanceof Syncroton_Exception_Status) { $OofStatus = $e->getCode(); @@ -134,7 +131,7 @@ $Get = $Oof->appendChild($this->_outputDom->createElementNS('uri:Settings', 'Get')); $OofGet->appendXML($Get, $this->_device); } - } elseif (!empty($this->_OofSet)) { + } else if (!empty($this->_OofSet)) { try { $this->_deviceBackend->setOOF($this->_OofSet); $OofStatus = self::STATUS_SUCCESS;
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/Sync.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/Sync.php
Changed
@@ -15,82 +15,82 @@ * @package Syncroton * @subpackage Command */ -class Syncroton_Command_Sync extends Syncroton_Command_Wbxml +class Syncroton_Command_Sync extends Syncroton_Command_Wbxml { - public const STATUS_SUCCESS = 1; - public const STATUS_PROTOCOL_VERSION_MISMATCH = 2; - public const STATUS_INVALID_SYNC_KEY = 3; - public const STATUS_PROTOCOL_ERROR = 4; - public const STATUS_SERVER_ERROR = 5; - public const STATUS_ERROR_IN_CLIENT_SERVER_CONVERSION = 6; - public const STATUS_CONFLICT_MATCHING_THE_CLIENT_AND_SERVER_OBJECT = 7; - public const STATUS_OBJECT_NOT_FOUND = 8; - public const STATUS_USER_ACCOUNT_MAYBE_OUT_OF_DISK_SPACE = 9; - public const STATUS_ERROR_SETTING_NOTIFICATION_GUID = 10; - public const STATUS_DEVICE_NOT_PROVISIONED_FOR_NOTIFICATIONS = 11; - public const STATUS_FOLDER_HIERARCHY_HAS_CHANGED = 12; - public const STATUS_RESEND_FULL_XML = 13; - public const STATUS_WAIT_INTERVAL_OUT_OF_RANGE = 14; - public const STATUS_TOO_MANY_COLLECTIONS = 15; - - public const CONFLICT_OVERWRITE_SERVER = 0; - public const CONFLICT_OVERWRITE_PIM = 1; - - public const MIMESUPPORT_DONT_SEND_MIME = 0; - public const MIMESUPPORT_SMIME_ONLY = 1; - public const MIMESUPPORT_SEND_MIME = 2; - - public const BODY_TYPE_PLAIN_TEXT = 1; - public const BODY_TYPE_HTML = 2; - public const BODY_TYPE_RTF = 3; - public const BODY_TYPE_MIME = 4; - + const STATUS_SUCCESS = 1; + const STATUS_PROTOCOL_VERSION_MISMATCH = 2; + const STATUS_INVALID_SYNC_KEY = 3; + const STATUS_PROTOCOL_ERROR = 4; + const STATUS_SERVER_ERROR = 5; + const STATUS_ERROR_IN_CLIENT_SERVER_CONVERSION = 6; + const STATUS_CONFLICT_MATCHING_THE_CLIENT_AND_SERVER_OBJECT = 7; + const STATUS_OBJECT_NOT_FOUND = 8; + const STATUS_USER_ACCOUNT_MAYBE_OUT_OF_DISK_SPACE = 9; + const STATUS_ERROR_SETTING_NOTIFICATION_GUID = 10; + const STATUS_DEVICE_NOT_PROVISIONED_FOR_NOTIFICATIONS = 11; + const STATUS_FOLDER_HIERARCHY_HAS_CHANGED = 12; + const STATUS_RESEND_FULL_XML = 13; + const STATUS_WAIT_INTERVAL_OUT_OF_RANGE = 14; + const STATUS_TOO_MANY_COLLECTIONS = 15; + + const CONFLICT_OVERWRITE_SERVER = 0; + const CONFLICT_OVERWRITE_PIM = 1; + + const MIMESUPPORT_DONT_SEND_MIME = 0; + const MIMESUPPORT_SMIME_ONLY = 1; + const MIMESUPPORT_SEND_MIME = 2; + + const BODY_TYPE_PLAIN_TEXT = 1; + const BODY_TYPE_HTML = 2; + const BODY_TYPE_RTF = 3; + const BODY_TYPE_MIME = 4; + /** * truncate types */ - public const TRUNCATE_ALL = 0; - public const TRUNCATE_4096 = 1; - public const TRUNCATE_5120 = 2; - public const TRUNCATE_7168 = 3; - public const TRUNCATE_10240 = 4; - public const TRUNCATE_20480 = 5; - public const TRUNCATE_51200 = 6; - public const TRUNCATE_102400 = 7; - public const TRUNCATE_NOTHING = 8; - + const TRUNCATE_ALL = 0; + const TRUNCATE_4096 = 1; + const TRUNCATE_5120 = 2; + const TRUNCATE_7168 = 3; + const TRUNCATE_10240 = 4; + const TRUNCATE_20480 = 5; + const TRUNCATE_51200 = 6; + const TRUNCATE_102400 = 7; + const TRUNCATE_NOTHING = 8; + /** * filter types */ - public const FILTER_NOTHING = 0; - public const FILTER_1_DAY_BACK = 1; - public const FILTER_3_DAYS_BACK = 2; - public const FILTER_1_WEEK_BACK = 3; - public const FILTER_2_WEEKS_BACK = 4; - public const FILTER_1_MONTH_BACK = 5; - public const FILTER_3_MONTHS_BACK = 6; - public const FILTER_6_MONTHS_BACK = 7; - public const FILTER_INCOMPLETE = 8; - - + const FILTER_NOTHING = 0; + const FILTER_1_DAY_BACK = 1; + const FILTER_3_DAYS_BACK = 2; + const FILTER_1_WEEK_BACK = 3; + const FILTER_2_WEEKS_BACK = 4; + const FILTER_1_MONTH_BACK = 5; + const FILTER_3_MONTHS_BACK = 6; + const FILTER_6_MONTHS_BACK = 7; + const FILTER_INCOMPLETE = 8; + + protected $_defaultNameSpace = 'uri:AirSync'; protected $_documentElement = 'Sync'; - + /** * list of collections * - * @var array<string,Syncroton_Model_SyncCollection> + * @var array */ - protected $_collections = ; - - protected $_modifications = ; - + protected $_collections = array(); + + protected $_modifications = array(); + /** * the global WindowSize * * @var integer */ protected $_globalWindowSize; - + /** * there are more entries than WindowSize available * the MoreAvailable tag hot added to the xml output @@ -98,65 +98,69 @@ * @var boolean */ protected $_moreAvailable = false; - + + /** + * @var Syncroton_Model_SyncState + */ + protected $_syncState; + protected $_maxWindowSize = 100; - + protected $_heartbeatInterval = null; - + /** - * process the XML file and add, change, delete or fetches data + * process the XML file and add, change, delete or fetches data */ public function handle() { // input xml $requestXML = simplexml_import_dom($this->_mergeSyncRequest($this->_requestBody, $this->_device)); - + if (! isset($requestXML->Collections)) { $this->_outputDom->documentElement->appendChild( $this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_RESEND_FULL_XML) ); - + return $this->_outputDom; } - - $intervalDiv = 1; + if (isset($requestXML->HeartbeatInterval)) { $intervalDiv = 1; $this->_heartbeatInterval = (int)$requestXML->HeartbeatInterval; - } elseif (isset($requestXML->Wait)) { + } else if (isset($requestXML->Wait)) { $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)); - $sync->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Limit', floor($maxInterval / $intervalDiv))); + $sync->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Limit', floor($maxInterval/$intervalDiv))); $this->_heartbeatInterval = null; return; } - + $this->_globalWindowSize = isset($requestXML->WindowSize) ? (int)$requestXML->WindowSize : 100; if (!$this->_globalWindowSize || $this->_globalWindowSize > 512) { $this->_globalWindowSize = 512; } - + if ($this->_globalWindowSize > $this->_maxWindowSize) { $this->_globalWindowSize = $this->_maxWindowSize; } - + // load options from lastsynccollection - $lastSyncCollection = 'options' => ; + $lastSyncCollection = array('options' => array()); if (!empty($this->_device->lastsynccollection)) { $lastSyncCollection = Zend_Json::decode($this->_device->lastsynccollection); if (!array_key_exists('options', $lastSyncCollection) || !is_array($lastSyncCollection'options')) { - $lastSyncCollection'options' = ; + $lastSyncCollection'options' = array(); } } @@ -168,117 +172,106 @@ return; } - $collections = ; - + $collections = array(); + foreach ($requestXML->Collections->Collection as $xmlCollection) { $collectionId = (string)$xmlCollection->CollectionId; - + $collections$collectionId = new Syncroton_Model_SyncCollection($xmlCollection); - + // do we have to reuse the options from the previous request? if (!isset($xmlCollection->Options) && array_key_exists($collectionId, $lastSyncCollection'options')) { $collections$collectionId->options = $lastSyncCollection'options'$collectionId; - if ($this->_logger instanceof Zend_Log) { - $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " restored options to " . print_r($collections$collectionId->options, true)); - } + if ($this->_logger instanceof Zend_Log) + $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " restored options to " . print_r($collections$collectionId->options, TRUE)); } - + // store current options for next Sync command request (sticky options) $lastSyncCollection'options'$collectionId = $collections$collectionId->options; } - + $this->_device->lastsynccollection = Zend_Json::encode($lastSyncCollection); - + if ($this->_device->isDirty()) { Syncroton_Registry::getDeviceBackend()->update($this->_device); } - + foreach ($collections as $collectionData) { // has the folder been synchronised to the device already try { $collectionData->folder = $this->_folderBackend->getFolder($this->_device, $collectionData->collectionId); - + } catch (Syncroton_Exception_NotFound $senf) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " folder {$collectionData->collectionId} not found"); - } - + // trigger INVALID_SYNCKEY instead of OBJECT_NOTFOUND when synckey is higher than 0 // to avoid a syncloop for the iPhone if ($collectionData->syncKey > 0) { - $collectionData->folder = new Syncroton_Model_Folder( + $collectionData->folder = new Syncroton_Model_Folder(array( 'deviceId' => $this->_device, - 'serverId' => $collectionData->collectionId, - ); + 'serverId' => $collectionData->collectionId + )); } - + $this->_collections$collectionData->collectionId = $collectionData; - + continue; } - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " SyncKey is {$collectionData->syncKey} Class: {$collectionData->folder->class} CollectionId: {$collectionData->collectionId}"); - } - + // initial synckey if($collectionData->syncKey === 0) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " initial client synckey 0 provided"); - } - + // reset sync state for this folder $this->_syncStateBackend->resetState($this->_device, $collectionData->folder); $this->_contentStateBackend->resetState($this->_device, $collectionData->folder); - - $collectionData->syncState = new Syncroton_Model_SyncState( + + $collectionData->syncState = new Syncroton_Model_SyncState(array( 'device_id' => $this->_device, 'counter' => 0, 'type' => $collectionData->folder, - 'lastsync' => $this->_syncTimeStamp, - ); - + 'lastsync' => $this->_syncTimeStamp + )); + $this->_collections$collectionData->collectionId = $collectionData; - + continue; } - - $syncKeyReused = $this->_syncStateBackend->haveNext($this->_device, $collectionData->folder, $collectionData->syncKey); - if ($syncKeyReused) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " already known synckey {$collectionData->syncKey} provided"); - } - } - // check for invalid synckey + + // check for invalid sycnkey if(($collectionData->syncState = $this->_syncStateBackend->validate($this->_device, $collectionData->folder, $collectionData->syncKey)) === false) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " invalid synckey {$collectionData->syncKey} provided"); - } - + // reset sync state for this folder $this->_syncStateBackend->resetState($this->_device, $collectionData->folder); $this->_contentStateBackend->resetState($this->_device, $collectionData->folder); - + $this->_collections$collectionData->collectionId = $collectionData; - + continue; } - + $dataController = Syncroton_Data_Factory::factory($collectionData->folder->class, $this->_device, $this->_syncTimeStamp); - + switch($collectionData->folder->class) { case Syncroton_Data_Factory::CLASS_CALENDAR: $dataClass = 'Syncroton_Model_Event'; break; - + case Syncroton_Data_Factory::CLASS_CONTACTS: $dataClass = 'Syncroton_Model_Contact'; break; - + case Syncroton_Data_Factory::CLASS_EMAIL: $dataClass = 'Syncroton_Model_Email'; break; - + case Syncroton_Data_Factory::CLASS_NOTES: $dataClass = 'Syncroton_Model_Note'; break; @@ -286,274 +279,157 @@ case Syncroton_Data_Factory::CLASS_TASKS: $dataClass = 'Syncroton_Model_Task'; break; - + default: throw new Syncroton_Exception_UnexpectedValue('invalid class provided'); + break; } - - $clientModifications = - 'added' => , - 'changed' => , - 'deleted' => , - 'forceAdd' => , - 'forceChange' => , - 'toBeFetched' => , - ; - + + $clientModifications = array( + 'added' => array(), + 'changed' => array(), + 'deleted' => array(), + 'forceAdd' => array(), + 'forceChange' => array(), + 'toBeFetched' => array(), + ); + // handle incoming data if($collectionData->hasClientAdds()) { $adds = $collectionData->getClientAdds(); - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " found " . count($adds) . " entries to be added to server"); - } - - $clientIdMap = ; - if ($syncKeyReused && $collectionData->syncState->clientIdMap) { - $clientIdMap = Zend_Json::decode($collectionData->syncState->clientIdMap); - } - + foreach ($adds as $add) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " add entry with clientId " . (string) $add->ClientId); - } try { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " adding entry as new"); - } - - $clientId = (string)$add->ClientId; - // If the sync key was reused, but we don't have a $clientId mapping, - // this means the client sent a new item with the same sync_key. - if ($syncKeyReused && array_key_exists($clientId, $clientIdMap)) { - // We don't normally store the clientId, so if a command with Add's is resent, - // we have to look-up the corresponding serverId using a cached clientId => serverId mapping, - // otherwise we would duplicate all added items on resend. - $serverId = $clientIdMap$clientId; - $clientModifications'added'$serverId = - 'clientId' => (string)$add->ClientId, - 'serverId' => $serverId, - 'status' => self::STATUS_SUCCESS, - 'contentState' => null, - ; - } else { - $serverId = $dataController->createEntry($collectionData->collectionId, new $dataClass($add->ApplicationData)); - $clientModifications'added'$serverId = - 'clientId' => (string)$add->ClientId, - 'serverId' => $serverId, - 'status' => self::STATUS_SUCCESS, - 'contentState' => $this->_contentStateBackend->create(new Syncroton_Model_Content( - 'device_id' => $this->_device, - 'folder_id' => $collectionData->folder, - 'contentid' => $serverId, - 'creation_time' => $this->_syncTimeStamp, - 'creation_synckey' => $collectionData->syncKey + 1, - )), - ; - } - + + $serverId = $dataController->createEntry($collectionData->collectionId, new $dataClass($add->ApplicationData)); + + $clientModifications'added'$serverId = array( + 'clientId' => (string)$add->ClientId, + 'serverId' => $serverId, + 'status' => self::STATUS_SUCCESS, + 'contentState' => $this->_contentStateBackend->create(new Syncroton_Model_Content(array( + 'device_id' => $this->_device, + 'folder_id' => $collectionData->folder, + 'contentid' => $serverId, + 'creation_time' => $this->_syncTimeStamp, + 'creation_synckey' => $collectionData->syncKey + 1 + ))) + ); + } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " failed to add entry " . $e->getMessage()); - } - $clientModifications'added' = + $clientModifications'added' = array( 'clientId' => (string)$add->ClientId, - 'status' => self::STATUS_SERVER_ERROR, - ; + 'status' => self::STATUS_SERVER_ERROR + ); } } } - + // handle changes, but only if not first sync - if(!$syncKeyReused && $collectionData->syncKey > 1 && $collectionData->hasClientChanges()) { + if($collectionData->syncKey > 1 && $collectionData->hasClientChanges()) { $changes = $collectionData->getClientChanges(); - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " found " . count($changes) . " entries to be updated on server"); - } - + foreach ($changes as $change) { $serverId = (string)$change->ServerId; - + try { $dataController->updateEntry($collectionData->collectionId, $serverId, new $dataClass($change->ApplicationData)); $clientModifications'changed'$serverId = self::STATUS_SUCCESS; - + } catch (Syncroton_Exception_AccessDenied $e) { $clientModifications'changed'$serverId = self::STATUS_CONFLICT_MATCHING_THE_CLIENT_AND_SERVER_OBJECT; $clientModifications'forceChange'$serverId = $serverId; - + } catch (Syncroton_Exception_NotFound $e) { // entry does not exist anymore, will get deleted automaticaly $clientModifications'changed'$serverId = self::STATUS_OBJECT_NOT_FOUND; - + } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " failed to update entry " . $e); - } // something went wrong while trying to update the entry $clientModifications'changed'$serverId = self::STATUS_SERVER_ERROR; } } } - + // handle deletes, but only if not first sync - if(!$syncKeyReused && $collectionData->hasClientDeletes()) { + if($collectionData->hasClientDeletes()) { $deletes = $collectionData->getClientDeletes(); - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " found " . count($deletes) . " entries to be deleted on server"); - } - + foreach ($deletes as $delete) { $serverId = (string)$delete->ServerId; - + try { // check if we have sent this entry to the phone $state = $this->_contentStateBackend->getContentState($this->_device, $collectionData->folder, $serverId); - + try { $dataController->deleteEntry($collectionData->collectionId, $serverId, $collectionData); - + } catch(Syncroton_Exception_NotFound $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->crit(__METHOD__ . '::' . __LINE__ . ' tried to delete entry ' . $serverId . ' but entry was not found'); - } - + } catch (Syncroton_Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' tried to delete entry ' . $serverId . ' but a error occured: ' . $e->getMessage()); - } $clientModifications'forceAdd'$serverId = $serverId; } $this->_contentStateBackend->delete($state); - + } catch (Syncroton_Exception_NotFound $senf) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' ' . $serverId . ' should have been removed from client already'); - } // should we send a special status??? //$collectionData->deleted$serverId = self::STATUS_SUCCESS; } - + $clientModifications'deleted'$serverId = self::STATUS_SUCCESS; } } - + // handle fetches, but only if not first sync if($collectionData->syncKey > 1 && $collectionData->hasClientFetches()) { // the default value for GetChanges is 1. If the phone don't want the changes it must set GetChanges to 0 // some prevoius versions of iOS did not set GetChanges to 0 for fetches. Let's enforce getChanges to false here. $collectionData->getChanges = false; - + $fetches = $collectionData->getClientFetches(); - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " found " . count($fetches) . " entries to be fetched from server"); - } - - $toBeFetched = ; - + + $toBeFetched = array(); + foreach ($fetches as $fetch) { $serverId = (string)$fetch->ServerId; - + $toBeFetched$serverId = $serverId; } - + $collectionData->toBeFetched = $toBeFetched; } - + $this->_collections$collectionData->collectionId = $collectionData; $this->_modifications$collectionData->collectionId = $clientModifications; } } - - private function getServerModifications($dataController, $collectionData, $clientModifications) - { - $serverModifications = - 'added' => , - 'changed' => , - 'deleted' => , - ; - - // We first use hasChanges because it has a fast path for when there are no changes by fetching the count of messages only. - // However, in all other cases we will end up fetching the same entries as below, which is less than ideal. - // TODO: We should create a new method, which checks if there are no changes, and otherwise just let the code below figure out - // if there are any changes to process. - if (!$dataController->hasChanges($this->_contentStateBackend, $collectionData->folder, $collectionData->syncState)) { - return $serverModifications; - } - - // update _syncTimeStamp as $dataController->hasChanges might have spent some time - $this->_syncTimeStamp = new DateTime('now', new DateTimeZone('UTC')); - - // fetch entries added since last sync - $allClientEntries = $this->_contentStateBackend->getFolderState( - $this->_device, - $collectionData->folder, - $collectionData->syncState->counter - ); - - // fetch entries changed since last sync - $allChangedEntries = $dataController->getChangedEntries( - $collectionData->collectionId, - $collectionData->syncState, - $collectionData->options'filterType' - ); - - // fetch all entries - $allServerEntries = $dataController->getServerEntries( - $collectionData->collectionId, - $collectionData->options'filterType' - ); - - // add entries - $serverDiff = array_diff($allServerEntries, $allClientEntries); - // add entries which produced problems during delete from client - $serverModifications'added' = $clientModifications'forceAdd'; - // add entries not yet sent to client - $serverModifications'added' = array_unique(array_merge($serverModifications'added', $serverDiff)); - - // @todo still needed? - foreach($serverModifications'added' as $id => $serverId) { - // skip entries added by client during this sync session - if(isset($clientModifications'added'$serverId) && !isset($clientModifications'forceAdd'$serverId)) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped added entry: " . $serverId); - } - unset($serverModifications'added'$id); - } - } - - // entries to be deleted - $serverModifications'deleted' = array_diff($allClientEntries, $allServerEntries); - - // entries changed since last sync - $serverModifications'changed' = array_merge($allChangedEntries, $clientModifications'forceChange'); - - foreach($serverModifications'changed' as $id => $serverId) { - // skip entry, if it got changed by client during current sync - if(isset($clientModifications'changed'$serverId) && !isset($clientModifications'forceChange'$serverId)) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped changed entry: " . $serverId); - } - unset($serverModifications'changed'$id); - } - // skip entry, make sure we don't sent entries already added by client in this request - elseif (isset($clientModifications'added'$serverId) && !isset($clientModifications'forceAdd'$serverId)) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped change for added entry: " . $serverId); - } - unset($serverModifications'changed'$id); - } - } - - // entries comeing in scope are already in $serverModifications'added' and do not need to - // be send with $serverCanges - $serverModifications'changed' = array_diff($serverModifications'changed', $serverModifications'added'); - - return $serverModifications; - } - + /** * (non-PHPdoc) * @see Syncroton_Command_Wbxml::getResponse() @@ -561,20 +437,20 @@ public function getResponse() { $sync = $this->_outputDom->documentElement; - + $collections = $this->_outputDom->createElementNS('uri:AirSync', 'Collections'); $totalChanges = 0; // Detect devices that do not support empty Sync reponse $emptySyncSupported = !preg_match('/(meego|nokian800)/i', $this->_device->useragent); - + // continue only if there are changes or no time is left if ($this->_heartbeatInterval > 0) { $intervalStart = time(); $sleepCallback = Syncroton_Registry::getSleepCallback(); $wakeupCallback = Syncroton_Registry::getWakeupCallback(); - + do { // take a break to save battery lifetime $sleepCallback(); @@ -582,94 +458,90 @@ // make sure the connection is still alive, abort otherwise if (connection_aborted()) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " Exiting on aborted connection"); - } exit; } $wakeupCallback(); - - $now = new DateTime('now', new DateTimeZone('UTC')); + + $now = new DateTime(null, new DateTimeZone('utc')); foreach($this->_collections as $collectionData) { - // continue immediately if folder does not exist + // continue immediately if folder does not exist if (! ($collectionData->folder instanceof Syncroton_Model_IFolder)) { break 2; - - // countinue immediately if syncstate is invalid + + // countinue immediately if syncstate is invalid } elseif (! ($collectionData->syncState instanceof Syncroton_Model_ISyncState)) { break 2; - + } else { if ($collectionData->getChanges !== true) { continue; } - + try { // just check if the folder still exists $this->_folderBackend->get($collectionData->folder); } catch (Syncroton_Exception_NotFound $senf) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " collection does not exist anymore: " . $collectionData->collectionId); - } - + $collectionData->getChanges = false; - + // make sure this is the last while loop // no break 2 here, as we like to check the other folders too $intervalStart -= $this->_heartbeatInterval; } - + // check that the syncstate still exists and is still valid try { $syncState = $this->_syncStateBackend->getSyncState($this->_device, $collectionData->folder); - + // another process synchronized data of this folder already. let's skip it if ($syncState->id !== $collectionData->syncState->id) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " syncstate changed during heartbeat interval for collection: " . $collectionData->folder->serverId); - } - + $collectionData->getChanges = false; - + // make sure this is the last while loop // no break 2 here, as we like to check the other folders too $intervalStart -= $this->_heartbeatInterval; } } catch (Syncroton_Exception_NotFound $senf) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " no syncstate found anymore for collection: " . $collectionData->folder->serverId); - } - + $collectionData->syncState = null; - + // make sure this is the last while loop // no break 2 here, as we like to check the other folders too $intervalStart -= $this->_heartbeatInterval; } - - + + // safe battery time by skipping folders which got synchronied less than Syncroton_Command_Ping::$quietTime seconds ago - if (! $collectionData->syncState instanceof Syncroton_Model_SyncState || + if ( ! $collectionData->syncState instanceof Syncroton_Model_SyncState || ($now->getTimestamp() - $collectionData->syncState->lastsync->getTimestamp()) < Syncroton_Registry::getQuietTime()) { continue; } - - $dataController = Syncroton_Data_Factory::factory($collectionData->folder->class, $this->_device, $this->_syncTimeStamp); - + + $dataController = Syncroton_Data_Factory::factory($collectionData->folder->class , $this->_device, $this->_syncTimeStamp); + // countinue immediately if there are any changes available if($dataController->hasChanges($this->_contentStateBackend, $collectionData->folder, $collectionData->syncState)) { break 2; } } } - - // See: http://www.tine20.org/forum/viewtopic.php?f=12&t=12146 - // - // 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 + + // See: http://www.tine20.org/forum/viewtopic.php?f=12&t=12146 + // + // 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 (Syncroton_Server::validateSession() && time() - $intervalStart < $this->_heartbeatInterval - (Syncroton_Registry::getPingTimeout() + 10)); } @@ -677,47 +549,27 @@ foreach ($this->_collections as $collectionData) { if (! ($collectionData->folder instanceof Syncroton_Model_IFolder)) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " Detected a folder hierarchy change on {$collectionData->collectionId}."); - } $sync->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_FOLDER_HIERARCHY_HAS_CHANGED)); return $this->_outputDom; } } - // Handle Calendar folders first. - // Outlook can't match MeetingRequest with an event that wasn't synced yet, which - // leads to duplicated events in Outlook's calendar. - uasort( - $this->_collections, - function ($a, $b) { - $ac = $a->folder && $a->folder->class == Syncroton_Data_Factory::CLASS_CALENDAR; - $bc = $b->folder && $b->folder->class == Syncroton_Data_Factory::CLASS_CALENDAR; - if ($ac) { - return $bc ? 0 : -1; - } - return $bc ? 1 : 0; - } - ); - - foreach ($this->_collections as $collectionData) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " Processing {$collectionData->collectionId}..."); - } - + foreach($this->_collections as $collectionData) { $collectionChanges = 0; - + /** * keep track of entries added on server side */ - $newContentStates = ; - + $newContentStates = array(); + /** * keep track of entries deleted on server side */ - $deletedContentStates = ; - + $deletedContentStates = array(); + // invalid synckey provided if (! ($collectionData->syncState instanceof Syncroton_Model_ISyncState)) { // set synckey to 0 @@ -725,8 +577,8 @@ $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey', 0)); $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $collectionData->collectionId)); $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_INVALID_SYNC_KEY)); - - // initial sync + + // initial sync } elseif ($collectionData->syncState->counter === 0) { $collectionData->syncState->counter++; @@ -739,51 +591,125 @@ $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey', $collectionData->syncState->counter)); $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $collectionData->collectionId)); $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_SUCCESS)); + } else { - $dataController = Syncroton_Data_Factory::factory($collectionData->folder->class, $this->_device, $this->_syncTimeStamp); + $dataController = Syncroton_Data_Factory::factory($collectionData->folder->class , $this->_device, $this->_syncTimeStamp); + $clientModifications = $this->_modifications$collectionData->collectionId; - $serverModifications = - 'added' => , - 'changed' => , - 'deleted' => , - ; + $serverModifications = array( + 'added' => array(), + 'changed' => array(), + 'deleted' => array(), + ); $status = self::STATUS_SUCCESS; + $hasChanges = 0; - if ($collectionData->getChanges === true) { + if($collectionData->getChanges === true) { // continue sync session? if(is_array($collectionData->syncState->pendingdata)) { + if ($this->_logger instanceof Zend_Log) + $this->_logger->info(__METHOD__ . '::' . __LINE__ . " restored from sync state "); + $serverModifications = $collectionData->syncState->pendingdata; - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " restored from sync state."); - } } else { try { - $serverModifications = $this->getServerModifications($dataController, $collectionData, $clientModifications); + $hasChanges = $dataController->hasChanges($this->_contentStateBackend, $collectionData->folder, $collectionData->syncState); } catch (Syncroton_Exception_NotFound $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " Folder changes checking failed (not found): " . $e->getTraceAsString()); - } $status = self::STATUS_FOLDER_HIERARCHY_HAS_CHANGED; } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->crit(__METHOD__ . '::' . __LINE__ . " Folder changes checking failed: " . $e->getMessage()); + + // Prevent from removing client entries when getServerEntries() fails + // @todo: should we break the loop here? + $status = self::STATUS_SERVER_ERROR; + } + } + + if ($hasChanges) { + // update _syncTimeStamp as $dataController->hasChanges might have spent some time + $this->_syncTimeStamp = new DateTime(null, new DateTimeZone('utc')); + + try { + // fetch entries added since last sync + $allClientEntries = $this->_contentStateBackend->getFolderState( + $this->_device, + $collectionData->folder + ); + + // fetch entries changed since last sync + $allChangedEntries = $dataController->getChangedEntries( + $collectionData->collectionId, + $collectionData->syncState->lastsync, + $this->_syncTimeStamp, + $collectionData->options'filterType' + ); + + // fetch all entries + $allServerEntries = $dataController->getServerEntries( + $collectionData->collectionId, + $collectionData->options'filterType' + ); + + // add entries + $serverDiff = array_diff($allServerEntries, $allClientEntries); + // add entries which produced problems during delete from client + $serverModifications'added' = $clientModifications'forceAdd'; + // add entries not yet sent to client + $serverModifications'added' = array_unique(array_merge($serverModifications'added', $serverDiff)); + + // @todo still needed? + foreach($serverModifications'added' as $id => $serverId) { + // skip entries added by client during this sync session + if(isset($clientModifications'added'$serverId) && !isset($clientModifications'forceAdd'$serverId)) { + if ($this->_logger instanceof Zend_Log) + $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped added entry: " . $serverId); + unset($serverModifications'added'$id); + } + } + + // entries to be deleted + $serverModifications'deleted' = array_diff($allClientEntries, $allServerEntries); + + // entries changed since last sync + $serverModifications'changed' = array_merge($allChangedEntries, $clientModifications'forceChange'); + + foreach($serverModifications'changed' as $id => $serverId) { + // skip entry, if it got changed by client during current sync + if(isset($clientModifications'changed'$serverId) && !isset($clientModifications'forceChange'$serverId)) { + if ($this->_logger instanceof Zend_Log) + $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped changed entry: " . $serverId); + unset($serverModifications'changed'$id); + } + // skip entry, make sure we don't sent entries already added by client in this request + else if (isset($clientModifications'added'$serverId) && !isset($clientModifications'forceAdd'$serverId)) { + if ($this->_logger instanceof Zend_Log) + $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped change for added entry: " . $serverId); + unset($serverModifications'changed'$id); + } } - if ($this->_logger instanceof Zend_Log) { + // entries comeing in scope are already in $serverModifications'added' and do not need to + // be send with $serverCanges + $serverModifications'changed' = array_diff($serverModifications'changed', $serverModifications'added'); + } catch (Exception $e) { + if ($this->_logger instanceof Zend_Log) + $this->_logger->crit(__METHOD__ . '::' . __LINE__ . " Folder state checking failed: " . $e->getMessage()); + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " Folder state checking failed: " . $e->getTraceAsString()); - } // Prevent from removing client entries when getServerEntries() fails // @todo: should we break the loop here? $status = self::STATUS_SERVER_ERROR; } - } - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " found (added/changed/deleted) " . count($serverModifications'added') . '/' . count($serverModifications'changed') . '/' . count($serverModifications'deleted') . ' entries for sync from server to client'); + if ($this->_logger instanceof Zend_Log) + $this->_logger->info(__METHOD__ . '::' . __LINE__ . " found (added/changed/deleted) " . count($serverModifications'added') . '/' . count($serverModifications'changed') . '/' . count($serverModifications'deleted') . ' entries for sync from server to client'); } } @@ -792,31 +718,27 @@ if (!empty($collectionData->folder->class)) { $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Class', $collectionData->folder->class)); } - + $syncKeyElement = $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey')); - + $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $collectionData->collectionId)); $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', $status)); - + $responses = $this->_outputDom->createElementNS('uri:AirSync', 'Responses'); - - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " Processing collection " . $collectionData->collectionId); - } - + // send reponse for newly added entries if(!empty($clientModifications'added')) { foreach($clientModifications'added' as $entryData) { $add = $responses->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Add')); $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ClientId', $entryData'clientId')); - // we have no serverId if the add failed + // we have no serverId is the add failed if(isset($entryData'serverId')) { $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $entryData'serverId')); } $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', $entryData'status')); } } - + // send reponse for changed entries if(!empty($clientModifications'changed')) { foreach($clientModifications'changed' as $serverId => $status) { @@ -827,12 +749,12 @@ } } } - + // send response for to be fetched entries if(!empty($collectionData->toBeFetched)) { // unset all truncation settings as entries are not allowed to be truncated during fetch $fetchCollectionData = clone $collectionData; - + // unset truncationSize if (isset($fetchCollectionData->options'bodyPreferences') && is_array($fetchCollectionData->options'bodyPreferences')) { foreach($fetchCollectionData->options'bodyPreferences' as $key => $bodyPreference) { @@ -840,86 +762,101 @@ } } $fetchCollectionData->options'mimeTruncation' = Syncroton_Command_Sync::TRUNCATE_NOTHING; - + foreach($collectionData->toBeFetched as $serverId) { $fetch = $responses->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Fetch')); $fetch->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $serverId)); - + try { $applicationData = $this->_outputDom->createElementNS('uri:AirSync', 'ApplicationData'); - + $dataController ->getEntry($fetchCollectionData, $serverId) ->appendXML($applicationData, $this->_device); - + $fetch->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_SUCCESS)); - + $fetch->appendChild($applicationData); } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage()); - } - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getTraceAsString()); - } $fetch->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_OBJECT_NOT_FOUND)); } } } - + if ($responses->hasChildNodes() === true) { $collection->appendChild($responses); } - + $commands = $this->_outputDom->createElementNS('uri:AirSync', 'Commands'); - + foreach($serverModifications'added' as $id => $serverId) { if($collectionChanges == $collectionData->windowSize || $totalChanges + $collectionChanges >= $this->_globalWindowSize) { break; } - + + #/** + # * somewhere is a problem in the logic for handling moreAvailable + # * + # * it can happen, that we have a contentstate (which means we sent the entry to the client + # * and that this entry is yet in $collectionData->syncState->pendingdata'serverAdds' + # * I have no idea how this can happen, but the next lines of code work around this problem + # */ + #try { + # $this->_contentStateBackend->getContentState($this->_device, $collectionData->folder, $serverId); + # + # if ($this->_logger instanceof Zend_Log) + # $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped an entry($serverId) which is already on the client"); + # + # unset($serverModifications'added'$id); + # continue; + # + #} catch (Syncroton_Exception_NotFound $senf) { + # // do nothing => content state should not exist yet + #} + try { $add = $this->_outputDom->createElementNS('uri:AirSync', 'Add'); $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $serverId)); - + $applicationData = $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ApplicationData')); - - $dataController - ->getEntry($collectionData, $serverId) - ->appendXML($applicationData, $this->_device); - + + $dataController + ->getEntry($collectionData, $serverId) + ->appendXML($applicationData, $this->_device); + $commands->appendChild($add); - - $newContentStates = new Syncroton_Model_Content( + + $newContentStates = new Syncroton_Model_Content(array( 'device_id' => $this->_device, 'folder_id' => $collectionData->folder, 'contentid' => $serverId, 'creation_time' => $this->_syncTimeStamp, - 'creation_synckey' => $collectionData->syncState->counter + 1, - ); + 'creation_synckey' => $collectionData->syncState->counter + 1 + )); $collectionChanges++; } catch (Syncroton_Exception_MemoryExhausted $seme) { // continue to next entry, as there is not enough memory left for the current entry // this will lead to MoreAvailable at the end and the entry will be synced during the next Sync command - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " memory exhausted for entry: " . $serverId); - } - + if ($this->_logger instanceof Zend_Log) + $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " memory exhausted for entry: " . $serverId); + break; - + } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage()); - } - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getTraceAsString()); - } // We bump collectionChanges anyways to make sure the windowSize still applies. $collectionChanges++; } - - // mark as sent to the client, even the conversion to xml might have failed + + // mark as sent to the client, even the conversion to xml might have failed unset($serverModifications'added'$id); } @@ -930,239 +867,174 @@ if($collectionChanges == $collectionData->windowSize || $totalChanges + $collectionChanges >= $this->_globalWindowSize) { break; } - + try { $change = $this->_outputDom->createElementNS('uri:AirSync', 'Change'); $change->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $serverId)); - + $applicationData = $change->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ApplicationData')); - - $collectionData->options'_changesOnly' = true; - - $dataController - ->getEntry($collectionData, $serverId) - ->appendXML($applicationData, $this->_device); - + + $dataController + ->getEntry($collectionData, $serverId) + ->appendXML($applicationData, $this->_device); + $commands->appendChild($change); - + $collectionChanges++; } catch (Syncroton_Exception_MemoryExhausted $seme) { // continue to next entry, as there is not enough memory left for the current entry // this will lead to MoreAvailable at the end and the entry will be synced during the next Sync command - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " memory exhausted for entry: " . $serverId); - } - + if ($this->_logger instanceof Zend_Log) + $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " memory exhausted for entry: " . $serverId); + break; - + } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage()); - } // We bump collectionChanges anyways to make sure the windowSize still applies. $collectionChanges++; } - unset($serverModifications'changed'$id); + unset($serverModifications'changed'$id); } foreach($serverModifications'deleted' as $id => $serverId) { if($collectionChanges == $collectionData->windowSize || $totalChanges + $collectionChanges >= $this->_globalWindowSize) { break; } - + try { // check if we have sent this entry to the phone $state = $this->_contentStateBackend->getContentState($this->_device, $collectionData->folder, $serverId); - + $delete = $this->_outputDom->createElementNS('uri:AirSync', 'Delete'); $delete->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $serverId)); - + $deletedContentStates = $state; - + $commands->appendChild($delete); - + $collectionChanges++; } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unable to convert entry to xml: " . $e->getMessage()); - } // We bump collectionChanges anyways to make sure the windowSize still applies. $collectionChanges++; } - + unset($serverModifications'deleted'$id); } - - $countOfPendingChanges = (count($serverModifications'added') + count($serverModifications'changed') + count($serverModifications'deleted')); + + $countOfPendingChanges = (count($serverModifications'added') + count($serverModifications'changed') + count($serverModifications'deleted')); if ($countOfPendingChanges > 0) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " there are " . $countOfPendingChanges . " more items available"); - } $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'MoreAvailable')); } else { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " there are no more items available"); - } $serverModifications = null; } - + if ($commands->hasChildNodes() === true) { $collection->appendChild($commands); } - + $totalChanges += $collectionChanges; - - // If the client resent an old sync-key, we should still respond with the latest sync key - if (isset($collectionData->syncState->counterNext)) { - //TODO we're not resending the changes in between, but I'm not sure we have to. - $collectionData->syncState->counter = $collectionData->syncState->counterNext; - } - + // increase SyncKey if needed if (( - // sent the clients updates... ? - !empty($clientModifications'added') || - !empty($clientModifications'changed') || - !empty($clientModifications'deleted') - ) || ( - // is the server sending updates to the client... ? - $commands->hasChildNodes() === true - ) || ( - // changed the pending data... ? - $collectionData->syncState->pendingdata != $serverModifications - ) + // sent the clients updates... ? + !empty($clientModifications'added') || + !empty($clientModifications'changed') || + !empty($clientModifications'deleted') + ) || ( + // is the server sending updates to the client... ? + $commands->hasChildNodes() === true + ) || ( + // changed the pending data... ? + $collectionData->syncState->pendingdata != $serverModifications + ) ) { - // ...then increase SyncKey - $collectionData->syncState->counter++; - } + // ...then increase SyncKey + $collectionData->syncState->counter++; + } $syncKeyElement->appendChild($this->_outputDom->createTextNode($collectionData->syncState->counter)); - - if ($this->_logger instanceof Zend_Log) { - $this->_logger->info(__METHOD__ . '::' . __LINE__ . " current synckey is " . $collectionData->syncState->counter); - } - + + if ($this->_logger instanceof Zend_Log) + $this->_logger->info(__METHOD__ . '::' . __LINE__ . " current synckey is ". $collectionData->syncState->counter); + if (!$emptySyncSupported || $collection->childNodes->length > 4 || $collectionData->syncState->counter != $collectionData->syncKey) { - $collections->appendChild($collection); + $collections->appendChild($collection); } - - //Store next - $collectionData->syncState->extraData = $dataController->getExtraData($collectionData->folder); } - - if (isset($collectionData->syncState) && + + if (isset($collectionData->syncState) && $collectionData->syncState instanceof Syncroton_Model_ISyncState && - $collectionData->syncState->counter != $collectionData->syncKey + $collectionData->syncState->counter != $collectionData->syncKey ) { - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " update syncState for collection: " . $collectionData->collectionId); - } - + // store pending data in sync state when needed - if (isset($countOfPendingChanges) && $countOfPendingChanges > 0) { - $collectionData->syncState->pendingdata = - 'added' => $serverModifications'added' ?? , - 'changed' => $serverModifications'changed' ?? , - 'deleted' => $serverModifications'deleted' ?? , - ; + if(isset($countOfPendingChanges) && $countOfPendingChanges > 0) { + $collectionData->syncState->pendingdata = array( + 'added' => (array)$serverModifications'added', + 'changed' => (array)$serverModifications'changed', + 'deleted' => (array)$serverModifications'deleted' + ); } else { $collectionData->syncState->pendingdata = null; } - + + + if (!empty($clientModifications'added')) { + if ($this->_logger instanceof Zend_Log) + $this->_logger->info(__METHOD__ . '::' . __LINE__ . " remove previous synckey as client added new entries"); + $keepPreviousSyncKey = false; + } else { + $keepPreviousSyncKey = true; + } + $collectionData->syncState->lastsync = clone $this->_syncTimeStamp; // increment sync timestamp by 1 second $collectionData->syncState->lastsync->modify('+1 sec'); - if (!empty($clientModifications'added')) { - // Store a client id mapping in case we encounter a reused sync_key in a future request. - $newClientIdMap = ; - foreach($clientModifications'added' as $entryData) { - // No serverId if we failed to add - if ($entryData'status' == self::STATUS_SUCCESS) { - $newClientIdMap$entryData'clientId' = $entryData'serverId'; - } + + try { + $transactionId = Syncroton_Registry::getTransactionManager()->startTransaction(Syncroton_Registry::getDatabase()); + + // store new synckey + $this->_syncStateBackend->create($collectionData->syncState, $keepPreviousSyncKey); + + // store contentstates for new entries added to client + foreach($newContentStates as $state) { + $this->_contentStateBackend->create($state); } - $collectionData->syncState->clientIdMap = Zend_Json::encode($newClientIdMap); - } - - //Retry in case of deadlock - $retryCounter = 0; - while (true) { - try { - $transactionId = Syncroton_Registry::getTransactionManager()->startTransaction(Syncroton_Registry::getDatabase()); - // store new synckey - $this->_syncStateBackend->create($collectionData->syncState, true); // @phpstan-ignore-line - - // store contentstates for new entries added to client - foreach($newContentStates as $state) { - try { - //This can happen if we rerun a previous sync-key - $state = $this->_contentStateBackend->getContentState($state->device_id, $state->folder_id, $state->contentid); - $this->_contentStateBackend->update($state); - } catch(Exception $zdse) { - $this->_contentStateBackend->create($state); - } - } - - // remove contentstates for entries to be deleted on client - foreach($deletedContentStates as $state) { - $this->_contentStateBackend->delete($state); - } - - Syncroton_Registry::getTransactionManager()->commitTransaction($transactionId); - break; - } catch (Syncroton_Exception_DeadlockDetected $zdse) { - $retryCounter++; - if ($retryCounter > 60) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . ' exception while storing new synckey. Aborting after 5 retries.'); - } - - // something went wrong - // maybe another parallel request added a new synckey - // we must remove data added from client - if (!empty($clientModifications'added') && isset($dataController)) { - foreach ($clientModifications'added' as $added) { - $this->_contentStateBackend->delete($added'contentState'); - $dataController->deleteEntry($collectionData->collectionId, $added'serverId'); - } - } - - Syncroton_Registry::getTransactionManager()->rollBack(); - - throw $zdse; - } - - Syncroton_Registry::getTransactionManager()->rollBack(); - // Give the other transactions some time before we try again - sleep(1); - if ($this->_logger instanceof Zend_Log) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . ' error during transaction, trying again.'); - } - } catch (Exception $zdse) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . ' exception while storing new synckey.'); - } - // something went wrong - // maybe another parallel request added a new synckey - // we must remove data added from client - if (!empty($clientModifications'added') && isset($dataController)) { - foreach ($clientModifications'added' as $added) { - $this->_contentStateBackend->delete($added'contentState'); - $dataController->deleteEntry($collectionData->collectionId, $added'serverId'); - } + + // remove contentstates for entries to be deleted on client + foreach($deletedContentStates as $state) { + $this->_contentStateBackend->delete($state); + } + + Syncroton_Registry::getTransactionManager()->commitTransaction($transactionId); + } catch (Zend_Db_Statement_Exception $zdse) { + // something went wrong + // maybe another parallel request added a new synckey + // we must remove data added from client + if (!empty($clientModifications'added')) { + foreach ($clientModifications'added' as $added) { + $this->_contentStateBackend->delete($added'contentState'); + $dataController->deleteEntry($collectionData->collectionId, $added'serverId', array()); } - - Syncroton_Registry::getTransactionManager()->rollBack(); - - throw $zdse; } + + Syncroton_Registry::getTransactionManager()->rollBack(); + + throw $zdse; } } - + // store current filter type try { - /** @var Syncroton_Model_Folder $folderState */ $folderState = $this->_folderBackend->get($collectionData->folder); $folderState->lastfiltertype = $collectionData->options'filterType'; if ($folderState->isDirty()) { @@ -1170,63 +1042,61 @@ } } catch (Syncroton_Exception_NotFound $senf) { // failed to get folderstate => should not happen but is also no problem in this state - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->warn(__METHOD__ . '::' . __LINE__ . ' failed to get folder state for: ' . $collectionData->collectionId); - } } } - + if ($collections->hasChildNodes() === true) { $sync->appendChild($collections); } - + if ($sync->hasChildNodes()) { return $this->_outputDom; } - + return null; } - + /** * remove Commands and Supported from collections XML tree - * + * * @param DOMDocument $document * @return DOMDocument */ protected function _cleanUpXML(DOMDocument $document) { $cleanedDocument = clone $document; - + $xpath = new DomXPath($cleanedDocument); $xpath->registerNamespace('AirSync', 'uri:AirSync'); - + $collections = $xpath->query("//AirSync:Sync/AirSync:Collections/AirSync:Collection"); - + // remove Commands and Supported elements foreach ($collections as $collection) { - foreach ('Commands', 'Supported' as $element) { - /** @var DOMElement $collection */ + foreach (array('Commands', 'Supported') as $element) { $childrenToRemove = $collection->getElementsByTagName($element); - + foreach ($childrenToRemove as $childToRemove) { $collection->removeChild($childToRemove); } } } - + return $cleanedDocument; } - + /** * merge a partial XML document with the XML document from the previous request - * + * * @param DOMDocument|null $requestBody - * @return DOMDocument + * @return SimpleXMLElement */ protected function _mergeSyncRequest($requestBody, Syncroton_Model_Device $device) { - $lastSyncCollection = ; - + $lastSyncCollection = array(); + if (!empty($device->lastsynccollection)) { $lastSyncCollection = Zend_Json::decode($device->lastsynccollection); if (!empty($lastSyncCollection'lastXML')) { @@ -1234,75 +1104,71 @@ $lastXML->loadXML($lastSyncCollection'lastXML'); } } - - if (! $requestBody instanceof DOMDocument) { - if (!empty($lastXML)) { - $requestBody = $lastXML; - } else { - throw new Syncroton_Exception_UnexpectedValue('no xml body found'); - } + + if (! $requestBody instanceof DOMDocument && isset($lastXML) && $lastXML instanceof DOMDocument) { + $requestBody = $lastXML; + } elseif (! $requestBody instanceof DOMDocument) { + throw new Syncroton_Exception_UnexpectedValue('no xml body found'); } - + if ($requestBody->getElementsByTagName('Partial')->length > 0) { $partialBody = clone $requestBody; - $requestBody = $lastXML ?? (new DOMDocument()); - + $requestBody = $lastXML; + $xpath = new DomXPath($requestBody); $xpath->registerNamespace('AirSync', 'uri:AirSync'); - + foreach ($partialBody->documentElement->childNodes as $child) { if (! $child instanceof DOMElement) { continue; } - - /** @var DOMElement $child */ + if ($child->tagName == 'Partial') { continue; } - + if ($child->tagName == 'Collections') { foreach ($child->getElementsByTagName('Collection') as $updatedCollection) { $collectionId = $updatedCollection->getElementsByTagName('CollectionId')->item(0)->nodeValue; - + $existingCollections = $xpath->query("//AirSync:Sync/AirSync:Collections/AirSync:CollectionAirSync:CollectionId='$collectionId'"); - + if ($existingCollections->length > 0) { - /** @var DOMElement $existingCollection */ $existingCollection = $existingCollections->item(0); foreach ($updatedCollection->childNodes as $updatedCollectionChild) { if (! $updatedCollectionChild instanceof DOMElement) { continue; } - + $duplicateChild = $existingCollection->getElementsByTagName($updatedCollectionChild->tagName); - + if ($duplicateChild->length > 0) { - $existingCollection->replaceChild($requestBody->importNode($updatedCollectionChild, true), $duplicateChild->item(0)); + $existingCollection->replaceChild($requestBody->importNode($updatedCollectionChild, TRUE), $duplicateChild->item(0)); } else { - $existingCollection->appendChild($requestBody->importNode($updatedCollectionChild, true)); + $existingCollection->appendChild($requestBody->importNode($updatedCollectionChild, TRUE)); } } } else { - $importedCollection = $requestBody->importNode($updatedCollection, true); + $importedCollection = $requestBody->importNode($updatedCollection, TRUE); } } - + } else { $duplicateChild = $xpath->query("//AirSync:Sync/AirSync:{$child->tagName}"); - + if ($duplicateChild->length > 0) { - $requestBody->documentElement->replaceChild($requestBody->importNode($child, true), $duplicateChild->item(0)); + $requestBody->documentElement->replaceChild($requestBody->importNode($child, TRUE), $duplicateChild->item(0)); } else { - $requestBody->documentElement->appendChild($requestBody->importNode($child, true)); + $requestBody->documentElement->appendChild($requestBody->importNode($child, TRUE)); } } } } - + $lastSyncCollection'lastXML' = $this->_cleanUpXML($requestBody)->saveXML(); - + $device->lastsynccollection = Zend_Json::encode($lastSyncCollection); - + return $requestBody; } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Command/Wbxml.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Command/Wbxml.php
Changed
@@ -15,121 +15,122 @@ * @package Syncroton * @subpackage Command */ - + abstract class Syncroton_Command_Wbxml implements Syncroton_Command_ICommand { /** * informations about the currently device * - * @var Syncroton_Model_IDevice + * @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_Policy + * + * @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 + * @var string */ protected $_defaultNameSpace; - + /** * the main xml tag * - * @var ?string + * @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 = ; - + protected $_parts = array(); + /** * list of headers - * + * * @var array */ - protected $_headers = ; - + protected $_headers = array(); + /** * the constructor * @@ -137,12 +138,12 @@ * @param Syncroton_Model_Device $device * @param array $requestParameters */ - public function __construct($requestBody, Syncroton_Model_IDevice $device, $requestParameters = ) + public function __construct($requestBody, Syncroton_Model_IDevice $device, $requestParameters) { $this->_requestBody = $requestBody; $this->_device = $device; $this->_requestParameters = $requestParameters; - $this->_policyKey = $requestParameters'policyKey' ?? null; + $this->_policyKey = isset($requestParameters'policyKey') ? $requestParameters'policyKey' : null; $this->_deviceBackend = Syncroton_Registry::getDeviceBackend(); $this->_folderBackend = Syncroton_Registry::getFolderBackend(); @@ -152,57 +153,55 @@ if (Syncroton_Registry::isRegistered('loggerBackend')) { $this->_logger = Syncroton_Registry::get('loggerBackend'); } - - $this->_syncTimeStamp = new DateTime('now', new DateTimeZone('UTC')); - + + $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) { + + 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)) { - /** @var Syncroton_Model_Policy $policy */ $policy = $this->_policyBackend->get($this->_device->policyId); - - if ((int) $policy->policyKey != (int) $this->_policyKey) { + + 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; } - + // 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() @@ -213,7 +212,7 @@ } /** * return array of part streams - * + * * @return array */ public function getParts()
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Data/AData.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Data/AData.php
Changed
@@ -17,30 +17,16 @@ */ abstract class Syncroton_Data_AData implements Syncroton_Data_IData { - public const LONGID_DELIMITER = "\xe2\x87\x94"; // UTF-8 character ⇔ - - /** @var DateTime */ + const LONGID_DELIMITER = "\xe2\x87\x94"; # UTF-8 character ⇔ + + /** + * @var DateTime + */ protected $_timeStamp; - - /** @var Syncroton_Model_IDevice */ - protected $_device; - - /** @var Zend_Db_Adapter_Abstract */ - protected $_db; - - /** @var string */ - protected $_tablePrefix; - - /** @var string */ - protected $_ownerId; - - /** @var array */ - protected $_supportedFolderTypes = ; - - + /** * the constructor - * + * * @param Syncroton_Model_IDevice $_device * @param DateTime $_timeStamp */ @@ -52,10 +38,10 @@ $this->_tablePrefix = 'Syncroton_'; $this->_ownerId = '1234'; } - + /** * return one folder identified by id - * + * * @param string $id * @throws Syncroton_Exception_NotFound * @return Syncroton_Model_Folder @@ -66,23 +52,23 @@ ->from($this->_tablePrefix . 'data_folder') ->where('owner_id = ?', $this->_ownerId) ->where('id = ?', $id); - + $stmt = $this->_db->query($select); $folder = $stmt->fetch(); $stmt = null; # see https://bugs.php.net/bug.php?id=44081 - + if ($folder === false) { throw new Syncroton_Exception_NotFound("folder $id not found"); } - - return new Syncroton_Model_Folder( + + return new Syncroton_Model_Folder(array( 'serverId' => $folder'id', 'displayName' => $folder'name', 'type' => $folder'type', - 'parentId' => !empty($folder'parent_id') ? $folder'parent_id' : null, - ); + 'parentId' => !empty($folder'parent_id') ? $folder'parent_id' : null + )); } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::createFolder() @@ -92,53 +78,53 @@ if (!in_array($folder->type, $this->_supportedFolderTypes)) { throw new Syncroton_Exception_UnexpectedValue(); } - - $id = !empty($folder->serverId) ? $folder->serverId : sha1(mt_rand() . microtime()); - - $this->_db->insert($this->_tablePrefix . 'data_folder', + + $id = !empty($folder->serverId) ? $folder->serverId : sha1(mt_rand(). microtime()); + + $this->_db->insert($this->_tablePrefix . 'data_folder', array( 'id' => $id, 'type' => $folder->type, 'name' => $folder->displayName, 'owner_id' => $this->_ownerId, 'parent_id' => $folder->parentId, - 'creation_time' => $this->_timeStamp->format("Y-m-d H:i:s"), - ); - + 'creation_time' => $this->_timeStamp->format("Y-m-d H:i:s") + )); + return $this->getFolder($id); } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::createEntry() */ - public function createEntry($_folderId, Syncroton_Model_IEntry $_entry) - { - $id = sha1(mt_rand() . microtime()); - - $this->_db->insert($this->_tablePrefix . 'data', - 'id' => $id, + public function createEntry($_folderId, Syncroton_Model_IEntry $_entry) + { + $id = sha1(mt_rand(). microtime()); + + $this->_db->insert($this->_tablePrefix . 'data', array( + 'id' => $id, 'class' => get_class($_entry), 'folder_id' => $_folderId, 'creation_time' => $this->_timeStamp->format("Y-m-d H:i:s"), - 'data' => serialize($_entry), - ); - - return $id; - } - + 'data' => serialize($_entry) + )); + + return $id; + } + /** * (non-PHPdoc) * @see Syncroton_Data_IData::deleteEntry() */ - public function deleteEntry($_folderId, $_serverId, $_collectionData = null) + public function deleteEntry($_folderId, $_serverId, $_collectionData) { $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->serverId : $_folderId; - - $result = $this->_db->delete($this->_tablePrefix . 'data', 'id = ?' => $_serverId); - + + $result = $this->_db->delete($this->_tablePrefix . 'data', array('id = ?' => $_serverId)); + return (bool) $result; } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::deleteFolder() @@ -146,13 +132,13 @@ public function deleteFolder($_folderId) { $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->serverId : $_folderId; - - $result = $this->_db->delete($this->_tablePrefix . 'data', 'folder_id = ?' => $folderId); - $result = $this->_db->delete($this->_tablePrefix . 'data_folder', 'id = ?' => $folderId); - + + $result = $this->_db->delete($this->_tablePrefix . 'data', array('folder_id = ?' => $folderId)); + $result = $this->_db->delete($this->_tablePrefix . 'data_folder', array('id = ?' => $folderId)); + return (bool) $result; } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::emptyFolderContents() @@ -161,7 +147,7 @@ { return true; } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::getAllFolders() @@ -172,52 +158,55 @@ ->from($this->_tablePrefix . 'data_folder') ->where('type IN (?)', $this->_supportedFolderTypes) ->where('owner_id = ?', $this->_ownerId); - + $stmt = $this->_db->query($select); $folders = $stmt->fetchAll(); $stmt = null; # see https://bugs.php.net/bug.php?id=44081 - - $result = ; - + + $result = array(); + foreach ((array) $folders as $folder) { - $result$folder'id' = new Syncroton_Model_Folder( + $result$folder'id' = new Syncroton_Model_Folder(array( 'serverId' => $folder'id', 'displayName' => $folder'name', 'type' => $folder'type', - 'parentId' => $folder'parent_id', - ); + 'parentId' => $folder'parent_id' + )); } - + return $result; } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::getChangedEntries() */ - public function getChangedEntries($_folderId, Syncroton_Model_ISyncState $syncState, $filterType = null) + public function getChangedEntries($_folderId, DateTime $_startTimeStamp, DateTime $_endTimeStamp = NULL, $filterType = NULL) { - $_startTimeStamp = $syncState->lastsync; $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId; - + $select = $this->_db->select() - ->from($this->_tablePrefix . 'data', 'id') + ->from($this->_tablePrefix . 'data', array('id')) ->where('folder_id = ?', $_folderId) ->where('last_modified_time > ?', $_startTimeStamp->format("Y-m-d H:i:s")); - - $ids = ; - + + if ($_endTimeStamp instanceof DateTime) { + $select->where('last_modified_time < ?', $_endTimeStamp->format("Y-m-d H:i:s")); + } + + $ids = array(); + $stmt = $this->_db->query($select); while ($id = $stmt->fetchColumn()) { $ids = $id; } - + return $ids; } - + /** * retrieve folders which were modified since last sync - * + * * @param DateTime $startTimeStamp * @param DateTime $endTimeStamp * @return array list of Syncroton_Model_Folder @@ -230,25 +219,25 @@ ->where('owner_id = ?', $this->_ownerId) ->where('last_modified_time > ?', $startTimeStamp->format('Y-m-d H:i:s')) ->where('last_modified_time <= ?', $endTimeStamp->format('Y-m-d H:i:s')); - + $stmt = $this->_db->query($select); $folders = $stmt->fetchAll(); $stmt = null; # see https://bugs.php.net/bug.php?id=44081 - - $result = ; - + + $result = array(); + foreach ((array) $folders as $folder) { - $result$folder'id' = new Syncroton_Model_Folder( + $result$folder'id' = new Syncroton_Model_Folder(array( 'serverId' => $folder'id', 'displayName' => $folder'name', 'type' => $folder'type', - 'parentId' => $folder'parent_id', - ); + 'parentId' => $folder'parent_id' + )); } - + return $result; } - + /** * @param Syncroton_Model_IFolder|string $_folderId * @param string $_filter @@ -257,21 +246,21 @@ public function getServerEntries($_folderId, $_filter) { $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId; - - $select = $this->_db->select() - ->from($this->_tablePrefix . 'data', 'id') - ->where('folder_id = ?', $_folderId); - - $ids = ; - - $stmt = $this->_db->query($select); + + $select = $this->_db->select() + ->from($this->_tablePrefix . 'data', array('id')) + ->where('folder_id = ?', $_folderId); + + $ids = array(); + + $stmt = $this->_db->query($select); while ($id = $stmt->fetchColumn()) { $ids = $id; - } - - return $ids; + } + + return $ids; } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::getCountOfChanges() @@ -280,42 +269,42 @@ { $allClientEntries = $contentBackend->getFolderState($this->_device, $folder); $allServerEntries = $this->getServerEntries($folder->serverId, $folder->lastfiltertype); - + $addedEntries = array_diff($allServerEntries, $allClientEntries); $deletedEntries = array_diff($allClientEntries, $allServerEntries); - $changedEntries = $this->getChangedEntries($folder->serverId, $syncState, $folder->lastfiltertype); - + $changedEntries = $this->getChangedEntries($folder->serverId, $syncState->lastsync, null, $folder->lastfiltertype); + return count($addedEntries) + count($deletedEntries) + count($changedEntries); } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::getFileReference() */ - public function getFileReference($fileReference) - { - throw new Syncroton_Exception_NotFound('filereference not found'); - } - + public function getFileReference($fileReference) + { + throw new Syncroton_Exception_NotFound('filereference not found'); + } + /** * (non-PHPdoc) * @see Syncroton_Data_IData::getEntry() */ - public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId) - { + public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId) + { $select = $this->_db->select() - ->from($this->_tablePrefix . 'data', 'data') + ->from($this->_tablePrefix . 'data', array('data')) ->where('id = ?', $serverId); - + $stmt = $this->_db->query($select); $entry = $stmt->fetchColumn(); if ($entry === false) { throw new Syncroton_Exception_NotFound("entry $serverId not found in folder {$collection->collectionId}"); } - + return unserialize($entry); - } + } /** * (non-PHPdoc) @@ -325,59 +314,53 @@ { return !!$this->getCountOfChanges($contentBackend, $folder, $syncState); } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::moveItem() */ public function moveItem($_srcFolderId, $_serverId, $_dstFolderId) { - $this->_db->update($this->_tablePrefix . 'data', - 'folder_id' => $_dstFolderId, - , - 'id = ?' => $_serverId, - ); - + $this->_db->update($this->_tablePrefix . 'data', array( + 'folder_id' => $_dstFolderId, + ), array( + 'id = ?' => $_serverId + )); + return $_serverId; } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::updateEntry() */ - public function updateEntry($_folderId, $_serverId, Syncroton_Model_IEntry $_entry) + public function updateEntry($_folderId, $_serverId, Syncroton_Model_IEntry $_entry) { - $this->_db->update($this->_tablePrefix . 'data', + $this->_db->update($this->_tablePrefix . 'data', array( 'folder_id' => $_folderId, 'last_modified_time' => $this->_timeStamp->format("Y-m-d H:i:s"), - 'data' => serialize($_entry), - , - 'id = ?' => $_serverId, - ); - - return $_serverId; + 'data' => serialize($_entry) + ), array( + 'id = ?' => $_serverId + )); } - + /** * (non-PHPdoc) * @see Syncroton_Data_IData::updateFolder() - */ - public function updateFolder(Syncroton_Model_IFolder $folder) - { - $this->_db->update($this->_tablePrefix . 'data_folder', + */ + public function updateFolder(Syncroton_Model_IFolder $folder) + { + $this->_db->update($this->_tablePrefix . 'data_folder', array( 'name' => $folder->displayName, 'parent_id' => $folder->parentId, 'last_modified_time' => $this->_timeStamp->format("Y-m-d H:i:s"), - , + ), array( 'id = ?' => $folder->serverId, - 'owner_id = ?' => $this->_ownerId, - ); - + 'owner_id = ?' => $this->_ownerId + )); + return $this->getFolder($folder->serverId); - } - - public function getExtraData(Syncroton_Model_IFolder $folder) - { - return null; - } + } } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Data/Calendar.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Data/Calendar.php
Changed
@@ -17,20 +17,20 @@ */ class Syncroton_Data_Calendar extends Syncroton_Data_AData implements Syncroton_Data_IDataCalendar { - protected $_supportedFolderTypes = + protected $_supportedFolderTypes = array( Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR, - Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR_USER_CREATED, - ; - + Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR_USER_CREATED + ); + /** * set attendee status for meeting - * - * @param Syncroton_Model_MeetingResponse $response The meeting response - * - * @return string ID of new calendar entry + * + * @param Syncroton_Model_MeetingResponse $request the meeting response + * @return string id of new calendar entry */ - public function setAttendeeStatus(Syncroton_Model_MeetingResponse $response) + public function setAttendeeStatus(Syncroton_Model_MeetingResponse $reponse) { - return $response->requestId; + return $reponse->requestId; } } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Data/Contacts.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Data/Contacts.php
Changed
@@ -15,31 +15,31 @@ * @package Syncroton * @subpackage Data */ + class Syncroton_Data_Contacts extends Syncroton_Data_AData implements Syncroton_Data_IDataSearch { - protected $_supportedFolderTypes = + protected $_supportedFolderTypes = array( Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT, - Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED, - ; - + Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED + ); + /** * (non-PHPdoc) * @see Syncroton_Data_IDataSearch::getSearchEntry() */ public function getSearchEntry($longId, $options) { - $collectionId, $serverId = explode(Syncroton_Data_AData::LONGID_DELIMITER, $longId, 2); - - /** @var Syncroton_Model_Contact $contact */ - $contact = $this->getEntry(new Syncroton_Model_SyncCollection('collectionId' => $collectionId), $serverId); - - return new Syncroton_Model_GAL( + list($collectionId, $serverId) = explode(Syncroton_Data_AData::LONGID_DELIMITER, $longId, 2); + + $contact = $this->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $collectionId)), $serverId); + + return new Syncroton_Model_GAL(array( 'firstName' => $contact->firstName, 'lastName' => $contact->lastName, - 'picture' => new Syncroton_Model_GALPicture('status' => 1, 'data' => 'abc'), - ); + 'picture' => new Syncroton_Model_GALPicture(array('status' => 1, 'data' => 'abc')) + )); } - + /** * (non-PHPdoc) * @see Syncroton_Data_IDataSearch::search() @@ -47,37 +47,37 @@ public function search(Syncroton_Model_StoreRequest $store) { $storeResponse = new Syncroton_Model_StoreResponse(); - + $serverIds = $this->getServerEntries('addressbookFolderId', Syncroton_Command_Sync::FILTER_NOTHING); - + $total = 0; - $found = ; - + $found = array(); + foreach ($serverIds as $serverId) { - /** @var Syncroton_Model_Contact $contact */ - $contact = $this->getEntry(new Syncroton_Model_SyncCollection('collectionId' => 'addressbookFolderId'), $serverId); - + $contact = $this->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => 'addressbookFolderId')), $serverId); + if ($contact->firstName == $store->query) { $total++; - - if (count($found) == $store->options'range'1 + 1) { + + if (count($found) == $store->options'range'1+1) { continue; } - $found = new Syncroton_Model_StoreResponseResult( - 'longId' => 'addressbookFolderId' . Syncroton_Data_AData::LONGID_DELIMITER . $serverId, - 'properties' => $this->getSearchEntry('addressbookFolderId' . Syncroton_Data_AData::LONGID_DELIMITER . $serverId, $store->options), - ); + $found = new Syncroton_Model_StoreResponseResult(array( + 'longId' => 'addressbookFolderId' . Syncroton_Data_AData::LONGID_DELIMITER . $serverId, + 'properties' => $this->getSearchEntry('addressbookFolderId' . Syncroton_Data_AData::LONGID_DELIMITER . $serverId, $store->options) + )); } } - + if (count($found) > 0) { $storeResponse->result = $found; - $storeResponse->range = 0, count($found) - 1; + $storeResponse->range = array(0, count($found) - 1); $storeResponse->total = $total; } else { - $storeResponse->total = $total; + $storeResponse->total = $total; } - + return $storeResponse; } } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Data/Email.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Data/Email.php
Changed
@@ -17,52 +17,52 @@ */ class Syncroton_Data_Email extends Syncroton_Data_AData implements Syncroton_Data_IDataEmail { - protected $_supportedFolderTypes = + protected $_supportedFolderTypes = array( Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS, Syncroton_Command_FolderSync::FOLDERTYPE_DRAFTS, Syncroton_Command_FolderSync::FOLDERTYPE_INBOX, Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED, Syncroton_Command_FolderSync::FOLDERTYPE_OUTBOX, - Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL, - ; - + Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL + ); + /** * (non-PHPdoc) * @see Syncroton_Data_IDataEmail::forwardEmail() */ public function forwardEmail($source, $inputStream, $saveInSent, $replaceMime) { - if ($inputStream == 'triggerException') { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::MAILBOX_SERVER_OFFLINE); - } - + if ($inputStream == 'triggerException') { + throw new Syncroton_Exception_Status(Syncroton_Exception_Status::MAILBOX_SERVER_OFFLINE); + } + // forward email } - + /** * (non-PHPdoc) * @see Syncroton_Data_AData::getFileReference() */ - public function getFileReference($fileReference) - { - $messageId, $partId = explode(Syncroton_Data_AData::LONGID_DELIMITER, $fileReference, 2); - - // example code - return new Syncroton_Model_FileReference( - 'contentType' => 'text/plain', - 'data' => 'Lars', - ); + public function getFileReference($fileReference) + { + list($messageId, $partId) = explode(Syncroton_Data_AData::LONGID_DELIMITER, $fileReference, 2); + + // example code + return new Syncroton_Model_FileReference(array( + 'contentType' => 'text/plain', + 'data' => 'Lars' + )); } - + /** * (non-PHPdoc) * @see Syncroton_Data_IDataEmail::replyEmail() - */ - public function replyEmail($source, $inputStream, $saveInSent, $replaceMime) - { - // forward email - } - + */ + public function replyEmail($source, $inputStream, $saveInSent, $replaceMime) + { + // forward email + } + /** * (non-PHPdoc) * @see Syncroton_Data_AData::updateEntry() @@ -70,9 +70,8 @@ public function updateEntry($_folderId, $_serverId, Syncroton_Model_IEntry $_entry) { // not used by email - return ''; } - + /** * (non-PHPdoc) * @see Syncroton_Data_IDataEmail::sendEmail() @@ -85,3 +84,4 @@ // send email } } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Data/Factory.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Data/Factory.php
Changed
@@ -18,40 +18,39 @@ class Syncroton_Data_Factory { - public const CLASS_CALENDAR = 'Calendar'; - public const CLASS_CONTACTS = 'Contacts'; - public const CLASS_EMAIL = 'Email'; - public const CLASS_NOTES = 'Notes'; - public const CLASS_TASKS = 'Tasks'; - public const STORE_EMAIL = 'Mailbox'; - public const STORE_GAL = 'GAL'; - - protected static $_classMap = ; - + const CLASS_CALENDAR = 'Calendar'; + const CLASS_CONTACTS = 'Contacts'; + const CLASS_EMAIL = 'Email'; + const CLASS_NOTES = 'Notes'; + const CLASS_TASKS = 'Tasks'; + const STORE_EMAIL = 'Mailbox'; + const STORE_GAL = 'GAL'; + + protected static $_classMap = array(); + /** - * @param string $_classFactory + * @param unknown_type $_class * @param Syncroton_Model_IDevice $_device - * @param DateTime $_timeStamp - * + * @param DateTime $_timeStamp * @throws InvalidArgumentException * @return Syncroton_Data_IData */ public static function factory($_classFactory, Syncroton_Model_IDevice $_device, DateTime $_timeStamp) { - switch ($_classFactory) { + switch($_classFactory) { case self::CLASS_CALENDAR: $className = Syncroton_Registry::get(Syncroton_Registry::CALENDAR_DATA_CLASS); break; - + case self::CLASS_CONTACTS: $className = Syncroton_Registry::get(Syncroton_Registry::CONTACTS_DATA_CLASS); break; - + case self::STORE_EMAIL: case self::CLASS_EMAIL: $className = Syncroton_Registry::get(Syncroton_Registry::EMAIL_DATA_CLASS); break; - + case self::CLASS_NOTES: $className = Syncroton_Registry::get(Syncroton_Registry::NOTES_DATA_CLASS); break; @@ -66,14 +65,16 @@ default: throw new Syncroton_Exception_UnexpectedValue('invalid class type provided'); + breeak; } - + $class = new $className($_device, $_timeStamp); - + if (! $class instanceof Syncroton_Data_IData) { throw new RuntimeException('class must be instanceof Syncroton_Data_IData'); } - + return $class; } } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Data/IData.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Data/IData.php
Changed
@@ -19,37 +19,37 @@ { /** * create new entry - * + * * @param string $folderId * @param Syncroton_Model_IEntry $entry * @return string id of created entry */ public function createEntry($folderId, Syncroton_Model_IEntry $entry); - + /** * create a new folder in backend - * + * * @param Syncroton_Model_IFolder $folder * @return Syncroton_Model_IFolder */ public function createFolder(Syncroton_Model_IFolder $folder); - + /** * delete entry in backend - * - * @param string $_folderId - * @param string $_serverId - * @param ?Syncroton_Model_SyncCollection $_collectionData + * + * @param string $_folderId + * @param string $_serverId + * @param unknown_type $_collectionData */ - public function deleteEntry($_folderId, $_serverId, $_collectionData = null); - + public function deleteEntry($_folderId, $_serverId, $_collectionData); + /** * delete folder - * + * * @param string $folderId */ public function deleteFolder($folderId); - + /** * empty folder * @@ -57,77 +57,71 @@ * @param array $options */ public function emptyFolderContents($folderId, $options); - + /** * return list off all folders * @return array of Syncroton_Model_IFolder */ public function getAllFolders(); - - public function getChangedEntries($folderId, Syncroton_Model_ISyncState $syncState, $filterType = null); - - /** - * Retrieve extra data that is stored with the sync key - * @return string|null - **/ - public function getExtraData(Syncroton_Model_IFolder $folder); - - + + public function getChangedEntries($folderId, DateTime $startTimeStamp, DateTime $endTimeStamp = NULL, $filterType = NULL); + /** * retrieve folders which were modified since last sync - * + * * @param DateTime $startTimeStamp * @param DateTime $endTimeStamp */ public function getChangedFolders(DateTime $startTimeStamp, DateTime $endTimeStamp); - + public function getCountOfChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState); - + /** - * + * * @param Syncroton_Model_SyncCollection $collection * @param string $serverId - * @return Syncroton_Model_IXMLEntry + * @return Syncroton_Model_IEntry */ public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId); - + /** - * - * @param string $fileReference + * + * @param unknown_type $fileReference * @return Syncroton_Model_FileReference */ public function getFileReference($fileReference); - + /** - * return array of all id's stored in folder - * - * @param Syncroton_Model_IFolder|string $folderId - * @param string $filter - * @return array - */ + * return array of all id's stored in folder + * + * @param Syncroton_Model_IFolder|string $folderId + * @param string $filter + * @return array + */ public function getServerEntries($folderId, $filter); /** * return true if any data got modified in the backend - * + * * @param Syncroton_Backend_IContent $contentBackend * @param Syncroton_Model_IFolder $folder * @param Syncroton_Model_ISyncState $syncState * @return bool */ public function hasChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState); - + public function moveItem($srcFolderId, $serverId, $dstFolderId); - + /** * update existing entry - * + * * @param string $folderId * @param string $serverId * @param Syncroton_Model_IEntry $entry * @return string id of updated entry */ public function updateEntry($folderId, $serverId, Syncroton_Model_IEntry $entry); - + public function updateFolder(Syncroton_Model_IFolder $folder); } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Data/IDataCalendar.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Data/IDataCalendar.php
Changed
@@ -19,9 +19,10 @@ { /** * set attendee status for meeting - * + * * @param Syncroton_Model_MeetingResponse $request the meeting response * @return string id of new calendar entry */ public function setAttendeeStatus(Syncroton_Model_MeetingResponse $request); } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Data/IDataEmail.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Data/IDataEmail.php
Changed
@@ -19,15 +19,15 @@ { /** * send an email - * + * * @param resource $inputStream * @param boolean $saveInSent */ public function sendEmail($inputStream, $saveInSent); - + /** * forward an email - * + * * @param string|array $source is either a string(LongId) or an array with following properties collectionId, itemId and instanceId * @param string $inputStream * @param string $saveInSent @@ -36,10 +36,11 @@ /** * reply to an email - * + * * @param string|array $source is either a string(LongId) or an array with following properties collectionId, itemId and instanceId * @param string $inputStream * @param string $saveInSent */ public function replyEmail($source, $inputStream, $saveInSent, $replaceMime); } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Data/Notes.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Data/Notes.php
Changed
@@ -17,8 +17,8 @@ */ class Syncroton_Data_Notes extends Syncroton_Data_AData { - protected $_supportedFolderTypes = + protected $_supportedFolderTypes = array( Syncroton_Command_FolderSync::FOLDERTYPE_NOTE, - Syncroton_Command_FolderSync::FOLDERTYPE_NOTE_USER_CREATED, - ; + Syncroton_Command_FolderSync::FOLDERTYPE_NOTE_USER_CREATED + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Data/Tasks.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Data/Tasks.php
Changed
@@ -17,8 +17,9 @@ */ class Syncroton_Data_Tasks extends Syncroton_Data_AData { - protected $_supportedFolderTypes = + protected $_supportedFolderTypes = array( Syncroton_Command_FolderSync::FOLDERTYPE_TASK, - Syncroton_Command_FolderSync::FOLDERTYPE_TASK_USER_CREATED, - ; + Syncroton_Command_FolderSync::FOLDERTYPE_TASK_USER_CREATED + ); } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status.php
Changed
@@ -20,87 +20,87 @@ class Syncroton_Exception_Status extends Syncroton_Exception { // http://msdn.microsoft.com/en-us/library/ee218647%28v=exchg.80%29 - public const INVALID_CONTENT = 101; - public const INVALID_WBXML = 102; - public const INVALID_XML = 103; - public const INVALID_DATE_TIME = 104; - public const INVALID_COMBINATION_OF_IDS = 105; - public const INVALID_IDS = 106; - public const INVALID_MIME = 107; - public const DEVICE_MISSING_OR_INVALID = 108; - public const DEVICE_TYPE_MISSING_OR_INVALID = 109; - public const SERVER_ERROR = 110; - public const SERVER_ERROR_RETRY_LATER = 111; - public const ACTIVE_DIRECTORY_ACCESS_DENIED = 112; - public const MAILBOX_QUOTA_EXCEEDED = 113; - public const MAILBOX_SERVER_OFFLINE = 114; - public const SEND_QUOTA_EXCEEDED = 115; - public const MESSAGE_RECIPIENT_UNRESOLVED = 116; - public const MESSAGE_REPLY_NOT_ALLOWED = 117; - public const MESSAGE_PREVIOUSLY_SENT = 118; - public const MESSAGE_HAS_NO_RECIPIENT = 119; - public const MAIL_SUBMISSION_FAILED = 120; - public const MESSAGE_REPLY_FAILED = 121; - public const ATTACHMENT_IS_TOO_LARGE = 122; - public const USER_HAS_NO_MAILBOX = 123; - public const USER_CANNOT_BE_ANONYMOUS = 124; - public const USER_PRINCIPAL_COULD_NOT_BE_FOUND = 125; - public const USER_DISABLED_FOR_SYNC = 126; - public const USER_ON_NEW_MAILBOX_CANNOT_SYNC = 127; - public const USER_ON_LEGACY_MAILBOX_CANNOT_SYNC = 128; - public const DEVICE_IS_BLOCKED_FOR_THIS_USER = 129; - public const ACCESS_DENIED = 130; - public const ACCOUNT_DISABLED = 131; - public const SYNC_STATE_NOT_FOUND = 132; - public const SYNC_STATE_LOCKED = 133; - public const SYNC_STATE_CORRUPT = 134; - public const SYNC_STATE_ALREADY_EXISTS = 135; - public const SYNC_STATE_VERSION_INVALID = 136; - public const COMMAND_NOT_SUPPORTED = 137; - public const VERSION_NOT_SUPPORTED = 138; - public const DEVICE_NOT_FULLY_PROVISIONABLE = 139; - public const REMOTE_WIPE_REQUESTED = 140; - public const LEGACY_DEVICE_ON_STRICT_POLICY = 141; - public const DEVICE_NOT_PROVISIONED = 142; - public const POLICY_REFRESH = 143; - public const INVALID_POLICY_KEY = 144; - public const EXTERNALLY_MANAGED_DEVICES_NOT_ALLOWED = 145; - public const NO_RECURRENCE_IN_CALENDAR = 146; - public const UNEXPECTED_ITEM_CLASS = 147; - public const REMOTE_SERVER_HAS_NO_SSL = 148; - public const INVALID_STORED_REQUEST = 149; - public const ITEM_NOT_FOUND = 150; - public const TOO_MANY_FOLDERS = 151; - public const NO_FOLDERS_FOUND = 152; - public const ITEMS_LOST_AFTER_MOVE = 153; - public const FAILURE_IN_MOVE_OPERATION = 154; - public const MOVE_COMMAND_DISALLOWED = 155; - public const MOVE_COMMAND_INVALID_DESTINATION = 156; - public const AVAILABILITY_TO_MANY_RECIPIENTS = 160; - public const AVAILABILITY_DL_LIMIT_REACHED = 161; - public const AVAILABILITY_TRANSIENT_FAILURE = 162; - public const AVAILABILITY_FAILURE = 163; - public const BODY_PART_PREFERENCE_TYPE_NOT_SUPPORTED = 164; - public const DEVICE_INFORMATION_REQUIRED = 165; - public const INVALID_ACCOUNT_ID = 166; - public const ACCOUNT_SEND_DISABLED = 167; - public const IRM_FEATURE_DISABLED = 168; - public const IRM_TRANSIENT_ERROR = 169; - public const IRM_PERMANENT_ERROR = 170; - public const IRM_INVALID_TEMPLATE_ID = 171; - public const IRM_OPERATION_NOT_PERMITTED = 172; - public const NO_PICTURE = 173; - public const PICTURE_TO_LARGE = 174; - public const PICTURE_LIMIT_REACHED = 175; - public const BODY_PART_CONVERSATION_TOO_LARGE = 176; - public const MAXIMUM_DEVICES_REACHED = 177; + const INVALID_CONTENT = 101; + const INVALID_WBXML = 102; + const INVALID_XML = 103; + const INVALID_DATE_TIME = 104; + const INVALID_COMBINATION_OF_IDS = 105; + const INVALID_IDS = 106; + const INVALID_MIME = 107; + const DEVICE_MISSING_OR_INVALID = 108; + const DEVICE_TYPE_MISSING_OR_INVALID = 109; + const SERVER_ERROR = 110; + const SERVER_ERROR_RETRY_LATER = 111; + const ACTIVE_DIRECTORY_ACCESS_DENIED = 112; + const MAILBOX_QUOTA_EXCEEDED = 113; + const MAILBOX_SERVER_OFFLINE = 114; + const SEND_QUOTA_EXCEEDED = 115; + const MESSAGE_RECIPIENT_UNRESOLVED = 116; + const MESSAGE_REPLY_NOT_ALLOWED = 117; + const MESSAGE_PREVIOUSLY_SENT = 118; + const MESSAGE_HAS_NO_RECIPIENT = 119; + const MAIL_SUBMISSION_FAILED = 120; + const MESSAGE_REPLY_FAILED = 121; + const ATTACHMENT_IS_TOO_LARGE = 122; + const USER_HAS_NO_MAILBOX = 123; + const USER_CANNOT_BE_ANONYMOUS = 124; + const USER_PRINCIPAL_COULD_NOT_BE_FOUND = 125; + const USER_DISABLED_FOR_SYNC = 126; + const USER_ON_NEW_MAILBOX_CANNOT_SYNC = 127; + const USER_ON_LEGACY_MAILBOX_CANNOT_SYNC = 128; + const DEVICE_IS_BLOCKED_FOR_THIS_USER = 129; + const ACCESS_DENIED = 130; + const ACCOUNT_DISABLED = 131; + const SYNC_STATE_NOT_FOUND = 132; + const SYNC_STATE_LOCKED = 133; + const SYNC_STATE_CORRUPT = 134; + const SYNC_STATE_ALREADY_EXISTS = 135; + const SYNC_STATE_VERSION_INVALID = 136; + const COMMAND_NOT_SUPPORTED = 137; + const VERSION_NOT_SUPPORTED = 138; + const DEVICE_NOT_FULLY_PROVISIONABLE = 139; + const REMOTE_WIPE_REQUESTED = 140; + const LEGACY_DEVICE_ON_STRICT_POLICY = 141; + const DEVICE_NOT_PROVISIONED = 142; + const POLICY_REFRESH = 143; + const INVALID_POLICY_KEY = 144; + const EXTERNALLY_MANAGED_DEVICES_NOT_ALLOWED = 145; + const NO_RECURRENCE_IN_CALENDAR = 146; + const UNEXPECTED_ITEM_CLASS = 147; + const REMOTE_SERVER_HAS_NO_SSL = 148; + const INVALID_STORED_REQUEST = 149; + const ITEM_NOT_FOUND = 150; + const TOO_MANY_FOLDERS = 151; + const NO_FOLDERS_FOUND = 152; + const ITEMS_LOST_AFTER_MOVE = 153; + const FAILURE_IN_MOVE_OPERATION = 154; + const MOVE_COMMAND_DISALLOWED = 155; + const MOVE_COMMAND_INVALID_DESTINATION = 156; + const AVAILABILITY_TO_MANY_RECIPIENTS = 160; + const AVAILABILITY_DL_LIMIT_REACHED = 161; + const AVAILABILITY_TRANSIENT_FAILURE = 162; + const AVAILABILITY_FAILURE = 163; + const BODY_PART_PREFERENCE_TYPE_NOT_SUPPORTED = 164; + const DEVICE_INFORMATION_REQUIRED = 165; + const INVALID_ACCOUNT_ID = 166; + const ACCOUNT_SEND_DISABLED = 167; + CONST IRM_FEATURE_DISABLED = 168; + const IRM_TRANSIENT_ERROR = 169; + const IRM_PERMANENT_ERROR = 170; + const IRM_INVALID_TEMPLATE_ID = 171; + const IRM_OPERATION_NOT_PERMITTED = 172; + const NO_PICTURE = 173; + const PICTURE_TO_LARGE = 174; + const PICTURE_LIMIT_REACHED = 175; + const BODY_PART_CONVERSATION_TOO_LARGE = 176; + const MAXIMUM_DEVICES_REACHED = 177; /** * Common error messages assigned to error codes * * @var array */ - protected $_commonMessages = + protected $_commonMessages = array( self::INVALID_CONTENT => "Invalid request body", self::INVALID_WBXML => "Invalid WBXML request", self::INVALID_XML => "Invalid XML request", @@ -175,20 +175,20 @@ self::PICTURE_LIMIT_REACHED => "The number of contact photos returned exceeds the size limit set by the MaxPictures element", self::BODY_PART_CONVERSATION_TOO_LARGE => "The conversation is too large to compute the body parts", self::MAXIMUM_DEVICES_REACHED => "The user's account has too many device partnerships", - ; + ); /** * Error messages assigned to class-specific error codes * * @var array */ - protected $_errorMessages = ; + protected $_errorMessages = array(); /** * Constructor */ - public function __construct() + function __construct() { $args = func_get_args(); @@ -202,7 +202,7 @@ $message = $args0; } - if (empty($code)) { + if (!$code) { $code = self::SERVER_ERROR; }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/Autodiscover.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/Autodiscover.php
Changed
@@ -19,14 +19,14 @@ */ class Syncroton_Exception_Status_Autodiscover extends Syncroton_Exception_Status { - public const PROTOCOL_ERROR = 2; + const PROTOCOL_ERROR = 2; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = + protected $_errorMessages = array( self::PROTOCOL_ERROR => "Protocol error", - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/FolderCreate.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/FolderCreate.php
Changed
@@ -19,21 +19,21 @@ */ class Syncroton_Exception_Status_FolderCreate extends Syncroton_Exception_Status { - public const FOLDER_EXISTS = 2; - public const SPECIAL_FOLDER = 3; - public const PARENT_NOT_FOUND = 5; - public const FOLDER_SERVER_ERROR = 6; - public const INVALID_SYNCKEY = 9; - public const INVALID_REQUEST = 10; - public const UNKNOWN_ERROR = 11; - public const UNKNOWN_CODE = 12; + const FOLDER_EXISTS = 2; + const SPECIAL_FOLDER = 3; + const PARENT_NOT_FOUND = 5; + const FOLDER_SERVER_ERROR = 6; + const INVALID_SYNCKEY = 9; + const INVALID_REQUEST = 10; + const UNKNOWN_ERROR = 11; + const UNKNOWN_CODE = 12; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = + protected $_errorMessages = array( self::FOLDER_EXISTS => "A folder that has this name already exists", self::SPECIAL_FOLDER => "The specified folder is a special system folder", self::PARENT_NOT_FOUND => "The specified parent folder was not found", @@ -42,5 +42,5 @@ self::INVALID_REQUEST => "Malformed request", self::UNKNOWN_ERROR => "An unknown error occurred", self::UNKNOWN_CODE => "Unusual back-end issue", - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/FolderDelete.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/FolderDelete.php
Changed
@@ -19,24 +19,24 @@ */ class Syncroton_Exception_Status_FolderDelete extends Syncroton_Exception_Status { - public const SPECIAL_FOLDER = 3; - public const FOLDER_NOT_FOUND = 4; - public const FOLDER_SERVER_ERROR = 6; - public const INVALID_SYNCKEY = 9; - public const INVALID_REQUEST = 10; - public const UNKNOWN_ERROR = 11; + const SPECIAL_FOLDER = 3; + const FOLDER_NOT_FOUND = 4; + const FOLDER_SERVER_ERROR = 6; + const INVALID_SYNCKEY = 9; + const INVALID_REQUEST = 10; + const UNKNOWN_ERROR = 11; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = + protected $_errorMessages = array( self::SPECIAL_FOLDER => "The specified folder is a special system folder", self::FOLDER_NOT_FOUND => "The specified folder doesn't exist", self::FOLDER_SERVER_ERROR => "An error occurred on the server", self::INVALID_SYNCKEY => "Synchronization key mismatch or invalid synchronization key", self::INVALID_REQUEST => "Malformed request", self::UNKNOWN_ERROR => "An unknown error occurred", - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/FolderSync.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/FolderSync.php
Changed
@@ -19,22 +19,22 @@ */ class Syncroton_Exception_Status_FolderSync extends Syncroton_Exception_Status { - public const FOLDER_SERVER_ERROR = 6; - public const INVALID_SYNCKEY = 9; - public const INVALID_REQUEST = 10; - public const UNKNOWN_ERROR = 11; - public const UNKNOWN_CODE = 12; + const FOLDER_SERVER_ERROR = 6; + const INVALID_SYNCKEY = 9; + const INVALID_REQUEST = 10; + const UNKNOWN_ERROR = 11; + const UNKNOWN_CODE = 12; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = + protected $_errorMessages = array( self::FOLDER_SERVER_ERROR => "An error occurred on the server", self::INVALID_SYNCKEY => "Synchronization key mismatch or invalid synchronization key", self::INVALID_REQUEST => "Malformed request", self::UNKNOWN_ERROR => "An unknown error occurred", self::UNKNOWN_CODE => "Unusual back-end issue", - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/FolderUpdate.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/FolderUpdate.php
Changed
@@ -19,21 +19,21 @@ */ class Syncroton_Exception_Status_FolderUpdate extends Syncroton_Exception_Status { - public const FOLDER_EXISTS = 2; - public const SPECIAL_FOLDER = 3; - public const FOLDER_NOT_FOUND = 4; - public const PARENT_NOT_FOUND = 5; - public const FOLDER_SERVER_ERROR = 6; - public const INVALID_SYNCKEY = 9; - public const INVALID_REQUEST = 10; - public const UNKNOWN_ERROR = 11; + const FOLDER_EXISTS = 2; + const SPECIAL_FOLDER = 3; + const FOLDER_NOT_FOUND = 4; + const PARENT_NOT_FOUND = 5; + const FOLDER_SERVER_ERROR = 6; + const INVALID_SYNCKEY = 9; + const INVALID_REQUEST = 10; + const UNKNOWN_ERROR = 11; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = + protected $_errorMessages = array( self::FOLDER_EXISTS => "A folder that has this name already exists or is a special folder", self::SPECIAL_FOLDER => "The specified folder is the Recipient information folder which cannot be updated", self::FOLDER_NOT_FOUND => "The specified folder doesn't exist", @@ -42,5 +42,5 @@ self::INVALID_SYNCKEY => "Synchronization key mismatch or invalid synchronization key", self::INVALID_REQUEST => "Malformed request", self::UNKNOWN_ERROR => "An unknown error occurred", - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/GetItemEstimate.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/GetItemEstimate.php
Changed
@@ -19,18 +19,18 @@ */ class Syncroton_Exception_Status_GetItemEstimate extends Syncroton_Exception_Status { - public const INVALID_COLLECTION = 2; - public const SYNCSTATE_NOT_PRIMED = 3; - public const INVALID_SYNCKEY = 4; + const INVALID_COLLECTION = 2; + const SYNCSTATE_NOT_PRIMED = 3; + const INVALID_SYNCKEY = 4; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = + protected $_errorMessages = array( self::INVALID_COLLECTION => "A collection was invalid or one of the specified collection IDs was invalid", self::SYNCSTATE_NOT_PRIMED => "The synchronization state has not been primed", self::INVALID_SYNCKEY => "The specified synchronization key was invalid", - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/ItemOperations.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/ItemOperations.php
Changed
@@ -19,29 +19,29 @@ */ class Syncroton_Exception_Status_ItemOperations extends Syncroton_Exception_Status { - public const PROTOCOL_ERROR = 2; - public const ITEM_SERVER_ERROR = 3; - public const DOCLIB_INVALID_URI = 4; - public const DOCLIB_ACCESS_DENIED = 5; - public const DOCLIB_NOT_FOUND = 6; - public const DOCLIB_CONN_FAILED = 7; - public const INVALID_BYTE_RANGE = 8; - public const UNKNOWN_STORE = 9; - public const FILE_EMPTY = 10; - public const DATA_TOO_LARGE = 11; - public const FILE_IO_ERROR = 12; - public const CONVERSION_ERROR = 14; - public const INVALID_ATTACHMENT = 15; - public const RESOURCE_ACCESS_DENIED = 16; - public const PARTIAL_SUCCESS = 17; - public const CREDENTIALS_REQUIRED = 18; + const PROTOCOL_ERROR = 2; + const ITEM_SERVER_ERROR = 3; + const DOCLIB_INVALID_URI = 4; + const DOCLIB_ACCESS_DENIED = 5; + const DOCLIB_NOT_FOUND = 6; + const DOCLIB_CONN_FAILED = 7; + const INVALID_BYTE_RANGE = 8; + const UNKNOWN_STORE = 9; + const FILE_EMPTY = 10; + const DATA_TOO_LARGE = 11; + const FILE_IO_ERROR = 12; + const CONVERSION_ERROR = 14; + const INVALID_ATTACHMENT = 15; + const RESOURCE_ACCESS_DENIED = 16; + const PARTIAL_SUCCESS = 17; + const CREDENTIALS_REQUIRED = 18; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = + protected $_errorMessages = array( self::PROTOCOL_ERROR => "Protocol error - protocol violation/XML validation error", self::ITEM_SERVER_ERROR => "Server error", self::DOCLIB_INVALID_URI => "Document library access - The specified URI is bad", @@ -58,5 +58,5 @@ self::RESOURCE_ACCESS_DENIED => "Access to the resource is denied", self::PARTIAL_SUCCESS => "Partial success; the command completed partially", self::CREDENTIALS_REQUIRED => "Credentials required", - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/MeetingResponse.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/MeetingResponse.php
Changed
@@ -19,18 +19,18 @@ */ class Syncroton_Exception_Status_MeetingResponse extends Syncroton_Exception_Status { - public const INVALID_REQUEST = 2; - public const MEETING_SERVER_ERROR = 3; - public const MEETING_ERROR = 4; + const INVALID_REQUEST = 2; + const MEETING_SERVER_ERROR = 3; + const MEETING_ERROR = 4; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = + protected $_errorMessages = array( self::INVALID_REQUEST => "Invalid meeting request", self::MEETING_SERVER_ERROR => "An error occurred on the server mailbox", self::MEETING_ERROR => "An error occurred on the server", - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/MoveItems.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/MoveItems.php
Changed
@@ -19,22 +19,22 @@ */ class Syncroton_Exception_Status_MoveItems extends Syncroton_Exception_Status { - public const INVALID_SOURCE = 1; - public const INVALID_DESTINATION = 2; - public const SAME_FOLDER = 4; - public const ITEM_EXISTS_OR_LOCKED = 5; - public const FOLDER_LOCKED = 7; + const INVALID_SOURCE = 1; + const INVALID_DESTINATION = 2; + const SAME_FOLDER = 4; + const ITEM_EXISTS_OR_LOCKED = 5; + const FOLDER_LOCKED = 7; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = + protected $_errorMessages = array( self::INVALID_SOURCE => "Invalid source collection ID or item ID", self::INVALID_DESTINATION => "Invalid destination collection ID", self::SAME_FOLDER => "Source and destination collection IDs are the same", self::ITEM_EXISTS_OR_LOCKED => "The item cannot be moved to more than one item at a time, or the source or destination item was locked", self::FOLDER_LOCKED => "Source or destination item was locked", - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/Settings.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/Settings.php
Changed
@@ -19,24 +19,24 @@ */ class Syncroton_Exception_Status_Settings extends Syncroton_Exception_Status { - public const PROTOCOL_ERROR = 2; - public const ACCESS_DENIED = 3; - public const SERVICE_UNAVAILABLE = 4; - public const INVALID_ARGUMENTS = 5; - public const CONFLICTING_ARGUMENTS = 6; - public const DENIED_BY_POLICY = 7; + const PROTOCOL_ERROR = 2; + const ACCESS_DENIED = 3; + const SERVICE_UNAVAILABLE = 4; + const INVALID_ARGUMENTS = 5; + const CONFLICTING_ARGUMENTS = 6; + const DENIED_BY_POLICY = 7; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = - self::PROTOCOL_ERROR => "Protocol error", - self::ACCESS_DENIED => "Access denied", - self::SERVICE_UNAVAILABLE => "Server unavailable", - self::INVALID_ARGUMENTS => "Invalid arguments", - self::CONFLICTING_ARGUMENTS => "Conflicting arguments", - self::DENIED_BY_POLICY => "Denied by policy. Disabled by administrator", - ; + protected $_errorMessages = array( + self::PROTOCOL_ERROR => "Protocol error"; + self::ACCESS_DENIED => "Access denied"; + self::SERVICE_UNAVAILABLE => "Server unavailable"; + self::INVALID_ARGUMENTS => "Invalid arguments"; + self::CONFLICTING_ARGUMENTS => "Conflicting arguments"; + self::DENIED_BY_POLICY => "Denied by policy. Disabled by administrator"; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/Status/Sync.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Exception/Status/Sync.php
Changed
@@ -19,25 +19,25 @@ */ class Syncroton_Exception_Status_Sync extends Syncroton_Exception_Status { - public const INVALID_SYNCKEY = 3; - public const PROTOCOL_ERROR = 4; - public const SYNC_SERVER_ERROR = 5; - public const INVALID_ITEM = 6; - public const OBJECT_CONFLICT = 7; - public const OBJECT_NOT_FOUND = 8; - public const SYNC_ERROR = 9; - public const HIERARCHY_CHANGED = 12; - public const INCOMPLETE_REQUEST = 13; - public const INVALID_INTERVAL = 14; - public const INVALID_REQUEST = 15; - public const SYNC_RETRY = 16; + const INVALID_SYNCKEY = 3; + const PROTOCOL_ERROR = 4; + const SYNC_SERVER_ERROR = 5; + const INVALID_ITEM = 6; + const OBJECT_CONFLICT = 7; + const OBJECT_NOT_FOUND = 8; + const SYNC_ERROR = 9; + const HIERARCHY_CHANGED = 12; + const INCOMPLETE_REQUEST = 13; + const INVALID_INTERVAL = 14; + const INVALID_REQUEST = 15; + const SYNC_RETRY = 16; /** * Error messages assigned to error codes * * @var array */ - protected $_errorMessages = + protected $_errorMessages = array( self::INVALID_SYNCKEY => "Invalid synchronization key", self::PROTOCOL_ERROR => "Protocol error", self::SYNC_SERVER_ERROR => "Server error", @@ -50,5 +50,5 @@ self::INVALID_INTERVAL => "Invalid Wait or HeartbeatInterval value", self::INVALID_REQUEST => "Too many collections are included in the Sync request", self::SYNC_RETRY => "Something on the server caused a retriable error", - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/AEntry.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/AEntry.php
Changed
@@ -15,12 +15,13 @@ * @package Syncroton * @subpackage Model */ + abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, IteratorAggregate, Countable { - protected $_elements = ; - + protected $_elements = array(); + protected $_isDirty; - + /** * (non-PHPdoc) * @see Syncroton_Model_IEntry::__construct() @@ -30,31 +31,29 @@ if (is_array($properties)) { $this->setFromArray($properties); } - + $this->_isDirty = false; } - - + + /** * (non-PHPdoc) * @see Countable::count() - */ - #\ReturnTypeWillChange + */ public function count() { return count($this->_elements); } - + /** * (non-PHPdoc) * @see IteratorAggregate::getIterator() */ - #\ReturnTypeWillChange - public function getIterator() - { - return new ArrayIterator($this->_elements); + public function getIterator() + { + return new ArrayIterator($this->_elements); } - + /** * (non-PHPdoc) * @see Syncroton_Model_IEntry::isDirty() @@ -63,7 +62,7 @@ { return $this->_isDirty; } - + /** * (non-PHPdoc) * @see Syncroton_Model_IEntry::setFromArray() @@ -79,28 +78,28 @@ } } } - - public function &__get($name) - { - return $this->_elements$name; - } - - public function __set($name, $value) + + public function &__get($name) + { + return $this->_elements$name; + } + + public function __set($name, $value) { if (!array_key_exists($name, $this->_elements) || $this->_elements$name != $value) { $this->_elements$name = $value; - + $this->_isDirty = true; - } - } - - public function __isset($name) - { - return isset($this->_elements$name); - } - - public function __unset($name) - { - unset($this->_elements$name); + } + } + + public function __isset($name) + { + return isset($this->_elements$name); + } + + public function __unset($name) + { + unset($this->_elements$name); } -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/AXMLEntry.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/AXMLEntry.php
Changed
@@ -19,11 +19,11 @@ abstract class Syncroton_Model_AXMLEntry extends Syncroton_Model_AEntry implements Syncroton_Model_IXMLEntry { protected $_xmlBaseElement; - - protected $_properties = ; - + + protected $_properties = array(); + protected $_dateTimeFormat = "Y-m-d\TH:i:s.000\Z"; - + /** * (non-PHPdoc) * @see Syncroton_Model_IEntry::__construct() @@ -35,10 +35,10 @@ } elseif (is_array($properties)) { $this->setFromArray($properties); } - + $this->_isDirty = false; } - + /** * (non-PHPdoc) * @see Syncroton_Model_IEntry::appendXML() @@ -46,27 +46,27 @@ public function appendXML(DOMElement $domParrent, Syncroton_Model_IDevice $device) { $this->_addXMLNamespaces($domParrent); - + foreach($this->_elements as $elementName => $value) { // skip empty values if($value === null || $value === '' || (is_array($value) && empty($value))) { continue; } - - $nameSpace, $elementProperties = $this->_getElementProperties($elementName); - - if ($nameSpace == 'Internal') { - continue; - } - - $elementVersion = $elementProperties'supportedSince' ?? '12.0'; - + + list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName); + + if ($nameSpace == 'Internal') { + continue; + } + + $elementVersion = isset($elementProperties'supportedSince') ? $elementProperties'supportedSince' : '12.0'; + if (version_compare($device->acsversion, $elementVersion, '<')) { continue; } - + $nameSpace = 'uri:' . $nameSpace; - + if (isset($elementProperties'childElement')) { $element = $domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName)); foreach($value as $subValue) { @@ -75,13 +75,13 @@ $element->appendChild($subElement); } $domParrent->appendChild($element); - } elseif ($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); } - } elseif ($elementProperties'type' == 'none') { + } else if ($elementProperties'type' == 'none') { if ($value) { $element = $domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName)); $domParrent->appendChild($element); @@ -93,80 +93,80 @@ } } } - + /** * (non-PHPdoc) * @see Syncroton_Model_IEntry::getProperties() */ public function getProperties($selectedNamespace = null) { - $properties = ; - + $properties = array(); + foreach($this->_properties as $namespace => $namespaceProperties) { if ($selectedNamespace !== null && $namespace != $selectedNamespace) { continue; } - $properties = array_merge($properties, array_keys($namespaceProperties)); + $properties = array_merge($properties, array_keys($namespaceProperties)); } - + return $properties; - + } - - /** - * set properties from SimpleXMLElement object - * - * @param SimpleXMLElement $properties - * @throws InvalidArgumentException - */ - public function setFromSimpleXMLElement(SimpleXMLElement $properties) - { + + /** + * set properties from SimpleXMLElement object + * + * @param SimpleXMLElement $xmlCollection + * @throws InvalidArgumentException + */ + public function setFromSimpleXMLElement(SimpleXMLElement $properties) + { if (!in_array($properties->getName(), (array) $this->_xmlBaseElement)) { - throw new InvalidArgumentException('Unexpected element name: ' . $properties->getName()); - } - + throw new InvalidArgumentException('Unexpected element name: ' . $properties->getName()); + } + foreach (array_keys($this->_properties) as $namespace) { if ($namespace == 'Internal') { continue; } - - $this->_parseNamespace($namespace, $properties); - } - - return; + + $this->_parseNamespace($namespace, $properties); + } + + return; } - + /** * add needed xml namespaces to DomDocument - * - * @param DOMElement $domParent + * + * @param unknown_type $domParrent */ - protected function _addXMLNamespaces(DOMElement $domParent) + protected function _addXMLNamespaces(DOMElement $domParrent) { - foreach ($this->_properties as $namespace => $namespaceProperties) { + foreach($this->_properties as $namespace => $namespaceProperties) { // don't add default namespace again - if ($domParent->ownerDocument->documentElement->namespaceURI != 'uri:' . $namespace) { - $domParent->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:' . $namespace, 'uri:' . $namespace); - } + if($domParrent->ownerDocument->documentElement->namespaceURI != 'uri:'.$namespace) { + $domParrent->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:'.$namespace, 'uri:'.$namespace); + } } - } - + } + protected function _appendXMLElement(Syncroton_Model_IDevice $device, DOMElement $element, $elementProperties, $value) { - if ($value instanceof Syncroton_Model_IEntry) { - $value->appendXML($element, $device); // @phpstan-ignore-line - } else { - if ($value instanceof DateTime) { + if ($value instanceof Syncroton_Model_IEntry) { + $value->appendXML($element, $device); + } else { + if ($value instanceof DateTime) { $value = $value->format($this->_dateTimeFormat); - - } elseif (isset($elementProperties'encoding') && $elementProperties'encoding' == 'base64') { - if (is_resource($value)) { + + } elseif (isset($elementProperties'encoding') && $elementProperties'encoding' == 'base64') { + if (is_resource($value)) { rewind($value); - $value = stream_get_contents($value); - } - $value = base64_encode($value); - } - + $value = stream_get_contents($value); + } + $value = base64_encode($value); + } + if ($elementProperties'type' == 'byteArray') { $element->setAttributeNS('uri:Syncroton', 'Syncroton:encoding', 'opaque'); // encode to base64; the wbxml encoder will base64_decode it again @@ -174,15 +174,15 @@ $element->appendChild($element->ownerDocument->createCDATASection(base64_encode($value))); } else { // strip off any non printable control characters - if (!ctype_print((string)$value)) { + if (!ctype_print($value)) { $value = $this->_removeControlChars($value); } - + $element->appendChild($element->ownerDocument->createTextNode($this->_enforceUTF8($value))); - } - } + } + } } - + /** * remove control chars from a string which are not allowed in XML values * @@ -193,15 +193,15 @@ { // Replace non-character UTF-8 sequences that cause XML Parser to fail // https://git.kolab.org/T1311 - $dirty = str_replace("\xEF\xBF\xBE", "\xEF\xBF\xBF", '', $dirty); + $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 - * + * * @param string $dirty the string with maybe invalid utf-8 data * @return string string with valid utf-8 */ @@ -212,87 +212,62 @@ return $clean; } } - + if (function_exists('mb_convert_encoding')) { if (($clean = mb_convert_encoding($dirty, 'UTF-8', 'UTF-8')) !== false) { return $clean; } } - + return $dirty; } - - /** - * Fix date-time string input - * - * @param string $date Date time string - * - * @return string - */ - protected function _fixDateTimeString($date) - { - // Note: Some clients send date-time in local charset instead of ascii - // It is not supported by PHP DateTime constructor - - $from = - 'Ù¡','Ù¢','Ù£','Ù¤','Ù¥','Ù¦','Ù§','Ù¨','Ù©','Ù ', // arabic - 'Û±','Û²','Û³','Û´','Ûµ','Û¶','Û·','Û¸','Û¹','Û°', // persian - ; - - $to = - '1','2','3','4','5','6','7','8','9','0', - '1','2','3','4','5','6','7','8','9','0', - ; - - return str_replace($from, $to, $date); - } - + /** - * - * @param string $element + * + * @param unknown_type $element * @throws InvalidArgumentException - * @return array + * @return multitype:unknown */ - protected function _getElementProperties($element) + protected function _getElementProperties($element) { foreach($this->_properties as $namespace => $namespaceProperties) { - if (array_key_exists($element, $namespaceProperties)) { - return $namespace, $namespaceProperties$element; - } - } - - throw new InvalidArgumentException("$element is no valid property of " . get_class($this)); + if (array_key_exists($element, $namespaceProperties)) { + return array($namespace, $namespaceProperties$element); + } + } + + throw new InvalidArgumentException("$element is no valid property of " . get_class($this)); } - + protected function _parseNamespace($nameSpace, SimpleXMLElement $properties) { - // fetch data from Contacts namespace - $children = $properties->children("uri:$nameSpace"); - + // fetch data from Contacts namespace + $children = $properties->children("uri:$nameSpace"); + foreach ($children as $elementName => $xmlElement) { $elementName = lcfirst($elementName); - + if (!isset($this->_properties$nameSpace$elementName)) { continue; } - - , $elementProperties = $this->_getElementProperties($elementName); - + + list (, $elementProperties) = $this->_getElementProperties($elementName); + switch ($elementProperties'type') { case 'container': if (!empty($elementProperties'multiple')) { $property = (array) $this->$elementName; - + if (isset($elementProperties'class')) { $property = new $elementProperties'class'($xmlElement); } else { $property = (string) $xmlElement; } - } elseif (isset($elementProperties'childElement')) { - $property = ; - + } else if (isset($elementProperties'childElement')) { + $property = array(); + $childElement = ucfirst($elementProperties'childElement'); - + foreach ($xmlElement->$childElement as $subXmlElement) { if (isset($elementProperties'class')) { $property = new $elementProperties'class'($subXmlElement); @@ -301,15 +276,15 @@ } } } else { - $subClassName = $elementProperties'class' ?? get_class($this) . ucfirst($elementName); - - $property = new $subClassName($xmlElement); + $subClassName = isset($elementProperties'class') ? $elementProperties'class' : get_class($this) . ucfirst($elementName); + + $property = new $subClassName($xmlElement); } - + break; - + case 'datetime': - $property = new DateTime($this->_fixDateTimeString((string) $xmlElement), new DateTimeZone('UTC')); + $property = new DateTime((string) $xmlElement, new DateTimeZone('UTC')); break; case 'number': @@ -324,30 +299,30 @@ if (isset($elementProperties'encoding') && $elementProperties'encoding' == 'base64') { $property = base64_decode($property); } - + $this->$elementName = $property; - } + } } - - public function &__get($name) - { - $this->_getElementProperties($name); - - return $this->_elements$name; - } - - public function __set($name, $value) - { - $nameSpace, $properties = $this->_getElementProperties($name); - - if ($properties'type' == 'datetime' && !$value instanceof DateTime) { - throw new InvalidArgumentException("value for $name must be an instance of DateTime"); - } - - if (!array_key_exists($name, $this->_elements) || $this->_elements$name != $value) { + + public function &__get($name) + { + $this->_getElementProperties($name); + + return $this->_elements$name; + } + + public function __set($name, $value) + { + list ($nameSpace, $properties) = $this->_getElementProperties($name); + + if ($properties'type' == 'datetime' && !$value instanceof DateTime) { + throw new InvalidArgumentException("value for $name must be an instance of DateTime"); + } + + if (!array_key_exists($name, $this->_elements) || $this->_elements$name != $value) { $this->_elements$name = $value; - + $this->_isDirty = true; - } - } -} + } + } +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Account.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Account.php
Changed
@@ -14,30 +14,30 @@ * * @package Syncroton * @subpackage Model - * @property string $accountId - * @property string $accountName - * @property string $userDisplayName - * @property bool $sendDisabled - * @property string $primaryAddress - * @property array $addresses + * @property string accountId + * @property string accountName + * @property string userDisplayName + * @property bool sendDisabled + * @property string primaryAddress + * @property array addresses */ class Syncroton_Model_Account extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'Account'; - protected $_properties = - 'Settings' => - 'accountId' => 'type' => 'string', - 'accountName' => 'type' => 'string', - 'userDisplayName' => 'type' => 'string', - 'sendDisabled' => 'type' => 'number', + protected $_properties = array( + 'Settings' => array( + 'accountId' => array('type' => 'string'), + 'accountName' => array('type' => 'string'), + 'userDisplayName' => array('type' => 'string'), + 'sendDisabled' => array('type' => 'number'), // 'emailAddresses' => array('type' => 'container'), - , - 'Internal' => - 'primaryAddress' => 'type' => 'string', - 'addresses' => 'type' => 'array', - , - ; + ), + 'Internal' => array( + 'primaryAddress' => array('type' => 'string'), + 'addresses' => array('type' => 'array'), + ), + ); /** * (non-PHPdoc)
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Contact.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Contact.php
Changed
@@ -14,91 +14,90 @@ * * @package Syncroton * @subpackage Model - * @property string $alias - * @property DateTime $anniversary - * @property string $assistantName - * @property string $assistantPhoneNumber - * @property DateTime $birthday - * @property string $business2PhoneNumber - * @property string $businessAddressCity - * @property Syncroton_Model_EmailBody $body - * @property string $firstName - * @property string $lastName + * @property string Alias + * @property DateTime Anniversary + * @property string AssistantName + * @property string AssistantPhoneNumber + * @property DateTime Birthday + * @property string Business2PhoneNumber + * @property string BusinessAddressCity + * @property Syncroton_Model_EmailBody Body */ + class Syncroton_Model_Contact extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'ApplicationData'; - - protected $_properties = - 'AirSyncBase' => - 'body' => 'type' => 'container', 'class' => 'Syncroton_Model_EmailBody', - , - 'Contacts' => - 'alias' => 'type' => 'string', 'supportedSince' => '14.0', - 'anniversary' => 'type' => 'datetime', - 'assistantName' => 'type' => 'string', - 'assistantPhoneNumber' => 'type' => 'string', - 'birthday' => 'type' => 'datetime', - 'business2PhoneNumber' => 'type' => 'string', - 'businessAddressCity' => 'type' => 'string', - 'businessAddressCountry' => 'type' => 'string', - 'businessAddressPostalCode' => 'type' => 'string', - 'businessAddressState' => 'type' => 'string', - 'businessAddressStreet' => 'type' => 'string', - 'businessFaxNumber' => 'type' => 'string', - 'businessPhoneNumber' => 'type' => 'string', - 'carPhoneNumber' => 'type' => 'string', - 'categories' => 'type' => 'container', 'childElement' => 'category', - 'children' => 'type' => 'container', 'childElement' => 'child', - 'companyName' => 'type' => 'string', - 'department' => 'type' => 'string', - 'email1Address' => 'type' => 'string', - 'email2Address' => 'type' => 'string', - 'email3Address' => 'type' => 'string', - 'fileAs' => 'type' => 'string', - 'firstName' => 'type' => 'string', - 'home2PhoneNumber' => 'type' => 'string', - 'homeAddressCity' => 'type' => 'string', - 'homeAddressCountry' => 'type' => 'string', - 'homeAddressPostalCode' => 'type' => 'string', - 'homeAddressState' => 'type' => 'string', - 'homeAddressStreet' => 'type' => 'string', - 'homeFaxNumber' => 'type' => 'string', - 'homePhoneNumber' => 'type' => 'string', - 'jobTitle' => 'type' => 'string', - 'lastName' => 'type' => 'string', - 'middleName' => 'type' => 'string', - 'mobilePhoneNumber' => 'type' => 'string', - 'officeLocation' => 'type' => 'string', - 'otherAddressCity' => 'type' => 'string', - 'otherAddressCountry' => 'type' => 'string', - 'otherAddressPostalCode' => 'type' => 'string', - 'otherAddressState' => 'type' => 'string', - 'otherAddressStreet' => 'type' => 'string', - 'pagerNumber' => 'type' => 'string', - 'picture' => 'type' => 'string', 'encoding' => 'base64', - 'padioPhoneNumber' => 'type' => 'string', - 'rtf' => 'type' => 'string', - 'spouse' => 'type' => 'string', - 'suffix' => 'type' => 'string', - 'title' => 'type' => 'string', - 'webPage' => 'type' => 'string', - 'weightedRank' => 'type' => 'string', 'supportedSince' => '14.0', - 'yomiCompanyName' => 'type' => 'string', - 'yomiFirstName' => 'type' => 'string', - 'yomiLastName' => 'type' => 'string', - , - 'Contacts2' => - 'accountName' => 'type' => 'string', - 'companyMainPhone' => 'type' => 'string', - 'customerId' => 'type' => 'string', - 'governmentId' => 'type' => 'string', - 'iMAddress' => 'type' => 'string', - 'iMAddress2' => 'type' => 'string', - 'iMAddress3' => 'type' => 'string', - 'managerName' => 'type' => 'string', - 'mMS' => 'type' => 'string', - 'nickName' => 'type' => 'string', - , - ; -} + + protected $_properties = array( + 'AirSyncBase' => array( + 'body' => array('type' => 'container', 'class' => 'Syncroton_Model_EmailBody') + ), + 'Contacts' => array( + 'alias' => array('type' => 'string', 'supportedSince' => '14.0'), + 'anniversary' => array('type' => 'datetime'), + 'assistantName' => array('type' => 'string'), + 'assistantPhoneNumber' => array('type' => 'string'), + 'birthday' => array('type' => 'datetime'), + 'business2PhoneNumber' => array('type' => 'string'), + 'businessAddressCity' => array('type' => 'string'), + 'businessAddressCountry' => array('type' => 'string'), + 'businessAddressPostalCode' => array('type' => 'string'), + 'businessAddressState' => array('type' => 'string'), + 'businessAddressStreet' => array('type' => 'string'), + 'businessFaxNumber' => array('type' => 'string'), + 'businessPhoneNumber' => array('type' => 'string'), + 'carPhoneNumber' => array('type' => 'string'), + 'categories' => array('type' => 'container', 'childElement' => 'category'), + 'children' => array('type' => 'container', 'childElement' => 'child'), + 'companyName' => array('type' => 'string'), + 'department' => array('type' => 'string'), + 'email1Address' => array('type' => 'string'), + 'email2Address' => array('type' => 'string'), + 'email3Address' => array('type' => 'string'), + 'fileAs' => array('type' => 'string'), + 'firstName' => array('type' => 'string'), + 'home2PhoneNumber' => array('type' => 'string'), + 'homeAddressCity' => array('type' => 'string'), + 'homeAddressCountry' => array('type' => 'string'), + 'homeAddressPostalCode' => array('type' => 'string'), + 'homeAddressState' => array('type' => 'string'), + 'homeAddressStreet' => array('type' => 'string'), + 'homeFaxNumber' => array('type' => 'string'), + 'homePhoneNumber' => array('type' => 'string'), + 'jobTitle' => array('type' => 'string'), + 'lastName' => array('type' => 'string'), + 'middleName' => array('type' => 'string'), + 'mobilePhoneNumber' => array('type' => 'string'), + 'officeLocation' => array('type' => 'string'), + 'otherAddressCity' => array('type' => 'string'), + 'otherAddressCountry' => array('type' => 'string'), + 'otherAddressPostalCode' => array('type' => 'string'), + 'otherAddressState' => array('type' => 'string'), + 'otherAddressStreet' => array('type' => 'string'), + 'pagerNumber' => array('type' => 'string'), + 'picture' => array('type' => 'string', 'encoding' => 'base64'), + 'padioPhoneNumber' => array('type' => 'string'), + 'rtf' => array('type' => 'string'), + 'spouse' => array('type' => 'string'), + 'suffix' => array('type' => 'string'), + 'title' => array('type' => 'string'), + 'webPage' => array('type' => 'string'), + 'weightedRank' => array('type' => 'string', 'supportedSince' => '14.0'), + 'yomiCompanyName' => array('type' => 'string'), + 'yomiFirstName' => array('type' => 'string'), + 'yomiLastName' => array('type' => 'string'), + ), + 'Contacts2' => array( + 'accountName' => array('type' => 'string'), + 'companyMainPhone' => array('type' => 'string'), + 'customerId' => array('type' => 'string'), + 'governmentId' => array('type' => 'string'), + 'iMAddress' => array('type' => 'string'), + 'iMAddress2' => array('type' => 'string'), + 'iMAddress3' => array('type' => 'string'), + 'managerName' => array('type' => 'string'), + 'mMS' => array('type' => 'string'), + 'nickName' => array('type' => 'string'), + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Content.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Content.php
Changed
@@ -18,3 +18,4 @@ class Syncroton_Model_Content extends Syncroton_Model_AEntry implements Syncroton_Model_IContent { } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Device.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Device.php
Changed
@@ -17,36 +17,37 @@ */ class Syncroton_Model_Device extends Syncroton_Model_AEntry implements Syncroton_Model_IDevice { - public const TYPE_IPHONE = 'iphone'; - public const TYPE_WEBOS = 'webos'; - public const TYPE_ANDROID = 'android'; - public const TYPE_ANDROID_40 = 'android40'; - public const TYPE_SMASUNGGALAXYS2 = 'samsunggti9100'; // Samsung Galaxy S-3 - public const TYPE_BLACKBERRY = 'blackberry'; - + const TYPE_IPHONE = 'iphone'; + const TYPE_WEBOS = 'webos'; + const TYPE_ANDROID = 'android'; + const TYPE_ANDROID_40 = 'android40'; + const TYPE_SMASUNGGALAXYS2 = 'samsunggti9100'; // Samsung Galaxy S-3 + const TYPE_BLACKBERRY = 'blackberry'; + /** * Returns major firmware version of this device - * - * @return int|string + * + * @return int/string */ public function getMajorVersion() { switch (strtolower($this->devicetype)) { case Syncroton_Model_Device::TYPE_BLACKBERRY: if (preg_match('/(.+)\/(.+)/', $this->useragent, $matches)) { - , $name, $version = $matches; + list(, $name, $version) = $matches; return $version; } break; - + case Syncroton_Model_Device::TYPE_IPHONE: if (preg_match('/(.+)\/(\d+)\.(\d+)/', $this->useragent, $matches)) { - , $name, $majorVersion, $minorVersion = $matches; + list(, $name, $majorVersion, $minorVersion) = $matches; return $majorVersion; } break; } - + return 0; } } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/DeviceInformation.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/DeviceInformation.php
Changed
@@ -14,29 +14,29 @@ * * @package Syncroton * @subpackage Model - * @property string $friendlyName - * @property string $iMEI - * @property string $mobileOperator - * @property string $model - * @property string $oS - * @property string $oSLanguage - * @property string $phoneNumber + * @property string friendlyName + * @property string iMEI + * @property string mobileOperator + * @property string model + * @property string oS + * @property string oSLanguage + * @property string phoneNumber */ class Syncroton_Model_DeviceInformation extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'Set'; - - protected $_properties = - 'Settings' => - 'enableOutboundSMS' => 'type' => 'number', - 'friendlyName' => 'type' => 'string', - 'iMEI' => 'type' => 'string', - 'mobileOperator' => 'type' => 'string', - 'model' => 'type' => 'string', - 'oS' => 'type' => 'string', - 'oSLanguage' => 'type' => 'string', - 'phoneNumber' => 'type' => 'string', - , - ; -} + + protected $_properties = array( + 'Settings' => array( + 'enableOutboundSMS' => array('type' => 'number'), + 'friendlyName' => array('type' => 'string'), + 'iMEI' => array('type' => 'string'), + 'mobileOperator' => array('type' => 'string'), + 'model' => array('type' => 'string'), + 'oS' => array('type' => 'string'), + 'oSLanguage' => array('type' => 'string'), + 'phoneNumber' => array('type' => 'string') + ), + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Email.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Email.php
Changed
@@ -14,77 +14,77 @@ * * @package Syncroton * @subpackage Model - * @property array $attachments - * @property string $contentType - * @property array $flag - * @property Syncroton_Model_EmailBody $body - * @property array $cc - * @property array $to - * @property int $lastVerbExecuted - * @property DateTime $lastVerbExecutionTime - * @property int $read + * @property array attachments + * @property string contentType + * @property array flag + * @property Syncroton_Model_EmailBody body + * @property array cc + * @property array to + * @property int lastVerbExecuted + * @property DateTime lastVerbExecutionTime + * @property int read */ class Syncroton_Model_Email extends Syncroton_Model_AXMLEntry { - public const LASTVERB_UNKNOWN = 0; - public const LASTVERB_REPLYTOSENDER = 1; - public const LASTVERB_REPLYTOALL = 2; - public const LASTVERB_FORWARD = 3; - + const LASTVERB_UNKNOWN = 0; + const LASTVERB_REPLYTOSENDER = 1; + const LASTVERB_REPLYTOALL = 2; + const LASTVERB_FORWARD = 3; + protected $_xmlBaseElement = 'ApplicationData'; - - protected $_properties = - 'AirSyncBase' => - 'attachments' => 'type' => 'container', 'childElement' => 'attachment', 'class' => 'Syncroton_Model_EmailAttachment', - 'contentType' => 'type' => 'string', - 'body' => 'type' => 'container', 'class' => 'Syncroton_Model_EmailBody', - 'nativeBodyType' => 'type' => 'number', - , - 'Email' => - 'busyStatus' => 'type' => 'number', - 'categories' => 'type' => 'container', 'childElement' => 'category', 'supportedSince' => '14.0', - 'cc' => 'type' => 'string', - 'completeTime' => 'type' => 'datetime', - 'contentClass' => 'type' => 'string', - 'dateReceived' => 'type' => 'datetime', - 'disallowNewTimeProposal' => 'type' => 'number', - 'displayTo' => 'type' => 'string', - 'dTStamp' => 'type' => 'datetime', - 'endTime' => 'type' => 'datetime', - 'flag' => 'type' => 'container', 'class' => 'Syncroton_Model_EmailFlag', - 'from' => 'type' => 'string', - 'globalObjId' => 'type' => 'string', - 'importance' => 'type' => 'number', - 'instanceType' => 'type' => 'number', - 'internetCPID' => 'type' => 'string', - 'location' => 'type' => 'string', - 'meetingRequest' => 'type' => 'container', 'class' => 'Syncroton_Model_EmailMeetingRequest', - 'messageClass' => 'type' => 'string', - 'organizer' => 'type' => 'string', - 'read' => 'type' => 'number', - 'recurrences' => 'type' => 'container', - 'reminder' => 'type' => 'number', - 'replyTo' => 'type' => 'string', - 'responseRequested' => 'type' => 'number', - 'sensitivity' => 'type' => 'number', - 'startTime' => 'type' => 'datetime', - 'status' => 'type' => 'number', - 'subject' => 'type' => 'string', - 'threadTopic' => 'type' => 'string', - 'timeZone' => 'type' => 'timezone', - 'to' => 'type' => 'string', - , - 'Email2' => - 'accountId' => 'type' => 'string', 'supportedSince' => '14.1', - 'conversationId' => 'type' => 'byteArray', 'supportedSince' => '14.0', - 'conversationIndex' => 'type' => 'byteArray', 'supportedSince' => '14.0', - 'lastVerbExecuted' => 'type' => 'number', 'supportedSince' => '14.0', - 'lastVerbExecutionTime' => 'type' => 'datetime', 'supportedSince' => '14.0', - 'meetingMessageType' => 'type' => 'number', 'supportedSince' => '14.1', - 'receivedAsBcc' => 'type' => 'number', 'supportedSince' => '14.0', - 'sender' => 'type' => 'string', 'supportedSince' => '14.0', - 'umCallerID' => 'type' => 'string', 'supportedSince' => '14.0', - 'umUserNotes' => 'type' => 'string', 'supportedSince' => '14.0', - , - ; + + protected $_properties = array( + 'AirSyncBase' => array( + 'attachments' => array('type' => 'container', 'childElement' => 'attachment', 'class' => 'Syncroton_Model_EmailAttachment'), + 'contentType' => array('type' => 'string'), + 'body' => array('type' => 'container', 'class' => 'Syncroton_Model_EmailBody'), + 'nativeBodyType' => array('type' => 'number'), + ), + 'Email' => array( + 'busyStatus' => array('type' => 'number'), + 'categories' => array('type' => 'container', 'childElement' => 'category', 'supportedSince' => '14.0'), + 'cc' => array('type' => 'string'), + 'completeTime' => array('type' => 'datetime'), + 'contentClass' => array('type' => 'string'), + 'dateReceived' => array('type' => 'datetime'), + 'disallowNewTimeProposal' => array('type' => 'number'), + 'displayTo' => array('type' => 'string'), + 'dTStamp' => array('type' => 'datetime'), + 'endTime' => array('type' => 'datetime'), + 'flag' => array('type' => 'container', 'class' => 'Syncroton_Model_EmailFlag'), + 'from' => array('type' => 'string'), + 'globalObjId' => array('type' => 'string'), + 'importance' => array('type' => 'number'), + 'instanceType' => array('type' => 'number'), + 'internetCPID' => array('type' => 'string'), + 'location' => array('type' => 'string'), + 'meetingRequest' => array('type' => 'container', 'class' => 'Syncroton_Model_EmailMeetingRequest'), + 'messageClass' => array('type' => 'string'), + 'organizer' => array('type' => 'string'), + 'read' => array('type' => 'number'), + 'recurrences' => array('type' => 'container'), + 'reminder' => array('type' => 'number'), + 'replyTo' => array('type' => 'string'), + 'responseRequested' => array('type' => 'number'), + 'sensitivity' => array('type' => 'number'), + 'startTime' => array('type' => 'datetime'), + 'status' => array('type' => 'number'), + 'subject' => array('type' => 'string'), + 'threadTopic' => array('type' => 'string'), + 'timeZone' => array('type' => 'timezone'), + 'to' => array('type' => 'string'), + ), + 'Email2' => array( + 'accountId' => array('type' => 'string', 'supportedSince' => '14.1'), + 'conversationId' => array('type' => 'byteArray', 'supportedSince' => '14.0'), + 'conversationIndex' => array('type' => 'byteArray', 'supportedSince' => '14.0'), + 'lastVerbExecuted' => array('type' => 'number', 'supportedSince' => '14.0'), + 'lastVerbExecutionTime' => array('type' => 'datetime', 'supportedSince' => '14.0'), + 'meetingMessageType' => array('type' => 'number', 'supportedSince' => '14.1'), + 'receivedAsBcc' => array('type' => 'number', 'supportedSince' => '14.0'), + 'sender' => array('type' => 'string', 'supportedSince' => '14.0'), + 'umCallerID' => array('type' => 'string', 'supportedSince' => '14.0'), + 'umUserNotes' => array('type' => 'string', 'supportedSince' => '14.0'), + ), + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/EmailAttachment.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/EmailAttachment.php
Changed
@@ -14,30 +14,30 @@ * * @package Syncroton * @subpackage Model - * @property string $class - * @property string $collectionId - * @property bool $deletesAsMoves - * @property bool $getChanges - * @property string $syncKey - * @property int $windowSize + * @property string class + * @property string collectionId + * @property bool deletesAsMoves + * @property bool getChanges + * @property string syncKey + * @property int windowSize */ class Syncroton_Model_EmailAttachment extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'Attachment'; - - protected $_properties = - 'AirSyncBase' => - 'contentId' => 'type' => 'string', - 'contentLocation' => 'type' => 'string', - 'displayName' => 'type' => 'string', - 'estimatedDataSize' => 'type' => 'string', - 'fileReference' => 'type' => 'string', - 'isInline' => 'type' => 'number', - 'method' => 'type' => 'string', - , - 'Email2' => - 'umAttDuration' => 'type' => 'number', 'supportedSince' => '14.0', - 'umAttOrder' => 'type' => 'number', 'supportedSince' => '14.0', - , - ; -} + + protected $_properties = array( + 'AirSyncBase' => array( + 'contentId' => array('type' => 'string'), + 'contentLocation' => array('type' => 'string'), + 'displayName' => array('type' => 'string'), + 'estimatedDataSize' => array('type' => 'string'), + 'fileReference' => array('type' => 'string'), + 'isInline' => array('type' => 'number'), + 'method' => array('type' => 'string'), + ), + 'Email2' => array( + 'umAttDuration' => array('type' => 'number', 'supportedSince' => '14.0'), + 'umAttOrder' => array('type' => 'number', 'supportedSince' => '14.0'), + ), + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/EmailBody.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/EmailBody.php
Changed
@@ -14,31 +14,31 @@ * * @package Syncroton * @subpackage Model - * @property int $estimatedDataSize - * @property string $data - * @property string $part - * @property string $preview - * @property bool $truncated - * @property string $type + * @property int EstimatedDataSize + * @property string Data + * @property string Part + * @property string Preview + * @property bool Truncated + * @property string Type */ class Syncroton_Model_EmailBody extends Syncroton_Model_AXMLEntry { - public const TYPE_PLAINTEXT = 1; - public const TYPE_HTML = 2; - public const TYPE_RTF = 3; - public const TYPE_MIME = 4; - + const TYPE_PLAINTEXT = 1; + const TYPE_HTML = 2; + const TYPE_RTF = 3; + const TYPE_MIME = 4; + protected $_xmlBaseElement = 'Body'; - - protected $_properties = - 'AirSyncBase' => - 'type' => 'type' => 'string', - 'estimatedDataSize' => 'type' => 'string', - 'data' => 'type' => 'string', - 'truncated' => 'type' => 'number', - 'part' => 'type' => 'number', - 'preview' => 'type' => 'string', 'supportedSince' => '14.0', - , - ; -} + + protected $_properties = array( + 'AirSyncBase' => array( + 'type' => array('type' => 'string'), + 'estimatedDataSize' => array('type' => 'string'), + 'data' => array('type' => 'string'), + 'truncated' => array('type' => 'number'), + 'part' => array('type' => 'number'), + 'preview' => array('type' => 'string', 'supportedSince' => '14.0'), + ), + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/EmailFlag.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/EmailFlag.php
Changed
@@ -16,45 +16,45 @@ * * @package Syncroton * @subpackage Model - * @property DateTime $completeTime - * @property DateTime $dateCompleted - * @property DateTime $dueDate - * @property string $flagType - * @property DateTime $ordinalDate - * @property int $reminderSet - * @property DateTime $reminderTime - * @property DateTime $startDate - * @property string $status - * @property string $subject - * @property string $subOrdinalDate - * @property DateTime $utcDueDate - * @property DateTime $utcStartDate + * @property DateTime CompleteTime + * @property DateTime DateCompleted + * @property DateTime DueDate + * @property string FlagType + * @property DateTime OrdinalDate + * @property int ReminderSet + * @property DateTime ReminderTime + * @property DateTime StartDate + * @property string Status + * @property string Subject + * @property string SubOrdinalDate + * @property DateTime UtcDueDate + * @property DateTime UtcStartDate */ class Syncroton_Model_EmailFlag extends Syncroton_Model_AXMLEntry { - public const STATUS_CLEARED = 0; - public const STATUS_COMPLETE = 1; - public const STATUS_ACTIVE = 2; + const STATUS_CLEARED = 0; + const STATUS_COMPLETE = 1; + const STATUS_ACTIVE = 2; protected $_xmlBaseElement = 'Flag'; - protected $_properties = - 'Email' => - 'completeTime' => 'type' => 'datetime', - 'flagType' => 'type' => 'string', - 'status' => 'type' => 'number', - , - 'Tasks' => - 'dateCompleted' => 'type' => 'datetime', - 'dueDate' => 'type' => 'datetime', - 'ordinalDate' => 'type' => 'datetime', - 'reminderSet' => 'type' => 'number', - 'reminderTime' => 'type' => 'datetime', - 'startDate' => 'type' => 'datetime', - 'subject' => 'type' => 'string', - 'subOrdinalDate' => 'type' => 'string', - 'utcStartDate' => 'type' => 'datetime', - 'utcDueDate' => 'type' => 'datetime', - , - ; + protected $_properties = array( + 'Email' => array( + 'completeTime' => array('type' => 'datetime'), + 'flagType' => array('type' => 'string'), + 'status' => array('type' => 'number'), + ), + 'Tasks' => array( + 'dateCompleted' => array('type' => 'datetime'), + 'dueDate' => array('type' => 'datetime'), + 'ordinalDate' => array('type' => 'datetime'), + 'reminderSet' => array('type' => 'number'), + 'reminderTime' => array('type' => 'datetime'), + 'startDate' => array('type' => 'datetime'), + 'subject' => array('type' => 'string'), + 'subOrdinalDate' => array('type' => 'string'), + 'utcStartDate' => array('type' => 'datetime'), + 'utcDueDate' => array('type' => 'datetime'), + ), + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/EmailMeetingRequest.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/EmailMeetingRequest.php
Changed
@@ -14,83 +14,85 @@ * * @package Syncroton * @subpackage Model - * @property bool $allDayEvent - * @property int $busyStatus - * @property int $disallowNewTimeProposal - * @property DateTime $dtStamp - * @property DateTime $endTime - * @property string $globalObjId - * @property int $instanceType - * @property int $meetingMessageType - * @property string $organizer - * @property string $recurrenceId - * @property array $recurrences - * @property int $reminder - * @property int $responseRequested - * @property int $sensitivity - * @property DateTime $startTime - * @property string $timezone + * @property bool AllDayEvent + * @property int BusyStatus + * @property int DisallowNewTimeProposal + * @property DateTime DtStamp + * @property DateTime EndTime + * @property string GlobalObjId + * @property int InstanceType + * @property int MeetingMessageType + * @property string Organizer + * @property string RecurrenceId + * @property array Recurrences + * @property int Reminder + * @property int ResponseRequested + * @property int Sensitivity + * @property DateTime StartTime + * @property string Timezone */ class Syncroton_Model_EmailMeetingRequest extends Syncroton_Model_AXMLEntry { /** * busy status constants */ - public const BUSY_STATUS_FREE = 0; - public const BUSY_STATUS_TENATTIVE = 1; - public const BUSY_STATUS_BUSY = 2; - public const BUSY_STATUS_OUT = 3; + const BUSY_STATUS_FREE = 0; + const BUSY_STATUS_TENATTIVE = 1; + const BUSY_STATUS_BUSY = 2; + const BUSY_STATUS_OUT = 3; /** * sensitivity constants */ - public const SENSITIVITY_NORMAL = 0; - public const SENSITIVITY_PERSONAL = 1; - public const SENSITIVITY_PRIVATE = 2; - public const SENSITIVITY_CONFIDENTIAL = 3; + const SENSITIVITY_NORMAL = 0; + const SENSITIVITY_PERSONAL = 1; + const SENSITIVITY_PRIVATE = 2; + const SENSITIVITY_CONFIDENTIAL = 3; /** * instanceType constants */ - public const TYPE_NORMAL = 0; - public const TYPE_RECURRING_MASTER = 1; - public const TYPE_RECURRING_SINGLE = 2; - public const TYPE_RECURRING_EXCEPTION = 3; + const TYPE_NORMAL = 0; + const TYPE_RECURRING_MASTER = 1; + const TYPE_RECURRING_SINGLE = 2; + const TYPE_RECURRING_EXCEPTION = 3; /** * messageType constants */ - public const MESSAGE_TYPE_NORMAL = 0; - public const MESSAGE_TYPE_REQUEST = 1; - public const MESSAGE_TYPE_FULL_UPDATE = 2; - public const MESSAGE_TYPE_INFO_UPDATE = 3; - public const MESSAGE_TYPE_OUTDATED = 4; - public const MESSAGE_TYPE_COPY = 5; - public const MESSAGE_TYPE_DELEGATED = 6; + const MESSAGE_TYPE_NORMAL = 0; + const MESSAGE_TYPE_REQUEST = 1; + const MESSAGE_TYPE_FULL_UPDATE = 2; + const MESSAGE_TYPE_INFO_UPDATE = 3; + const MESSAGE_TYPE_OUTDATED = 4; + const MESSAGE_TYPE_COPY = 5; + const MESSAGE_TYPE_DELEGATED = 6; + + protected $_dateTimeFormat = "Ymd\THis\Z"; protected $_xmlBaseElement = 'MeetingRequest'; - protected $_properties = - 'Email' => - 'allDayEvent' => 'type' => 'number', - 'busyStatus' => 'type' => 'number', - 'disallowNewTimeProposal' => 'type' => 'number', - 'dtStamp' => 'type' => 'datetime', - 'endTime' => 'type' => 'datetime', - 'globalObjId' => 'type' => 'string', - 'instanceType' => 'type' => 'number', - 'location' => 'type' => 'string', - 'organizer' => 'type' => 'string', //e-mail address - 'recurrenceId' => 'type' => 'datetime', - 'recurrences' => 'type' => 'container', - 'reminder' => 'type' => 'number', - 'responseRequested' => 'type' => 'number', - 'sensitivity' => 'type' => 'number', - 'startTime' => 'type' => 'datetime', - 'timeZone' => 'type' => 'timezone', - , - 'Email2' => - 'meetingMessageType' => 'type' => 'number', - , - ; + protected $_properties = array( + 'Email' => array( + 'allDayEvent' => array('type' => 'number'), + 'busyStatus' => array('type' => 'number'), + 'disallowNewTimeProposal' => array('type' => 'number'), + 'dtStamp' => array('type' => 'datetime'), + 'endTime' => array('type' => 'datetime'), + 'globalObjId' => array('type' => 'string'), + 'instanceType' => array('type' => 'datetime'), + 'location' => array('type' => 'string'), + 'organizer' => array('type' => 'string'), //e-mail address + 'recurrenceId' => array('type' => 'datetime'), + 'recurrences' => array('type' => 'container'), + 'reminder' => array('type' => 'number'), + 'responseRequested' => array('type' => 'number'), + 'sensitivity' => array('type' => 'number'), + 'startTime' => array('type' => 'datetime'), + 'timeZone' => array('type' => 'timezone'), + ), + 'Email2' => array( + 'meetingMessageType' => array('type' => 'number'), + ), + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/EmailRecurrence.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/EmailRecurrence.php
Changed
@@ -14,18 +14,19 @@ * * @package Syncroton * @subpackage Model - * @property int $calendarType - * @property int $dayOfMonth - * @property int $dayOfWeek - * @property int $firstDayOfWeek - * @property int $interval - * @property int $isLeapMonth - * @property int $monthOfYear - * @property int $occurrences - * @property int $type - * @property DateTime $until - * @property int $weekOfMonth + * @property int CalendarType + * @property int DayOfMonth + * @property int DayOfWeek + * @property int FirstDayOfWeek + * @property int Interval + * @property int IsLeapMonth + * @property int MonthOfYear + * @property int Occurrences + * @property int Type + * @property DateTime Until + * @property int WeekOfMonth */ + class Syncroton_Model_EmailRecurrence extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'Recurrence'; @@ -33,41 +34,41 @@ /** * recur types */ - public const TYPE_DAILY = 0; // Recurs daily - public const TYPE_WEEKLY = 1; // Recurs weekly - public const TYPE_MONTHLY = 3; // Recurs monthly - public const TYPE_MONTHLY_DAYN = 2; // Recurs monthly on the nth day - public const TYPE_YEARLY = 5; // Recurs yearly on the nth day of the nth month each year - public const TYPE_YEARLY_DAYN = 6; // Recurs yearly on the nth day of the week of the nth month + const TYPE_DAILY = 0; // Recurs daily + const TYPE_WEEKLY = 1; // Recurs weekly + const TYPE_MONTHLY = 3; // Recurs monthly + const TYPE_MONTHLY_DAYN = 2; // Recurs monthly on the nth day + const TYPE_YEARLY = 5; // Recurs yearly on the nth day of the nth month each year + const TYPE_YEARLY_DAYN = 6; // Recurs yearly on the nth day of the week of the nth month /** * day of week constants */ - public const RECUR_DOW_SUNDAY = 1; - public const RECUR_DOW_MONDAY = 2; - public const RECUR_DOW_TUESDAY = 4; - public const RECUR_DOW_WEDNESDAY = 8; - public const RECUR_DOW_THURSDAY = 16; - public const RECUR_DOW_FRIDAY = 32; - public const RECUR_DOW_SATURDAY = 64; + const RECUR_DOW_SUNDAY = 1; + const RECUR_DOW_MONDAY = 2; + const RECUR_DOW_TUESDAY = 4; + const RECUR_DOW_WEDNESDAY = 8; + const RECUR_DOW_THURSDAY = 16; + const RECUR_DOW_FRIDAY = 32; + const RECUR_DOW_SATURDAY = 64; protected $_dateTimeFormat = "Ymd\THis\Z"; - protected $_properties = - 'Email' => - 'dayOfMonth' => 'type' => 'number', - 'dayOfWeek' => 'type' => 'number', - 'interval' => 'type' => 'number', // 1 or 2 - 'monthOfYear' => 'type' => 'number', - 'occurrences' => 'type' => 'number', - 'type' => 'type' => 'number', - 'until' => 'type' => 'datetime', - 'weekOfMonth' => 'type' => 'number', - , - 'Email2' => - 'calendarType' => 'type' => 'number', - 'firstDayOfWeek' => 'type' => 'number', - 'isLeapMonth' => 'type' => 'number', - , - ; + protected $_properties = array( + 'Email' => array( + 'dayOfMonth' => array('type' => 'number'), + 'dayOfWeek' => array('type' => 'number'), + 'interval' => array('type' => 'number'), // 1 or 2 + 'monthOfYear' => array('type' => 'number'), + 'occurrences' => array('type' => 'number'), + 'type' => array('type' => 'number'), + 'until' => array('type' => 'datetime'), + 'weekOfMonth' => array('type' => 'number'), + ), + 'Email2' => array( + 'calendarType' => array('type' => 'number'), + 'firstDayOfWeek' => array('type' => 'number'), + 'isLeapMonth' => array('type' => 'number'), + ) + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Event.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Event.php
Changed
@@ -14,62 +14,59 @@ * * @package Syncroton * @subpackage Model - * - * @property bool $allDayEvent - * @property string $class - * @property string $collectionId - * @property bool $deletesAsMoves - * @property DateTime $endTime - * @property bool $getChanges - * @property DateTime $startTime - * @property string $syncKey - * @property int $windowSize + * @property string class + * @property string collectionId + * @property bool deletesAsMoves + * @property bool getChanges + * @property string syncKey + * @property int windowSize */ + class Syncroton_Model_Event extends Syncroton_Model_AXMLEntry { - /** - * busy status constants - */ - public const BUSY_STATUS_FREE = 0; - public const BUSY_STATUS_TENATTIVE = 1; - public const BUSY_STATUS_BUSY = 2; - - protected $_dateTimeFormat = "Ymd\THis\Z"; - + /** + * busy status constants + */ + const BUSY_STATUS_FREE = 0; + const BUSY_STATUS_TENATTIVE = 1; + const BUSY_STATUS_BUSY = 2; + + protected $_dateTimeFormat = "Ymd\THis\Z"; + protected $_xmlBaseElement = 'ApplicationData'; - - protected $_properties = - 'AirSyncBase' => - 'body' => 'type' => 'container', 'class' => 'Syncroton_Model_EmailBody', - , - 'Calendar' => - 'allDayEvent' => 'type' => 'number', - 'appointmentReplyTime' => 'type' => 'datetime', - 'attendees' => 'type' => 'container', 'childElement' => 'attendee', 'class' => 'Syncroton_Model_EventAttendee', - 'busyStatus' => 'type' => 'number', - 'categories' => 'type' => 'container', 'childElement' => 'category', - 'disallowNewTimeProposal' => 'type' => 'number', - 'dtStamp' => 'type' => 'datetime', - 'endTime' => 'type' => 'datetime', - 'exceptions' => 'type' => 'container', 'childElement' => 'exception', 'class' => 'Syncroton_Model_EventException', - 'location' => 'type' => 'string', - 'meetingStatus' => 'type' => 'number', - 'onlineMeetingConfLink' => 'type' => 'string', - 'onlineMeetingExternalLink' => 'type' => 'string', - 'organizerEmail' => 'type' => 'string', - 'organizerName' => 'type' => 'string', - 'recurrence' => 'type' => 'container', - 'reminder' => 'type' => 'number', - 'responseRequested' => 'type' => 'number', - 'responseType' => 'type' => 'number', - 'sensitivity' => 'type' => 'number', - 'startTime' => 'type' => 'datetime', - 'subject' => 'type' => 'string', - 'timezone' => 'type' => 'timezone', - 'uID' => 'type' => 'string', - , - ; - + + protected $_properties = array( + 'AirSyncBase' => array( + 'body' => array('type' => 'container', 'class' => 'Syncroton_Model_EmailBody') + ), + 'Calendar' => array( + 'allDayEvent' => array('type' => 'number'), + 'appointmentReplyTime' => array('type' => 'datetime'), + 'attendees' => array('type' => 'container', 'childElement' => 'attendee', 'class' => 'Syncroton_Model_EventAttendee'), + 'busyStatus' => array('type' => 'number'), + 'categories' => array('type' => 'container', 'childElement' => 'category'), + 'disallowNewTimeProposal' => array('type' => 'number'), + 'dtStamp' => array('type' => 'datetime'), + 'endTime' => array('type' => 'datetime'), + 'exceptions' => array('type' => 'container', 'childElement' => 'exception', 'class' => 'Syncroton_Model_EventException'), + 'location' => array('type' => 'string'), + 'meetingStatus' => array('type' => 'number'), + 'onlineMeetingConfLink' => array('type' => 'string'), + 'onlineMeetingExternalLink' => array('type' => 'string'), + 'organizerEmail' => array('type' => 'string'), + 'organizerName' => array('type' => 'string'), + 'recurrence' => array('type' => 'container'), + 'reminder' => array('type' => 'number'), + 'responseRequested' => array('type' => 'number'), + 'responseType' => array('type' => 'number'), + 'sensitivity' => array('type' => 'number'), + 'startTime' => array('type' => 'datetime'), + 'subject' => array('type' => 'string'), + 'timezone' => array('type' => 'timezone'), + 'uID' => array('type' => 'string'), + ) + ); + /** * (non-PHPdoc) * @see Syncroton_Model_IEntry::appendXML() @@ -80,7 +77,7 @@ parent::appendXML($domParrent, $device); $exceptionElements = $domParrent->getElementsByTagName('Exception'); - $parentFields = 'AllDayEvent'/*, 'Attendees'*/, 'Body', 'BusyStatus'/*, 'Categories'*/, 'DtStamp', 'EndTime', 'Location', 'MeetingStatus', 'Reminder', 'ResponseType', 'Sensitivity', 'StartTime', 'Subject'; + $parentFields = array('AllDayEvent'/*, 'Attendees'*/, 'Body', 'BusyStatus'/*, 'Categories'*/, 'DtStamp', 'EndTime', 'Location', 'MeetingStatus', 'Reminder', 'ResponseType', 'Sensitivity', 'StartTime', 'Subject'); if ($exceptionElements->length > 0) { $mainEventElement = $exceptionElements->item(0)->parentNode->parentNode; @@ -100,31 +97,31 @@ } } } - + /** - * some elements of an exception can be left out, if they have the same value + * some elements of an exception can be left out, if they have the same value * like the main event - * + * * this function copies these elements to the exception for backends which need * this elements in the exceptions too. Tine 2.0 needs this for example. */ public function copyFieldsFromParent() { - if (isset($this->_elements'exceptions') && is_array($this->_elements'exceptions')) { - foreach ($this->_elements'exceptions' as $exception) { - // no need to update deleted exceptions - if ($exception->deleted == 1) { - continue; - } - - $parentFields = 'allDayEvent', 'attendees', 'body', 'busyStatus', 'categories', 'dtStamp', 'endTime', 'location', 'meetingStatus', 'reminder', 'responseType', 'sensitivity', 'startTime', 'subject'; - - foreach ($parentFields as $field) { - if (!isset($exception->$field) && isset($this->_elements$field)) { - $exception->$field = $this->_elements$field; - } - } - } - } + if (isset($this->_elements'exceptions') && is_array($this->_elements'exceptions')) { + foreach ($this->_elements'exceptions' as $exception) { + // no need to update deleted exceptions + if ($exception->deleted == 1) { + continue; + } + + $parentFields = array('allDayEvent', 'attendees', 'body', 'busyStatus', 'categories', 'dtStamp', 'endTime', 'location', 'meetingStatus', 'reminder', 'responseType', 'sensitivity', 'startTime', 'subject'); + + foreach ($parentFields as $field) { + if (!isset($exception->$field) && isset($this->_elements$field)) { + $exception->$field = $this->_elements$field; + } + } + } + } } -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/EventAttendee.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/EventAttendee.php
Changed
@@ -14,39 +14,40 @@ * * @package Syncroton * @subpackage Model - * @property string $class - * @property string $collectionId - * @property bool $deletesAsMoves - * @property bool $getChanges - * @property string $syncKey - * @property int $windowSize + * @property string class + * @property string collectionId + * @property bool deletesAsMoves + * @property bool getChanges + * @property string syncKey + * @property int windowSize */ + class Syncroton_Model_EventAttendee extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'Attendee'; - - /** - * attendee status - */ - public const ATTENDEE_STATUS_UNKNOWN = 0; - public const ATTENDEE_STATUS_TENTATIVE = 2; - public const ATTENDEE_STATUS_ACCEPTED = 3; - public const ATTENDEE_STATUS_DECLINED = 4; - public const ATTENDEE_STATUS_NOTRESPONDED = 5; - - /** - * attendee types - */ - public const ATTENDEE_TYPE_REQUIRED = 1; - public const ATTENDEE_TYPE_OPTIONAL = 2; - public const ATTENDEE_TYPE_RESOURCE = 3; - - protected $_properties = - 'Calendar' => - 'attendeeStatus' => 'type' => 'number', - 'attendeeType' => 'type' => 'number', - 'email' => 'type' => 'string', - 'name' => 'type' => 'string', - , - ; -} + + /** + * attendee status + */ + const ATTENDEE_STATUS_UNKNOWN = 0; + const ATTENDEE_STATUS_TENTATIVE = 2; + const ATTENDEE_STATUS_ACCEPTED = 3; + const ATTENDEE_STATUS_DECLINED = 4; + const ATTENDEE_STATUS_NOTRESPONDED = 5; + + /** + * attendee types + */ + const ATTENDEE_TYPE_REQUIRED = 1; + const ATTENDEE_TYPE_OPTIONAL = 2; + const ATTENDEE_TYPE_RESOURCE = 3; + + protected $_properties = array( + 'Calendar' => array( + 'attendeeStatus' => array('type' => 'number'), + 'attendeeType' => array('type' => 'number'), + 'email' => array('type' => 'string'), + 'name' => array('type' => 'string'), + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/EventException.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/EventException.php
Changed
@@ -14,44 +14,41 @@ * * @package Syncroton * @subpackage Model - * - * @property bool $allDayEvent - * @property string $class - * @property string $collectionId - * @property bool $deletesAsMoves - * @property DateTime $endTime - * @property bool $getChanges - * @property DateTime $startTime - * @property string $syncKey - * @property int $windowSize + * @property string class + * @property string collectionId + * @property bool deletesAsMoves + * @property bool getChanges + * @property string syncKey + * @property int windowSize */ + class Syncroton_Model_EventException extends Syncroton_Model_AXMLEntry -{ +{ protected $_xmlBaseElement = 'Exception'; - + protected $_dateTimeFormat = "Ymd\THis\Z"; - - protected $_properties = - 'AirSyncBase' => - 'body' => 'type' => 'container', 'class' => 'Syncroton_Model_EmailBody', - , - 'Calendar' => - 'allDayEvent' => 'type' => 'number', - 'appointmentReplyTime' => 'type' => 'datetime', - 'attendees' => 'type' => 'container', 'childElement' => 'attendee', 'class' => 'Syncroton_Model_EventAttendee', - 'busyStatus' => 'type' => 'number', - 'categories' => 'type' => 'container', 'childElement' => 'category', - 'deleted' => 'type' => 'number', - 'dtStamp' => 'type' => 'datetime', - 'endTime' => 'type' => 'datetime', - 'exceptionStartTime' => 'type' => 'datetime', - 'location' => 'type' => 'string', - 'meetingStatus' => 'type' => 'number', - 'reminder' => 'type' => 'number', - 'responseType' => 'type' => 'number', - 'sensitivity' => 'type' => 'number', - 'startTime' => 'type' => 'datetime', - 'subject' => 'type' => 'string', - , - ; -} + + protected $_properties = array( + 'AirSyncBase' => array( + 'body' => array('type' => 'container', 'class' => 'Syncroton_Model_EmailBody') + ), + 'Calendar' => array( + 'allDayEvent' => array('type' => 'number'), + 'appointmentReplyTime' => array('type' => 'datetime'), + 'attendees' => array('type' => 'container', 'childElement' => 'attendee', 'class' => 'Syncroton_Model_EventAttendee'), + 'busyStatus' => array('type' => 'number'), + 'categories' => array('type' => 'container', 'childElement' => 'category'), + 'deleted' => array('type' => 'number'), + 'dtStamp' => array('type' => 'datetime'), + 'endTime' => array('type' => 'datetime'), + 'exceptionStartTime' => array('type' => 'datetime'), + 'location' => array('type' => 'string'), + 'meetingStatus' => array('type' => 'number'), + 'reminder' => array('type' => 'number'), + 'responseType' => array('type' => 'number'), + 'sensitivity' => array('type' => 'number'), + 'startTime' => array('type' => 'datetime'), + 'subject' => array('type' => 'string'), + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/EventRecurrence.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/EventRecurrence.php
Changed
@@ -14,58 +14,59 @@ * * @package Syncroton * @subpackage Model - * @property int $calendarType - * @property int $dayOfMonth - * @property int $dayOfWeek - * @property int $firstDayOfWeek - * @property int $interval - * @property int $isLeapMonth - * @property int $monthOfYear - * @property int $occurrences - * @property int $type - * @property DateTime $until - * @property int $weekOfMonth + * @property int CalendarType + * @property int DayOfMonth + * @property int DayOfWeek + * @property int FirstDayOfWeek + * @property int Interval + * @property int IsLeapMonth + * @property int MonthOfYear + * @property int Occurrences + * @property int Type + * @property DateTime Until + * @property int WeekOfMonth */ + class Syncroton_Model_EventRecurrence extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'Recurrence'; - - /** - * recur types - */ - public const TYPE_DAILY = 0; // Recurs daily. - public const TYPE_WEEKLY = 1; // Recurs weekly - public const TYPE_MONTHLY = 2; // Recurs monthly - public const TYPE_MONTHLY_DAYN = 3; // Recurs monthly on the nth day - public const TYPE_YEARLY = 5; // Recurs yearly - public const TYPE_YEARLY_DAYN = 6; // Recurs yearly on the nth day - - /** - * day of week constants - */ - public const RECUR_DOW_SUNDAY = 1; - public const RECUR_DOW_MONDAY = 2; - public const RECUR_DOW_TUESDAY = 4; - public const RECUR_DOW_WEDNESDAY = 8; - public const RECUR_DOW_THURSDAY = 16; - public const RECUR_DOW_FRIDAY = 32; - public const RECUR_DOW_SATURDAY = 64; - + + /** + * recur types + */ + const TYPE_DAILY = 0; // Recurs daily. + const TYPE_WEEKLY = 1; // Recurs weekly + const TYPE_MONTHLY = 2; // Recurs monthly + const TYPE_MONTHLY_DAYN = 3; // Recurs monthly on the nth day + const TYPE_YEARLY = 5; // Recurs yearly + const TYPE_YEARLY_DAYN = 6; // Recurs yearly on the nth day + + /** + * day of week constants + */ + const RECUR_DOW_SUNDAY = 1; + const RECUR_DOW_MONDAY = 2; + const RECUR_DOW_TUESDAY = 4; + const RECUR_DOW_WEDNESDAY = 8; + const RECUR_DOW_THURSDAY = 16; + const RECUR_DOW_FRIDAY = 32; + const RECUR_DOW_SATURDAY = 64; + protected $_dateTimeFormat = "Ymd\THis\Z"; - - protected $_properties = - 'Calendar' => - 'calendarType' => 'type' => 'number', - 'dayOfMonth' => 'type' => 'number', - 'dayOfWeek' => 'type' => 'number', - 'firstDayOfWeek' => 'type' => 'number', - 'interval' => 'type' => 'number', - 'isLeapMonth' => 'type' => 'number', - 'monthOfYear' => 'type' => 'number', - 'occurrences' => 'type' => 'number', - 'type' => 'type' => 'number', - 'until' => 'type' => 'datetime', - 'weekOfMonth' => 'type' => 'number', - , - ; -} + + protected $_properties = array( + 'Calendar' => array( + 'calendarType' => array('type' => 'number'), + 'dayOfMonth' => array('type' => 'number'), + 'dayOfWeek' => array('type' => 'number'), + 'firstDayOfWeek' => array('type' => 'number'), + 'interval' => array('type' => 'number'), + 'isLeapMonth' => array('type' => 'number'), + 'monthOfYear' => array('type' => 'number'), + 'occurrences' => array('type' => 'number'), + 'type' => array('type' => 'number'), + 'until' => array('type' => 'datetime'), + 'weekOfMonth' => array('type' => 'number'), + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/FileReference.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/FileReference.php
Changed
@@ -14,32 +14,33 @@ * * @package Syncroton * @subpackage Model - * @property string $contentType - * @property string $data - * @property int $part + * @property string ContentType + * @property string Data */ + class Syncroton_Model_FileReference extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'ApplicationData'; - - protected $_properties = - 'AirSyncBase' => - 'contentType' => 'type' => 'string', - , - 'ItemOperations' => - 'data' => 'type' => 'string', 'encoding' => 'base64', - 'part' => 'type' => 'number', - , - ; - + + protected $_properties = array( + 'AirSyncBase' => array( + 'contentType' => array('type' => 'string'), + ), + 'ItemOperations' => array( + 'data' => array('type' => 'string', 'encoding' => 'base64'), + 'part' => array('type' => 'number') + ) + ); + /** - * - * @param SimpleXMLElement $properties + * + * @param SimpleXMLElement $xmlCollection * @throws InvalidArgumentException */ public function setFromSimpleXMLElement(SimpleXMLElement $properties) { - // do nothing + //do nothing + return; } -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Folder.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Folder.php
Changed
@@ -18,24 +18,22 @@ */ class Syncroton_Model_Folder extends Syncroton_Model_AXMLEntry implements Syncroton_Model_IFolder { - protected $_xmlBaseElement = 'FolderUpdate', 'FolderCreate'; - - protected $_properties = - 'FolderHierarchy' => - 'parentId' => 'type' => 'string', - 'serverId' => 'type' => 'string', - 'displayName' => 'type' => 'string', - 'type' => 'type' => 'number', - , - 'Internal' => - 'id' => 'type' => 'string', - 'deviceId' => 'type' => 'string', - 'ownerId' => 'type' => 'string', - 'class' => 'type' => 'string', - 'creationTime' => 'type' => 'datetime', - 'creationSynckey' => 'type' => 'number', - 'lastfiltertype' => 'type' => 'number', - 'resync' => 'type' => 'number', - , - ; + protected $_xmlBaseElement = array('FolderUpdate', 'FolderCreate'); + + protected $_properties = array( + 'FolderHierarchy' => array( + 'parentId' => array('type' => 'string'), + 'serverId' => array('type' => 'string'), + 'displayName' => array('type' => 'string'), + 'type' => array('type' => 'number') + ), + 'Internal' => array( + 'id' => array('type' => 'string'), + 'deviceId' => array('type' => 'string'), + 'ownerId' => array('type' => 'string'), + 'class' => array('type' => 'string'), + 'creationTime' => array('type' => 'datetime'), + 'lastfiltertype' => array('type' => 'number') + ), + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/GAL.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/GAL.php
Changed
@@ -17,35 +17,35 @@ * @package Syncroton * @subpackage Model * - * @property string $alias - * @property string $company - * @property string $displayName - * @property string $emailAddress - * @property string $firstName - * @property string $lastName - * @property string $mobilePhone - * @property string $office - * @property string $phone - * @property string $picture - * @property string $title + * @property string Alias + * @property string Company + * @property string DisplayName + * @property string EmailAddress + * @property string FirstName + * @property string LastName + * @property string MobilePhone + * @property string Office + * @property string Phone + * @property string Picture + * @property string Title */ class Syncroton_Model_GAL extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'ApplicationData'; - protected $_properties = - 'GAL' => - 'alias' => 'type' => 'string', 'supportedSince' => '2.5', - 'company' => 'type' => 'string', 'supportedSince' => '2.5', - 'displayName' => 'type' => 'string', 'supportedSince' => '2.5', - 'emailAddress' => 'type' => 'string', 'supportedSince' => '2.5', - 'firstName' => 'type' => 'string', 'supportedSince' => '2.5', - 'lastName' => 'type' => 'string', 'supportedSince' => '2.5', - 'mobilePhone' => 'type' => 'string', 'supportedSince' => '2.5', - 'office' => 'type' => 'string', 'supportedSince' => '2.5', - 'phone' => 'type' => 'string', 'supportedSince' => '2.5', - 'picture' => 'type' => 'container', 'supportedSince' => '14.0', - 'title' => 'type' => 'string', 'supportedSince' => '2.5', - , - ; + protected $_properties = array( + 'GAL' => array( + 'alias' => array('type' => 'string', 'supportedSince' => '2.5'), + 'company' => array('type' => 'string', 'supportedSince' => '2.5'), + 'displayName' => array('type' => 'string', 'supportedSince' => '2.5'), + 'emailAddress' => array('type' => 'string', 'supportedSince' => '2.5'), + 'firstName' => array('type' => 'string', 'supportedSince' => '2.5'), + 'lastName' => array('type' => 'string', 'supportedSince' => '2.5'), + 'mobilePhone' => array('type' => 'string', 'supportedSince' => '2.5'), + 'office' => array('type' => 'string', 'supportedSince' => '2.5'), + 'phone' => array('type' => 'string', 'supportedSince' => '2.5'), + 'picture' => array('type' => 'container', 'supportedSince' => '14.0'), + 'title' => array('type' => 'string', 'supportedSince' => '2.5'), + ) + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/GALPicture.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/GALPicture.php
Changed
@@ -17,24 +17,24 @@ * @package Syncroton * @subpackage Model * - * @property string $status - * @property string $data + * @property string Status + * @property string Data */ class Syncroton_Model_GALPicture extends Syncroton_Model_AXMLEntry { - public const STATUS_SUCCESS = 1; - public const STATUS_NOPHOTO = 173; - public const STATUS_TOOLARGE = 174; - public const STATUS_OVERLIMIT = 175; + const STATUS_SUCCESS = 1; + const STATUS_NOPHOTO = 173; + const STATUS_TOOLARGE = 174; + const STATUS_OVERLIMIT = 175; protected $_xmlBaseElement = 'ApplicationData'; - protected $_properties = - 'AirSync' => - 'status' => 'type' => 'number', - , - 'GAL' => - 'data' => 'type' => 'byteArray', - , - ; + protected $_properties = array( + 'AirSync' => array( + 'status' => array('type' => 'number'), + ), + 'GAL' => array( + 'data' => array('type' => 'byteArray'), + ), + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/IContent.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/IContent.php
Changed
@@ -14,14 +14,15 @@ * * @package Syncroton * @subpackage Model - * @property string $id - * @property string $device_id - * @property string $folder_id - * @property string $contentid - * @property DateTime $creation_time - * @property string $creation_synckey - * @property string $is_deleted + * @property string id + * @property string device_id + * @property string folder_id + * @property string contentid + * @property DateTime creation_time + * @property string creation_synckey + * @property string is_deleted */ interface Syncroton_Model_IContent { } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/IDevice.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/IDevice.php
Changed
@@ -1,13 +1,12 @@ <?php - /** * Syncroton * * @package Syncroton * @subpackage Model * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 - * @copyright Copyright (c) 2012-2014 Kolab Systems AG - * @author Aleksander Machniak <machniak@kolabsys.com> + * @copyright Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de) + * @author Lars Kneschke <l.kneschke@metaways.de> */ /** @@ -15,29 +14,31 @@ * * @package Syncroton * @subpackage Model - * @property string $acsversion - * @property string $deviceid - * @property string $devicetype - * @property string $friendlyname - * @property string $id - * @property string $imei - * @property string $model - * @property string $os - * @property string $oslanguage - * @property string $ownerId - * @property string $phonenumber - * @property string $pingfolder - * @property int $pinglifetime - * @property string $policykey - * @property string $policyId - * @property int $remotewipe - * @property string $useragent - * @property string $contactsfilter_id - * @property string $calendarfilter_id - * @property string $tasksfilter_id - * @property string $emailfilter_id - * @property string $lastsynccollection - * @property DateTime $lastping + * @property string id + * @property string deviceid + * @property string devicetype + * @property string policykey + * @property string policyId + * @property string ownerId + * @property string acsversion + * @property string pingfolder + * @property string pinglifetime + * @property string remotewipe + * @property string useragent + * @property string imei + * @property string model + * @property string friendlyname + * @property string os + * @property string oslanguage + * @property string phonenumber + * @property string pinglifetime + * @property string pingfolder + * @property string contactsfilter_id + * @property string calendarfilter_id + * @property string tasksfilter_id + * @property string emailfilter_id + * @property string lastsynccollection + * @property DateTime lastping */ interface Syncroton_Model_IDevice extends Syncroton_Model_IEntry { @@ -48,3 +49,4 @@ */ public function getMajorVersion(); } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/IEntry.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/IEntry.php
Changed
@@ -1,5 +1,5 @@ <?php -/* +/** * Syncroton * * @package Syncroton @@ -10,33 +10,33 @@ */ /** - * class to handle ActiveSync entry + * class to handle ActiveSync contact * * @package Syncroton * @subpackage Model - * @property string $class - * @property string $collectionId - * @property bool $deletesAsMoves - * @property bool $getChanges - * @property string $syncKey - * @property int $windowSize + * @property string class + * @property string collectionId + * @property bool deletesAsMoves + * @property bool getChanges + * @property string syncKey + * @property int windowSize */ interface Syncroton_Model_IEntry { /** - * - * @param SimpleXMLElement|array|null $properties + * + * @param unknown_type $properties */ public function __construct($properties = null); - + /** * return true if data have got changed after initial data got loaded via constructor */ public function isDirty(); - + /** - * + * * @param array $properties - */ - public function setFromArray(array $properties); -} + */ + public function setFromArray(array $properties); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/IFolder.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/IFolder.php
Changed
@@ -14,17 +14,17 @@ * * @package Syncroton * @subpackage Model - * @property string $id - * @property string $deviceId - * @property string $class - * @property string $serverId - * @property string $parentId - * @property string $displayName - * @property DateTime $creationTime - * @property int $creationSynckey - * @property int $lastfiltertype - * @property int $type + * @property string id + * @property string deviceId + * @property string class + * @property string serverId + * @property string parentId + * @property string displayName + * @property string creationTime + * @property string lastfiltertype + * @property string type */ interface Syncroton_Model_IFolder { } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/IPolicy.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/IPolicy.php
Changed
@@ -14,18 +14,19 @@ * * @package Syncroton * @subpackage Model - * @property string $id - * @property string $deviceid - * @property string $devicetype - * @property string $policyKey - * @property string $policyId - * @property string $ownerId - * @property string $acsversion - * @property string $pingfolder - * @property string $pinglifetime - * @property string $remotewipe - * @property string $useragent + * @property string id + * @property string deviceid + * @property string devicetype + * @property string policyKey + * @property string policyId + * @property string ownerId + * @property string acsversion + * @property string pingfolder + * @property string pinglifetime + * @property string remotewipe + * @property string useragent */ interface Syncroton_Model_IPolicy { } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/ISyncState.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/ISyncState.php
Changed
@@ -14,15 +14,13 @@ * * @package Syncroton * @subpackage Model - * @property string $deviceId - * @property string $type - * @property int $counter - * @property DateTime $lastsync - * @property string $id - * @property ?array $pendingdata - * @property string $clientIdMap JSON-encoded array - * @property string $extraData JSON-encoded array + * @property string device_id + * @property string type + * @property string counter + * @property DateTime lastsync + * @property string pendingdata */ interface Syncroton_Model_ISyncState { } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/IXMLEntry.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/IXMLEntry.php
Changed
@@ -18,23 +18,23 @@ interface Syncroton_Model_IXMLEntry extends Syncroton_Model_IEntry { /** - * - * @param DOMElement $_domParent + * + * @param DOMElement $_domParrent * @param Syncroton_Model_IDevice $device */ - public function appendXML(DOMElement $_domParent, Syncroton_Model_IDevice $device); - + public function appendXML(DOMElement $_domParrent, Syncroton_Model_IDevice $device); + /** * return array of valid properties - * + * * @return array */ - public function getProperties($selectedNamespace = null); - + public function getProperties(); + /** - * - * @param SimpleXMLElement $properties + * + * @param SimpleXMLElement $xmlCollection * @throws InvalidArgumentException */ public function setFromSimpleXMLElement(SimpleXMLElement $properties); -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/MeetingResponse.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/MeetingResponse.php
Changed
@@ -14,34 +14,34 @@ * * @package Syncroton * @subpackage Model - * @property int $userResponse - * @property string $collectionId - * @property string $calendarId - * @property string $requestId - * @property string $instanceId - * @property string $longId + * @property int userResponse + * @property string collectionId + * @property string calendarId + * @property string requestId + * @property string instanceId + * @property string longId */ class Syncroton_Model_MeetingResponse extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'Request'; - - /** - * attendee status - */ - public const RESPONSE_ACCEPTED = 1; - public const RESPONSE_TENTATIVE = 2; - public const RESPONSE_DECLINED = 3; - - protected $_properties = - 'MeetingResponse' => - 'userResponse' => 'type' => 'number', - 'collectionId' => 'type' => 'string', - 'calendarId' => 'type' => 'string', - 'requestId' => 'type' => 'string', - 'instanceId' => 'type' => 'datetime', - , - 'Search' => - 'longId' => 'type' => 'string', - , - ; -} + + /** + * attendee status + */ + const RESPONSE_ACCEPTED = 1; + const RESPONSE_TENTATIVE = 2; + const RESPONSE_DECLINED = 3; + + protected $_properties = array( + 'MeetingResponse' => array( + 'userResponse' => array('type' => 'number'), + 'collectionId' => array('type' => 'string'), + 'calendarId' => array('type' => 'string'), + 'requestId' => array('type' => 'string'), + 'instanceId' => array('type' => 'datetime'), + ), + 'Search' => array( + 'longId' => array('type' => 'string') + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Note.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Note.php
Changed
@@ -14,25 +14,25 @@ * * @package Syncroton * @subpackage Model - * @property Syncroton_Model_EmailBody $body - * @property array $categories - * @property DateTime $lastModifiedDate - * @property string $messageClass - * @property string $subject + * @property Syncroton_Model_EmailBody body + * @property array categories + * @property DateTime lastModifiedDate + * @property string messageClass + * @property string subject */ class Syncroton_Model_Note extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'ApplicationData'; - protected $_properties = - 'AirSyncBase' => - 'body' => 'type' => 'container', 'class' => 'Syncroton_Model_EmailBody', - , - 'Notes' => - 'categories' => 'type' => 'container', 'childElement' => 'category', - 'lastModifiedDate' => 'type' => 'datetime', - 'messageClass' => 'type' => 'string', - 'subject' => 'type' => 'string', - , - ; -} + protected $_properties = array( + 'AirSyncBase' => array( + 'body' => array('type' => 'container', 'class' => 'Syncroton_Model_EmailBody') + ), + 'Notes' => array( + 'categories' => array('type' => 'container', 'childElement' => 'category'), + 'lastModifiedDate' => array('type' => 'datetime'), + 'messageClass' => array('type' => 'string'), + 'subject' => array('type' => 'string'), + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Oof.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Oof.php
Changed
@@ -15,26 +15,21 @@ * * @package Syncroton * @subpackage Model - * - * @property DateTime $endTime - * @property Syncroton_Model_OofMessage $oofMessage - * @property int $oofState - * @property DateTime $startTime */ class Syncroton_Model_Oof extends Syncroton_Model_AXMLEntry { - public const STATUS_DISABLED = 0; - public const STATUS_GLOBAL = 1; - public const STATUS_TIME_BASED = 2; + const STATUS_DISABLED = 0; + const STATUS_GLOBAL = 1; + const STATUS_TIME_BASED = 2; - protected $_xmlBaseElement = 'Get', 'Set'; + protected $_xmlBaseElement = array('Get', 'Set'); - protected $_properties = - 'Settings' => - 'endTime' => 'type' => 'datetime', - 'oofMessage' => 'type' => 'container', 'multiple' => true, 'class' => 'Syncroton_Model_OofMessage', - 'oofState' => 'type' => 'number', - 'startTime' => 'type' => 'datetime', - , - ; + protected $_properties = array( + 'Settings' => array( + 'endTime' => array('type' => 'datetime'), + 'oofMessage' => array('type' => 'container', 'multiple' => true, 'class' => 'Syncroton_Model_OofMessage'), + 'oofState' => array('type' => 'number'), + 'startTime' => array('type' => 'datetime'), + ) + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/OofMessage.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/OofMessage.php
Changed
@@ -18,16 +18,16 @@ */ class Syncroton_Model_OofMessage extends Syncroton_Model_AXMLEntry { - protected $_xmlBaseElement = 'OofMessage'; + protected $_xmlBaseElement = array('OofMessage'); - protected $_properties = - 'Settings' => - 'appliesToInternal' => 'type' => 'none', - 'appliesToExternalKnown' => 'type' => 'none', - 'appliesToExternalUnknown' => 'type' => 'none', - 'bodyType' => 'type' => 'string', - 'enabled' => 'type' => 'string', - 'replyMessage' => 'type' => 'string', - , - ; + protected $_properties = array( + 'Settings' => array( + 'appliesToInternal' => array('type' => 'none'), + 'appliesToExternalKnown' => array('type' => 'none'), + 'appliesToExternalUnknown' => array('type' => 'none'), + 'bodyType' => array('type' => 'string'), + 'enabled' => array('type' => 'string'), + 'replyMessage' => array('type' => 'string'), + ) + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Policy.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Policy.php
Changed
@@ -18,57 +18,59 @@ class Syncroton_Model_Policy extends Syncroton_Model_AXMLEntry implements Syncroton_Model_IPolicy { protected $_xmlBaseElement = 'EASProvisionDoc'; - - protected $_properties = - 'Internal' => - 'id' => 'type' => 'string', - 'description' => 'type' => 'string', - 'name' => 'type' => 'string', - 'policyKey' => 'type' => 'string', - , - 'Provision' => - 'allowBluetooth' => 'type' => 'number', - 'allowBrowser' => 'type' => 'number', - 'allowCamera' => 'type' => 'number', - 'allowConsumerEmail' => 'type' => 'number', - 'allowDesktopSync' => 'type' => 'number', - 'allowHTMLEmail' => 'type' => 'number', - 'allowInternetSharing' => 'type' => 'number', - 'allowIrDA' => 'type' => 'number', - 'allowPOPIMAPEmail' => 'type' => 'number', - 'allowRemoteDesktop' => 'type' => 'number', - 'allowSimpleDevicePassword' => 'type' => 'number', - 'allowSMIMEEncryptionAlgorithmNegotiation' => 'type' => 'number', - 'allowSMIMESoftCerts' => 'type' => 'number', - 'allowStorageCard' => 'type' => 'number', - 'allowTextMessaging' => 'type' => 'number', - 'allowUnsignedApplications' => 'type' => 'number', - 'allowUnsignedInstallationPackages' => 'type' => 'number', - 'allowWifi' => 'type' => 'number', - 'alphanumericDevicePasswordRequired' => 'type' => 'number', - 'approvedApplicationList' => 'type' => 'container', 'childName' => 'Hash', - 'attachmentsEnabled' => 'type' => 'number', - 'devicePasswordEnabled' => 'type' => 'number', - 'devicePasswordExpiration' => 'type' => 'number', - 'devicePasswordHistory' => 'type' => 'number', - 'maxAttachmentSize' => 'type' => 'number', - 'maxCalendarAgeFilter' => 'type' => 'number', - 'maxDevicePasswordFailedAttempts' => 'type' => 'number', - 'maxEmailAgeFilter' => 'type' => 'number', - 'maxEmailBodyTruncationSize' => 'type' => 'number', - 'maxEmailHTMLBodyTruncationSize' => 'type' => 'number', - 'maxInactivityTimeDeviceLock' => 'type' => 'number', - 'minDevicePasswordComplexCharacters' => 'type' => 'number', - 'minDevicePasswordLength' => 'type' => 'number', - 'passwordRecoveryEnabled' => 'type' => 'number', - 'requireDeviceEncryption' => 'type' => 'number', - 'requireEncryptedSMIMEMessages' => 'type' => 'number', - 'requireEncryptionSMIMEAlgorithm' => 'type' => 'number', - 'requireManualSyncWhenRoaming' => 'type' => 'number', - 'requireSignedSMIMEAlgorithm' => 'type' => 'number', - 'requireSignedSMIMEMessages' => 'type' => 'number', - 'requireStorageCardEncryption' => 'type' => 'number', - 'unapprovedInROMApplicationList' => 'type' => 'container', 'childName' => 'ApplicationName', - , - ; + + protected $_properties = array( + 'Internal' => array( + 'id' => array('type' => 'string'), + 'description' => array('type' => 'string'), + 'name' => array('type' => 'string'), + 'policyKey' => array('type' => 'string'), + ), + 'Provision' => array( + 'allowBluetooth' => array('type' => 'number'), + 'allowSMIMEEncryptionAlgorithmNegotiation' => array('type' => 'number'), + 'allowBrowser' => array('type' => 'number'), + 'allowCamera' => array('type' => 'number'), + 'allowConsumerEmail' => array('type' => 'number'), + 'allowDesktopSync' => array('type' => 'number'), + 'allowHTMLEmail' => array('type' => 'number'), + 'allowInternetSharing' => array('type' => 'number'), + 'allowIrDA' => array('type' => 'number'), + 'allowPOPIMAPEmail' => array('type' => 'number'), + 'allowRemoteDesktop' => array('type' => 'number'), + 'allowSimpleDevicePassword' => array('type' => 'number'), + 'allowSMIMEEncryptionAlgorithmNegotiation' => array('type' => 'number'), + 'allowSMIMESoftCerts' => array('type' => 'number'), + 'allowStorageCard' => array('type' => 'number'), + 'allowTextMessaging' => array('type' => 'number'), + 'allowUnsignedApplications' => array('type' => 'number'), + 'allowUnsignedInstallationPackages' => array('type' => 'number'), + 'allowWifi' => array('type' => 'number'), + 'alphanumericDevicePasswordRequired' => array('type' => 'number'), + 'approvedApplicationList' => array('type' => 'container', 'childName' => 'Hash'), + 'attachmentsEnabled' => array('type' => 'number'), + 'devicePasswordEnabled' => array('type' => 'number'), + 'devicePasswordExpiration' => array('type' => 'number'), + 'devicePasswordHistory' => array('type' => 'number'), + 'maxAttachmentSize' => array('type' => 'number'), + 'maxCalendarAgeFilter' => array('type' => 'number'), + 'maxDevicePasswordFailedAttempts' => array('type' => 'number'), + 'maxEmailAgeFilter' => array('type' => 'number'), + 'maxEmailBodyTruncationSize' => array('type' => 'number'), + 'maxEmailHTMLBodyTruncationSize' => array('type' => 'number'), + 'maxInactivityTimeDeviceLock' => array('type' => 'number'), + 'minDevicePasswordComplexCharacters' => array('type' => 'number'), + 'minDevicePasswordLength' => array('type' => 'number'), + 'passwordRecoveryEnabled' => array('type' => 'number'), + 'requireDeviceEncryption' => array('type' => 'number'), + 'requireEncryptedSMIMEMessages' => array('type' => 'number'), + 'requireEncryptionSMIMEAlgorithm' => array('type' => 'number'), + 'requireManualSyncWhenRoaming' => array('type' => 'number'), + 'requireSignedSMIMEAlgorithm' => array('type' => 'number'), + 'requireSignedSMIMEMessages' => array('type' => 'number'), + 'requireStorageCardEncryption' => array('type' => 'number'), + 'unapprovedInROMApplicationList' => array('type' => 'container', 'childName' => 'ApplicationName') + ) + ); } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/SendMail.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/SendMail.php
Changed
@@ -19,16 +19,16 @@ */ class Syncroton_Model_SendMail extends Syncroton_Model_AXMLEntry { - protected $_properties = - 'ComposeMail' => - 'accountId' => 'type' => 'string', - 'clientId' => 'type' => 'string', - 'mime' => 'type' => 'byteArray', - 'saveInSentItems' => 'type' => 'string', - 'status' => 'type' => 'number', - , - 'RightsManagement' => - 'templateID' => 'type' => 'string', - , - ; + protected $_properties = array( + 'ComposeMail' => array( + 'accountId' => array('type' => 'string'), + 'clientId' => array('type' => 'string'), + 'mime' => array('type' => 'byteArray'), + 'saveInSentItems' => array('type' => 'string'), + 'status' => array('type' => 'number'), + ), + 'RightsManagement' => array( + 'templateID' => array('type' => 'string'), + ) + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/SmartForward.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/SmartForward.php
Changed
@@ -19,18 +19,18 @@ */ class Syncroton_Model_SmartForward extends Syncroton_Model_AXMLEntry { - protected $_properties = - 'ComposeMail' => - 'accountId' => 'type' => 'string', - 'clientId' => 'type' => 'string', - 'mime' => 'type' => 'byteArray', - 'replaceMime' => 'type' => 'string', - 'saveInSentItems' => 'type' => 'string', - 'source' => 'type' => 'container', // or string - 'status' => 'type' => 'number', - , - 'RightsManagement' => - 'templateID' => 'type' => 'string', - , - ; + protected $_properties = array( + 'ComposeMail' => array( + 'accountId' => array('type' => 'string'), + 'clientId' => array('type' => 'string'), + 'mime' => array('type' => 'byteArray'), + 'replaceMime' => array('type' => 'string'), + 'saveInSentItems' => array('type' => 'string'), + 'source' => array('type' => 'container'), // or string + 'status' => array('type' => 'number'), + ), + 'RightsManagement' => array( + 'templateID' => array('type' => 'string'), + ) + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/SmartReply.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/SmartReply.php
Changed
@@ -19,18 +19,18 @@ */ class Syncroton_Model_SmartReply extends Syncroton_Model_AXMLEntry { - protected $_properties = - 'ComposeMail' => - 'accountId' => 'type' => 'string', - 'clientId' => 'type' => 'string', - 'mime' => 'type' => 'byteArray', - 'replaceMime' => 'type' => 'string', - 'saveInSentItems' => 'type' => 'string', - 'source' => 'type' => 'container', // or string - 'status' => 'type' => 'number', - , - 'RightsManagement' => - 'templateID' => 'type' => 'string', - , - ; + protected $_properties = array( + 'ComposeMail' => array( + 'accountId' => array('type' => 'string'), + 'clientId' => array('type' => 'string'), + 'mime' => array('type' => 'byteArray'), + 'replaceMime' => array('type' => 'string'), + 'saveInSentItems' => array('type' => 'string'), + 'source' => array('type' => 'container'), // or string + 'status' => array('type' => 'number'), + ), + 'RightsManagement' => array( + 'templateID' => array('type' => 'string'), + ) + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/StoreRequest.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/StoreRequest.php
Changed
@@ -16,13 +16,13 @@ * * @package Syncroton * @subpackage Model - * @property string $name - * @property array $options - * @property array $query + * @property string name + * @property array options + * @property array query */ class Syncroton_Model_StoreRequest { - protected $_store = ; + protected $_store = array(); protected $_xmlStore; @@ -37,12 +37,12 @@ public function setFromArray(array $properties) { - $this->_store = - 'options' => + $this->_store = array( + 'options' => array( 'mimeSupport' => Syncroton_Command_Sync::MIMESUPPORT_DONT_SEND_MIME, - 'bodyPreferences' => , - , - ; + 'bodyPreferences' => array() + ), + ); foreach ($properties as $key => $value) { try { @@ -67,13 +67,13 @@ $this->_xmlStore = $xmlStore; - $this->_store = + $this->_store = array( 'name' => (string) $xmlStore->Name, - 'options' => + 'options' => array( 'mimeSupport' => Syncroton_Command_Sync::MIMESUPPORT_DONT_SEND_MIME, - 'bodyPreferences' => , - , - ; + 'bodyPreferences' => array(), + ), + ); // Process Query if ($this->_store'name' == 'GAL') { @@ -176,15 +176,15 @@ $this->_store'options''range' = (string) $xmlStore->Options->Range; } else { switch ($this->_store'name') { - case 'DocumentLibrary': - case 'Document Library': //? - $this->_store'options''range' = '0-999'; - break; - case 'Mailbox': - case 'GAL': - default: - $this->_store'options''range' = '0-99'; - break; + case 'DocumentLibrary': + case 'Document Library': //? + '0-999'; + break; + case 'Mailbox': + case 'GAL': + default: + '0-99'; + break; } } @@ -193,20 +193,20 @@ if (isset($xmlStore->Options->MIMESupport)) { $this->_store'options''mimeSupport' = (int) $xmlStore->Options->MIMESupport; } - /* - if (isset($xmlStore->Options->MIMETruncation)) { - $this->_store'options''mimeTruncation' = (int)$xmlStore->Options->MIMETruncation; - } - */ +/* + if (isset($xmlStore->Options->MIMETruncation)) { + $this->_store'options''mimeTruncation' = (int)$xmlStore->Options->MIMETruncation; + } +*/ // try to fetch element from AirSyncBase:BodyPreference $airSyncBase = $xmlStore->Options->children('uri:AirSyncBase'); if (isset($airSyncBase->BodyPreference)) { foreach ($airSyncBase->BodyPreference as $bodyPreference) { $type = (int) $bodyPreference->Type; - $this->_store'options''bodyPreferences'$type = - 'type' => $type, - ; + $this->_store'options''bodyPreferences'$type = array( + 'type' => $type + ); // optional if (isset($bodyPreference->TruncationSize)) { @@ -244,4 +244,4 @@ { unset($this->_store$name); } -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/StoreResponse.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/StoreResponse.php
Changed
@@ -1,13 +1,12 @@ <?php - /** * Syncroton * * @package Syncroton * @subpackage Model * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 - * @copyright Copyright (c) 2012-2014 Kolab Systems AG - * @author Aleksander Machniak <machniak@kolabsys.com> + * @copyright Copyright (c) 2012-2012 Metaways Infosystems GmbH (http://www.metaways.de) + * @author Lars Kneschke <l.kneschke@metaways.de> */ /** @@ -15,41 +14,40 @@ * * @package Syncroton * @subpackage Model - * - * @property int $status - * @property array $result - * @property array $range - * @property int $total + * @property string status + * @property array result + * @property array range + * @property int total */ class Syncroton_Model_StoreResponse extends Syncroton_Model_AXMLEntry { /** * status constants */ - public const STATUS_SUCCESS = 1; - public const STATUS_INVALIDREQUEST = 2; - public const STATUS_SERVERERROR = 3; - public const STATUS_BADLINK = 4; - public const STATUS_ACCESSDENIED = 5; - public const STATUS_NOTFOUND = 6; - public const STATUS_CONNECTIONFAILED = 7; - public const STATUS_TOOCOMPLEX = 8; - public const STATUS_TIMEDOUT = 10; - public const STATUS_FOLDERSYNCREQUIRED = 11; - public const STATUS_ENDOFRANGE = 12; - public const STATUS_ACCESSBLOCKED = 13; - public const STATUS_CREDENTIALSREQUIRED = 14; + const STATUS_SUCCESS = 1; + const STATUS_INVALIDREQUEST = 2; + const STATUS_SERVERERROR = 3; + const STATUS_BADLINK = 4; + const STATUS_ACCESSDENIED = 5; + const STATUS_NOTFOUND = 6; + const STATUS_CONNECTIONFAILED = 7; + const STATUS_TOOCOMPLEX = 8; + const STATUS_TIMEDOUT = 10; + const STATUS_FOLDERSYNCREQUIRED = 11; + const STATUS_ENDOFRANGE = 12; + const STATUS_ACCESSBLOCKED = 13; + const STATUS_CREDENTIALSREQUIRED = 14; protected $_xmlBaseElement = 'Store'; - protected $_properties = - 'Search' => - 'status' => 'type' => 'number', - 'result' => 'type' => 'container', 'multiple' => true, - 'range' => 'type' => 'string', - 'total' => 'type' => 'number', - , - ; + protected $_properties = array( + 'Search' => array( + 'status' => array('type' => 'number'), + 'result' => array('type' => 'container', 'multiple' => true), + 'range' => array('type' => 'string'), + 'total' => array('type' => 'number'), + ) + ); /** * (non-PHPdoc) @@ -65,7 +63,7 @@ continue; } - $nameSpace, $elementProperties = $this->_getElementProperties($elementName); + list ($nameSpace, $elementProperties) = $this->_getElementProperties($elementName); $nameSpace = 'uri:' . $nameSpace; @@ -83,7 +81,6 @@ $value = implode('-', $value); } - // no break default: $element = $_domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName)); $element->appendChild($_domParrent->ownerDocument->createTextNode($value));
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/StoreResponseResult.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/StoreResponseResult.php
Changed
@@ -19,14 +19,14 @@ { protected $_xmlBaseElement = 'Result'; - protected $_properties = - 'AirSync' => - 'class' => 'type' => 'string', - 'collectionId' => 'type' => 'string', - , - 'Search' => - 'longId' => 'type' => 'string', 'supportedSince' => '2.5', - 'properties' => 'type' => 'container', 'supportedSince' => '2.5', - , - ; + protected $_properties = array( + 'AirSync' => array( + 'class' => array('type' => 'string'), + 'collectionId' => array('type' => 'string'), + ), + 'Search' => array( + 'longId' => array('type' => 'string', 'supportedSince' => '2.5'), + 'properties' => array('type' => 'container', 'supportedSince' => '2.5'), + ) + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/SyncCollection.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/SyncCollection.php
Changed
@@ -14,39 +14,35 @@ * * @package Syncroton * @subpackage Model - * - * @property string $class - * @property string $collectionId - * @property bool $deletesAsMoves - * @property Syncroton_Model_IFolder $folder - * @property bool $getChanges - * @property array $options - * @property int $syncKey - * @property ?Syncroton_Model_ISyncState $syncState - * @property array $toBeFetched - * @property int $windowSize + * @property string class + * @property string collectionId + * @property bool deletesAsMoves + * @property bool getChanges + * @property string syncKey + * @property int windowSize */ + class Syncroton_Model_SyncCollection extends Syncroton_Model_AXMLEntry { - protected $_elements = + protected $_elements = array( 'syncState' => null, - 'folder' => null, - ; - + 'folder' => null + ); + protected $_xmlCollection; - + protected $_xmlBaseElement = 'Collection'; - - public function __construct($properties = null) - { - if ($properties instanceof SimpleXMLElement) { - $this->setFromSimpleXMLElement($properties); - } elseif (is_array($properties)) { - $this->setFromArray($properties); + + public function __construct($properties = null) + { + if ($properties instanceof SimpleXMLElement) { + $this->setFromSimpleXMLElement($properties); + } elseif (is_array($properties)) { + $this->setFromArray($properties); } - + if (!isset($this->_elements'options')) { - $this->_elements'options' = ; + $this->_elements'options' = array(); } if (!isset($this->_elements'options''filterType')) { $this->_elements'options''filterType' = Syncroton_Command_Sync::FILTER_NOTHING; @@ -57,14 +53,14 @@ if (!isset($this->_elements'options''mimeTruncation')) { $this->_elements'options''mimeTruncation' = Syncroton_Command_Sync::TRUNCATE_NOTHING; } - if (!isset($this->_elements'options''bodyPreferences')) { - $this->_elements'options''bodyPreferences' = ; + if (!isset($this->_elements'options''bodyPreferences')) { + $this->_elements'options''bodyPreferences' = array(); } - } - + } + /** * return XML element which holds all client Add commands - * + * * @return SimpleXMLElement */ public function getClientAdds() @@ -72,13 +68,13 @@ if (! $this->_xmlCollection instanceof SimpleXMLElement) { throw new InvalidArgumentException('no collection xml element set'); } - + return $this->_xmlCollection->Commands->Add; } - + /** * return XML element which holds all client Change commands - * + * * @return SimpleXMLElement */ public function getClientChanges() @@ -86,13 +82,13 @@ if (! $this->_xmlCollection instanceof SimpleXMLElement) { throw new InvalidArgumentException('no collection xml element set'); } - + return $this->_xmlCollection->Commands->Change; } - + /** * return XML element which holds all client Delete commands - * + * * @return SimpleXMLElement */ public function getClientDeletes() @@ -100,13 +96,13 @@ if (! $this->_xmlCollection instanceof SimpleXMLElement) { throw new InvalidArgumentException('no collection xml element set'); } - + return $this->_xmlCollection->Commands->Delete; } - + /** * return XML element which holds all client Fetch commands - * + * * @return SimpleXMLElement */ public function getClientFetches() @@ -114,13 +110,13 @@ if (! $this->_xmlCollection instanceof SimpleXMLElement) { throw new InvalidArgumentException('no collection xml element set'); } - + return $this->_xmlCollection->Commands->Fetch; } - + /** * check if client sent a Add command - * + * * @throws InvalidArgumentException * @return bool */ @@ -129,13 +125,13 @@ if (! $this->_xmlCollection instanceof SimpleXMLElement) { return false; } - + return isset($this->_xmlCollection->Commands->Add); } - + /** * check if client sent a Change command - * + * * @throws InvalidArgumentException * @return bool */ @@ -144,13 +140,13 @@ if (! $this->_xmlCollection instanceof SimpleXMLElement) { return false; } - + return isset($this->_xmlCollection->Commands->Change); } - + /** * check if client sent a Delete command - * + * * @throws InvalidArgumentException * @return bool */ @@ -159,13 +155,13 @@ if (! $this->_xmlCollection instanceof SimpleXMLElement) { return false; } - + return isset($this->_xmlCollection->Commands->Delete); } - + /** * check if client sent a Fetch command - * + * * @throws InvalidArgumentException * @return bool */ @@ -174,14 +170,14 @@ if (! $this->_xmlCollection instanceof SimpleXMLElement) { return false; } - + return isset($this->_xmlCollection->Commands->Fetch); } - + /** * this functions does not only set from SimpleXMLElement but also does merge from SimpleXMLElement * to support partial sync requests - * + * * @param SimpleXMLElement $properties * @throws InvalidArgumentException */ @@ -190,29 +186,29 @@ if (!in_array($properties->getName(), (array) $this->_xmlBaseElement)) { throw new InvalidArgumentException('Unexpected element name: ' . $properties->getName()); } - + $this->_xmlCollection = $properties; - + if (isset($properties->CollectionId)) { $this->_elements'collectionId' = (string)$properties->CollectionId; } - + if (isset($properties->SyncKey)) { $this->_elements'syncKey' = (int)$properties->SyncKey; } - + if (isset($properties->Class)) { $this->_elements'class' = (string)$properties->Class; } elseif (!array_key_exists('class', $this->_elements)) { $this->_elements'class' = null; } - + if (isset($properties->WindowSize)) { $this->_elements'windowSize' = (string)$properties->WindowSize; } elseif (!array_key_exists('windowSize', $this->_elements)) { $this->_elements'windowSize' = 100; } - + if (isset($properties->DeletesAsMoves)) { if ((string)$properties->DeletesAsMoves === '0') { $this->_elements'deletesAsMoves' = false; @@ -222,7 +218,7 @@ } elseif (!array_key_exists('deletesAsMoves', $this->_elements)) { $this->_elements'deletesAsMoves' = true; } - + if (isset($properties->ConversationMode)) { if ((string)$properties->ConversationMode === '0') { $this->_elements'conversationMode' = false; @@ -232,7 +228,7 @@ } elseif (!array_key_exists('conversationMode', $this->_elements)) { $this->_elements'conversationMode' = true; } - + if (isset($properties->GetChanges)) { if ((string)$properties->GetChanges === '0') { $this->_elements'getChanges' = false; @@ -242,82 +238,82 @@ } elseif (!array_key_exists('getChanges', $this->_elements)) { $this->_elements'getChanges' = true; } - + if (isset($properties->Supported)) { // @todo collect supported elements } - - // process options + + // process options if (isset($properties->Options)) { - $this->_elements'options' = ; - - // optional parameters - if (isset($properties->Options->FilterType)) { - $this->_elements'options''filterType' = (int)$properties->Options->FilterType; - } - if (isset($properties->Options->MIMESupport)) { - $this->_elements'options''mimeSupport' = (int)$properties->Options->MIMESupport; - } - if (isset($properties->Options->MIMETruncation)) { - $this->_elements'options''mimeTruncation' = (int)$properties->Options->MIMETruncation; - } - if (isset($properties->Options->Class)) { - $this->_elements'options''class' = (string)$properties->Options->Class; + $this->_elements'options' = array(); + + // optional parameters + if (isset($properties->Options->FilterType)) { + $this->_elements'options''filterType' = (int)$properties->Options->FilterType; + } + if (isset($properties->Options->MIMESupport)) { + $this->_elements'options''mimeSupport' = (int)$properties->Options->MIMESupport; + } + if (isset($properties->Options->MIMETruncation)) { + $this->_elements'options''mimeTruncation' = (int)$properties->Options->MIMETruncation; } - - // try to fetch element from AirSyncBase:BodyPreference - $airSyncBase = $properties->Options->children('uri:AirSyncBase'); - - if (isset($airSyncBase->BodyPreference)) { - - foreach ($airSyncBase->BodyPreference as $bodyPreference) { - $type = (int) $bodyPreference->Type; - $this->_elements'options''bodyPreferences'$type = - 'type' => $type, - ; - - // optional - if (isset($bodyPreference->TruncationSize)) { - $this->_elements'options''bodyPreferences'$type'truncationSize' = (int) $bodyPreference->TruncationSize; - } - - // optional - if (isset($bodyPreference->Preview)) { - $this->_elements'options''bodyPreferences'$type'preview' = (int) $bodyPreference->Preview; + if (isset($properties->Options->Class)) { + $this->_elements'options''class' = (string)$properties->Options->Class; + } + + // try to fetch element from AirSyncBase:BodyPreference + $airSyncBase = $properties->Options->children('uri:AirSyncBase'); + + if (isset($airSyncBase->BodyPreference)) { + + foreach ($airSyncBase->BodyPreference as $bodyPreference) { + $type = (int) $bodyPreference->Type; + $this->_elements'options''bodyPreferences'$type = array( + 'type' => $type + ); + + // optional + if (isset($bodyPreference->TruncationSize)) { + $this->_elements'options''bodyPreferences'$type'truncationSize' = (int) $bodyPreference->TruncationSize; } + + // optional + if (isset($bodyPreference->Preview)) { + $this->_elements'options''bodyPreferences'$type'preview' = (int) $bodyPreference->Preview; + } } } - + if (isset($airSyncBase->BodyPartPreference)) { // process BodyPartPreference elements } - } + } } - + public function toArray() { - $result = ; - - foreach ('syncKey', 'collectionId', 'deletesAsMoves', 'conversationMode', 'getChanges', 'windowSize', 'class', 'options' as $key) { + $result = array(); + + foreach (array('syncKey', 'collectionId', 'deletesAsMoves', 'conversationMode', 'getChanges', 'windowSize', 'class', 'options') as $key) { if (isset($this->$key)) { $result$key = $this->$key; } } - + return $result; } - + public function &__get($name) { - if (array_key_exists($name, $this->_elements)) { - return $this->_elements$name; + if (array_key_exists($name, $this->_elements)) { + return $this->_elements$name; } echo $name . PHP_EOL; - return null; + return null; } - + public function __set($name, $value) { $this->_elements$name = $value; } -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/SyncState.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/SyncState.php
Changed
@@ -18,3 +18,4 @@ class Syncroton_Model_SyncState extends Syncroton_Model_AEntry implements Syncroton_Model_ISyncState { } +
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/Task.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/Task.php
Changed
@@ -14,37 +14,35 @@ * * @package Syncroton * @subpackage Model - * @property string $class - * @property string $collectionId - * @property bool $deletesAsMoves - * @property bool $getChanges - * @property string $syncKey - * @property DateTime $utcDueDate - * @property DateTime $utcStartDate - * @property int $windowSize + * @property string class + * @property string collectionId + * @property bool deletesAsMoves + * @property bool getChanges + * @property string syncKey + * @property int windowSize */ class Syncroton_Model_Task extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'ApplicationData'; - - protected $_properties = - 'AirSyncBase' => - 'body' => 'type' => 'container', 'class' => 'Syncroton_Model_EmailBody', - , - 'Tasks' => - 'categories' => 'type' => 'container', 'childElement' => 'category', - 'complete' => 'type' => 'number', - 'dateCompleted' => 'type' => 'datetime', - 'dueDate' => 'type' => 'datetime', - 'importance' => 'type' => 'number', - 'recurrence' => 'type' => 'container', - 'reminderSet' => 'type' => 'number', - 'reminderTime' => 'type' => 'datetime', - 'sensitivity' => 'type' => 'number', - 'startDate' => 'type' => 'datetime', - 'subject' => 'type' => 'string', - 'utcDueDate' => 'type' => 'datetime', - 'utcStartDate' => 'type' => 'datetime', - , - ; -} + + protected $_properties = array( + 'AirSyncBase' => array( + 'body' => array('type' => 'container', 'class' => 'Syncroton_Model_EmailBody') + ), + 'Tasks' => array( + 'categories' => array('type' => 'container', 'childElement' => 'category'), + 'complete' => array('type' => 'number'), + 'dateCompleted' => array('type' => 'datetime'), + 'dueDate' => array('type' => 'datetime'), + 'importance' => array('type' => 'number'), + 'recurrence' => array('type' => 'container'), + 'reminderSet' => array('type' => 'number'), + 'reminderTime' => array('type' => 'datetime'), + 'sensitivity' => array('type' => 'number'), + 'startDate' => array('type' => 'datetime'), + 'subject' => array('type' => 'string'), + 'utcDueDate' => array('type' => 'datetime'), + 'utcStartDate' => array('type' => 'datetime'), + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Model/TaskRecurrence.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Model/TaskRecurrence.php
Changed
@@ -14,54 +14,54 @@ * * @package Syncroton * @subpackage Model - * @property string $class - * @property string $collectionId - * @property bool $deletesAsMoves - * @property bool $getChanges - * @property string $syncKey - * @property int $windowSize + * @property string class + * @property string collectionId + * @property bool deletesAsMoves + * @property bool getChanges + * @property string syncKey + * @property int windowSize */ class Syncroton_Model_TaskRecurrence extends Syncroton_Model_AXMLEntry { protected $_xmlBaseElement = 'Recurrence'; - + /** * recur types */ - public const TYPE_DAILY = 0; // Recurs daily. - public const TYPE_WEEKLY = 1; // Recurs weekly - public const TYPE_MONTHLY = 2; // Recurs monthly - public const TYPE_MONTHLY_DAYN = 3; // Recurs monthly on the nth day - public const TYPE_YEARLY = 5; // Recurs yearly - public const TYPE_YEARLY_DAYN = 6; // Recurs yearly on the nth day - + const TYPE_DAILY = 0; // Recurs daily. + const TYPE_WEEKLY = 1; // Recurs weekly + const TYPE_MONTHLY = 2; // Recurs monthly + const TYPE_MONTHLY_DAYN = 3; // Recurs monthly on the nth day + const TYPE_YEARLY = 5; // Recurs yearly + const TYPE_YEARLY_DAYN = 6; // Recurs yearly on the nth day + /** * day of week constants */ - public const RECUR_DOW_SUNDAY = 1; - public const RECUR_DOW_MONDAY = 2; - public const RECUR_DOW_TUESDAY = 4; - public const RECUR_DOW_WEDNESDAY = 8; - public const RECUR_DOW_THURSDAY = 16; - public const RECUR_DOW_FRIDAY = 32; - public const RECUR_DOW_SATURDAY = 64; - - protected $_properties = - 'Tasks' => - 'calendarType' => 'type' => 'number', - 'dayOfMonth' => 'type' => 'number', - 'dayOfWeek' => 'type' => 'number', - 'deadOccur' => 'type' => 'number', - 'firstDayOfWeek' => 'type' => 'number', - 'interval' => 'type' => 'number', - 'isLeapMonth' => 'type' => 'number', - 'monthOfYear' => 'type' => 'number', - 'occurrences' => 'type' => 'number', - 'regenerate' => 'type' => 'number', - 'start' => 'type' => 'datetime', - 'type' => 'type' => 'number', - 'until' => 'type' => 'datetime', - 'weekOfMonth' => 'type' => 'number', - , - ; -} + const RECUR_DOW_SUNDAY = 1; + const RECUR_DOW_MONDAY = 2; + const RECUR_DOW_TUESDAY = 4; + const RECUR_DOW_WEDNESDAY = 8; + const RECUR_DOW_THURSDAY = 16; + const RECUR_DOW_FRIDAY = 32; + const RECUR_DOW_SATURDAY = 64; + + protected $_properties = array( + 'Tasks' => array( + 'calendarType' => array('type' => 'number'), + 'dayOfMonth' => array('type' => 'number'), + 'dayOfWeek' => array('type' => 'number'), + 'deadOccur' => array('type' => 'number'), + 'firstDayOfWeek' => array('type' => 'number'), + 'interval' => array('type' => 'number'), + 'isLeapMonth' => array('type' => 'number'), + 'monthOfYear' => array('type' => 'number'), + 'occurrences' => array('type' => 'number'), + 'regenerate' => array('type' => 'number'), + 'start' => array('type' => 'datetime'), + 'type' => array('type' => 'number'), + 'until' => array('type' => 'datetime'), + 'weekOfMonth' => array('type' => 'number'), + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Registry.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Registry.php
Changed
@@ -27,34 +27,33 @@ */ class Syncroton_Registry extends ArrayObject { - public const CALENDAR_DATA_CLASS = 'calendar_data_class'; - public const CONTACTS_DATA_CLASS = 'contacts_data_class'; - public const EMAIL_DATA_CLASS = 'email_data_class'; - public const NOTES_DATA_CLASS = 'notes_data_class'; - public const TASKS_DATA_CLASS = 'tasks_data_class'; - public const GAL_DATA_CLASS = 'gal_data_class'; - - public const DEFAULT_POLICY = 'default_policy'; - public const PING_TIMEOUT = 'ping_timeout'; - public const PING_INTERVAL = 'ping_interval'; - public const QUIET_TIME = 'quiet_time'; - public const SESSION_VALIDATOR = 'session_validator'; - public const MAX_COLLECTIONS = 'max_collections'; - public const MAX_PING_INTERVAL = 'max_ping_interval'; - - public const DATABASE = 'database'; - public const TRANSACTIONMANAGER = 'transactionmanager'; - - public const CONTENTSTATEBACKEND = 'contentstatebackend'; - public const DEVICEBACKEND = 'devicebackend'; - public const FOLDERBACKEND = 'folderbackend'; - public const POLICYBACKEND = 'policybackend'; - public const SYNCSTATEBACKEND = 'syncstatebackend'; - public const LOGGERBACKEND = 'loggerBackend'; - - public const SLEEP_CALLBACK = 'sleep_callback'; - public const WAKEUP_CALLBACK = 'wakeup_callback'; - + const CALENDAR_DATA_CLASS = 'calendar_data_class'; + const CONTACTS_DATA_CLASS = 'contacts_data_class'; + const EMAIL_DATA_CLASS = 'email_data_class'; + const NOTES_DATA_CLASS = 'notes_data_class'; + const TASKS_DATA_CLASS = 'tasks_data_class'; + const GAL_DATA_CLASS = 'gal_data_class'; + + const DEFAULT_POLICY = 'default_policy'; + const PING_TIMEOUT = 'ping_timeout'; + const PING_INTERVAL = 'ping_interval'; + const QUIET_TIME = 'quiet_time'; + const SESSION_VALIDATOR = 'session_validator'; + const MAX_COLLECTIONS = 'max_collections'; + + const DATABASE = 'database'; + const TRANSACTIONMANAGER = 'transactionmanager'; + + const CONTENTSTATEBACKEND = 'contentstatebackend'; + const DEVICEBACKEND = 'devicebackend'; + 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. * @var string @@ -63,7 +62,7 @@ /** * Registry object provides storage for shared objects. - * @var Syncroton_Registry|null + * @var Syncroton_Registry */ private static $_registry = null; @@ -88,10 +87,10 @@ { return self::get(self::DATABASE); } - + /** - * return transaction manager class - * + * return transaction manager class + * * @return Syncroton_TransactionManagerInterface */ public static function getTransactionManager() @@ -99,10 +98,10 @@ if (!self::isRegistered(self::TRANSACTIONMANAGER)) { self::set(self::TRANSACTIONMANAGER, Syncroton_TransactionManager::getInstance()); } - + return self::get(self::TRANSACTIONMANAGER); - } - + } + /** * Set the default registry instance to a specified instance. * @@ -197,13 +196,13 @@ 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() @@ -211,16 +210,16 @@ 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() @@ -228,16 +227,16 @@ 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() @@ -245,10 +244,10 @@ 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) * @@ -262,7 +261,7 @@ return self::get(self::PING_INTERVAL); } - + /** /** * Return maximum ping interval (HeartbeatInterval) value (in seconds) @@ -279,10 +278,10 @@ } /** - * return ping timeout - * - * sleep "ping timeout" seconds between folder checks in Ping and Sync command - * + * return ping timeout + * + * sleep "ping timeout" seconds between folder checks in Ping and Sync command + * * @return int */ public static function getPingTimeout() @@ -290,10 +289,10 @@ if (!self::isRegistered(self::PING_TIMEOUT)) { return 60; } - + return self::get(self::PING_TIMEOUT); } - + /** * Return maximum number of collections in Sync/Ping request * @@ -306,26 +305,26 @@ /** * returns policy backend - * + * * creates Syncroton_Backend_Policy on the fly if not set before via * Syncroton_Registry::set(self::POLICYBACKEND, $backend); - * - * @return Syncroton_Backend_Policy + * + * @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 quiet time + * + * don't check folders if last sync was "quiet time" seconds ago + * * @return int */ public static function getQuietTime() @@ -333,10 +332,10 @@ if (!self::isRegistered(self::QUIET_TIME)) { return 180; } - + return self::get(self::QUIET_TIME); } - + /** * Returns sleep callback function * @@ -350,7 +349,7 @@ public static function getSleepCallback() { if (!self::isRegistered(self::SLEEP_CALLBACK)) { - self::set(self::SLEEP_CALLBACK, function () {}); + self::set(self::SLEEP_CALLBACK, function() {}); } return self::get(self::SLEEP_CALLBACK); @@ -368,7 +367,7 @@ public static function getWakeupCallback() { if (!self::isRegistered(self::WAKEUP_CALLBACK)) { - self::set(self::WAKEUP_CALLBACK, function () {}); + self::set(self::WAKEUP_CALLBACK, function() {}); } return self::get(self::WAKEUP_CALLBACK); @@ -385,7 +384,7 @@ public static function getSessionValidator() { if (!self::isRegistered(self::SESSION_VALIDATOR)) { - self::set(self::SESSION_VALIDATOR, function () { + self::set(self::SESSION_VALIDATOR, function() { return true; }); } @@ -395,10 +394,10 @@ /** * 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() @@ -406,7 +405,7 @@ if (!self::isRegistered(self::SYNCSTATEBACKEND)) { self::set(self::SYNCSTATEBACKEND, new Syncroton_Backend_SyncState(self::getDatabase())); } - + return self::get(self::SYNCSTATEBACKEND); } @@ -432,34 +431,34 @@ { 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)) { @@ -474,7 +473,7 @@ if (!class_exists($className)) { throw new InvalidArgumentException('invalid $_className provided'); } - + self::set(self::TASKS_DATA_CLASS, $className); } @@ -491,7 +490,7 @@ { 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. @@ -514,7 +513,7 @@ * @param array $array data array * @param integer $flags ArrayObject flags */ - public function __construct($array = , $flags = parent::ARRAY_AS_PROPS) + public function __construct($array = array(), $flags = parent::ARRAY_AS_PROPS) { parent::__construct($array, $flags); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Server.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Server.php
Changed
@@ -10,246 +10,228 @@ /** * class to handle incoming http ActiveSync requests - * + * * @package Syncroton */ class Syncroton_Server { - public const PARAMETER_ATTACHMENTNAME = 0; - public const PARAMETER_COLLECTIONID = 1; - public const PARAMETER_ITEMID = 3; - public const PARAMETER_OPTIONS = 7; - public const MAX_HEARTBEAT_INTERVAL = 3540; // 59 minutes - + const PARAMETER_ATTACHMENTNAME = 0; + const PARAMETER_COLLECTIONID = 1; + const PARAMETER_ITEMID = 3; + const PARAMETER_OPTIONS = 7; + const MAX_HEARTBEAT_INTERVAL = 3540; // 59 minutes + protected $_body; - + /** * informations about the currently device * * @var Syncroton_Backend_IDevice */ protected $_deviceBackend; - + /** * @var Zend_Log */ protected $_logger; - + /** * @var Zend_Controller_Request_Http */ protected $_request; - + protected $_userId; - + public function __construct($userId, Zend_Controller_Request_Http $request = null, $body = null) { if (Syncroton_Registry::isRegistered('loggerBackend')) { $this->_logger = Syncroton_Registry::get('loggerBackend'); } - + $this->_userId = $userId; $this->_request = $request instanceof Zend_Controller_Request_Http ? $request : new Zend_Controller_Request_Http(); $this->_body = $body !== null ? $body : fopen('php://input', 'r'); - - // Not available on unauthenticated OPTIONS request - if (!empty($this->_userId)) { - $this->_deviceBackend = Syncroton_Registry::getDeviceBackend(); - } - + + $this->_deviceBackend = Syncroton_Registry::getDeviceBackend(); + } - + public function handle() { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' REQUEST METHOD: ' . $this->_request->getMethod()); - } - - if ($this->_request->getMethod() != "OPTIONS" && empty($this->_userId)) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . ' Not authenticated'); - header('WWW-Authenticate: Basic realm="ActiveSync for Kolab"'); - header('HTTP/1.1 401 Unauthorized'); - exit; - } - + switch($this->_request->getMethod()) { case 'OPTIONS': $this->_handleOptions(); break; - + case 'POST': $this->_handlePost(); break; - + case 'GET': echo "It works!<br>Your userid is: {$this->_userId} and your IP address is: {$_SERVER'REMOTE_ADDR'}."; break; } } - + /** * handle options request */ protected function _handleOptions() { $command = new Syncroton_Command_Options(); - + $this->_sendHeaders($command->getHeaders()); } - + protected function _sendHeaders(array $headers) { foreach ($headers as $name => $value) { header($name . ': ' . $value); } - } - + } + /** * handle post request */ protected function _handlePost() { $requestParameters = $this->_getRequestParameters($this->_request); - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' REQUEST ' . print_r($requestParameters, true)); - } - + $className = 'Syncroton_Command_' . $requestParameters'command'; - - if (!class_exists($className)) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->notice(__METHOD__ . '::' . __LINE__ . " command not supported: " . $requestParameters'command'); - } - + + if(!class_exists($className)) { + if ($this->_logger instanceof Zend_Log) + $this->_logger->crit(__METHOD__ . '::' . __LINE__ . " command not supported: " . $requestParameters'command'); + header("HTTP/1.1 501 not implemented"); - + return; } - + // get user device $device = $this->_getUserDevice($this->_userId, $requestParameters); - + if ($requestParameters'contentType' == 'application/vnd.ms-sync.wbxml' || $requestParameters'contentType' == 'application/vnd.ms-sync') { // decode wbxml request try { $decoder = new Syncroton_Wbxml_Decoder($this->_body); $requestBody = $decoder->decode(); if ($this->_logger instanceof Zend_Log) { - $this->_logDomDocument($requestBody, 'request', __METHOD__, __LINE__); + $requestBody->formatOutput = true; + $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " xml request:\n" . $requestBody->saveXML()); } } catch(Syncroton_Wbxml_Exception_UnexpectedEndOfFile $e) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " unexpected end of file."); - } - $requestBody = null; + $requestBody = NULL; } } else { $requestBody = $this->_body; } - + header("MS-Server-ActiveSync: 14.00.0536.000"); // avoid sending HTTP header "Content-Type: text/html" for empty sync responses ini_set('default_mimetype', 'application/vnd.ms-sync.wbxml'); - + try { $command = new $className($requestBody, $device, $requestParameters); - + $response = $command->handle(); if (!$response) { $response = $command->getResponse(); } } catch (Syncroton_Exception_ProvisioningNeeded $sepn) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->info(__METHOD__ . '::' . __LINE__ . " provisioning needed"); - } - + header("HTTP/1.1 449 Retry after sending a PROVISION command"); - + if (version_compare($device->acsversion, '14.0', '>=')) { $response = $sepn->domDocument; } else { // pre 14.0 method return; } - + } catch (Exception $e) { - if ($this->_logger instanceof Zend_Log) { - $this->_logger->err(__METHOD__ . '::' . __LINE__ . " unexpected exception occured: " . get_class($e)); - } - if ($this->_logger instanceof Zend_Log) { - $this->_logger->err(__METHOD__ . '::' . __LINE__ . " exception message: " . $e->getMessage()); - } - if ($this->_logger instanceof Zend_Log) { - $this->_logger->err(__METHOD__ . '::' . __LINE__ . " " . $e->getTraceAsString()); - } - + if ($this->_logger instanceof Zend_Log) + $this->_logger->crit(__METHOD__ . '::' . __LINE__ . " unexpected exception occured: " . get_class($e)); + if ($this->_logger instanceof Zend_Log) + $this->_logger->crit(__METHOD__ . '::' . __LINE__ . " exception message: " . $e->getMessage()); + if ($this->_logger instanceof Zend_Log) + $this->_logger->crit(__METHOD__ . '::' . __LINE__ . " " . $e->getTraceAsString()); + header("HTTP/1.1 500 Internal server error"); - + return; } - + if ($response instanceof DOMDocument) { if ($this->_logger instanceof Zend_Log) { - $this->_logDomDocument($response, 'response', __METHOD__, __LINE__); + $this->_logDomDocument(Zend_Log::DEBUG, $response, __METHOD__, __LINE__); } - + if (isset($command) && $command instanceof Syncroton_Command_ICommand) { $this->_sendHeaders($command->getHeaders()); } - + $outputStream = fopen("php://temp", 'r+'); - + $encoder = new Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3); - + try { - $encoder->encode($response); + $encoder->encode($response); } 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::WARN, $response, __METHOD__, __LINE__); } - + header("HTTP/1.1 500 Internal server error"); - + return; } - - if ($requestParameters'acceptMultipart' == true && isset($command)) { + + if ($requestParameters'acceptMultipart' == true) { $parts = $command->getParts(); - + // output multipartheader $bodyPartCount = 1 + count($parts); - + // number of parts (4 bytes) $header = pack('i', $bodyPartCount); - + $partOffset = 4 + (($bodyPartCount * 2) * 4); - + // wbxml body start and length $streamStat = fstat($outputStream); $header .= pack('ii', $partOffset, $streamStat'size'); - + $partOffset += $streamStat'size'; - + // calculate start and length of parts foreach ($parts as $partId => $partStream) { rewind($partStream); $streamStat = fstat($partStream); - + // part start and length $header .= pack('ii', $partOffset, $streamStat'size'); $partOffset += $streamStat'size'; } - + echo $header; } - + // output body rewind($outputStream); fpassthru($outputStream); - + // output multiparts if (isset($parts)) { foreach ($parts as $partStream) { @@ -259,50 +241,49 @@ } } } - + /** * write (possible big) DOMDocument in smaller chunks to log file - * + * + * @param unknown $priority * @param DOMDocument $dom - * @param string $action * @param string $method * @param int $line */ - protected function _logDomDocument(DOMDocument $dom, $action, $method, $line) + protected function _logDomDocument($priority, DOMDocument $dom, $method, $line) { - if (method_exists($this->_logger, 'hasDebug') && !$this->_logger->hasDebug()) { - return; - } - + $loops = 0; + $tempStream = tmpfile(); $meta_data = stream_get_meta_data($tempStream); $filename = $meta_data"uri"; - + $dom->formatOutput = true; $dom->save($filename); $dom->formatOutput = false; - + rewind($tempStream); - - $loops = 0; + + // log data in 1MByte chunks while (!feof($tempStream)) { - $this->_logger->debug("{$method}::{$line} xml {$action} ({$loops}):\n" . fread($tempStream, 1048576)); + $this->_logger->log($method . '::' . $line . " xml response($loops):\n" . fread($tempStream, 1048576), $priority); + $loops++; } - + fclose($tempStream); } - + /** * return request params - * + * * @return array */ protected function _getRequestParameters(Zend_Controller_Request_Http $request) { if (strpos($request->getRequestUri(), '&') === false) { - $commands = + $commands = array( 0 => 'Sync', 1 => 'SendMail', 2 => 'SmartForward', @@ -321,9 +302,9 @@ 19 => 'ItemOperations', 20 => 'Provision', 21 => 'ResolveRecipients', - 22 => 'ValidateCert', - ; - + 22 => 'ValidateCert' + ); + $requestParameters = substr($request->getRequestUri(), strpos($request->getRequestUri(), '?')); $stream = fopen("php://temp", 'r+'); @@ -332,36 +313,35 @@ // unpack the first 4 bytes $unpacked = unpack('CprotocolVersion/Ccommand/vlocale', fread($stream, 4)); - + // 140 => 14.0 $protocolVersion = substr($unpacked'protocolVersion', 0, -1) . '.' . substr($unpacked'protocolVersion', -1); $command = $commands$unpacked'command'; $locale = $unpacked'locale'; - $deviceId = null; - + // unpack deviceId $length = ord(fread($stream, 1)); if ($length > 0) { $toUnpack = fread($stream, $length); - + $unpacked = unpack("H" . ($length * 2) . "string", $toUnpack); $deviceId = $unpacked'string'; } - + // unpack policyKey $length = ord(fread($stream, 1)); if ($length > 0) { $unpacked = unpack('Vstring', fread($stream, $length)); $policyKey = $unpacked'string'; } - + // unpack device type $length = ord(fread($stream, 1)); if ($length > 0) { $unpacked = unpack('A' . $length . 'string', fread($stream, $length)); $deviceType = $unpacked'string'; } - + while (! feof($stream)) { $tag = ord(fread($stream, 1)); $length = ord(fread($stream, 1)); @@ -374,51 +354,50 @@ switch ($tag) { case self::PARAMETER_ATTACHMENTNAME: $unpacked = unpack('A' . $length . 'string', fread($stream, $length)); - + $attachmentName = $unpacked'string'; break; - + case self::PARAMETER_COLLECTIONID: $unpacked = unpack('A' . $length . 'string', fread($stream, $length)); - + $collectionId = $unpacked'string'; break; - + case self::PARAMETER_ITEMID: $unpacked = unpack('A' . $length . 'string', fread($stream, $length)); - + $itemId = $unpacked'string'; break; - + case self::PARAMETER_OPTIONS: $options = ord(fread($stream, 1)); - - $saveInSent = !!($options & 0x01); + + $saveInSent = !!($options & 0x01); $acceptMultiPart = !!($options & 0x02); break; - + default: - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->crit(__METHOD__ . '::' . __LINE__ . " found unhandled command parameters"); - } - + } } - - $result = + + $result = array( 'protocolVersion' => $protocolVersion, 'command' => $command, 'deviceId' => $deviceId, - 'deviceType' => $deviceType ?? null, - 'policyKey' => $policyKey ?? null, - 'saveInSent' => $saveInSent ?? false, - 'collectionId' => $collectionId ?? null, - 'itemId' => $itemId ?? null, - 'attachmentName' => $attachmentName ?? null, - 'acceptMultipart' => $acceptMultiPart ?? false, - ; + 'deviceType' => isset($deviceType) ? $deviceType : null, + 'policyKey' => isset($policyKey) ? $policyKey : null, + 'saveInSent' => isset($saveInSent) ? $saveInSent : false, + 'collectionId' => isset($collectionId) ? $collectionId : null, + 'itemId' => isset($itemId) ? $itemId : null, + 'attachmentName' => isset($attachmentName) ? $attachmentName : null, + 'acceptMultipart' => isset($acceptMultiPart) ? $acceptMultiPart : false + ); } else { - $result = + $result = array( 'protocolVersion' => $request->getServer('HTTP_MS_ASPROTOCOLVERSION'), 'command' => $request->getQuery('Cmd'), 'deviceId' => $request->getQuery('DeviceId'), @@ -428,49 +407,49 @@ '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'); - + return $result; } - + /** * get existing device of owner or create new device for owner * - * @param string $ownerId - * @param array $requestParameters - * - * @return Syncroton_Model_IDevice + * @param unknown_type $ownerId + * @param unknown_type $deviceId + * @param unknown_type $deviceType + * @param unknown_type $userAgent + * @param unknown_type $protocolVersion + * @return Syncroton_Model_Device */ protected function _getUserDevice($ownerId, $requestParameters) { try { $device = $this->_deviceBackend->getUserDevice($ownerId, $requestParameters'deviceId'); - + $device->useragent = $requestParameters'userAgent'; $device->acsversion = $requestParameters'protocolVersion'; - $device->devicetype = $requestParameters'deviceType'; - + if ($device->isDirty()) { $device = $this->_deviceBackend->update($device); } - + } catch (Syncroton_Exception_NotFound $senf) { - $device = $this->_deviceBackend->create(new Syncroton_Model_Device( + $device = $this->_deviceBackend->create(new Syncroton_Model_Device(array( 'owner_id' => $ownerId, 'deviceid' => $requestParameters'deviceId', '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 + ))); } - /** @var Syncroton_Model_Device $device */ return $device; }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/TransactionManager.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/TransactionManager.php
Changed
@@ -1,7 +1,7 @@ <?php /** * Syncroton - * + * * @package Syncroton * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 * @copyright Copyright (c) 2008-2012 Metaways Infosystems GmbH (http://www.metaways.de) @@ -10,17 +10,17 @@ /** * Transaction Manger for Syncroton - * + * * This is the central class, all transactions within Syncroton must be handled with. - * For each supported transactionable (backend) this class start a real transaction on + * For each supported transactionable (backend) this class start a real transaction on * the first startTransaction request. - * + * * Transactions of all transactionable will be commited at once when all requested transactions * are being commited using this class. - * + * * Transactions of all transactionable will be roll back when one rollBack is requested * using this class. - * + * * @package Syncroton */ class Syncroton_TransactionManager implements Syncroton_TransactionManagerInterface @@ -28,30 +28,30 @@ /** * @var array holds all transactionables with open transactions */ - protected $_openTransactionables = ; - + protected $_openTransactionables = array(); + /** * @var array list of all open (not commited) transactions */ - protected $_openTransactions = ; + protected $_openTransactions = array(); /** - * @var ?Syncroton_TransactionManager + * @var Syncroton_TransactionManager */ - private static $_instance = null; - + private static $_instance = NULL; + /** * @var Zend_Log */ protected $_logger; - + /** * don't clone. Use the singleton. */ private function __clone() { - + } - + /** * constructor */ @@ -61,37 +61,35 @@ $this->_logger = Syncroton_Registry::get('loggerBackend'); } } - + /** - * @return Syncroton_TransactionManager + * @return Tinebase_TransactionManager */ - public static function getInstance() + public static function getInstance() { - if (self::$_instance === null) { - self::$_instance = new Syncroton_TransactionManager(); + if (self::$_instance === NULL) { + self::$_instance = new Syncroton_TransactionManager; } - + return self::$_instance; } - + /** * starts a transaction * * @param mixed $_transactionable * @return string transactionId - * @throws Exception + * @throws Tinebase_Exception_UnexpectedValue */ public function startTransaction($_transactionable) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " startTransaction request"); - } - + if (! in_array($_transactionable, $this->_openTransactionables)) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " new transactionable. Starting transaction on this resource"); - } - + if ($_transactionable instanceof Zend_Db_Adapter_Abstract) { #Tinebase_Backend_Sql_Command::setAutocommit($_transactionable,false); $_transactionable->beginTransaction(); @@ -99,20 +97,19 @@ $this->rollBack(); throw new Syncroton_Exception_UnexpectedValue('Unsupported transactionable!'); } - + array_push($this->_openTransactionables, $_transactionable); } - - $transactionId = sha1(mt_rand() . microtime()); + + $transactionId = sha1(mt_rand(). microtime()); array_push($this->_openTransactions, $transactionId); - - if ($this->_logger instanceof Zend_Log) { + + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " queued transaction with id $transactionId"); - } - + return $transactionId; } - + /** * commits a transaction * @@ -121,55 +118,51 @@ */ public function commitTransaction($_transactionId) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " commitTransaction request for $_transactionId"); - } - + $transactionIdx = array_search($_transactionId, $this->_openTransactions); if ($transactionIdx !== false) { unset($this->_openTransactions$transactionIdx); } - + $numOpenTransactions = count($this->_openTransactions); - + if ($numOpenTransactions === 0) { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " no more open transactions in queue commiting all transactionables"); - } foreach ($this->_openTransactionables as $transactionableIdx => $transactionable) { if ($transactionable instanceof Zend_Db_Adapter_Abstract) { $transactionable->commit(); #Tinebase_Backend_Sql_Command::setAutocommit($transactionable,true); } } - $this->_openTransactionables = ; - $this->_openTransactions = ; + $this->_openTransactionables = array(); + $this->_openTransactions = array(); } else { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " commiting defered, as there are still $numOpenTransactions in the queue"); - } } } - + /** * perform rollBack on all transactionables with open transactions - * + * * @return void */ public function rollBack() { - if ($this->_logger instanceof Zend_Log) { + if ($this->_logger instanceof Zend_Log) $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " rollBack request, rollBack all transactionables"); - } - + foreach ($this->_openTransactionables as $transactionable) { if ($transactionable instanceof Zend_Db_Adapter_Abstract) { $transactionable->rollBack(); #Tinebase_Backend_Sql_Command::setAutocommit($transactionable,true); } } - - $this->_openTransactionables = ; - $this->_openTransactions = ; + + $this->_openTransactionables = array(); + $this->_openTransactions = array(); } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/TransactionManagerInterface.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/TransactionManagerInterface.php
Changed
@@ -1,7 +1,7 @@ <?php /** * Syncroton - * + * * @package Syncroton * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 * @copyright Copyright (c) 2008-2012 Metaways Infosystems GmbH (http://www.metaways.de) @@ -10,35 +10,35 @@ /** * Transaction Manger for Syncroton - * + * * This is the central class, all transactions within Syncroton must be handled with. - * For each supported transactionable (backend) this class start a real transaction on + * For each supported transactionable (backend) this class start a real transaction on * the first startTransaction request. - * + * * Transactions of all transactionable will be commited at once when all requested transactions * are being commited using this class. - * + * * Transactions of all transactionable will be roll back when one rollBack is requested * using this class. - * + * * @package Syncroton */ interface Syncroton_TransactionManagerInterface { /** - * @return mixed + * @return Tinebase_TransactionManager */ public static function getInstance(); - + /** * starts a transaction * * @param mixed $_transactionable * @return string transactionId - * @throws Exception + * @throws Tinebase_Exception_UnexpectedValue */ public function startTransaction($_transactionable); - + /** * commits a transaction * @@ -46,10 +46,10 @@ * @return void */ public function commitTransaction($_transactionId); - + /** * perform rollBack on all transactionables with open transactions - * + * * @return void */ public function rollBack();
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Abstract.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Abstract.php
Changed
@@ -16,7 +16,7 @@ * @package Wbxml * @subpackage Wbxml */ - + abstract class Syncroton_Wbxml_Abstract { /** @@ -25,83 +25,83 @@ * @var resource */ protected $_stream; - + /** * the wbxml version * - * @var int + * @var string */ protected $_version; - + /** - * the Document Public Identifier + * the Document Public Identifier * * @var string */ protected $_dpi; - + /** * the current active dtd * - * @var Syncroton_Wbxml_Dtd_ActiveSync + * @var Syncroton_Wbxml_Dtd_Syncml_Abstract */ protected $_dtd; - + /** * the charSet used in the wbxml file * * @var string */ protected $_charSet; - + /** * currently active code page * - * @var Syncroton_Wbxml_Dtd_ActiveSync_Abstract + * @var array */ protected $_codePage; - + /** * see section 5.5 * */ - public const DPI_WELLKNOWN = 'WELLKNOWN'; - + const DPI_WELLKNOWN = 'WELLKNOWN'; + /** * see section 5.5 * */ - public const DPI_STRINGTABLE = 'STRINGTABLE'; - - public const SWITCH_PAGE = 0x00; - public const END = 0x01; - public const ENTITY = 0x02; - public const STR_I = 0x03; - public const LITERAL = 0x04; - public const EXT_I_0 = 0x40; - public const EXT_I_1 = 0x41; - public const EXT_I_2 = 0x42; - public const PI = 0x43; - public const LITERAL_C = 0x44; - public const EXT_T_0 = 0x80; - public const EXT_T_1 = 0x81; - public const EXT_T_2 = 0x82; - public const STR_T = 0x83; - public const LITERAL_A = 0x84; - public const EXT_0 = 0xC0; - public const EXT_1 = 0xC1; - public const EXT_2 = 0xC2; - public const OPAQUE = 0xC3; - public const LITERAL_AC = 0xC4; - + const DPI_STRINGTABLE = 'STRINGTABLE'; + + const SWITCH_PAGE = 0x00; + const END = 0x01; + const ENTITY = 0x02; + const STR_I = 0x03; + const LITERAL = 0x04; + const EXT_I_0 = 0x40; + const EXT_I_1 = 0x41; + const EXT_I_2 = 0x42; + const PI = 0x43; + const LITERAL_C = 0x44; + const EXT_T_0 = 0x80; + const EXT_T_1 = 0x81; + const EXT_T_2 = 0x82; + const STR_T = 0x83; + const LITERAL_A = 0x84; + const EXT_0 = 0xC0; + const EXT_1 = 0xC1; + const EXT_2 = 0xC2; + const OPAQUE = 0xC3; + const LITERAL_AC = 0xC4; + /** * the real name for this DPI is "unknown" * But Microsoft is using them for their ActiveSync stuff * instead defining their own DPI like the sycnml creators did * */ - public const DPI_1 = '-//AIRSYNC//DTD AirSync//EN'; - + const DPI_1 = '-//AIRSYNC//DTD AirSync//EN'; + /** * return wellknown identifiers * @@ -114,12 +114,12 @@ if(!defined('Syncroton_Wbxml_Abstract::DPI_' . $_uInt)) { throw new Syncroton_Wbxml_Exception('unknown wellknown identifier: ' . $_uInt); } - + $dpi = constant('Syncroton_Wbxml_Abstract::DPI_' . $_uInt); - + return $dpi; } - + /** * return multibyte integer * @@ -128,27 +128,27 @@ protected function _getMultibyteUInt() { $uInt = 0; - + do { $byte = $this->_getByte(); $uInt <<= 7; $uInt += ($byte & 127); } while (($byte & 128) != 0); - + return $uInt; } - + protected function _getByte() { $byte = fread($this->_stream, 1); - + if($byte === false) { throw new Syncroton_Wbxml_Exception("failed reading one byte"); } - + return ord($byte); } - + protected function _getOpaque($_length) { $string = ''; @@ -166,7 +166,7 @@ $string .= $chunk; $_length -= $len; } - + if (feof($this->_stream)) { break; } @@ -174,7 +174,7 @@ return $string; } - + /** * get a 0 terminated string * @@ -183,28 +183,28 @@ protected function _getTerminatedString() { $string = ''; - + while (($byte = $this->_getByte()) != 0) { $string .= chr($byte); - } - + } + return $string; } - + protected function _writeByte($_byte) { fwrite($this->_stream, chr($_byte)); } - + protected function _writeMultibyteUInt($_integer) { - $multibyte = null; + $multibyte = NULL; $remainder = $_integer; - + do { $byte = ($remainder & 127); $remainder >>= 7; - if($multibyte === null) { + if($multibyte === NULL) { $multibyte = chr($byte); } else { $multibyte = chr($byte | 128) . $multibyte; @@ -213,15 +213,15 @@ fwrite($this->_stream, $multibyte); } - + protected function _writeString($_string) { fwrite($this->_stream, $_string); } - + /** * write opaque string to stream - * + * * @param string|resource $_string * @throws Syncroton_Wbxml_Exception */ @@ -235,22 +235,22 @@ } $length = ftell($stream); rewind($stream); - - $this->_writeByte(Syncroton_Wbxml_Abstract::OPAQUE); + + $this->_writeByte(Syncroton_Wbxml_Abstract::OPAQUE); $this->_writeMultibyteUInt($length); - $writenBytes = stream_copy_to_stream($stream, $this->_stream); - - if($writenBytes !== $length) { - throw new Syncroton_Wbxml_Exception('blow'); + $writenBytes = stream_copy_to_stream($stream, $this->_stream); + + if($writenBytes !== $length) { + throw new Syncroton_Wbxml_Exception('blow'); } - + fclose($stream); } - + protected function _writeTerminatedString($_string) { $this->_writeByte(Syncroton_Wbxml_Abstract::STR_I); fwrite($this->_stream, $_string); fwrite($this->_stream, chr(0)); } -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Decoder.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Decoder.php
Changed
@@ -16,30 +16,30 @@ * @package Wbxml * @subpackage Wbxml */ - + class Syncroton_Wbxml_Decoder extends Syncroton_Wbxml_Abstract { /** - * type of Document Public Identifier + * type of Document Public Identifier * * @var string the type can be Syncroton_Wbxml_Abstract::DPI_STRINGTABLE or Syncroton_Wbxml_Abstract::DPI_WELLKNOWN */ protected $_dpiType; - + /** * the string table * * @var array */ - protected $_stringTable = ; - + protected $_stringTable = array(); + /** * the xml document * * @var DOMDocument */ protected $_dom; - + /** * the main name space / aka the namespace of first tag * @@ -52,39 +52,39 @@ * * @param resource $_stream */ - public function __construct($_stream, $_dpi = null) + public function __construct($_stream, $_dpi = NULL) { if(!is_resource($_stream) || get_resource_type($_stream) != 'stream') { throw new Syncroton_Wbxml_Exception('$_stream must be a stream'); } - if($_dpi !== null) { + if($_dpi !== NULL) { $this->_dpi = $_dpi; } - + $this->_stream = $_stream; - + $this->_version = $this->_getByte(); - + if(feof($this->_stream)) { throw new Syncroton_Wbxml_Exception_UnexpectedEndOfFile(); } - + $this->_getDPI(); - + $this->_getCharset(); - + $this->_getStringTable(); - + // resolve DPI as we have read the stringtable now // this->_dpi contains the string table index if($this->_dpiType === Syncroton_Wbxml_Abstract::DPI_STRINGTABLE) { $this->_dpi = $this->_stringTable$this->_dpi; } - + #$this->_dtd = Syncroton_Wbxml_Dtd_Factory::factory($this->_dpi); $this->_dtd = Syncroton_Wbxml_Dtd_Factory::factory(Syncroton_Wbxml_Dtd_Factory::ACTIVESYNC); } - + /** * return the Document Public Identifier * @@ -95,37 +95,37 @@ { return $this->_dpi; } - + /** * return the wbxml version * - * @return int + * @return string */ public function getVersion() { return $this->_version; } - + /** - * decodes the tags + * decodes the tags * * @return DOMDocument the decoded xml */ public function decode() { - $openTags = null; - $node = null; + $openTags = NULL; + $node = NULL; $this->_codePage = $this->_dtd->getCurrentCodePage(); - + while (!feof($this->_stream)) { $byte = $this->_getByte(); - + switch($byte) { case Syncroton_Wbxml_Abstract::END: $node = $node->parentNode; $openTags--; break; - + case Syncroton_Wbxml_Abstract::OPAQUE: $length = $this->_getMultibyteUInt(); if($length > 0) { @@ -133,14 +133,14 @@ try { // let see if we can decode it. maybe the opaque data is wbxml encoded content $opaqueDataStream = fopen("php://temp", 'r+'); - fwrite($opaqueDataStream, $opaque); + fputs($opaqueDataStream, $opaque); rewind($opaqueDataStream); - + $opaqueContentDecoder = new Syncroton_Wbxml_Decoder($opaqueDataStream); $dom = $opaqueContentDecoder->decode(); - + fclose($opaqueDataStream); - + foreach($dom->childNodes as $newNode) { if($newNode instanceof DOMElement) { $newNode = $this->_dom->importNode($newNode, true); @@ -149,22 +149,22 @@ } } catch (Exception $e) { // if not, just treat it as a string - $node->appendChild($this->_dom->createTextNode($opaque)); + $node->appendChild($this->_dom->createTextNode($opaque)); } } break; - + case Syncroton_Wbxml_Abstract::STR_I: $string = $this->_getTerminatedString(); - $node->appendChild($this->_dom->createTextNode($string)); + $node->appendChild($this->_dom->createTextNode($string)); break; - + case Syncroton_Wbxml_Abstract::SWITCH_PAGE: $page = $this->_getByte(); $this->_codePage = $this->_dtd->switchCodePage($page); #echo "switched to codepage $page\n"; break; - + default: $tagHasAttributes = (($byte & 0x80) != 0); $tagHasContent = (($byte & 0x40) != 0); @@ -179,10 +179,10 @@ } $nameSpace = $this->_codePage->getNameSpace(); $codePageName = $this->_codePage->getCodePageName(); - + #echo "Tag: $nameSpace:$tag\n"; - - if ($node === null) { + + if ($node === NULL) { // create the domdocument $node = $this->_createDomDocument($nameSpace, $tag); $newNode = $node->documentElement; @@ -192,23 +192,23 @@ } $newNode = $node->appendChild($this->_dom->createElementNS('uri:' . $codePageName, $tag)); } - + if ($tagHasAttributes) { $attributes = $this->_getAttributes(); } - + if ($tagHasContent == true) { $node = $newNode; $openTags++; } - + break; } } return $this->_dom; } - + /** * creates the root of the xml document * @@ -217,7 +217,7 @@ protected function _createDomDocument($_nameSpace, $_tag) { $this->_dom = $this->_dtd->getDomDocument($_nameSpace, $_tag); - + return $this->_dom; } @@ -239,7 +239,7 @@ protected function _getDPI() { $uInt = $this->_getMultibyteUInt(); - + if($uInt == 0) { // get identifier from stringtable $this->_dpiType = Syncroton_Wbxml_Abstract::DPI_STRINGTABLE; @@ -251,25 +251,27 @@ $this->_dpi = Syncroton_Wbxml_Abstract::getDPI($uInt); } } - + /** * see http://www.iana.org/assignments/character-sets (MIBenum) * 106: UTF-8 + * */ protected function _getCharset() { $uInt = $this->_getMultibyteUInt(); - + switch($uInt) { case 106: $this->_charSet = 'UTF-8'; break; - + default: throw new Syncroton_Wbxml_Exception('unsuported charSet: ' . $uInt); + break; } } - + /** * get string table and store strings indexed by start * @@ -278,27 +280,27 @@ protected function _getStringTable() { $length = $this->_getMultibyteUInt(); - + if($length > 0) { $rawStringTable = $this->_getOpaque($length); - $index = null; - $string = null; - + $index = NULL; + $string = NULL; + for($i = 0; $i < strlen($rawStringTable); $i++) { - if($index === null) { + if($index === NULL) { $index = $i; } if(ord($rawStringTable$i) != 0) { $string .= $rawStringTable$i; } - + // either the string has ended or we reached a \0 - if($i + 1 == strlen($rawStringTable) || ord($rawStringTable$i) == 0) { + if($i+1 == strlen($rawStringTable) || ord($rawStringTable$i) == 0){ $this->_stringTable$index = $string; - $index = null; - $string = null; + $index = NULL; + $string = NULL; } } } - } -} + } +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync.php
Changed
@@ -19,39 +19,39 @@ class Syncroton_Wbxml_Dtd_ActiveSync { - public const CODEPAGE_AIRSYNC = 0; - public const CODEPAGE_CONTACTS = 1; - public const CODEPAGE_EMAIL = 2; - public const CODEPAGE_AIRNOTIFY = 3; - public const CODEPAGE_CALENDAR = 4; - public const CODEPAGE_MOVE = 5; - public const CODEPAGE_ITEMESTIMATE = 6; - public const CODEPAGE_FOLDERHIERARCHY = 7; - public const CODEPAGE_MEETINGRESPONSE = 8; - public const CODEPAGE_TASKS = 9; - public const CODEPAGE_RESOLVERECIPIENTS = 10; - public const CODEPAGE_VALIDATECERT = 11; - public const CODEPAGE_CONTACTS2 = 12; - public const CODEPAGE_PING = 13; - public const CODEPAGE_PROVISION = 14; - public const CODEPAGE_SEARCH = 15; - public const CODEPAGE_GAL = 16; - public const CODEPAGE_AIRSYNCBASE = 17; - public const CODEPAGE_SETTINGS = 18; - public const CODEPAGE_DOCUMENTLIBRARY = 19; - public const CODEPAGE_ITEMOPERATIONS = 20; - public const CODEPAGE_COMPOSEMAIL = 21; - public const CODEPAGE_EMAIL2 = 22; - public const CODEPAGE_NOTES = 23; - public const CODEPAGE_RIGHTSMANAGEMENT = 24; - + const CODEPAGE_AIRSYNC = 0; + const CODEPAGE_CONTACTS = 1; + const CODEPAGE_EMAIL = 2; + const CODEPAGE_AIRNOTIFY = 3; + const CODEPAGE_CALENDAR = 4; + const CODEPAGE_MOVE = 5; + const CODEPAGE_ITEMESTIMATE = 6; + const CODEPAGE_FOLDERHIERARCHY = 7; + const CODEPAGE_MEETINGRESPONSE = 8; + const CODEPAGE_TASKS = 9; + const CODEPAGE_RESOLVERECIPIENTS = 10; + const CODEPAGE_VALIDATECERT = 11; + const CODEPAGE_CONTACTS2 = 12; + const CODEPAGE_PING = 13; + const CODEPAGE_PROVISION = 14; + const CODEPAGE_SEARCH = 15; + const CODEPAGE_GAL = 16; + const CODEPAGE_AIRSYNCBASE = 17; + const CODEPAGE_SETTINGS = 18; + const CODEPAGE_DOCUMENTLIBRARY = 19; + const CODEPAGE_ITEMOPERATIONS = 20; + const CODEPAGE_COMPOSEMAIL = 21; + const CODEPAGE_EMAIL2 = 22; + const CODEPAGE_NOTES = 23; + const CODEPAGE_RIGHTSMANAGEMENT = 24; + /** * variable to hold currently active codepage * * @var Syncroton_Wbxml_Dtd_ActiveSync_Abstract */ protected $_currentCodePage; - + /** * the constructor * @@ -60,17 +60,17 @@ { $this->_currentCodePage = new Syncroton_Wbxml_Dtd_ActiveSync_CodePage0(); } - + /** * returns reference to current codepage * * @return Syncroton_Wbxml_Dtd_ActiveSync_Abstract */ - public function getCurrentCodePage() + public function getCurrentCodePage() { return $this->_currentCodePage; } - + /** * switch to another codepage * @@ -80,12 +80,12 @@ public function switchCodePage($_codePageId) { $className = 'Syncroton_Wbxml_Dtd_ActiveSync_CodePage' . $_codePageId; - + $this->_currentCodePage = new $className(); - + return $this->_currentCodePage; } - + /** * get initial dom document * @@ -95,16 +95,16 @@ { // 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 $dom = $imp->createDocument($_nameSpace, $_tag, $dtd); - + $dom->encoding = 'utf-8'; $dom->formatOutput = false; - + return $dom; } -} +}
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/Abstract.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/Abstract.php
Changed
@@ -16,49 +16,49 @@ * @package Wbxml * @subpackage ActiveSync */ - + abstract class Syncroton_Wbxml_Dtd_ActiveSync_Abstract { /** * codepage number * - * @var ?integer + * @var integer */ - protected $_codePageNumber = null; - + protected $_codePageNumber = NULL; + /** * codepage name * - * @var ?string + * @var string */ - protected $_codePageName = null; + protected $_codePageName = NULL; /** * document page identifier * not needed for ActiveSync * - * @var ?integer + * @var integer */ - protected $_dpi = null; - + protected $_dpi = NULL; + /** * mapping of tags to id's * * @var array */ - protected $_tags = ; - + protected $_tags = array(); + /** * return document page identifier * is always NULL for activesync * - * @return int|null + * @return unknown */ public function getDPI() { return $this->_dpi; } - + /** * get codepage name * @@ -68,7 +68,7 @@ { return $this->_codePageName; } - + /** * get namespace identifier * @@ -78,7 +78,7 @@ { return 'uri:' . $this->_codePageName; } - + /** * get tag identifier * @@ -94,21 +94,21 @@ return $this->_tags$_tag; } - + /** * return tag by given identity * - * @param int $_identity - * @return mixed + * @param unknown_type $_identity + * @return unknown */ public function getTag($_identity) { $tag = array_search($_identity, $this->_tags); - + if($tag === false) { throw new Syncroton_Wbxml_Exception("identity $_identity not found"); } - + return $tag; } -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage0.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage0.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage0 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 0; - + protected $_codePageName = 'AirSync'; - - protected $_tags = + + protected $_tags = array( 'Sync' => 0x05, 'Responses' => 0x06, 'Add' => 0x07, @@ -59,6 +59,6 @@ 'Partial' => 0x26, 'ConversationMode' => 0x27, 'MaxItems' => 0x28, - 'HeartbeatInterval' => 0x29, - ; -} + 'HeartbeatInterval' => 0x29 + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage1.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage1.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage1 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 1; - + protected $_codePageName = 'Contacts'; - - protected $_tags = + + protected $_tags = array( 'Anniversary' => 0x05, 'AssistantName' => 0x06, 'AssistantPhoneNumber' => 0x07, @@ -80,6 +80,6 @@ 'Rtf' => 0x3b, 'Picture' => 0x3c, 'Alias' => 0x3d, - 'WeightedRank' => 0x3e, - ; -} + 'WeightedRank' => 0x3e + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage10.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage10.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage10 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 10; - + protected $_codePageName = 'ResolveRecipients'; - - protected $_tags = + + protected $_tags = array( 'ResolveRecipients' => 0x05, 'Response' => 0x06, 'Status' => 0x07, @@ -47,6 +47,6 @@ 'Picture' => 0x1a, 'MaxSize' => 0x1b, 'Data' => 0x1c, - 'MaxPictures' => 0x1d, - ; -} + 'MaxPictures' => 0x1d + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage11.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage11.php
Changed
@@ -15,19 +15,19 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage11 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 11; - + protected $_codePageName = 'ValidateCert'; - - protected $_tags = + + protected $_tags = array( 'ValidateCert' => 0x05, 'Certificates' => 0x06, 'Certificate' => 0x07, 'CertificateChain' => 0x08, 'CheckCRL' => 0x09, - 'Status' => 0x0a, - ; -} + 'Status' => 0x0a + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage12.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage12.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage12 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 12; - + protected $_codePageName = 'Contacts2'; - - protected $_tags = + + protected $_tags = array( 'CustomerId' => 0x05, 'GovernmentId' => 0x06, 'IMAddress' => 0x07, @@ -32,6 +32,6 @@ 'CompanyMainPhone' => 0x0b, 'AccountName' => 0x0c, 'NickName' => 0x0d, - 'MMS' => 0x0e, - ; -} + 'MMS' => 0x0e + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage13.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage13.php
Changed
@@ -21,7 +21,7 @@ protected $_codePageName = 'Ping'; - protected $_tags = + protected $_tags = array( 'Ping' => 0x05, 'AutdState' => 0x06, //unused 'Status' => 0x07, @@ -30,6 +30,6 @@ 'Folder' => 0x0a, 'Id' => 0x0b, 'Class' => 0x0c, - 'MaxFolders' => 0x0d, - ; + 'MaxFolders' => 0x0d + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage14.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage14.php
Changed
@@ -16,14 +16,14 @@ * @subpackage ActiveSync * @todo add missing tags */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage14 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 14; - + protected $_codePageName = 'Provision'; - - protected $_tags = + + protected $_tags = array( 'Provision' => 0x05, 'Policies' => 0x06, 'Policy' => 0x07, @@ -78,5 +78,5 @@ 'ApplicationName' => 0x38, 'ApprovedApplicationList' => 0x39, 'Hash' => 0x3a, - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage15.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage15.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage15 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 15; - + protected $_codePageName = 'Search'; - - protected $_tags = + + protected $_tags = array( 'Search' => 0x05, 'Store' => 0x07, 'Name' => 0x08, @@ -51,6 +51,6 @@ 'ConversationId' => 0x20, 'Picture' => 0x21, 'MaxSize' => 0x22, - 'MaxPictures' => 0x23, - ; -} + 'MaxPictures' => 0x23 + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage16.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage16.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage16 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 16; - + protected $_codePageName = 'GAL'; - - protected $_tags = + + protected $_tags = array( 'DisplayName' => 0x05, 'Phone' => 0x06, 'Office' => 0x07, @@ -37,5 +37,5 @@ 'Picture' => 0x10, 'Status' => 0x11, 'Data' => 0x12, - ; -} + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage17.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage17.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage17 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 17; - + protected $_codePageName = 'AirSyncBase'; - - protected $_tags = + + protected $_tags = array( 'BodyPreference' => 0x05, 'Type' => 0x06, 'TruncationSize' => 0x07, @@ -45,5 +45,5 @@ 'BodyPartReference' => 0x19, 'BodyPart' => 0x1a, 'Status' => 0x1b, - ; -} + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage18.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage18.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage18 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 18; - + protected $_codePageName = 'Settings'; - - protected $_tags = + + protected $_tags = array( 'Settings' => 0x05, 'Status' => 0x06, 'Get' => 0x07, @@ -61,5 +61,5 @@ 'UserDisplayName' => 0x28, 'SendDisabled' => 0x29, 'RightsManagementInformation' => 0x2b, - ; + ); }
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage19.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage19.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage19 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 19; - + protected $_codePageName = 'DocumentLibrary'; - - protected $_tags = + + protected $_tags = array( 'LinkId' => 0x05, 'DisplayName' => 0x06, 'IsFolder' => 0x07, @@ -30,6 +30,6 @@ 'LastModifiedDate' => 0x09, 'IsHidden' => 0x0a, 'ContentLength' => 0x0b, - 'ContentType' => 0x0c, - ; -} + 'ContentType' => 0x0c + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage2.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage2.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage2 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 2; - + protected $_codePageName = 'Email'; - - protected $_tags = + + protected $_tags = array( 'Attachment' => 0x05, 'Attachments' => 0x06, 'AttName' => 0x07, @@ -81,6 +81,6 @@ 'ContentClass' => 0x3c, 'FlagType' => 0x3d, 'CompleteTime' => 0x3e, - 'DisallowNewTimeProposal' => 0x3f, - ; -} + 'DisallowNewTimeProposal' => 0x3f + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage20.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage20.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage20 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 20; - + protected $_codePageName = 'ItemOperations'; - - protected $_tags = + + protected $_tags = array( 'ItemOperations' => 0x05, 'Fetch' => 0x06, 'Store' => 0x07, @@ -44,5 +44,5 @@ 'DstFldId' => 0x17, 'ConversationId' => 0x18, 'MoveAlways' => 0x19, - ; -} + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage21.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage21.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage21 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 21; - + protected $_codePageName = 'ComposeMail'; - - protected $_tags = + + protected $_tags = array( 'SendMail' => 0x05, 'SmartForward' => 0x06, 'SmartReply' => 0x07, @@ -37,5 +37,5 @@ 'ClientId' => 0x11, 'Status' => 0x12, 'AccountId' => 0x13, - ; -} + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage22.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage22.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage22 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 22; - + protected $_codePageName = 'Email2'; - - protected $_tags = + + protected $_tags = array( 'UmCallerID' => 0x05, 'UmUserNotes' => 0x06, 'UmAttDuration' => 0x07, @@ -38,5 +38,5 @@ 'AccountId' => 0x11, 'FirstDayOfWeek' => 0x12, 'MeetingMessageType' => 0x13, - ; -} + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage23.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage23.php
Changed
@@ -15,18 +15,18 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage23 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 23; - + protected $_codePageName = 'Notes'; - - protected $_tags = + + protected $_tags = array( 'Subject' => 0x05, 'MessageClass' => 0x06, 'LastModifiedDate' => 0x07, 'Categories' => 0x08, 'Category' => 0x09, - ; -} + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage24.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage24.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage24 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 24; - + protected $_codePageName = 'RightsManagement'; - - protected $_tags = + + protected $_tags = array( 'RightsManagementSupport' => 0x05, 'RightsManagementTemplates' => 0x06, 'RightsManagementTemplate' => 0x07, @@ -42,7 +42,7 @@ 'TemplateID' => 0x15, 'TemplateDescription' => 0x16, 'ContentOwner' => 0x17, - 'RemoveRightsManagementDistribution' => 0x18, - ; - -} + 'RemoveRightsManagementDistribution' => 0x18 + ); + +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage254.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage254.php
Changed
@@ -19,13 +19,13 @@ class Syncroton_Wbxml_Dtd_ActiveSync_CodePage254 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 254; - + protected $_codePageName = 'WindowsLive'; - - protected $_tags = + + protected $_tags = array( 'Annotations' => 0x05, 'Annotation' => 0x06, 'Name' => 0x07, - 'Value' => 0x08, - ; -} + 'Value' => 0x08 + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage3.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage3.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage3 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 3; - + protected $_codePageName = 'AirNotify'; - - protected $_tags = + + protected $_tags = array( 'Notify' => 0x05, 'Notification' => 0x06, 'Version' => 0x07, @@ -41,9 +41,9 @@ 'Id' => 0x14, 'Expiry' => 0x15, 'NotifyGUID' => 0x16, - 'DeivceFriendlyName' => 0x17, - ; + 'DeivceFriendlyName' => 0x17 + ); // attribute page #"Version='1.1'" => 0x05, -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage4.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage4.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage4 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 4; - + protected $_codePageName = 'Calendar'; - - protected $_tags = + + protected $_tags = array( 'Timezone' => 0x05, 'AllDayEvent' => 0x06, 'Attendees' => 0x07, @@ -69,6 +69,6 @@ 'IsLeapMonth' => 0x38, 'FirstDayOfWeek' => 0x39, 'OnlineMeetingConfLink' => 0x3a, - 'OnlineMeetingExternalLink' => 0x3b, - ; -} + 'OnlineMeetingExternalLink' => 0x3b + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage5.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage5.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage5 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 5; protected $_codePageName = 'Move'; - protected $_tags = + protected $_tags = array( 'MoveItems' => 0x05, 'Move' => 0x06, 'SrcMsgId' => 0x07, @@ -30,6 +30,6 @@ 'DstFldId' => 0x09, 'Response' => 0x0a, 'Status' => 0x0b, - 'DstMsgId' => 0x0c, - ; -} + 'DstMsgId' => 0x0c + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage6.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage6.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage6 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 6; - + protected $_codePageName = 'ItemEstimate'; - - protected $_tags = + + protected $_tags = array( 'GetItemEstimate' => 0x05, 'Version' => 0x06, 'Collections' => 0x07, @@ -32,6 +32,6 @@ 'DateTime' => 0x0b, 'Estimate' => 0x0c, 'Response' => 0x0d, - 'Status' => 0x0e, - ; -} + 'Status' => 0x0e + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage7.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage7.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage7 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 7; - + protected $_codePageName = 'FolderHierarchy'; - - protected $_tags = + + protected $_tags = array( 'Folders' => 0x05, 'Folder' => 0x06, 'DisplayName' => 0x07, @@ -42,6 +42,6 @@ 'FolderUpdate' => 0x15, 'FolderSync' => 0x16, 'Count' => 0x17, - 'Version' => 0x18, // not used anymore - ; -} + 'Version' => 0x18 // not used anymore + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage8.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage8.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage8 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 8; - + protected $_codePageName = 'MeetingResponse'; - - protected $_tags = + + protected $_tags = array( 'CalendarId' => 0x05, 'CollectionId' => 0x06, 'MeetingResponse' => 0x07, @@ -32,6 +32,6 @@ 'Status' => 0x0b, 'UserResponse' => 0x0c, 'Version' => 0x0d, // not used anymore - 'InstanceId' => 0x0e, - ; -} + 'InstanceId' => 0x0e + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage9.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage9.php
Changed
@@ -15,14 +15,14 @@ * @package Wbxml * @subpackage ActiveSync */ - + class Syncroton_Wbxml_Dtd_ActiveSync_CodePage9 extends Syncroton_Wbxml_Dtd_ActiveSync_Abstract { protected $_codePageNumber = 9; - + protected $_codePageName = 'Tasks'; - - protected $_tags = + + protected $_tags = array( 'Body' => 0x05, 'BodySize' => 0x06, 'BodyTruncated' => 0x07, @@ -57,5 +57,5 @@ 'CalendarType' => 0x24, 'IsLeapMonth' => 0x25, 'FirstDayOfWeek' => 0x26, - ; -} + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Exception/CodePageNotFound.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Exception/CodePageNotFound.php
Changed
@@ -16,7 +16,7 @@ * @package Wbxml * @subpackage Wbxml */ - -class Syncroton_Wbxml_Dtd_Exception_CodePageNotFound extends Exception -{ -} + + class Syncroton_Wbxml_Dtd_Exception_CodePageNotFound extends Exception + { + } \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Factory.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Factory.php
Changed
@@ -16,28 +16,34 @@ * @package Wbxml * @subpackage Wbxml */ + class Syncroton_Wbxml_Dtd_Factory { - public const ACTIVESYNC = 'AirSync'; - public const SYNCML = 'SyncML'; - + const ACTIVESYNC='AirSync'; + + const SYNCML='SyncML'; + /** * factory function to return a selected contacts backend class * * @param string $type - * @return Syncroton_Wbxml_Dtd_ActiveSync + * @return Addressbook_Backend_Interface */ - public static function factory($type) + static public function factory ($_type) { - switch ($type) { + switch ($_type) { case self::ACTIVESYNC: $instance = new Syncroton_Wbxml_Dtd_ActiveSync(); break; - + + case self::SYNCML: + $instance = new Syncroton_Wbxml_Dtd_Syncml(); + break; + default: - throw new Syncroton_Wbxml_Exception('unsupported DTD: ' . $type); + throw new Syncroton_Wbxml_Exception('unsupported DTD: ' . $_type); + break; } - return $instance; } -} +}
View file
kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Syncml
Added
+(directory)
View file
kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Syncml.php
Added
@@ -0,0 +1,42 @@ +<?php +/** + * Syncroton + * + * @package Wbxml + * @subpackage Syncml + * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 + * @copyright Copyright (c) 2008-2009 Metaways Infosystems GmbH (http://www.metaways.de) + * @author Lars Kneschke <l.kneschke@metaways.de> + * @version $Id:Factory.php 4968 2008-10-17 09:09:33Z l.kneschke@metaways.de $ + */ + +/** + * class documentation + * + * @package Wbxml + * @subpackage Syncml + */ + +class Syncroton_Wbxml_Dtd_Syncml +{ + /** + * factory function to return a selected contacts backend class + * + * @param string $type + * @return Addressbook_Backend_Interface + */ + static public function factory ($_type) + { + switch ($_type) { + case 'syncml:syncml1.1': + case 'syncml:syncml1.2': + case 'syncml:metinf1.1': + case 'syncml:metinf1.2': + case 'syncml:devinf1.1': + case 'syncml:devinf1.2': + throw new Syncroton_Wbxml_Exception('unsupported DTD: ' . $_type); + break; + } + return $instance; + } +}
View file
kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Syncml/Abstract.php
Added
@@ -0,0 +1,103 @@ +<?php +/** + * Syncroton + * + * @package Wbxml + * @subpackage Syncml + * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 + * @copyright Copyright (c) 2008-2009 Metaways Infosystems GmbH (http://www.metaways.de) + * @author Lars Kneschke <l.kneschke@metaways.de> + * @version $Id:Abstract.php 4968 2008-10-17 09:09:33Z l.kneschke@metaways.de $ + */ + +/** + * class documentation + * + * @package Wbxml + * @subpackage Syncml + */ + +class Syncroton_Wbxml_Dtd_Syncml_Abstract +{ + protected $_tags; + + protected $_identity; + + protected $_codePages; + + protected $_currentCodePage; + + public function __construct($_initialCodePage = 0x00) + { + $this->switchCodePage($_initialCodePage); + } + + /** + * switch codepage + * + * @param integer $_id id of the codePage + * @return array + */ + public function switchCodePage($_id) + { + if(!isset($this->_codePages$_id)) { + throw new Syncroton_Wbxml_Dtd_Exception_CodePageNotFound('invalid codePage id: ' . $_id); + } + $this->_currentCodePage = $_id; + $this->_tags = $this->_codePages$this->_currentCodePage'tags'; + $this->_identity = array_flip($this->_tags); + + return $this->_codePages$this->_currentCodePage; + } + + /** + * get currently active codepage + * + * @return array + */ + public function getCurrentCodePage() + { + return $this->_codePages$this->_currentCodePage; + } + + public function getTag($_identity) + { + if(!isset($this->_identity$_identity)) { + throw new Syncroton_Wbxml_Exception("identity $_identity not found"); + } + + return $this->_identity$_identity; + } + + public function getIdentity($_tag) + { + if(!isset($this->_tags$_tag)) { + var_dump($this->_tags); + throw new Syncroton_Wbxml_Exception("tag $_tag not found"); + } + + return $this->_tags$_tag; + } + + /** + * switch codepage by urn + * + * @param string $_urn + * @return array + */ + public function switchCodePageByUrn($_urn) + { + $codePageNumber = NULL; + foreach($this->_codePages as $codePage) { + if($codePage'urn' == $_urn) { + $codePageNumber = $codePage'codePageNumber'; + } + } + + if($codePageNumber === NULL) { + throw new Syncroton_Wbxml_Dtd_Exception_CodePageNotFound("codePage with URN $_urn not found"); + } + + return $this->switchCodePage($codePageNumber); + } +} \ No newline at end of file
View file
kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Syncml/DevInfo11.php
Added
@@ -0,0 +1,71 @@ +<?php +/** + * Syncroton + * + * @package Wbxml + * @subpackage Syncml + * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 + * @copyright Copyright (c) 2008-2009 Metaways Infosystems GmbH (http://www.metaways.de) + * @author Lars Kneschke <l.kneschke@metaways.de> + * @version $Id:DevInfo11.php 4968 2008-10-17 09:09:33Z l.kneschke@metaways.de $ + */ + +/** + * class documentation + * + * @package Wbxml + * @subpackage Syncml + */ + +class Syncroton_Wbxml_Dtd_Syncml_DevInfo11 extends Syncroton_Wbxml_Dtd_Syncml_Abstract +{ + protected $_codePages = array( + 0x00 => array( + 'codePageNumber'=> 0x00, + 'dtdname' => 'DevInf', + 'dpi' => '-//SYNCML//DTD DevInf 1.1//EN', + 'url' => 'http://www.syncml.org/docs/devinf_v11_20020215.dtd', + 'urn' => 'syncml:devinf1.1', + 'tags' => array( + "CTCap" => 0x05, + "CTType" => 0x06, + "DataStore" => 0x07, + "DataType" => 0x08, + "DevID" => 0x09, + "DevInf" => 0x0a, + "DevTyp" => 0x0b, + "DisplayName" => 0x0c, + "DSMem" => 0x0d, + "Ext" => 0x0e, + "FwV" => 0x0f, + "HwV" => 0x10, + "Man" => 0x11, + "MaxGUIDSize" => 0x12, + "MaxID" => 0x13, + "MaxMem" => 0x14, + "Mod" => 0x15, + "OEM" => 0x16, + "ParamName" => 0x17, + "PropName" => 0x18, + "Rx" => 0x19, + "Rx-Pref" => 0x1a, + "SharedMem" => 0x1b, + "Size" => 0x1c, + "SourceRef" => 0x1d, + "SwV" => 0x1e, + "SyncCap" => 0x1f, + "SyncType" => 0x20, + "Tx" => 0x21, + "Tx-Pref" => 0x22, + "ValEnum" => 0x23, + "VerCT" => 0x24, + "VerDTD" => 0x25, + "XNam" => 0x26, + "XVal" => 0x27, + "UTC" => 0x28, + "SupportNumberOfChanges"=> 0x29, + "SupportLargeObjs" => 0x2a + ) + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Syncml/DevInfo12.php
Added
@@ -0,0 +1,80 @@ +<?php +/** + * Syncroton + * + * @package Wbxml + * @subpackage Syncml + * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 + * @copyright Copyright (c) 2008-2009 Metaways Infosystems GmbH (http://www.metaways.de) + * @author Lars Kneschke <l.kneschke@metaways.de> + * @version $Id:DevInfo12.php 4968 2008-10-17 09:09:33Z l.kneschke@metaways.de $ + */ + +/** + * class documentation + * + * @package Wbxml + * @subpackage Syncml + */ + +class Syncroton_Wbxml_Dtd_Syncml_DevInfo12 extends Syncroton_Wbxml_Dtd_Syncml_Abstract +{ + protected $_codePages = array( + 0x00 => array( + 'codePageNumber'=> 0x00, + 'dtdname' => 'DevInf', + 'dpi' => '-//OMA//DTD SYNCML-DEVINF 1.2//EN', + 'url' => 'http://www.openmobilealliance.org/tech/DTD/OMA-SyncML-Device_Information-DTD-1.2.dtd', + 'urn' => 'syncml:devinf1.2', + 'tags' => array( + "CTCap" => 0x05, + "CTType" => 0x06, + "DataStore" => 0x07, + "DataType" => 0x08, + "DevID" => 0x09, + "DevInf" => 0x0a, + "DevTyp" => 0x0b, + "DisplayName" => 0x0c, + "DSMem" => 0x0d, + "Ext" => 0x0e, + "FwV" => 0x0f, + "HwV" => 0x10, + "Man" => 0x11, + "MaxGUIDSize" => 0x12, + "MaxID" => 0x13, + "MaxMem" => 0x14, + "Mod" => 0x15, + "OEM" => 0x16, + "ParamName" => 0x17, + "PropName" => 0x18, + "Rx" => 0x19, + "Rx-Pref" => 0x1a, + "SharedMem" => 0x1b, + "Size" => 0x1c, + "SourceRef" => 0x1d, + "SwV" => 0x1e, + "SyncCap" => 0x1f, + "SyncType" => 0x20, + "Tx" => 0x21, + "Tx-Pref" => 0x22, + "ValEnum" => 0x23, + "VerCT" => 0x24, + "VerDTD" => 0x25, + "XNam" => 0x26, + "XVal" => 0x27, + "UTC" => 0x28, + "SupportNumberOfChanges"=> 0x29, + "SupportLargeObjs" => 0x2a, + "Property" => 0x2b, + "PropParam" => 0x2c, + "MaxOccur" => 0x2d, + "NoTruncate" => 0x2e, + "Filter-Rx" => 0x30, + "FilterCap" => 0x31, + "FilterKeyword" => 0x32, + "FieldLevel" => 0x33, + "SupportHierarchicalSync"=> 0x34 + ) + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Syncml/Syncml11.php
Added
@@ -0,0 +1,107 @@ +<?php +/** + * Syncroton + * + * @package Wbxml + * @subpackage Syncml + * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 + * @copyright Copyright (c) 2008-2009 Metaways Infosystems GmbH (http://www.metaways.de) + * @author Lars Kneschke <l.kneschke@metaways.de> + * @version $Id:Syncml11.php 4968 2008-10-17 09:09:33Z l.kneschke@metaways.de $ + */ + +/** + * class documentation + * + * @package Wbxml + * @subpackage Syncml + */ + +class Syncroton_Wbxml_Dtd_Syncml_Syncml11 extends Syncroton_Wbxml_Dtd_Syncml_Abstract +{ + protected $_codePages = array( + 0x00 => array( + 'codePageNumber'=> 0x00, + 'dtdname' => 'SyncML', + 'dpi' => '-//SYNCML//DTD SyncML 1.1//EN', + 'url' => "http://www.syncml.org/docs/syncml_represent_v11_20020213.dtd", + 'urn' => 'syncml:syncml1.1', + 'tags' => array( + 'Add' => 0x05, + 'Alert' => 0x06, + 'Archive' => 0x07, + 'Atomic' => 0x08, + 'Chal' => 0x09, + 'Cmd' => 0x0a, + 'CmdID' => 0x0b, + 'CmdRef' => 0x0c, + 'Copy' => 0x0d, + 'Cred' => 0x0e, + 'Data' => 0x0f, + 'Delete' => 0x10, + 'Exec' => 0x11, + 'Final' => 0x12, + 'Get' => 0x13, + 'Item' => 0x14, + 'Lang' => 0x15, + 'LocName' => 0x16, + 'LocURI' => 0x17, + 'Map' => 0x18, + 'MapItem' => 0x19, + 'Meta' => 0x1a, + 'MsgID' => 0x1b, + 'MsgRef' => 0x1c, + 'NoResp' => 0x1d, + 'NoResults' => 0x1e, + 'Put' => 0x1f, + 'Replace' => 0x20, + 'RespURI' => 0x21, + 'Results' => 0x22, + 'Search' => 0x23, + 'Sequence' => 0x24, + 'SessionID' => 0x25, + 'SftDel' => 0x26, + 'Source' => 0x27, + 'SourceRef' => 0x28, + 'Status' => 0x29, + 'Sync' => 0x2a, + 'SyncBody' => 0x2b, + 'SyncHdr' => 0x2c, + 'SyncML' => 0x2d, + 'Target' => 0x2e, + 'TargetRef' => 0x2f, + 'Reserved for future use.' => 0x30, + 'VerDTD' => 0x31, + 'VerProto' => 0x32, + 'NumberOfChanges' => 0x33, + 'MoreData' => 0x34 + ) + ), + 0x01 => array( + 'codePageNumber'=> 0x01, + 'dtdname' => 'MetInf', + 'dpi' => '-//SYNCML//DTD MetInf 1.1//EN', + 'url' => 'http://www.syncml.org/docs/syncml_metinf_v11_20020215.dtd ', + 'urn' => 'syncml:metinf1.1', + 'tags' => array( + 'Anchor' => 0x05, + 'EMI' => 0x06, + 'Format' => 0x07, + 'FreeID' => 0x08, + 'FreeMem' => 0x09, + 'Last' => 0x0a, + 'Mark' => 0x0b, + 'MaxMsgSize' => 0x0c, + 'Mem' => 0x0d, + 'MetInf' => 0x0e, + 'Next' => 0x0f, + 'NextNonce' => 0x10, + 'SharedMem' => 0x11, + 'Size' => 0x12, + 'Type' => 0x13, + 'Version' => 0x14, + 'MaxObjSize' => 0x15 + ) + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Dtd/Syncml/Syncml12.php
Added
@@ -0,0 +1,122 @@ +<?php +/** + * Syncroton + * + * @package Wbxml + * @subpackage Syncml + * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 + * @copyright Copyright (c) 2008-2009 Metaways Infosystems GmbH (http://www.metaways.de) + * @author Lars Kneschke <l.kneschke@metaways.de> + * @version $Id:Syncml12.php 4968 2008-10-17 09:09:33Z l.kneschke@metaways.de $ + */ + +/** + * class documentation + * + * @package Wbxml + * @subpackage Syncml + */ + +class Syncroton_Wbxml_Dtd_Syncml_Syncml12 extends Syncroton_Wbxml_Dtd_Syncml_Abstract +{ + + /** + * section 8.2 + * + * @var array + */ + protected $_codePages = array( + 0x00 => array( + 'codePageNumber'=> 0x00, + 'dtdname' => 'SyncML', + 'dpi' => '-//SYNCML//DTD SyncML 1.2//EN', + 'url' => 'http://www.openmobilealliance.org/tech/DTD/OMA-TS-SyncML_RepPro_DTD-V1_2.dtd', + 'urn' => 'SYNCML:SYNCML1.2', + 'tags' => array( + 'Add' => 0x05, + 'Alert' => 0x06, + 'Archive' => 0x07, + 'Atomic' => 0x08, + 'Chal' => 0x09, + 'Cmd' => 0x0a, + 'CmdID' => 0x0b, + 'CmdRef' => 0x0c, + 'Copy' => 0x0d, + 'Cred' => 0x0e, + 'Data' => 0x0f, + 'Delete' => 0x10, + 'Exec' => 0x11, + 'Final' => 0x12, + 'Get' => 0x13, + 'Item' => 0x14, + 'Lang' => 0x15, + 'LocName' => 0x16, + 'LocURI' => 0x17, + 'Map' => 0x18, + 'MapItem' => 0x19, + 'Meta' => 0x1a, + 'MsgID' => 0x1b, + 'MsgRef' => 0x1c, + 'NoResp' => 0x1d, + 'NoResults' => 0x1e, + 'Put' => 0x1f, + 'Replace' => 0x20, + 'RespURI' => 0x21, + 'Results' => 0x22, + 'Search' => 0x23, + 'Sequence' => 0x24, + 'SessionID' => 0x25, + 'SftDel' => 0x26, + 'Source' => 0x27, + 'SourceRef' => 0x28, + 'Status' => 0x29, + 'Sync' => 0x2a, + 'SyncBody' => 0x2b, + 'SyncHdr' => 0x2c, + 'SyncML' => 0x2d, + 'Target' => 0x2e, + 'TargetRef' => 0x2f, + 'Reserved for future use.' => 0x30, + 'VerDTD' => 0x31, + 'VerProto' => 0x32, + 'NumberOfChanges' => 0x33, + 'MoreData' => 0x34, + 'Field' => 0x35, + 'Filter' => 0x36, + 'Record' => 0x37, + 'FilterType' => 0x38, + 'SourceParent' => 0x39, + 'TargetParent' => 0x3a, + 'Move' => 0x3b, + 'Correlator' => 0x3c + ) + ), + 0x01 => array( + 'codePageNumber'=> 0x01, + 'dtdname' => 'MetInf', + 'dpi' => '-//OMA//DTD SYNCML-METINF 1.2//EN', + 'url' => 'http://www.openmobilealliance.org/tech/DTD/OMA-TS-SyncML_MetaInfo_DTD-V1_2.dtd', + 'urn' => 'syncml:metinf1.2', + 'tags' => array( + 'Anchor' => 0x05, + 'EMI' => 0x06, + 'Format' => 0x07, + 'FreeID' => 0x08, + 'FreeMem' => 0x09, + 'Last' => 0x0a, + 'Mark' => 0x0b, + 'MaxMsgSize' => 0x0c, + 'Mem' => 0x0d, + 'MetInf' => 0x0e, + 'Next' => 0x0f, + 'NextNonce' => 0x10, + 'SharedMem' => 0x11, + 'Size' => 0x12, + 'Type' => 0x13, + 'Version' => 0x14, + 'MaxObjSize' => 0x15, + 'FieldLevel' => 0x16 + ) + ) + ); +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Encoder.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Encoder.php
Changed
@@ -16,22 +16,64 @@ * @package Wbxml * @subpackage Wbxml */ - + class Syncroton_Wbxml_Encoder extends Syncroton_Wbxml_Abstract { /** + * stack of dtd objects + * + * @var array + */ + protected $_dtdStack = array(); + + /** + * stack of stream resources + * + * @var array + */ + protected $_streamStack = array(); + + /** + * stack of levels when to pop data from the other stacks + * + * @var array + */ + protected $_popStack = array(); + + /** * count level of tags * - * @var int + * @var string */ protected $_level = 0; - + + /** + * when to take data next time from the different stacks + * + * @var unknown_type + */ + protected $_nextStackPop = NULL; + + /** + * collect data trough different calls to _handleCharacters + * + * @var string + */ + protected $_currentTagData = NULL; + + /** + * the current tag as read by the parser + * + * @var string + */ + protected $_currentTag = NULL; + /** * the constructor * * @param resource $_stream - * @param string $_charSet - * @param int $_version + * @param string $_charSet + * @param integer $_version */ public function __construct($_stream, $_charSet = 'UTF-8', $_version = 2) { @@ -43,18 +85,18 @@ /** * initialize internal variables and write wbxml header to stream * - * @param DOMDocument $_dom + * @param string $_urn * @todo check if dpi > 0, instead checking the urn */ protected function _initialize($_dom) { $this->_dtd = Syncroton_Wbxml_Dtd_Factory::factory($_dom->doctype->name); $this->_codePage = $this->_dtd->getCurrentCodePage(); - + // the WBXML version $this->_writeByte($this->_version); - - if($this->_codePage->getDPI() === null) { + + if($this->_codePage->getDPI() === NULL) { // the document public identifier $this->_writeMultibyteUInt(1); } else { @@ -63,22 +105,22 @@ $this->_writeMultibyteUInt(0); // the offset of the DPI in the string table $this->_writeByte(0); - } - + } + // write the charSet $this->_writeCharSet($this->_charSet); - - if($this->_codePage->getDPI() === null) { + + if($this->_codePage->getDPI() === NULL) { // the length of the string table $this->_writeMultibyteUInt(0); } else { // the length of the string table $this->_writeMultibyteUInt(strlen($this->_codePage->getDPI())); // the dpi - $this->_writeString($this->_codePage->getDPI()); - } + $this->_writeString($this->_codePage->getDPI()); + } } - + /** * write charset to stream * @@ -91,95 +133,164 @@ case 'UTF-8': $this->_writeMultibyteUInt(106); break; - + default: throw new Syncroton_Wbxml_Exception('unsuported charSet ' . strtoupper($_charSet)); + break; } + } - + /** * start encoding of xml to wbxml * - * @param DOMDocument $_dom the DOM document + * @param string $_xml the xml string + * @return resource stream */ public function encode(DOMDocument $_dom) { $_dom->formatOutput = false; + + $tempStream = tmpfile(); + $meta_data = stream_get_meta_data($tempStream); + $filename = $meta_data"uri"; + $_dom->save($filename); + rewind($tempStream); + $this->_initialize($_dom); - $this->_traverseDom($_dom); - } - - private function getAttributes($node) - { - $attributes = ; - if ($node->attributes) { - for ($i = 0; $i < $node->attributes->length; ++$i) { - $attributes$node->attributes->item($i)->name = $node->attributes->item($i)->value; + + $parser = xml_parser_create_ns($this->_charSet, ';'); + xml_set_object($parser, $this); + xml_set_element_handler($parser, '_handleStartTag', '_handleEndTag'); + xml_set_character_data_handler($parser, '_handleCharacters'); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); + + while (!feof($tempStream)) { + if (!xml_parse($parser, fread($tempStream, 1048576), feof($tempStream))) { + // uncomment to write xml document to file + #rewind($tempStream); + #$xmlStream = fopen(tempnam(sys_get_temp_dir(), "xmlerrors"), 'r+'); + #stream_copy_to_stream($tempStream, $xmlStream); + #fclose($xmlStream); + + throw new Syncroton_Wbxml_Exception(sprintf('XML error: %s at line %d', + xml_error_string(xml_get_error_code($parser)), + xml_get_current_line_number($parser) + )); } } - return $attributes; - } - private function writeNode($node, $withContent = false, $data = null) - { - if($this->_codePage->getNameSpace() != $node->namespaceURI) { - $this->_switchCodePage($node->namespaceURI); - } - $this->_writeTag($node->localName, $this->getAttributes($node), $withContent, $data); + fclose($tempStream); + xml_parser_free($parser); } - protected function _traverseDom($_dom) + /** + * get's called by xml parser when tag starts + * + * @param resource $_parser + * @param string $_tag current tag prefixed with namespace + * @param array $_attributes list of tag attributes + */ + protected function _handleStartTag($_parser, $_tag, $_attributes) { - if ($_dom->childNodes->length == 0) { - return false; - } - // print(str_pad("", $this->_level, " ") . "traversing {$_dom->nodeName}" . "\n"); $this->_level++; - $prevNode = $_dom; - $foundElementNode = false; - foreach ($_dom->childNodes as $node) { - if ($node->nodeType == XML_ELEMENT_NODE) { - $foundElementNode = true; - if ($prevNode && $this->_level > 1) { - // print(str_pad("", $this->_level, " ") . "{$node->nodeName} creating parent {$prevNode->nodeName}" . "\n"); - $this->writeNode($prevNode, true); - $prevNode = null; - } - if (!$this->_traverseDom($node)) { - // print(str_pad("", $this->_level, " ") . "{$node->nodeName} content {$node->nodeValue}" . "\n"); - $data = $node->nodeValue; - if (strlen($data) == 0) { - $this->writeNode($node); - } else { - $this->writeNode($node, true, $data); - $this->_writeByte(Syncroton_Wbxml_Abstract::END); - // print("Closing tag after writing tag\n"); - } - } else { - $this->_writeByte(Syncroton_Wbxml_Abstract::END); - // print("Closing tag\n"); - } - } + $this->_currentTagData = null; + + // write data for previous tag happens whith <tag1><tag2> + if($this->_currentTag !== NULL) { + $this->_writeTag($this->_currentTag, $this->_attributes, true); } - $this->_level--; - return $foundElementNode; - } + list($nameSpace, $this->_currentTag) = explode(';', $_tag); + + if($this->_codePage->getNameSpace() != $nameSpace) { + $this->_switchCodePage($nameSpace); + } + $this->_attributes = $_attributes; + + } + /** * strip uri: from nameSpace * - * @param string $_nameSpace - * - * @return string + * @param unknown_type $_nameSpace + * @return unknown */ protected function _stripNameSpace($_nameSpace) { return substr($_nameSpace, 4); } + + /** + * get's called by xml parser when tag ends + * + * @param resource $_parser + * @param string $_tag current tag prefixed with namespace + */ + protected function _handleEndTag($_parser, $_tag) + { + #echo "$_tag Level: $this->_level == $this->_nextStackPop \n"; + + if($this->_nextStackPop !== NULL && $this->_nextStackPop == $this->_level) { + #echo "TAG: $_tag\n"; + $this->_writeByte(Syncroton_Wbxml_Abstract::END); + + $subStream = $this->_stream; + $subStreamLength = ftell($subStream); + + $this->_dtd = array_pop($this->_dtdStack); + $this->_stream = array_pop($this->_streamStack); + $this->_nextStackPop = array_pop($this->_popStack); + $this->_codePage = $this->_dtd->getCurrentCodePage(); + + rewind($subStream); + #while (!feof($subStream)) {$buffer = fgets($subStream, 4096);echo $buffer;} + $this->_writeByte(Syncroton_Wbxml_Abstract::OPAQUE); + $this->_writeMultibyteUInt($subStreamLength); + + $writenBytes = stream_copy_to_stream($subStream, $this->_stream); + if($writenBytes !== $subStreamLength) { + //echo "$writenBytes !== $subStreamLength\n"; + throw new Syncroton_Wbxml_Exception('blow'); + } + fclose($subStream); + #echo "$this->_nextStackPop \n"; exit; + } else { + if ($this->_currentTag !== NULL && $this->_currentTagData !== NULL) { + $this->_writeTag($this->_currentTag, $this->_attributes, true, $this->_currentTagData); + $this->_writeByte(Syncroton_Wbxml_Abstract::END); + } elseif ($this->_currentTag !== NULL && $this->_currentTagData === NULL) { + // for example <UTC/> tag with no data, jumps directly from _handleStartTag to _handleEndTag + $this->_writeTag($this->_currentTag, $this->_attributes); + // no end tag required, tag has no content + } else { + $this->_writeByte(Syncroton_Wbxml_Abstract::END); + } + } + + #list($urn, $tag) = explode(';', $_tag); echo "</$tag> ($this->_level)\n"; + + // reset $this->_currentTag, as tag got writen to stream already + $this->_currentTag = NULL; + + $this->_level--; + } /** + * collects data(value) of tag + * can be called multiple lines if the value contains linebreaks + * + * @param resource $_parser the xml parser + * @param string $_data the data(value) of the tag + */ + protected function _handleCharacters($_parser, $_data) + { + $this->_currentTagData .= $_data; + } + + /** * writes tag with data to stream * * @param string $_tag @@ -187,59 +298,75 @@ * @param bool $_hasContent * @param string $_data */ - protected function _writeTag($_tag, $_attributes = null, $_hasContent = false, $_data = null) + protected function _writeTag($_tag, $_attributes=NULL, $_hasContent=false, $_data=NULL) { - if($_hasContent == false && $_data !== null) { + if($_hasContent == false && $_data !== NULL) { throw new Syncroton_Wbxml_Exception('$_hasContent can not be false, when $_data !== NULL'); } - + // handle the tag $identity = $this->_codePage->getIdentity($_tag); - + if (is_array($_attributes) && isset($_attributes'uri:Syncroton;encoding')) { $encoding = 'opaque'; unset($_attributes'uri:Syncroton;encoding'); } else { $encoding = 'termstring'; } - + if(!empty($_attributes)) { $identity |= 0x80; } - + if($_hasContent == true) { $identity |= 0x40; } - + $this->_writeByte($identity); - + // handle the data - if($_data !== null) { + if($_data !== NULL) { if ($encoding == 'opaque') { - $this->_writeOpaqueString(base64_decode($_data)); + $this->_writeOpaqueString(base64_decode($_data)); } else { $this->_writeTerminatedString($_data); } } + + $this->_currentTagData = NULL; } /** * switch code page * - * @param string $_nameSpace + * @param string $_urn */ protected function _switchCodePage($_nameSpace) { - $codePageName = $this->_stripNameSpace($_nameSpace); - if(!defined('Syncroton_Wbxml_Dtd_ActiveSync::CODEPAGE_' . strtoupper($codePageName))) { - throw new Syncroton_Wbxml_Exception('codepage ' . $codePageName . ' not found'); + try { + $codePageName = $this->_stripNameSpace($_nameSpace); + if(!defined('Syncroton_Wbxml_Dtd_ActiveSync::CODEPAGE_'. strtoupper($codePageName))) { + throw new Syncroton_Wbxml_Exception('codepage ' . $codePageName . ' not found'); + } + // switch to another codepage + // no need to write the wbxml header again + $codePageId = constant('Syncroton_Wbxml_Dtd_ActiveSync::CODEPAGE_'. strtoupper($codePageName)); + $this->_codePage = $this->_dtd->switchCodePage($codePageId); + + $this->_writeByte(Syncroton_Wbxml_Abstract::SWITCH_PAGE); + $this->_writeByte($codePageId); + } catch (Syncroton_Wbxml_Dtd_Exception_CodePageNotFound $e) { + // switch to another dtd + // need to write the wbxml header again + // put old dtd and stream on stack + $this->_dtdStack = $this->_dtd; + $this->_streamStack = $this->_stream; + $this->_popStack = $this->_nextStackPop; + $this->_nextStackPop = $this->_level; + + $this->_stream = fopen("php://temp", 'r+'); + + $this->_initialize($_urn); } - // switch to another codepage - // no need to write the wbxml header again - $codePageId = constant('Syncroton_Wbxml_Dtd_ActiveSync::CODEPAGE_' . strtoupper($codePageName)); - $this->_codePage = $this->_dtd->switchCodePage($codePageId); - - $this->_writeByte(Syncroton_Wbxml_Abstract::SWITCH_PAGE); - $this->_writeByte($codePageId); } -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Exception.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Exception.php
Changed
@@ -17,7 +17,7 @@ * @subpackage Wbxml */ -class Syncroton_Wbxml_Exception extends Exception +class Syncroton_Wbxml_Exception extends Exception { protected $message = 'wbxml exception'; -} +} \ No newline at end of file
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Wbxml/Exception/UnexpectedEndOfFile.php -> kolab-syncroton-2.3.22.tar.gz/lib/ext/Syncroton/Wbxml/Exception/UnexpectedEndOfFile.php
Changed
@@ -19,5 +19,5 @@ class Syncroton_Wbxml_Exception_UnexpectedEndOfFile extends Syncroton_Wbxml_Exception { - protected $message = 'unexpected end of file detected'; -} + protected $message = 'unexpcted end of file detected'; +} \ No newline at end of file
View file
kolab-syncroton-2.3.22.tar.gz/lib/ext/rtf.php
Added
@@ -0,0 +1,705 @@ +<?php +/* + This class contains code from rtfclass.php that was written by Markus Fischer and placed by him under + GPLv2 License. + + =======================================NOTES FROM ORIGINAL AUTHOR==================================== + Rich Text Format - Parsing Class + ================================ + + (c) 2000 Markus Fischer + <mfischer@josefine.ben.tuwien.ac.at> + http://josefine.ben.tuwien.ac.at/~mfischer/ + + Latest versions of this class can always be found at + http://josefine.ben.tuwien.ac.at/~mfischer/developing/php/rtf/rtfclass.phps + Testing suite is available at + http://josefine.ben.tuwien.ac.at/~mfischer/developing/php/rtf/ + + License: GPLv2 + + Specification: + http://msdn.microsoft.com/library/default.asp?URL=/library/specs/rtfspec.htm + + General Notes: + ============== + Unknown or unspupported control symbols are silently gnored + + Group stacking is still not supported :( + group stack logic implemented; however not really used yet + ===================================================================================================== + + It was modified by me (Andreas Brodowski) to allow compressed RTF being uncompressed by code I ported from + Java to PHP and adapted according the needs of Z-Push. + + Currently it is being used to detect empty RTF Streams from Nokia Phones in MfE Clients + + It needs to be used by other backend writers that needs to have notes in calendar, appointment or tasks + objects to be written to their databases since devices send them usually in RTF Format... With Zarafa + you can write them directly to DB and Zarafa is doing the conversion job. Other Groupware systems usually + don't have this possibility... + + Aleksander Machniak <machniak@kolabsys.com> fixed some deprecated function usage and some small issues + +*/ + + +class rtf { + var $LZRTF_HDR_DATA = "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscript \\fdecor MS Sans SerifSymbolArialTimes New RomanCourier{\\colortbl\\red0\\green0\\blue0\n\r\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx"; + var $LZRTF_HDR_LEN = 207; + var $CRC32_TABLE = array( 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3, + 0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7, + 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B, + 0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, + 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433, + 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457, + 0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB, + 0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F, + 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683, + 0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7, + 0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, + 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F, + 0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713, + 0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777, + 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB, + 0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF, + 0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, + ); + + var $rtf; // rtf core stream + var $rtf_len; // length in characters of the stream (get performace due avoiding calling strlen everytime) + var $err = array(); // array of error message, no entities on no error + + var $wantXML; // convert to XML + var $wantHTML; // convert to HTML + var $wantASCII; // convert to HTML + + // the only variable which should be accessed from the outside + var $out; // output data stream (depends on which $wantXXXXX is set to true + var $outstyles; // htmlified styles (generated after parsing if wantHTML + var $styles = array(); // if wantHTML, stylesheet definitions are put in here + + // internal parser variables -------------------------------- + // control word variables + var $cword; // holds the current (or last) control word, depending on $cw + var $cw; // are we currently parsing a control word ? + var $cfirst; // could this be the first character ? so watch out for control symbols + + var $flags = array(); // parser flags + + var $queue; // every character which is no sepcial char, not belongs to a control word/symbol; is generally considered being 'plain' + + var $stack = array(); // group stack + + /* keywords which don't follw the specification (used by Word '97 - 2000) */ + // not yet used + var $control_exception = array( + "clFitText", + "clftsWidth(-?0-9+)?", + "clNoWrap(-?0-9+)?", + "clwWidth(-?0-9+)?", + "tdfrmtxtBottom(-?0-9+)?", + "tdfrmtxtLeft(-?0-9+)?", + "tdfrmtxtRight(-?0-9+)?", + "tdfrmtxtTop(-?0-9+)?", + "trftsWidthA(-?0-9+)?", + "trftsWidthB(-?0-9+)?", + "trftsWidth(-?0-9+)?", + "trwWithA(-?0-9+)?", + "trwWithB(-?0-9+)?", + "trwWith(-?0-9+)?", + "spectspecifygen(-?0-9+)?", + ); + + var $charset_table = array( + "0" => "ANSI", + "1" => "Default", + "2" => "Symbol", + "77" => "Mac", + "128" => "Shift Jis", + "129" => "Hangul", + "130" => "Johab", + "134" => "GB2312", + "136" => "Big5", + "161" => "Greek", + "162" => "Turkish", + "163" => "Vietnamese", + "177" => "Hebrew", + "178" => "Arabic", + "179" => "Arabic Traditional", + "180" => "Arabic user", + "181" => "Hebrew user", + "186" => "Baltic", + "204" => "Russian", + "222" => "Thai", + "238" => "Eastern European", + "255" => "PC 437", + "255" => "OEM", + ); + + /* note: the only conversion table used */ + var $fontmodifier_table = array( + "bold" => "b", + "italic" => "i", + "underlined" => "u", + "strikethru" => "strike", + ); + + + function __construct() { + $this->rtf_len = 0; + $this->rtf = ''; + + $this->out = ''; + } + + // loadrtf - load the raw rtf data to be converted by this class + // data = the raw rtf + function loadrtf($data) { + if (($this->rtf = $this->uncompress($data))) { + $this->rtf_len = strlen($this->rtf); + }; + if($this->rtf_len == 0) { + debugLog("No data in stream found"); + return false; + }; + return true; + } + + function output($typ) { + switch($typ) { + case "ascii": $this->wantASCII = true; break; + case "xml": $this->wantXML = true; break; + case "html": $this->wantHTML = true; break; + default: break; + } + } + + // uncompress - uncompress compressed rtf data + // src = the compressed raw rtf in LZRTF format + function uncompress($src) { + $header = unpack("LcSize/LuSize/Lmagic/Lcrc32",substr($src,0,16)); + $in = 16; + if ($header'cSize' != strlen($src)-4) { + debugLog("Stream too short"); + return false; + } + + if ($header'crc32' != $this->LZRTFCalcCRC32($src,16,(($header'cSize'+4))-16)) { + debugLog("CRC MISMATCH"); + return false; + } + + if ($header'magic' == 0x414c454d) { // uncompressed RTF - return as is. + $dest = substr($src,$in,$header'uSize'); + } else if ($header'magic' == 0x75465a4c) { // compressed RTF - uncompress. + $dst = $this->LZRTF_HDR_DATA; + $out = $this->LZRTF_HDR_LEN; + $oblen = $this->LZRTF_HDR_LEN + $header'uSize'; + $flagCount = 0; + $flags = 0; + while ($out<$oblen) { + $flags = ($flagCount++ % 8 == 0) ? ord($src$in++) : $flags >> 1; + if (($flags & 1) == 1) { + $offset = ord($src$in++); + $length = ord($src$in++); + $offset = ($offset << 4) | ($length >> 4); + $length = ($length & 0xF) + 2; + $offset = (int)($out / 4096) * 4096 + $offset; + if ($offset >= $out) $offset -= 4096; + $end = $offset + $length; + while ($offset < $end) { + $dst$out++ = $dst$offset++; + }; + } else { + $dst$out++ = $src$in++; + } + } + $src = $dst; + $dest = substr($src,$this->LZRTF_HDR_LEN,$header'uSize'); + } else { // unknown magic - returfn false (please report if this ever happens) + debugLog("Unknown Magic"); + return false; + } + + return $dest; + } + + // LZRTFCalcCRC32 - calculates the CRC32 of the LZRTF data part + // buf = the whole rtf data part + // off = start point of crc calculation + // len = length of data to calculate CRC for + // function is necessary since in RTF there is no XOR 0xffffffff being done (said to be 0x00 unsafe CRC32 calculation + function LZRTFCalcCRC32($buf, $off, $len) { + $c=0; + $end = $off + $len; + for($i=$off;$i < $end;$i++) { + $c=$this->CRC32_TABLE($c ^ ord($buf$i)) & 0xFF ^ (($c >> 8) & 0x00ffffff); + } + return $c; + } + + function parserInit() { /* Default values according to the specs */ + $this->flags = array( + "fontsize" => 24, + "beginparagraph" => true, + ); + } + + function parseControl($control, $parameter) { + switch ($control) { + case "fonttbl": // font table definition start + $this->flags"fonttbl" = true; // signal fonttable control words they are allowed to behave as expected + break; + case "f": // define or set font + if($this->flags"fonttbl") { // if its set, the fonttable definition is written to; else its read from + $this->flags"fonttbl_current_write" = $parameter; + } else { + $this->flags"fonttbl_current_read" = $parameter; + } + break; + case "fcharset": // this is for preparing flushQueue; it then moves the Queue to $this->fonttable .. instead to formatted output + $this->flags"fonttbl_want_fcharset" = $parameter; + break; + case "fs": // sets the current fontsize; is used by stylesheets (which are therefore generated on the fly + $this->flags"fontsize" = $parameter; + break; + + case "qc": // handle center alignment + $this->flags"alignment" = "center"; + break; + case "qr": // handle right alignment + $this->flags"alignment" = "right"; + break; + + case "pard": // reset paragraph settings (only alignment) + $this->flags"alignment" = ""; + break; + case "par": // define new paragraph (for now, thats a simple break in html) begin new line + if($this->wantHTML) { + $this->out .= "</div>"; + } + else if($this->wantASCII) { + $this->out .= "\n"; + } + $this->flags"beginparagraph" = true; + break; + case "bnone": // bold + $parameter = "0"; + case "b": + // haven'y yet figured out WHY I need a (string)-cast here ... hm + if((string)$parameter == "0") + $this->flags"bold" = false; + else + $this->flags"bold" = true; + break; + case "ulnone": // underlined + $parameter = "0"; + case "ul": + if((string)$parameter == "0") + $this->flags"underlined" = false; + else + $this->flags"underlined" = true; + break; + case "inone": // italic + $parameter = "0"; + case "i": + if((string)$parameter == "0") + $this->flags"italic" = false; + else + $this->flags"italic" = true; + break; + case "strikenone": // strikethru + $parameter = "0"; + case "strike": + if((string)$parameter == "0") + $this->flags"strikethru" = false; + else + $this->flags"strikethru" = true; + break; + case "plain": // reset all font modifiers and fontsize to 12 + $this->flags"bold" = false; + $this->flags"italic" = false; + $this->flags"underlined" = false; + $this->flags"strikethru" = false; + $this->flags"fontsize" = 12; + + $this->flags"subscription" = false; + $this->flags"superscription" = false; + break; + case "subnone": // subscription + $parameter = "0"; + case "sub": + if((string)$parameter == "0") + $this->flags"subscription" = false; + else + $this->flags"subscription" = true; + break; + case "supernone": // superscription + $parameter = "0"; + case "super": + if((string)$parameter == "0") + $this->flags"superscription" = false; + else + $this->flags"superscription" = true; + break; + } + } + + /* + Dispatch the control word to the output stream + */ + + function flushControl() { + if(preg_match("/^(A-Za-z+)(-?0-9*) ?$/", $this->cword, $match)) { + $this->parseControl($match1, $match2); + if($this->wantXML) { + $this->out.="<control word=\"".$match1."\""; + if(strlen($match2) > 0) + $this->out.=" param=\"".$match2."\""; + $this->out.="/>"; + } + } + } + + /* + If output stream supports comments, dispatch it + */ + + function flushComment($comment) { + if($this->wantXML || $this->wantHTML) { + $this->out.="<!-- ".$comment." -->"; + } + } + + /* + Dispatch start/end of logical rtf groups (not every output type needs it; merely debugging purpose) + */ + + function flushGroup($state) { + if($state == "open") { /* push onto the stack */ + array_push($this->stack, $this->flags); + + if($this->wantXML) + $this->out.="<group>"; + } + if($state == "close") { /* pop from the stack */ + $this->last_flags = $this->flags; + $this->flags = array_pop($this->stack); + + $this->flags"fonttbl_current_write" = ""; // on group close, no more fontdefinition will be written to this id + // this is not really the right way to do it ! + // of course a '}' not necessarily donates a fonttable end; a fonttable + // group at least *can* contain sub-groups + // therefore an stacked approach is heavily needed + $this->flags"fonttbl" = false; // no matter what you do, if a group closes, its fonttbl definition is closed too + + if($this->wantXML) + $this->out.="</group>"; + } + } + + function flushHead() { + if($this->wantXML) + $this->out.="<rtf>"; + } + + function flushBottom() { + if($this->wantXML) + $this->out.="</rtf>"; + } + + function checkHtmlSpanContent($command) { + reset($this->fontmodifier_table); + while(list($rtf, $html) = each($this->fontmodifier_table)) { + if($this->flags$rtf == true) { + if($command == "start") + $this->out .= "<".$html.">"; + else + $this->out .= "</".$html.">"; + } + } + } + + /* + flush text in queue + */ + function flushQueue() { + if(strlen($this->queue)) { + // processing logic + if (isset($this->flags"fonttbl_want_fcharset") && + preg_match("/^0-9+$/", $this->flags"fonttbl_want_fcharset")) { + $this->fonttable$this->flags"fonttbl_want_fcharset""charset" = $this->queue; + $this->flags"fonttbl_want_fcharset" = ""; + $this->queue = ""; + } + + // output logic + if (strlen($this->queue)) { + /* + Everything which passes this is (or, at leat, *should*) be only outputted plaintext + Thats why we can safely add the css-stylesheet when using wantHTML + */ + if($this->wantXML) + $this->out.= "<plain>".$this->queue."</plain>"; + else if($this->wantHTML) { + // only output html if a valid (for now, just numeric;) fonttable is given + if(preg_match("/^0-9+$/", $this->flags"fonttbl_current_read")) { + if($this->flags"beginparagraph" == true) { + $this->flags"beginparagraph" = false; + $this->out .= "<div align=\""; + switch($this->flags"alignment") { + case "right": + $this->out .= "right"; + break; + case "center": + $this->out .= "center"; + break; + case "left": + default: + $this->out .= "left"; + } + $this->out .= "\">"; + } + + /* define new style for that span */ + $this->styles"f".$this->flags"fonttbl_current_read"."s".$this->flags"fontsize" = "font-family:".$this->fonttable$this->flags"fonttbl_current_read""charset"." font-size:".$this->flags"fontsize".";"; + /* write span start */ + $this->out .= "<span class=\"f".$this->flags"fonttbl_current_read"."s".$this->flags"fontsize"."\">"; + + /* check if the span content has a modifier */ + $this->checkHtmlSpanContent("start"); + /* write span content */ + $this->out .= $this->queue; + /* close modifiers */ + $this->checkHtmlSpanContent("stop"); + /* close span */ + $this->out .= "</span>"; + } + } + $this->queue = ""; + } + } + } + + /* + handle special charactes like \'ef + */ + + function flushSpecial($special) { + if(strlen($special) == 2) { + if($this->wantASCII) + $this->out .= chr(hexdec('0x'.$special)); + else if($this->wantXML) + $this->out .= "<special value=\"".$special."\"/>"; + else if($this->wantHTML){ + $this->out .= "<special value=\"".$special."\"/>"; + switch($special) { + case "c1": $this->out .= "Á"; break; + case "e1": $this->out .= "á"; break; + case "c0": $this->out .= "À"; break; + case "e0": $this->out .= "à"; break; + case "c9": $this->out .= "É"; break; + case "e9": $this->out .= "é"; break; + case "c8": $this->out .= "È"; break; + case "e8": $this->out .= "è"; break; + case "cd": $this->out .= "Í"; break; + case "ed": $this->out .= "í"; break; + case "cc": $this->out .= "Ì"; break; + case "ec": $this->out .= "ì"; break; + case "d3": $this->out .= "Ó"; break; + case "f3": $this->out .= "ó"; break; + case "d2": $this->out .= "Ò"; break; + case "f2": $this->out .= "ò"; break; + case "da": $this->out .= "Ú"; break; + case "fa": $this->out .= "ú"; break; + case "d9": $this->out .= "Ù"; break; + case "f9": $this->out .= "ù"; break; + case "80": $this->out .= "€"; break; + case "d1": $this->out .= "Ñ"; break; + case "f1": $this->out .= "ñ"; break; + case "c7": $this->out .= "Ç"; break; + case "e7": $this->out .= "ç"; break; + case "dc": $this->out .= "Ü"; break; + case "fc": $this->out .= "ü"; break; + case "bf": $this->out .= "¿"; break; + case "a1": $this->out .= "¡"; break; + case "b7": $this->out .= "·"; break; + case "a9": $this->out .= "©"; break; + case "ae": $this->out .= "®"; break; + case "ba": $this->out .= "º"; break; + case "aa": $this->out .= "ª"; break; + case "b2": $this->out .= "²"; break; + case "b3": $this->out .= "³"; break; + } + } + } + } + + /* + Output errors at end + */ + function flushErrors() { + if(count($this->err) > 0) { + if($this->wantXML) { + $this->out .= "<errors>"; + while(list($num,$value) = each($this->err)) { + $this->out .= "<message>".$value."</message>"; + } + $this->out .= "</errors>"; + } + } + } + + function makeStyles() { + $this->outstyles = "<style type=\"text/css\"><!--\n"; + reset($this->styles); + while(list($stylename, $styleattrib) = each($this->styles)) { + $this->outstyles .= ".".$stylename." { ".$styleattrib." }\n"; + } + $this->outstyles .= "--></style>\n"; + } + + function parse() { + + $this->parserInit(); + + $i = 0; + $this->cw = false; // flag if control word is currently parsed + $this->cfirst = false; // first control character ? + $this->cword = ""; // last or current control word (depends on $this->cw + $this->queue = ""; // plain text data found during parsing + + $this->flushHead(); + + while($i < $this->rtf_len) { + switch($this->rtf$i) { + case "{": + if($this->cw) { + $this->flushControl(); + $this->cw = false; + $this->cfirst = false; + } else + $this->flushQueue(); + + $this->flushGroup("open"); + break; + case "}": + if($this->cw) { + $this->flushControl(); + $this->cw = false; + $this->cfirst = false; + } else + $this->flushQueue(); + + $this->flushGroup("close"); + break; + case "\\": + if($this->cfirst) { // catches '\\' + $this->queue .= "\\"; // replaced single quotes + $this->cfirst = false; + $this->cw = false; + break; + } + if($this->cw) { + $this->flushControl(); + } else + $this->flushQueue(); + $this->cw = true; + $this->cfirst = true; + $this->cword = ""; + break; + default: + if((ord($this->rtf$i) == 10) || (ord($this->rtf$i) == 13)) break; // eat line breaks + if($this->cw) { // active control word ? + /* + Watch the RE: there's an optional space at the end which IS part of + the control word (but actually its ignored by flushControl) + */ + if(preg_match("/^a-zA-Z0-9-?$/", $this->rtf$i)) { // continue parsing + $this->cword .= $this->rtf$i; + $this->cfirst = false; + } else { + /* + Control word could be a 'control symbol', like \~ or \* etc. + */ + $specialmatch = false; + if($this->cfirst) { + if($this->rtf$i == '\'') { // expect to get some special chars + $this->flushQueue(); + $this->flushSpecial($this->rtf$i+1.$this->rtf$i+2); + $i+=2; + $specialmatch = true; + $this->cw = false; + $this->cfirst = false; + $this->cword = ""; + } else + if(preg_match("/^{}\*$/", $this->rtf$i)) { + $this->flushComment("control symbols not yet handled"); + $specialmatch = true; + } + $this->cfirst = false; + } else { + if($this->rtf$i == ' ') { // space delimtes control words, so just discard it and flush the controlword + $this->cw = false; + $this->flushControl(); + break; + } + } + if(!$specialmatch) { + $this->flushControl(); + $this->cw = false; + $this->cfirst = false; + /* + The current character is a delimeter, but is NOT + part of the control word so we hop one step back + in the stream and process it again + */ + $i--; + } + } + } else { + // < and > need translation before putting into queue when XML or HTML is wanted + if(($this->wantHTML) || ($this->wantXML)) { + switch($this->rtf$i) { + case "<": + $this->queue .= "<"; + break; + case ">": + $this->queue .= ">"; + break; + default: + $this->queue .= $this->rtf$i; + break; + } + } else + $this->queue .= $this->rtf$i; + } + + } + $i++; + } + $this->flushQueue(); + $this->flushErrors(); + $this->flushBottom(); + + if($this->wantHTML) { + $this->makeStyles(); + } + } +}
View file
kolab-syncroton-2.4.2.tar.gz/lib/init.php -> kolab-syncroton-2.3.22.tar.gz/lib/init.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | |
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -28,23 +28,25 @@ */ class kolab_sync extends rcube { - /** @var string Application name */ + /** + * Application name + * + * @var string + */ public $app_name = 'ActiveSync for Kolab'; // no double quotes inside - /** @var string|null Request user name */ - public $username; + /** + * Current user + * + * @var rcube_user + */ + public $user; - /** @var string|null Request user password */ + public $username; public $password; - public $task; - - protected $per_user_log_dir; - protected $log_dir; - protected $logger; - - public const CHARSET = 'UTF-8'; - public const VERSION = "2.4.2"; + const CHARSET = 'UTF-8'; + const VERSION = "2.3.22"; /** @@ -55,7 +57,7 @@ * * @return kolab_sync The one and only instance */ - public static function get_instance($mode = 0, $env = '') + static function get_instance($mode = 0, $env = '') { if (!self::$instance || !is_a(self::$instance, 'kolab_sync')) { self::$instance = new kolab_sync(); @@ -72,16 +74,15 @@ public function startup() { // Initialize Syncroton Logger - $debug_mode = $this->config->get('activesync_debug') ? kolab_sync_logger::DEBUG : kolab_sync_logger::WARN; - $this->logger = new kolab_sync_logger($debug_mode); - $this->log_dir = $this->config->get('log_dir'); + $debug_mode = $this->config->get('activesync_debug') ? kolab_sync_logger::DEBUG : kolab_sync_logger::WARN; + $this->logger = new kolab_sync_logger($debug_mode); // Get list of plugins // WARNING: We can use only plugins that are prepared for this - // e.g. are not using output or rcmail objects and - // do not throw errors when using them - $plugins = (array)$this->config->get('activesync_plugins', 'kolab_auth'); - $plugins = array_unique(array_merge($plugins, 'libkolab', 'libcalendaring')); + // e.g. are not using output or rcmail objects or + // doesn't throw errors when using them + $plugins = (array)$this->config->get('activesync_plugins', array('kolab_auth')); + $plugins = array_unique(array_merge($plugins, array('libkolab', 'libcalendaring'))); // Initialize/load plugins $this->plugins = kolab_sync_plugin_api::get_instance(); @@ -114,7 +115,7 @@ } if (isset($basicAuthData) && !empty($basicAuthData)) { - $_SERVER'PHP_AUTH_USER', $_SERVER'PHP_AUTH_PW' = explode(":", $basicAuthData); + list($_SERVER'PHP_AUTH_USER', $_SERVER'PHP_AUTH_PW') = explode(":", $basicAuthData); } } @@ -128,36 +129,34 @@ } } - // Set log directory per-user - $this->set_log_dir($_SERVER'PHP_AUTH_USER'); - // Authenticate the user $userid = $this->authenticate($_SERVER'PHP_AUTH_USER', $_SERVER'PHP_AUTH_PW'); } - if (!empty($userid)) { - $this->plugins->exec_hook('ready', 'task' => 'syncroton'); + if (empty($userid)) { + header('WWW-Authenticate: Basic realm="' . $this->app_name .'"'); + header('HTTP/1.1 401 Unauthorized'); + exit; + } - // Set log directory per-user (again, in case the username changed above) - $this->set_log_dir(); + $this->plugins->exec_hook('ready', array('task' => 'syncroton')); - // Save user password for Roundcube Framework - $this->password = $_SERVER'PHP_AUTH_PW'; - } + // Set log directory per-user + $this->set_log_dir(); + + // Save user password for Roundcube Framework + $this->password = $_SERVER'PHP_AUTH_PW'; // 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()); - // The unauthenticated OPTIONS request doesn't require these backends and we can't instantiate them without credentials for the underlying storage backend - if (!empty($userid)) { - Syncroton_Registry::set(Syncroton_Registry::DEVICEBACKEND, new kolab_sync_backend_device()); - Syncroton_Registry::set(Syncroton_Registry::FOLDERBACKEND, new kolab_sync_backend_folder()); - 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, $this, 'sleep'); - } + 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); + Syncroton_Registry::set(Syncroton_Registry::FOLDERBACKEND, new kolab_sync_backend_folder); + 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'); @@ -167,13 +166,13 @@ Syncroton_Registry::setGALDataClass('kolab_sync_data_gal'); // Configuration - Syncroton_Registry::set(Syncroton_Registry::PING_TIMEOUT, (int) $this->config->get('activesync_ping_timeout', 60)); - Syncroton_Registry::set(Syncroton_Registry::PING_INTERVAL, (int) $this->config->get('activesync_ping_interval', 15 * 60)); - Syncroton_Registry::set(Syncroton_Registry::QUIET_TIME, (int) $this->config->get('activesync_quiet_time', 3 * 60)); + Syncroton_Registry::set(Syncroton_Registry::PING_TIMEOUT, (int) $this->config->get('activesync_ping_timeout', 60)); + Syncroton_Registry::set(Syncroton_Registry::PING_INTERVAL, (int) $this->config->get('activesync_ping_interval', 15 * 60)); + Syncroton_Registry::set(Syncroton_Registry::QUIET_TIME, (int) $this->config->get('activesync_quiet_time', 3 * 60)); Syncroton_Registry::set(Syncroton_Registry::MAX_COLLECTIONS, (int) $this->config->get('activesync_max_folders', 100)); // Run Syncroton - $syncroton = new Syncroton_Server($userid ?? null); + $syncroton = new Syncroton_Server($userid); $syncroton->handle(); } @@ -184,7 +183,7 @@ * @param string $username User name * @param string $password User password * - * @return null|int User ID + * @param int User ID */ public function authenticate($username, $password) { @@ -194,72 +193,71 @@ $cache_key = sha1($username . '::' . $host); if (!$cache || !($auth = $cache->get($cache_key))) { - $auth = $this->plugins->exec_hook('authenticate', + $auth = $this->plugins->exec_hook('authenticate', array( 'host' => $host, 'user' => $username, 'pass' => $password, - ); + )); if (!$auth'abort' && $cache) { - $cache->set($cache_key, + $cache->set($cache_key, array( 'user' => $auth'user', 'host' => $auth'host', - ); + )); } // LDAP server failure... send 503 error - if (!empty($auth'kolab_ldap_error')) { + 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(); + if (method_exists('kolab_auth', 'ldap_close')) { + kolab_auth::ldap_close(); + } } - } else { + } + else { $auth'pass' = $password; } - $err = null; - // Authenticate - get Roundcube user ID - if (empty($auth'abort') && ($userid = $this->login($auth'user', $auth'pass', $auth'host', $err))) { + if (!$auth'abort' && ($userid = $this->login($auth'user', $auth'pass', $auth'host', $err))) { // set real username $this->username = $auth'user'; return $userid; } - - if ($err) { + else if ($err) { $err_str = $this->get_storage()->get_error_str(); } if (class_exists('kolab_auth', false)) { - kolab_auth::log_login_error($auth'user', !empty($err_str) ? $err_str : $err); + kolab_auth::log_login_error($auth'user', $err_str ?: $err); } - $this->plugins->exec_hook('login_failed', + $this->plugins->exec_hook('login_failed', array( 'host' => $auth'host', 'user' => $auth'user', - ); + )); // IMAP server failure... send 503 error if ($err == rcube_imap_generic::ERROR_BAD) { self::server_error(); } - - return null; } + /** * Storage host selection */ private function select_host($username) { // Get IMAP host - $host = $this->config->get('imap_host', $this->config->get('default_host')); + $host = $this->config->get('default_host'); if (is_array($host)) { - $user, $domain = explode('@', $username); + list($user, $domain) = explode('@', $username); // try to select host by mail domain if (!empty($domain)) { @@ -267,7 +265,8 @@ if (is_array($mail_domains) && in_array_nocase($domain, $mail_domains)) { $host = $storage_host; break; - } elseif (stripos($storage_host, $domain) !== false || stripos(strval($mail_domains), $domain) !== false) { + } + else if (stripos($storage_host, $domain) !== false || stripos(strval($mail_domains), $domain) !== false) { $host = is_numeric($storage_host) ? $mail_domains : $storage_host; break; } @@ -276,8 +275,8 @@ // take the first entry if $host is not found if (is_array($host)) { - $key = key($host); - $host = is_numeric($key) ? $host$key : $key; + list($key, $val) = each($host); + $host = is_numeric($key) ? $val : $key; } } @@ -299,14 +298,13 @@ // parse $host $a_host = parse_url($host); - $port = null; - $ssl = null; - if (!empty($a_host'host')) { + if ($a_host'host') { $host = $a_host'host'; - $ssl = (isset($a_host'scheme') && in_array($a_host'scheme', 'ssl','imaps','tls')) ? $a_host'scheme' : null; + $ssl = (isset($a_host'scheme') && in_array($a_host'scheme', array('ssl','imaps','tls'))) ? $a_host'scheme' : null; if (!empty($a_host'port')) { $port = $a_host'port'; - } elseif ($ssl && $ssl != 'tls' && (!$default_port || $default_port == 143)) { + } + else if ($ssl && $ssl != 'tls' && (!$default_port || $default_port == 143)) { $port = 993; } } @@ -320,9 +318,10 @@ if ($login_lc) { if ($login_lc == 2 || $login_lc === true) { $username = mb_strtolower($username); - } elseif (strpos($username, '@')) { + } + else if (strpos($username, '@')) { // lowercase domain name - $local, $domain = explode('@', $username); + list($local, $domain) = explode('@', $username); $username = $local . '@' . mb_strtolower($domain); } } @@ -351,17 +350,18 @@ $user = rcube_user::create($username, $host); if (!$user) { - self::raise_error( + self::raise_error(array( 'code' => 620, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Failed to create a user record", - , true, false); + ), true, false); return null; } - } else { - self::raise_error( + } + else { + self::raise_error(array( 'code' => 620, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Access denied for new user $username. 'auto_create_user' is disabled", - , true, false); + ), true, false); return null; } } @@ -384,35 +384,15 @@ /** - * Initializes and returns the storage backend object - */ - public static function storage() - { - $class = 'kolab_sync_storage'; - $self = self::get_instance(); - - if (($name = $self->config->get('activesync_storage')) && $name != 'kolab') { - $class .= '_' . strtolower($name); - } - - return $class::get_instance(); - } - - - /** * Set logging directory per-user */ - protected function set_log_dir($username = null) + protected function set_log_dir() { - if (empty($username)) { - $username = $this->username; - } - - if (empty($username)) { + if (empty($this->username)) { return; } - $this->logger->set_username($username); + $this->logger->set_username($this->username); $user_debug = (bool) $this->config->get('per_user_logging'); @@ -420,7 +400,8 @@ return; } - $log_dir = $this->log_dir . DIRECTORY_SEPARATOR . $username; + $log_dir = $this->config->get('log_dir'); + $log_dir .= DIRECTORY_SEPARATOR . $this->username; // No automatically creating any log directories if (!is_dir($log_dir)) { @@ -432,7 +413,8 @@ if (!empty($_GET'DeviceId')) { $deviceId = $_GET'DeviceId'; - } elseif ( + } + else if ( !empty($_SERVER'QUERY_STRING') && strpos($_SERVER'QUERY_STRING', '&') == false && ($query = base64_decode($_SERVER'QUERY_STRING')) @@ -481,10 +463,6 @@ */ public static function server_error() { - if (php_sapi_name() == 'cli') { - throw new Exception("LDAP/IMAP error on authentication"); - } - header("HTTP/1.1 503 Service Temporarily Unavailable"); header("Retry-After: 120"); exit; @@ -505,27 +483,22 @@ if ($this->config->get('devel_mode') || $this->config->get('performance_stats')) { // we have to disable per_user_logging to make sure stats end up in the main console log $this->config->set('per_user_logging', false); - $this->config->set('log_dir', $this->log_dir); // make sure logged numbers use unified format setlocale(LC_NUMERIC, 'en_US.utf8', 'en_US.UTF-8', 'en_US', 'C'); - $mem = ''; - if (function_exists('memory_get_usage')) { + if (function_exists('memory_get_usage')) $mem = round(memory_get_usage() / 1048576, 1); - } - if (function_exists('memory_get_peak_usage')) { + if (function_exists('memory_get_peak_usage')) $mem .= '/' . round(memory_get_peak_usage() / 1048576, 1); - } - $query = $_SERVER'QUERY_STRING' ?? ''; + $query = $_SERVER'QUERY_STRING'; $log = $query . ($mem ? ($query ? ' ' : '') . "$mem" : ''); - if (defined('KOLAB_SYNC_START')) { + if (defined('KOLAB_SYNC_START')) self::print_timer(KOLAB_SYNC_START, $log); - } else { + else self::console($log); - } } } @@ -546,10 +519,7 @@ $book->close(); } - kolab_sync_data_gal::$address_books = ; + kolab_sync_data_gal::$address_books = array(); } - - // Reset internal cache of the storage class - self::storage()->reset(); } }
View file
kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_backend.php
Added
@@ -0,0 +1,1059 @@ +<?php + +/** + +--------------------------------------------------------------------------+ + | Kolab Sync (ActiveSync for Kolab) | + | | + | Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> | + | | + | This program is free software: you can redistribute it and/or modify | + | it under the terms of the GNU Affero General Public License as published | + | by the Free Software Foundation, either version 3 of the License, or | + | (at your option) any later version. | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU Affero General Public License for more details. | + | | + | You should have received a copy of the GNU Affero General Public License | + | along with this program. If not, see <http://www.gnu.org/licenses/> | + +--------------------------------------------------------------------------+ + | Author: Aleksander Machniak <machniak@kolabsys.com> | + +--------------------------------------------------------------------------+ +*/ + +class kolab_sync_backend +{ + /** + * Singleton instace of kolab_sync_backend + * + * @var kolab_sync_backend + */ + static protected $instance; + + protected $storage; + protected $folder_meta; + protected $folder_uids; + protected $root_meta; + + static protected $types = array( + 1 => '', + 2 => 'mail.inbox', + 3 => 'mail.drafts', + 4 => 'mail.wastebasket', + 5 => 'mail.sentitems', + 6 => 'mail.outbox', + 7 => 'task.default', + 8 => 'event.default', + 9 => 'contact.default', + 10 => 'note.default', + 11 => 'journal.default', + 12 => 'mail', + 13 => 'event', + 14 => 'contact', + 15 => 'task', + 16 => 'journal', + 17 => 'note', + ); + + static protected $classes = array( + Syncroton_Data_Factory::CLASS_CALENDAR => 'event', + Syncroton_Data_Factory::CLASS_CONTACTS => 'contact', + Syncroton_Data_Factory::CLASS_EMAIL => 'mail', + Syncroton_Data_Factory::CLASS_NOTES => 'note', + Syncroton_Data_Factory::CLASS_TASKS => 'task', + ); + + const ROOT_MAILBOX = 'INBOX'; +// const ROOT_MAILBOX = ''; + const ASYNC_KEY = '/private/vendor/kolab/activesync'; + const UID_KEY = '/shared/vendor/cmu/cyrus-imapd/uniqueid'; + + + /** + * This implements the 'singleton' design pattern + * + * @return kolab_sync_backend The one and only instance + */ + static function get_instance() + { + if (!self::$instance) { + self::$instance = new kolab_sync_backend; + self::$instance->startup(); // init AFTER object was linked with self::$instance + } + + return self::$instance; + } + + + /** + * Class initialization + */ + public function startup() + { + $this->storage = rcube::get_instance()->get_storage(); + + // @TODO: reset cache? if we do this for every request the cache would be useless + // There's no session here + //$this->storage->clear_cache('mailboxes.', true); + + // set additional header used by libkolab + $this->storage->set_options(array( + // @TODO: there can be Roundcube plugins defining additional headers, + // we maybe would need to add them here + 'fetch_headers' => 'X-KOLAB-TYPE X-KOLAB-MIME-VERSION', + 'skip_deleted' => true, + 'threading' => false, + )); + + // Disable paging + $this->storage->set_pagesize(999999); + } + + + /** + * List known devices + * + * @return array Device list as hash array + */ + public function devices_list() + { + if ($this->root_meta === null) { + // @TODO: consider server annotation instead of INBOX + if ($meta = $this->storage->get_metadata(self::ROOT_MAILBOX, self::ASYNC_KEY)) { + $this->root_meta = $this->unserialize_metadata($metaself::ROOT_MAILBOXself::ASYNC_KEY); + } + else { + $this->root_meta = array(); + } + } + + if (!empty($this->root_meta'DEVICE') && is_array($this->root_meta'DEVICE')) { + return $this->root_meta'DEVICE'; + } + + return array(); + } + + + /** + * Get list of folders available for sync + * + * @param string $deviceid Device identifier + * @param string $type Folder type + * @param bool $flat_mode Enables flat-list mode + * + * @return array|bool List of mailbox folders, False on backend failure + */ + public function folders_list($deviceid, $type, $flat_mode = false) + { + // get all folders of specified type + $folders = kolab_storage::list_folders('', '*', $type, false, $typedata); + + // get folders activesync config + $folderdata = $this->folder_meta(); + + if (!is_array($folders) || !is_array($folderdata)) { + return false; + } + + $folders_list = array(); + + // check if folders are "subscribed" for activesync + foreach ($folderdata as $folder => $meta) { + if (empty($meta'FOLDER') || empty($meta'FOLDER'$deviceid) + || empty($meta'FOLDER'$deviceid'S') + ) { + continue; + } + + // force numeric folder name to be a string (T1283) + $folder = (string) $folder; + + if (!empty($type) && !in_array($folder, $folders)) { + continue; + } + + // Activesync folder identifier (serverId) + $folder_type = $typedata$folder ?: 'mail'; + $folder_id = self::folder_id($folder, $folder_type); + + $folders_list$folder_id = $this->folder_data($folder, $folder_type); + } + + if ($flat_mode) { + $folders_list = $this->folders_list_flat($folders_list, $type, $typedata); + } + + return $folders_list; + } + + /** + * Converts list of folders to a "flat" list + */ + private function folders_list_flat($folders, $type, $typedata) + { + $delim = $this->storage->get_hierarchy_delimiter(); + + foreach ($folders as $idx => $folder) { + if ($folder'parentId') { + // for non-mail folders we make the list completely flat + if ($type != 'mail') { + $display_name = kolab_storage::object_name($folder'imap_name'); + $display_name = html_entity_decode($display_name, ENT_COMPAT, RCUBE_CHARSET); + + $folders$idx'parentId' = 0; + $folders$idx'displayName' = $display_name; + } + // for mail folders we modify only folders with non-existing parents + else if (!isset($folders$folder'parentId')) { + $items = explode($delim, $folder'imap_name'); + $parent = 0; + + // find existing parent + while (count($items) > 0) { + array_pop($items); + + $parent_name = implode($delim, $items); + $parent_type = $typedata$parent_name ?: 'mail'; + $parent_id = self::folder_id($parent_name, $parent_type); + + if (isset($folders$parent_id)) { + $parent = $parent_id; + break; + } + } + + if (!$parent) { + $display_name = kolab_storage::object_name($folder'imap_name'); + $display_name = html_entity_decode($display_name, ENT_COMPAT, RCUBE_CHARSET); + } + else { + $parent_name = $folders$parent_id'imap_name'; + $display_name = substr($folder'imap_name', strlen($parent_name)+1); + $display_name = rcube_charset::convert($display_name, 'UTF7-IMAP'); + $display_name = str_replace($delim, ' » ', $display_name); + } + + $folders$idx'parentId' = $parent; + $folders$idx'displayName' = $display_name; + } + } + } + + return $folders; + } + + /** + * Getter for folder metadata + * + * @return array|bool Hash array with meta data for each folder, False on backend failure + */ + public function folder_meta() + { + if (!isset($this->folder_meta)) { + // get folders activesync config + $folderdata = $this->storage->get_metadata("*", self::ASYNC_KEY); + + if (!is_array($folderdata)) { + return $this->folder_meta = false; + } + + $this->folder_meta = array(); + + foreach ($folderdata as $folder => $meta) { + if ($asyncdata = $metaself::ASYNC_KEY) { + if ($metadata = $this->unserialize_metadata($asyncdata)) { + $this->folder_meta$folder = $metadata; + } + } + } + } + + return $this->folder_meta; + } + + + /** + * Creates folder and subscribes to the device + * + * @param string $name Folder name (UTF7-IMAP) + * @param int $type Folder (ActiveSync) type + * @param string $deviceid Device identifier + * + * @return bool True on success, False on failure + */ + public function folder_create($name, $type, $deviceid) + { + if ($this->storage->folder_exists($name)) { + $created = true; + } + else { + $type = self::type_activesync2kolab($type); + $created = kolab_storage::folder_create($name, $type, true); + } + + if ($created) { + // Set ActiveSync subscription flag + $this->folder_set($name, $deviceid, 1); + + return true; + } + + return false; + } + + + /** + * Renames a folder + * + * @param string $old_name Old folder name (UTF7-IMAP) + * @param string $new_name New folder name (UTF7-IMAP) + * @param int $type Folder (ActiveSync) type + * + * @return bool True on success, False on failure + */ + public function folder_rename($old_name, $new_name, $type) + { + $this->folder_meta = null; + + $type = self::type_activesync2kolab($type); + + // don't use kolab_storage for moving mail folders + if (preg_match('/^mail/', $type)) { + return $this->storage->rename_folder($old_name, $new_name); + } + else { + return kolab_storage::folder_rename($old_name, $new_name); + } + } + + + /** + * Deletes folder + * + * @param string $name Folder name (UTF7-IMAP) + * @param string $deviceid Device identifier + * + */ + public function folder_delete($name, $deviceid) + { + unset($this->folder_meta$name); + + return kolab_storage::folder_delete($name); + } + + + /** + * Sets ActiveSync subscription flag on a folder + * + * @param string $name Folder name (UTF7-IMAP) + * @param string $deviceid Device identifier + * @param int $flag Flag value (0|1|2) + */ + public function folder_set($name, $deviceid, $flag) + { + if (empty($deviceid)) { + return false; + } + + // get folders activesync config + $metadata = $this->folder_meta(); + + if (!is_array($metadata)) { + return false; + } + + $metadata = $metadata$name; + + if ($flag) { + if (empty($metadata)) { + $metadata = array(); + } + + if (empty($metadata'FOLDER')) { + $metadata'FOLDER' = array(); + } + + if (empty($metadata'FOLDER'$deviceid)) { + $metadata'FOLDER'$deviceid = array(); + } + + // Z-Push uses: + // 1 - synchronize, no alarms + // 2 - synchronize with alarms + $metadata'FOLDER'$deviceid'S' = $flag; + } + + if (!$flag) { + unset($metadata'FOLDER'$deviceid'S'); + + if (empty($metadata'FOLDER'$deviceid)) { + unset($metadata'FOLDER'$deviceid); + } + + if (empty($metadata'FOLDER')) { + unset($metadata'FOLDER'); + } + + if (empty($metadata)) { + $metadata = null; + } + } + + // Return if nothing's been changed + if (!self::data_array_diff($this->folder_meta$name, $metadata)) { + return true; + } + + $this->folder_meta$name = $metadata; + + return $this->storage->set_metadata($name, array( + self::ASYNC_KEY => $this->serialize_metadata($metadata))); + } + + + public function device_get($id) + { + $devices_list = $this->devices_list(); + + $result = $devices_list$id; + + return $result; + } + + /** + * Registers new device on server + * + * @param array $device Device data + * @param string $id Device ID + * + * @return bool True on success, False on failure + */ + public function device_create($device, $id) + { + // Fill local cache + $this->devices_list(); + + // Some devices create dummy devices with name "validate" (#1109) + // This device entry is used in two initial requests, but later + // the device registers a real name. We can remove this dummy entry + // on new device creation + $this->device_delete('validate'); + + // Old Kolab_ZPush device parameters + // MODE: -1 | 0 | 1 (not set | flatmode | foldermode) + // TYPE: device type string + // ALIAS: user-friendly device name + + // Syncroton (kolab_sync_backend_device) uses + // ID: internal identifier in syncroton database + // TYPE: device type string + // ALIAS: user-friendly device name + + $metadata = $this->root_meta; + $metadata'DEVICE'$id = $device; + $metadata = array(self::ASYNC_KEY => $this->serialize_metadata($metadata)); + + $result = $this->storage->set_metadata(self::ROOT_MAILBOX, $metadata); + + if ($result) { + // Update local cache + $this->root_meta'DEVICE'$id = $device; + + // subscribe default set of folders + $this->device_init_subscriptions($id); + } + + return $result; + } + + /** + * Device update. + * + * @param array $device Device data + * @param string $id Device ID + * + * @return bool True on success, False on failure + */ + public function device_update($device, $id) + { + $devices_list = $this->devices_list(); + $old_device = $devices_list$id; + + if (!$old_device) { + return false; + } + + // Do nothing if nothing is changed + if (!self::data_array_diff($old_device, $device)) { + return true; + } + + $device = array_merge($old_device, $device); + + $metadata = $this->root_meta; + $metadata'DEVICE'$id = $device; + $metadata = array(self::ASYNC_KEY => $this->serialize_metadata($metadata)); + + $result = $this->storage->set_metadata(self::ROOT_MAILBOX, $metadata); + + if ($result) { + // Update local cache + $this->root_meta'DEVICE'$id = $device; + } + + return $result; + } + + + /** + * Device delete. + * + * @param string $id Device ID + * + * @return bool True on success, False on failure + */ + public function device_delete($id) + { + $device = $this->device_get($id); + + if (!$device) { + return false; + } + + unset($this->root_meta'DEVICE'$id, $this->root_meta'FOLDER'$id); + + if (empty($this->root_meta'DEVICE')) { + unset($this->root_meta'DEVICE'); + } + if (empty($this->root_meta'FOLDER')) { + unset($this->root_meta'FOLDER'); + } + + $metadata = $this->serialize_metadata($this->root_meta); + $metadata = array(self::ASYNC_KEY => $metadata); + + // update meta data + $result = $this->storage->set_metadata(self::ROOT_MAILBOX, $metadata); + + if ($result) { + // remove device annotation for every folder + foreach ($this->folder_meta() as $folder => $meta) { + // skip root folder (already handled above) + if ($folder == self::ROOT_MAILBOX) + continue; + + if (!empty($meta'FOLDER') && isset($meta'FOLDER'$id)) { + unset($meta'FOLDER'$id); + + if (empty($meta'FOLDER')) { + unset($this->folder_meta$folder'FOLDER'); + unset($meta'FOLDER'); + } + if (empty($meta)) { + unset($this->folder_meta$folder); + $meta = null; + } + + $metadata = array(self::ASYNC_KEY => $this->serialize_metadata($meta)); + $res = $this->storage->set_metadata($folder, $metadata); + + if ($res && $meta) { + $this->folder_meta$folder = $meta; + } + } + } + } + + return $result; + } + + /** + * Subscribe default set of folders on device registration + */ + private function device_init_subscriptions($deviceid) + { + // INBOX always exists + $this->folder_set('INBOX', $deviceid, 1); + + $supported_types = array( + 'mail.drafts', + 'mail.wastebasket', + 'mail.sentitems', + 'mail.outbox', + 'event.default', + 'contact.default', + 'note.default', + 'task.default', + 'event', + 'contact', + 'note', + 'task', + 'event.confidential', + 'event.private', + 'task.confidential', + 'task.private', + ); + + // This default set can be extended by adding following values: + $modes = array( + 'SUB_PERSONAL' => 1, // all subscribed folders in personal namespace + 'ALL_PERSONAL' => 2, // all folders in personal namespace + 'SUB_OTHER' => 4, // all subscribed folders in other users namespace + 'ALL_OTHER' => 8, // all folders in other users namespace + 'SUB_SHARED' => 16, // all subscribed folders in shared namespace + 'ALL_SHARED' => 32, // all folders in shared namespace + ); + + $rcube = rcube::get_instance(); + $config = $rcube->config; + $mode = (int) $config->get('activesync_init_subscriptions'); + $folders = array(); + + // Subscribe to default folders + $foldertypes = kolab_storage::folders_typedata(); + + if (!empty($foldertypes)) { + $_foldertypes = array_intersect($foldertypes, $supported_types); + + // get default folders + foreach ($_foldertypes as $folder => $type) { + // only personal folders + if ($this->storage->folder_namespace($folder) == 'personal') { + $flag = preg_match('/^(event|task)/', $type) ? 2 : 1; + $this->folder_set($folder, $deviceid, $flag); + $folders = $folder; + } + } + } + + // we're in default mode, exit + if (!$mode) { + return; + } + + // below we support additionally all mail folders + $supported_types = 'mail'; + $supported_types = 'mail.junkemail'; + + // get configured special folders + $special_folders = array(); + $map = array( + 'drafts' => 'mail.drafts', + 'junk' => 'mail.junkemail', + 'sent' => 'mail.sentitems', + 'trash' => 'mail.wastebasket', + ); + + foreach ($map as $folder => $type) { + if ($folder = $config->get($folder . '_mbox')) { + $special_folders$folder = $type; + } + } + + // get folders list(s) + if (($mode & $modes'ALL_PERSONAL') || ($mode & $modes'ALL_OTHER') || ($mode & $modes'ALL_SHARED')) { + $all_folders = $this->storage->list_folders(); + if (($mode & $modes'SUB_PERSONAL') || ($mode & $modes'SUB_OTHER') || ($mode & $modes'SUB_SHARED')) { + $subscribed_folders = $this->storage->list_folders_subscribed(); + } + } + else { + $all_folders = $this->storage->list_folders_subscribed(); + } + + foreach ($all_folders as $folder) { + // folder already subscribed + if (in_array($folder, $folders)) { + continue; + } + + $type = $foldertypes$folder ?: 'mail'; + if ($type == 'mail' && isset($special_folders$folder)) { + $type = $special_folders$folder; + } + + if (!in_array($type, $supported_types)) { + continue; + } + + $ns = strtoupper($this->storage->folder_namespace($folder)); + + // subscribe the folder according to configured mode + // and folder namespace/subscription status + if (($mode & $modes"ALL_$ns") + || (($mode & $modes"SUB_$ns") + && (!isset($subscribed_folders) || in_array($folder, $subscribed_folders))) + ) { + $flag = preg_match('/^(event|task)/', $type) ? 2 : 1; + $this->folder_set($folder, $deviceid, $flag); + } + } + } + + /** + * Helper method to decode saved IMAP metadata + */ + private function unserialize_metadata($str) + { + if (!empty($str)) { + // Support old Z-Push annotation format + if ($str0 != '{') { + $str = base64_decode($str); + } + $data = json_decode($str, true); + return $data; + } + + return null; + } + + /** + * Helper method to encode IMAP metadata for saving + */ + private function serialize_metadata($data) + { + if (!empty($data) && is_array($data)) { + $data = json_encode($data); +// $data = base64_encode($data); + return $data; + } + + return null; + } + + /** + * Returns Kolab folder type for specified ActiveSync type ID + */ + public static function type_activesync2kolab($type) + { + if (!empty(self::$types$type)) { + return self::$types$type; + } + + return ''; + } + + /** + * Returns ActiveSync folder type for specified Kolab type + */ + public static function type_kolab2activesync($type) + { + $type = preg_replace('/\.(confidential|private)$/i', '', $type); + + if ($key = array_search($type, self::$types)) { + return $key; + } + + return key(self::$types); + } + + /** + * Returns Kolab folder type for specified ActiveSync class name + */ + public static function class_activesync2kolab($class) + { + if (!empty(self::$classes$class)) { + return self::$classes$class; + } + + return ''; + } + + /** + * Returns folder data in Syncroton format + */ + private function folder_data($folder, $type) + { + // Folder name parameters + $delim = $this->storage->get_hierarchy_delimiter(); + $items = explode($delim, $folder); + $name = array_pop($items); + + // Folder UID + $folder_id = $this->folder_id($folder, $type); + + // Folder type + if (strcasecmp($folder, 'INBOX') === 0) { + // INBOX is always inbox, prevent from issues related with a change of + // folder type annotation (it can be initially unset). + $type = 2; + } + else { + $type = self::type_kolab2activesync($type); + + // fix type, if there's no type annotation it's detected as UNKNOWN we'll use 'mail' (12) + if ($type == 1) { + $type = 12; + } + } + + // Syncroton folder data array + return array( + 'serverId' => $folder_id, + 'parentId' => count($items) ? self::folder_id(implode($delim, $items)) : 0, + 'displayName' => rcube_charset::convert($name, 'UTF7-IMAP', kolab_sync::CHARSET), + 'type' => $type, + // for internal use + 'imap_name' => $folder, + ); + } + + /** + * Builds folder ID based on folder name + */ + public function folder_id($name, $type = null) + { + // ActiveSync expects folder identifiers to be max.64 characters + // So we can't use just folder name + + $name = (string) $name; + + if ($name === '') { + return null; + } + + if (isset($this->folder_uids$name)) { + return $this->folder_uids$name; + } + +/* + @TODO: For now uniqueid annotation doesn't work, we will create UIDs by ourselves. + There's one inconvenience of this solution: folder name/type change + would be handled in ActiveSync as delete + create. + + // get folders unique identifier + $folderdata = $this->storage->get_metadata($name, self::UID_KEY); + + if ($folderdata && !empty($folderdata$name)) { + $uid = $folderdata$nameself::UID_KEY; + return $this->folder_uids$name = $uid; + } +*/ + if (strcasecmp($name, 'INBOX') === 0) { + // INBOX is always inbox, prevent from issues related with a change of + // folder type annotation (it can be initially unset). + $type = 'mail.inbox'; + } + else { + if ($type === null) { + $type = kolab_storage::folder_type($name); + } + + $type = preg_replace('/\.(confidential|private)$/i', '', $type); + } + + // Add type to folder UID hash, so type change can be detected by Syncroton + $uid = $name . '!!' . $type; + $uid = md5($uid); + + return $this->folder_uids$name = $uid; + } + + /** + * Returns IMAP folder name + * + * @param string $id Folder identifier + * @param string $deviceid Device dentifier + * + * @return string Folder name (UTF7-IMAP) + */ + public function folder_id2name($id, $deviceid) + { + // check in cache first + if (!empty($this->folder_uids)) { + if (($name = array_search($id, $this->folder_uids)) !== false) { + return $name; + } + } + +/* + @TODO: see folder_id() + + // get folders unique identifier + $folderdata = $this->storage->get_metadata('*', self::UID_KEY); + + foreach ((array)$folderdata as $folder => $data) { + if (!empty($dataself::UID_KEY)) { + $uid = $dataself::UID_KEY; + $this->folder_uids$folder = $uid; + if ($uid == $id) { + $name = $folder; + } + } + } +*/ + // get all folders of specified type + $folderdata = $this->folder_meta(); + + if (!is_array($folderdata) || $id === null) { + return null; + } + + // check if folders are "subscribed" for activesync + foreach ($folderdata as $folder => $meta) { + if (empty($meta'FOLDER') || empty($meta'FOLDER'$deviceid) + || empty($meta'FOLDER'$deviceid'S') + ) { + continue; + } + + if ($uid = self::folder_id($folder)) { + $this->folder_uids$folder = $uid; + } + + if ($uid === $id) { + $name = $folder; + } + } + + return $name; + } + + /** + */ + public function modseq_set($deviceid, $folderid, $synctime, $data) + { + $synctime = $synctime->format('Y-m-d H:i:s'); + $rcube = rcube::get_instance(); + $db = $rcube->get_dbh(); + $old_data = $this->modseq$folderid$synctime; + + if (empty($old_data)) { + $this->modseq$folderid$synctime = $data; + $data = json_encode($data); + + $db->set_option('ignore_key_errors', true); + $db->query("INSERT INTO `syncroton_modseq` (`device_id`, `folder_id`, `synctime`, `data`)" + ." VALUES (?, ?, ?, ?)", + $deviceid, $folderid, $synctime, $data); + $db->set_option('ignore_key_errors', false); + } + } + + public function modseq_get($deviceid, $folderid, $synctime) + { + $synctime = $synctime->format('Y-m-d H:i:s'); + + if (empty($this->modseq$folderid$synctime)) { + $this->modseq$folderid = array(); + + $rcube = rcube::get_instance(); + $db = $rcube->get_dbh(); + + $db->limitquery("SELECT `data`, `synctime` FROM `syncroton_modseq`" + ." WHERE `device_id` = ? AND `folder_id` = ? AND `synctime` <= ?" + ." ORDER BY `synctime` DESC", + 0, 1, $deviceid, $folderid, $synctime); + + if ($row = $db->fetch_assoc()) { + $synctime = $row'synctime'; + // @TODO: make sure synctime from sql is in "Y-m-d H:i:s" format + $this->modseq$folderid$synctime = json_decode($row'data', true); + } + + // Cleanup: remove all records except the current one + $db->query("DELETE FROM `syncroton_modseq`" + ." WHERE `device_id` = ? AND `folder_id` = ? AND `synctime` <> ?", + $deviceid, $folderid, $synctime); + } + + return @$this->modseq$folderid$synctime; + } + + /** + * Set state of relation objects at specified point in time + */ + public function relations_state_set($deviceid, $folderid, $synctime, $relations) + { + $synctime = $synctime->format('Y-m-d H:i:s'); + $rcube = rcube::get_instance(); + $db = $rcube->get_dbh(); + $old_data = $this->relations$folderid$synctime; + + if (empty($old_data)) { + $this->relations$folderid$synctime = $relations; + $data = rcube_charset::clean(json_encode($relations)); + + $db->set_option('ignore_key_errors', true); + $db->query("INSERT INTO `syncroton_relations_state`" + ." (`device_id`, `folder_id`, `synctime`, `data`)" + ." VALUES (?, ?, ?, ?)", + $deviceid, $folderid, $synctime, $data); + $db->set_option('ignore_key_errors', false); + } + } + + /** + * Get state of relation objects at specified point in time + */ + public function relations_state_get($deviceid, $folderid, $synctime) + { + $synctime = $synctime->format('Y-m-d H:i:s'); + + if (empty($this->relations$folderid$synctime)) { + $this->relations$folderid = array(); + + $rcube = rcube::get_instance(); + $db = $rcube->get_dbh(); + + $db->limitquery("SELECT `data`, `synctime` FROM `syncroton_relations_state`" + ." WHERE `device_id` = ? AND `folder_id` = ? AND `synctime` <= ?" + ." ORDER BY `synctime` DESC", + 0, 1, $deviceid, $folderid, $synctime); + + if ($row = $db->fetch_assoc()) { + $synctime = $row'synctime'; + // @TODO: make sure synctime from sql is in "Y-m-d H:i:s" format + $this->relations$folderid$synctime = json_decode($row'data', true); + } + + // Cleanup: remove all records except the current one + $db->query("DELETE FROM `syncroton_relations_state`" + ." WHERE `device_id` = ? AND `folder_id` = ? AND `synctime` <> ?", + $deviceid, $folderid, $synctime); + } + + return @$this->relations$folderid$synctime; + } + + /** + * Return last storage error + */ + public static function last_error() + { + return kolab_storage::$last_error; + } + + /** + * Compares two arrays + * + * @param array $array1 + * @param array $array2 + * + * @return bool True if arrays differs, False otherwise + */ + private static function data_array_diff($array1, $array2) + { + if (!is_array($array1) || !is_array($array2)) { + return $array1 != $array2; + } + + if (count($array1) != count($array2)) { + return true; + } + + foreach ($array1 as $key => $val) { + if (!array_key_exists($key, $array2)) { + return true; + } + if ($val !== $array2$key) { + return true; + } + } + + return false; + } +}
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_backend_common.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_backend_common.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -61,13 +61,13 @@ * * @var array */ - protected $cache = ; + protected $cache = array(); /** * Constructor */ - public function __construct() + function __construct() { $this->db = rcube::get_instance()->get_dbh(); @@ -79,10 +79,10 @@ /** * Creates new Syncroton object in database * - * @param object $object Object + * @param Syncroton_Model_* $object Object * - * @return object Object - * @throws InvalidArgumentException|Syncroton_Exception_DeadlockDetected|Exception + * @throws InvalidArgumentException + * @return Syncroton_Model_* Object */ public function create($object) { @@ -91,27 +91,21 @@ } $data = $this->object_to_array($object); - $cols = ; + $cols = array(); - $data'id' = $object->id = sha1(mt_rand() . microtime()); + $data'id' = $object->id = sha1(mt_rand(). microtime()); foreach (array_keys($data) as $key) { $cols = $this->db->quote_identifier($key); } - $result = $this->db->query( - 'INSERT INTO `' . $this->table_name . '`' . ' (' . implode(', ', $cols) . ')' + $result = $this->db->query('INSERT INTO `' . $this->table_name . '`' . ' (' . implode(', ', $cols) . ')' . ' VALUES(' . implode(', ', array_fill(0, count($cols), '?')) . ')', array_values($data) ); - if ($err = $this->db->is_error($result)) { - $err = "Failed to save instance of {$this->interface_name}: {$err}"; - if ($this->db->error_info()0 == '40001') { - throw new Syncroton_Exception_DeadlockDetected($err); - } else { - throw new Exception($err); - } + if ($this->db->is_error($result)) { + throw new Exception('Failed to save instance of ' . $this->interface_name); } return $object; @@ -120,17 +114,16 @@ /** * Returns Syncroton data object * - * @param string $id - * + * @param string $id * @throws Syncroton_Exception_NotFound - * @return object + * @return Syncroton_Model_* */ public function get($id) { $id = $id instanceof $this->interface_name ? $id->id : $id; if ($id) { - $select = $this->db->query('SELECT * FROM `' . $this->table_name . '` WHERE `id` = ?', $id); + $select = $this->db->query('SELECT * FROM `' . $this->table_name . '` WHERE `id` = ?', array($id)); $data = $this->db->fetch_assoc($select); } @@ -144,30 +137,19 @@ /** * Deletes Syncroton data object * - * @param string|Syncroton_Model_IEntry $id Object or identifier + * @param string|Syncroton_Model_* $id Object or identifier * * @return bool True on success, False on failure - * @throws Syncroton_Exception_DeadlockDetected|Exception */ public function delete($id) { - // @phpstan-ignore-next-line $id = $id instanceof $this->interface_name ? $id->id : $id; if (!$id) { return false; } - $result = $this->db->query('DELETE FROM `' . $this->table_name . '` WHERE `id` = ?', $id); - - if ($err = $this->db->is_error($result)) { - $err = "Failed to delete instance of {$this->interface_name}: {$err}"; - if ($this->db->error_info()0 == '40001') { - throw new Syncroton_Exception_DeadlockDetected($err); - } else { - throw new Exception($err); - } - } + $result = $this->db->query('DELETE FROM `' . $this->table_name .'` WHERE `id` = ?', array($id)); return (bool) $this->db->affected_rows($result); } @@ -175,10 +157,10 @@ /** * Updates Syncroton data object * - * @param object $object + * @param Syncroton_Model_* $object * - * @return object Object - * @throws InvalidArgumentException|Syncroton_Exception_DeadlockDetected|Exception + * @throws InvalidArgumentException + * @return Syncroton_Model_* Object */ public function update($object) { @@ -187,24 +169,15 @@ } $data = $this->object_to_array($object); - $set = ; + $set = array(); foreach (array_keys($data) as $key) { $set = $this->db->quote_identifier($key) . ' = ?'; } - $result = $this->db->query('UPDATE `' . $this->table_name . '` SET ' . implode(', ', $set) + $this->db->query('UPDATE `' . $this->table_name . '` SET ' . implode(', ', $set) . ' WHERE `id` = ' . $this->db->quote($object->id), array_values($data)); - if ($err = $this->db->is_error($result)) { - $err = "Failed to update instance of {$this->interface_name}: {$err}"; - if ($this->db->error_info()0 == '40001') { - throw new Syncroton_Exception_DeadlockDetected($err); - } else { - throw new Exception($err); - } - } - return $object; } @@ -218,7 +191,6 @@ public function userAccounts($device) { // this method is overwritten by kolab_sync_backend class - return ; } /** @@ -244,7 +216,7 @@ */ protected function object_to_array($object) { - $data = ; + $data = array(); foreach ($object as $key => $value) { if ($value instanceof DateTime) {
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_backend_content.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_backend_content.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -42,7 +42,7 @@ { $id = $id instanceof Syncroton_Model_IContent ? $id->id : $id; - $result = $this->db->query("UPDATE `{$this->table_name}` SET `is_deleted` = 1 WHERE `id` = ?", $id); + $result = $this->db->query("UPDATE `{$this->table_name}` SET `is_deleted` = 1 WHERE `id` = ?", array($id)); if ($result = (bool) $this->db->affected_rows($result)) { unset($this->cache'content_folderstate'); @@ -55,7 +55,6 @@ * @param Syncroton_Model_IDevice|string $_deviceId * @param Syncroton_Model_IFolder|string $_folderId * @param string $_contentId - * * @return Syncroton_Model_IContent */ public function getContentState($_deviceId, $_folderId, $_contentId) @@ -83,15 +82,13 @@ * * @param Syncroton_Model_IDevice|string $_deviceId * @param Syncroton_Model_IFolder|string $_folderId - * @param int $syncKey - * * @return array */ - public function getFolderState($_deviceId, $_folderId, $syncKey = null) + public function getFolderState($_deviceId, $_folderId) { $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId; $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId; - $cachekey = $deviceId . ':' . $folderId . ':' . ($syncKey ?: '*'); + $cachekey = $deviceId . ':' . $folderId; // in Sync request we call this function twice in case when // folder state changed - use cache to skip at least one SELECT query @@ -102,12 +99,9 @@ $where = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId); $where = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folderId); $where = $this->db->quote_identifier('is_deleted') . ' = 0'; - if ($syncKey) { - $where = $this->db->quote_identifier('creation_synckey') . ' < ' . $this->db->quote($syncKey + 1); - } $select = $this->db->query("SELECT `contentid` FROM `{$this->table_name}` WHERE " . implode(' AND ', $where)); - $result = ; + $result = array(); while ($state = $this->db->fetch_assoc($select)) { $result = $state'contentid'; @@ -126,8 +120,9 @@ { $deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId; $folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId; + $cachekey = $deviceId . ':' . $folderId; - unset($this->cache'content_folderstate'); + unset($this->cache'content_folderstate'$cachekey); $where = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId); $where = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folderId);
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_backend_device.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_backend_device.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -32,9 +32,9 @@ protected $interface_name = 'Syncroton_Model_IDevice'; /** - * Kolab Sync storage backend + * Kolab Sync backend * - * @var kolab_sync_storage + * @var kolab_sync_backend */ protected $backend; @@ -45,7 +45,7 @@ public function __construct() { parent::__construct(); - $this->backend = kolab_sync::storage(); + $this->backend = kolab_sync_backend::get_instance(); } /** @@ -60,11 +60,11 @@ $device = parent::create($device); // Create device entry in kolab backend - $created = $this->backend->device_create( + $created = $this->backend->device_create(array( 'ID' => $device->id, 'TYPE' => $device->devicetype, 'ALIAS' => $device->friendlyname, - , $device->deviceid); + ), $device->deviceid); if (!$created) { throw new Syncroton_Exception_NotFound('Device creation failed'); @@ -76,7 +76,7 @@ /** * Delete a device * - * @param string|Syncroton_Model_IDevice $device Device object + * @param Syncroton_Model_IDevice $device Device object * * @return bool True on success, False on failure */ @@ -135,8 +135,7 @@ $engine = kolab_sync::get_instance(); $identities = $engine->user->list_identities(); $email = $engine->get_user_email(); - $addresses = ; - $displayname = null; + $addresses = array(); // read email addresses and display name (default ident comes first) foreach ((array)$identities as $ident) { @@ -148,20 +147,20 @@ } if (empty($displayname) && empty($email) && empty($addresses)) { - return ; + return array(); } - $account = new Syncroton_Model_Account(); + $account = new Syncroton_Model_Account; if ($email) { - $addresses = array_diff($addresses, $email); + $addresses = array_diff($addresses, array($email)); } $account->userDisplayName = $displayname; $account->primaryAddress = $email; $account->addresses = array_unique($addresses); - return $account; + return array($account); } /** @@ -169,14 +168,14 @@ * * @param array $request Oof/Get request data * - * @return Syncroton_Model_Oof|null Response object or NULL if OOF is not supported + * @return Syncroton_Model_Oof Response object or NULL if OOF is not supported * @throws Syncroton_Exception_Status */ public function getOOF($request) { $vacation_engine = $this->vacation_engine(); if (!$vacation_engine) { - return null; + return; } $vacation = $vacation_engine->get_vacation(); @@ -184,7 +183,8 @@ if (!$vacation'enabled') { $status = Syncroton_Model_Oof::STATUS_DISABLED; $vacation'start' = $vacation'end' = null; - } elseif ($vacation'start' || $vacation'end') { + } + else if ($vacation'start' || $vacation'end') { // in Activesync both or none time are required if (!$vacation'start' && $vacation'end') { $vacation'start' = new DateTime('1970-01-01', new DateTimeZone('UTC')); @@ -202,37 +202,34 @@ } $status = Syncroton_Model_Oof::STATUS_TIME_BASED; - } else { + } + else { $status = Syncroton_Model_Oof::STATUS_GLOBAL; } - $message = null; - if ($vacation'message') { - $message = ; - // convert message format, Roundcube supports plain text only if ($request'bodyType' == 'HTML') { $text2html = new rcube_text2html($vacation'message'); $vacation'message' = $text2html->get_html(); } - foreach ('Internal', 'ExternalKnown', 'ExternalUnknown' as $type) { - $message = new Syncroton_Model_OofMessage( + foreach (array('Internal', 'ExternalKnown', 'ExternalUnknown') as $type) { + $message = new Syncroton_Model_OofMessage(array( "appliesTo$type" => true, 'enabled' => 1, 'bodyType' => 'Text', 'replyMessage' => rcube_charset::clean($vacation'message'), - ); + )); } } - return new Syncroton_Model_Oof( + return new Syncroton_Model_Oof(array( 'oofState' => $status, 'startTime' => $vacation'start', 'endTime' => $vacation'end', 'oofMessage' => $message, - ); + )); } /** @@ -260,7 +257,8 @@ if (empty($vacation'start') || empty($vacation'end')) { throw new Syncroton_Exception_Status_Settings(Syncroton_Exception_Status_Settings::INVALID_ARGUMENTS); } - } else { + } + else { $vacation'start' = $vacation'end' = null; } @@ -289,7 +287,7 @@ $vacation_engine->set_vacation($vacation); } // disable out-of-office - elseif (isset($request->oofState)) { + else if (isset($request->oofState)) { if ($vacation'enabled') { $vacation'enabled' = false; @@ -308,7 +306,7 @@ if (class_exists('managesieve')) { $plugin = $engine->plugins->get_plugin('managesieve'); - $vacation = $plugin->get_engine('vacation'); // @phpstan-ignore-line + $vacation = $plugin->get_engine('vacation'); if ($vacation->connect($engine->username, $engine->password)) { throw new Exception("Connection to managesieve server failed");
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_backend_folder.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_backend_folder.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -50,22 +50,18 @@ * * @param Syncroton_Model_Device|string $deviceid Device object or identifier * @param string $class Class name - * @param int $syncKey Sync key * * @return array List of object identifiers */ - public function getFolderState($deviceid, $class, $syncKey = null) + public function getFolderState($deviceid, $class) { $device_id = $deviceid instanceof Syncroton_Model_IDevice ? $deviceid->id : $deviceid; $where = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id); - $where = $this->db->quote_identifier('class') . ' = ' . $this->db->quote($class); - if ($syncKey) { - $where = $this->db->quote_identifier('creation_synckey') . ' < ' . $this->db->quote($syncKey + 1); - } + $where = $this->db->quote_identifier('class') . ' = ' . $this->db->quote($class); - $select = $this->db->query('SELECT * FROM `' . $this->table_name . '` WHERE ' . implode(' AND ', $where)); - $result = ; + $select = $this->db->query('SELECT * FROM `' . $this->table_name .'` WHERE ' . implode(' AND ', $where)); + $result = array(); while ($folder = $this->db->fetch_assoc($select)) { $result$folder'folderid' = $this->get_object($folder); @@ -87,16 +83,13 @@ $device_id = $deviceid instanceof Syncroton_Model_IDevice ? $deviceid->id : $deviceid; $where = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id); - $where = $this->db->quote_identifier('folderid') . ' = ' . $this->db->quote($folderid); + $where = $this->db->quote_identifier('folderid') . ' = ' . $this->db->quote($folderid); $select = $this->db->query('SELECT * FROM `' . $this->table_name . '` WHERE ' . implode(' AND ', $where)); $folder = $this->db->fetch_assoc($select); - if (!empty($folder'resync')) { - throw new Syncroton_Exception_NotFound("Folder $folderid not found because of resync"); - } if (empty($folder)) { - throw new Syncroton_Exception_NotFound("Folder $folderid not found"); + throw new Syncroton_Exception_NotFound('Folder not found'); } return $this->get_object($folder); @@ -114,43 +107,39 @@ $timestamp = new DateTime('now', new DateTimeZone('utc')); $client_crc = ''; $server_crc = ''; - $client_folders = ; - $server_folders = ; - $folder_classes = + $client_folders = array(); + $server_folders = array(); + $folder_classes = array( Syncroton_Data_Factory::CLASS_CALENDAR, Syncroton_Data_Factory::CLASS_CONTACTS, Syncroton_Data_Factory::CLASS_EMAIL, Syncroton_Data_Factory::CLASS_NOTES, - Syncroton_Data_Factory::CLASS_TASKS, - ; + Syncroton_Data_Factory::CLASS_TASKS + ); // Reset imap cache so we work with up-to-date folders list rcube::get_instance()->get_storage()->clear_cache('mailboxes', true); - // Retrieve all folders already sent to the client - $select = $this->db->query("SELECT * FROM `{$this->table_name}` WHERE `device_id` = ?", $device->id); - - while ($folder = $this->db->fetch_assoc($select)) { - if (!empty($folder'resync')) { - // Folder re-sync requested - return true; - } - - $client_folders$folder'folderid' = $this->get_object($folder); - } - foreach ($folder_classes as $class) { try { // retrieve all folders available in data backend $dataController = Syncroton_Data_Factory::factory($class, $device, $timestamp); $server_folders = array_merge($server_folders, $dataController->getAllFolders()); - } catch (Exception $e) { + } + catch (Exception $e) { rcube::raise_error($e, true, false); // This is server error, returning True might cause infinite sync loops return false; } } + // retrieve all folders sent to the client + $select = $this->db->query("SELECT * FROM `{$this->table_name}` WHERE `device_id` = ?", $device->id); + + while ($folder = $this->db->fetch_assoc($select)) { + $client_folders$folder'folderid' = $this->get_object($folder); + } + ksort($client_folders); ksort($server_folders); @@ -175,10 +164,15 @@ case 'displayName': case 'parentId': return strtolower($string); + break; + case 'serverId': return 'folderid'; + break; + default: return parent::from_camelcase($string); + break; } } @@ -191,12 +185,19 @@ switch ($string) { case 'displayname': return 'displayName'; + break; + case 'parentid': return 'parentId'; + break; + case 'folderid': return 'serverId'; + break; + default: return parent::to_camelcase($string, $ucFirst); + break; } } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_backend_policy.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_backend_policy.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | |
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_backend_state.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_backend_state.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -41,7 +41,6 @@ */ public function create($object, $keep_previous_state = true) { - unset($object->counterNext); $object = parent::create($object); if ($keep_previous_state !== true) { @@ -58,9 +57,9 @@ protected function _deleteOtherStates(Syncroton_Model_ISyncState $state) { // remove all other synckeys - $where = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($state->deviceId); - $where = $this->db->quote_identifier('type') . ' = ' . $this->db->quote($state->type); - $where = $this->db->quote_identifier('counter') . ' <> ' . $this->db->quote($state->counter); + $where = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($state->deviceId); + $where = $this->db->quote_identifier('type') . ' = ' . $this->db->quote($state->type); + $where = $this->db->quote_identifier('counter') . ' <> ' . $this->db->quote($state->counter); $this->db->query("DELETE FROM `{$this->table_name}` WHERE " . implode(' AND ', $where)); } @@ -110,7 +109,7 @@ $folder_id = $folderid instanceof Syncroton_Model_IFolder ? $folderid->id : $folderid; $where = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id); - $where = $this->db->quote_identifier('type') . ' = ' . $this->db->quote($folder_id); + $where = $this->db->quote_identifier('type') . ' = ' . $this->db->quote($folder_id); $select = $this->db->limitquery("SELECT * FROM `{$this->table_name}` WHERE " . implode(' AND ', $where) . " ORDER BY `counter` DESC", 0, 1); @@ -136,7 +135,7 @@ $folder_id = $folderid instanceof Syncroton_Model_IFolder ? $folderid->id : $folderid; $where = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id); - $where = $this->db->quote_identifier('type') . ' = ' . $this->db->quote($folder_id); + $where = $this->db->quote_identifier('type') . ' = ' . $this->db->quote($folder_id); $this->db->query("DELETE FROM `{$this->table_name}` WHERE " . implode(' AND ', $where)); } @@ -148,19 +147,19 @@ * @param Syncroton_Model_IFolder|string $folderid Folder object or identifier * @param int $sync_key State key * - * @return Syncroton_Model_SyncState|false + * @return Syncroton_Model_SyncState */ public function validate($deviceid, $folderid, $sync_key) { $device_id = $deviceid instanceof Syncroton_Model_IDevice ? $deviceid->id : $deviceid; $folder_id = $folderid instanceof Syncroton_Model_IFolder ? $folderid->id : $folderid; - $states = ; + $states = array(); // get sync data // we'll get all records, thanks to this we'll be able to // skip _deleteOtherStates() call below (one DELETE query less) $where'device_id' = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id); - $where'type' = $this->db->quote_identifier('type') . ' = ' . $this->db->quote($folder_id); + $where'type' = $this->db->quote_identifier('type') . ' = ' . $this->db->quote($folder_id); $select = $this->db->query("SELECT * FROM `{$this->table_name}` WHERE " . implode(' AND ', $where)); @@ -176,33 +175,26 @@ $state = $states$sync_key; $next = max(array_keys($states)); - $where = ; - $where'device_id' = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id); - $where'folder_id' = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folder_id); + $where = array(); + $where'device_id' = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id); + $where'folder_id' = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folder_id); $where'is_deleted' = $this->db->quote_identifier('is_deleted') . ' = 1'; - // found more recent synckey => the last sync response was not received by the client + // found more recent synckey => the last sync response got not received by the client if ($next > $sync_key) { - // We store the clientIdMap with the "next" sync state, so we need to copy it back. - $state->clientIdMap = $states$next->clientIdMap; - $state->counterNext = $next; - } else { - // finally delete all entries marked for removal in syncroton_content table - $retryCounter = 0; - while (true) { - $result = $this->db->query("DELETE FROM `syncroton_content` WHERE " . implode(' AND ', $where)); - if ($this->db->is_error($result)) { - $retryCounter++; - // Retry on deadlock - if ($this->db->error_info()0 != '40001' || $retryCounter > 60) { - throw new Exception('Failed to delete entries in sync_key check'); - } - } else { - break; - } - //Give the other transactions some time before we try again - sleep(1); - } + $where'synckey' = $this->db->quote_identifier('creation_synckey') . ' = ' . $this->db->quote($state->counter); + // undelete entries marked as deleted in syncroton_content table + $this->db->query("UPDATE `syncroton_content` SET `is_deleted` = 0 WHERE " . implode(' AND ', $where)); + + // remove entries added during latest sync in syncroton_content table + unset($where'is_deleted'); + $where'synckey' = $this->db->quote_identifier('creation_synckey') . ' > ' . $this->db->quote($state->counter); + + $this->db->query("DELETE FROM `syncroton_content` WHERE " . implode(' AND ', $where)); + } + else { + // finaly delete all entries marked for removal in syncroton_content table + $this->db->query("DELETE FROM `syncroton_content` WHERE " . implode(' AND ', $where)); } // remove all other synckeys @@ -212,17 +204,4 @@ return $state; } - - public function haveNext($deviceid, $folderid, $sync_key) - { - $device_id = $deviceid instanceof Syncroton_Model_IDevice ? $deviceid->id : $deviceid; - $folder_id = $folderid instanceof Syncroton_Model_IFolder ? $folderid->id : $folderid; - - $where'device_id' = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id); - $where'type' = $this->db->quote_identifier('type') . ' = ' . $this->db->quote($folder_id); - $where'counter' = $this->db->quote_identifier('counter') . ' > ' . $this->db->quote($sync_key); - - $select = $this->db->query("SELECT id FROM `{$this->table_name}` WHERE " . implode(' AND ', $where)); - return $this->db->num_rows($select) > 0; - } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_body_converter.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_body_converter.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -60,14 +60,14 @@ // ActiveSync types: TYPE_PLAINTEXT, TYPE_HTML, TYPE_RTF, TYPE_MIME switch ($this->type) { - case Syncroton_Model_EmailBody::TYPE_PLAINTEXT: - return $this->convert_plain($type); - case Syncroton_Model_EmailBody::TYPE_HTML: - return $this->convert_html($type); - case Syncroton_Model_EmailBody::TYPE_RTF: - return $this->convert_rtf($type); - default: - return $this->text; + case Syncroton_Model_EmailBody::TYPE_PLAINTEXT: + return $this->convert_text_plain($type); + case Syncroton_Model_EmailBody::TYPE_HTML: + return $this->convert_text_html($type); + case Syncroton_Model_EmailBody::TYPE_RTF: + return $this->convert_rtf($type); + default: + return $this->text; } } @@ -79,16 +79,16 @@ * * @return string Body value */ - protected function convert_plain($type) + protected function convert_text_plain($type) { $data = $this->text; switch ($type) { - case Syncroton_Model_EmailBody::TYPE_HTML: - return '<pre>' . htmlspecialchars($data, ENT_COMPAT, kolab_sync::CHARSET) . '</pre>'; - case Syncroton_Model_EmailBody::TYPE_RTF: - // @TODO - return ''; + case Syncroton_Model_EmailBody::TYPE_HTML: + return '<pre>' . htmlspecialchars($data, ENT_COMPAT, kolab_sync::CHARSET) . '</pre>'; + case Syncroton_Model_EmailBody::TYPE_RTF: + // @TODO + return ''; } return $data; @@ -102,17 +102,17 @@ * * @return string Body value */ - protected function convert_html($type) + protected function convert_text_html($type) { switch ($type) { - case Syncroton_Model_EmailBody::TYPE_PLAINTEXT: - $txt = new rcube_html2text($this->text, false, true); - return $txt->get_text(); - case Syncroton_Model_EmailBody::TYPE_RTF: - // @TODO - return ''; - case Syncroton_Model_EmailBody::TYPE_MIME: - return ''; + case Syncroton_Model_EmailBody::TYPE_PLAINTEXT: + $txt = new rcube_html2text($this->text, false, true); + return $txt->get_text(); + case Syncroton_Model_EmailBody::TYPE_RTF: + // @TODO + return ''; + case Syncroton_Model_EmailBody::TYPE_MIME: + return ''; } return $this->text; @@ -128,28 +128,20 @@ */ protected function convert_rtf($type) { + $rtf = new rtf(); + $rtf->loadrtf($this->text); + switch ($type) { - case Syncroton_Model_EmailBody::TYPE_PLAINTEXT: - try { - $document = new RtfHtmlPhp\Document($this->text); - $formatter = new RtfHtmlPhp\Html\HtmlFormatter(RCUBE_CHARSET); - $txt = new rcube_html2text($formatter->format($document), false, true); - return $txt->get_text(); - } catch (Exception $e) { - $logger = Syncroton_Registry::get('loggerBackend'); - $logger->warn("Failed to convert RTF content"); - return ''; - } - case Syncroton_Model_EmailBody::TYPE_HTML: - try { - $document = new RtfHtmlPhp\Document($this->text); - $formatter = new RtfHtmlPhp\Html\HtmlFormatter(RCUBE_CHARSET); - return $formatter->format($document); - } catch (Exception $e) { - $logger = Syncroton_Registry::get('loggerBackend'); - $logger->warn("Failed to convert RTF content"); - return ''; - } + case Syncroton_Model_EmailBody::TYPE_PLAINTEXT: + $rtf->output('ascii'); + $rtf->parse(); + return $rtf->out; + case Syncroton_Model_EmailBody::TYPE_HTML: + // @TODO: Conversion to HTML is broken, + // convert to text and use <PRE> tags + $rtf->output('ascii'); + $rtf->parse(); + return '<pre>' . trim($rtf->out) . '</pre>'; } return $this->text;
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_data.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_data.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -31,18 +31,11 @@ /** * ActiveSync protocol version * - * @var float + * @var int */ protected $asversion = 0; /** - * The storage backend - * - * @var kolab_sync_storage - */ - protected $backend; - - /** * information about the current device * * @var Syncroton_Model_IDevice @@ -78,13 +71,6 @@ protected $defaultFolder; /** - * default root folder - * - * @var string - */ - protected $defaultRootFolder; - - /** * type of user created folders * * @var int @@ -92,17 +78,24 @@ protected $folderType; /** - * Internal cache for storage folders list + * Internal cache for kolab_storage folder objects * * @var array */ - protected $folders = ; + protected $folders = array(); /** - * Logger instance. + * Internal cache for IMAP folders list * - * @var kolab_sync_logger + * @var array */ + protected $imap_folders = array(); + + /** + * Logger instance. + * + * @var kolab_sync_logger + */ protected $logger; /** @@ -117,7 +110,7 @@ * * @var array */ - protected $ext_devices = + protected $ext_devices = array( 'iphone', 'ipad', 'thundertine', @@ -125,50 +118,47 @@ 'wp', 'wp8', 'playbook', - ; - - protected $lastsync_folder = null; - protected $lastsync_time = null; + ); - public const RESULT_OBJECT = 0; - public const RESULT_UID = 1; - public const RESULT_COUNT = 2; + const RESULT_OBJECT = 0; + const RESULT_UID = 1; + const RESULT_COUNT = 2; /** * Recurrence types */ - public const RECUR_TYPE_DAILY = 0; // Recurs daily. - public const RECUR_TYPE_WEEKLY = 1; // Recurs weekly - public const RECUR_TYPE_MONTHLY = 2; // Recurs monthly - public const RECUR_TYPE_MONTHLY_DAYN = 3; // Recurs monthly on the nth day - public const RECUR_TYPE_YEARLY = 5; // Recurs yearly - public const RECUR_TYPE_YEARLY_DAYN = 6; // Recurs yearly on the nth day + const RECUR_TYPE_DAILY = 0; // Recurs daily. + const RECUR_TYPE_WEEKLY = 1; // Recurs weekly + const RECUR_TYPE_MONTHLY = 2; // Recurs monthly + const RECUR_TYPE_MONTHLY_DAYN = 3; // Recurs monthly on the nth day + const RECUR_TYPE_YEARLY = 5; // Recurs yearly + const RECUR_TYPE_YEARLY_DAYN = 6; // Recurs yearly on the nth day /** * Day of week constants */ - public const RECUR_DOW_SUNDAY = 1; - public const RECUR_DOW_MONDAY = 2; - public const RECUR_DOW_TUESDAY = 4; - public const RECUR_DOW_WEDNESDAY = 8; - public const RECUR_DOW_THURSDAY = 16; - public const RECUR_DOW_FRIDAY = 32; - public const RECUR_DOW_SATURDAY = 64; - public const RECUR_DOW_LAST = 127; // The last day of the month. Used as a special value in monthly or yearly recurrences. + const RECUR_DOW_SUNDAY = 1; + const RECUR_DOW_MONDAY = 2; + const RECUR_DOW_TUESDAY = 4; + const RECUR_DOW_WEDNESDAY = 8; + const RECUR_DOW_THURSDAY = 16; + const RECUR_DOW_FRIDAY = 32; + const RECUR_DOW_SATURDAY = 64; + const RECUR_DOW_LAST = 127; // The last day of the month. Used as a special value in monthly or yearly recurrences. /** * Mapping of recurrence types * * @var array */ - protected $recurTypeMap = + protected $recurTypeMap = array( self::RECUR_TYPE_DAILY => 'DAILY', self::RECUR_TYPE_WEEKLY => 'WEEKLY', self::RECUR_TYPE_MONTHLY => 'MONTHLY', self::RECUR_TYPE_MONTHLY_DAYN => 'MONTHLY', self::RECUR_TYPE_YEARLY => 'YEARLY', self::RECUR_TYPE_YEARLY_DAYN => 'YEARLY', - ; + ); /** * Mapping of weekdays @@ -176,7 +166,7 @@ * * @var array */ - protected $recurDayMap = + protected $recurDayMap = array( 'SU' => self::RECUR_DOW_SUNDAY, 'MO' => self::RECUR_DOW_MONDAY, 'TU' => self::RECUR_DOW_TUESDAY, @@ -184,7 +174,7 @@ 'TH' => self::RECUR_DOW_THURSDAY, 'FR' => self::RECUR_DOW_FRIDAY, 'SA' => self::RECUR_DOW_SATURDAY, - ; + ); /** @@ -195,10 +185,10 @@ */ public function __construct(Syncroton_Model_IDevice $device, DateTime $syncTimeStamp) { - $this->backend = kolab_sync::storage(); + $this->backend = kolab_sync_backend::get_instance(); $this->device = $device; $this->asversion = floatval($device->acsversion); - $this->syncTimeStamp = $this->backend->syncTimeStamp = $syncTimeStamp; + $this->syncTimeStamp = $syncTimeStamp; $this->logger = Syncroton_Registry::get(Syncroton_Registry::LOGGERBACKEND); $this->defaultRootFolder = $this->defaultFolder . '::Syncroton'; @@ -207,7 +197,8 @@ try { $this->timezone = rcube::get_instance()->config->get('timezone', 'GMT'); kolab_format::$timezone = new DateTimeZone($this->timezone); - } catch (Exception $e) { + } + catch (Exception $e) { //rcube::raise_error($e, true); $this->timezone = 'GMT'; kolab_format::$timezone = new DateTimeZone('GMT'); @@ -221,14 +212,15 @@ */ public function getAllFolders() { - $list = ; + $list = array(); // device supports multiple folders ? if ($this->isMultiFolder()) { // get the folders the user has access to $list = $this->listFolders(); - } elseif ($default = $this->getDefaultFolder()) { - $list = $default'serverId' => $default; + } + else if ($default = $this->getDefaultFolder()) { + $list = array($default'serverId' => $default); } // getAllFolders() is called only in FolderSync @@ -254,9 +246,7 @@ */ public function getChangedFolders(DateTime $startTimeStamp, DateTime $endTimeStamp) { - // FIXME/TODO: Can we get mtime of a DAV folder? - // Without this, we have a problem if folder ID does not change on rename - return ; + return array(); } /** @@ -299,7 +289,8 @@ // Return first on the list if there's no default if (empty($default)) { - $default = array_first($folders); + $key = array_shift(array_keys($folders)); + $default = $folders$key; // make sure the type is default here $default'type' = $this->defaultFolderType; } @@ -317,16 +308,46 @@ */ public function createFolder(Syncroton_Model_IFolder $folder) { - $result = $this->backend->folder_create($folder->displayName, $folder->type, $this->device->deviceid, $folder->parentId); + $parentid = $folder->parentId; + $type = $folder->type; + $display_name = $folder->displayName; + + if ($parentid) { + $parent = $this->backend->folder_id2name($parentid, $this->device->deviceid); + + if ($parent === null) { + throw new Syncroton_Exception_Status_FolderCreate(Syncroton_Exception_Status_FolderCreate::PARENT_NOT_FOUND); + } + } + + $name = rcube_charset::convert($display_name, kolab_sync::CHARSET, 'UTF7-IMAP'); + + if ($parent !== null) { + $rcube = rcube::get_instance(); + $storage = $rcube->get_storage(); + $delim = $storage->get_hierarchy_delimiter(); + $name = $parent . $delim . $name; + } + + // Create IMAP folder + $result = $this->backend->folder_create($name, $type, $this->device->deviceid); if ($result) { - $folder->serverId = $result; + $folder->serverId = $this->backend->folder_id($name); return $folder; } + $errno = Syncroton_Exception_Status_FolderCreate::UNKNOWN_ERROR; + + // Special case when client tries to create a subfolder of INBOX + // which is not possible on Cyrus-IMAP (T2223) + if ($parent == 'INBOX' && stripos($this->backend->last_error(), 'invalid') !== false) { + $errno = Syncroton_Exception_Status_FolderCreate::SPECIAL_FOLDER; + } + // Note: Looks like Outlook 2013 ignores any errors on FolderCreate command - throw new Syncroton_Exception_Status_FolderCreate(Syncroton_Exception_Status_FolderCreate::UNKNOWN_ERROR); + throw new Syncroton_Exception_Status_FolderCreate($errno); } /** @@ -334,7 +355,32 @@ */ public function updateFolder(Syncroton_Model_IFolder $folder) { - $result = $this->backend->folder_rename($folder->serverId, $this->device->deviceid, $folder->displayName, $folder->parentId); + $parentid = $folder->parentId; + $type = $folder->type; + $display_name = $folder->displayName; + $old_name = $this->backend->folder_id2name($folder->serverId, $this->device->deviceid); + + if ($parentid) { + $parent = $this->backend->folder_id2name($parentid, $this->device->deviceid); + } + + $name = rcube_charset::convert($display_name, kolab_sync::CHARSET, 'UTF7-IMAP'); + + if ($parent !== null) { + $rcube = rcube::get_instance(); + $storage = $rcube->get_storage(); + $delim = $storage->get_hierarchy_delimiter(); + $name = $parent . $delim . $name; + } + + // Rename/move IMAP folder + if ($name == $old_name) { + $result = true; + // @TODO: folder type change? + } + else { + $result = $this->backend->folder_rename($old_name, $name, $type); + } if ($result) { return $folder; @@ -352,28 +398,53 @@ $folder = $folder->serverId; } + $name = $this->backend->folder_id2name($folder, $this->device->deviceid); + // @TODO: throw exception - return $this->backend->folder_delete($folder, $this->device->deviceid); + return $this->backend->folder_delete($name, $this->device->deviceid); } /** * Empty folder (remove all entries and optionally subfolders) * - * @param string $folderid Folder identifier + * @param string $folderId Folder identifier * @param array $options Options */ public function emptyFolderContents($folderid, $options) { - // ActiveSync spec.: Clients use EmptyFolderContents to empty the Deleted Items folder. - // The client can clear out all items in the Deleted Items folder when the user runs out of storage quota - // (indicated by the return of an MailboxQuotaExceeded (113) status code from the server. - // FIXME: Does that mean we don't need this to work on any other folder? - // TODO: Respond with MailboxQuotaExceeded status. Where exactly? - - foreach ($this->extractFolders($folderid) as $folderid) { - if (!$this->backend->folder_empty($folderid, $this->device->deviceid, !empty($options'deleteSubFolders'))) { + $folders = $this->extractFolders($folderid); + + foreach ($folders as $folderid) { + $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid); + $folder = $this->getFolderObject($foldername); + + if (!$folder || !$folder->valid) { throw new Syncroton_Exception_Status_ItemOperations(Syncroton_Exception_Status_ItemOperations::ITEM_SERVER_ERROR); } + + // Remove all entries + $folder->delete_all(); + + // Remove subfolders + if (!empty($options'deleteSubFolders')) { + $list = $this->listFolders($folderid); + + if (!is_array($list)) { + throw new Syncroton_Exception_Status_ItemOperations(Syncroton_Exception_Status_ItemOperations::ITEM_SERVER_ERROR); + } + + foreach ($list as $folderid => $folder) { + $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid); + $folder = $this->getFolderObject($foldername); + + if (!$folder || !$folder->valid) { + throw new Syncroton_Exception_Status_ItemOperations(Syncroton_Exception_Status_ItemOperations::ITEM_SERVER_ERROR); + } + + // Remove all entries + $folder->delete_all(); + } + } } } @@ -389,16 +460,23 @@ */ public function moveItem($srcFolderId, $serverId, $dstFolderId) { - // TODO: Optimize, we just need to find the folder ID and UID, we do not need to "fetch" it. - $item = $this->getObject($srcFolderId, $serverId); + $item = $this->getObject($srcFolderId, $serverId, $folder); - if (!$item) { + if (!$item || !$folder) { throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE); } - $uid = $this->backend->moveItem($item'folderId', $this->device->deviceid, $this->modelName, $item'uid', $dstFolderId); + $dstname = $this->backend->folder_id2name($dstFolderId, $this->device->deviceid); + + if ($dstname === null) { + throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_DESTINATION); + } + + if (!$folder->move($serverId, $dstname)) { + throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE); + } - return $this->serverId($uid, $dstFolderId); + return $item'uid'; } /** @@ -412,32 +490,21 @@ public function createEntry($folderId, Syncroton_Model_IEntry $entry) { $entry = $this->toKolab($entry, $folderId); + $entry = $this->createObject($folderId, $entry); - if ($folderId == $this->defaultRootFolder) { - $default = $this->getDefaultFolder(); - - if (!is_array($default)) { - throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); - } - - $folderId = $default'realid' ?? $default'serverId'; - } - - $uid = $this->backend->createItem($folderId, $this->device->deviceid, $this->modelName, $entry); - - if (empty($uid)) { + if (empty($entry)) { throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); } - return $this->serverId($uid, $folderId); + return $entry'_serverId'; } /** * update existing entry * - * @param string $folderId - * @param string $serverId - * @param Syncroton_Model_IEntry $entry + * @param string $folderId + * @param string $serverId + * @param SimpleXMLElement $entry * * @return string ID of the updated entry */ @@ -450,49 +517,39 @@ } $entry = $this->toKolab($entry, $folderId, $oldEntry); - $uid = $this->backend->updateItem($oldEntry'folderId', $this->device->deviceid, $this->modelName, $oldEntry'uid', $entry); + $entry = $this->updateObject($folderId, $serverId, $entry); - if (empty($uid)) { + if (empty($entry)) { throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); } - return $this->serverId($uid, $oldEntry'folderId'); + return $entry'_serverId'; } /** - * Delete entry + * delete entry * - * @param string $folderId - * @param string $serverId - * @param ?Syncroton_Model_SyncCollection $collectionData + * @param string $folderId + * @param string $serverId + * @param array $collectionData */ - public function deleteEntry($folderId, $serverId, $collectionData = null) + public function deleteEntry($folderId, $serverId, $collectionData) { - // TODO: Optimize, we just need to find the folder ID and UID, we do not need to "fetch" it. - $object = $this->getObject($folderId, $serverId); - - if ($object) { - $deleted = $this->backend->deleteItem($object'folderId', $this->device->deviceid, $this->modelName, $object'uid'); + $deleted = $this->deleteObject($folderId, $serverId); - if (!$deleted) { - throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); - } + if (!$deleted) { + throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); } } - /** - * Get attachment data from the server. - * - * @param string $fileReference - * - * @return Syncroton_Model_FileReference - */ + public function getFileReference($fileReference) { // to be implemented by Email data class - throw new Syncroton_Exception_NotFound('File references not supported'); + // @TODO: throw "unimplemented" exception here? } + /** * Search for existing entries * @@ -500,31 +557,108 @@ * @param array $filter Search filter * @param int $result_type Type of the result (see RESULT_* constants) * - * @return array|int Search result as count or array of uids/objects + * @return array|int Search result as count or array of uids/objects */ - protected function searchEntries($folderid, $filter = , $result_type = self::RESULT_UID, $extraData = null) + protected function searchEntries($folderid, $filter = array(), $result_type = self::RESULT_UID) { - $result = $result_type == self::RESULT_COUNT ? 0 : ; - $ts = time(); - $force = $this->lastsync_folder != $folderid || $this->lastsync_time <= $ts - Syncroton_Registry::getPingTimeout(); - $found = false; + if ($folderid == $this->defaultRootFolder) { + $folders = $this->listFolders(); + + if (!is_array($folders)) { + throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); + } + + $folders = array_keys($folders); + } + else { + $folders = array($folderid); + } - foreach ($this->extractFolders($folderid) as $fid) { - $search = $this->backend->searchEntries($fid, $this->device->deviceid, $this->device->id, $this->modelName, $filter, $result_type, $force, $extraData); - $found = true; + // there's a PHP Warning from kolab_storage if $filter isn't an array + if (empty($filter)) { + $filter = array(); + } + else { + $changed_objects = $this->getChangesByRelations($folderid, $filter); + } + + $result = $result_type == self::RESULT_COUNT ? 0 : array(); + $found = 0; + + foreach ($folders as $folder_id) { + $foldername = $this->backend->folder_id2name($folder_id, $this->device->deviceid); + $folder = $this->getFolderObject($foldername); + + if (!$folder || !$folder->valid) { + throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); + } + + $found++; + $error = false; switch ($result_type) { + case self::RESULT_COUNT: + $count = $folder->count($filter); + + if ($count === null || $count === false) { + $error = true; + } + else { + $result += (int) $count; + } + break; + + case self::RESULT_UID: + $uids = $folder->get_uids($filter); + + if (!is_array($uids)) { + $error = true; + } + else if (!empty($uids)) { + $result = array_merge($result, $this->applyServerId($uids, $folder)); + } + break; + } + + if ($error) { + throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); + } + + // handle tag modifications + if (!empty($changed_objects)) { + // build new filter + // search objects mathing current filter, + // relations may contain members of many types, we need to + // search them by UID in all requested folders to get + // only these with requested type (and that really exist + // in specified folders) + $tag_filter = array(array('uid', '=', $changed_objects)); + foreach ($filter as $f) { + if ($f0 != 'changed') { + $tag_filter = $f; + } + } + + switch ($result_type) { case self::RESULT_COUNT: - $result += $search; + // Note: this way we're potentally counting the same objects twice + // I'm not sure if this is a problem, we most likely do not + // need a precise result here + $count = $folder->count($tag_filter); + if ($count !== null && $count !== false) { + $result += (int) $count; + } + break; case self::RESULT_UID: - foreach ($search as $idx => $uid) { - $search$idx = $this->serverId($uid, $fid); + $uids = $folder->get_uids($tag_filter); + if (is_array($uids) && !empty($uids)) { + $result = array_unique(array_merge($result, $this->applyServerId($uids, $folder))); } - $result = array_unique(array_merge($result, $search)); break; + } } } @@ -532,8 +666,138 @@ throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); } - $this->lastsync_folder = $folderid; - $this->lastsync_time = $ts; + return $result; + } + + /** + * Detect changes of relation (tag) objects data and assigned objects + * Returns relation member identifiers + */ + protected function getChangesByRelations($folderid, $filter) + { + if (!$this->tag_categories) { + return; + } + + // get period filter, create new objects filter + foreach ($filter as $f) { + if ($f0 == 'changed' && $f1 == '>') { + $since = $f2; + } + } + + // this is not search for changes, do nothing + if (empty($since)) { + return; + } + + // get relations state from the last sync + $last_state = (array) $this->backend->relations_state_get($this->device->id, $folderid, $since); + + // get current relations state + $config = kolab_storage_config::get_instance(); + $default = true; + $filter = array( + array('type', '=', 'relation'), + array('category', '=', 'tag') + ); + + $relations = $config->get_objects($filter, $default, 100); + + $result = array(); + $changed = false; + + // compare states, get members of changed relations + foreach ($relations as $relation) { + $rel_id = $relation'uid'; + + if ($relation'changed') { + $relation'changed'->setTimezone(new DateTimeZone('UTC')); + } + + // last state unknown... + if (empty($last_state$rel_id)) { + // ...get all members + if (!empty($relation'members')) { + $changed = true; + $result = array_merge($result, $relation'members'); + } + } + // last state known, changed tag name... + else if ($last_state$rel_id'name' != $relation'name') { + // ...get all (old and new) members + $members_old = explode("\n", $last_state$rel_id'members'); + $changed = true; + $members = array_unique(array_merge($relation'members', $members_old)); + $result = array_merge($result, $members); + } + // last state known, any other change change... + else if ($last_state$rel_id'changed' < $relation'changed'->format('U')) { + // ...find new and removed members + $members_old = explode("\n", $last_state$rel_id'members'); + $new = array_diff($relation'members', $members_old); + $removed = array_diff($members_old, $relation'members'); + + if (!empty($new) || !empty($removed)) { + $changed = true; + $result = array_merge($result, $new, $removed); + } + } + + unset($last_state$rel_id); + } + + // get members of deleted relations + if (!empty($last_state)) { + $changed = true; + foreach ($last_state as $relation) { + $members = explode("\n", $relation'members'); + $result = array_merge($result, $members); + } + } + + // save current state + if ($changed) { + $data = array(); + foreach ($relations as $relation) { + $data$relation'uid' = array( + 'name' => $relation'name', + 'changed' => $relation'changed'->format('U'), + 'members' => implode("\n", (array)$relation'members'), + ); + } + + $now = new DateTime('now', new DateTimeZone('UTC')); + + $this->backend->relations_state_set($this->device->id, $folderid, $now, $data); + } + + // in mail mode return only message URIs + if ($this->modelName == 'mail') { + // lambda function to skip email members + $filter_func = function($value) { + return strpos($value, 'imap://') === 0; + }; + + $result = array_filter(array_unique($result), $filter_func); + } + // otherwise return only object UIDs + else { + // lambda function to skip email members + $filter_func = function($value) { + return strpos($value, 'urn:uuid:') === 0; + }; + + // lambda function to parse member URI + $member_func = function($value) { + if (strpos($value, 'urn:uuid:') === 0) { + $value = substr($value, 9); + } + return $value; + }; + + $result = array_map($member_func, array_filter(array_unique($result), $filter_func)); + } return $result; } @@ -543,61 +807,63 @@ * * @param int $filter_type Filter type * - * @return array Filter query + * @param array Filter query */ protected function filter($filter_type = 0) { // overwrite by child class according to specified type - return ; + return array(); } /** * get all entries changed between two dates * * @param string $folderId - * @param Syncroton_Model_ISyncState $syncState - * @param int $filter_type + * @param DateTime $start + * @param DateTime $end + * @param int $filterType * * @return array */ - public function getChangedEntries($folderId, Syncroton_Model_ISyncState $syncState, $filter_type = null) + public function getChangedEntries($folderId, DateTime $start, DateTime $end = null, $filter_type = null) { - $start = $syncState->lastsync; $filter = $this->filter($filter_type); - $filter = 'changed', '>', $start; + $filter = array('changed', '>', $start); - return $this->searchEntries($folderId, $filter, self::RESULT_UID, $syncState->extraData); + if ($end) { + $filter = array('changed', '<=', $end); + } + + return $this->searchEntries($folderId, $filter, self::RESULT_UID); } /** * Get count of entries changed between two dates * * @param string $folderId - * @param Syncroton_Model_ISyncState $syncState - * @param int $filter_type + * @param DateTime $start + * @param DateTime $end + * @param int $filterType * * @return int */ - private function getChangedEntriesCount($folderId, Syncroton_Model_ISyncState $syncState, $filter_type = null) + public function getChangedEntriesCount($folderId, DateTime $start, DateTime $end = null, $filter_type = null) { - $start = $syncState->lastsync; $filter = $this->filter($filter_type); - $filter = 'changed', '>', $start; - - return $this->searchEntries($folderId, $filter, self::RESULT_COUNT, $syncState->extraData); - } + $filter = array('changed', '>', $start); + if ($end) { + $filter = array('changed', '<=', $end); + } - public function getExtraData(Syncroton_Model_IFolder $folder) - { - return $this->backend->getExtraData($folder->serverId, $this->device->deviceid); + return $this->searchEntries($folderId, $filter, self::RESULT_COUNT); } /** * get id's of all entries available on the server * - * @param string $folder_id - * @param string $filter_type + * @param string $folderId + * @param int $filterType * * @return array */ @@ -612,8 +878,8 @@ /** * get count of all entries available on the server * - * @param string $folder_id - * @param string $filter_type + * @param string $folderId + * @param int $filterType * * @return int */ @@ -636,9 +902,9 @@ */ public function getCountOfChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState) { - $allClientEntries = $contentBackend->getFolderState($this->device, $folder, $syncState->counter); + $allClientEntries = $contentBackend->getFolderState($this->device, $folder); $allServerEntries = $this->getServerEntries($folder->serverId, $folder->lastfiltertype); - $changedEntries = $this->getChangedEntriesCount($folder->serverId, $syncState, $folder->lastfiltertype); + $changedEntries = $this->getChangedEntriesCount($folder->serverId, $syncState->lastsync, null, $folder->lastfiltertype); $addedEntries = array_diff($allServerEntries, $allClientEntries); $deletedEntries = array_diff($allClientEntries, $allServerEntries); @@ -657,11 +923,11 @@ public function hasChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState) { try { - if ($this->getChangedEntriesCount($folder->serverId, $syncState, $folder->lastfiltertype)) { + if ($this->getChangedEntriesCount($folder->serverId, $syncState->lastsync, null, $folder->lastfiltertype)) { return true; } - $allClientEntries = $contentBackend->getFolderState($this->device, $folder, $syncState->counter); + $allClientEntries = $contentBackend->getFolderState($this->device, $folder); // @TODO: Consider looping over all folders here, not in getServerEntries() and // getChangedEntriesCount(). This way we could break the loop and not check all folders @@ -672,7 +938,8 @@ $deletedEntries = array_diff($allClientEntries, $allServerEntries); return count($addedEntries) > 0 || count($deletedEntries) > 0; - } catch (Exception $e) { + } + catch (Exception $e) { // return "no changes" if something failed return false; } @@ -681,45 +948,150 @@ /** * Fetches the entry from the backend */ - protected function getObject($folderid, $entryid) + protected function getObject($folderid, $entryid, &$folder = null) { - foreach ($this->extractFolders($folderid) as $fid) { - $crc = null; - $uid = $entryid; - - // See self::serverId() for full explanation - // Use (slower) UID prefix matching... - if (preg_match('/^CRC(0-9A-Fa-f{8})(.+)$/', $uid, $matches)) { - $crc = $matches1; - $uid = $matches2; - - if (strlen($entryid) >= 64) { - $objects = $this->backend->getItemsByUidPrefix($fid, $this->device->deviceid, $this->modelName, $uid); - - foreach ($objects as $object) { - if (($object'uid' === $uid || strpos($object'uid', $uid) === 0) - && $crc == $this->objectCRC($object'uid', $fid) - ) { - $object'folderId' = $fid; - return $object; + $folders = $this->extractFolders($folderid); + + if (empty($folders)) { + return null; + } + + foreach ($folders as $folderid) { + $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid); + $folder = $this->getFolderObject($foldername); + + if ($folder && $folder->valid) { + $crc = null; + $uid = $entryid; + + // See self::serverId() for full explanation + // Use (slower) UID prefix matching... + if (preg_match('/^CRC(0-9A-Fa-f{8})(.+)$/', $uid, $matches)) { + $crc = $matches1; + $uid = $matches2; + + if (strlen($entryid) >= 64) { + foreach ($folder->select(array(array('uid', '~*', $uid))) as $object) { + if (($object'uid' == $uid || strpos($object'uid', $uid) === 0) + && $crc == $this->objectCRC($object'uid', $folder) + ) { + $object'_folderid' = $folderid; + return $object; + } } + + continue; } + } - continue; + // Or (faster) strict UID matching... + if (($object = $folder->get_object($uid)) + && ($crc === null || $crc == $this->objectCRC($object'uid', $folder)) + ) { + $object'_folderid' = $folderid; + return $object; } } + } + } - // Or (faster) strict UID matching... - $object = $this->backend->getItem($fid, $this->device->deviceid, $this->modelName, $uid); + /** + * Saves the entry on the backend + */ + protected function createObject($folderid, $data) + { + if ($folderid == $this->defaultRootFolder) { + $default = $this->getDefaultFolder(); - if (!empty($object) && ($crc === null || $crc == $this->objectCRC($uid, $fid))) { - $object'folderId' = $fid; - return $object; + if (!is_array($default)) { + return null; + } + + $folderid = isset($default'realid') ? $default'realid' : $default'serverId'; + } + + // convert categories into tags, save them after creating an object + if ($this->tag_categories) { + $tags = $data'categories'; + unset($data'categories'); + } + + $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid); + $folder = $this->getFolderObject($foldername); + + // Set User-Agent for saved objects + $app = kolab_sync::get_instance(); + $app->config->set('useragent', $app->app_name . ' ' . kolab_sync::VERSION); + + if ($folder && $folder->valid && $folder->save($data)) { + if (!empty($tags)) { + $this->setKolabTags($data'uid', $tags); + } + + $data'_serverId' = $this->serverId($data'uid', $folder); + + return $data; + } + } + + /** + * Updates the entry on the backend + */ + protected function updateObject($folderid, $entryid, $data) + { + $object = $this->getObject($folderid, $entryid); + + if ($object) { + $folder = $this->getFolderObject($object'_mailbox'); + + // convert categories into tags, save them after updating an object + if ($this->tag_categories && array_key_exists('categories', $data)) { + $tags = (array) $data'categories'; + unset($data'categories'); + } + + // Set User-Agent for saved objects + $app = kolab_sync::get_instance(); + $app->config->set('useragent', $app->app_name . ' ' . kolab_sync::VERSION); + + if ($folder && $folder->valid && $folder->save($data)) { + if (isset($tags)) { + $this->setKolabTags($data'uid', $tags); + } + + $data'_serverId' = $this->serverId($object'uid', $folder); + + return $data; } } } /** + * Removes the entry from the backend + */ + protected function deleteObject($folderid, $entryid) + { + $object = $this->getObject($folderid, $entryid); + + if ($object) { + $folder = $this->getFolderObject($object'_mailbox'); + + if ($folder && $folder->valid && $folder->delete($object'uid')) { + if ($this->tag_categories) { + $this->setKolabTags($object'uid', null); + } + + return true; + } + + return false; + } + + // object doesn't exist, confirm deletion + return true; + } + + /** * Returns internal folder IDs * * @param string $folderid Folder identifier @@ -732,16 +1104,17 @@ $folderid = $folderid->serverId; } - if ($folderid === $this->defaultRootFolder) { + if ($folderid == $this->defaultRootFolder) { $folders = $this->listFolders(); if (!is_array($folders)) { - throw new Syncroton_Exception_NotFound('Folder not found'); + return null; } $folders = array_keys($folders); - } else { - $folders = $folderid; + } + else { + $folders = array($folderid); } return $folders; @@ -756,22 +1129,19 @@ */ protected function listFolders($parentid = null) { - if (empty($this->folders)) { - $this->folders = $this->backend->folders_list( - $this->device->deviceid, - $this->modelName, - $this->isMultiFolder() - ); + if (empty($this->imap_folders)) { + $this->imap_folders = $this->backend->folders_list( + $this->device->deviceid, $this->modelName, $this->isMultiFolder()); } - if ($parentid === null || !is_array($this->folders)) { - return $this->folders; + if ($parentid === null || !is_array($this->imap_folders)) { + return $this->imap_folders; } - $folders = ; - $parents = $parentid; + $folders = array(); + $parents = array($parentid); - foreach ($this->folders as $folder_id => $folder) { + foreach ($this->imap_folders as $folder_id => $folder) { if ($folder'parentId' && in_array($folder'parentId', $parents)) { $folders$folder_id = $folder; $parents = $folder_id; @@ -782,37 +1152,88 @@ } /** + * Returns Folder object (uses internal cache) + * + * @param string $name Folder name (UTF7-IMAP) + * + * @return kolab_storage_folder Folder object + */ + protected function getFolderObject($name) + { + if ($name === null || $name === '') { + return null; + } + + if (!isset($this->folders$name)) { + $this->folders$name = kolab_storage::get_folder($name, $this->modelName); + } + + return $this->folders$name; + } + + /** * Returns ActiveSync settings of specified folder * - * @param string $folderid Folder identifier + * @param string $name Folder name (UTF7-IMAP) * * @return array Folder settings */ - protected function getFolderConfig($folderid) + protected function getFolderConfig($name) + { + $metadata = $this->backend->folder_meta(); + + if (!is_array($metadata)) { + return array(); + } + + $deviceid = $this->device->deviceid; + $config = $metadata$name'FOLDER'$deviceid; + + return array( + 'ALARMS' => $config'S' == 2, + ); + } + + /** + * Returns real folder name for specified folder ID + */ + protected function getFolderName($folderid) { if ($folderid == $this->defaultRootFolder) { - $default = $this->getDefaultFolder(); + $default = $this->getDefaultFolder(); if (!is_array($default)) { - return ; + return null; } - $folderid = $default'realid' ?? $default'serverId'; + $folderid = isset($default'realid') ? $default'realid' : $default'serverId'; + } + + return $this->backend->folder_id2name($folderid, $this->device->deviceid); + } + + /** + * Returns folder ID from Kolab folder object + */ + protected function getFolderId($folder) + { + if (!$this->isMultiFolder()) { + return $this->defaultRootFolder; } - return $this->backend->getFolderConfig($folderid, $this->device->deviceid, $this->modelName); + return $this->backend->folder_id($folder->get_name(), $folder->get_type()); } /** * Convert contact from xml to kolab format * - * @param mixed $data Contact data - * @param string $folderId Folder identifier - * @param array $entry Old Contact data for merge + * @param Syncroton_Model_IEntry $data Contact data + * @param string $folderId Folder identifier + * @param array $entry Old Contact data for merge * * @return array */ - abstract public function toKolab($data, $folderId, $entry = null); + abstract function toKolab(Syncroton_Model_IEntry $data, $folderId, $entry = null); /** * Extracts data from kolab data array @@ -843,12 +1264,10 @@ if ($count == 2 && $name_items0 == 'x-custom') { $value = null; - if (!empty($data'x-custom') && is_array($data'x-custom')) { - foreach ($data'x-custom' as $val) { - if (is_array($val) && $val0 == $name_items1) { - $value = $val1; - break; - } + foreach ((array) $data'x-custom' as $val) { + if (is_array($val) && $val0 == $name_items1) { + $value = $val1; + break; } } @@ -889,7 +1308,7 @@ $key_name = $name_items2; if (!isset($data$name)) { - $data$name = ; + $data$name = array(); } foreach ($data$name as $idx => $element) { @@ -902,7 +1321,7 @@ if (!isset($found)) { $data$name = array_values($data$name); $found = count($data$name); - $data$name$found = 'type' => $type; + $data$name$found = array('type' => $type); } $data$name$found$key_name = $value; @@ -912,15 +1331,14 @@ // custom properties if ($count == 2 && $name_items0 == 'x-custom') { - $data'x-custom' = isset($data'x-custom') ? ((array) $data'x-custom') : ; - foreach ($data'x-custom' as $idx => $val) { + foreach ((array) $data'x-custom' as $idx => $val) { if (is_array($val) && $val0 == $name_items1) { $data'x-custom'$idx1 = $value; return; } } - $data'x-custom' = $name_items1, $value; + $data'x-custom' = array($name_items1, $value); return; } @@ -1009,12 +1427,12 @@ /** * Setter for Body attribute according to client version * - * @param string $value Body - * @param array $params Body parameters + * @param string $value Body + * @param array $param Body parameters * * @reurn Syncroton_Model_EmailBody Body element */ - protected function setBody($value, $params = ) + protected function setBody($value, $params = array()) { if (empty($value) && empty($params)) { return; @@ -1044,17 +1462,16 @@ * @param int $type Result data type (to which the body will be converted, if specified). * One or array of Syncroton_Model_EmailBody constants. * - * @return string|null Body value + * @return string Body value */ protected function getBody($body, $type = null) { - $data = null; if ($body && $body->data) { $data = $body->data; } if (!$data || empty($type)) { - return null; + return; } $type = (array) $type; @@ -1082,10 +1499,10 @@ $prefs = $opts'bodyPreferences'; $html_type = Syncroton_Command_Sync::BODY_TYPE_HTML; $type = Syncroton_Command_Sync::BODY_TYPE_PLAIN_TEXT; - $params = ; + $params = array(); // HTML? check for opening and closing <html> or <body> tags - $is_html = preg_match('/<(html|body)(\s+a-z|>)/', $body, $m) && strpos($body, '</' . $m1 . '>') > 0; + $is_html = preg_match('/<(html|body)(\s+a-z|>)/', $body, $m) && strpos($body, '</'.$m1.'>') > 0; // here we assume that all devices support plain text if ($is_html) { @@ -1105,7 +1522,7 @@ $real_length = $body_length = strlen($body); // truncate the body if needed - if (isset($prefs$type'truncationSize') && ($truncateAt = $prefs$type'truncationSize') && $body_length > $truncateAt) { + if (($truncateAt = $prefs$type'truncationSize') && $body_length > $truncateAt) { $body = mb_strcut($body, 0, $truncateAt); $body_length = strlen($body); @@ -1124,16 +1541,18 @@ * * @param DateTime|int|string $date Unix timestamp, date (YYYY-MM-DD) or PHP DateTime object * - * @return DateTime|null Datetime object + * @return DateTime Datetime object */ protected static function date_from_kolab($date) { if (!empty($date)) { if (is_numeric($date)) { $date = new DateTime('@' . $date); - } elseif (is_string($date)) { + } + else if (is_string($date)) { $date = new DateTime($date, new DateTimeZone('UTC')); - } elseif ($date instanceof DateTime) { + } + else if ($date instanceof DateTime) { $date = clone $date; $tz = $date->getTimezone(); $tz_name = $tz->getName(); @@ -1143,23 +1562,23 @@ $utc = new DateTimeZone('UTC'); // safe dateonly object conversion to UTC // note: _dateonly flag is set by libkolab e.g. for birthdays - if (!empty($date->_dateonly)) { + if ($date->_dateonly) { // avoid time change $date = new DateTime($date->format('Y-m-d'), $utc); // set time to noon to avoid timezone troubles $date->setTime(12, 0, 0); - } else { + } + else { $date->setTimezone($utc); } } - } else { + } + else { return null; // invalid input } return $date; } - - return null; } /** @@ -1167,75 +1586,72 @@ */ protected function recurrence_from_kolab($collection, $data, &$result, $type = 'Event') { - if (empty($data'recurrence') || !empty($data'recurrence_date') || empty($data'recurrence''FREQ')) { + if (empty($data'recurrence') || !empty($data'recurrence_date')) { return; } - $recurrence = ; + $recurrence = array(); $r = $data'recurrence'; // required fields switch($r'FREQ') { - case 'DAILY': - $recurrence'type' = self::RECUR_TYPE_DAILY; - break; - - case 'WEEKLY': - $day = $r'BYDAY' ?? 0; - if (!$day && (!empty($data'_start') || !empty($data'start'))) { - $days = '', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA','SU'; - $start = $data'_start' ?? $data'start'; - $day = $days$start->format('N'); - } - - $recurrence'type' = self::RECUR_TYPE_WEEKLY; + case 'DAILY': + $recurrence'type' = self::RECUR_TYPE_DAILY; + break; + + case 'WEEKLY': + $recurrence'type' = self::RECUR_TYPE_WEEKLY; + $recurrence'dayOfWeek' = $this->day2bitmask($r'BYDAY'); + break; + + case 'MONTHLY': + if (!empty($r'BYMONTHDAY')) { + // @TODO: ActiveSync doesn't support multi-valued month days, + // should we replicate the recurrence element for each day of month? + $month_day = array_shift(explode(',', $r'BYMONTHDAY')); + $recurrence'type' = self::RECUR_TYPE_MONTHLY; + $recurrence'dayOfMonth' = $month_day; + } + else { + $week = (int) substr($r'BYDAY', 0, -2); + $week = ($week == -1) ? 5 : $week; + $day = substr($r'BYDAY', -2); + $recurrence'type' = self::RECUR_TYPE_MONTHLY_DAYN; + $recurrence'weekOfMonth' = $week; $recurrence'dayOfWeek' = $this->day2bitmask($day); - break; - - case 'MONTHLY': - if (!empty($r'BYMONTHDAY')) { - // @TODO: ActiveSync doesn't support multi-valued month days, - // should we replicate the recurrence element for each day of month? - $month_day, = explode(',', $r'BYMONTHDAY'); - $recurrence'type' = self::RECUR_TYPE_MONTHLY; - $recurrence'dayOfMonth' = $month_day; - } elseif (!empty($r'BYDAY')) { - $week = (int) substr($r'BYDAY', 0, -2); - $week = ($week == -1) ? 5 : $week; - $day = substr($r'BYDAY', -2); - $recurrence'type' = self::RECUR_TYPE_MONTHLY_DAYN; - $recurrence'weekOfMonth' = $week; - $recurrence'dayOfWeek' = $this->day2bitmask($day); - } else { - return; - } - break; + } + break; + + case 'YEARLY': + // @TODO: ActiveSync doesn't support multi-valued months, + // should we replicate the recurrence element for each month? + $month = array_shift(explode(',', $r'BYMONTH')); + + if (!empty($r'BYDAY')) { + $week = (int) substr($r'BYDAY', 0, -2); + $week = ($week == -1) ? 5 : $week; + $day = substr($r'BYDAY', -2); + $recurrence'type' = self::RECUR_TYPE_YEARLY_DAYN; + $recurrence'weekOfMonth' = $week; + $recurrence'dayOfWeek' = $this->day2bitmask($day); + $recurrence'monthOfYear' = $month; + } + else if (!empty($r'BYMONTHDAY')) { + // @TODO: ActiveSync doesn't support multi-valued month days, + // should we replicate the recurrence element for each day of month? + $month_day = array_shift(explode(',', $r'BYMONTHDAY')); + $recurrence'type' = self::RECUR_TYPE_YEARLY; + $recurrence'dayOfMonth' = $month_day; + $recurrence'monthOfYear' = $month; + } + else { + $recurrence'type' = self::RECUR_TYPE_YEARLY; + $recurrence'monthOfYear' = $month; + } + break; - case 'YEARLY': - // @TODO: ActiveSync doesn't support multi-valued months, - // should we replicate the recurrence element for each month? - $month, = explode(',', $r'BYMONTH'); - - if (!empty($r'BYDAY')) { - $week = (int) substr($r'BYDAY', 0, -2); - $week = ($week == -1) ? 5 : $week; - $day = substr($r'BYDAY', -2); - $recurrence'type' = self::RECUR_TYPE_YEARLY_DAYN; - $recurrence'weekOfMonth' = $week; - $recurrence'dayOfWeek' = $this->day2bitmask($day); - $recurrence'monthOfYear' = $month; - } elseif (!empty($r'BYMONTHDAY')) { - // @TODO: ActiveSync doesn't support multi-valued month days, - // should we replicate the recurrence element for each day of month? - $month_day, = explode(',', $r'BYMONTHDAY'); - $recurrence'type' = self::RECUR_TYPE_YEARLY; - $recurrence'dayOfMonth' = $month_day; - $recurrence'monthOfYear' = $month; - } else { - $recurrence'type' = self::RECUR_TYPE_YEARLY; - $recurrence'monthOfYear' = $month; - } - break; + default: + return; } // Skip all empty values (T2519) @@ -1248,7 +1664,8 @@ if (!empty($r'UNTIL')) { $recurrence'until' = self::date_from_kolab($r'UNTIL'); - } elseif (!empty($r'COUNT')) { + } + else if (!empty($r'COUNT')) { $recurrence'occurrences' = $r'COUNT'; } @@ -1281,52 +1698,53 @@ $type = $recurrence->type; switch ($type) { - case self::RECUR_TYPE_DAILY: - break; + case self::RECUR_TYPE_DAILY: + break; - case self::RECUR_TYPE_WEEKLY: - $rrule'BYDAY' = $this->bitmask2day($recurrence->dayOfWeek); - break; + case self::RECUR_TYPE_WEEKLY: + $rrule'BYDAY' = $this->bitmask2day($recurrence->dayOfWeek); + break; - case self::RECUR_TYPE_MONTHLY: - $rrule'BYMONTHDAY' = $recurrence->dayOfMonth; - break; + case self::RECUR_TYPE_MONTHLY: + $rrule'BYMONTHDAY' = $recurrence->dayOfMonth; + break; - case self::RECUR_TYPE_MONTHLY_DAYN: - $week = $recurrence->weekOfMonth; - $day = $recurrence->dayOfWeek; - $byDay = $week == 5 ? -1 : $week; - $byDay .= $this->bitmask2day($day); + case self::RECUR_TYPE_MONTHLY_DAYN: + $week = $recurrence->weekOfMonth; + $day = $recurrence->dayOfWeek; + $byDay = $week == 5 ? -1 : $week; + $byDay .= $this->bitmask2day($day); - $rrule'BYDAY' = $byDay; - break; + $rrule'BYDAY' = $byDay; + break; - case self::RECUR_TYPE_YEARLY: - $rrule'BYMONTH' = $recurrence->monthOfYear; - $rrule'BYMONTHDAY' = $recurrence->dayOfMonth; - break; + case self::RECUR_TYPE_YEARLY: + $rrule'BYMONTH' = $recurrence->monthOfYear; + $rrule'BYMONTHDAY' = $recurrence->dayOfMonth; + break; - case self::RECUR_TYPE_YEARLY_DAYN: - $rrule'BYMONTH' = $recurrence->monthOfYear; + case self::RECUR_TYPE_YEARLY_DAYN: + $rrule'BYMONTH' = $recurrence->monthOfYear; - $week = $recurrence->weekOfMonth; - $day = $recurrence->dayOfWeek; - $byDay = $week == 5 ? -1 : $week; - $byDay .= $this->bitmask2day($day); + $week = $recurrence->weekOfMonth; + $day = $recurrence->dayOfWeek; + $byDay = $week == 5 ? -1 : $week; + $byDay .= $this->bitmask2day($day); - $rrule'BYDAY' = $byDay; - break; + $rrule'BYDAY' = $byDay; + break; } $rrule'FREQ' = $this->recurTypeMap$type; - $rrule'INTERVAL' = $recurrence->interval ?? 1; + $rrule'INTERVAL' = isset($recurrence->interval) ? $recurrence->interval : 1; if (isset($recurrence->until)) { if ($timezone) { $recurrence->until->setTimezone($timezone); } $rrule'UNTIL' = $recurrence->until; - } elseif (!empty($recurrence->occurrences)) { + } + else if (!empty($recurrence->occurrences)) { $rrule'COUNT' = $recurrence->occurrences; } @@ -1347,42 +1765,38 @@ return null; } - $ex_list = ; + $ex_list = array(); // exceptions (modified occurences) - if (!empty($data'recurrence''EXCEPTIONS')) { - foreach ((array)$data'recurrence''EXCEPTIONS' as $exception) { - $exception'_mailbox' = $data'_mailbox'; + foreach ((array)$data'recurrence''EXCEPTIONS' as $exception) { + $exception'_mailbox' = $data'_mailbox'; - $ex = $this->getEntry($collection, $exception, true); // @phpstan-ignore-line - $date = clone ($exception'recurrence_date' ?: $ex'startTime'); + $ex = $this->getEntry($collection, $exception, true); + $date = clone ($exception'recurrence_date' ?: $ex'startTime'); - $ex'exceptionStartTime' = self::set_exception_time($date, $data'_start' ?? null); + $ex'exceptionStartTime' = self::set_exception_time($date, $data'_start'); - // remove fields not supported by Syncroton_Model_EventException - unset($ex'uID'); + // remove fields not supported by Syncroton_Model_EventException + unset($ex'uID'); - // @TODO: 'thisandfuture=true' is not supported in Activesync - // we'd need to slit the event into two separate events + // @TODO: 'thisandfuture=true' is not supported in Activesync + // we'd need to slit the event into two separate events - $ex_list = new Syncroton_Model_EventException($ex); - } + $ex_list = new Syncroton_Model_EventException($ex); } // exdate (deleted occurences) - if (!empty($data'recurrence''EXDATE')) { - foreach ((array)$data'recurrence''EXDATE' as $exception) { - if (!($exception instanceof DateTime)) { - continue; - } + foreach ((array)$data'recurrence''EXDATE' as $exception) { + if (!($exception instanceof DateTime)) { + continue; + } - $ex = - 'deleted' => 1, - 'exceptionStartTime' => self::set_exception_time($exception, $data'_start' ?? null), - ; + $ex = array( + 'deleted' => 1, + 'exceptionStartTime' => self::set_exception_time($exception, $data'_start'), + ); - $ex_list = new Syncroton_Model_EventException($ex); - } + $ex_list = new Syncroton_Model_EventException($ex); } return $ex_list; @@ -1393,26 +1807,24 @@ */ protected function exceptions_to_kolab($data, &$rrule, $folderid, $timezone = null) { - $rrule'EXDATE' = ; - $rrule'EXCEPTIONS' = ; + $rrule'EXDATE' = array(); + $rrule'EXCEPTIONS' = array(); // handle exceptions from recurrence if (!empty($data->exceptions)) { foreach ($data->exceptions as $exception) { - $date = clone $exception->exceptionStartTime; - if ($timezone) { - $date->setTimezone($timezone); - } - if ($exception->deleted) { + $date = clone $exception->exceptionStartTime; + if ($timezone) { + $date->setTimezone($timezone); + } $date->setTime(0, 0, 0); $rrule'EXDATE' = $date; - } else { - $ex = $this->toKolab($exception, $folderid, null, $timezone); // @phpstan-ignore-line - - $ex'recurrence_date' = $date; + } + else { + $ex = $this->toKolab($exception, $folderid, null, $timezone); - if (!empty($data->allDayEvent)) { + if ($data->allDayEvent) { $ex'allday' = 1; } @@ -1447,6 +1859,32 @@ } /** + * Returns list of tag names assigned to kolab object + */ + protected function getKolabTags($uid, $categories = null) + { + $config = kolab_storage_config::get_instance(); + $tags = $config->get_tags($uid); + $tags = array_filter(array_map(function($v) { return $v'name'; }, $tags)); + + // merge result with old categories + if (!empty($categories)) { + $tags = array_unique(array_merge($tags, (array) $categories)); + } + + return $tags; + } + + /** + * Set tags to kolab object + */ + protected function setKolabTags($uid, $tags) + { + $config = kolab_storage_config::get_instance(); + $config->save_tags($uid, $tags); + } + + /** * Converts string of days (TU,TH) to bitmask used by ActiveSync * * @param string $days @@ -1459,9 +1897,7 @@ $result = 0; foreach ($days as $day) { - if ($day) { - $result = $result + ($this->recurDayMap$day ?? 0); - } + $result = $result + $this->recurDayMap$day; } return $result; @@ -1476,7 +1912,7 @@ */ protected function bitmask2day($days) { - $days_arr = ; + $days_arr = array(); for ($bitmask = 1; $bitmask <= self::RECUR_DOW_SATURDAY; $bitmask = $bitmask << 1) { $dayMatch = $days & $bitmask; @@ -1499,7 +1935,8 @@ if (preg_match($option, $this->device->devicetype)) { return true; } - } elseif (stripos($this->device->devicetype, $option) !== false) { + } + else if (stripos($this->device->devicetype, $option) !== false) { return true; } } @@ -1513,7 +1950,7 @@ protected function user_emails() { $user_emails = kolab_sync::get_instance()->user->list_emails(); - $user_emails = array_map(function ($v) { return $v'email'; }, $user_emails); + $user_emails = array_map(function($v) { return $v'email'; }, $user_emails); return $user_emails; } @@ -1523,6 +1960,10 @@ */ protected function serverId($uid, $folder) { + if ($this->modelName == 'mail') { + return $uid; + } + // When ActiveSync communicates with the client, it refers to objects with a ServerId // We can't use object UID for ServerId because: // - ServerId is limited to 64 chars, @@ -1553,11 +1994,25 @@ protected function objectCRC($uid, $folder) { if (!is_object($folder)) { - $folder = $this->backend->getFolder($folder, $this->device->deviceid, $this->modelName); + $folder = $this->getFolderObject($folder); } $folder_uid = $folder->get_uid(); return strtoupper(hash('crc32b', $folder_uid . $uid)); // always 8 chars } + + /** + * Apply serverId() on a set of uids + */ + protected function applyServerId($uids, $folder) + { + if (!empty($uids) && $this->modelName != 'mail') { + $self = $this; + $func = function($uid) use ($self, $folder) { return $self->serverId($uid, $folder); }; + $uids = array_map($func, $uids); + } + + return $uids; + } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_data_calendar.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_data_calendar.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -31,7 +31,7 @@ /** * Mapping from ActiveSync Calendar namespace fields */ - protected $mapping = + protected $mapping = array( 'allDayEvent' => 'allday', 'startTime' => 'start', // keep it before endTime here //'attendees' => 'attendees', @@ -54,7 +54,7 @@ 'subject' => 'title', //'timezone' => 'timezone', 'uID' => 'uid', - ; + ); /** * Kolab object type @@ -87,59 +87,51 @@ /** * attendee status */ - public const ATTENDEE_STATUS_UNKNOWN = 0; - public const ATTENDEE_STATUS_TENTATIVE = 2; - public const ATTENDEE_STATUS_ACCEPTED = 3; - public const ATTENDEE_STATUS_DECLINED = 4; - public const ATTENDEE_STATUS_NOTRESPONDED = 5; + const ATTENDEE_STATUS_UNKNOWN = 0; + const ATTENDEE_STATUS_TENTATIVE = 2; + const ATTENDEE_STATUS_ACCEPTED = 3; + const ATTENDEE_STATUS_DECLINED = 4; + const ATTENDEE_STATUS_NOTRESPONDED = 5; /** * attendee types */ - public const ATTENDEE_TYPE_REQUIRED = 1; - public const ATTENDEE_TYPE_OPTIONAL = 2; - public const ATTENDEE_TYPE_RESOURCE = 3; + const ATTENDEE_TYPE_REQUIRED = 1; + const ATTENDEE_TYPE_OPTIONAL = 2; + const ATTENDEE_TYPE_RESOURCE = 3; /** * busy status constants */ - public const BUSY_STATUS_FREE = 0; - public const BUSY_STATUS_TENTATIVE = 1; - public const BUSY_STATUS_BUSY = 2; - public const BUSY_STATUS_OUTOFOFFICE = 3; + const BUSY_STATUS_FREE = 0; + const BUSY_STATUS_TENTATIVE = 1; + const BUSY_STATUS_BUSY = 2; + const BUSY_STATUS_OUTOFOFFICE = 3; /** * Sensitivity values */ - public const SENSITIVITY_NORMAL = 0; - public const SENSITIVITY_PERSONAL = 1; - public const SENSITIVITY_PRIVATE = 2; - public const SENSITIVITY_CONFIDENTIAL = 3; + const SENSITIVITY_NORMAL = 0; + const SENSITIVITY_PERSONAL = 1; + const SENSITIVITY_PRIVATE = 2; + const SENSITIVITY_CONFIDENTIAL = 3; - /** - * Internal iTip states - */ - public const ITIP_ACCEPTED = 'ACCEPTED'; - public const ITIP_DECLINED = 'DECLINED'; - public const ITIP_TENTATIVE = 'TENTATIVE'; - public const ITIP_CANCELLED = 'CANCELLED'; - - public const KEY_DTSTAMP = 'x-custom.X-ACTIVESYNC-DTSTAMP'; - public const KEY_REPLYTIME = 'x-custom.X-ACTIVESYNC-REPLYTIME'; + const KEY_DTSTAMP = 'x-custom.X-ACTIVESYNC-DTSTAMP'; + const KEY_RESPONSE_DTSTAMP = 'x-custom.X-ACTIVESYNC-RESPONSE-DTSTAMP'; /** * Mapping of attendee status * * @var array */ - protected $attendeeStatusMap = + protected $attendeeStatusMap = array( 'UNKNOWN' => self::ATTENDEE_STATUS_UNKNOWN, 'TENTATIVE' => self::ATTENDEE_STATUS_TENTATIVE, 'ACCEPTED' => self::ATTENDEE_STATUS_ACCEPTED, 'DECLINED' => self::ATTENDEE_STATUS_DECLINED, 'DELEGATED' => self::ATTENDEE_STATUS_UNKNOWN, 'NEEDS-ACTION' => self::ATTENDEE_STATUS_NOTRESPONDED, - ; + ); /** * Mapping of attendee type @@ -147,35 +139,35 @@ * NOTE: recurrences need extra handling! * @var array */ - protected $attendeeTypeMap = + protected $attendeeTypeMap = array( 'REQ-PARTICIPANT' => self::ATTENDEE_TYPE_REQUIRED, 'OPT-PARTICIPANT' => self::ATTENDEE_TYPE_OPTIONAL, // 'NON-PARTICIPANT' => self::ATTENDEE_TYPE_RESOURCE, // 'CHAIR' => self::ATTENDEE_TYPE_RESOURCE, - ; + ); /** * Mapping of busy status * * @var array */ - protected $busyStatusMap = + protected $busyStatusMap = array( 'free' => self::BUSY_STATUS_FREE, 'tentative' => self::BUSY_STATUS_TENTATIVE, 'busy' => self::BUSY_STATUS_BUSY, 'outofoffice' => self::BUSY_STATUS_OUTOFOFFICE, - ; + ); /** * mapping of sensitivity * * @var array */ - protected $sensitivityMap = + protected $sensitivityMap = array( 'public' => self::SENSITIVITY_PERSONAL, 'private' => self::SENSITIVITY_PRIVATE, 'confidential' => self::SENSITIVITY_CONFIDENTIAL, - ; + ); /** @@ -183,72 +175,77 @@ * * @param Syncroton_Model_SyncCollection $collection Collection data * @param string $serverId Local entry identifier - * @param bool $as_array Return entry as array + * @param boolean $as_array Return entry as array * - * @return array|Syncroton_Model_Event Event object + * @return array|Syncroton_Model_Event|array Event object */ public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId, $as_array = false) { $event = is_array($serverId) ? $serverId : $this->getObject($collection->collectionId, $serverId); - $config = !empty($event'folderId') ? $this->getFolderConfig($event'folderId') : ; - $result = ; - - $is_outlook = stripos($this->device->devicetype, 'outlook') !== false; - $is_android = stripos($this->device->devicetype, 'android') !== false; + $config = $this->getFolderConfig($event'_mailbox'); + $result = array(); + // Timezone // Kolab Format 3.0 and xCal does support timezone per-date, but ActiveSync allows // only one timezone per-event. We'll use timezone of the start date - $result'timezone' = kolab_sync_timezone_converter::encodeTimezoneFromDate($event'start'); + if ($event'start' instanceof DateTime) { + $timezone = $event'start'->getTimezone(); + + if ($timezone && ($tz_name = $timezone->getName()) != 'UTC') { + $tzc = kolab_sync_timezone_converter::getInstance(); + + if ($tz_name = $tzc->encodeTimezone($tz_name)) { + $result'timezone' = $tz_name; + } + } + } // Calendar namespace fields foreach ($this->mapping as $key => $name) { $value = $this->getKolabDataItem($event, $name); switch ($name) { - case 'changed': - case 'end': - case 'start': - // For all-day events Kolab uses different times - // At least Android doesn't display such event as all-day event - if ($value && is_a($value, 'DateTime')) { - $date = clone $value; - if (!empty($event'allday')) { - // need this for self::date_from_kolab() - $date->_dateonly = false; // @phpstan-ignore-line - - if ($name == 'start') { - $date->setTime(0, 0, 0); - } elseif ($name == 'end') { - $date->setTime(0, 0, 0); - $date->modify('+1 day'); - } - } + case 'changed': + case 'end': + case 'start': + // For all-day events Kolab uses different times + // At least Android doesn't display such event as all-day event + if ($value && is_a($value, 'DateTime')) { + $date = clone $value; + if ($event'allday') { + // need this for self::date_from_kolab() + $date->_dateonly = false; - // set this date for use in recurrence exceptions handling if ($name == 'start') { - $event'_start' = $date; + $date->setTime(0, 0, 0); } + else if ($name == 'end') { + $date->setTime(0, 0, 0); + $date->modify('+1 day'); + } + } - $value = self::date_from_kolab($date); + // set this date for use in recurrence exceptions handling + if ($name == 'start') { + $event'_start' = $date; } - break; + $value = self::date_from_kolab($date); + } - case 'sensitivity': - if (!empty($value)) { - $value = intval($this->sensitivityMap$value); - } - break; + break; - case 'free_busy': - if (!empty($value)) { - $value = $this->busyStatusMap$value; - } - break; + case 'sensitivity': + $value = intval($this->sensitivityMap$value); + break; - case 'description': - $value = $this->body_from_kolab($value, $collection); - break; + case 'free_busy': + $value = $this->busyStatusMap$value; + break; + + case 'description': + $value = $this->body_from_kolab($value, $collection); + break; } // Ignore empty values (but not integer 0) @@ -260,12 +257,12 @@ } // Event reminder time - if (!empty($config'ALARMS')) { + if ($config'ALARMS') { $result'reminder' = $this->from_kolab_alarm($event); } - $result'categories' = ; - $result'attendees' = ; + $result'categories' = array(); + $result'attendees' = array(); // Categories, Roundcube Calendar plugin supports only one category at a time if (!empty($event'categories')) { @@ -276,11 +273,11 @@ if (!empty($event'attendees')) { foreach ($event'attendees' as $idx => $attendee) { if ($attendee'role' == 'ORGANIZER') { - if (!empty($attendee'name')) { - $result'organizerName' = $attendee'name'; + if ($name = $attendee'name') { + $result'organizerName' = $name; } - if (!empty($attendee'email')) { - $result'organizerEmail' = $attendee'email'; + if ($email = $attendee'email') { + $result'organizerEmail' = $email; } unset($event'attendees'$idx); @@ -289,51 +286,39 @@ } } - $resp_type = self::ATTENDEE_STATUS_UNKNOWN; - $user_rsvp = false; - // Attendees if (!empty($event'attendees')) { $user_emails = $this->user_emails(); + $user_rsvp = false; foreach ($event'attendees' as $idx => $attendee) { - if (empty($attendee'email')) { + $att = array(); + + if ($email = $attendee'email') { + $att'email' = $email; + } + else { // In Activesync email is required continue; } - $email = $attendee'email'; + $att'name' = $attendee'name' ?: $email; - $att = - 'email' => $email, - 'name' => !empty($attendee'name') ? $attendee'name' : $email, - ; - - $type = isset($attendee'role') ? $this->attendeeTypeMap$attendee'role' : null; + $type = isset($attendee'role') ? $this->attendeeTypeMap$attendee'role' : null; $status = isset($attendee'status') ? $this->attendeeStatusMap$attendee'status' : null; if ($this->asversion >= 12) { if (isset($attendee'cutype') && strtolower($attendee'cutype') == 'resource') { $att'attendeeType' = self::ATTENDEE_TYPE_RESOURCE; } else { - $att'attendeeType' = $type ?: self::ATTENDEE_TYPE_REQUIRED; + $att'attendeeType' = $type ?: self::ATTENDEE_TYPE_REQUIRED; } $att'attendeeStatus' = $status ?: self::ATTENDEE_STATUS_UNKNOWN; } - if (in_array_nocase($email, $user_emails)) { + if ($email && in_array_nocase($email, $user_emails)) { $user_rsvp = !empty($attendee'rsvp'); $resp_type = $status ?: self::ATTENDEE_STATUS_UNKNOWN; - - // Synchronize the attendee status to the event status to get the same behaviour as outlook. - if (($is_outlook || $is_android) && isset($attendee'status')) { - if ($attendee'status' == 'ACCEPTED') { - $result'busyStatus' = self::BUSY_STATUS_BUSY; - } - if ($attendee'status' == 'TENTATIVE') { - $result'busyStatus' = self::BUSY_STATUS_TENTATIVE; - } - } } $result'attendees' = new Syncroton_Model_EventAttendee($att); @@ -341,7 +326,7 @@ } // Event meeting status - $this->meeting_status_from_kolab($event, $result); + $this->meeting_status_from_kolab($collection, $event, $result); // Recurrence (and exceptions) $this->recurrence_from_kolab($collection, $event, $result); @@ -350,58 +335,30 @@ $result'responseRequested' = $result'meetingStatus' == 3 && $user_rsvp ? 1 : 0; $result'responseType' = $result'meetingStatus' == 3 ? $resp_type : null; - // Appointment Reply Time (without it Outlook displays e.g. "Accepted on None") - if ($resp_type != self::ATTENDEE_STATUS_UNKNOWN) { - if ($reply_time = $this->getKolabDataItem($event, self::KEY_REPLYTIME)) { - $result'appointmentReplyTime' = new DateTime($reply_time, new DateTimeZone('UTC')); - } elseif (!empty($event'changed')) { - $reply_time = clone $event'changed'; - $reply_time->setTimezone(new DateTimeZone('UTC')); - $result'appointmentReplyTime' = $reply_time; - } - } - return $as_array ? $result : new Syncroton_Model_Event($result); } /** - * Convert an event from xml to libkolab array + * convert contact from xml to libkolab array * - * @param Syncroton_Model_Event|Syncroton_Model_EventException $data Event or event exception to convert - * @param string $folderid Folder identifier - * @param array $entry Existing entry - * @param DateTimeZone $timezone Timezone of the event + * @param Syncroton_Model_IEntry $data Contact to convert + * @param string $folderid Folder identifier + * @param array $entry Existing entry + * @param DateTimeZone $timezone Timezone of the event * * @return array */ - public function toKolab($data, $folderid, $entry = null, $timezone = null) + public function toKolab(Syncroton_Model_IEntry $data, $folderid, $entry = null, $timezone = null) { - if (empty($entry) && !empty($data->uID)) { - // If we don't have an existing event (not a modification) we nevertheless check for conflicts. - // This is necessary so we don't overwrite the server-side copy in case the client did not have it available - // when generating an Add command. - try { - $entry = $this->getObject($folderid, $data->uID); - - if ($entry) { - $this->logger->debug('Found and existing event for UID: ' . $data->uID); - } - } catch (Exception $e) { - // uID is not available on exceptions, so we guard for that and silently ignore. - } - } - - $config = $this->getFolderConfig($entry ? $entry'folderId' : $folderid); - $event = !empty($entry) ? $entry : ; + $event = !empty($entry) ? $entry : array(); + $foldername = isset($event'_mailbox') ? $event'_mailbox' : $this->getFolderName($folderid); + $config = $this->getFolderConfig($foldername); $is_exception = $data instanceof Syncroton_Model_EventException; $dummy_tz = str_repeat('A', 230) . '=='; $is_outlook = stripos($this->device->devicetype, 'outlook') !== false; - $is_android = stripos($this->device->devicetype, 'android') !== false; - // check data validity (of a new event) - if (empty($event)) { - $this->check_event($data); - } + // check data validity + $this->check_event($data); if (!empty($event'start') && ($event'start' instanceof DateTime)) { $old_timezone = $event'start'->getTimezone(); @@ -410,19 +367,19 @@ // Timezone if (!$timezone && isset($data->timezone) && $data->timezone != $dummy_tz) { $tzc = kolab_sync_timezone_converter::getInstance(); - $expected = !empty($old_timezone) ? $old_timezone : kolab_format::$timezone; + $expected = $old_timezone ?: kolab_format::$timezone; try { $timezone = $tzc->getTimezone($data->timezone, $expected->getName()); $timezone = new DateTimeZone($timezone); - } catch (Exception $e) { - $this->logger->warn('Failed to convert the timezone information. UID: ' . $event'uid' . 'Timezone: ' . $data->timezone); + } + catch (Exception $e) { $timezone = null; } } if (empty($timezone)) { - $timezone = !empty($old_timezone) ? $old_timezone : new DateTimeZone('UTC'); + $timezone = $old_timezone ?: new DateTimeZone('UTC'); } $event'allday' = 0; @@ -437,60 +394,50 @@ $value = $data->$key; - // Skip ghosted (unset) properties, (but make sure 'changed' timestamp is reset) - if ($value === null && $name != 'changed') { - continue; - } - switch ($name) { - case 'changed': - $value = null; - break; + case 'changed': + $value = null; + break; - case 'end': - case 'start': - if ($timezone && $value) { - $value->setTimezone($timezone); - } + case 'end': + case 'start': + if ($timezone && $value) { + $value->setTimezone($timezone); + } - if ($value && $data->allDayEvent) { - $value->_dateonly = true; + if ($value && $data->allDayEvent) { + $value->_dateonly = true; - // In ActiveSync all-day event ends on 00:00:00 next day - // In Kolab we just ignore the time spec. - if ($name == 'end') { - $diff = date_diff($event'start', $value); - $value = clone $event'start'; + // In ActiveSync all-day event ends on 00:00:00 next day + // In Kolab we just ignore the time spec. + if ($name == 'end') { + $diff = date_diff($event'start', $value); + $value = clone $event'start'; - if ($diff->days > 1) { - $value->add(new DateInterval('P' . ($diff->days - 1) . 'D')); - } + if ($diff->days > 1) { + $value->add(new DateInterval('P' . ($diff->days - 1) . 'D')); } } - break; + } + break; - case 'sensitivity': - $map = array_flip($this->sensitivityMap); - $value = $map$value ?? null; - break; + case 'sensitivity': + $map = array_flip($this->sensitivityMap); + $value = $map$value; + break; - case 'free_busy': - // Outlook sets the busy state to the attendance state, and we don't want to change the event state based on that. - // Outlook doesn't have the concept of an event state, so we just ignore this. - if ($is_outlook || $is_android) { - continue 2; - } - $map = array_flip($this->busyStatusMap); - $value = $map$value ?? null; - break; + case 'free_busy': + $map = array_flip($this->busyStatusMap); + $value = $map$value; + break; - case 'description': - $value = $this->getBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT); - // If description isn't specified keep old description - if ($value === null) { - continue 2; - } - break; + case 'description': + $value = $this->getBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT); + // If description isn't specified keep old description + if ($value === null) { + continue 2; + } + break; } $this->setKolabDataItem($event, $name, $value); @@ -498,9 +445,9 @@ // Try to fix allday events from Android // It doesn't set all-day flag but the period is a whole day - if (empty($event'allday') && !empty($event'end') && !empty($event'start')) { + if (!$event'allday' && $event'end' && $event'start') { $interval = @date_diff($event'start', $event'end'); - if ($interval->format('%y%m%d%h%i%s') === '001000') { + if ($interval && $interval->format('%y%m%d%h%i%s') === '001000') { $event'allday' = 1; $event'end' = clone $event'start'; } @@ -508,12 +455,12 @@ // Reminder // @TODO: should alarms be used when importing event from phone? - if (!empty($config'ALARMS')) { + if ($config'ALARMS') { $event'valarms' = $this->to_kolab_alarm($data->reminder, $event); } - $attendees = ; - $categories = ; + $attendees = array(); + $categories = array(); // Categories if (isset($data->categories)) { @@ -523,40 +470,25 @@ } // Organizer - if (!$is_exception) { - // Organizer specified - if ($organizer_email = $data->organizerEmail) { - $attendees = - 'role' => 'ORGANIZER', - 'name' => $data->organizerName, - 'email' => $organizer_email, - ; - } elseif (!empty($event'attendees')) { - // Organizer not specified, use one from the original event if that's an update - foreach ($event'attendees' as $idx => $attendee) { - if (!empty($attendee'email') && !empty($attendee'role') && $attendee'role' == 'ORGANIZER') { - $organizer_email = $attendee'email'; - $attendees = - 'role' => 'ORGANIZER', - 'name' => $attendee'name' ?? '', - 'email' => $organizer_email, - ; - } - } - } + if (!$is_exception && ($organizer_email = $data->organizerEmail)) { + $attendees = array( + 'role' => 'ORGANIZER', + 'name' => $data->organizerName, + 'email' => $organizer_email, + ); } // Attendees - // Whenever Outlook sends dummy timezone it is an event where the user is an attendee. - // In these cases Attendees element is bogus: contains invalid status and does not - // contain all attendees. We have to ignore it. - if ($is_outlook && !$is_exception && $data->timezone === $dummy_tz) { - $this->logger->debug('Dummy outlook update detected, ignoring attendee changes.'); + // Outlook 2013 sends a dummy update just after MeetingResponse has been processed, + // this update resets attendee status set in the MeetingResponse request. + // We ignore changes to attendees data on such updates + if ($is_outlook && $this->isDummyOutlookUpdate($data, $entry, $event)) { $attendees = $entry'attendees'; - } elseif (isset($data->attendees)) { + } + else if (isset($data->attendees)) { + $statusMap = array_flip($this->attendeeStatusMap); foreach ($data->attendees as $attendee) { - if (!empty($organizer_email) && $attendee->email && !strcasecmp($attendee->email, $organizer_email)) { - // skip the organizer + if ($attendee->email && $attendee->email == $organizer_email) { continue; } @@ -569,11 +501,11 @@ $role = array_search(self::ATTENDEE_TYPE_REQUIRED, $this->attendeeTypeMap); } - $_attendee = + $_attendee = array( 'role' => $role, 'name' => $attendee->name != $attendee->email ? $attendee->name : '', 'email' => $attendee->email, - ; + ); if (isset($attendee->attendeeType) && $attendee->attendeeType == self::ATTENDEE_TYPE_RESOURCE) { $_attendee'cutype' = 'RESOURCE'; @@ -585,7 +517,8 @@ $_attendee'status' = 'NEEDS-ACTION'; $_attendee'rsvp' = true; } - } elseif (!empty($event'attendees') && !empty($attendee->email)) { + } + else if (!empty($event'attendees') && !empty($attendee->email)) { // copy the old attendee status foreach ($event'attendees' as $old_attendee) { if ($old_attendee'email' == $_attendee'email' && isset($old_attendee'status')) { @@ -600,53 +533,35 @@ } } - // Outlook does not send the correct attendee status when changing between accepted and tentative, but it toggles the busyStatus. - if ($is_outlook || $is_android) { - $status = null; - if ($data->busyStatus == self::BUSY_STATUS_BUSY) { - $status = "ACCEPTED"; - } elseif ($data->busyStatus == self::BUSY_STATUS_TENTATIVE) { - $status = "TENTATIVE"; - } - - if ($status) { - $this->logger->debug("Updating our attendee status based on the busy status to {$status}."); - $emails = $this->user_emails(); - $this->find_and_update_attendee_status($attendees, $status, $emails); - } + // Make sure the event has the organizer set + if (!$organizer_email && ($identity = kolab_sync::get_instance()->user->get_identity())) { + $attendees = array( + 'role' => 'ORGANIZER', + 'name' => $identity'name', + 'email' => $identity'email', + ); } - if (!$is_exception) { - // Make sure the event has the organizer set - if (!$organizer_email && ($identity = kolab_sync::get_instance()->user->get_identity())) { - $attendees = - 'role' => 'ORGANIZER', - 'name' => $identity'name', - 'email' => $identity'email', - ; - } + $event'attendees' = $attendees; + $event'categories' = $categories; - // recurrence (and exceptions) + // recurrence (and exceptions) + if (!$is_exception) { $event'recurrence' = $this->recurrence_to_kolab($data, $folderid, $timezone); } - $event'attendees' = $attendees; - $event'categories' = $categories; - $event'exceptions' = $event'recurrence''EXCEPTIONS' ?? ; - // Bump SEQUENCE number on update (Outlook only). // It's been confirmed that any change of the event that has attendees specified // bumps SEQUENCE number of the event (we can see this in sent iTips). // Unfortunately Outlook also sends an update when no SEQUENCE bump // is needed, e.g. when updating attendee status. // We try our best to bump the SEQUENCE only when expected - // @phpstan-ignore-next-line if (!empty($entry) && !$is_exception && !empty($data->attendees) && $data->timezone != $dummy_tz) { if ($last_update = $this->getKolabDataItem($event, self::KEY_DTSTAMP)) { $last_update = new DateTime($last_update); } - if (!empty($data->dtStamp) && $data->dtStamp != $last_update) { + if ($data->dtStamp && $data->dtStamp != $last_update) { if ($this->has_significant_changes($event, $entry)) { $event'sequence'++; $this->logger->debug('Found significant changes in the updated event. Bumping SEQUENCE to ' . $event'sequence'); @@ -657,7 +572,7 @@ // Because we use last event modification time above, we make sure // the event modification time is not (re)set by the server, // we use the original Outlook's timestamp. - if ($is_outlook && !empty($data->dtStamp)) { + if ($is_outlook && $data->dtStamp) { $this->setKolabDataItem($event, self::KEY_DTSTAMP, $data->dtStamp->format(DateTime::ATOM)); } @@ -678,217 +593,84 @@ */ public function setAttendeeStatus(Syncroton_Model_MeetingResponse $request) { - $status_map = + $status_map = array( 1 => 'ACCEPTED', 2 => 'TENTATIVE', 3 => 'DECLINED', - ; - - $status = $status_map$request->userResponse ?? null; + ); - if (empty($status)) { - throw new Syncroton_Exception_Status_MeetingResponse(Syncroton_Exception_Status_MeetingResponse::MEETING_ERROR); - } - - // extract event from the invitation - try { - $event, $existing = $this->get_event_from_invitation($request); - } catch (Exception $e) { - throw new Syncroton_Exception_Status_MeetingResponse(Syncroton_Exception_Status_MeetingResponse::MEETING_ERROR); - } - /* - switch ($status) { - case 'ACCEPTED': $event'free_busy' = 'busy'; break; - case 'TENTATIVE': $event'free_busy' = 'tentative'; break; - case 'DECLINED': $event'free_busy' = 'free'; break; - } - */ - // Store response timestamp for further use - $reply_time = new DateTime('now', new DateTimeZone('UTC')); - $this->setKolabDataItem($event, self::KEY_REPLYTIME, $reply_time->format('Ymd\THis\Z')); - - // Update/Save the event - if (empty($existing)) { - $folderId = $this->save_event($event, $status); - - // Create SyncState for the new event, so it is not synced twice - if ($folderId) { - try { - $syncBackend = Syncroton_Registry::getSyncStateBackend(); - $folderBackend = Syncroton_Registry::getFolderBackend(); - $contentBackend = Syncroton_Registry::getContentStateBackend(); - $syncFolder = $folderBackend->getFolder($this->device->id, $folderId); - $syncState = $syncBackend->getSyncState($this->device->id, $syncFolder->id); - - $contentBackend->create(new Syncroton_Model_Content( - 'device_id' => $this->device->id, - 'folder_id' => $syncFolder->id, - 'contentid' => $this->serverId($event'uid', $folderId), - 'creation_time' => $syncState->lastsync, - 'creation_synckey' => $syncState->counter, - )); - } catch (Exception $e) { - // ignore - } + if ($status = $status_map$request->userResponse) { + // extract event from the invitation + list($event, $existing) = $this->get_event_from_invitation($request); +/* + switch ($status) { + case 'ACCEPTED': $event'free_busy' = 'busy'; break; + case 'TENTATIVE': $event'free_busy' = 'tentative'; break; + case 'DECLINED': $event'free_busy' = 'free'; break; + } +*/ + // Store Outlook response timestamp for further use + if (stripos($this->device->devicetype, 'outlook') !== false) { + $dtstamp = new DateTime('now', new DateTimeZone('UTC')); + $dtstamp = $dtstamp->format(DateTime::ATOM); } - } else { - $folderId = $this->update_event($event, $existing, $status, $request->instanceId); - } - - if (!$folderId) { - throw new Syncroton_Exception_Status_MeetingResponse(Syncroton_Exception_Status_MeetingResponse::MEETING_ERROR); - } - - // TODO: ActiveSync version >= 16, send the iTip response. - if (isset($request->sendResponse)) { - // SendResponse can contain Body to use as email body (can be empty) - // TODO: Activesync >= 16.1 proposedStartTime and proposedEndTime. - } - - // FIXME: We should not return an UID when status=DECLINED - // as it's expected by the specification. Server - // should delete an event in such a case, but we - // keep the event copy with appropriate attendee status instead. - return $this->serverId($event'uid', $folderId); - } - - /** - * Process an event from an iTip message - update the event in the recipient's calendar - * - * @param array $event Event data from the iTip - * - * @return string|null Attendee status from the iTip (self::ITIP_* constant value) - */ - public function processItipReply($event) - { - // FIXME: This does not prevent from spoofing, i.e. an iTip message - // could be sent by anyone impersonating an organizer or attendee - - // FIXME: This will not work with Kolab delegation, as we do look - // for the event instance in personal folders only (for now) - // We also do not use SENT-BY,DELEGATED-TO,DELEGATED-FROM here at all. - - // FIXME: This is potential performance problem - we update an event - // whenever we sync an email message. User can have multiple AC clients - // or many iTip messages in INBOX. Should we remember which email was - // already processed? - - // FIXME: Should we check SEQUENCE or something else to prevent - // overwriting the attendee status with outdated status (on REPLY)? - - // Here we're handling CANCEL message, find the event (or occurrence) and remove it - if ($event'_method' == 'CANCEL') { - // TODO: Performance: When we're going to delete the event we don't have to fetch it, - // we just need to find that it exists and in which folder. - - if ($existing = $this->find_event_by_uid($event'uid')) { - // Note: Normally we'd just set the event status to canceled, but - // ActiveSync clients do not understand that, we have to delete it - - if (!empty($event'recurrence_date')) { - // A single recurring event occurrence - $rec_day = $event'recurrence_date'->format('Ymd'); - // Remove the matching RDATE entry - if (!empty($existing'recurrence''RDATE')) { - foreach ($existing'recurrence''RDATE' as $j => $rdate) { - if ($rdate->format('Ymd') == $rec_day) { - unset($existing'recurrence''RDATE'$j); - break; - } - } - } - - // Check EXDATE list, maybe already cancelled - if (!empty($existing'recurrence''EXDATE')) { - foreach ($existing'recurrence''EXDATE' as $j => $exdate) { - if ($exdate->format('Ymd') == $rec_day) { - return self::ITIP_CANCELLED; // skip update - } - } - } else { - $existing'recurrence''EXDATE' = ; - } - if (!isset($existing'exceptions')) { - $existing'exceptions' = ; - } + // Update/Save the event + if (empty($existing)) { + if ($dtstamp) { + $this->setKolabDataItem($event, self::KEY_RESPONSE_DTSTAMP, $dtstamp); + } - if (!empty($existing'exceptions')) { - foreach ($existing'exceptions' as $i => $exception) { - if (libcalendaring::is_recurrence_exception($event, $exception)) { - unset($existing'exceptions'$i); - } - } + $folder = $this->save_event($event, $status); + + // Create SyncState for the new event, so it is not synced twice + if ($folder) { + $folderId = $this->getFolderId($folder); + + try { + $syncBackend = Syncroton_Registry::getSyncStateBackend(); + $folderBackend = Syncroton_Registry::getFolderBackend(); + $contentBackend = Syncroton_Registry::getContentStateBackend(); + $syncFolder = $folderBackend->getFolder($this->device->id, $folderId); + $syncState = $syncBackend->getSyncState($this->device->id, $syncFolder->id); + + $contentBackend->create(new Syncroton_Model_Content(array( + 'device_id' => $this->device->id, + 'folder_id' => $syncFolder->id, + 'contentid' => $this->serverId($event'uid', $folder), + 'creation_time' => $syncState->lastsync, + 'creation_synckey' => $syncState->counter, + ))); } - - // Add an exception to the master event - $existing'recurrence''EXDATE' = $event'recurrence_date'; - - // TODO: Handle errors - $this->save_event($existing, null); - } else { - $folder = $this->backend->getFolder($existing'folderId', $this->device->deviceid, $this->modelName); - if ($folder && $folder->valid) { - // TODO: Handle errors - $folder->delete($event'uid'); + catch (Exception $e) { + // ignore } } } - - return self::ITIP_CANCELLED; - } - - // Here we're handling REPLY message - if (empty($event'attendees') || $event'_method' != 'REPLY') { - return null; - } - - $attendeeStatus = null; - $attendeeEmail = null; - - // Get the attendee/status - foreach ($event'attendees' as $attendee) { - if (empty($attendee'role') || $attendee'role' != 'ORGANIZER') { - if (!empty($attendee'email') && !empty($attendee'status')) { - // Per iTip spec. there should be only one (non-organizer) attendee here - // FIXME: Verify is it realy the case with e.g. Kolab webmail, If not, we should - // probably use the message sender from the From: header - $attendeeStatus = strtoupper($attendee'status'); - $attendeeEmail = $attendee'email'; - break; + else { + if ($dtstamp) { + $this->setKolabDataItem($existing, self::KEY_RESPONSE_DTSTAMP, $dtstamp); } + + $folder = $this->update_event($event, $existing, $status, $request->instanceId); } - } - // Find the event (or occurrence) and update it - if ($attendeeStatus && ($existing = $this->find_event_by_uid($event'uid'))) { - // TODO: We should probably check the SEQUENCE to not reset status to an outdated value - - if (!empty($event'recurrence_date')) { - // A single recurring event occurrence - // Find the exception entry, it should exist, if not ignore - if (!empty($existing'exceptions')) { - foreach ($existing'exceptions' as $i => $exception) { - if (!empty($exception'attendees') && libcalendaring::is_recurrence_exception($event, $exception)) { - $attendees = &$existing'exceptions'$i'attendees'; - break; - } - } - } - } elseif (!empty($existing'attendees')) { - $attendees = &$existing'attendees'; + if (!$folder) { + throw new Syncroton_Exception_Status_MeetingResponse(Syncroton_Exception_Status_MeetingResponse::MEETING_ERROR); } - if (isset($attendees)) { - $found = $this->find_and_update_attendee_status($attendees, $attendeeStatus, $attendeeEmail, $changed); - if ($found && $changed) { - // TODO: error handling - $this->save_event($existing, null); - } + // TODO: ActiveSync version >= 16, send the iTip response. + if (isset($request->sendResponse)) { + // SendResponse can contain Body to use as email body (can be empty) + // TODO: Activesync >= 16.1 proposedStartTime and proposedEndTime. } } - return $attendeeStatus; + // FIXME: We should not return an UID when status=DECLINED + // as it's expected by the specification. Server + // should delete an event in such a case, but we + // keep the event copy with appropriate attendee status instead. + return empty($status) ? null : $this->serverId($event'uid', $folder); } /** @@ -906,12 +688,12 @@ // find the event in calendar $existing = $this->find_event_by_uid($event'uid'); - return $event, $existing; + return array($event, $existing); } // Event from calendar folder - if ($event = $this->getObject($request->collectionId, $request->requestId)) { - return $event, $event; + if ($event = $this->getObject($request->collectionId, $request->requestId, $folder)) { + return array($event, $event); } throw new Syncroton_Exception_Status_MeetingResponse(Syncroton_Exception_Status_MeetingResponse::INVALID_REQUEST); @@ -931,17 +713,12 @@ // TODO: should we check every existing event folder even if not subscribed for sync? - if ($folders = $this->listFolders()) { - foreach ($folders as $_folder) { - $folder = $this->backend->getFolder($_folder'serverId', $this->device->deviceid, $this->modelName); - - if ($folder - && $folder->get_namespace() == 'personal' - && ($result = $this->backend->getItem($_folder'serverId', $this->device->deviceid, $this->modelName, $uid)) - ) { - $result'folderId' = $_folder'serverId'; - return $result; - } + foreach ($this->listFolders() as $folder) { + $storage_folder = $this->getFolderObject($folder'imap_name'); + if ($storage_folder->get_namespace() == 'personal' + && ($result = $storage_folder->get_object($uid)) + ) { + return $result; } } } @@ -956,59 +733,13 @@ throw new Syncroton_Exception_Status_MeetingResponse(Syncroton_Exception_Status_MeetingResponse::INVALID_REQUEST); } - // A single recurring event occurrence - if (!empty($event'recurrence_date')) { - $event'recurrence' = ; - - if ($status) { - $this->update_attendee_status($event, $status); - $status = null; - } - - if (!isset($old'exceptions')) { - $old'exceptions' = ; - } - - $existing = false; - foreach ($old'exceptions' as $i => $exception) { - if (libcalendaring::is_recurrence_exception($event, $exception)) { - $old'exceptions'$i = $event; - $existing = true; - } - } - - // TODO: In case organizer first cancelled an occurrence and then invited - // an attendee to the same date, and attendee accepts, we should remove EXDATE entry. - // FIXME: We have to check with ActiveSync clients whether it is better - // to have an exception with DECLINED attendee status, or an EXDATE entry - - if (!$existing) { - $old'exceptions' = $event; - } - } - // A main event update - elseif (isset($event'sequence') && $event'sequence' > $old'sequence') { - // FIXME: Can we be smarter here? Should we update everything? What about e.g. new attendees? - // And do we need to check the sequence? - $props = 'start', 'end', 'title', 'description', 'location', 'free_busy'; - - foreach ($props as $prop) { - if (isset($event$prop)) { - $old$prop = $event$prop; - } - } - - // Copy new custom properties - if (!empty($event'x-custom')) { - foreach ($event'x-custom' as $key => $val) { - $old'x-custom'$key = $val; - } - } + if ($event'free_busy') { + $old'free_busy' = $event'free_busy'; } // Updating an existing event is most-likely a response // to an iTip request with bumped SEQUENCE - $old'sequence' = ($old'sequence' ?? 0) + 1; + $old'sequence' += 1; // Update the event return $this->save_event($old, $status); @@ -1020,23 +751,25 @@ */ protected function save_event(&$event, $status = null) { - $first = null; - $default = null; - - if (!isset($event'folderId')) { - // Find the folder to which we'll save the event - if ($folders = $this->listFolders()) { - foreach ($folders as $_folder) { - $folder = $this->backend->getFolder($_folder'serverId', $this->device->deviceid, $this->modelName); - - if ($folder && $folder->get_namespace() == 'personal') { - if ($_folder'type' == 8) { - $default = $_folder'serverId'; - break; - } - if (!$first) { - $first = $_folder'serverId'; - } + // Find default folder to which we'll save the event + if (!isset($event'_mailbox')) { + $folders = $this->listFolders(); + $storage = rcube::get_instance()->get_storage(); + + // find the default + foreach ($folders as $folder) { + if ($folder'type' == 8 && $storage->folder_namespace($folder'imap_name') == 'personal') { + $event'_mailbox' = $folder'imap_name'; + break; + } + } + + // if there's no folder marked as default, use any + if (!isset($event'_mailbox') && !empty($folders)) { + foreach ($folders as $folder) { + if ($storage->folder_namespace($folder'imap_name') == 'personal') { + $event'_mailbox' = $folder'imap_name'; + break; } } } @@ -1051,55 +784,39 @@ // TODO: Free/busy trigger? - $old_uid = isset($event'folderId') ? $event'uid' : null; - $folder_id = $event'folderId' ?? ($default ?? $first); - $folder = $this->backend->getFolder($folder_id, $this->device->deviceid, $this->modelName); + if (isset($event'_mailbox')) { + $folder = $this->getFolderObject($event'_mailbox'); - if (!empty($folder) && $folder->valid && $folder->save($event, $this->modelName, $old_uid)) { - return $folder_id; + if ($folder && $folder->valid && $folder->save($event)) { + return $folder; + } } return false; } /** - * Update the attendee status of the user matching $emails + * Update the attendee status of the user */ - protected function find_and_update_attendee_status(&$attendees, $status, $emails, &$changed = false) + protected function update_attendee_status(&$event, $status) { - $found = false; - foreach ((array) $attendees as $i => $attendee) { - if (!empty($attendee'email') - && (empty($attendee'role') || $attendee'role' != 'ORGANIZER') - && in_array_nocase($attendee'email', $emails) - ) { - $changed = $changed || ($status != ($attendee'status' ?? '')); - $attendees$i'status' = $status; - $attendees$i'rsvp' = false; - $this->logger->debug('Updating existing attendee: ' . $attendee'email' . ' status: ' . $status); - $found = true; + $organizer = null; + $emails = $this->user_emails(); + + foreach ((array) $event'attendees' as $i => $attendee) { + if ($attendee'role' == 'ORGANIZER') { + $organizer = $attendee; + } + else if ($attendee'email' && in_array_nocase($attendee'email', $emails)) { + $event'attendees'$i'status' = $status; + $event'attendees'$i'rsvp' = false; + $event_attendee = $attendee; } } - return $found; - } - /** - * Update the attendee status of the user - */ - protected function update_attendee_status(&$event, $status) - { - $emails = $this->user_emails(); - - if (!$this->find_and_update_attendee_status($event'attendees', $status, $emails)) { - $this->logger->debug('Adding new attendee ' . $emails0 . ' status: ' . $status); - // Add the user to the attendees list - $event'attendees' = - 'role' => 'OPT-PARTICIPANT', - 'name' => '', - 'email' => $emails0, - 'status' => $status, - 'rsvp' => false, - ; + if (!$event_attendee) { + $this->logger->warn('MeetingResponse on an event where the user is not an attendee. UID: ' . $event'uid'); + throw new Syncroton_Exception_Status_MeetingResponse(Syncroton_Exception_Status_MeetingResponse::MEETING_ERROR); } } @@ -1108,31 +825,31 @@ * * @param int $filter_type Filter type * - * @return array Filter query + * @param array Filter query */ protected function filter($filter_type = 0) { - $filter = 'type', '=', $this->modelName; + $filter = array(array('type', '=', $this->modelName)); switch ($filter_type) { - case Syncroton_Command_Sync::FILTER_2_WEEKS_BACK: - $mod = '-2 weeks'; - break; - case Syncroton_Command_Sync::FILTER_1_MONTH_BACK: - $mod = '-1 month'; - break; - case Syncroton_Command_Sync::FILTER_3_MONTHS_BACK: - $mod = '-3 months'; - break; - case Syncroton_Command_Sync::FILTER_6_MONTHS_BACK: - $mod = '-6 months'; - break; + case Syncroton_Command_Sync::FILTER_2_WEEKS_BACK: + $mod = '-2 weeks'; + break; + case Syncroton_Command_Sync::FILTER_1_MONTH_BACK: + $mod = '-1 month'; + break; + case Syncroton_Command_Sync::FILTER_3_MONTHS_BACK: + $mod = '-3 months'; + break; + case Syncroton_Command_Sync::FILTER_6_MONTHS_BACK: + $mod = '-6 months'; + break; } if (!empty($mod)) { $dt = new DateTime('now', new DateTimeZone('UTC')); $dt->modify($mod); - $filter = 'dtend', '>', $dt; + $filter = array('dtend', '>', $dt); } return $filter; @@ -1141,7 +858,7 @@ /** * Set MeetingStatus according to event data */ - protected function meeting_status_from_kolab($event, &$result) + protected function meeting_status_from_kolab($collection, $event, &$result) { // 0 - The event is an appointment, which has no attendees. // 1 - The event is a meeting and the user is the meeting organizer. @@ -1162,7 +879,8 @@ if ($event'status' == 'CANCELLED') { $status = $is_organizer ? 5 : 7; - } else { + } + else { $status = $is_organizer ? 1 : 3; } } @@ -1177,7 +895,7 @@ { if (isset($event'valarms')) { foreach ($event'valarms' as $alarm) { - if (in_array($alarm'action', 'DISPLAY', 'AUDIO')) { + if (in_array($alarm'action', array('DISPLAY', 'AUDIO'))) { $value = $alarm'trigger'; break; } @@ -1187,10 +905,11 @@ if (!empty($value) && $value instanceof DateTime) { if (!empty($event'start') && ($interval = $event'start'->diff($value))) { if ($interval->invert && !$interval->m && !$interval->y) { - return intval(round($interval->s / 60) + $interval->i + $interval->h * 60 + $interval->d * 60 * 24); + return intval(round($interval->s/60) + $interval->i + $interval->h * 60 + $interval->d * 60 * 24); } } - } elseif (!empty($value) && preg_match('/^(-+*)PT*(0-9+)(WDHMS)$/', $value, $matches)) { + } + else if (!empty($value) && preg_match('/^(-+*)PT*(0-9+)(WDHMS)$/', $value, $matches)) { $value = intval($matches2); if ($value && $matches1 != '-') { @@ -1198,14 +917,10 @@ } switch ($matches3) { - case 'S': $value = intval(round($value / 60)); - break; - case 'H': $value *= 60; - break; - case 'D': $value *= 24 * 60; - break; - case 'W': $value *= 7 * 24 * 60; - break; + case 'S': $value = intval(round($value/60)); break; + case 'H': $value *= 60; break; + case 'D': $value *= 24 * 60; break; + case 'W': $value *= 7 * 24 * 60; break; } return $value; @@ -1218,27 +933,28 @@ protected function to_kolab_alarm($value, $event) { if ($value === null || $value === '') { - return isset($event'valarms') ? (array) $event'valarms' : ; + return isset($event'valarms') ? (array) $event'valarms' : array(); } - $valarms = ; - $unsupported = ; + $valarms = array(); + $unsupported = array(); if (!empty($event'valarms')) { foreach ($event'valarms' as $alarm) { - if (empty($current) && in_array($alarm'action', 'DISPLAY', 'AUDIO')) { + if (!$current && in_array($alarm'action', array('DISPLAY', 'AUDIO'))) { $current = $alarm; - } else { + } + else { $unsupported = $alarm; } } } - $valarms = + $valarms = array( 'action' => !empty($current'action') ? $current'action' : 'DISPLAY', 'description' => !empty($current'description') ? $current'description' : '', 'trigger' => sprintf('-PT%dM', $value), - ; + ); if (!empty($unsupported)) { $valarms = array_merge($valarms, $unsupported); @@ -1250,7 +966,7 @@ /** * Sanity checks on event input * - * @param Syncroton_Model_Event|Syncroton_Model_EventException &$entry Entry object + * @param Syncroton_Model_IEntry &$entry Entry object * * @throws Syncroton_Exception_Status_Sync */ @@ -1271,13 +987,15 @@ $entry->startTime = $rounded; $entry->endTime = $end; - } elseif (empty($entry->startTime)) { + } + else if (empty($entry->startTime)) { if ($entry->endTime < $now || $entry->endTime < $rounded) { throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::INVALID_ITEM); } $entry->startTime = $rounded; - } elseif (empty($entry->endTime)) { + } + else if (empty($entry->endTime)) { if ($entry->startTime < $now) { throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::INVALID_ITEM); } @@ -1293,8 +1011,8 @@ protected function has_significant_changes($event, $old) { // Calendar namespace fields - foreach ('allday', 'start', 'end', 'location', 'recurrence' as $key) { - if (($event$key ?? null) != ($old$key ?? null)) { + foreach (array('allday', 'start', 'end', 'location', 'recurrence') as $key) { + if ($event$key != $old$key) { // Comparing recurrence is tricky as there can be differences in default // value handling. Let's try to handle most common cases if ($key == 'recurrence' && $this->fixed_recurrence($event) == $this->fixed_recurrence($old)) { @@ -1332,14 +1050,14 @@ $rec = (array) $event'recurrence'; // Add BYDAY if not exists - if (($rec'FREQ' ?? '') == 'WEEKLY' && empty($rec'BYDAY')) { - $days = 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'; + if ($rec'FREQ' == 'WEEKLY' && empty($rec'BYDAY')) { + $days = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'); $day = $event'start'->format('w'); $rec'BYDAY' = $days$day; } - if (empty($rec'INTERVAL')) { + if (!$rec'INTERVAL') { $rec'INTERVAL' = 1; } @@ -1347,4 +1065,39 @@ return $rec; } + + /** + * Check if the event update request is a fake (for Outlook) + */ + protected function isDummyOutlookUpdate($data, $entry, &$result) + { + $is_dummy = false; + + // Outlook 2013 sends a dummy update just after MeetingResponse has been processed, + // this update resets attendee status set in the MeetingResponse request. + // We ignore attendees data in such updates, they should not happen according to + // https://msdn.microsoft.com/en-us/library/office/hh428685(v=exchg.140).aspx + // but they will contain some data as alarms and free/busy status so we don't + // ignore them completely + if (!empty($entry) && !empty($data->attendees) && stripos($this->device->devicetype, 'outlook') !== false) { + // Some of these requests use just dummy Timezone + $dummy_tz = str_repeat('A', 230) . '=='; + + if ($data->timezone == $dummy_tz) { + $is_dummy = true; + } + + // But some of them do not, so we have check if that is a first + // update immediately (up to 5 seconds) after MeetingResponse request + if (!$is_dummy && ($dtstamp = $this->getKolabDataItem($entry, self::KEY_RESPONSE_DTSTAMP))) { + $dtstamp = new DateTime($dtstamp); + $now = new DateTime('now', new DateTimeZone('UTC')); + $is_dummy = $now->getTimestamp() - $dtstamp->getTimestamp() <= 5; + } + + $this->unsetKolabDataItem($result, self::KEY_RESPONSE_DTSTAMP); + } + + return $is_dummy; + } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_data_contacts.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_data_contacts.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -31,7 +31,7 @@ /** * Mapping from ActiveSync Contacts namespace fields */ - protected $mapping = + protected $mapping = array( 'anniversary' => 'anniversary', 'assistantName' => 'assistant:0', //'assistantPhoneNumber' => 'assistantphonenumber', @@ -94,7 +94,7 @@ 'managerName' => 'manager:0', //'mMS' => 'mms', 'nickName' => 'nickname', - ; + ); /** * Kolab object type @@ -149,13 +149,11 @@ * * @param Syncroton_Model_SyncCollection $collection Collection data * @param string $serverId Local entry identifier - * - * @return array|Syncroton_Model_Contact Contact object */ public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId) { $data = is_array($serverId) ? $serverId : $this->getObject($collection->collectionId, $serverId); - $result = ; + $result = array(); if (empty($data)) { throw new Syncroton_Exception_NotFound("Contact $serverId not found"); @@ -166,23 +164,23 @@ $value = $this->getKolabDataItem($data, $name); switch ($name) { - case 'photo': - if ($value) { - // ActiveSync limits photo size to 48KB (of base64 encoded string) - if (strlen($value) * 1.33 > 48 * 1024) { - continue 2; - } + case 'photo': + if ($value) { + // ActiveSync limits photo size to 48KB (of base64 encoded string) + if (strlen($value) * 1.33 > 48 * 1024) { + continue 2; } - break; + } + break; - case 'birthday': - case 'anniversary': - $value = self::date_from_kolab($value); - break; + case 'birthday': + case 'anniversary': + $value = self::date_from_kolab($value); + break; - case 'notes': - $value = $this->body_from_kolab($value, $collection); - break; + case 'notes': + $value = $this->body_from_kolab($value, $collection); + break; } if (empty($value) || is_array($value)) { @@ -193,14 +191,13 @@ } // email address(es): email1Address, email2Address, email3Address - for ($x = 0; $x < 3; $x++) { - if (!empty($data'email'$x)) { - $email = $data'email'$x; + for ($x=0; $x<3; $x++) { + if ($email = $data'email'$x) { if (is_array($email)) { $email = $email'address'; } if ($email) { - $result'email' . ($x + 1) . 'Address' = $email; + $result'email' . ($x+1) . 'Address' = $email; } } } @@ -211,67 +208,67 @@ /** * convert contact from xml to libkolab array * - * @param Syncroton_Model_Contact $data Contact to convert - * @param string $folderId Folder identifier - * @param array $entry Existing entry + * @param Syncroton_Model_IEntry $data Contact to convert + * @param string $folderId Folder identifier + * @param array $entry Existing entry * * @return array Kolab object array */ - public function toKolab($data, $folderId, $entry = null) + public function toKolab(Syncroton_Model_IEntry $data, $folderId, $entry = null) { - $contact = !empty($entry) ? $entry : ; + $contact = !empty($entry) ? $entry : array(); // Contacts namespace fields foreach ($this->mapping as $key => $name) { $value = $data->$key; switch ($name) { - case 'address.work.street': - if (strtolower($this->device->devicetype) == 'palm') { - // palm pre sends the whole address in the <Contacts:BusinessStreet> tag - $value = null; - } - break; + case 'address.work.street': + if (strtolower($this->device->devicetype) == 'palm') { + // palm pre sends the whole address in the <Contacts:BusinessStreet> tag + $value = null; + } + break; - case 'website.homepage.url': - // remove facebook urls - if (preg_match('/^fb:\/\//', $value)) { - $value = null; - } - break; + case 'website.homepage.url': + // remove facebook urls + if (preg_match('/^fb:\/\//', $value)) { + $value = null; + } + break; - case 'notes': - $value = $this->getBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT); - // If note isn't specified keep old note - if ($value === null) { - continue 2; - } - break; + case 'notes': + $value = $this->getBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT); + // If note isn't specified keep old note + if ($value === null) { + continue 2; + } + break; - case 'photo': - // If photo isn't specified keep old photo - if ($value === null) { - continue 2; - } - break; - - case 'birthday': - case 'anniversary': - if ($value) { - // convert date to string format, so libkolab will store - // it with no time and timezone what could be incorrectly re-calculated (#2555) - $value = $value->format('Y-m-d'); - } - break; + case 'photo': + // If photo isn't specified keep old photo + if ($value === null) { + continue 2; + } + break; + + case 'birthday': + case 'anniversary': + if ($value) { + // convert date to string format, so libkolab will store + // it with no time and timezone what could be incorrectly re-calculated (#2555) + $value = $value->format('Y-m-d'); + } + break; } $this->setKolabDataItem($contact, $name, $value); } // email address(es): email1Address, email2Address, email3Address - $emails = ; - for ($x = 0; $x < 3; $x++) { - $key = 'email' . ($x + 1) . 'Address'; + $emails = array(); + for ($x=0; $x<3; $x++) { + $key = 'email' . ($x+1) . 'Address'; if ($value = $data->$key) { // Android sends email address as: Lars Kneschke <l.kneschke@metaways.de> if (preg_match('/(.*)<(.+@^@+)>/', $value, $matches)) { @@ -289,7 +286,7 @@ $type = $email'type'; } } - $emails = 'address' => $value, 'type' => $type; + $emails = array('address' => $value, 'type' => $type); } } $contact'email' = $emails; @@ -307,12 +304,12 @@ $list = parent::getAllFolders(); if ($this->isMultiFolder() && $this->hasGAL()) { - $list$this->galFolder = new Syncroton_Model_Folder( + $list$this->galFolder = new Syncroton_Model_Folder(array( 'displayName' => $this->galFolderName, // @TODO: localization? 'serverId' => $this->galFolder, 'parentId' => 0, 'type' => 14, - ); + )); } return $list; @@ -349,7 +346,7 @@ /** * Empty folder (remove all entries and optionally subfolders) * - * @param string $folderid Folder identifier + * @param string $folderId Folder identifier * @param array $options Options */ public function emptyFolderContents($folderid, $options) @@ -408,9 +405,9 @@ /** * update existing entry * - * @param string $folderId - * @param string $serverId - * @param Syncroton_Model_IEntry $entry + * @param string $folderId + * @param string $serverId + * @param SimpleXMLElement $entry * * @return string ID of the updated entry */ @@ -424,13 +421,13 @@ } /** - * Delete an entry + * delete entry * - * @param string $folderId - * @param string $serverId - * @param ?Syncroton_Model_SyncCollection $collectionData + * @param string $folderId + * @param string $serverId + * @param array $collectionData */ - public function deleteEntry($folderId, $serverId, $collectionData = null) + public function deleteEntry($folderId, $serverId, $collectionData) { if (strpos($serverId, $this->galPrefix) === 0 && $this->hasGAL()) { throw new Syncroton_Exception_AccessDenied("Deleting GAL entries is not possible"); @@ -444,13 +441,13 @@ * * @param int $filter_type Filter type * - * @return array Filter query + * @param array Filter query */ protected function filter($filter_type = 0) { // specify object type, contact folders in Kolab might // contain also ditribution-list objects, we'll skip them - return 'type', '=', $this->modelName; + return array(array('type', '=', $this->modelName)); } /** @@ -470,14 +467,14 @@ * * @return array|int Search result as count or array of uids/objects */ - protected function searchEntries($folderid, $filter = , $result_type = self::RESULT_UID, $extraData = null) + protected function searchEntries($folderid, $filter = array(), $result_type = self::RESULT_UID) { // GAL Folder exists, return result from LDAP only if ($folderid === $this->galFolder && $this->hasGAL()) { return $this->searchGALEntries($filter, $result_type); } - $result = parent::searchEntries($folderid, $filter, $result_type, $extraData); + $result = parent::searchEntries($folderid, $filter, $result_type); // Merge results from LDAP if ($this->hasGAL() && !$this->isMultiFolder()) { @@ -485,7 +482,8 @@ if ($result_type == self::RESULT_COUNT) { $result += $gal_result; - } else { + } + else { $result = array_merge($result, $gal_result); } } @@ -496,13 +494,13 @@ /** * Fetches the entry from the backend */ - protected function getObject($folderid, $entryid) + protected function getObject($folderid, $entryid, &$folder = null) { if (strpos($entryid, $this->galPrefix) === 0 && $this->hasGAL()) { return $this->getGALEntry($entryid); } - return parent::getObject($folderid, $entryid); + return parent::getObject($folderid, $entryid, $folder); } /** @@ -520,7 +518,7 @@ // will be done as delete + create foreach ($filter as $f) { if ($f0 == 'changed') { - return $result_type == self::RESULT_COUNT ? 0 : ; + return $result_type == self::RESULT_COUNT ? 0 : array(); } } @@ -529,7 +527,7 @@ return $result_type == self::RESULT_COUNT ? count($result) : $result; } - $result = ; + $result = array(); foreach ($this->getGALSources() as $source) { if ($book = kolab_sync_data_gal::get_address_book($source'id')) { @@ -538,7 +536,7 @@ $book->set_pagesize(10000); $set = $book->list_records(); - foreach ($set as $contact) { + while ($contact = $set->next()) { $result = $this->createGALEntryUID($contact, $source'id'); } } @@ -556,30 +554,28 @@ * * @param string $serverId Entry identifier * - * @return array|null Contact data + * @return array Contact data */ protected function getGALEntry($serverId) { - $source, $timestamp, $uid = $this->resolveGALEntryUID($serverId); + list($source, $timestamp, $uid) = $this->resolveGALEntryUID($serverId); if ($source && $uid && ($book = kolab_sync_data_gal::get_address_book($source))) { $book->reset(); - $set = $book->search('uid', $uid, rcube_addressbook::SEARCH_STRICT, true, true); + $set = $book->search('uid', array($uid), rcube_addressbook::SEARCH_STRICT, true, true); $result = $set->first(); if ($result'uid' == $uid && $result'changed' == $timestamp) { // As in kolab_sync_data_gal we use only one email address if (empty($result'email')) { $emails = $book->get_col_values('email', $result, true); - $result'email' = $emails0; + $result'email' = array($emails0); } return $result; } } - - return null; } /** @@ -596,11 +592,12 @@ if ($gal_sync === true) { $enabled = true; - } elseif (is_array($gal_sync)) { + } + else if (is_array($gal_sync)) { $enabled = $this->deviceTypeFilter($gal_sync); } - $this->galSources = $enabled ? kolab_sync_data_gal::get_address_sources() : ; + $this->galSources = $enabled ? kolab_sync_data_gal::get_address_sources() : array(); if ($cache_type = $rcube->config->get('activesync_gal_cache', 'db')) { $cache_ttl = $rcube->config->get('activesync_gal_cache_ttl', '1d'); @@ -635,6 +632,6 @@ return $items; // source, timestamp, uid } - return ; + return array(); } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_data_email.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_data_email.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -28,12 +28,12 @@ */ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_IDataSearch { - public const MAX_SEARCH_RESULT = 200; + const MAX_SEARCH_RESULT = 200; /** * Mapping from ActiveSync Email namespace fields */ - protected $mapping = + protected $mapping = array( 'cc' => 'cc', //'contentClass' => 'contentclass', 'dateReceived' => 'internaldate', @@ -48,22 +48,22 @@ 'subject' => 'subject', //'threadTopic' => 'threadtopic', 'to' => 'to', - ; + ); - public static $memory_accumulated = 0; + static $memory_accumulated = 0; /** * Special folder type/name map * * @var array */ - protected $folder_types = + protected $folder_types = array( 2 => 'Inbox', 3 => 'Drafts', 4 => 'Deleted Items', 5 => 'Sent Items', 6 => 'Outbox', - ; + ); /** * Kolab object type @@ -93,8 +93,6 @@ */ protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED; - protected $storage; - /** * the constructor @@ -110,52 +108,10 @@ // Outlook 2013 support multi-folder $this->ext_devices = 'windowsoutlook15'; - } - /** - * Encode a globalObjId according to https://interoperability.blob.core.windows.net/files/MS-ASEMAIL/%5bMS-ASEMAIL%5d-150526.pdf 2.2.2.3 - * - * @param array $data An array with the data to encode - * - * @return string the encoded globalObjId - */ - public static function encodeGlobalObjId(array $data): string - { - $classid = "040000008200e00074c5b7101a82e008"; - if (!empty($data'data')) { - $payload = $data'data'; - } else { - $uid = $data'uid'; - $payload = "vCal-Uid\1\0\0\0{$uid}\0"; - } - - $packed = pack( - "H32nCCPx8Va*", - $classid, - $data'year' ?? 0, - $data'month' ?? 0, - $data'day' ?? 0, - $data'now' ?? 0, - strlen($payload), - $payload - ); - - return base64_encode($packed); - } - - /** - * Decode a globalObjId according to https://interoperability.blob.core.windows.net/files/MS-ASEMAIL/%5bMS-ASEMAIL%5d-150526.pdf 2.2.2.3 - * - * @param string $globalObjId The encoded globalObjId - * - * @return array An array with the decoded data - */ - public static function decodeGlobalObjId(string $globalObjId): array - { - $unpackString = 'H32classid/nyear/Cmonth/Cday/Pnow/x8/Vbytecount/a*data'; - $decoded = unpack($unpackString, base64_decode($globalObjId)); - $decoded'uid' = substr($decoded'data', strlen("vCal-Uid\1\0\0\0"), -1); - return $decoded; + if ($this->asversion >= 14) { + $this->tag_categories = true; + } } /** @@ -186,31 +142,31 @@ $value = null; switch ($name) { - case 'internaldate': - $value = self::date_from_kolab(rcube_utils::strtotime($headers->internaldate)); - break; + case 'internaldate': + $value = self::date_from_kolab(rcube_utils::strtotime($headers->internaldate)); + break; - case 'cc': - case 'to': - case 'replyto': - case 'from': - $addresses = rcube_mime::decode_address_list($headers->$name, null, true, $headers->charset); + case 'cc': + case 'to': + case 'replyto': + case 'from': + $addresses = rcube_mime::decode_address_list($headers->$name, null, true, $headers->charset); - foreach ($addresses as $idx => $part) { - // @FIXME: set name + address or address only? - $addresses$idx = format_email_recipient($part'mailto', $part'name'); - } + foreach ($addresses as $idx => $part) { + // @FIXME: set name + address or address only? + $addresses$idx = format_email_recipient($part'mailto', $part'name'); + } - $value = implode(',', $addresses); - break; + $value = implode(',', $addresses); + break; - case 'subject': - $value = $headers->get('subject'); - break; + case 'subject': + $value = $headers->get('subject'); + break; - case 'charset': - $value = self::charset_to_cp($headers->charset); - break; + case 'charset': + $value = self::charset_to_cp($headers->charset); + break; } if (empty($value) || is_array($value)) { @@ -224,8 +180,8 @@ $result$key = $value; } - // $result'ConversationId' = 'FF68022058BD485996BE15F6F6D99320'; - // $result'ConversationIndex' = 'CA2CFA8A23'; +// $result'ConversationId' = 'FF68022058BD485996BE15F6F6D99320'; +// $result'ConversationIndex' = 'CA2CFA8A23'; // Read flag $result'read' = intval(!empty($headers->flags'SEEN')); @@ -233,10 +189,10 @@ // Flagged message if (!empty($headers->flags'FLAGGED')) { // Use FollowUp flag which is used in Android when message is marked with a star - $result'flag' = new Syncroton_Model_EmailFlag( + $result'flag' = new Syncroton_Model_EmailFlag(array( 'flagType' => 'FollowUp', 'status' => Syncroton_Model_EmailFlag::STATUS_ACTIVE, - ); + )); } else { $result'flag' = new Syncroton_Model_EmailFlag(); } @@ -245,17 +201,10 @@ if ($headers->priority) { if ($headers->priority < 3) { $result'importance' = 2; // High - } elseif ($headers->priority > 3) { - $result'importance' = 0; // Low } - } - - // Categories (Tags) - $result'categories' = $headers->others'categories' ?? ; - - //The body never changes, so make sure we don't re-send it to the client on a change - if ($collection->options'_changesOnly' ?? false) { - return new Syncroton_Model_Email($result); + else if ($headers->priority > 3) { + $result'importance' = 0; // Low + } } // get truncation and body type @@ -269,42 +218,44 @@ if (isset($prefsSyncroton_Command_Sync::BODY_TYPE_MIME'truncationSize')) { $truncateAt = $prefsSyncroton_Command_Sync::BODY_TYPE_MIME'truncationSize'; - } elseif (isset($opts'mimeTruncation') && $opts'mimeTruncation' < Syncroton_Command_Sync::TRUNCATE_NOTHING) { + } + else if (isset($opts'mimeTruncation') && $opts'mimeTruncation' < Syncroton_Command_Sync::TRUNCATE_NOTHING) { switch ($opts'mimeTruncation') { - case Syncroton_Command_Sync::TRUNCATE_ALL: - $truncateAt = 0; - break; - case Syncroton_Command_Sync::TRUNCATE_4096: - $truncateAt = 4096; - break; - case Syncroton_Command_Sync::TRUNCATE_5120: - $truncateAt = 5120; - break; - case Syncroton_Command_Sync::TRUNCATE_7168: - $truncateAt = 7168; - break; - case Syncroton_Command_Sync::TRUNCATE_10240: - $truncateAt = 10240; - break; - case Syncroton_Command_Sync::TRUNCATE_20480: - $truncateAt = 20480; - break; - case Syncroton_Command_Sync::TRUNCATE_51200: - $truncateAt = 51200; - break; - case Syncroton_Command_Sync::TRUNCATE_102400: - $truncateAt = 102400; - break; + case Syncroton_Command_Sync::TRUNCATE_ALL: + $truncateAt = 0; + break; + case Syncroton_Command_Sync::TRUNCATE_4096: + $truncateAt = 4096; + break; + case Syncroton_Command_Sync::TRUNCATE_5120: + $truncateAt = 5120; + break; + case Syncroton_Command_Sync::TRUNCATE_7168: + $truncateAt = 7168; + break; + case Syncroton_Command_Sync::TRUNCATE_10240: + $truncateAt = 10240; + break; + case Syncroton_Command_Sync::TRUNCATE_20480: + $truncateAt = 20480; + break; + case Syncroton_Command_Sync::TRUNCATE_51200: + $truncateAt = 51200; + break; + case Syncroton_Command_Sync::TRUNCATE_102400: + $truncateAt = 102400; + break; } } - } else { + } + else { // The spec is not very clear, but it looks that if MimeSupport is not set // we can't add Syncroton_Command_Sync::BODY_TYPE_MIME to the supported types // list below (Bug #1688) - $types = + $types = array( Syncroton_Command_Sync::BODY_TYPE_HTML, Syncroton_Command_Sync::BODY_TYPE_PLAIN_TEXT, - ; + ); // @TODO: if client can support both HTML and TEXT use one of // them which is better according to the real message body type @@ -315,7 +266,7 @@ $truncateAt = $prefs$type'truncationSize'; } - $preview = (int) ($prefs$type'preview' ?? 0); + $preview = (int) $prefs$type'preview'; $airSyncBaseType = $type; break; @@ -323,20 +274,20 @@ } } - $body_params = 'type' => $airSyncBaseType; + $body_params = array('type' => $airSyncBaseType); // Message body // In Sync examples there's one in which bodyPreferences is not defined // in such case Truncated=1 and there's no body sent to the client // only it's estimated size - $isTruncated = 0; if (empty($prefs)) { $messageBody = ''; $real_length = $headers->size; $truncateAt = 0; $body_length = 0; $isTruncated = 1; - } elseif ($airSyncBaseType == Syncroton_Command_Sync::BODY_TYPE_MIME) { + } + else if ($airSyncBaseType == Syncroton_Command_Sync::BODY_TYPE_MIME) { // Check if we have enough memory to handle the message $messageBody = $this->message_mem_check($message, $headers->size); static::$memory_accumulated += $headers->size; @@ -351,7 +302,8 @@ // strip out any non utf-8 characters $messageBody = rcube_charset::clean($messageBody); $real_length = $body_length = strlen($messageBody); - } else { + } + else { $messageBody = $this->getMessageBody($message, $airSyncBaseType == Syncroton_Command_Sync::BODY_TYPE_HTML); // strip out any non utf-8 characters $messageBody = rcube_charset::clean($messageBody); @@ -383,143 +335,33 @@ $result'nativeBodyType' = $message->has_html_part() ? 2 : 1; // Message class - $result'messageClass' = 'IPM.Note'; - $result'contentClass' = 'urn:content-classes:message'; - if ($headers->ctype == 'multipart/signed' - && !empty($message->parts1) - && $message->parts1->mimetype == 'application/pkcs7-signature' + && count($message->attachments) == 1 && $message->attachments0->mimetype == 'application/pkcs7-signature' ) { $result'messageClass' = 'IPM.Note.SMIME.MultipartSigned'; - } elseif ($headers->ctype == 'application/pkcs7-mime' || $headers->ctype == 'application/x-pkcs7-mime') { + } + else if ($headers->ctype == 'application/pkcs7-mime' || $headers->ctype == 'application/x-pkcs7-mime') { $result'messageClass' = 'IPM.Note.SMIME'; - } elseif ($event = $this->get_invitation_event_from_message($message)) { - // Note: Depending on MessageClass a client will display a proper set of buttons - // Either Accept/Maybe/Decline (REQUEST), or "Remove from Calendar" (CANCEL) or none (REPLY). - $result'messageClass' = 'IPM.Schedule.Meeting.Request'; - $result'contentClass' = 'urn:content-classes:calendarmessage'; - - $meeting = ; - - $meeting'allDayEvent' = $event'allday' ?? null ? 1 : 0; - $meeting'startTime' = self::date_from_kolab($event'start'); - $meeting'dtStamp' = self::date_from_kolab($event'dtstamp' ?? null); - $meeting'endTime' = self::date_from_kolab($event'end' ?? null); - $meeting'location' = $event'location' ?? null; - $meeting'instanceType' = Syncroton_Model_EmailMeetingRequest::TYPE_NORMAL; - - if (!empty($event'recurrence_date')) { - $meeting'recurrenceId' = self::date_from_kolab($event'recurrence_date'); - if (!empty($event'status') && $event'status' == 'CANCELLED') { - $meeting'instanceType' = Syncroton_Model_EmailMeetingRequest::TYPE_RECURRING_EXCEPTION; - } else { - $meeting'instanceType' = Syncroton_Model_EmailMeetingRequest::TYPE_RECURRING_SINGLE; - } - } elseif (!empty($event'recurrence')) { - $meeting'instanceType' = Syncroton_Model_EmailMeetingRequest::TYPE_RECURRING_MASTER; - // TODO: MeetingRequest recurrence is different that the one in Calendar - // $this->recurrence_from_kolab($collection, $event, $meeting); - } - - // Organizer - if (!empty($event'attendees')) { - foreach ($event'attendees' as $attendee) { - if (!empty($attendee'role') && $attendee'role' == 'ORGANIZER' && !empty($attendee'email')) { - $meeting'organizer' = $attendee'email'; - break; - } - } - } - - // Current time as a number of 100-nanosecond units since 1601-01-01 - $fileTime = ($event'start'->getTimestamp() + 11644473600) * 10000000; - - // Kolab Format 3.0 and xCal does support timezone per-date, but ActiveSync allows - // only one timezone per-event. We'll use timezone of the start date - $meeting'timeZone' = kolab_sync_timezone_converter::encodeTimezoneFromDate($event'start'); - $meeting'globalObjId' = self::encodeGlobalObjId( - 'uid' => $event'uid', - 'year' => intval($event'start'->format('Y')), - 'month' => intval($event'start'->format('n')), - 'day' => intval($event'start'->format('j')), - 'now' => $fileTime, - ); - - if ($event'_method' == 'REQUEST') { - $meeting'meetingMessageType' = Syncroton_Model_EmailMeetingRequest::MESSAGE_TYPE_REQUEST; - - // Some clients (iOS) without this flag do not send the invitation reply to the organizer. - // Note: Microsoft says "the value of the ResponseRequested element comes from the PARTSTAT - // parameter value of "NEEDS-ACTION" in the request". I think it is safe to do this for all requests. - // Note: This does not have impact on the existence of Accept/Decline buttons in the client. - $meeting'responseRequested' = 1; - } else { // REPLY or CANCEL - $meeting'meetingMessageType' = Syncroton_Model_EmailMeetingRequest::MESSAGE_TYPE_NORMAL; - $itip_processing = kolab_sync::get_instance()->config->get('activesync_itip_processing'); - $attendeeStatus = null; - - if ($itip_processing && empty($headers->flags'SEEN')) { - // Optionally process the message and update the event in recipient's calendar - // Warning: Only for development purposes, for now it's better to use wallace - $calendar_class = new kolab_sync_data_calendar($this->device, $this->syncTimeStamp); - $attendeeStatus = $calendar_class->processItipReply($event); - } elseif ($event'_method' == 'CANCEL') { - $attendeeStatus = kolab_sync_data_calendar::ITIP_CANCELLED; - } elseif (!empty($event'attendees')) { - // Get the attendee/status in the REPLY - foreach ($event'attendees' as $attendee) { - if (empty($attendee'role') || $attendee'role' != 'ORGANIZER') { - if (!empty($attendee'email') && !empty($attendee'status')) { - // Per iTip spec. there should be only one (non-organizer) attendee here - // FIXME: Verify is it realy the case with e.g. Kolab webmail, If not, we should - // probably use the message sender from the From: header - $attendeeStatus = strtoupper($attendee'status'); - break; - } - } - } - } - - switch ($attendeeStatus) { - case kolab_sync_data_calendar::ITIP_CANCELLED: - $result'messageClass' = 'IPM.Schedule.Meeting.Canceled'; - break; - case kolab_sync_data_calendar::ITIP_DECLINED: - $result'messageClass' = 'IPM.Schedule.Meeting.Resp.Neg'; - break; - case kolab_sync_data_calendar::ITIP_TENTATIVE: - $result'messageClass' = 'IPM.Schedule.Meeting.Resp.Tent'; - break; - case kolab_sync_data_calendar::ITIP_ACCEPTED: - $result'messageClass' = 'IPM.Schedule.Meeting.Resp.Pos'; - break; - default: - $skipRequest = true; - } - } + } + else { + $result'messageClass' = 'IPM.Note'; + } - // New time proposals aren't supported by Kolab. - // This disables the UI elements related to this on the client side - $meeting'disallowNewTimeProposal' = 1; + $result'contentClass' = 'urn:content-classes:message'; - if (empty($skipRequest)) { - $result'meetingRequest' = new Syncroton_Model_EmailMeetingRequest($meeting); - } + // Categories (Tags) + if ($this->tag_categories) { + // convert kolab tags into categories + $result'categories' = $this->getKolabTags($message); } - $is_ios = preg_match('/(iphone|ipad)/i', $this->device->devicetype); - // attachments $attachments = array_merge($message->attachments, $message->inline_parts); if (!empty($attachments)) { - $result'attachments' = ; + $result'attachments' = array(); foreach ($attachments as $attachment) { - $att = ; - - if ($is_ios && !empty($event) && $attachment->mime_id == $event'_mime_id') { - continue; - } + $att = array(); $filename = rcube_charset::clean($attachment->filename); if (empty($filename) && $attachment->mimetype == 'text/html') { @@ -559,26 +401,25 @@ */ public function getSearchEntry($longId, $options) { - $collection = new Syncroton_Model_SyncCollection( + $collection = new Syncroton_Model_SyncCollection(array( 'options' => $options, - ); + )); return $this->getEntry($collection, $longId); } /** - * convert email from xml to libkolab array + * convert contact from xml to libkolab array * - * @param Syncroton_Model_Email $data Email to convert - * @param string $folderid Folder identifier - * @param array $entry Existing entry + * @param Syncroton_Model_IEntry $data Contact to convert + * @param string $folderid Folder identifier + * @param array $entry Existing entry * * @return array */ - public function toKolab($data, $folderid, $entry = null) + public function toKolab(Syncroton_Model_IEntry $data, $folderid, $entry = null) { // does nothing => you can't add emails via ActiveSync - return ; } /** @@ -586,28 +427,28 @@ * * @param int $filter_type Filter type * - * @return array Filter query + * @param array Filter query */ protected function filter($filter_type = 0) { - $filter = ; + $filter = array(); switch ($filter_type) { - case Syncroton_Command_Sync::FILTER_1_DAY_BACK: - $mod = '-1 day'; - break; - case Syncroton_Command_Sync::FILTER_3_DAYS_BACK: - $mod = '-3 days'; - break; - case Syncroton_Command_Sync::FILTER_1_WEEK_BACK: - $mod = '-1 week'; - break; - case Syncroton_Command_Sync::FILTER_2_WEEKS_BACK: - $mod = '-2 weeks'; - break; - case Syncroton_Command_Sync::FILTER_1_MONTH_BACK: - $mod = '-1 month'; - break; + case Syncroton_Command_Sync::FILTER_1_DAY_BACK: + $mod = '-1 day'; + break; + case Syncroton_Command_Sync::FILTER_3_DAYS_BACK: + $mod = '-3 days'; + break; + case Syncroton_Command_Sync::FILTER_1_WEEK_BACK: + $mod = '-1 week'; + break; + case Syncroton_Command_Sync::FILTER_2_WEEKS_BACK: + $mod = '-2 weeks'; + break; + case Syncroton_Command_Sync::FILTER_1_MONTH_BACK: + $mod = '-1 month'; + break; } if (!empty($mod)) { @@ -636,18 +477,18 @@ // device doesn't support multiple folders if (!$this->isMultiFolder()) { // We'll return max. one folder of supported type - $result = ; + $result = array(); $types = $this->folder_types; foreach ($list as $idx => $folder) { $type = $folder'type' == 12 ? 2 : $folder'type'; // unknown to Inbox if ($folder_id = $types$type) { - $result$folder_id = + $result$folder_id = array( 'displayName' => $folder_id, 'serverId' => $folder_id, 'parentId' => 0, 'type' => $type, - ; + ); } } @@ -664,17 +505,15 @@ /** * Return list of folders for specified folder ID * - * @param string $folder_id Folder identifier - * * @return array Folder identifiers list */ protected function extractFolders($folder_id) { $list = $this->listFolders(); - $result = ; + $result = array(); if (!is_array($list)) { - throw new Syncroton_Exception_NotFound("Folder $folder_id not found: no folders available"); + throw new Syncroton_Exception_NotFound('Folder not found'); } // device supports multiple folders? @@ -682,7 +521,8 @@ if ($list$folder_id) { $result = $folder_id; } - } elseif ($type = array_search($folder_id, $this->folder_types)) { + } + else if ($type = array_search($folder_id, $this->folder_types)) { foreach ($list as $id => $folder) { if ($folder'type' == $type || ($folder_id == 'Inbox' && $folder'type' == 12)) { $result = $id; @@ -691,7 +531,7 @@ } if (empty($result)) { - throw new Syncroton_Exception_NotFound("Folder $folder_id not found."); + throw new Syncroton_Exception_NotFound('Folder not found'); } return $result; @@ -709,38 +549,44 @@ */ public function moveItem($srcFolderId, $serverId, $dstFolderId) { - $msg = $this->parseMessageId($serverId); - $dest = $this->extractFolders($dstFolderId); - $dest_id = array_shift($dest); + $msg = $this->parseMessageId($serverId); + $dest = $this->extractFolders($dstFolderId); + $dest_id = array_shift($dest); + $dest_name = $this->backend->folder_id2name($dest_id, $this->device->deviceid); if (empty($msg)) { throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE); } - $uid = $this->backend->moveItem($msg'folderId', $this->device->deviceid, $this->modelName, $msg'uid', $dest_id); + if ($dest_name === null) { + throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_DESTINATION); + } - return $uid ? $this->serverId($uid, $dest_id) : null; + if (!$this->storage->move_message($msg'uid', $dest_name, $msg'foldername')) { + throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE); + } + + // Use COPYUID feature (RFC2359) to get the new UID of the copied message + $copyuid = $this->storage->conn->data'COPYUID'; + + if (is_array($copyuid) && ($uid = $copyuid1)) { + return $this->createMessageId($dest_id, $uid); + } } /** * add entry from xml data * - * @param string $folderId Folder identifier - * @param Syncroton_Model_Email $entry Entry + * @param string $folderId Folder identifier + * @param Syncroton_Model_IEntry $entry Entry * - * @return string ID of the created entry + * @return array */ public function createEntry($folderId, Syncroton_Model_IEntry $entry) { - $params = 'flags' => !empty($entry->read) ? 'SEEN' : 'UNSEEN'; - - $uid = $this->backend->createItem($folderId, $this->device->deviceid, $this->modelName, $entry->body->data, $params); - - if (!$uid) { - throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); - } - - return $this->serverId($uid, $folderId); + // Throw exception here for better handling of unsupported + // entry creation, it can be object of class Email or SMS here + throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::INVALID_ITEM); } /** @@ -752,45 +598,48 @@ */ public function updateEntry($folderId, $serverId, Syncroton_Model_IEntry $entry) { - $msg = $this->parseMessageId($serverId); + $msg = $this->parseMessageId($serverId); + $message = $this->getObject($serverId); - if (empty($msg)) { + if (empty($message)) { throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); } - $params = 'flags' => ; - - if (isset($entry->categories)) { - $params'categories' = $entry->categories; - } + $is_flagged = !empty($message->headers->flags'FLAGGED'); // Read status change if (isset($entry->read)) { - $params'flags' = !empty($entry->read) ? 'SEEN' : 'UNSEEN'; + // here we update only Read flag + $flag = (((int)$entry->read != 1) ? 'UN' : '') . 'SEEN'; + $this->storage->set_flag($msg'uid', $flag, $msg'foldername'); } // Flag change - if (isset($entry->flag)) { - if (empty($entry->flag) || empty($entry->flag->flagType)) { - $params'flags' = 'UNFLAGGED'; - } elseif (preg_match('/follow\s*up/i', $entry->flag->flagType)) { - $params'flags' = 'FLAGGED'; + if (isset($entry->flag) && (empty($entry->flag) || empty($entry->flag->flagType))) { + if ($is_flagged) { + $this->storage->set_flag($msg'uid', 'UNFLAGGED', $msg'foldername'); + } + } + else if (!$is_flagged && !empty($entry->flag)) { + if ($entry->flag->flagType && preg_match('/follow\s*up/i', $entry->flag->flagType)) { + $this->storage->set_flag($msg'uid', 'FLAGGED', $msg'foldername'); } } - $this->backend->updateItem($msg'folderId', $this->device->deviceid, $this->modelName, $msg'uid', null, $params); - - return $serverId; + // Categories (Tags) change + if (isset($entry->categories)) { + $this->setKolabTags($message, $entry->categories); + } } /** - * Delete an email (or move to Trash) + * delete entry * - * @param string $folderId - * @param string $serverId - * @param ?Syncroton_Model_SyncCollection $collection + * @param string $folderId + * @param string $serverId + * @param Syncroton_Model_SyncCollection $collection */ - public function deleteEntry($folderId, $serverId, $collection = null) + public function deleteEntry($folderId, $serverId, $collection) { $trash = kolab_sync::get_instance()->config->get('trash_mbox'); $msg = $this->parseMessageId($serverId); @@ -799,13 +648,17 @@ throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); } - // Note: If DeletesAsMoves is not specified in the request, its default is 1 (true). - $moveToTrash = !isset($collection->deletesAsMoves) || !empty($collection->deletesAsMoves); - - $deleted = $this->backend->deleteItem($msg'folderId', $this->device->deviceid, $this->modelName, $msg'uid', $moveToTrash); - - if (!$deleted) { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); + // move message to trash folder + if ($collection->deletesAsMoves + && strlen($trash) + && $trash != $msg'foldername' + && $this->storage->folder_exists($trash) + ) { + $this->storage->move_message($msg'uid', $trash, $msg'foldername'); + } + // set delete flag + else { + $this->storage->set_flag($msg'uid', 'DELETED', $msg'foldername'); } } @@ -834,7 +687,7 @@ $sent_folder = kolab_sync::get_instance()->config->get('sent_mbox'); if (strlen($sent_folder) && $this->storage->folder_exists($sent_folder)) { - return $this->storage->save_message($sent_folder, $message->source(), '', false, 'SEEN'); + return $this->storage->save_message($sent_folder, $message->source(), '', false, array('SEEN')); } } } @@ -877,19 +730,19 @@ // forward original message as attachment if (!$replaceMime) { - $this->storage->set_folder($message->folder); + $this->storage->set_folder($msg'foldername'); $attachment = $this->storage->get_raw_body($msg'uid'); if (empty($attachment)) { throw new Syncroton_Exception_Status(Syncroton_Exception_Status::ITEM_NOT_FOUND); } - $sync_msg->add_attachment($attachment, + $sync_msg->add_attachment($attachment, array( 'encoding' => '8bit', 'content_type' => 'message/rfc822', 'disposition' => 'inline', //'name' => 'message.eml', - ); + )); } // Send message @@ -897,8 +750,7 @@ // Set FORWARDED flag on the replied message if (empty($message->headers->flags'FORWARDED')) { - $params = 'flags' => 'FORWARDED'; - $this->backend->updateItem($msg'folderId', $this->device->deviceid, $this->modelName, $msg'uid', null, $params); + $this->storage->set_flag($msg'uid', 'FORWARDED', $msg'foldername'); } } @@ -948,12 +800,247 @@ // Set ANSWERED flag on the replied message if (empty($message->headers->flags'ANSWERED')) { - $params = 'flags' => 'ANSWERED'; - $this->backend->updateItem($msg'folderId', $this->device->deviceid, $this->modelName, $msg'uid', null, $params); + $this->storage->set_flag($msg'uid', 'ANSWERED', $msg'foldername'); } } /** + * Search for existing entries + * + * @param string $folderid + * @param array $filter + * @param int $result_type Type of the result (see RESULT_* constants) + * + * @return array|int Search result as count or array of uids/objects + */ + protected function searchEntries($folderid, $filter = array(), $result_type = self::RESULT_UID) + { + $folders = $this->extractFolders($folderid); + $filter_str = 'ALL UNDELETED'; + + // convert filter into one IMAP search string + foreach ($filter as $idx => $filter_item) { + if (is_array($filter_item)) { + // This is a request for changes since last time + // we'll use HIGHESTMODSEQ value from the last Sync + if ($filter_item0 == 'changed' && $filter_item1 == '>') { + $modseq_lasttime = $filter_item2; + $modseq_data = array(); + $modseq = (array) $this->backend->modseq_get($this->device->id, $folderid, $modseq_lasttime); + } + } + else { + $filter_str .= ' ' . $filter_item; + } + } + + // get members of modified relations + $changed_msgs = $this->getChangesByRelations($folderid, $filter); + + $result = $result_type == self::RESULT_COUNT ? 0 : array(); + $found = 0; + $ts = time(); + + foreach ($folders as $folder_id) { + $foldername = $this->backend->folder_id2name($folder_id, $this->device->deviceid); + + if ($foldername === null) { + continue; + } + + $found++; + + $this->storage->set_folder($foldername); + + // Synchronize folder (if it wasn't synced in this request already) + if ($this->lastsync_folder != $folderid + || $this->lastsync_time <= $ts - Syncroton_Registry::getPingTimeout() + ) { + $this->storage->folder_sync($foldername); + } + + // We're in "get changes" mode + if (isset($modseq_data)) { + $folder_data = $this->storage->folder_data($foldername); + $modified = false; + + // If previous HIGHESTMODSEQ doesn't exist we can't get changes + // We can only get folder's HIGHESTMODSEQ value and store it for the next try + // Skip search if HIGHESTMODSEQ didn't change + if ($folder_data'HIGHESTMODSEQ') { + $modseq_data$foldername = $folder_data'HIGHESTMODSEQ'; + if ($modseq_data$foldername != $modseq$foldername) { + $modseq_update = true; + if ($modseq && $modseq$foldername) { + $modified = true; + $filter_str .= " MODSEQ " . ($modseq$foldername + 1); + } + } + } + } + else { + $modified = true; + } + + // We could use messages cache by replacing search() with index() + // in some cases. This however is possible only if user has skip_deleted=true, + // in his Roundcube preferences, otherwise we'd make often cache re-initialization, + // because Roundcube message cache can work only with one skip_deleted + // setting at a time. We'd also need to make sure folder_sync() was called + // before (see above). + // + // if ($filter_str == 'ALL UNDELETED') + // $search = $this->storage->index($foldername, null, null, true, true); + // else + + if ($modified) { + $search = $this->storage->search_once($foldername, $filter_str); + + if (!($search instanceof rcube_result_index) || $search->is_error()) { + throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); + } + + switch ($result_type) { + case self::RESULT_COUNT: + $result += (int) $search->count(); + break; + + case self::RESULT_UID: + if ($uids = $search->get()) { + foreach ($uids as $idx => $uid) { + $uids$idx = $this->createMessageId($folder_id, $uid); + } + $result = array_merge($result, $uids); + } + break; + } + } + + // handle relation changes + if (!empty($changed_msgs)) { + $uids = $this->findRelationMembersInFolder($foldername, $changed_msgs, $filter); + + switch ($result_type) { + case self::RESULT_COUNT: + $result += (int) count($uids); + break; + + case self::RESULT_UID: + foreach ($uids as $idx => $uid) { + $uids$idx = $this->createMessageId($folder_id, $uid); + } + $result = array_unique(array_merge($result, $uids)); + break; + } + } + } + + if (!$found) { + throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); + } + + $this->lastsync_folder = $folderid; + $this->lastsync_time = $ts; + + if (!empty($modseq_update)) { + $this->backend->modseq_set($this->device->id, $folderid, + $this->syncTimeStamp, $modseq_data); + + // if previous modseq information does not exist save current set as it, + // we would at least be able to detect changes since now + if (empty($result) && empty($modseq)) { + $this->backend->modseq_set($this->device->id, $folderid, + $modseq_lasttime, $modseq_data); + } + } + + return $result; + } + + /** + * Find members (messages) in specified folder + */ + protected function findRelationMembersInFolder($foldername, $members, $filter) + { + foreach ($members as $member) { + // IMAP URI members + if ($url = kolab_storage_config::parse_member_url($member)) { + $result$url'folder'$url'uid' = $url'params'; + } + } + + // convert filter into one IMAP search string + $filter_str = 'ALL UNDELETED'; + foreach ($filter as $filter_item) { + if (is_string($filter_item)) { + $filter_str .= ' ' . $filter_item; + } + } + + $rcube = rcube::get_instance(); + $storage = $rcube->get_storage(); + $found = array(); + + // first find messages by UID + if (!empty($result$foldername)) { + $index = $storage->search_once($foldername, 'UID ' + . rcube_imap_generic::compressMessageSet(array_keys($result$foldername))); + $found = $index->get(); + + // remove found messages from the $result + if (!empty($found)) { + $result$foldername = array_diff_key($result$foldername, array_flip($found)); + + if (empty($result$foldername)) { + unset($result$foldername); + } + + // now apply the current filter to the found messages + $index = $storage->search_once($foldername, $filter_str . ' UID ' + . rcube_imap_generic::compressMessageSet($found)); + $found = $index->get(); + } + } + + // search by message parameters + if (!empty($result)) { + // @TODO: do this search in chunks (for e.g. 25 messages)? + $search = ''; + $search_count = 0; + + foreach ($result as $data) { + foreach ($data as $p) { + $search_params = array(); + $search_count++; + + foreach ($p as $key => $val) { + $key = strtoupper($key); + // don't search by subject, we don't want false-positives + if ($key != 'SUBJECT') { + $search_params = 'HEADER ' . $key . ' ' . rcube_imap_generic::escape($val); + } + } + + $search .= ' (' . implode(' ', $search_params) . ')'; + } + } + + $search_str .= ' ' . str_repeat(' OR', $search_count-1) . $search; + + // search messages in current folder + $search = $storage->search_once($foldername, $search_str); + $uids = $search->get(); + + if (!empty($uids)) { + // add UIDs into the result + $found = array_unique(array_merge($found, $uids)); + } + } + + return $found; + } + + /** * ActiveSync Search handler * * @param Syncroton_Model_StoreRequest $store Search query @@ -962,7 +1049,7 @@ */ public function search(Syncroton_Model_StoreRequest $store) { - $folders, $search_str = $this->parse_search_query($store); + list($folders, $search_str) = $this->parse_search_query($store); if (empty($search_str)) { throw new Exception('Empty/invalid search request'); @@ -972,7 +1059,7 @@ throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); } - $result = ; + $result = array(); // @TODO: caching with Options->RebuildResults support @@ -983,8 +1070,8 @@ continue; } - // $this->storage->set_folder($foldername); - // $this->storage->folder_sync($foldername); +// $this->storage->set_folder($foldername); +// $this->storage->folder_sync($foldername); $search = $this->storage->search_once($foldername, $search_str); @@ -992,14 +1079,13 @@ continue; } - $search->revert(); $uids = $search->get(); foreach ($uids as $idx => $uid) { - $uids$idx = new Syncroton_Model_StoreResponseResult( - 'longId' => $this->serverId($uid, $folderid), + $uids$idx = new Syncroton_Model_StoreResponseResult(array( + 'longId' => $this->createMessageId($folderid, $uid), 'collectionId' => $folderid, 'class' => 'Email', - ); + )); } $result = array_merge($result, $uids); @@ -1024,13 +1110,13 @@ $start = $total; } if ($limit > $total) { - $limit = max($start + 1, $total); + $limit = max($start+1, $total); } if ($start > 0 || $limit < $total) { - $result = array_slice($result, $start, $limit - $start); + $result = array_slice($result, $start, $limit-$start); } - $response->range = $start, $start + count($result) - 1; + $response->range = array($start, $start + count($result) - 1); } // Build result array, convert to ActiveSync format @@ -1051,10 +1137,14 @@ $options = $store->options; $query = $store->query; $search_str = ''; - $folders = ; + $folders = array(); if (empty($query) || !is_array($query)) { - return ; + return array(); + } + + if (isset($query'and''freeText') && strlen($query'and''freeText')) { + $search = $query'and''freeText'; } if (!empty($query'and''collections')) { @@ -1077,19 +1167,18 @@ $search_str .= ' BEFORE ' . $query'and''lessThan''value'->format('d-M-Y'); } - if (isset($query'and''freeText') && strlen($query'and''freeText')) { - // @FIXME: Should we use TEXT/BODY search? ActiveSync protocol specification says "indexed fields" - $search = $query'and''freeText'; - $search_keys = 'SUBJECT', 'TO', 'FROM', 'CC'; - $search_str .= str_repeat(' OR', count($search_keys) - 1); - + if ($search !== null) { + // @FIXME: should we use TEXT/BODY search? + // ActiveSync protocol specification says "indexed fields" + $search_keys = array('SUBJECT', 'TO', 'FROM', 'CC'); + $search_str .= str_repeat(' OR', count($search_keys)-1); foreach ($search_keys as $key) { $search_str .= sprintf(" %s {%d}\r\n%s", $key, strlen($search), $search); } } - if (!strlen($search_str)) { - return ; + if (empty($search_str)) { + return array(); } $search_str = 'ALL UNDELETED ' . trim($search_str); @@ -1105,13 +1194,13 @@ $folders = array_keys($folders); } - return $folders, $search_str; + return array($folders, $search_str); } /** * Fetches the entry from the backend */ - protected function getObject($entryid, $dummy = null) + protected function getObject($entryid, $dummy = null, &$folder = null) { $message = $this->parseMessageId($entryid); @@ -1120,33 +1209,32 @@ return null; } - return $this->backend->getItem($message'folderId', $this->device->deviceid, $this->modelName, $message'uid'); + // get message + $message = new rcube_message($message'uid', $message'foldername'); + + return $message && !empty($message->headers) ? $message : null; } /** - * Get attachment data from the server. - * - * @param string $fileReference - * * @return Syncroton_Model_FileReference */ public function getFileReference($fileReference) { - $folderid, $uid, $part_id = explode('::', $fileReference); + list($folderid, $uid, $part_id) = explode('::', $fileReference); $message = $this->getObject($fileReference); if (!$message) { - throw new Syncroton_Exception_NotFound("Message $fileReference not found"); + throw new Syncroton_Exception_NotFound('Message not found'); } $part = $message->mime_parts$part_id; $body = $message->get_part_body($part_id); - return new Syncroton_Model_FileReference( + return new Syncroton_Model_FileReference(array( 'contentType' => $part->mimetype, 'data' => $body, - ); + )); } /** @@ -1159,32 +1247,36 @@ $entryid = $entryid'itemId'; } - if (!is_string($entryid) || !strpos($entryid, '::')) { + // Note: the id might be in a form of <folder>::<uid>::<part_id> + list($folderid, $uid) = explode('::', $entryid); + + if (empty($uid)) { return; } - // Note: the id might be in a form of <folder>::<uid>::<part_id> - $folderid, $uid = explode('::', $entryid); + $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid); - return - 'uid' => $uid, - 'folderId' => $folderid, - ; + if ($foldername === null || $foldername === false) { + return; + } + + return array( + 'uid' => $uid, + 'folderid' => $folderid, + 'foldername' => $foldername, + ); } /** * Creates entry ID of the message */ - protected function serverId($uid, $folderid) + public function createMessageId($folderid, $uid) { return $folderid . '::' . $uid; } /** * Returns body of the message in specified format - * - * @param rcube_message $message - * @param bool $html */ protected function getMessageBody($message, $html = false) { @@ -1208,18 +1300,9 @@ /** * Returns body of the message part in specified format - * - * @param rcube_message $message - * @param rcube_message_part $part - * @param bool $html */ protected function getMessagePartBody($message, $part, $html = false) { - if (empty($part->size) || empty($part->mime_id)) { - // TODO: Throw an exception? - return ''; - } - // Check if we have enough memory to handle the message in it $body = $this->message_mem_check($message, $part->size, false); @@ -1232,49 +1315,49 @@ return ''; } - $ctype_secondary = !empty($part->ctype_secondary) ? $part->ctype_secondary : null; - if ($html) { - if ($ctype_secondary == 'html') { + if ($part->ctype_secondary == 'html') { // charset was converted to UTF-8 in rcube_storage::get_message_part(), // change/add charset specification in HTML accordingly - $meta = '<meta http-equiv="Content-Type" content="text/html; charset=' . RCUBE_CHARSET . '" />'; + $meta = '<meta http-equiv="Content-Type" content="text/html; charset='.RCUBE_CHARSET.'" />'; // remove old meta tag and add the new one, making sure // that it is placed in the head $body = preg_replace('/<meta^>+charset=a-z0-9-_+^>*>/Ui', '', $body); - $body = preg_replace('/(<head^>*>)/Ui', '\\1' . $meta, $body, -1, $rcount); + $body = preg_replace('/(<head^>*>)/Ui', '\\1'.$meta, $body, -1, $rcount); if (!$rcount) { $body = '<head>' . $meta . '</head>' . $body; } - } elseif ($ctype_secondary == 'enriched') { + } + else if ($part->ctype_secondary == 'enriched') { $body = rcube_enriched::to_html($body); - } else { + } + else { // Roundcube >= 1.2 if (class_exists('rcube_text2html')) { - $flowed = isset($part->ctype_parameters'format') && $part->ctype_parameters'format' == 'flowed'; - $delsp = isset($part->ctype_parameters'delsp') && $part->ctype_parameters'delsp' == 'yes'; - $options = 'flowed' => $flowed, 'wrap' => false, 'delsp' => $delsp; + $flowed = $part->ctype_parameters'format' == 'flowed'; + $delsp = $part->ctype_parameters'delsp' == 'yes'; + $options = array('flowed' => $flowed, 'wrap' => false, 'delsp' => $delsp); $text2html = new rcube_text2html($body, false, $options); $body = '<html><body>' . $text2html->get_html() . '</body></html>'; - } else { + } + else { $body = '<html><body><pre>' . $body . '</pre></body></html>'; } } - } else { - if ($ctype_secondary == 'enriched') { + } + else { + if ($part->ctype_secondary == 'enriched') { $body = rcube_enriched::to_html($body); $part->ctype_secondary = 'html'; } - if ($ctype_secondary == 'html') { + if ($part->ctype_secondary == 'html') { $txt = new rcube_html2text($body, false, true); $body = $txt->get_text(); - } else { - if ($ctype_secondary == 'plain' - && !empty($part->ctype_parameters'format') - && $part->ctype_parameters'format' == 'flowed' - ) { + } + else { + if ($part->ctype_secondary == 'plain' && $part->ctype_parameters'format' == 'flowed') { $body = rcube_mime::unfold_flowed($body); } } @@ -1303,12 +1386,112 @@ return mb_strcut(trim($body), 0, $size); } + /** + * Returns list of tag names assigned to an email message + */ + protected function getKolabTags($message, $dummy = null) + { + // support only messages with message-id + if (!($msg_id = $message->headers->get('message-id', false))) { + return null; + } + + $config = kolab_storage_config::get_instance(); + $delta = Syncroton_Registry::getPingTimeout(); + $folder = $message->folder; + $uid = $message->uid; + + // get tag objects raleted to specified message-id + $tags = $config->get_tags($msg_id); + + foreach ($tags as $idx => $tag) { + // resolve members if it wasn't done recently + $force = empty($this->tag_rts$tag'uid') || $this->tag_rts$tag'uid' <= time() - $delta; + $members = $config->resolve_members($tag, $force); + + if (empty($members$folder) || !in_array($uid, $members$folder)) { + unset($tags$idx); + } + + if ($force) { + $this->tag_rts$tag'uid' = time(); + } + } + + $tags = array_filter(array_map(function($v) { return $v'name'; }, $tags)); + + // make sure current folder is set correctly again + $this->storage->set_folder($folder); + + return !empty($tags) ? $tags : null; + } + + /** + * Set tags to an email message + */ + protected function setKolabTags($message, $tags) + { + $config = kolab_storage_config::get_instance(); + $delta = Syncroton_Registry::getPingTimeout(); + $folder = $message->folder; + $uri = kolab_storage_config::get_message_uri($message->headers, $folder); + + // for all tag objects... + foreach ($config->get_tags() as $relation) { + // resolve members if it wasn't done recently + $uid = $relation'uid'; + $force = empty($this->tag_rts$uid) || $this->tag_rts$uid <= time() - $delta; + + if ($force) { + $config->resolve_members($relation, $force); + $this->tag_rts$tag'uid' = time(); + } + + $selected = !empty($tags) && in_array($relation'name', $tags); + $found = !empty($relation'members') && in_array($uri, $relation'members'); + $update = false; + + // remove member from the relation + if ($found && !$selected) { + $relation'members' = array_diff($relation'members', (array) $uri); + $update = true; + } + // add member to the relation + else if (!$found && $selected) { + $relation'members' = $uri; + $update = true; + } + + if ($update) { + $config->save($relation, 'relation'); + } + + $tags = array_diff($tags, (array) $relation'name'); + } + + // create new relations + if (!empty($tags)) { + foreach ($tags as $tag) { + $relation = array( + 'name' => $tag, + 'members' => (array) $uri, + 'category' => 'tag', + ); + + $config->save($relation, 'relation'); + } + } + + // make sure current folder is set correctly again + $this->storage->set_folder($folder); + } + public static function charset_to_cp($charset) { // @TODO: ????? // The body is converted to utf-8 in get_part_body(), what about headers? return 65001; // UTF-8 - /* + $aliases = array( 'asmo708' => 708, 'shiftjis' => 932, @@ -1411,7 +1594,6 @@ if (preg_match('/^(ibm|dos|cp|windows|win)0-9+/', $charset, $m)) { return substr($charset, strlen($m1) + 1); } - */ } /** @@ -1435,19 +1617,22 @@ foreach ($lines as $line) { // don't wrap already quoted lines - if (isset($line0) && $line0 == '>') { + if ($line0 == '>') { $line = '>' . rtrim($line); - } elseif (mb_strlen($line) > $max) { + } + else if (mb_strlen($line) > $max) { $newline = ''; foreach (explode("\n", rcube_mime::wordwrap($line, $length - 2)) as $l) { if (strlen($l)) { $newline .= '> ' . $l . "\n"; - } else { + } + else { $newline .= ">\n"; } } $line = rtrim($newline); - } else { + } + else { $line = '> ' . $line; } @@ -1461,51 +1646,30 @@ /** * Returns calendar event data from the iTip invitation attached to a mail message */ - public function get_invitation_event_from_message($message) - { - // Parse the message and find iTip attachments - $libcal = libcalendaring::get_instance(); - $libcal->mail_message_load('object' => $message); - $ical_objects = $libcal->get_mail_ical_objects(); - - // Skip methods we do not support here - if (!in_array($ical_objects->method, 'REQUEST', 'CANCEL', 'REPLY')) { - return null; - } - - // We support only one event in the iTip - foreach ($ical_objects as $mime_id => $event) { - if ($event'_type' == 'event') { - $event'_method' = $ical_objects->method; - $event'_mime_id' = $ical_objects->mime_id; - - return $event; - } - } - - return null; - } - - /** - * Returns calendar event data from the iTip invitation attached to a mail message - */ public function get_invitation_event($messageId) { // Get the mail message object if ($message = $this->getObject($messageId)) { - return $this->get_invitation_event_from_message($message); + // Parse the message and find iTip attachments + $libcal = libcalendaring::get_instance(); + $libcal->mail_message_load(array('object' => $message)); + $ical_objects = $libcal->get_mail_ical_objects(); + + // We support only one event in the iTip + foreach ($ical_objects as $mime_id => $event) { + if ($event'_type' == 'event') { + return $event; + } + } } - return null; } private function mem_check($need) { - $mem_limit = (int) parse_bytes(ini_get('memory_limit')); + $mem_limit = parse_bytes(ini_get('memory_limit')); $memory = static::$memory_accumulated; - - // @phpstan-ignore-next-line - return ($mem_limit > 0 && $memory + $need > $mem_limit) ? false : true; + return $mem_limit > 0 && $memory + $need > $mem_limit ? false : true; } /** @@ -1526,7 +1690,7 @@ // If we already rised the memory we throw an exception, so the message // will be synchronized in the next run (then we might have enough memory) if ($memory_rised) { - throw new Syncroton_Exception_MemoryExhausted(); + throw new Syncroton_Exception_MemoryExhausted; } $memory_rised = true; @@ -1540,7 +1704,6 @@ if (ini_set('memory_limit', $memory_needed) !== false) { // Memory has been rised, check again - // @phpstan-ignore-next-line if ($this->mem_check($size * 5)) { return; }
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_data_gal.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_data_gal.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -28,26 +28,26 @@ */ class kolab_sync_data_gal extends kolab_sync_data implements Syncroton_Data_IDataSearch { - public const MAX_SEARCH_RESULT = 100; + const MAX_SEARCH_RESULT = 100; /** * LDAP search result * * @var array */ - protected $result = ; + protected $result = array(); /** * LDAP address books list * * @var array */ - public static $address_books = ; + public static $address_books = array(); /** * Mapping from ActiveSync Contacts namespace fields */ - protected $mapping = + protected $mapping = array( 'alias' => 'nickname', 'company' => 'organization', 'displayName' => 'name', @@ -59,7 +59,7 @@ 'picture' => 'photo', 'phone' => 'phone', 'title' => 'jobtitle', - ; + ); /** * Kolab object type @@ -103,9 +103,8 @@ // Use configured fields mapping $rcube = rcube::get_instance(); $fieldmap = (array) $rcube->config->get('activesync_gal_fieldmap'); - if (!empty($fieldmap)) { - $fieldmap = array_intersect_key($fieldmap, array_keys($this->mapping)); + $fieldmap = array_intersec_key($fieldmap, array_keys($this->mapping)); $this->mapping = array_merge($this->mapping, $fieldmap); } } @@ -113,19 +112,15 @@ /** * Not used but required by parent class */ - public function toKolab($data, $folderId, $entry = null) + public function toKolab(Syncroton_Model_IEntry $data, $folderId, $entry = null) { - return ; } /** * Not used but required by parent class - * - * @return array|Syncroton_Model_Contact Contact object */ public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId) { - throw new Syncroton_Exception_NotFound("getEntry() on GAL is not implemented"); } /** @@ -138,7 +133,7 @@ */ public function getSearchEntry($data, $options) { - $result = ; + $result = array(); // Contacts namespace fields foreach ($this->mapping as $key => $name) { @@ -149,24 +144,24 @@ } switch ($name) { - case 'photo': - // @TODO: MaxPictures option - // ActiveSync limits photo size of GAL contact to 100KB - $maxsize = 102400; - if (!empty($options'picture''maxSize')) { - $maxsize = min($maxsize, $options'picture''maxSize'); - } - - if (strlen($value) > $maxsize) { - continue 2; - } - - $value = new Syncroton_Model_GALPicture( - 'data' => $value, // binary - 'status' => Syncroton_Model_GALPicture::STATUS_SUCCESS, - ); - - break; + case 'photo': + // @TODO: MaxPictures option + // ActiveSync limits photo size of GAL contact to 100KB + $maxsize = 102400; + if (!empty($options'picture''maxSize')) { + $maxsize = min($maxsize, $options'picture''maxSize'); + } + + if (strlen($value) > $maxsize) { + continue 2; + } + + $value = new Syncroton_Model_GALPicture(array( + 'data' => $value, // binary + 'status' => Syncroton_Model_GALPicture::STATUS_SUCCESS, + )); + + break; } $result$key = $value; @@ -193,7 +188,7 @@ throw new Exception('Empty/invalid search request'); } - $records = ; + $records = array(); $rcube = rcube::get_instance(); // @TODO: caching with Options->RebuildResults support @@ -225,7 +220,7 @@ // get records $result = $book->list_records(); - foreach ($result as $row) { + while ($row = $result->next()) { $row'sourceid' = $idx; // make sure 'email' item is there, convert all email:* into one @@ -260,22 +255,22 @@ $start = $total; } if ($limit > $total) { - $limit = max($start + 1, $total); + $limit = max($start+1, $total); } if ($start > 0 || $limit < $total) { - $records = array_slice($records, $start, $limit - $start); + $records = array_slice($records, $start, $limit-$start); } - $response->range = $start, $start + count($records) - 1; + $response->range = array($start, $start + count($records) - 1); } // Build result array, convert to ActiveSync format foreach ($records as $idx => $rec) { - $response->result = new Syncroton_Model_StoreResponseResult( + $response->result = new Syncroton_Model_StoreResponseResult(array( 'longId' => $rec'ID', 'properties' => $this->getSearchEntry($rec, $options), - ); + )); unset($records$idx); } @@ -287,7 +282,7 @@ * * @param string $id Address book identifier * - * @return rcube_addressbook|null Address book object + * @return rcube_contacts Address book object */ public static function get_address_book($id) { @@ -297,31 +292,26 @@ // use existing instance if (isset(self::$address_books$id) && (self::$address_books$id instanceof rcube_addressbook)) { $book = self::$address_books$id; - } elseif ($id && $ldap_config$id) { - $book = new rcube_ldap( - $ldap_config$id, - $config->get('ldap_debug'), - $config->mail_domain($_SESSION'storage_host') - ); + } + else if ($id && $ldap_config$id) { + $book = new rcube_ldap($ldap_config$id, $config->get('ldap_debug'), + $config->mail_domain($_SESSION'storage_host')); } - if (empty($book)) { - rcube::raise_error( - + if (!$book) { + rcube::raise_error(array( 'code' => 700, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Addressbook source ($id) not found!", - true, - false - ); + 'message' => "Addressbook source ($id) not found!"), + true, false); return null; } - /* - // set configured sort order - if ($sort_col = $this->config->get('addressbook_sort_col')) - $book->set_sort_order($sort_col); - */ +/* + // set configured sort order + if ($sort_col = $this->config->get('addressbook_sort_col')) + $book->set_sort_order($sort_col); +*/ // add to the 'books' array for shutdown function self::$address_books$id = $book; @@ -332,7 +322,7 @@ /** * Return LDAP address books list * - * @return array Address books array + * @return array Address books array */ public static function get_address_sources() { @@ -344,15 +334,15 @@ $async_books = (array) $config->get('autocomplete_addressbooks'); } - $list = ; + $list = array(); foreach ((array)$async_books as $id) { $prop = $ldap_config$id; if (!empty($prop) && is_array($prop)) { - $list$id = + $list$id = array( 'id' => $id, 'name' => $prop'name', - ; + ); } } @@ -370,7 +360,8 @@ if (!empty($row'email')) { if (is_array($row'email')) { $key .= ':' . implode(':', $row'email'); - } else { + } + else { $key .= ':' . $row'email'; } } @@ -383,7 +374,7 @@ */ protected function getLDAPDataItem($data, $name) { - $name, $index = explode(':', $name); + list($name, $index) = explode(':', $name); $name = str_replace('.', ':', $name); if (isset($data$name)) {
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_data_notes.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_data_notes.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -31,13 +31,13 @@ /** * Mapping from ActiveSync Calendar namespace fields */ - protected $mapping = + protected $mapping = array( 'body' => 'description', 'categories' => 'categories', 'lastModifiedDate' => 'changed', //'messageClass' => 'messageClass', 'subject' => 'title', - ; + ); /** * Kolab object type @@ -67,6 +67,11 @@ */ protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_NOTE_USER_CREATED; + /** + * Enable mapping Activesync categories into Kolab tags (relations) + */ + protected $tag_categories = true; + /** * Appends note data to xml element @@ -80,20 +85,21 @@ public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId, $as_array = false) { $note = is_array($serverId) ? $serverId : $this->getObject($collection->collectionId, $serverId); - $result = ; +// $config = $this->getFolderConfig($note'_mailbox'); + $result = array(); // Calendar namespace fields foreach ($this->mapping as $key => $name) { $value = $this->getKolabDataItem($note, $name); switch ($name) { - case 'changed': - $value = self::date_from_kolab($value); - break; + case 'changed': + $value = self::date_from_kolab($value); + break; - case 'description': - $value = $this->body_from_kolab($value, $collection); - break; + case 'description': + $value = $this->body_from_kolab($value, $collection); + break; } if (empty($value) || is_array($value)) { @@ -105,39 +111,44 @@ $result'messageClass' = 'IPM.StickyNote'; + // convert kolab tags into categories + $result'categories' = $this->getKolabTags($note'uid', $result'categories'); + return $as_array ? $result : new Syncroton_Model_Note($result); } /** * convert note from xml to libkolab array * - * @param Syncroton_Model_Note $data Note to convert - * @param string $folderid Folder identifier - * @param array $entry Existing entry + * @param Syncroton_Model_IEntry $data Note to convert + * @param string $folderid Folder identifier + * @param array $entry Existing entry * * @return array */ - public function toKolab($data, $folderid, $entry = null) + public function toKolab(Syncroton_Model_IEntry $data, $folderid, $entry = null) { - $note = !empty($entry) ? $entry : ; + $note = !empty($entry) ? $entry : array(); + $foldername = isset($note'_mailbox') ? $note'_mailbox' : $this->getFolderName($folderid); +// $config = $this->getFolderConfig($foldername); // Calendar namespace fields foreach ($this->mapping as $key => $name) { $value = $data->$key; switch ($name) { - case 'description': - $supported_body_types = - Syncroton_Model_EmailBody::TYPE_HTML, - Syncroton_Model_EmailBody::TYPE_PLAINTEXT, - ; - $value = $this->getBody($value, $supported_body_types); - - // If description isn't specified keep old description - if ($value === null) { - continue 2; - } - break; + case 'description': + $supported_body_types = array( + Syncroton_Model_EmailBody::TYPE_HTML, + Syncroton_Model_EmailBody::TYPE_PLAINTEXT, + ); + $value = $this->getBody($value, $supported_body_types); + + // If description isn't specified keep old description + if ($value === null) { + continue 2; + } + break; } $this->setKolabDataItem($note, $name, $value);
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_data_tasks.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_data_tasks.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -31,7 +31,7 @@ /** * Mapping from ActiveSync Calendar namespace fields */ - protected $mapping = + protected $mapping = array( 'body' => 'description', 'categories' => 'categories', //'complete' => 'complete', // handled separately @@ -46,26 +46,26 @@ 'subject' => 'title', 'utcDueDate' => 'due', 'utcStartDate' => 'start', - ; + ); /** * Sensitivity values */ - public const SENSITIVITY_NORMAL = 0; - public const SENSITIVITY_PERSONAL = 1; - public const SENSITIVITY_PRIVATE = 2; - public const SENSITIVITY_CONFIDENTIAL = 3; + const SENSITIVITY_NORMAL = 0; + const SENSITIVITY_PERSONAL = 1; + const SENSITIVITY_PRIVATE = 2; + const SENSITIVITY_CONFIDENTIAL = 3; /** * mapping of sensitivity * * @var array */ - protected $sensitivityMap = + protected $sensitivityMap = array( 'public' => self::SENSITIVITY_PERSONAL, 'private' => self::SENSITIVITY_PRIVATE, 'confidential' => self::SENSITIVITY_CONFIDENTIAL, - ; + ); /** * Kolab object type @@ -95,6 +95,11 @@ */ protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_TASK_USER_CREATED; + /** + * Enable mapping Activesync categories into Kolab tags (relations) + */ + protected $tag_categories = true; + /** * Appends contact data to xml element @@ -108,40 +113,39 @@ public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId, $as_array = false) { $task = is_array($serverId) ? $serverId : $this->getObject($collection->collectionId, $serverId); - $result = ; +// $config = $this->getFolderConfig($task'_mailbox'); + $result = array(); // Completion status (required) - $result'complete' = intval(($task'status' ?? null) == 'COMPLETED' || ($task'complete' ?? null) == 100); + $result'complete' = intval($task'status' == 'COMPLETED' || $task'complete' == 100); // Calendar namespace fields foreach ($this->mapping as $key => $name) { $value = $this->getKolabDataItem($task, $name); switch ($name) { - case 'due': - case 'start': - if (preg_match('/^UTC/i', $key)) { - $value = self::date_from_kolab($value); - } - break; - - case 'changed': - $value = $result'complete' ? self::date_from_kolab($value) : null; - break; - - case 'description': - $value = $this->body_from_kolab($value, $collection); - break; - - case 'sensitivity': - if (!empty($value)) { - $value = intval($this->sensitivityMap$value); - } - break; - - case 'priority': - $value = $this->prio_to_importance($value); - break; + case 'due': + case 'start': + if (preg_match('/^UTC/i', $key)) { + $value = self::date_from_kolab($value); + } + break; + + case 'changed': + $value = $result'complete' ? self::date_from_kolab($value) : null; + break; + + case 'description': + $value = $this->body_from_kolab($value, $collection); + break; + + case 'sensitivity': + $value = intval($this->sensitivityMap$value); + break; + + case 'priority': + $value = $this->prio_to_importance($value); + break; } if (empty($value) || is_array($value)) { @@ -151,12 +155,17 @@ $result$key = $value; } + // convert kolab tags into categories + $result'categories' = $this->getKolabTags($task'uid', $result'categories'); + // Recurrence $this->recurrence_from_kolab($collection, $task, $result, 'Task'); return $as_array ? $result : new Syncroton_Model_Task($result); } + + /** * Apply a timezone matching the utc offset. */ @@ -175,15 +184,17 @@ /** * convert contact from xml to libkolab array * - * @param Syncroton_Model_Task $data Contact to convert - * @param string $folderid Folder identifier - * @param array $entry Existing entry + * @param Syncroton_Model_IEntry $data Contact to convert + * @param string $folderid Folder identifier + * @param array $entry Existing entry * * @return array */ - public function toKolab($data, $folderid, $entry = null) + public function toKolab(Syncroton_Model_IEntry $data, $folderid, $entry = null) { - $task = !empty($entry) ? $entry : ; + $task = !empty($entry) ? $entry : array(); + $foldername = isset($task'_mailbox') ? $task'_mailbox' : $this->getFolderName($folderid); +// $config = $this->getFolderConfig($foldername); $task'allday' = 0; @@ -193,38 +204,38 @@ switch ($name) { - case 'due': - case 'start': - // We expect to always get regular and utc variants, so we only need to take one into account. - if ($key == 'utcStartDate' || $key == 'utcDueDate') { - continue 2; + case 'due': + case 'start': + // We expect to always get regular and utc variants, so we only need to take one into account. + if ($key == 'utcStartDate' || $key == 'utcDueDate') { + continue 2; + } + if ($value) { + if ($name =='due' && $data->utcDueDate) { + $value = static::applyTimezone($value, $data->utcDueDate); } - if ($value) { - if ($name == 'due' && $data->utcDueDate) { - $value = self::applyTimezone($value, $data->utcDueDate); - } - if ($name == 'start' && $data->utcStartDate) { - $value = self::applyTimezone($value, $data->utcStartDate); - } + if ($name =='start' && $data->utcStartDate) { + $value = static::applyTimezone($value, $data->utcStartDate); } - break; - - case 'sensitivity': - $map = array_flip($this->sensitivityMap); - $value = $map$value ?? 'none' ?? self::SENSITIVITY_NORMAL; - break; - - case 'description': - $value = $this->getBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT); - // If description isn't specified keep old description - if ($value === null) { - continue 2; - } - break; - - case 'priority': - $value = $this->importance_to_prio($value); - break; + } + break; + + case 'sensitivity': + $map = array_flip($this->sensitivityMap); + $value = $map$value; + break; + + case 'description': + $value = $this->getBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT); + // If description isn't specified keep old description + if ($value === null) { + continue 2; + } + break; + + case 'priority': + $value = $this->importance_to_prio($value); + break; } $this->setKolabDataItem($task, $name, $value); @@ -233,13 +244,10 @@ if (!empty($data->complete)) { $task'status' = 'COMPLETED'; $task'complete' = 100; - } elseif (isset($data->complete)) { - if ((!empty($task'status') && $task'status' == 'COMPLETED') - || (!empty($task'complete') && $task'complete' == 100) - ) { - $task'status' = ''; - $task'complete' = 0; - } + } + else if (isset($data->complete) && ($task'status' == 'COMPLETED' || $task'complete' == 100)) { + $task'status' = ''; + $task'complete' = 0; } // recurrence @@ -253,14 +261,14 @@ * * @param int $filter_type Filter type * - * @return array Filter query + * @param array Filter query */ protected function filter($filter_type = 0) { - $filter = 'type', '=', $this->modelName; + $filter = array(array('type', '=', $this->modelName)); if ($filter_type == Syncroton_Command_Sync::FILTER_INCOMPLETE) { - $filter = 'tags', '!~', 'x-complete'; + $filter = array('tags', '!~', 'x-complete'); } return $filter; @@ -282,18 +290,18 @@ } switch ($value) { - case 1: - case 2: - case 3: - case 4: - return 2; - case 5: - return 1; - case 6: - case 7: - case 8: - case 9: - return 0; + case 1: + case 2: + case 3: + case 4: + return 2; + case 5: + return 1; + case 6: + case 7: + case 8: + case 9: + return 0; } return; @@ -311,12 +319,12 @@ } switch ($value) { - case 0: - return 9; - case 1: - return 5; - case 2: - return 1; + case 0: + return 9; + case 1: + return 5; + case 2: + return 1; } return;
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_logger.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_logger.php
Changed
@@ -1,5 +1,4 @@ <?php - /* +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | @@ -30,7 +29,6 @@ { public $mode; - protected $log_driver; protected $logfile; protected $format; protected $log_dir; @@ -39,13 +37,12 @@ /** * Constructor */ - public function __construct($mode = null) + function __construct($mode = null) { $rcube = rcube::get_instance(); $this->mode = intval($mode); $this->logfile = $rcube->config->get('activesync_log_file'); - $this->log_driver = $rcube->config->get('log_driver'); $this->format = $rcube->config->get('log_date_format', 'd-M-Y H:i:s O'); $this->log_dir = $rcube->config->get('log_dir'); @@ -62,17 +59,6 @@ } /** - * Check whether debug logging is enabled - * - * @return bool - */ - public function hasDebug() - { - // This is what we check in self::log() below - return !empty($this->log_dir) && $this->mode >= self::NOTICE; - } - - /** * Message logger * * @param string $message Log message @@ -83,7 +69,8 @@ if (is_numeric($method)) { $mode = $method; $method = array_search($method, $this->_priorities); - } else { + } + else { $mode = $this->_priorities$method; } @@ -103,17 +90,16 @@ // if log_file is configured all logs will go to it // otherwise use separate file for info/debug and warning/error - $file = "undefined"; if (!$logfile) { switch ($mode) { - case self::DEBUG: - case self::INFO: - case self::NOTICE: - $file = 'console'; - break; - default: - $file = 'errors'; - break; + case self::DEBUG: + case self::INFO: + case self::NOTICE: + $file = 'console'; + break; + default: + $file = 'errors'; + break; } $logfile = $log_dir . DIRECTORY_SEPARATOR . $file; @@ -121,7 +107,8 @@ if (version_compare(version_parse(RCUBE_VERSION), '1.4.0') >= 0) { $logfile .= $rcube->config->get('log_file_ext', '.log'); } - } elseif ($logfile0 != '/') { + } + else if ($logfile0 != '/') { $logfile = $log_dir . DIRECTORY_SEPARATOR . $logfile; } @@ -129,40 +116,18 @@ $message = var_export($message, true); } - // write message in logfmt format with extra info when configured to log to STDOUT - if ($this->log_driver == 'logfmt') { - $user_name = $this->username; - - $output = "name=$file component=syncroton"; - $params = 'cmd' => 'Cmd', 'device' => 'DeviceId', 'type' => 'DeviceType'; - - foreach ($params as $key => $val) { - if ($val = $_GET$val) { - $output .= " $key=$val"; - } - } - - if (!empty($user_name)) { - $output .= " user=$user_name"; - } - $line = json_encode($message); - $output .= " log=$line\n"; - file_put_contents("php://stdout", $output, FILE_APPEND) !== false; - return; - } - // add user/request information to the log if ($mode <= self::WARN) { - $device = ; - $params = 'cmd' => 'Cmd', 'device' => 'DeviceId', 'type' => 'DeviceType'; + $device = array(); + $params = array('cmd' => 'Cmd', 'device' => 'DeviceId', 'type' => 'DeviceType'); if (!empty($this->username)) { $device'user' = $this->username; } foreach ($params as $key => $val) { - if (isset($_GET$val)) { - $device$key = $_GET$val; + if ($val = $_GET$val) { + $device$key = $val; } } @@ -174,13 +139,6 @@ $date = rcube_utils::date_format($this->format); $logline = sprintf("%s: %s %s\n", $date, $method, $message); - // write message with file name when configured to log to STDOUT - if ($this->log_driver == 'stdout') { - $stdout = "php://stdout"; - file_put_contents($stdout, $logline, FILE_APPEND); - return; - } - if ($fp = @fopen($logfile, 'a')) { fwrite($fp, $logline); fflush($fp);
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_message.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_message.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -25,17 +25,17 @@ class kolab_sync_message { - protected $headers = ; + protected $headers = array(); protected $body; protected $ctype; - protected $ctype_params = ; + protected $ctype_params = array(); /** * Constructor * * @param string|resource $source MIME message source */ - public function __construct($source) + function __construct($source) { $this->parse_mime($source); } @@ -52,7 +52,7 @@ public function source() { - $headers = ; + $headers = array(); // Build the message back foreach ($this->headers as $header => $header_value) { @@ -89,22 +89,22 @@ * Adds attachment to the message * * @param string $body Attachment body (not encoded) - * @param array $params Attachment parameters (Mail_mimePart format) + * @param string $params Attachment parameters (Mail_mimePart format) */ - public function add_attachment($body, $params = ) + public function add_attachment($body, $params = array()) { // convert the message into multipart/mixed if ($this->ctype != 'multipart/mixed') { $boundary = '_' . md5(rand() . microtime()); $this->body = "--$boundary\r\n" - . "Content-Type: " . $this->headers'Content-Type' . "\r\n" - . "Content-Transfer-Encoding: " . $this->headers'Content-Transfer-Encoding' . "\r\n" - . "\r\n" . trim($this->body) . "\r\n" - . "--$boundary\r\n"; + ."Content-Type: " . $this->headers'Content-Type'."\r\n" + ."Content-Transfer-Encoding: " . $this->headers'Content-Transfer-Encoding'."\r\n" + ."\r\n" . trim($this->body) . "\r\n" + ."--$boundary\r\n"; $this->ctype = 'multipart/mixed'; - $this->ctype_params = 'boundary' => $boundary; + $this->ctype_params = array('boundary' => $boundary); unset($this->headers'Content-Transfer-Encoding'); $this->save_content_type($this->ctype, $this->ctype_params); } @@ -128,8 +128,8 @@ // add the attachment to the end of the message $this->body .= "\r\n" - . implode("\r\n", $body'headers') . "\r\n\r\n" - . $body'body' . "\r\n--$boundary--\r\n"; + .implode("\r\n", $body'headers') . "\r\n\r\n" + .$body'body' . "\r\n--$boundary--\r\n"; } /** @@ -153,15 +153,15 @@ * @param array $smtp_error SMTP error array (reference) * @param array $smtp_opts SMTP options (e.g. DSN request) * - * @return bool Send status. + * @return boolean Send status. */ public function send(&$smtp_error = null, $smtp_opts = null) { - $rcube = kolab_sync::get_instance(); + $rcube = rcube::get_instance(); $headers = $this->headers; $mailto = $headers'To'; - $headers'User-Agent' = $rcube->app_name . ' ' . kolab_sync::VERSION; + $headers'User-Agent' .= $rcube->app_name . ' ' . kolab_sync::VERSION; if ($agent = $rcube->config->get('useragent')) { $headers'User-Agent' .= '/' . $agent; } @@ -170,7 +170,7 @@ $headers'From' = $this->get_identity(); } // make sure there's sender name in From: - elseif ($rcube->config->get('activesync_fix_from') + else if ($rcube->config->get('activesync_fix_from') && preg_match('/^<?((\S+|("^"+"))@\S+)>?$/', trim($headers'From'), $m) ) { $identities = kolab_sync::get_instance()->user->list_identities(); @@ -196,17 +196,14 @@ $smtp_headers = $headers; // generate list of recipients - $recipients = ; + $recipients = array(); - if (!empty($headers'To')) { + if (!empty($headers'To')) $recipients = $headers'To'; - } - if (!empty($headers'Cc')) { + if (!empty($headers'Cc')) $recipients = $headers'Cc'; - } - if (!empty($headers'Bcc')) { + if (!empty($headers'Bcc')) $recipients = $headers'Bcc'; - } if (empty($headers'To') && empty($headers'Cc')) { $headers'To' = 'undisclosed-recipients:;'; @@ -226,13 +223,13 @@ // log error if (!$sent) { - rcube::raise_error('code' => 800, 'type' => 'smtp', + rcube::raise_error(array('code' => 800, 'type' => 'smtp', 'line' => __LINE__, 'file' => __FILE__, - 'message' => "SMTP error: " . implode("\n", $smtp_response), true, false); + 'message' => "SMTP error: ".join("\n", $smtp_response)), true, false); } if ($sent) { - $rcube->plugins->exec_hook('message_sent', 'headers' => $headers, 'body' => $this->body); + $rcube->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $this->body)); // remove MDN headers after sending unset($headers'Return-Receipt-To', $headers'Disposition-Notification-To'); @@ -241,16 +238,12 @@ // get all recipient addresses $mailto = rcube_mime::decode_address_list(implode(',', $recipients), null, false, null, true); - rcube::write_log( - 'sendmail', - sprintf( - "User %s %s; Message %s for %s; %s", - $rcube->get_user_name(), - rcube_utils::remote_addr(), - $headers'Message-ID', - implode(', ', $mailto), - !empty($smtp_response) ? implode('; ', $smtp_response) : '' - ) + rcube::write_log('sendmail', sprintf("User %s %s; Message %s for %s; %s", + $rcube->get_user_name(), + rcube_utils::remote_addr(), + $headers'Message-ID', + implode(', ', $mailto), + !empty($smtp_response) ? implode('; ', $smtp_response) : '') ); } } @@ -276,20 +269,20 @@ $message = stream_get_contents($message); } - $headers, $message = array_pad(preg_split('/\r?\n\r?\n/', $message, 2, PREG_SPLIT_NO_EMPTY), 2, ''); + list($headers, $message) = preg_split('/\r?\n\r?\n/', $message, 2, PREG_SPLIT_NO_EMPTY); $hdrs = self::parse_headers($headers); // multipart message - if (preg_match('/boundary="?(a-z0-9-\'\(\)+_\,\.\/:=\? +)"?/i', $hdrs'Content-Type' ?? '', $matches)) { + if (preg_match('/boundary="?(a-z0-9-\'\(\)+_\,\.\/:=\? +)"?/i', $hdrs'Content-Type', $matches)) { $boundary = '--' . $matches1; $message = explode($boundary, $message); - for ($x = 1, $parts = count($message) - 1; $x < $parts; $x++) { + for ($x=1, $parts = count($message) - 1; $x<$parts; $x++) { $message$x = "\r\n" . self::recode_message(ltrim($message$x)); } - return $headers . "\r\n\r\n" . implode($boundary, $message); + return $headers . "\r\n\r\n" . implode($boundary , $message); } // single part @@ -338,7 +331,10 @@ /** * MIME message parser * - * @param string|resource $message MIME message source + * @param string|resource $message MIME message source + * @param bool $decode_body Enables body decoding + * + * @return array Message headers array and message body */ protected function parse_mime($message) { @@ -347,7 +343,7 @@ $message = stream_get_contents($message); } - $headers, $message = preg_split('/\r?\n\r?\n/', $message, 2, PREG_SPLIT_NO_EMPTY); + list($headers, $message) = preg_split('/\r?\n\r?\n/', $message, 2, PREG_SPLIT_NO_EMPTY); $headers = self::parse_headers($headers); @@ -378,24 +374,23 @@ $headers = explode("\n", trim($headers)); $ln = 0; - $lines = ; + $lines = array(); foreach ($headers as $line) { if (ord($line0) <= 32) { $lines$ln .= (empty($lines$ln) ? '' : "\r\n") . $line; - } else { + } + else { $lines++$ln = trim($line); } } // Unify char-case of header names - $headers = ; + $headers = array(); foreach ($lines as $line) { - if (strpos($line, ':') !== false) { - $field, $string = explode(':', $line, 2); - if ($field = self::normalize_header_name($field)) { - $headers$field = trim($string); - } + list($field, $string) = explode(':', $line, 2); + if ($field = self::normalize_header_name($field)) { + $headers$field = trim($string); } } @@ -407,7 +402,7 @@ */ protected static function normalize_header_name($name) { - $headers_map = + $headers_map = array( 'subject' => 'Subject', 'from' => 'From', 'to' => 'To', @@ -417,11 +412,11 @@ 'references' => 'References', 'content-type' => 'Content-Type', 'content-transfer-encoding' => 'Content-Transfer-Encoding', - ; + ); $name_lc = strtolower($name); - return $headers_map$name_lc ?? $name; + return isset($headers_map$name_lc) ? $headers_map$name_lc : $name; } /** @@ -432,16 +427,16 @@ * * @return string Encoded body */ - protected static function encode($body, $encoding) + protected function encode($body, $encoding) { switch ($encoding) { - case 'base64': - $body = base64_encode($body); - $body = chunk_split($body, 76, "\r\n"); - break; - case 'quoted-printable': - $body = quoted_printable_encode($body); - break; + case 'base64': + $body = base64_encode($body); + $body = chunk_split($body, 76, "\r\n"); + break; + case 'quoted-printable': + $body = quoted_printable_encode($body); + break; } return $body; @@ -460,12 +455,12 @@ $body = str_replace("\r\n", "\n", $body); switch ($encoding) { - case 'base64': - $body = base64_decode($body); - break; - case 'quoted-printable': - $body = quoted_printable_decode($body); - break; + case 'base64': + $body = base64_decode($body); + break; + case 'quoted-printable': + $body = quoted_printable_decode($body); + break; } return $body; @@ -483,7 +478,7 @@ } } - protected function save_content_type($ctype, $params = ) + protected function save_content_type($ctype, $params = array()) { $this->ctype = $ctype; $this->ctype_params = $params; @@ -495,4 +490,5 @@ } } } + }
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_plugin_api.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_plugin_api.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -35,7 +35,7 @@ * * @return rcube_plugin_api The one and only instance if this class */ - public static function get_instance() + static function get_instance() { if (!self::$instance) { self::$instance = new kolab_sync_plugin_api(); @@ -44,20 +44,22 @@ return self::$instance; } + /** * Initialize plugin engine * * This has to be done after rcmail::load_gui() or rcmail::json_init() * was called because plugins need to have access to rcmail->output * - * @param rcube $app Instance of the rcube base class - * @param string $task Current application task (used for conditional plugin loading) + * @param object rcube Instance of the rcube base class + * @param string Current application task (used for conditional plugin loading) */ public function init($app, $task = '') { $this->task = $task; } + /** * Register a handler function for template objects * @@ -70,6 +72,7 @@ // empty } + /** * Register this plugin to be responsible for a specific task * @@ -81,6 +84,7 @@ $this->tasks$task = $owner; } + /** * Include a plugin script file in the current HTML page * @@ -91,6 +95,7 @@ //empty } + /** * Include a plugin stylesheet in the current HTML page *
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_timezone_converter.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_timezone_converter.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -33,11 +33,11 @@ /** * holds the instance of the singleton * - * @var ?kolab_sync_timezone_converter + * @var kolab_sync_timezone_onverter */ - private static $_instance; + private static $_instance = NULL; - protected $_startDate = ; + protected $_startDate = array(); /** * If set then the timezone guessing results will be cached. @@ -51,19 +51,11 @@ * array of offsets known by ActiceSync clients, but unknown by php * @var array */ - protected $_knownTimezones = - '0AIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==' => - 'Pacific/Kwajalein' => 'MHT', - , - ; - - - protected $_legacyTimezones = - // This is an outdated timezone that outlook keeps sending because of an outdate timezone database on windows - 'Lv///0kAcgBhAG4AIABTAHQAYQBuAGQAYQByAGQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkABAADABcAOwA7AOcDAAAAAEkAcgBhAG4AIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAwAEAAAAAAAAAAAAxP///w==' => - 'Asia/Tehran' => '+0330', - , - ; + protected $_knownTimezones = array( + '0AIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==' => array( + 'Pacific/Kwajalein' => 'MHT' + ) + ); /** * don't use the constructor. Use the singleton. @@ -88,7 +80,7 @@ */ public static function getInstance() { - if (self::$_instance === null) { + if (self::$_instance === NULL) { self::$_instance = new kolab_sync_timezone_converter(); } @@ -147,25 +139,30 @@ { if (is_string($_offsets) && isset($this->_knownTimezones$_offsets)) { $timezones = $this->_knownTimezones$_offsets; - } elseif (is_string($_offsets) && isset($this->_legacyTimezones$_offsets)) { - $timezones = $this->_legacyTimezones$_offsets; - } else { + } + else { if (is_string($_offsets)) { // unpack timezone info to array $_offsets = $this->_unpackTimezoneInfo($_offsets); } if (!$this->_validateOffsets($_offsets)) { - return ; + return array(); } $this->_setDefaultStartDateIfEmpty($_offsets); - $timezones = ; - foreach (DateTimeZone::listIdentifiers() as $timezoneIdentifier) { - $timezone = new DateTimeZone($timezoneIdentifier); - if (false !== ($matchingTransition = $this->_checkTimezone($timezone, $_offsets))) { - $timezones$timezoneIdentifier = $matchingTransition'abbr'; + $cacheId = $this->_getCacheId('timezones', $_offsets); + $timezones = $this->_loadFromCache($cacheId); + + if (!is_array($timezones)) { + $timezones = array(); + foreach (DateTimeZone::listIdentifiers() as $timezoneIdentifier) { + $timezone = new DateTimeZone($timezoneIdentifier); + if (false !== ($matchingTransition = $this->_checkTimezone($timezone, $_offsets))) { + $timezones$timezoneIdentifier = $matchingTransition'abbr'; + } } + $this->_saveInCache($timezones, $cacheId); } } @@ -178,7 +175,7 @@ * If {@see $_expectedTimezone} is set then the method will return this timezone if it matches. * * @param string|array $_offsets Activesync timezone definition - * @param string $_expectedTimezone Expected timezone name + * @param string $_expectedTomezone Expected timezone name * * @return string Expected timezone name */ @@ -188,7 +185,8 @@ if ($_expectedTimezone && isset($timezones$_expectedTimezone)) { return $_expectedTimezone; - } else { + } + else { return key($timezones); } } @@ -214,65 +212,48 @@ return $this->_packTimezoneInfo($offsets); } - - /** - * Returns an encoded timezone representation from $date - * - * @param DateTime $date The date with the timezone to encode - * - * @return string|null Timezone name - */ - public static function encodeTimezoneFromDate($date) - { - if ($date instanceof DateTime) { - $timezone = $date->getTimezone(); - - if (($tz_name = $timezone->getName()) != 'UTC') { - $tzc = self::getInstance(); - if ($tz_name = $tzc->encodeTimezone($tz_name, $date->format('Y-m-d'))) { - return $tz_name; - } - } - } - - return null; - } - /** * Get offsets for given timezone * * @param string $_timezone Timezone identifier * @param string|int $_startDate Start date * - * @return array|null Timezone offsets + * @return array Timezone offsets */ public function getOffsetsForTimezone($_timezone, $_startDate = null) { $this->_setStartDate($_startDate); - $offsets = $this->_getOffsetsTemplate(); + $cacheId = $this->_getCacheId('offsets', array($_timezone)); - try { - $timezone = new DateTimeZone($_timezone); - } catch (Exception $e) { - return null; - } + if (false === ($offsets = $this->_loadFromCache($cacheId))) { + $offsets = $this->_getOffsetsTemplate(); + + try { + $timezone = new DateTimeZone($_timezone); + } + catch (Exception $e) { + return null; + } - $standardTransition, $daylightTransition = $this->_getTransitionsForTimezoneAndYear($timezone, $this->_startDate'year'); + list($standardTransition, $daylightTransition) = $this->_getTransitionsForTimezoneAndYear($timezone, $this->_startDate'year'); - if ($standardTransition) { - $offsets'bias' = $standardTransition'offset' / 60 * -1; - if ($daylightTransition) { - $offsets = $this->_generateOffsetsForTransition($offsets, $standardTransition, 'standard', $timezone); - $offsets = $this->_generateOffsetsForTransition($offsets, $daylightTransition, 'daylight', $timezone); + if ($standardTransition) { + $offsets'bias' = $standardTransition'offset'/60*-1; + if ($daylightTransition) { + $offsets = $this->_generateOffsetsForTransition($offsets, $standardTransition, 'standard', $timezone); + $offsets = $this->_generateOffsetsForTransition($offsets, $daylightTransition, 'daylight', $timezone); - //@todo how do we get the standardBias (is usually 0)? - //$offsets'standardBias' = ... + //@todo how do we get the standardBias (is usually 0)? + //$offsets'standardBias' = ... - $offsets'daylightBias' = ($daylightTransition'offset' - $standardTransition'offset') / 60 * -1; - $offsets'standardHour' -= $offsets'daylightBias' / 60; - $offsets'daylightHour' += $offsets'daylightBias' / 60; + $offsets'daylightBias' = ($daylightTransition'offset' - $standardTransition'offset')/60*-1; + $offsets'standardHour' -= $offsets'daylightBias' / 60; + $offsets'daylightHour' += $offsets'daylightBias' / 60; + } } + + $this->_saveInCache($offsets, $cacheId); } return $offsets; @@ -301,7 +282,7 @@ $_offsets$_type . 'Minute' = (int) $transitionDate->format('i'); $_offsets$_type . 'Hour' = (int) $transitionDate->format('G'); - for ($i = 5; $i > 0; $i--) { + for ($i=5; $i>0; $i--) { if ($this->_isNthOcurrenceOfWeekdayInMonth($transitionDate, $i)) { $_offsets$_type . 'Week' = $i; break; @@ -356,10 +337,8 @@ * Check if the given {@param $_standardTransition} and {@param $_daylightTransition} * match to the object property {@see $_offsets} * - * @param array $_standardTransition - * @param array $_daylightTransition - * @param array $_offsets - * @param DateTimeZone $tz + * @param array $standardTransition + * @param array $daylightTransition * * @return bool */ @@ -382,7 +361,7 @@ $daylightOffset = ($_offsets'bias' + $_offsets'daylightBias') * 60 * -1; // the milestone is sending a positive value for daylightBias while it should send a negative value - $daylightOffsetMilestone = ($_offsets'bias' + ($_offsets'daylightBias' * -1)) * 60 * -1; + $daylightOffsetMilestone = ($_offsets'bias' + ($_offsets'daylightBias' * -1) ) * 60 * -1; if ( !empty($_daylightTransition) @@ -435,11 +414,10 @@ } /** - * Encode timezone info to activesync + * encode timezone info to activesync * * @param array $_timezoneInfo - * - * @return string|null + * @return string */ protected function _packTimezoneInfo($_timezoneInfo) { @@ -491,11 +469,11 @@ * Used e.g. when reverse-generating ActiveSync Timezone Offset Information * based on a given Timezone, {@see getOffsetsForTimezone} * - * @return array + * @return unknown_type */ protected function _getOffsetsTemplate() { - return + return array( 'bias' => 0, 'standardName' => '', 'standardYear' => 0, @@ -516,8 +494,8 @@ 'daylightMinute' => 0, 'daylightSecond' => 0, 'daylightMilliseconds' => 0, - 'daylightBias' => 0, - ; + 'daylightBias' => 0 + ); } /** @@ -543,7 +521,7 @@ /** * Parse and set object property {@see $_startDate} * - * @param mixed $_startDate + * @param string|int $_startDate * @return void */ protected function _setStartDate($_startDate) @@ -553,15 +531,17 @@ return; } - $startDateParsed = ; + $startDateParsed = array(); if (is_string($_startDate)) { $startDateParsed'string' = $_startDate; $startDateParsed'ts' = strtotime($_startDate); - } elseif (is_int($_startDate)) { + } + else if (is_int($_startDate)) { $startDateParsed'ts' = $_startDate; - $startDateParsed'string' = date('Y-m-d', $_startDate); - } else { + $startDateParsed'string' = strftime('%F', $_startDate); + } + else { $this->_setDefaultStartDateIfEmpty(); return; } @@ -588,8 +568,9 @@ } if (!empty($_offsets'standardYear')) { - $this->_setStartDate($_offsets'standardYear' . '-01-01'); - } else { + $this->_setStartDate($_offsets'standardYear'.'-01-01'); + } + else { $this->_setStartDate(time()); } } @@ -605,7 +586,7 @@ */ protected function _checkTimezone(DateTimeZone $timezone, $offsets) { - $standardTransition, $daylightTransition = $this->_getTransitionsForTimezoneAndYear($timezone, $this->_startDate'year'); + list($standardTransition, $daylightTransition) = $this->_getTransitionsForTimezoneAndYear($timezone, $this->_startDate'year'); if ($this->_checkTransition($standardTransition, $daylightTransition, $offsets, $timezone)) { return $standardTransition; @@ -633,24 +614,61 @@ $transitions = $_timezone->getTransitions($start, $end); if ($transitions === false) { - return null, null; + return array(); } foreach ($transitions as $index => $transition) { - if (date('Y', $transition'ts') == $_year) { - if (isset($transitions$index + 1) && date('Y', $transitions$index'ts') == date('Y', $transitions$index + 1'ts')) { - $daylightTransition = $transition'isdst' ? $transition : $transitions$index + 1; - $standardTransition = $transition'isdst' ? $transitions$index + 1 : $transition; - } else { + if (strftime('%Y', $transition'ts') == $_year) { + if (isset($transitions$index+1) && strftime('%Y', $transitions$index'ts') == strftime('%Y', $transitions$index+1'ts')) { + $daylightTransition = $transition'isdst' ? $transition : $transitions$index+1; + $standardTransition = $transition'isdst' ? $transitions$index+1 : $transition; + } + else { $daylightTransition = $transition'isdst' ? $transition : null; $standardTransition = $transition'isdst' ? null : $transition; } break; - } elseif ($index == count($transitions) - 1) { + } + else if ($index == count($transitions) -1) { $standardTransition = $transition; } } - return $standardTransition, $daylightTransition; + return array($standardTransition, $daylightTransition); + } + + protected function _getCacheId($_prefix, $_offsets) + { + return $_prefix . md5(serialize($_offsets)); + } + + protected function _loadFromCache($key) + { + if ($cache = $this->getCache()) { + return $cache->get($key); + } + + return false; + } + + protected function _saveInCache($value, $key) + { + if ($cache = $this->getCache()) { + $cache->set($key, $value); + } + } + + /** + * Getter for the cache engine object + */ + protected function getCache() + { + if ($this->cache === null) { + $rcube = rcube::get_instance(); + $cache = $rcube->get_cache_shared('activesync'); + $this->cache = $cache ? $cache : false; + } + + return $this->cache; } }
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_transaction_manager.php -> kolab-syncroton-2.3.22.tar.gz/lib/kolab_sync_transaction_manager.php
Changed
@@ -1,6 +1,6 @@ <?php -/* +/** +--------------------------------------------------------------------------+ | Kolab Sync (ActiveSync for Kolab) | | | @@ -43,17 +43,17 @@ /** * @var array holds all transactionables with open transactions */ - protected $_openTransactionables = ; + protected $_openTransactionables = array(); /** * @var array list of all open (not commited) transactions */ - protected $_openTransactions = ; + protected $_openTransactions = array(); /** - * @var ?self + * @var Syncroton_TransactionManager */ - private static $_instance; + private static $_instance = NULL; /** * @var Zend_Log @@ -78,12 +78,12 @@ } /** - * @return self + * @return Tinebase_TransactionManager */ public static function getInstance() { - if (self::$_instance === null) { - self::$_instance = new kolab_sync_transaction_manager(); + if (self::$_instance === NULL) { + self::$_instance = new kolab_sync_transaction_manager; } return self::$_instance; @@ -92,10 +92,9 @@ /** * starts a transaction * - * @param mixed $_transactionable - * - * @return string Transaction Id - * @throws Exception + * @param mixed $_transactionable + * @return string transactionId + * @throws Tinebase_Exception_UnexpectedValue */ public function startTransaction($_transactionable) { @@ -106,7 +105,8 @@ if (! in_array($_transactionable, $this->_openTransactionables)) { if ($_transactionable instanceof rcube_db) { $_transactionable->startTransaction(); - } else { + } + else { $this->rollBack(); throw new Syncroton_Exception_UnexpectedValue('Unsupported transactionable!'); } @@ -114,7 +114,7 @@ array_push($this->_openTransactionables, $_transactionable); } - $transactionId = sha1(mt_rand() . microtime()); + $transactionId = sha1(mt_rand(). microtime()); array_push($this->_openTransactions, $transactionId); return $transactionId; @@ -146,9 +146,10 @@ } } - $this->_openTransactionables = ; - $this->_openTransactions = ; - } else { + $this->_openTransactionables = array(); + $this->_openTransactions = array(); + } + else { if ($this->_logger instanceof Zend_Log) { $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " commiting defered, as there are still $numOpenTransactions in the queue"); } @@ -172,7 +173,7 @@ } } - $this->_openTransactionables = ; - $this->_openTransactions = ; + $this->_openTransactionables = array(); + $this->_openTransactions = array(); } }
View file
kolab-syncroton-2.3.22.tar.gz/tests/body_converter.php
Added
@@ -0,0 +1,50 @@ +<?php + +class body_converter extends PHPUnit\Framework\TestCase +{ + function setUp() + { + } + + + function data_html_to_text() + { + return array( + array('', ''), + array('<div></div>', ''), + array('<div>a</div>', 'a'), + array('<html><head><title>title</title></head></html>', ''), + ); + } + + /** + * @dataProvider data_html_to_text + */ + function test_html_to_text($html, $text) + { + $converter = new kolab_sync_body_converter($html, Syncroton_Model_EmailBody::TYPE_HTML); + $output = $converter->convert(Syncroton_Model_EmailBody::TYPE_PLAINTEXT); + + $this->assertEquals(trim($text), trim($output)); + } + + /** + * + */ + function test_rtf_to_text() + { + $rtf = '0QAAAB0CAABMWkZ1Pzsq5D8ACQMwAQMB9wKnAgBjaBEKwHNldALRcHJx4DAgVGFoA3ECgwBQ6wNUDzcyD9MyBgAGwwKDpxIBA+MReDA0EhUgAoArApEI5jsJbzAVwzEyvjgJtBdCCjIXQRb0ORIAHxeEGOEYExjgFcMyNTX/CbQaYgoyGmEaHBaKCaUa9v8c6woUG3YdTRt/Hwwabxbt/xyPF7gePxg4JY0YVyRMKR+dJfh9CoEBMAOyMTYDMUksgSc1FGAnNhqAJ1Q3My3BNAqFfS7A'; + $rtf = base64_decode($rtf); + $text = 'Test'; + $html = '<pre>Test</pre>'; + + $converter = new kolab_sync_body_converter($rtf, Syncroton_Model_EmailBody::TYPE_RTF); + + $output = $converter->convert(Syncroton_Model_EmailBody::TYPE_PLAINTEXT); + $this->assertEquals(trim($text), trim($output)); + + $output = $converter->convert(Syncroton_Model_EmailBody::TYPE_HTML); + $this->assertEquals(trim($html), trim($output)); + } + +}
View file
kolab-syncroton-2.4.2.tar.gz/tests/bootstrap.php -> kolab-syncroton-2.3.22.tar.gz/tests/bootstrap.php
Changed
@@ -1,8 +1,5 @@ <?php -error_reporting(E_ALL); -ini_set('display_errors', 1); - if (php_sapi_name() != 'cli') { die("Not in shell mode (php-cli)"); } @@ -10,6 +7,5 @@ define('TESTS_DIR', dirname(__FILE__) . '/'); require_once(TESTS_DIR . '/../lib/init.php'); -require_once(TESTS_DIR . '/SyncTestCase.php'); rcube::get_instance()->config->set('devel_mode', false);
View file
kolab-syncroton-2.3.22.tar.gz/tests/data.php
Added
@@ -0,0 +1,74 @@ +<?php + +class data extends PHPUnit\Framework\TestCase +{ + /** + * Test for kolab_sync_data::recurrence_to_kolab() + */ + function test_recurrence_to_kolab() + { + $xml = '<!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> + <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar"> + <ApplicationData> + <Calendar:Recurrence> + <Calendar:Type>0</Calendar:Type> + <Calendar:Interval>1</Calendar:Interval> + <Calendar:Until>20101128T225959Z</Calendar:Until> + </Calendar:Recurrence> + </ApplicationData> + </Sync>'; + + $xml = new SimpleXMLElement($xml); + $event = new Syncroton_Model_Event($xml->ApplicationData); + $data = new kolab_sync_data_test; + + $result = $data->recurrence_to_kolab($event); + + $this->assertEquals('DAILY', $result'FREQ'); + $this->assertEquals(1, $result'INTERVAL'); + $this->assertEquals('20101128T225959Z', $result'UNTIL'->format("Ymd\THis\Z")); + + $xml = '<!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> + <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar"> + <ApplicationData> + <Calendar:Recurrence> + <Calendar:Type>1</Calendar:Type> + <Calendar:Interval>1</Calendar:Interval> + <Calendar:DayOfWeek>8</Calendar:DayOfWeek> + </Calendar:Recurrence> + </ApplicationData> + </Sync>'; + + $xml = new SimpleXMLElement($xml); + $event = new Syncroton_Model_Event($xml->ApplicationData); + + $result = $data->recurrence_to_kolab($event, null); + + $this->assertEquals('WEEKLY', $result'FREQ'); + $this->assertEquals(1, $result'INTERVAL'); + $this->assertEquals('WE', $result'BYDAY'); + } +} + +/** + * kolab_sync_data wrapper, so we can test preotected methods too + */ +class kolab_sync_data_test extends kolab_sync_data +{ + function __construct() + { + } + + public function recurrence_to_kolab($data, $dummy1 = null, $dummy2 = null) + { + return parent::recurrence_to_kolab($data, null); + } + + function toKolab(Syncroton_Model_IEntry $data, $folderId, $entry = null, $timezone = null) + { + } + + function getEntry(Syncroton_Model_SyncCollection $collection, $serverId, $as_array = false) + { + } +}
View file
kolab-syncroton-2.3.22.tar.gz/tests/data_calendar.php
Added
@@ -0,0 +1,126 @@ +<?php + +class data_calendar extends PHPUnit\Framework\TestCase +{ + /** + * Test for kolab_sync_data_calendar::from_kolab_alarm() + */ + function test_from_kolab_alarm() + { + $obj = new kolab_sync_data_calendar_test; + + $result = $obj->from_kolab_alarm(array()); + $this->assertSame(null, $result); + + $event = array('valarms' => array(array( + 'action' => 'DISPLAY', + 'trigger' => 'PT5M', + ))); + $result = $obj->from_kolab_alarm($event); + $this->assertSame(null, $result); + + $event = array('valarms' => array(array( + 'action' => 'DISPLAY', + 'trigger' => '-PT5M', + ))); + $result = $obj->from_kolab_alarm($event); + $this->assertSame(5, $result); + + $event = array('valarms' => array(array( + 'action' => 'DISPLAY', + 'trigger' => 'PT0M', + ))); + $result = $obj->from_kolab_alarm($event); + $this->assertSame(0, $result); + + $event = array('valarms' => array(array( + 'action' => 'DISPLAY', + 'trigger' => '-PT0M', + ))); + $result = $obj->from_kolab_alarm($event); + $this->assertSame(0, $result); + + $event = array('valarms' => array(array( + 'action' => 'DISPLAY', + 'trigger' => 'PT0S', + ))); + $result = $obj->from_kolab_alarm($event); + $this->assertSame(0, $result); + + // alarms on specified DateTime (T2420) + + $event = array( + // no start datetime defined + 'valarms' => array( + array( + 'action' => 'DISPLAY', + 'trigger' => new DateTime('now + 1 hour'), + ), + ), + ); + $result = $obj->from_kolab_alarm($event); + $this->assertSame(null, $result); + + $event = array( + 'start' => new DateTime('now + 10 minutes'), + 'valarms' => array( + array( + 'action' => 'DISPLAY', + 'trigger' => new DateTime('now + 1 hour'), + ), + ), + ); + $result = $obj->from_kolab_alarm($event); + $this->assertSame(null, $result); + + $event = array( + 'start' => new DateTime('now + 60 minutes'), + 'valarms' => array( + array( + 'action' => 'DISPLAY', + 'trigger' => new DateTime('now + 50 minutes'), + ), + ), + ); + $result = $obj->from_kolab_alarm($event); + $this->assertSame(10, $result); + } + + /** + * Test for kolab_sync_data_calendar::to_kolab_alarm() + */ + function test_to_kolab_alarm() + { + $obj = new kolab_sync_data_calendar_test; + + $result = $obj->to_kolab_alarm(null, array()); + $this->assertSame(array(), $result); + + $result = $obj->to_kolab_alarm(0, array()); + $this->assertSame('-PT0M', $result0'trigger'); + + $result = $obj->to_kolab_alarm(15, array()); + $this->assertSame('-PT15M', $result0'trigger'); + $this->assertSame('DISPLAY', $result0'action'); + } +} + +/** + * kolab_sync_data_calendar wrapper, so we can test protected methods too + */ +class kolab_sync_data_calendar_test extends kolab_sync_data_calendar +{ + function __construct() + { + } + + public function from_kolab_alarm($value) + { + return parent::from_kolab_alarm($value); + } + + public function to_kolab_alarm($value, $event) + { + return parent::to_kolab_alarm($value, $event); + } +}
View file
kolab-syncroton-2.3.22.tar.gz/tests/data_tasks.php
Added
@@ -0,0 +1,78 @@ +<?php + +class data_tasks extends PHPUnit\Framework\TestCase +{ + function data_prio() + { + return array( + array(0, null), + array(1, 2), + array(2, 2), + array(3, 2), + array(4, 2), + array(5, 1), + array(6, 0), + array(7, 0), + array(8, 0), + array(9, 0), + // invalid input + array(10, null), + ); + } + + function data_importance() + { + return array( + array(0, 9), + array(1, 5), + array(2, 1), + // invalid input + array(null, null), + array(5, null), + ); + } + + /** + * Test for kolab_sync_data_tasks::prio_to_importance() + * @dataProvider data_prio() + */ + function test_prio_to_importance($input, $output) + { + $data = new kolab_sync_data_tasks_test; + $result = $data->prio_to_importance($input); + + $this->assertEquals($output, $result); + } + + /** + * Test for kolab_sync_data_tasks::importance_to_prio() + * @dataProvider data_importance() + */ + function test_importance_to_prio($input, $output) + { + $data = new kolab_sync_data_tasks_test; + $result = $data->importance_to_prio($input); + + $this->assertEquals($output, $result); + } +} + +/** + * kolab_sync_data_tasks wrapper, so we can test preotected methods too + */ +class kolab_sync_data_tasks_test extends kolab_sync_data_tasks +{ + function __construct() + { + } + + public function prio_to_importance($value) + { + return parent::prio_to_importance($value); + } + + public function importance_to_prio($value) + { + return parent::importance_to_prio($value); + } +}
View file
kolab-syncroton-2.3.22.tar.gz/tests/message.php
Added
@@ -0,0 +1,151 @@ +<?php + +class message extends PHPUnit\Framework\TestCase +{ + function setUp() + { + } + + + /** + * Test message parsing and headers setting + */ + function test_headers() + { + $source = file_get_contents(TESTS_DIR . '/src/mail.plain'); + $message = new kolab_sync_message($source); + $headers = $message->headers(); + + $this->assertArrayHasKey('MIME-Version', $headers); + $this->assertCount(8, $headers); + $this->assertEquals('kolab@domain.tld', $headers'To'); + + // test set_header() + $message->set_header('to', 'test@domain.tld'); + $headers = $message->headers(); + + $this->assertCount(8, $headers); + $this->assertEquals('test@domain.tld', $headers'To'); + } + + /** + * Test message parsing + */ + function test_source() + { + $source = file_get_contents(TESTS_DIR . '/src/mail.plain'); + $message = new kolab_sync_message($source); + $result = $message->source(); + + $this->assertEquals($source, str_replace("\r\n", "\n", $result)); + } + + /** + * Test adding attachments to the message + */ + function test_attachment() + { + $source = file_get_contents(TESTS_DIR . '/src/mail.plain'); + $mixed = file_get_contents(TESTS_DIR . '/src/mail.plain.mixed'); + $mixed2 = file_get_contents(TESTS_DIR . '/src/mail.mixed'); + + // test adding attachment to text/plain message + $message = new kolab_sync_message($source); + $message->add_attachment('aaa', array( + 'content_type' => 'text/plain', + 'encoding' => '8bit', + )); + + $result = $message->source(); + $result = str_replace("\r\n", "\n", $result); + if (preg_match('/boundary="(^"+)"/', $result, $m)) { + $mixed = str_replace('BOUNDARY', $m1, $mixed); + } + + $this->assertEquals($mixed, $result); + + // test adding attachment to multipart/mixed message + $message = new kolab_sync_message($mixed); + $message->add_attachment('aaa', array( + 'content_type' => 'text/plain', + 'encoding' => 'base64', + )); + + $result = $message->source(); + $result = str_replace("\r\n", "\n", $result); + if (preg_match('/boundary="(^"+)"/', $result, $m)) { + $mixed2 = str_replace('BOUNDARY', $m1, $mixed2); + } + + $this->assertEquals($mixed2, $result); + } + + /** + * Test appending a text to the message + */ + function test_append() + { + // test appending text to text/plain message + $source = file_get_contents(TESTS_DIR . '/src/mail.plain'); + $append = file_get_contents(TESTS_DIR . '/src/mail.plain.append'); + + $message = new kolab_sync_message($source); + $message->append('a'); + + $result = $message->source(); + $result = str_replace("\r\n", "\n", $result); + $this->assertEquals($append, $result); + } + + /** + * Test recoding the message + */ + function test_recode_message_1() + { + $source = file_get_contents(TESTS_DIR . '/src/mail.recode1'); + $result = file_get_contents(TESTS_DIR . '/src/mail.recode1.out'); + + $message = kolab_sync_message::recode_message($source); + + $this->assertEquals($result, $message); + } + + /** + * Test recoding the message + */ + function test_recode_message_2() + { + $source = file_get_contents(TESTS_DIR . '/src/mail.recode2'); + $result = file_get_contents(TESTS_DIR . '/src/mail.recode2.out'); + + $message = kolab_sync_message::recode_message($source); + + $this->assertEquals($result, $message); + } + + /** + * Test recoding the message + */ + function test_recode_message_3() + { + $source = file_get_contents(TESTS_DIR . '/src/mail.recode3'); + $result = file_get_contents(TESTS_DIR . '/src/mail.recode3.out'); + + $message = kolab_sync_message::recode_message($source); + + $this->assertEquals($result, $message); + } + + /** + * Test recoding the message + */ + function test_recode_message_4() + { + $source = file_get_contents(TESTS_DIR . '/src/mail.recode4'); + $result = file_get_contents(TESTS_DIR . '/src/mail.recode4.out'); + + $message = kolab_sync_message::recode_message($source); + + $this->assertEquals($result, $message); + } +}
View file
kolab-syncroton-2.4.2.tar.gz/tests/phpunit.xml -> kolab-syncroton-2.3.22.tar.gz/tests/phpunit.xml
Changed
@@ -2,11 +2,13 @@ bootstrap="bootstrap.php" colors="true"> <testsuites> - <testsuite name="Unit"> - <directory suffix="Test.php">Unit</directory> - </testsuite> - <testsuite name="Sync"> - <directory suffix="Test.php">Sync</directory> + <testsuite name="All Tests"> + <file>body_converter.php</file> + <file>data.php</file> + <file>data_calendar.php</file> + <file>data_tasks.php</file> + <file>message.php</file> + <file>timezone_converter.php</file> </testsuite> </testsuites> </phpunit>
View file
kolab-syncroton-2.3.22.tar.gz/tests/timezone_converter.php
Added
@@ -0,0 +1,161 @@ +<?php + +class timezone_converter extends PHPUnit\Framework\TestCase +{ + function setUp() + { + } + + + function test_list_timezones() + { +// date_default_timezone_set('America/Los_Angeles'); + + $converter = timezone_converter_test::getInstance(); + $output = $converter->getListOfTimezones('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAEAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAEAAAAAAAAAxP///w=='); + + $this->assertTrue(is_array($output)); + $this->assertSame(array(), $output); + + $converter = timezone_converter_test::getInstance(); + $output = $converter->getListOfTimezones('xP///0MAZQBuAHQAcgBhAGwAIABFAHUAcgBvAHAAZQAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAEMAZQBuAHQAcgBhAGwAIABFAHUAcgBvAHAAZQAgAEQAYQB5AGwAaQBnAGgAdAAgAFQAaQBtAGUAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w=='); + + $this->assertTrue(is_array($output)); + $this->assertTrue(isset($output'Europe/Warsaw')); + + $converter = timezone_converter_test::getInstance(); + $output = $converter->getListOfTimezones('4AEAAFAAYQBjAGkAZgBpAGMAIABTAHQAYQBuAGQAYQByAGQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAFAAYQBjAGkAZgBpAGMAIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w=='); + + $this->assertTrue(is_array($output)); + $this->assertTrue(isset($output'America/Los_Angeles')); + + $converter = timezone_converter_test::getInstance(); + $output = $converter->getListOfTimezones('Lv///0kAcgBhAG4AIABTAHQAYQBuAGQAYQByAGQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAAgADABcAOwA7AOcDAAAAAEkAcgBhAG4AIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAQAEAAAAAAAAAAAAxP///w=='); + + $this->assertTrue(is_array($output)); + $this->assertTrue(isset($output'Asia/Tehran')); + } + + function test_get_timezone() + { + date_default_timezone_set('America/Los_Angeles'); + + $converter = timezone_converter_test::getInstance(); + $datetime = new DateTime('2017-01-01T12:00:00Z'); + + $offsets = $converter->getOffsetsForTimezone('UTC', $datetime); + $output = $converter->getTimezone($offsets, 'UTC'); + + $this->assertSame('UTC', $output); + + $offsets = $converter->getOffsetsForTimezone('Europe/Warsaw', $datetime); + $output = $converter->getTimezone($offsets, 'Europe/Warsaw'); + + $this->assertSame('Europe/Warsaw', $output); + + $offsets = $converter->getOffsetsForTimezone('America/Los_Angeles', $datetime); + $output = $converter->getTimezone($offsets, 'America/Los_Angeles'); + + $this->assertSame('America/Los_Angeles', $output); + } + + function test_get_offsets_for_timezone() + { + date_default_timezone_set('America/Los_Angeles'); + + $converter = timezone_converter_test::getInstance(); + $datetime = new DateTime('2017-01-01T12:00:00Z'); + + $output = $converter->getOffsetsForTimezone('UTC', $datetime); + + $this->assertSame($output'bias', 0); + $this->assertSame($output'standardBias', 0); + $this->assertSame($output'daylightBias', 0); + $this->assertSame($output'standardMonth', 0); + $this->assertSame($output'daylightMonth', 0); + + $output = $converter->getOffsetsForTimezone('Europe/Warsaw', $datetime); + + $this->assertSame($output'standardBias', 0); + $this->assertSame($output'standardMonth', 10); + $this->assertSame($output'standardWeek', 5); + $this->assertSame($output'standardHour', 3); + $this->assertSame($output'daylightBias', -60); + $this->assertSame($output'daylightMonth', 3); + $this->assertSame($output'daylightWeek', 5); + $this->assertSame($output'daylightHour', 2); + + $output = $converter->getOffsetsForTimezone('America/Los_Angeles', $datetime); + + $this->assertSame($output'bias', 480); + $this->assertSame($output'standardBias', 0); + $this->assertSame($output'standardMonth', 11); + $this->assertSame($output'standardWeek', 1); + $this->assertSame($output'standardHour', 2); + $this->assertSame($output'daylightBias', -60); + $this->assertSame($output'daylightMonth', 3); + $this->assertSame($output'daylightWeek', 2); + $this->assertSame($output'daylightHour', 2); + + $output = $converter->getOffsetsForTimezone('Atlantic/Azores', $datetime); + + $this->assertSame($output'bias', 60); + $this->assertSame($output'standardBias', 0); + $this->assertSame($output'standardMonth', 10); + $this->assertSame($output'standardWeek', 5); + $this->assertSame($output'standardHour', 1); + $this->assertSame($output'daylightBias', -60); + $this->assertSame($output'daylightMonth', 3); + $this->assertSame($output'daylightWeek', 5); + $this->assertSame($output'daylightHour', 0); + + $output = $converter->getOffsetsForTimezone('Asia/Tehran', $datetime); + + $this->assertSame($output'bias', -210); + $this->assertSame($output'standardBias', 0); + $this->assertSame($output'standardMonth', 9); + $this->assertSame($output'standardWeek', 3); + $this->assertSame($output'standardDayOfWeek', 2); + $this->assertSame($output'standardHour', 24); + $this->assertSame($output'daylightBias', -60); + $this->assertSame($output'daylightMonth', 3); + $this->assertSame($output'daylightWeek', 4); + $this->assertSame($output'daylightDayOfWeek', 1); + $this->assertSame($output'daylightHour', 0); + } + + function data_timezone_conversion() + { + return array( + array('Asia/Tehran', 'Lv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAAgADABcAOwA7AOcDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAQAEAAAAAAAAAAAAxP///w=='), + array('Pacific/Pago_Pago', 'lAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=='), + array('Europe/Warsaw', 'xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w=='), + ); + } + + /** + * @dataProvider data_timezone_conversion + */ + function test_timezone_conversion($tz, $expected) + { + $datetime = new DateTime('2021-07-01T12:00:00Z'); + $converter = timezone_converter_test::getInstance(); + $output = $converter->encodeTimezone($tz, $datetime); + + $this->assertSame($expected, $output); + + $output = $converter->getListOfTimezones($output); + + $this->assertTrue(is_array($output)); + $this->assertTrue(isset($output$tz)); + } +} + +class timezone_converter_test extends kolab_sync_timezone_converter +{ + // disable cache + function getCache() + { + return null; + } +}
View file
kolab-syncroton-2.4.2.tar.gz/.gitignore
Deleted
@@ -1,10 +0,0 @@ -*.patch -/config/config.inc.php -/config/defaults.inc.php -/composer.json -/composer.lock -/lib/plugins -/lib/ext/Roundcube -/logs/*.log -/tests/.phpunit.result.cache -/vendor
View file
kolab-syncroton-2.4.2.tar.gz/.php-cs-fixer.php
Deleted
@@ -1,47 +0,0 @@ -<?php - -declare(strict_types=1); - -use PhpCsFixer\Config; -use PhpCsFixer\Finder; - -$finder = Finder::create() - ->in(__DIR__) - ->exclude( - 'lib/ext/Roundcube', - 'lib/plugins', - 'vendor', - ) - ->ignoreDotFiles(false) - ->name('*.php.dist'); - -return (new Config()) - ->setRiskyAllowed(true) - ->setRules( - '@PHP74Migration' => true, - '@PHP74Migration:risky' => true, - '@PHP80Migration' => true, - '@PSR1' => true, - '@PSR12' => true, - - 'concat_space' => - 'spacing' => 'one', - , - - 'declare_strict_types' => false, - 'phpdoc_add_missing_param_annotation' => false, - 'use_arrow_functions' => false, - 'void_return' => false, - - 'yoda_style' => - 'equal' => false, - 'identical' => false, - , - - // TODO - risky - 'no_unset_on_property' => false, - 'random_api_migration' => false, - 'strict_param' => false, - ) - ->setFinder($finder) - ->setCacheFile(sys_get_temp_dir() . '/php-cs-fixer.' . md5(__DIR__) . '.cache');
View file
kolab-syncroton-2.4.2.tar.gz/bin
Deleted
-(directory)
View file
kolab-syncroton-2.4.2.tar.gz/bin/analyzelogs.php
Deleted
@@ -1,149 +0,0 @@ -#!/usr/bin/env php -<?php -/* - +--------------------------------------------------------------------------+ - | Kolab Sync (ActiveSync for Kolab) | - | | - | Copyright (C) 2024, Apheleia IT AG <contact@apheleia-it.ch> | - | | - | This program is free software: you can redistribute it and/or modify | - | it under the terms of the GNU Affero General Public License as published | - | by the Free Software Foundation, either version 3 of the License, or | - | (at your option) any later version. | - | | - | This program is distributed in the hope that it will be useful, | - | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | GNU Affero General Public License for more details. | - | | - | You should have received a copy of the GNU Affero General Public License | - | along with this program. If not, see <http://www.gnu.org/licenses/> | - +--------------------------------------------------------------------------+ - | Author: Christian Mollekopf <mollekopf@apheleia-it.ch> | - +--------------------------------------------------------------------------+ -*/ - - -define('RCUBE_INSTALL_PATH', realpath(dirname(__FILE__) . '/../') . '/'); - -// Define include path -$include_path = RCUBE_INSTALL_PATH . 'lib' . PATH_SEPARATOR; -$include_path .= RCUBE_INSTALL_PATH . 'lib/ext' . PATH_SEPARATOR; -$include_path .= ini_get('include_path'); -set_include_path($include_path); - -require_once "Syncroton/Command/ICommand.php"; -require_once "Syncroton/Command/Wbxml.php"; -require_once "Syncroton/Command/Sync.php"; -require_once "Syncroton/Command/Ping.php"; -require_once "Syncroton/Command/MoveItems.php"; -require_once "Syncroton/Command/FolderSync.php"; - -$filename = $argv1; - -$content = file_get_contents($filename); - -// Split up the log files into chunks that hopefully match the commands -$parts = preg_split("/\.*\: " . preg_quote("DEBUG Syncroton_Server::handle::65 REQUEST METHOD: POST", '/') . "/", $content, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); - -function getStatusConstants($classname) -{ - $reflect = new ReflectionClass($classname); - $result = $reflect->getConstants(); - $result = array_filter($result, function ($val) { - return str_starts_with($val, "STATUS_"); - }, ARRAY_FILTER_USE_KEY); - $result = array_flip($result); - return $result; -} - -function explainStatus($command, $status) -{ - if (!$status) { - return "none"; - } - switch ($command) { - case "Ping": - $result = getStatusConstants("Syncroton_Command_Ping"); - return $result$status ?? "Unknown"; - case "Sync": - $result = getStatusConstants("Syncroton_Command_Sync"); - return $result$status ?? "Unknown"; - case "MoveItems": - $result = getStatusConstants("Syncroton_Command_MoveItems"); - return $result$status ?? "Unknown"; - case "FolderSync": - $result = getStatusConstants("Syncroton_Command_FolderSync"); - return $result$status ?? "Unknown"; - } - return "Unknown command"; -} - -foreach ($parts as $part) { - preg_match('/\(.*)\: /', $part, $matches); - $timestamp = $matches1; - - preg_match('/\command\ => (.*)/', $part, $matches); - $command = $matches1; - - preg_match('/\<Status\>(.*)\<\/Status\>/', $part, $matches); - $status = $matches1 ?? null; - - $statusExplained = explainStatus($command, $status); - - print(" Command: " . str_pad($command, 10) . str_pad("\tStatus: $status ($statusExplained)", 45) . "\tTimestamp: $timestamp\n"); - if ($command == "Sync") { - // Find collections within this sync - // 25-Sep-2024 09:16:35.347730: INFO Syncroton_Command_Sync::handle::221 SyncKey is 7301 Class: Email CollectionId: 38b950ebd62cd9a66929c89615d0fc04 - if (preg_match_all('/SyncKey is (.*) Class: (.*) CollectionId: (.*)/', $part, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { - foreach ($matches as $set) { - $offset = $set01; - $collectionId = $set30; - $class = $set20; - $synckey = $set10; - print(str_pad(" Collection: $collectionId ($class)", 58) . "\tSyncKey: $synckey\n"); - - //Find the offset for this collections messages - if (preg_match("/Processing $collectionId\.\.\./", $part, $match, PREG_OFFSET_CAPTURE, $offset)) { - // print_r($match); - $offset = $match01 ?? null; - //Find the actual changes - if ($offset && preg_match('/found \(added\/changed\/deleted\) (.*)\/(.*)\/(.*) entries for sync from server to client/', $part, $changesMatch, PREG_OFFSET_CAPTURE, $offset)) { - // If the offset is too large we are looking at the next collection. - if ($changesMatch01 - $offset < 200) { - print(" " . $changesMatch00 . "\n"); - } - } - } - //TODO We could figure out what the diff per collection was in terms of synckey to the last sync - //TODO We could figure out what we actually return in the response compared to the detected changeset - //TODO Warn if a collection is repeatedly synced with the same synckey, but changes are detected. It may be stuck in a sync loop. - } - } - - // Detect entries that are being added from the client - if (preg_match_all('/found (.*) entries to be added on server/', $part, $matches)) { - foreach ($matches0 ?? as $match) { - print(" " . $match . "\n"); - } - } - - if (preg_match_all('/found (.*) entries to be updated on server/', $part, $matches)) { - foreach ($matches0 ?? as $match) { - print(" " . $match . "\n"); - } - } - - if (preg_match_all('/found (.*) entries to be deleted on server/', $part, $matches)) { - foreach ($matches0 ?? as $match) { - print(" " . $match . "\n"); - } - } - } - //TODO on Sync: - //* number of Add/Change/Remove from client and from server - //* Synckey - //* list involved folders - //TODO on Sync: - //* Reason for interruption -}
View file
kolab-syncroton-2.4.2.tar.gz/bin/delete-device.php
Deleted
@@ -1,97 +0,0 @@ -#!/usr/bin/env php -<?php -/* - +--------------------------------------------------------------------------+ - | Kolab Sync (ActiveSync for Kolab) | - | | - | Copyright (C) 2024, Apheleia IT AG <contact@apheleia-it.ch> | - | | - | This program is free software: you can redistribute it and/or modify | - | it under the terms of the GNU Affero General Public License as published | - | by the Free Software Foundation, either version 3 of the License, or | - | (at your option) any later version. | - | | - | This program is distributed in the hope that it will be useful, | - | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | GNU Affero General Public License for more details. | - | | - | You should have received a copy of the GNU Affero General Public License | - | along with this program. If not, see <http://www.gnu.org/licenses/> | - +--------------------------------------------------------------------------+ - | Author: Christian Mollekopf <mollekopf@apheleia-it.ch> | - +--------------------------------------------------------------------------+ -*/ - - -define('RCUBE_INSTALL_PATH', realpath(dirname(__FILE__) . '/../') . '/'); -define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'lib/plugins/'); - -// Define include path -$include_path = RCUBE_INSTALL_PATH . 'lib' . PATH_SEPARATOR; -$include_path .= RCUBE_INSTALL_PATH . 'lib/ext' . PATH_SEPARATOR; -$include_path .= ini_get('include_path'); -set_include_path($include_path); - -// include composer autoloader (if available) -if (@file_exists(RCUBE_INSTALL_PATH . 'vendor/autoload.php')) { - require RCUBE_INSTALL_PATH . 'vendor/autoload.php'; -} - -// include global functions from Roundcube Framework -require_once 'Roundcube/bootstrap.php'; - -$opts = rcube_utils::get_opt( - 's' => 'since', // Deletes *all* devices that haven't been used since the given timestamp. Doesn't take owner and device id into account. Timestamp format e.g.: "2024-11-01" - 'o' => 'owner', - 'd' => 'deviceid', -); - -$rcube = \rcube::get_instance(); -$db = $rcube->get_dbh(); - -if (!empty($opts'since')) { - $since = $opts'since'; - $since = new DateTime($since); - print("Removing all devices that haven't been used since: " . $since->format('Y-m-d H:i:s') . "\n"); - - $db->query( - "DELETE FROM `syncroton_device`" - . " WHERE `lastping` < ? OR `lastping` = NULL", - $since->format('Y-m-d H:i:s') - ); - return; -} - -if (empty($opts'deviceid')) { - rcube::raise_error("Device id not specified (--deviceid).", false, true); -} -$device = $opts'deviceid'; - -if (empty($opts'owner')) { - rcube::raise_error("owner not specified (--owner).", false, true); -} -$owner = $opts'owner'; - -$select = $db->query( - "SELECT `user_id` FROM `users`" - . " WHERE `username` = ?" - . " ORDER BY `user_id` DESC", - \strtolower($owner) -); - -if ($data = $db->fetch_assoc($select)) { - $userid = $data'user_id'; -} else { - rcube::raise_error("User not found in roundcube database, aborting: $email.", false, true); -} - -print("Found the user with id: $userid\n"); - -$db->query( - "DELETE FROM syncroton_device WHERE owner_id = ? AND deviceid = ?", - $userid, - $device -); - -print("Deleted the device with the deviceid: $deviceid\n");
View file
kolab-syncroton-2.4.2.tar.gz/bin/inspect.php
Deleted
@@ -1,343 +0,0 @@ -#!/usr/bin/env php -<?php -/* - +--------------------------------------------------------------------------+ - | Kolab Sync (ActiveSync for Kolab) | - | | - | Copyright (C) 2024, Apheleia IT AG <contact@apheleia-it.ch> | - | | - | This program is free software: you can redistribute it and/or modify | - | it under the terms of the GNU Affero General Public License as published | - | by the Free Software Foundation, either version 3 of the License, or | - | (at your option) any later version. | - | | - | This program is distributed in the hope that it will be useful, | - | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | GNU Affero General Public License for more details. | - | | - | You should have received a copy of the GNU Affero General Public License | - | along with this program. If not, see <http://www.gnu.org/licenses/> | - +--------------------------------------------------------------------------+ - | Author: Christian Mollekopf <mollekopf@apheleia-it.ch> | - +--------------------------------------------------------------------------+ -*/ - - -define('RCUBE_INSTALL_PATH', realpath(dirname(__FILE__) . '/../') . '/'); -define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'lib/plugins/'); - -// Define include path -$include_path = RCUBE_INSTALL_PATH . 'lib' . PATH_SEPARATOR; -$include_path .= RCUBE_INSTALL_PATH . 'lib/ext' . PATH_SEPARATOR; -$include_path .= ini_get('include_path'); -set_include_path($include_path); - -// include composer autoloader (if available) -if (@file_exists(RCUBE_INSTALL_PATH . 'vendor/autoload.php')) { - require RCUBE_INSTALL_PATH . 'vendor/autoload.php'; -} - -// include global functions from Roundcube Framework -require_once 'Roundcube/bootstrap.php'; - - -function filterTypeToIMAPSearch($filter_type = 0) -{ - switch ($filter_type) { - case 1: - $mod = '-1 day'; - break; - case 2: - $mod = '-3 days'; - break; - case 3: - $mod = '-1 week'; - break; - case 4: - $mod = '-2 weeks'; - break; - case 5: - $mod = '-1 month'; - break; - } - - if (!empty($mod)) { - $dt = new DateTime('now', new DateTimeZone('UTC')); - $dt->modify($mod); - // RFC3501: IMAP SEARCH - return 'SINCE ' . $dt->format('d-M-Y'); - } - - return ""; -} - - -$opts = rcube_utils::get_opt( - 'e' => 'email', - 'p' => 'adminpassword', - 'd' => 'debug', -); - -if (empty($opts'email')) { - rcube::raise_error("Email address not specified (--email).", false, true); -} -$email = $opts'email'; - -$proxyAuth = false; -if ($password = $opts'adminpassword') { - $proxyAuth = true; - $user = "cyrus-admin"; -} else { - $password = $opts'password'; -} - -if (empty($password)) { - rcube::raise_error("Password not specified (--adminpassword/--password).", false, true); -} - -$rcube = rcube::get_instance(); -$default_port = $rcube->config->get('default_port', 143); -$default_host = $rcube->config->get('default_host'); -$imap = new \rcube_imap_generic(); -if ($proxyAuth) { - $options'auth_cid' = $user; - $options'auth_pw' = $password; -} -$options'auth_type' = 'PLAIN'; -$options'port' = $default_port; -$options'socket_options' = - 'ssl' => - 'verify_peer_name' => false, - 'verify_peer' => false, - 'allow_self_signed' => true, - , -; - -ini_set('display_errors', 1); -error_reporting(E_ALL); - -$debug = !empty($opts'debug'); - -$imap->setDebug($debug); -if (!$imap->connect($default_host, $email, $password, $options)) { - rcube::raise_error("Failed to connect to imap.", false, true); -} - -$rcube = \rcube::get_instance(); -$db = $rcube->get_dbh(); - -$select = $db->query( - "SELECT `user_id` FROM `users`" - . " WHERE `username` = ?" - . " ORDER BY `user_id` DESC", - \strtolower($email) -); - -if ($data = $db->fetch_assoc($select)) { - $userid = $data'user_id'; -} else { - rcube::raise_error("User not found in roundcube database (only available after first login): $email.", false, true); -} - -print("Found the user with id: $userid\n"); - -$devicesSelect = $db->query( - "SELECT `id`, `deviceid`, `devicetype` FROM `syncroton_device`" - . " WHERE `owner_id` = ?", - $userid -); - -$result = ; -while ($data = $db->fetch_assoc($devicesSelect)) { - $deviceid = $data"deviceid"; - $device_id = $data"id"; - - $result$device_id'deviceid' = $deviceid; - $result$device_id'devicetype' = $data"devicetype"; - - $select = $db->limitquery( - "SELECT `counter`, `lastsync` FROM `syncroton_synckey`" - . " WHERE `device_id` = ? AND `type` = 'FolderSync'" - . " ORDER BY `counter` DESC", - 0, - 1, - $device_id - ); - - if ($data = $db->fetch_assoc($select)) { - $result$device_id'FolderSync' = - "counter" => $data'counter', - "lastsync" => $data'lastsync', - ; - } else { - echo("Synckey not found.\n"); - } - - $folderSelect = $db->query( - "SELECT * FROM `syncroton_folder`" - . " WHERE `device_id` = ?", - $device_id - ); - - while ($folder = $db->fetch_assoc($folderSelect)) { - $select = $db->limitquery( - "SELECT `counter`, `lastsync`, `extra_data` FROM `syncroton_synckey`" - . " WHERE `device_id` = ? AND `type` = ?" - . " ORDER BY `counter` DESC", - 0, - 1, - $device_id, - $folder'id' - ); - - if ($data = $db->fetch_assoc($select)) { - $result$device_id'folders'$folder'id' = - "counter" => $data'counter', - "lastsync" => $data'lastsync', - "modseq" => $data'extra_data' ? json_decode($data'extra_data')->modseq : null, - ; - } - - $result$device_id'folders'$folder'id''name' = $folder'displayname'; - $result$device_id'folders'$folder'id''class' = $folder'class'; - $result$device_id'folders'$folder'id''lastfiltertype' = $folder'lastfiltertype' ?? null; - - $imap->select($folder'displayname'); - $result$device_id'folders'$folder'id''imapModseq' = $imap->data'HIGHESTMODSEQ' ?? null; - - $index = $imap->search( - $folder'displayname', - 'ALL UNDELETED ' . filterTypeToIMAPSearch($folder'lastfiltertype'), - false, - 'COUNT' - ); - if (!$index->is_error()) { - $result$device_id'folders'$folder'id''imapMessagecount' = $index->count(); - } - - $select = $db->query( - "SELECT count(*) FROM `syncroton_content`" - . " WHERE `device_id` = ? AND `folder_id` = ?", - $device_id, - $folder'id' - ); - - if ($data = $db->fetch_assoc($select)) { - $result$device_id'folders'$folder'id''contentCount' = array_values($data)0; - } - } -} - -if ($debug) { - var_export($result); -} - -function println($output) -{ - print("{$output}\n"); -} - -function filterType($value) -{ - if (!$value) { - return "No filter"; - } - switch($value) { - case 0: return "No filter"; - case 1: return "1 day"; - case 2: return "3 days"; - case 3: return "1 week"; - case 4: return "2 weeks"; - case 5: return "1 month"; - case 6: return "3 months (WARNING: not implemented)"; - case 7: return "6 months (WARNING: not implemented)"; - case 8: return "Filter by incomplete tasks"; - } - return "Unknown value: $value"; -} - -function getContentUids($db, $device_id, $folder_id) -{ - $contentSelect = $db->query( - "SELECT contentid FROM `syncroton_content`" - . " WHERE `device_id` = ? AND `folder_id` = ? AND `is_deleted` = 0", - $device_id, - $folder_id - ); - - $contentUids = ; - while ($content = $db->fetch_assoc($contentSelect)) { - $contentUids = explode('::', $content'contentid')1; - } - return $contentUids; -} - -function getImapUids($imap, $folder, $lastfiltertype) -{ - $imap->select($folder); - $index = $imap->search($folder, 'ALL UNDELETED ' . filterTypeToIMAPSearch($lastfiltertype), true); - if (!$index->is_error()) { - return $index->get(); - } - return ; -} - -println(""); -foreach ($result as $deviceId => $values) { - println("Device: $deviceId"); - println(" Last folder sync: " . $values'FolderSync''lastsync'); - println(" Folder sync count: " . $values'FolderSync''counter'); - println(" Folders:"); - foreach ($values'folders' ?? as $folderId => $folder) { - println(" " . $folder'name' . " ($folderId)"); - $messageCount = $folder'contentCount'; - $totalCount = $folder'imapMessagecount' ?? "unknown"; - $modseq = $folder'modseq' ?? "none"; - $imapModseq = $folder'imapModseq'; - // We're not using modseq for groupware folders - if ($messageCount == $totalCount && ($modseq == "none" || $modseq == $imapModseq)) { - println(" Status: Fully Synced ($messageCount messages)"); - } else { - println(" Status: Incomplete ($messageCount/$totalCount messages)"); - println(" Modseq: " . $modseq . "/" . $imapModseq); - } - println(" Last sync: " . ($folder'lastsync' ?? "None")); - println(" Number of syncs: " . ($folder'counter' ?? "None")); - println(" Filter type: " . filterType($folder'lastfiltertype' ?? null)); - - if (($folder'class' == "Email") && ($folder'counter' ?? false) && $messageCount != $totalCount && ($modseq == "none" || $modseq == $imapModseq)) { - if (($folder'lastfiltertype' ?? false) && $messageCount > $totalCount) { - // This doesn't have to indicate an issue, since the timewindow of the filter wanders, so some messages that have been synchronized may no longer match the window. - } else { - println(" Issue Detected: The sync state seems to be inconsistent. The device should be fully synced, but the sync counts differ."); - println(" There are $messageCount ContentParts (should match number of messages on the device), but $totalCount messages in IMAP matching the filter."); - - $contentUids = getContentUids($db, $deviceId, $folderId); - $imapUids = getImapUids($imap, $folder'name', $folder'lastfiltertype' ?? null); - - $entries = array_diff($imapUids, $contentUids); - if (!empty($entries)) { - println(" The following messages are on the server, but not the device:"); - foreach ($entries as $uid) { - println(" $uid"); - //TODO get details from imap? - } - } - - $entries = array_diff($contentUids, $imapUids); - if (!empty($entries)) { - println(" The following messages are on the device, but not the server:"); - foreach ($entries as $uid) { - println(" $uid"); - //TODO get details from the content part? - //TODO display creation_synckey? - } - } - println(""); - } - } - - println(""); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/bin/resync.php
Deleted
@@ -1,116 +0,0 @@ -#!/usr/bin/php -<?php -/* - +--------------------------------------------------------------------------+ - | Kolab Sync (ActiveSync for Kolab) | - | | - | Copyright (C) 2024, Apheleia IT AG <contact@apheleia-it.ch> | - | | - | This program is free software: you can redistribute it and/or modify | - | it under the terms of the GNU Affero General Public License as published | - | by the Free Software Foundation, either version 3 of the License, or | - | (at your option) any later version. | - | | - | This program is distributed in the hope that it will be useful, | - | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | GNU Affero General Public License for more details. | - | | - | You should have received a copy of the GNU Affero General Public License | - | along with this program. If not, see <http://www.gnu.org/licenses/> | - +--------------------------------------------------------------------------+ - | Author: Aleksander Machniak <machniak@apheleia-it.ch> | - +--------------------------------------------------------------------------+ -*/ - -define('RCUBE_INSTALL_PATH', realpath(dirname(__FILE__) . '/../') . '/'); -define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'lib/plugins/'); - -// Define include path -$include_path = RCUBE_INSTALL_PATH . 'lib' . PATH_SEPARATOR; -$include_path .= RCUBE_INSTALL_PATH . 'lib/ext' . PATH_SEPARATOR; -$include_path .= ini_get('include_path'); -set_include_path($include_path); - -// include composer autoloader (if available) -if (@file_exists(RCUBE_INSTALL_PATH . 'vendor/autoload.php')) { - require RCUBE_INSTALL_PATH . 'vendor/autoload.php'; -} - -// include global functions from Roundcube Framework -require_once 'Roundcube/bootstrap.php'; - -$opts = rcube_utils::get_opt( - 'o' => 'owner', - 'f' => 'folder', - 'd' => 'deviceid', - 't' => 'devicetype', // e.g. WindowsOutlook15 or iPhone -); - -$rcube = \rcube::get_instance(); -$db = $rcube->get_dbh(); - -if (empty($opts'owner')) { - rcube::raise_error("Owner not specified (--owner).", false, true); -} -if (empty($opts'folder')) { - rcube::raise_error("Folder name not specified (--folder).", false, true); -} - -$select = $db->query( - "SELECT `user_id` FROM `users` WHERE `username` = ? ORDER BY `user_id` DESC", - \strtolower($opts'owner') -); - -if ($data = $db->fetch_assoc($select)) { - $userid = $data'user_id'; -} else { - rcube::raise_error("User not found in Roundcube database.", false, true); -} - -$devices = ; -if (!empty($opts'deviceid')) { - $select = $db->query( - "SELECT `id` FROM `syncroton_device` WHERE `owner_id` = ? AND `deviceid` = ?", - $userid, - $opts'deviceid' - ); - while ($record = $db->fetch_assoc($select)) { - $devices = $record'id'; - } -} elseif (!empty($opts'devicetype')) { - $select = $db->query( - "SELECT `id` FROM `syncroton_device` WHERE `owner_id` = ? AND `devicetype` = ?", - $userid, - $opts'devicetype' - ); - while ($record = $db->fetch_assoc($select)) { - $devices = $record'id'; - } -} else { - $select = $db->query("SELECT `id` FROM `syncroton_device` WHERE `owner_id` = ?", $userid); - while ($record = $db->fetch_assoc($select)) { - $devices = $record'id'; - } -} - -if (empty($devices)) { - rcube::raise_error("Device not found.", false, true); -} - -// TODO: Support not only top-level folders - -$select = $db->query( - "SELECT `id`, `displayname`, `folderid` FROM `syncroton_folder`" - . " WHERE `device_id` IN (" . $db->array2list($devices) . ")" - . " AND `parentid` = '0' AND `displayname` = " . $db->quote($opts'folder') -); - -while ($record = $db->fetch_assoc($select)) { - if (!empty($opts'dry-run')) { - print("DRY-RUN {$record'displayname'} ({$record'id'}:{$record'folderid'})\n"); - } else { - $db->query("UPDATE `syncroton_folder` SET `resync` = 1 WHERE id = ?", $record'id'); - print("{$record'displayname'} ({$record'id'}:{$record'folderid'})\n"); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/docs/SQL/mysql/2023100500.sql
Deleted
@@ -1,2 +0,0 @@ - -ALTER TABLE `syncroton_synckey` ADD `client_id_map` longblob DEFAULT NULL;
View file
kolab-syncroton-2.4.2.tar.gz/docs/SQL/mysql/2024031100.sql
Deleted
@@ -1,3 +0,0 @@ - -ALTER TABLE `syncroton_synckey` ADD `extra_data` longblob DEFAULT NULL; -DROP TABLE `syncroton_modseq`;
View file
kolab-syncroton-2.4.2.tar.gz/docs/SQL/mysql/2024101700.sql
Deleted
@@ -1,1 +0,0 @@ -ALTER TABLE `syncroton_folder` ADD `resync` tinyint(1) DEFAULT NULL;
View file
kolab-syncroton-2.4.2.tar.gz/docs/SQL/mysql/2024102300.sql
Deleted
@@ -1,1 +0,0 @@ -ALTER TABLE `syncroton_folder` ADD `creation_synckey` int(11) NOT NULL DEFAULT '0';
View file
kolab-syncroton-2.4.2.tar.gz/lib/ext/Syncroton/Exception/DeadlockDetected.php
Deleted
@@ -1,20 +0,0 @@ -<?php -/** - * Syncroton - * - * @package Syncroton - * @subpackage Exception - * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3 - * @copyright Copyright (c) 2013-2013 Metaways Infosystems GmbH (http://www.metaways.de) - * @author Lars Kneschke <l.kneschke@metaways.de> - */ - -/** - * exception for database deadlocks - * - * @package Syncroton - * @subpackage Exception - */ -class Syncroton_Exception_DeadlockDetected extends Syncroton_Exception -{ -}
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_storage.php
Deleted
@@ -1,2066 +0,0 @@ -<?php - -/* - +--------------------------------------------------------------------------+ - | Kolab Sync (ActiveSync for Kolab) | - | | - | Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> | - | | - | This program is free software: you can redistribute it and/or modify | - | it under the terms of the GNU Affero General Public License as published | - | by the Free Software Foundation, either version 3 of the License, or | - | (at your option) any later version. | - | | - | This program is distributed in the hope that it will be useful, | - | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | GNU Affero General Public License for more details. | - | | - | You should have received a copy of the GNU Affero General Public License | - | along with this program. If not, see <http://www.gnu.org/licenses/> | - +--------------------------------------------------------------------------+ - | Author: Aleksander Machniak <machniak@kolabsys.com> | - +--------------------------------------------------------------------------+ -*/ - -/** - * Storage handling class with basic Kolab support (everything stored in IMAP) - */ -class kolab_sync_storage -{ - public const INIT_SUB_PERSONAL = 1; // all subscribed folders in personal namespace - public const INIT_ALL_PERSONAL = 2; // all folders in personal namespace - public const INIT_SUB_OTHER = 4; // all subscribed folders in other users namespace - public const INIT_ALL_OTHER = 8; // all folders in other users namespace - public const INIT_SUB_SHARED = 16; // all subscribed folders in shared namespace - public const INIT_ALL_SHARED = 32; // all folders in shared namespace - - public const MODEL_CALENDAR = 'event'; - public const MODEL_CONTACTS = 'contact'; - public const MODEL_EMAIL = 'mail'; - public const MODEL_NOTES = 'note'; - public const MODEL_TASKS = 'task'; - - public const ROOT_MAILBOX = 'INBOX'; - public const ASYNC_KEY = '/private/vendor/kolab/activesync'; - public const UID_KEY = '/shared/vendor/cmu/cyrus-imapd/uniqueid'; - - public const CTYPE_KEY = '/shared/vendor/kolab/folder-type'; - public const CTYPE_KEY_PRIVATE = '/private/vendor/kolab/folder-type'; - - public $syncTimeStamp; - - protected $storage; - protected $folder_meta; - protected $folder_uids; - protected $folders = ; - protected $root_meta; - protected $relations = ; - public $relationSupport = true; - protected $tag_rts = ; - private $modseq = ; - - protected static $instance; - - protected static $types = - 1 => '', - 2 => 'mail.inbox', - 3 => 'mail.drafts', - 4 => 'mail.wastebasket', - 5 => 'mail.sentitems', - 6 => 'mail.outbox', - 7 => 'task.default', - 8 => 'event.default', - 9 => 'contact.default', - 10 => 'note.default', - 11 => 'journal.default', - 12 => 'mail', - 13 => 'event', - 14 => 'contact', - 15 => 'task', - 16 => 'journal', - 17 => 'note', - ; - - - /** - * This implements the 'singleton' design pattern - * - * @return kolab_sync_storage The one and only instance - */ - public static function get_instance() - { - if (!self::$instance) { - self::$instance = new kolab_sync_storage(); - self::$instance->startup(); // init AFTER object was linked with self::$instance - } - - return self::$instance; - } - - /** - * Class initialization - */ - public function startup() - { - $this->storage = kolab_sync::get_instance()->get_storage(); - - // set additional header used by libkolab - $this->storage->set_options( - // @TODO: there can be Roundcube plugins defining additional headers, - // we maybe would need to add them here - 'fetch_headers' => 'X-KOLAB-TYPE X-KOLAB-MIME-VERSION', - 'skip_deleted' => true, - 'threading' => false, - ); - - // Disable paging - $this->storage->set_pagesize(999999); - } - - /** - * Clear internal cache state - */ - public function reset() - { - $this->folders = ; - } - - /** - * List known devices - * - * @return array Device list as hash array - */ - public function devices_list() - { - if ($this->root_meta === null) { - // @TODO: consider server annotation instead of INBOX - if ($meta = $this->storage->get_metadata(self::ROOT_MAILBOX, self::ASYNC_KEY)) { - $this->root_meta = $this->unserialize_metadata($metaself::ROOT_MAILBOXself::ASYNC_KEY); - } else { - $this->root_meta = ; - } - } - - if (!empty($this->root_meta'DEVICE') && is_array($this->root_meta'DEVICE')) { - return $this->root_meta'DEVICE'; - } - - return ; - } - - /** - * Get list of folders available for sync - * - * @param string $deviceid Device identifier - * @param string $type Folder type - * @param bool $flat_mode Enables flat-list mode - * - * @return array|bool List of mailbox folders, False on backend failure - */ - public function folders_list($deviceid, $type, $flat_mode = false) - { - // get all folders of specified type - $folders = kolab_storage::list_folders('', '*', $type, false, $typedata); - - // get folders activesync config - $folderdata = $this->folder_meta(); - - if (!is_array($folders) || !is_array($folderdata)) { - return false; - } - - $folders_list = ; - - // check if folders are "subscribed" for activesync - foreach ($folderdata as $folder => $meta) { - if (empty($meta'FOLDER') || empty($meta'FOLDER'$deviceid) - || empty($meta'FOLDER'$deviceid'S') - ) { - continue; - } - - // force numeric folder name to be a string (T1283) - $folder = (string) $folder; - - if (!empty($type) && !in_array($folder, $folders)) { - continue; - } - - // Activesync folder identifier (serverId) - $folder_type = !empty($typedata$folder) ? $typedata$folder : 'mail'; - $folder_id = $this->folder_id($folder, $folder_type); - - $folders_list$folder_id = $this->folder_data($folder, $folder_type); - } - - if ($flat_mode) { - $folders_list = $this->folders_list_flat($folders_list, $type, $typedata); - } - - return $folders_list; - } - - /** - * Converts list of folders to a "flat" list - */ - protected function folders_list_flat($folders, $type, $typedata) - { - $delim = $this->storage->get_hierarchy_delimiter(); - - foreach ($folders as $idx => $folder) { - if ($folder'parentId') { - // for non-mail folders we make the list completely flat - if ($type != self::MODEL_EMAIL) { - $display_name = kolab_storage::object_name($folder'imap_name'); - $display_name = html_entity_decode($display_name, ENT_COMPAT, RCUBE_CHARSET); - - $folders$idx'parentId' = 0; - $folders$idx'displayName' = $display_name; - } - // for mail folders we modify only folders with non-existing parents - elseif (!isset($folders$folder'parentId')) { - $items = explode($delim, $folder'imap_name'); - $parent = 0; - - // find existing parent - while (count($items) > 0) { - array_pop($items); - - $parent_name = implode($delim, $items); - $parent_type = !empty($typedata$parent_name) ? $typedata$parent_name : 'mail'; - $parent_id = $this->folder_id($parent_name, $parent_type); - - if (isset($folders$parent_id)) { - $parent = $parent_id; - break; - } - } - - if (!$parent) { - $display_name = kolab_storage::object_name($folder'imap_name'); - $display_name = html_entity_decode($display_name, ENT_COMPAT, RCUBE_CHARSET); - } else { - $parent_name = isset($parent_id) ? $folders$parent_id'imap_name' : ''; - $display_name = substr($folder'imap_name', strlen($parent_name) + 1); - $display_name = rcube_charset::convert($display_name, 'UTF7-IMAP'); - $display_name = str_replace($delim, ' » ', $display_name); - } - - $folders$idx'parentId' = $parent; - $folders$idx'displayName' = $display_name; - } - } - } - - return $folders; - } - - /** - * Getter for folder metadata - * - * @return array|bool Hash array with meta data for each folder, False on backend failure - */ - protected function folder_meta() - { - if (!isset($this->folder_meta)) { - // get folders activesync config - $folderdata = $this->storage->get_metadata("*", self::ASYNC_KEY); - - if (!is_array($folderdata)) { - return $this->folder_meta = false; - } - - $this->folder_meta = ; - - foreach ($folderdata as $folder => $meta) { - if (isset($metaself::ASYNC_KEY)) { - if ($metadata = $this->unserialize_metadata($metaself::ASYNC_KEY)) { - $this->folder_meta$folder = $metadata; - } - } - } - } - - return $this->folder_meta; - } - - /** - * Creates folder and subscribes to the device - * - * @param string $name Folder name (UTF8) - * @param int $type Folder (ActiveSync) type - * @param string $deviceid Device identifier - * @param ?string $parentid Parent folder id identifier - * - * @return string|false New folder identifier on success, False on failure - */ - public function folder_create($name, $type, $deviceid, $parentid = null) - { - $parent = null; - $name = rcube_charset::convert($name, kolab_sync::CHARSET, 'UTF7-IMAP'); - - if ($parentid) { - $parent = $this->folder_id2name($parentid, $deviceid); - - if ($parent === null) { - throw new Syncroton_Exception_Status_FolderCreate(Syncroton_Exception_Status_FolderCreate::PARENT_NOT_FOUND); - } - } - - if ($parent !== null) { - $delim = $this->storage->get_hierarchy_delimiter(); - $name = $parent . $delim . $name; - } - - if ($this->storage->folder_exists($name)) { - throw new Syncroton_Exception_Status_FolderCreate(Syncroton_Exception_Status_FolderCreate::FOLDER_EXISTS); - } - - $type = self::type_activesync2kolab($type); - $created = kolab_storage::folder_create($name, $type, true); - - if ($created) { - // Set ActiveSync subscription flag - $this->folder_set($name, $deviceid, 1); - - return $this->folder_id($name, $type); - } - - // Special case when client tries to create a subfolder of INBOX - // which is not possible on Cyrus-IMAP (T2223) - if ($parent === 'INBOX' && stripos($this->last_error(), 'invalid') !== false) { - throw new Syncroton_Exception_Status_FolderCreate(Syncroton_Exception_Status_FolderCreate::SPECIAL_FOLDER); - } - - return false; - } - - /** - * Renames a folder - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $new_name New folder name (UTF8) - * @param ?string $parentid Folder parent identifier - * - * @return bool True on success, False on failure - */ - public function folder_rename($folderid, $deviceid, $new_name, $parentid) - { - $old_name = $this->folder_id2name($folderid, $deviceid); - - if ($parentid) { - $parent = $this->folder_id2name($parentid, $deviceid); - } - - $name = rcube_charset::convert($new_name, kolab_sync::CHARSET, 'UTF7-IMAP'); - - if (isset($parent)) { - $delim = $this->storage->get_hierarchy_delimiter(); - $name = $parent . $delim . $name; - } - - // Rename/move IMAP folder - if ($name === $old_name) { - return true; - } - - $this->folder_meta = null; - - // TODO: folder type change? - - $type = kolab_storage::folder_type($old_name); - - // don't use kolab_storage for moving mail folders - if (preg_match('/^mail/', $type)) { - return $this->storage->rename_folder($old_name, $name); - } else { - return kolab_storage::folder_rename($old_name, $name); - } - } - - /** - * Deletes folder - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * - * @return bool True on success, False otherwise - */ - public function folder_delete($folderid, $deviceid) - { - $name = $this->folder_id2name($folderid, $deviceid); - $type = kolab_storage::folder_type($name); - - unset($this->folder_meta$name); - - // don't use kolab_storage for deleting mail folders - if (preg_match('/^mail/', $type)) { - return $this->storage->delete_folder($name); - } - - return kolab_storage::folder_delete($name); - } - - /** - * Deletes contents of a folder - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param bool $recursive Apply to the folder and its subfolders - * - * @return bool True on success, False otherwise - */ - public function folder_empty($folderid, $deviceid, $recursive = false) - { - $foldername = $this->folder_id2name($folderid, $deviceid); - - // Remove all entries - if (!$this->storage->clear_folder($foldername)) { - return false; - } - - // Remove subfolders - if ($recursive) { - $delim = $this->storage->get_hierarchy_delimiter(); - $folderdata = $this->folder_meta(); - - if (!is_array($folderdata)) { - return false; - } - - foreach ($folderdata as $subfolder => $meta) { - if (!empty($meta'FOLDER'$deviceid'S') && strpos((string) $subfolder, $foldername . $delim)) { - if (!$this->storage->clear_folder((string) $subfolder)) { - return false; - } - } - } - } - - return true; - } - - /** - * Sets ActiveSync subscription flag on a folder - * - * @param string $name Folder name (UTF7-IMAP) - * @param string $deviceid Device identifier - * @param int $flag Flag value (0|1|2) - * - * @return bool True on success, False on failure - */ - protected function folder_set($name, $deviceid, $flag) - { - if (empty($deviceid)) { - return false; - } - - // get folders activesync config - $metadata = $this->folder_meta(); - - if (!is_array($metadata)) { - return false; - } - - $metadata = $metadata$name ?? ; - - if ($flag) { - if (empty($metadata)) { - $metadata = ; - } - - if (empty($metadata'FOLDER')) { - $metadata'FOLDER' = ; - } - - if (empty($metadata'FOLDER'$deviceid)) { - $metadata'FOLDER'$deviceid = ; - } - - // Z-Push uses: - // 1 - synchronize, no alarms - // 2 - synchronize with alarms - $metadata'FOLDER'$deviceid'S' = $flag; - } else { - unset($metadata'FOLDER'$deviceid'S'); - - if (empty($metadata'FOLDER'$deviceid)) { - unset($metadata'FOLDER'$deviceid); - } - - if (empty($metadata'FOLDER')) { - unset($metadata'FOLDER'); - } - - if (empty($metadata)) { - $metadata = null; - } - } - - // Return if nothing's been changed - if (!self::data_array_diff($this->folder_meta$name ?? null, $metadata)) { - return true; - } - - $this->folder_meta$name = $metadata; - - return $this->storage->set_metadata($name, self::ASYNC_KEY => $this->serialize_metadata($metadata)); - } - - /** - * Returns device metadata - * - * @param string $id Device ID - * - * @return array|null Device metadata - */ - public function device_get($id) - { - $devices_list = $this->devices_list(); - return $devices_list$id ?? null; - } - - /** - * Registers new device on server - * - * @param array $device Device data - * @param string $id Device ID - * - * @return bool True on success, False on failure - */ - public function device_create($device, $id) - { - // Fill local cache - $this->devices_list(); - - // Some devices create dummy devices with name "validate" (#1109) - // This device entry is used in two initial requests, but later - // the device registers a real name. We can remove this dummy entry - // on new device creation - $this->device_delete('validate'); - - // Old Kolab_ZPush device parameters - // MODE: -1 | 0 | 1 (not set | flatmode | foldermode) - // TYPE: device type string - // ALIAS: user-friendly device name - - // Syncroton (kolab_sync_backend_device) uses - // ID: internal identifier in syncroton database - // TYPE: device type string - // ALIAS: user-friendly device name - - $metadata = $this->root_meta; - $metadata'DEVICE'$id = $device; - $metadata = self::ASYNC_KEY => $this->serialize_metadata($metadata); - - $result = $this->storage->set_metadata(self::ROOT_MAILBOX, $metadata); - - if ($result) { - // Update local cache - $this->root_meta'DEVICE'$id = $device; - - // subscribe default set of folders - $this->device_init_subscriptions($id); - } - - return $result; - } - - /** - * Device update. - * - * @param array $device Device data - * @param string $id Device ID - * - * @return bool True on success, False on failure - */ - public function device_update($device, $id) - { - $devices_list = $this->devices_list(); - $old_device = $devices_list$id; - - if (!$old_device) { - return false; - } - - // Do nothing if nothing is changed - if (!self::data_array_diff($old_device, $device)) { - return true; - } - - $device = array_merge($old_device, $device); - - $metadata = $this->root_meta; - $metadata'DEVICE'$id = $device; - $metadata = self::ASYNC_KEY => $this->serialize_metadata($metadata); - - $result = $this->storage->set_metadata(self::ROOT_MAILBOX, $metadata); - - if ($result) { - // Update local cache - $this->root_meta'DEVICE'$id = $device; - } - - return $result; - } - - /** - * Device delete. - * - * @param string $id Device ID - * - * @return bool True on success, False on failure - */ - public function device_delete($id) - { - $device = $this->device_get($id); - - if (!$device) { - return false; - } - - unset($this->root_meta'DEVICE'$id, $this->root_meta'FOLDER'$id); - - if (empty($this->root_meta'DEVICE')) { - unset($this->root_meta'DEVICE'); - } - if (empty($this->root_meta'FOLDER')) { - unset($this->root_meta'FOLDER'); - } - - $metadata = $this->serialize_metadata($this->root_meta); - $metadata = self::ASYNC_KEY => $metadata; - - // update meta data - $result = $this->storage->set_metadata(self::ROOT_MAILBOX, $metadata); - - if ($result) { - // remove device annotation for every folder - foreach ($this->folder_meta() as $folder => $meta) { - // skip root folder (already handled above) - if ($folder == self::ROOT_MAILBOX) { - continue; - } - - if (!empty($meta'FOLDER') && isset($meta'FOLDER'$id)) { - unset($meta'FOLDER'$id); - - if (empty($meta'FOLDER')) { - unset($this->folder_meta$folder'FOLDER'); - unset($meta'FOLDER'); - } - if (empty($meta)) { - unset($this->folder_meta$folder); - $meta = null; - } - - $metadata = self::ASYNC_KEY => $this->serialize_metadata($meta); - $res = $this->storage->set_metadata($folder, $metadata); - - if ($res && $meta) { - $this->folder_meta$folder = $meta; - } - } - } - } - - return $result; - } - - /** - * Creates an item in a folder. - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $type Activesync model name (folder type) - * @param string|array $data Object data (string for email, array for other types) - * @param array $params Additional parameters (e.g. mail flags) - * - * @return string|null Item UID on success or null on failure - */ - public function createItem($folderid, $deviceid, $type, $data, $params = ) - { - if ($type == self::MODEL_EMAIL) { - $foldername = $this->folder_id2name($folderid, $deviceid); - - $uid = $this->storage->save_message($foldername, $data, '', false, $params'flags' ?? ); - - if (!$uid) { - // $this->logger->error("Error while storing the message " . $this->storage->get_error_str()); - } - - return $uid; - } - - $useTags = $this->relationSupport && ($type == self::MODEL_TASKS || $type == self::MODEL_NOTES); - - // convert categories into tags, save them after creating an object - if ($useTags && !empty($data'categories')) { - $tags = $data'categories'; - unset($data'categories'); - } - - $folder = $this->getFolder($folderid, $deviceid, $type); - - // Set User-Agent for saved objects - $app = kolab_sync::get_instance(); - $app->config->set('useragent', $app->app_name . ' ' . kolab_sync::VERSION); - - if ($folder && $folder->valid && $folder->save($data)) { - if (!empty($tags) && ($type == self::MODEL_TASKS || $type == self::MODEL_NOTES)) { - $this->setCategories($data'uid', $tags); - } - - return $data'uid'; - } - - return null; - } - - /** - * Deletes an item from a folder by UID. - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $type Activesync model name (folder type) - * @param string $uid Requested object UID - * @param bool $moveToTrash Move to trash, instead of delete (for mail messages only) - * - * @return bool True on success, False on failure - */ - public function deleteItem($folderid, $deviceid, $type, $uid, $moveToTrash = false) - { - if ($type == self::MODEL_EMAIL) { - $foldername = $this->folder_id2name($folderid, $deviceid); - $trash = kolab_sync::get_instance()->config->get('trash_mbox'); - - // move message to the Trash folder - if ($moveToTrash && strlen($trash) && $trash != $foldername && $this->storage->folder_exists($trash)) { - return $this->storage->move_message($uid, $trash, $foldername); - } - - // delete the message - // According to the ActiveSync spec. "If the DeletesAsMoves element is set to false, - // the deletion is PERMANENT.", therefore we delete the message, and not flag as deleted. - - // FIXME: We could consider acting according to the 'flag_for_deletion' setting. - // Don't forget about 'read_when_deleted' setting then. - // $this->storage->set_flag($uid, 'DELETED', $foldername); - // $this->storage->set_flag($uid, 'SEEN', $foldername); - return $this->storage->delete_message($uid, $foldername); - } - - $useTags = $this->relationSupport && ($type == self::MODEL_TASKS || $type == self::MODEL_NOTES); - - $folder = $this->getFolder($folderid, $deviceid, $type); - - if (!$folder || !$folder->valid) { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - - if ($folder->delete($uid)) { - if ($useTags) { - $this->setCategories($uid, ); - } - - return true; - } - - return false; - } - - /** - * Updates an item in a folder. - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $type Activesync model name (folder type) - * @param string $uid Object UID - * @param string|array $data Object data (string for email, array for other types) - * @param array $params Additional parameters (e.g. mail flags) - * - * @return string|null Item UID on success or null on failure - */ - public function updateItem($folderid, $deviceid, $type, $uid, $data, $params = ) - { - if ($type == self::MODEL_EMAIL) { - $foldername = $this->folder_id2name($folderid, $deviceid); - - // Note: We do not support a message body update, as it's not needed - - foreach (($params'flags' ?? ) as $flag) { - $this->storage->set_flag($uid, $flag, $foldername); - } - - // Categories (Tags) change - if (isset($params'categories') && $this->relationSupport) { - $message = new rcube_message($uid, $foldername); - - if (empty($message->headers)) { - throw new Syncroton_Exception_Status_Sync(Syncroton_Exception_Status_Sync::SYNC_SERVER_ERROR); - } - - $this->setCategories($message, $params'categories'); - } - - return $uid; - } - - $folder = $this->getFolder($folderid, $deviceid, $type); - - $useTags = $this->relationSupport && ($type == self::MODEL_TASKS || $type == self::MODEL_NOTES); - - // convert categories into tags, save them after updating an object - if ($useTags && array_key_exists('categories', $data)) { - $tags = (array) $data'categories'; - unset($data'categories'); - } - - // Set User-Agent for saved objects - $app = kolab_sync::get_instance(); - $app->config->set('useragent', $app->app_name . ' ' . kolab_sync::VERSION); - - if ($folder && $folder->valid && $folder->save($data, $type, $uid)) { - if (isset($tags)) { - $this->setCategories($uid, $tags); - } - - return $uid; - } - - return null; - } - - /** - * Returns list of categories assigned to an object - * - * @param object|string $object UID or rcube_message object - * @param array $categories Addition tag names to merge with - * - * @return array List of categories - */ - public function getCategories($object, $categories = ) - { - if (is_object($object)) { - // support only messages with message-id - if (!($msg_id = $object->headers->get('message-id', false))) { - return ; - } - - $config = kolab_storage_config::get_instance(); - $delta = Syncroton_Registry::getPingTimeout(); - $folder = $object->folder; - $uid = $object->uid; - - // get tag objects raleted to specified message-id - $tags = $config->get_tags($msg_id); - - foreach ($tags as $idx => $tag) { - // resolve members if it wasn't done recently - $force = empty($this->tag_rts$tag'uid') || $this->tag_rts$tag'uid' <= time() - $delta; - $members = $config->resolve_members($tag, $force); - - if (empty($members$folder) || !in_array($uid, $members$folder)) { - unset($tags$idx); - } - - if ($force) { - $this->tag_rts$tag'uid' = time(); - } - } - - // make sure current folder is set correctly again - $this->storage->set_folder($folder); - } else { - $config = kolab_storage_config::get_instance(); - $tags = $config->get_tags($object); - } - - $tags = array_filter(array_map(function ($v) { return $v'name'; }, $tags)); - - // merge result with old categories - if (!empty($categories)) { - $tags = array_unique(array_merge($tags, (array) $categories)); - } - - return $tags; - } - - /** - * Gets kolab_storage_folder object from Activesync folder ID. - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $type Activesync model name (folder type) - * - * @return ?kolab_storage_folder - */ - public function getFolder($folderid, $deviceid, $type) - { - $unique_key = "$folderid:$deviceid:$type"; - - if (array_key_exists($unique_key, $this->folders)) { - return $this->folders$unique_key; - } - - $foldername = $this->folder_id2name($folderid, $deviceid); - - return $this->folders$unique_key = kolab_storage::get_folder($foldername, $type); - } - - /** - * Gets Activesync preferences for a folder. - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $type Activesync model name (folder type) - * - * @return array Folder preferences - */ - public function getFolderConfig($folderid, $deviceid, $type) - { - $foldername = $this->folder_id2name($folderid, $deviceid); - - $metadata = $this->folder_meta(); - $config = ; - - if (!empty($metadata$foldername'FOLDER'$deviceid)) { - $config = $metadata$foldername'FOLDER'$deviceid; - } - - return - 'ALARMS' => ($config'S' ?? 0) == 2, - ; - } - - /** - * Gets an item from a folder by UID. - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $type Activesync model name (folder type) - * @param string $uid Requested object UID - * - * @return array|rcube_message|null Object properties - */ - public function getItem($folderid, $deviceid, $type, $uid) - { - if ($type == self::MODEL_EMAIL) { - $foldername = $this->folder_id2name($folderid, $deviceid); - $message = new rcube_message($uid, $foldername); - - if (!empty($message->headers)) { - if ($this->relationSupport) { - $message->headers->others'categories' = $this->getCategories($message); - } - - return $message; - } - - return null; - } - - $folder = $this->getFolder($folderid, $deviceid, $type); - - if (!$folder || !$folder->valid) { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - - $result = $folder->get_object($uid); - - if ($result === false) { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - - $useTags = $this->relationSupport && ($type == self::MODEL_TASKS || $type == self::MODEL_NOTES); - - if ($useTags) { - $result'categories' = $this->getCategories($uid, $result'categories' ?? ); - } - - return $result; - } - - /** - * Gets items matching UID by prefix. - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $type Activesync model name (folder type) - * @param string $uid Requested object UID prefix - * - * @return array|iterable List of objects - */ - public function getItemsByUidPrefix($folderid, $deviceid, $type, $uid) - { - $folder = $this->getFolder($folderid, $deviceid, $type); - - if (!$folder || !$folder->valid) { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - - $result = $folder->select('uid', '~*', $uid); - - if ($result === null) { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - - return $result; - } - - /** - * Move an item from one folder to another. - * - * @param string $srcFolderId Source folder identifier - * @param string $deviceid Device identifier - * @param string $type Activesync model name (folder type) - * @param string $uid Object UID - * @param string $dstFolderId Destination folder identifier - * - * @return string New object UID - * @throws Syncroton_Exception_Status - */ - public function moveItem($srcFolderId, $deviceid, $type, $uid, $dstFolderId) - { - if ($type === self::MODEL_EMAIL) { - $src_name = $this->folder_id2name($srcFolderId, $deviceid); - $dst_name = $this->folder_id2name($dstFolderId, $deviceid); - - if ($dst_name === null) { - throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_DESTINATION); - } - - if ($src_name === null) { - throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE); - } - - if (!$this->storage->move_message($uid, $dst_name, $src_name)) { - throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_DESTINATION); - } - - // Use COPYUID feature (RFC2359) to get the new UID of the copied message - if (empty($this->storage->conn->data'COPYUID')) { - // Check if the source item actually exists. Cyrus IMAP reports - // OK on a MOVE with an invalid UID, But COPYUID will be empty. - // This way we only incur the cost of the extra check once the move fails. - if (!$this->storage->get_message_headers($uid, $src_name)) { - throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE); - } - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - - return $this->storage->conn->data'COPYUID'1; - } - - $srcFolder = $this->getFolder($srcFolderId, $deviceid, $type); - $dstFolder = $this->getFolder($dstFolderId, $deviceid, $type); - - if (!$srcFolder || !$dstFolder) { - throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_DESTINATION); - } - - if (!$srcFolder->move($uid, $dstFolder)) { - throw new Syncroton_Exception_Status_MoveItems(Syncroton_Exception_Status_MoveItems::INVALID_SOURCE); - } - - return $uid; - } - - /** - * Set categories to an object - * - * @param object|string $object UID or rcube_message object - * @param array $categories List of Category names - */ - public function setCategories($object, $categories) - { - if (!is_object($object)) { - $config = kolab_storage_config::get_instance(); - $config->save_tags($object, $categories); - return; - } - - $config = kolab_storage_config::get_instance(); - $delta = Syncroton_Registry::getPingTimeout(); - $uri = kolab_storage_config::get_message_uri($object->headers, $object->folder); - - // for all tag objects... - foreach ($config->get_tags() as $relation) { - // resolve members if it wasn't done recently - $uid = $relation'uid'; - $force = empty($this->tag_rts$uid) || $this->tag_rts$uid <= time() - $delta; - - if ($force) { - $config->resolve_members($relation, $force); - $this->tag_rts$relation'uid' = time(); - } - - $selected = !empty($categories) && in_array($relation'name', $categories); - $found = !empty($relation'members') && in_array($uri, $relation'members'); - $update = false; - - // remove member from the relation - if ($found && !$selected) { - $relation'members' = array_diff($relation'members', (array) $uri); - $update = true; - } - // add member to the relation - elseif (!$found && $selected) { - $relation'members' = $uri; - $update = true; - } - - if ($update) { - $config->save($relation, 'relation'); - } - - $categories = array_diff($categories, (array) $relation'name'); - } - - // create new relations - if (!empty($categories)) { - foreach ($categories as $tag) { - $relation = - 'name' => $tag, - 'members' => (array) $uri, - 'category' => 'tag', - ; - - $config->save($relation, 'relation'); - } - } - - // make sure current folder is set correctly again - $this->storage->set_folder($object->folder); - } - - /** - * Search for existing objects in a folder - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $device_key Device primary key - * @param string $type Activesync model name (folder type) - * @param array $filter Filter - * @param int $result_type Type of the result (see kolab_sync_data::RESULT_* constants) - * @param bool $force Force IMAP folder cache synchronization - * @param string $extraData Extra data as extracted by the getExtraData during the last sync - * - * @return array|int Search result as count or array of uids - */ - public function searchEntries($folderid, $deviceid, $device_key, $type, $filter, $result_type, $force, $extraData) - { - if ($type != self::MODEL_EMAIL) { - return $this->searchKolabEntries($folderid, $deviceid, $device_key, $type, $filter, $result_type, $force); - } - - $filter_str = 'ALL UNDELETED'; - - $getChangesMode = false; - // convert filter into one IMAP search string - foreach ($filter as $idx => $filter_item) { - if (is_array($filter_item)) { - if ($filter_item0 == 'changed' && $filter_item1 == '>') { - $getChangesMode = true; - } - } else { - $filter_str .= ' ' . $filter_item; - } - } - - $result = $result_type == kolab_sync_data::RESULT_COUNT ? 0 : ; - - $foldername = $this->folder_id2name($folderid, $deviceid); - - if ($foldername === null) { - return $result; - } - - $this->storage->set_folder($foldername); - - // Synchronize folder (if it wasn't synced in this request already) - if ($force) { - $this->storage->folder_sync($foldername); - } - - $modified = true; - // We're in "get changes" mode - if ($getChangesMode) { - $folder_data = $this->storage->folder_data($foldername); - - // If HIGHESTMODSEQ doesn't exist we can't get changes - if (!empty($folder_data'HIGHESTMODSEQ')) { - // Store modseq for later in getExtraData - if (!array_key_exists($deviceid, $this->modseq)) { - $this->modseq$deviceid = ; - } - $this->modseq$deviceid$folderid = $folder_data'HIGHESTMODSEQ'; - // After the initial sync we have no extraData - if ($extraData) { - $modseq_old = json_decode($extraData)->modseq; - // Skip search if HIGHESTMODSEQ didn't change - if ($folder_data'HIGHESTMODSEQ' == $modseq_old) { - $modified = false; - } else { - $filter_str .= " MODSEQ " . ($modseq_old + 1); - } - } else { - // If we don't have extra data we can't search for changes. - // Either we are in initial sync, which means there are no changes to find, - // or we are in the migration (no previous extraData), in which case we ignore changes for one sync key - // because we don't have the means to search for the changes. Going forward we'll have the modseq info. - $modified = false; - } - } else { - // We have no way of finding the changes. - // We could fall back to search by date or ignore changes, but both seems suboptimal. - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - } - - // We could use messages cache by replacing search() with index() - // in some cases. This however is possible only if user has skip_deleted=true, - // in his Roundcube preferences, otherwise we'd make often cache re-initialization, - // because Roundcube message cache can work only with one skip_deleted - // setting at a time. We'd also need to make sure folder_sync() was called - // before (see above). - // - // if ($filter_str == 'ALL UNDELETED') - // $search = $this->storage->index($foldername, null, null, true, true); - // else - - if ($modified) { - $search = $this->storage->search_once($foldername, $filter_str); - - if (!($search instanceof rcube_result_index) || $search->is_error()) { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - - switch ($result_type) { - case kolab_sync_data::RESULT_COUNT: - $result = $search->count(); - break; - - case kolab_sync_data::RESULT_UID: - $result = $search->get(); - break; - } - } - - // get members of modified relations - if ($this->relationSupport) { - $changed_msgs = $this->getChangesByRelations($folderid, $device_key, $type, $filter); - // handle relation changes - if (!empty($changed_msgs)) { - $members = $this->findRelationMembersInFolder($foldername, $changed_msgs, $filter); - - switch ($result_type) { - case kolab_sync_data::RESULT_COUNT: - $result += count($members); - break; - - case kolab_sync_data::RESULT_UID: - $result = array_values(array_unique(array_merge($result, $members))); - break; - } - } - - } - - return $result; - } - - - /** - * Return extra data that is stored with the sync key and passed in during the search to find changes. - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * - * @return string|null Extra data (JSON-encoded) - */ - public function getExtraData($folderid, $deviceid) - { - //We explicitly return a cached value that was used during the search. - //Otherwise we'd risk storing a higher modseq value and missing an update. - if (isset($this->modseq$deviceid$folderid)) { - return json_encode('modseq' => intval($this->modseq$deviceid$folderid)); - } - - //If we didn't fetch modseq in the first place we have to fetch it now. - $foldername = $this->folder_id2name($folderid, $deviceid); - if ($foldername !== null) { - $folder_data = $this->storage->folder_data($foldername); - if (!empty($folder_data'HIGHESTMODSEQ')) { - return json_encode('modseq' => intval($folder_data'HIGHESTMODSEQ')); - } - } - - return null; - } - - /** - * Search for existing objects in a folder - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $device_key Device primary key - * @param string $type Activesync model name (folder type) - * @param array $filter Filter - * @param int $result_type Type of the result (see kolab_sync_data::RESULT_* constants) - * @param bool $force Force IMAP folder cache synchronization - * - * @return array|int Search result as count or array of uids - */ - protected function searchKolabEntries($folderid, $deviceid, $device_key, $type, $filter, $result_type, $force) - { - // there's a PHP Warning from kolab_storage if $filter isn't an array - if (empty($filter)) { - $filter = ; - } elseif ($this->relationSupport && ($type == self::MODEL_TASKS || $type == self::MODEL_NOTES)) { - $changed_objects = $this->getChangesByRelations($folderid, $device_key, $type, $filter); - } - - $folder = $this->getFolder($folderid, $deviceid, $type); - - if (!$folder || !$folder->valid) { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - - $error = false; - - switch ($result_type) { - case kolab_sync_data::RESULT_COUNT: - $count = $folder->count($filter); - - if ($count === null) { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - - $result = (int) $count; - break; - - case kolab_sync_data::RESULT_UID: - default: - $uids = $folder->get_uids($filter); - - if (!is_array($uids)) { - throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); - } - - $result = $uids; - break; - } - - // handle tag modifications - if (!empty($changed_objects)) { - // build new filter - // search objects mathing current filter, - // relations may contain members of many types, we need to - // search them by UID in all requested folders to get - // only these with requested type (and that really exist - // in specified folders) - $tag_filter = 'uid', '=', $changed_objects; - foreach ($filter as $f) { - if ($f0 != 'changed') { - $tag_filter = $f; - } - } - - switch ($result_type) { - case kolab_sync_data::RESULT_COUNT: - // Note: this way we're potentally counting the same objects twice - // I'm not sure if this is a problem, we most likely do not - // need a precise result here - $count = $folder->count($tag_filter); - if ($count !== null) { - $result += (int) $count; - } - - break; - - case kolab_sync_data::RESULT_UID: - default: - $uids = $folder->get_uids($tag_filter); - if (is_array($uids) && !empty($uids)) { - $result = array_unique(array_merge($result, $uids)); - } - - break; - } - } - - return $result; - } - - /** - * Find members (messages) in specified folder - */ - protected function findRelationMembersInFolder($foldername, $members, $filter) - { - foreach ($members as $member) { - // IMAP URI members - if ($url = kolab_storage_config::parse_member_url($member)) { - $result$url'folder'$url'uid' = $url'params'; - } - } - - // convert filter into one IMAP search string - $filter_str = 'ALL UNDELETED'; - foreach ($filter as $filter_item) { - if (is_string($filter_item)) { - $filter_str .= ' ' . $filter_item; - } - } - - $found = ; - - // first find messages by UID - if (!empty($result$foldername)) { - $index = $this->storage->search_once($foldername, 'UID ' - . rcube_imap_generic::compressMessageSet(array_keys($result$foldername))); - $found = $index->get(); - - // remove found messages from the $result - if (!empty($found)) { - $result$foldername = array_diff_key($result$foldername, array_flip($found)); - - if (empty($result$foldername)) { - unset($result$foldername); - } - - // now apply the current filter to the found messages - $index = $this->storage->search_once($foldername, $filter_str . ' UID ' - . rcube_imap_generic::compressMessageSet($found)); - $found = $index->get(); - } - } - - // search by message parameters - if (!empty($result)) { - // @TODO: do this search in chunks (for e.g. 25 messages)? - $search = ''; - $search_count = 0; - - foreach ($result as $data) { - foreach ($data as $p) { - $search_params = ; - $search_count++; - - foreach ($p as $key => $val) { - $key = strtoupper($key); - // don't search by subject, we don't want false-positives - if ($key != 'SUBJECT') { - $search_params = 'HEADER ' . $key . ' ' . rcube_imap_generic::escape($val); - } - } - - $search .= ' (' . implode(' ', $search_params) . ')'; - } - } - - $search_str = str_repeat(' OR', $search_count - 1) . $search; - - // search messages in current folder - $search = $this->storage->search_once($foldername, $search_str); - $uids = $search->get(); - - if (!empty($uids)) { - // add UIDs into the result - $found = array_unique(array_merge($found, $uids)); - } - } - - return $found; - } - - /** - * Detect changes of relation (tag) objects data and assigned objects - * Returns relation member identifiers - */ - protected function getChangesByRelations($folderid, $device_key, $type, $filter) - { - // get period filter, create new objects filter - foreach ($filter as $f) { - if ($f0 == 'changed' && $f1 == '>') { - $since = $f2; - } - } - - // this is not search for changes, do nothing - if (empty($since)) { - return; - } - - // get relations state from the last sync - $last_state = (array) $this->relations_state_get($device_key, $folderid, $since); - - // get current relations state - $config = kolab_storage_config::get_instance(); - $default = true; - $filter = - 'type', '=', 'relation', - 'category', '=', 'tag', - ; - - $relations = $config->get_objects($filter, $default, 100); - - $result = ; - $changed = false; - - // compare states, get members of changed relations - foreach ($relations as $relation) { - $rel_id = $relation'uid'; - - if ($relation'changed') { - $relation'changed'->setTimezone(new DateTimeZone('UTC')); - } - - // last state unknown... - if (empty($last_state$rel_id)) { - // ...get all members - if (!empty($relation'members')) { - $changed = true; - $result = array_merge($result, $relation'members'); - } - } - // last state known, changed tag name... - elseif ($last_state$rel_id'name' != $relation'name') { - // ...get all (old and new) members - $members_old = explode("\n", $last_state$rel_id'members'); - $changed = true; - $members = array_unique(array_merge($relation'members', $members_old)); - $result = array_merge($result, $members); - } - // last state known, any other change change... - elseif ($last_state$rel_id'changed' < $relation'changed'->format('U')) { - // ...find new and removed members - $members_old = explode("\n", $last_state$rel_id'members'); - $new = array_diff($relation'members', $members_old); - $removed = array_diff($members_old, $relation'members'); - - if (!empty($new) || !empty($removed)) { - $changed = true; - $result = array_merge($result, $new, $removed); - } - } - - unset($last_state$rel_id); - } - - // get members of deleted relations - if (!empty($last_state)) { - $changed = true; - foreach ($last_state as $relation) { - $members = explode("\n", $relation'members'); - $result = array_merge($result, $members); - } - } - - // save current state - if ($changed) { - $data = ; - foreach ($relations as $relation) { - $data$relation'uid' = - 'name' => $relation'name', - 'changed' => $relation'changed'->format('U'), - 'members' => implode("\n", (array)$relation'members'), - ; - } - - // If the new and the old timestamp are the same our cache breaks. - // We must preserve the previous changes, because if this function is rerun we must detect the same changes again. - $sinceFormatted = $since->format('Y-m-d H:i:s'); - if ($this->syncTimeStamp->format('Y-m-d H:i:s') == $sinceFormatted) { - // Preserve the previous timestamp (relations_state_get just checks the overflow bucket first) - // FIXME: The one caveat is that we will still update the database and thus overwrite the old entry. - // That means if we rerun the same request, the changes will not be detected - // => We should not be dealing with timestamps really. - $this->relations$folderid$sinceFormatted . "-1" = $this->relations$folderid$sinceFormatted ?? null; - $this->relations$folderid$sinceFormatted = null; - } - - $this->relations_state_set($device_key, $folderid, $this->syncTimeStamp, $data); - } - - // in mail mode return only message URIs - if ($type == self::MODEL_EMAIL) { - // lambda function to skip email members - $filter_func = function ($value) { - return strpos($value, 'imap://') === 0; - }; - - $result = array_filter(array_unique($result), $filter_func); - } - // otherwise return only object UIDs - else { - // lambda function to skip email members - $filter_func = function ($value) { - return strpos($value, 'urn:uuid:') === 0; - }; - - // lambda function to parse member URI - $member_func = function ($value) { - if (strpos($value, 'urn:uuid:') === 0) { - $value = substr($value, 9); - } - return $value; - }; - - $result = array_map($member_func, array_filter(array_unique($result), $filter_func)); - } - - return $result; - } - - /** - * Subscribe default set of folders on device registration - */ - protected function device_init_subscriptions($deviceid) - { - // INBOX always exists - $this->folder_set('INBOX', $deviceid, 1); - - $supported_types = - 'mail.drafts', - 'mail.wastebasket', - 'mail.sentitems', - 'mail.outbox', - 'event.default', - 'contact.default', - 'note.default', - 'task.default', - 'event', - 'contact', - 'note', - 'task', - 'event.confidential', - 'event.private', - 'task.confidential', - 'task.private', - ; - - $rcube = rcube::get_instance(); - $config = $rcube->config; - $mode = (int) $config->get('activesync_init_subscriptions'); - $folders = ; - - // Subscribe to default folders - $foldertypes = kolab_storage::folders_typedata(); - - if (!empty($foldertypes)) { - $_foldertypes = array_intersect($foldertypes, $supported_types); - - // get default folders - foreach ($_foldertypes as $folder => $type) { - // only personal folders - if ($this->storage->folder_namespace($folder) == 'personal') { - $flag = preg_match('/^(event|task)/', $type) ? 2 : 1; - $this->folder_set($folder, $deviceid, $flag); - $folders = $folder; - } - } - } - - // we're in default mode, exit - if (!$mode) { - return; - } - - // below we support additionally all mail folders - $supported_types = 'mail'; - $supported_types = 'mail.junkemail'; - - // get configured special folders - $special_folders = ; - $map = - 'drafts' => 'mail.drafts', - 'junk' => 'mail.junkemail', - 'sent' => 'mail.sentitems', - 'trash' => 'mail.wastebasket', - ; - - foreach ($map as $folder => $type) { - if ($folder = $config->get($folder . '_mbox')) { - $special_folders$folder = $type; - } - } - - // get folders list(s) - if (($mode & self::INIT_ALL_PERSONAL) || ($mode & self::INIT_ALL_OTHER) || ($mode & self::INIT_ALL_SHARED)) { - $all_folders = $this->storage->list_folders(); - if (($mode & self::INIT_SUB_PERSONAL) || ($mode & self::INIT_SUB_OTHER) || ($mode & self::INIT_SUB_SHARED)) { - $subscribed_folders = $this->storage->list_folders_subscribed(); - } - } else { - $all_folders = $this->storage->list_folders_subscribed(); - } - - foreach ($all_folders as $folder) { - // folder already subscribed - if (in_array($folder, $folders)) { - continue; - } - - $type = ($foldertypes$folder ?? null) ?: 'mail'; - if ($type == 'mail' && isset($special_folders$folder)) { - $type = $special_folders$folder; - } - - if (!in_array($type, $supported_types)) { - continue; - } - - $ns = strtoupper($this->storage->folder_namespace($folder)); - - // subscribe the folder according to configured mode - // and folder namespace/subscription status - if (($mode & constant("self::INIT_ALL_{$ns}")) - || (($mode & constant("self::INIT_SUB_{$ns}")) - && (!isset($subscribed_folders) || in_array($folder, $subscribed_folders))) - ) { - $flag = preg_match('/^(event|task)/', $type) ? 2 : 1; - $this->folder_set($folder, $deviceid, $flag); - } - } - } - - /** - * Helper method to decode saved IMAP metadata - */ - protected function unserialize_metadata($str) - { - if (!empty($str)) { - $data = json_decode($str, true); - return $data; - } - - return null; - } - - /** - * Helper method to encode IMAP metadata for saving - */ - protected function serialize_metadata($data) - { - if (!empty($data) && is_array($data)) { - $data = json_encode($data); - return $data; - } - - return null; - } - - /** - * Returns Kolab folder type for specified ActiveSync type ID - */ - protected static function type_activesync2kolab($type) - { - if (!empty(self::$types$type)) { - return self::$types$type; - } - - return ''; - } - - /** - * Returns ActiveSync folder type for specified Kolab type - */ - protected static function type_kolab2activesync($type) - { - $type = preg_replace('/\.(confidential|private)$/i', '', $type); - - if ($key = array_search($type, self::$types)) { - return $key; - } - - return key(self::$types); - } - - /** - * Returns folder data in Syncroton format - */ - protected function folder_data($folder, $type) - { - // Folder name parameters - $delim = $this->storage->get_hierarchy_delimiter(); - $items = explode($delim, $folder); - $name = array_pop($items); - - // Folder UID - $folder_id = $this->folder_id($folder, $type); - - // Folder type - if (strcasecmp($folder, 'INBOX') === 0) { - // INBOX is always inbox, prevent from issues related with a change of - // folder type annotation (it can be initially unset). - $as_type = 2; - } else { - $as_type = self::type_kolab2activesync($type); - - // fix type, if there's no type annotation it's detected as UNKNOWN we'll use 'mail' (12) - if ($as_type == 1) { - $as_type = 12; - } - } - - // Syncroton folder data array - return - 'serverId' => $folder_id, - 'parentId' => count($items) ? $this->folder_id(implode($delim, $items), $type) : 0, - 'displayName' => rcube_charset::convert($name, 'UTF7-IMAP', kolab_sync::CHARSET), - 'type' => $as_type, - // for internal use - 'imap_name' => $folder, - ; - } - - /** - * Builds folder ID based on folder name - */ - protected function folder_id($name, $type = null) - { - // ActiveSync expects folder identifiers to be max.64 characters - // So we can't use just folder name - - $name = (string) $name; - - if ($name === '') { - return null; - } - - if (isset($this->folder_uids$name)) { - return $this->folder_uids$name; - } - - /* - @TODO: For now uniqueid annotation doesn't work, we will create UIDs by ourselves. - There's one inconvenience of this solution: folder name/type change - would be handled in ActiveSync as delete + create. - - // get folders unique identifier - $folderdata = $this->storage->get_metadata($name, self::UID_KEY); - - if ($folderdata && !empty($folderdata$name)) { - $uid = $folderdata$nameself::UID_KEY; - return $this->folder_uids$name = $uid; - } - */ - if (strcasecmp($name, 'INBOX') === 0) { - // INBOX is always inbox, prevent from issues related with a change of - // folder type annotation (it can be initially unset). - $type = 'mail.inbox'; - } else { - if ($type === null) { - $type = kolab_storage::folder_type($name); - } - - if ($type != null) { - $type = preg_replace('/\.(confidential|private)$/i', '', $type); - } - } - - // Add type to folder UID hash, so type change can be detected by Syncroton - $uid = $name . '!!' . $type; - $uid = md5($uid); - - return $this->folder_uids$name = $uid; - } - - /** - * Returns IMAP folder name - * - * @param string $id Folder identifier - * @param string $deviceid Device dentifier - * - * @return string|null Folder name (UTF7-IMAP) - */ - public function folder_id2name($id, $deviceid) - { - // check in cache first - if (!empty($this->folder_uids)) { - if (($name = array_search($id, $this->folder_uids)) !== false) { - return $name; - } - } - /* - @TODO: see folder_id() - - // get folders unique identifier - $folderdata = $this->storage->get_metadata('*', self::UID_KEY); - - foreach ((array)$folderdata as $folder => $data) { - if (!empty($dataself::UID_KEY)) { - $uid = $dataself::UID_KEY; - $this->folder_uids$folder = $uid; - if ($uid == $id) { - $name = $folder; - } - } - } - */ - // get all folders of specified type - $folderdata = $this->folder_meta(); - - if (!is_array($folderdata) || empty($id)) { - return null; - } - - $name = null; - - // check if folders are "subscribed" for activesync - foreach ($folderdata as $folder => $meta) { - if (empty($meta'FOLDER') || empty($meta'FOLDER'$deviceid) - || empty($meta'FOLDER'$deviceid'S') - ) { - continue; - } - - if ($uid = $this->folder_id($folder)) { - $this->folder_uids$folder = $uid; - } - - if ($uid === $id) { - $name = $folder; - } - } - - return $name; - } - - /** - * Set state of relation objects at specified point in time - */ - public function relations_state_set($device_key, $folderid, $synctime, $relations) - { - $synctime = $synctime->format('Y-m-d H:i:s'); - - // Protect against inserting the same values twice (this code can be executed twice in the same request) - if (!isset($this->relations$folderid$synctime)) { - $rcube = rcube::get_instance(); - $db = $rcube->get_dbh(); - $this->relations$folderid$synctime = $relations; - $data = rcube_charset::clean(json_encode($relations)); - - $result = $db->insert_or_update( - 'syncroton_relations_state', - 'device_id' => $device_key, 'folder_id' => $folderid, 'synctime' => $synctime, - 'data', - $data - ); - - if ($err = $db->is_error($result)) { - throw new Exception("Failed to save relation: {$err}"); - } - } - } - - /** - * Get state of relation objects at specified point in time - */ - protected function relations_state_get($device_key, $folderid, $synctime) - { - $synctime = $synctime->format('Y-m-d H:i:s'); - - //If we had a collision before - if (isset($this->relations$folderid$synctime . "-1")) { - return $this->relations$folderid$synctime . "-1"; - } - if (!isset($this->relations$folderid$synctime)) { - $rcube = rcube::get_instance(); - $db = $rcube->get_dbh(); - - $db->limitquery( - "SELECT `data`, `synctime` FROM `syncroton_relations_state`" - . " WHERE `device_id` = ? AND `folder_id` = ? AND `synctime` < ?" - . " ORDER BY `synctime` DESC", - 0, - 1, - $device_key, - $folderid, - $synctime - ); - $row = $db->fetch_assoc(); - if (!$row) { - // Only if we don't have a timestamp that is older than synctime do we return the next best. - // We MUST return an entry if there are any, because otherwise we will keep INSERTing new entries in, - // relations_state_set - $db->limitquery( - "SELECT `data`, `synctime` FROM `syncroton_relations_state`" - . " WHERE `device_id` = ? AND `folder_id` = ?" - . " ORDER BY `synctime` ASC", - 0, - 1, - $device_key, - $folderid, - $synctime - ); - $row = $db->fetch_assoc(); - } - - if ($row) { - // Don't use $row'synctime' for the internal cache. - // The synctime of the found row is usually earlier than the requested synctime. - // Note: We use internal cache because there's a call to both hasChanges() and - // getChangedEntries() in Sync. It's needed until we add some caching on a higher level. - $this->relations$folderid$synctime = json_decode($row'data', true); - - // Cleanup: remove all records older than the current one. - // We must use the row's synctime, otherwise we would delete the record we just loaded - // We must delete all entries that are before the synctime to clean up old entries, - // but we must also delete all entries that are more recent in case the sync gets rerun - // with the same timestamp (e.g. when rerunning the same sync request). - // Otherwise the number of entries will start to grow with every sync. - $db->query( - "DELETE FROM `syncroton_relations_state`" - . " WHERE `device_id` = ? AND `folder_id` = ? AND `synctime` <> ?", - $device_key, - $folderid, - $row'synctime' - ); - } - } - - return $this->relations$folderid$synctime ?? null; - } - - /** - * Return last storage error - */ - public static function last_error() - { - return kolab_storage::$last_error; - } - - /** - * Compares two arrays - * - * @param array $array1 - * @param array $array2 - * - * @return bool True if arrays differs, False otherwise - */ - protected static function data_array_diff($array1, $array2) - { - if (!is_array($array1) || !is_array($array2)) { - return $array1 != $array2; - } - - if (count($array1) != count($array2)) { - return true; - } - - foreach ($array1 as $key => $val) { - if (!array_key_exists($key, $array2)) { - return true; - } - if ($val !== $array2$key) { - return true; - } - } - - return false; - } -}
View file
kolab-syncroton-2.4.2.tar.gz/lib/kolab_sync_storage_kolab4.php
Deleted
@@ -1,571 +0,0 @@ -<?php - -/* - +--------------------------------------------------------------------------+ - | Kolab Sync (ActiveSync for Kolab) | - | | - | Copyright (C) 2011-2023, Apheleia IT AG <contact@apheleia-it.ch> | - | | - | This program is free software: you can redistribute it and/or modify | - | it under the terms of the GNU Affero General Public License as published | - | by the Free Software Foundation, either version 3 of the License, or | - | (at your option) any later version. | - | | - | This program is distributed in the hope that it will be useful, | - | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | GNU Affero General Public License for more details. | - | | - | You should have received a copy of the GNU Affero General Public License | - | along with this program. If not, see <http://www.gnu.org/licenses/> | - +--------------------------------------------------------------------------+ - | Author: Aleksander Machniak <machniak@kolabsys.com> | - +--------------------------------------------------------------------------+ -*/ - -/** - * Storage handling class with Kolab 4 support (IMAP + CalDAV + CardDAV) - */ -class kolab_sync_storage_kolab4 extends kolab_sync_storage -{ - protected $davStorage = null; - public $relationSupport = false; - - /** - * This implements the 'singleton' design pattern - * - * @return kolab_sync_storage_kolab4 The one and only instance - */ - public static function get_instance() - { - if (!self::$instance) { - self::$instance = new kolab_sync_storage_kolab4(); - self::$instance->startup(); // init AFTER object was linked with self::$instance - } - - return self::$instance; - } - - /** - * Class initialization - */ - public function startup() - { - $sync = kolab_sync::get_instance(); - - if ($sync->username === null || $sync->password === null) { - throw new Exception("Unsupported storage handler use!"); - } - - $url = $sync->config->get('activesync_dav_server', 'http://localhost'); - - if (strpos($url, '://') === false) { - $url = 'http://' . $url; - } - - // Inject user+password to the URL, there's no other way to pass it to the DAV client - $url = str_replace('://', '://' . rawurlencode($sync->username) . ':' . rawurlencode($sync->password) . '@', $url); - - $this->davStorage = new kolab_storage_dav($url); // DAV - $this->storage = $sync->get_storage(); // IMAP - - // set additional header used by libkolab - $this->storage->set_options( - 'skip_deleted' => true, - 'threading' => false, - ); - - // Disable paging - $this->storage->set_pagesize(999999); - } - - /** - * Get list of folders available for sync - * - * @param string $deviceid Device identifier - * @param string $type Folder (class) type - * @param bool $flat_mode Enables flat-list mode - * - * @return array|bool List of mailbox folders, False on backend failure - */ - public function folders_list($deviceid, $type, $flat_mode = false) - { - $list = ; - - // get mail folders subscribed for sync - if ($type === self::MODEL_EMAIL) { - $folderdata = $this->folder_meta(); - - if (!is_array($folderdata)) { - return false; - } - - $special_folders = $this->storage->get_special_folders(true); - $type_map = - 'drafts' => 3, - 'trash' => 4, - 'sent' => 5, - ; - - // Get the folders "subscribed" for activesync - foreach ($folderdata as $folder => $meta) { - if (empty($meta'FOLDER') || empty($meta'FOLDER'$deviceid) - || empty($meta'FOLDER'$deviceid'S') - ) { - continue; - } - - // Force numeric folder name to be a string (T1283) - $folder = (string) $folder; - - // Activesync folder properties - $folder_data = $this->folder_data($folder, 'mail'); - - // Set proper type for special folders - if (($type = array_search($folder, $special_folders)) && isset($type_map$type)) { - $folder_data'type' = $type_map$type; - } - - $list$folder_data'serverId' = $folder_data; - } - } elseif (in_array($type, self::MODEL_CONTACTS, self::MODEL_CALENDAR, self::MODEL_TASKS)) { - if (!empty($this->folders)) { - foreach ($this->folders as $unique_key => $folder) { - if (strpos($unique_key, "DAV:$type:") === 0) { - $folder_data = $this->folder_data($folder, $type); - $list$folder_data'serverId' = $folder_data; - } - } - } - - // TODO: For now all DAV folders are subscribed - - if (empty($list)) { - foreach ($this->davStorage->get_folders($type) as $folder) { - $folder_data = $this->folder_data($folder, $type); - $list$folder_data'serverId' = $folder_data; - - // Store all folder objects in internal cache, otherwise - // Any access to the folder (or list) will invoke excessive DAV requests - $unique_key = $folder_data'serverId' . ":$deviceid:$type"; - $this->folders$unique_key = $folder; - } - } - } - /* - // TODO - if ($flat_mode) { - $list = $this->folders_list_flat($list, $type, $typedata); - } - */ - return $list; - } - - /** - * Creates folder and subscribes to the device - * - * @param string $name Folder name (UTF8) - * @param int $type Folder (ActiveSync) type - * @param string $deviceid Device identifier - * @param ?string $parentid Parent folder identifier - * - * @return string|false New folder identifier on success, False on failure - */ - public function folder_create($name, $type, $deviceid, $parentid = null) - { - // Mail folder - if ($type <= 6 || $type == 12) { - $parent = null; - $name = rcube_charset::convert($name, kolab_sync::CHARSET, 'UTF7-IMAP'); - - if ($parentid) { - $parent = $this->folder_id2name($parentid, $deviceid); - - if ($parent === null) { - throw new Syncroton_Exception_Status_FolderCreate(Syncroton_Exception_Status_FolderCreate::PARENT_NOT_FOUND); - } - } - - if ($parent !== null) { - $delim = $this->storage->get_hierarchy_delimiter(); - $name = $parent . $delim . $name; - } - - if ($this->storage->folder_exists($name)) { - throw new Syncroton_Exception_Status_FolderCreate(Syncroton_Exception_Status_FolderCreate::FOLDER_EXISTS); - } - - // TODO: Support setting folder types? - - $created = $this->storage->create_folder($name, true); - - if ($created) { - // Set ActiveSync subscription flag - $this->folder_set($name, $deviceid, 1); - - return $this->folder_id($name, 'mail'); - } - - // Special case when client tries to create a subfolder of INBOX - // which is not possible on Cyrus-IMAP (T2223) - if ($parent == 'INBOX' && stripos($this->last_error(), 'invalid') !== false) { - throw new Syncroton_Exception('', Syncroton_Exception_Status_FolderCreate::SPECIAL_FOLDER); - } - - return false; - } elseif ($type == 8 || $type == 13 || $type == 7 || $type == 15 || $type == 9 || $type == 14) { - // DAV folder - $type = preg_replace('|\..*|', '', self::type_activesync2kolab($type)); - - // TODO: Folder hierarchy support - - // Check if folder exists - foreach ($this->davStorage->get_folders($type) as $folder) { - if ($folder->get_name() == $name) { - throw new Syncroton_Exception_Status_FolderCreate(Syncroton_Exception_Status_FolderCreate::FOLDER_EXISTS); - } - } - - $props = 'name' => $name, 'type' => $type; - - if ($id = $this->davStorage->folder_update($props)) { - return "DAV:{$type}:{$id}"; - } - - return false; - } - - throw new \Exception("Not implemented"); - } - - /** - * Renames a folder - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $new_name New folder name (UTF8) - * @param ?string $parentid Folder parent identifier - * - * @return bool True on success, False on failure - */ - public function folder_rename($folderid, $deviceid, $new_name, $parentid) - { - // DAV folder - if (strpos($folderid, 'DAV:') === 0) { - , $type, $id = explode(':', $folderid); - $props = - 'id' => $id, - 'name' => $new_name, - 'type' => $type, - ; - - // TODO: Folder hierarchy support - - return $this->davStorage->folder_update($props) !== false; - } - - // Mail folder - $old_name = $this->folder_id2name($folderid, $deviceid); - - if ($parentid) { - $parent = $this->folder_id2name($parentid, $deviceid); - } - - $name = rcube_charset::convert($new_name, kolab_sync::CHARSET, 'UTF7-IMAP'); - - if (isset($parent)) { - $delim = $this->storage->get_hierarchy_delimiter(); - $name = $parent . $delim . $name; - } - - if ($name === $old_name) { - return true; - } - - $this->folder_meta = null; - - return $this->storage->rename_folder($old_name, $name); - } - - /** - * Deletes folder - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * - * @return bool True on success, False otherwise - */ - public function folder_delete($folderid, $deviceid) - { - // DAV folder - if (strpos($folderid, 'DAV:') === 0) { - , $type, $id = explode(':', $folderid); - - return $this->davStorage->folder_delete($id, $type) !== false; - } - - // Mail folder - $name = $this->folder_id2name($folderid, $deviceid); - - unset($this->folder_meta$name); - - return $this->storage->delete_folder($name); - } - - /** - * Deletes contents of a folder - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param bool $recursive Apply to the folder and its subfolders - * - * @return bool True on success, False otherwise - */ - public function folder_empty($folderid, $deviceid, $recursive = false) - { - // DAV folder - if (strpos($folderid, 'DAV:') === 0) { - , $type, $id = explode(':', $folderid); - - if ($folder = $this->davStorage->get_folder($id, $type)) { - return $folder->delete_all(); - } - - // TODO: $recursive=true - - return false; - } - - // Mail folder - return parent::folder_empty($folderid, $deviceid, $recursive); - } - - /** - * Returns folder data in Syncroton format - */ - protected function folder_data($folder, $type) - { - // Mail folders - if (strpos($type, 'mail') === 0) { - return parent::folder_data($folder, $type); - } - - // DAV folders - return - 'serverId' => "DAV:{$type}:{$folder->id}", - 'parentId' => 0, // TODO: Folder hierarchy - 'displayName' => $folder->get_name(), - 'type' => $this->type_kolab2activesync($folder->default ? "$type.default" : $type), - ; - } - - /** - * Builds folder ID based on folder name - * - * @param string $name Folder name (UTF7-IMAP) - * @param string $type Kolab folder type - * - * @return string|null Folder identifier (up to 64 characters) - */ - protected function folder_id($name, $type = null) - { - if (!$type) { - $type = 'mail'; - } - - // ActiveSync expects folder identifiers to be max.64 characters - // So we can't use just folder name - $name = (string) $name; - - if ($name === '') { - return null; - } - - if (strpos($type, 'mail') !== 0) { - throw new Exception("Unsupported folder_id() call on a DAV folder"); - } - - if (isset($this->folder_uids$name)) { - return $this->folder_uids$name; - } - /* - @TODO: For now uniqueid annotation doesn't work, we will create UIDs by ourselves. - There's one inconvenience of this solution: folder name/type change - would be handled in ActiveSync as delete + create. - @TODO: Consider using MAILBOXID (RFC8474) that Cyrus v3 supports - - // get folders unique identifier - $folderdata = $this->storage->get_metadata($name, self::UID_KEY); - - if ($folderdata && !empty($folderdata$name)) { - $uid = $folderdata$nameself::UID_KEY; - return $this->folder_uids$name = $uid; - } - */ - if (strcasecmp($name, 'INBOX') === 0) { - // INBOX is always inbox, prevent from issues related with a change of - // folder type annotation (it can be initially unset). - $type = 'mail.inbox'; - } - - // Add type to folder UID hash, so type change can be detected by Syncroton - $uid = $name . '!!' . $type; - $uid = md5($uid); - - return $this->folder_uids$name = $uid; - } - - /** - * Returns IMAP folder name - * - * @param string $id Folder identifier - * @param string $deviceid Device dentifier - * - * @return null|string Folder name (UTF7-IMAP) - */ - public function folder_id2name($id, $deviceid) - { - // TODO: This method should become protected and be used for mail folders only - if (strpos($id, 'DAV:') === 0) { - throw new Exception("Unsupported folder_id2name() call on a DAV folder"); - } - - // check in cache first - if (!empty($this->folder_uids)) { - if (($name = array_search($id, $this->folder_uids)) !== false) { - return $name; - } - } - - // get all folders of specified type - $folderdata = $this->folder_meta(); - - if (!is_array($folderdata) || empty($id)) { - return null; - } - - // check if folders are "subscribed" for activesync - foreach ($folderdata as $folder => $meta) { - if (empty($meta'FOLDER') || empty($meta'FOLDER'$deviceid) - || empty($meta'FOLDER'$deviceid'S') - ) { - continue; - } - - if ($uid = $this->folder_id($folder, 'mail')) { - $this->folder_uids$folder = $uid; - } - - if ($uid === $id) { - $name = $folder; - } - } - - return $name ?? null; - } - - /** - * Gets kolab_storage_folder object from Activesync folder ID. - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $type Activesync model name (folder type) - * - * @return ?kolab_storage_folder - */ - public function getFolder($folderid, $deviceid, $type) - { - if (strpos($folderid, 'DAV:') !== 0) { - throw new Exception("Unsupported getFolder() call on a mail folder"); - } - - $unique_key = "$folderid:$deviceid:$type"; - - if (array_key_exists($unique_key, $this->folders)) { - return $this->folders$unique_key; - } - - , $type, $id = explode(':', $folderid); - - return $this->folders$unique_key = $this->davStorage->get_folder($id, $type); - } - - /** - * Gets Activesync preferences for a folder. - * - * @param string $folderid Folder identifier - * @param string $deviceid Device identifier - * @param string $type Activesync model name (folder type) - * - * @return array Folder preferences - */ - public function getFolderConfig($folderid, $deviceid, $type) - { - // TODO: Get "alarms" from the DAV folder props, or implement - // a storage for folder properties - return - 'ALARMS' => true, - ; - } - - /** - * Return last storage error - */ - public static function last_error() - { - // TODO - return null; - } - - /** - * Subscribe default set of folders on device registration - */ - protected function device_init_subscriptions($deviceid) - { - $config = rcube::get_instance()->config; - $mode = (int) $config->get('activesync_init_subscriptions'); - - $subscribed_folders = null; - - // Special folders only - if (!$mode) { - $all_folders = $this->storage->get_special_folders(true); - // We do not subscribe to the Spam folder by default, same as the old Kolab driver does - unset($all_folders'junk'); - $all_folders = array_unique(array_merge('INBOX', array_values($all_folders))); - } - // other modes - elseif (($mode & self::INIT_ALL_PERSONAL) || ($mode & self::INIT_ALL_OTHER) || ($mode & self::INIT_ALL_SHARED)) { - $all_folders = $this->storage->list_folders(); - if (($mode & self::INIT_SUB_PERSONAL) || ($mode & self::INIT_SUB_OTHER) || ($mode & self::INIT_SUB_SHARED)) { - $subscribed_folders = $this->storage->list_folders_subscribed(); - } - } else { - $all_folders = $this->storage->list_folders_subscribed(); - } - - foreach ($all_folders as $folder) { - $ns = strtoupper($this->storage->folder_namespace($folder)); - - // subscribe the folder according to configured mode - // and folder namespace/subscription status - if (!$mode - || ($mode & constant("self::INIT_ALL_{$ns}")) - || (($mode & constant("self::INIT_SUB_{$ns}")) && ($subscribed_folders === null || in_array($folder, $subscribed_folders))) - ) { - $this->folder_set($folder, $deviceid, 1); - } - } - - // TODO: Subscribe personal DAV folders, for now we assume all are subscribed - // TODO: Subscribe shared DAV folders - } - - public function getExtraData($folderid, $deviceid) - { - if (strpos($folderid, 'DAV:') === 0) { - return null; - } - return parent::getExtraData($folderid, $deviceid); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/phpstan.bootstrap.php
Deleted
@@ -1,12 +0,0 @@ -<?php - -// environment initialization - -require_once 'lib/init.php'; - -set_include_path(implode(PATH_SEPARATOR, - 'lib/plugins/libkolab/lib', - 'lib/plugins/libcalendaring', - 'lib/plugins/libcalendaring/lib', - ini_get('include_path'), -));
View file
kolab-syncroton-2.4.2.tar.gz/phpstan.neon
Deleted
@@ -1,18 +0,0 @@ -parameters: - bootstrapFiles: - - phpstan.bootstrap.php - - excludePaths: - - lib/plugins - - lib/ext/Roundcube - - paths: - - lib - - tests - - level: 4 - - scanDirectories: - - lib/ext - - treatPhpDocTypesAsCertain: false
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync
Deleted
-(directory)
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/FoldersTest.php
Deleted
@@ -1,603 +0,0 @@ -<?php - -class FoldersTest extends Tests\SyncTestCase -{ - /** - * Cleanup folders - */ - public function setUp(): void - { - // Note: We essentially assume the test account is in an initial state, extra folders may break tests - // Anyway, we first remove folders that might have been created during tests in this file - $this->deleteTestFolder('Test Folder', 'mail'); - $this->deleteTestFolder('NewFolder', 'mail'); - $this->deleteTestFolder('NewFolder2', 'mail'); - $this->deleteTestFolder('Test Folder New', 'mail'); - $this->deleteTestFolder('Test Contacts Folder', 'contact'); - $this->deleteTestFolder('Test Contacts New', 'contact'); - parent::setUp(); - } - - /** - * Test FolderSync command - */ - public function testFolderSyncBasic() - { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>0</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - // We expect some folders to exist (dont' know how many) - $this->assertTrue(intval($xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue) > 2); - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>1</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - // No changes on second sync - $this->assertSame(strval(0), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); - - - //Clear the creation_synckey (that's the migration scenario) - //Shouldn't trigger a change - $rcube = \rcube::get_instance(); - $db = $rcube->get_dbh(); - $result = $db->query( - "UPDATE `syncroton_folder` SET `creation_synckey` = null", - ); - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>1</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $this->printDom($dom); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - // No changes on second sync - $this->assertSame(strval(0), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); - } - - /** - * Test invalid sync key - */ - public function testFolderInvalidSyncKey() - { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>999</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('9', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - } - - - /** - * Test synckey reuse - */ - public function testSyncKeyResend() - { - $this->deleteTestFolder('NewFolder', 'mail'); - $this->deleteTestFolder('NewFolder2', 'mail'); - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>0</SyncKey> - </FolderSync> - EOF; - $response = $this->request($request, 'FolderSync'); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - - //Now change something - $this->createTestFolder("NewFolder", "mail"); - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>1</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame('2', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame(strval(1), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); - - //Resend the same synckey - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>1</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame('2', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame(strval(1), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); - - //And now make sure we can still move on - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>2</SyncKey> - </FolderSync> - EOF; - $response = $this->request($request, 'FolderSync'); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame('2', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - - //Now add another folder - $this->createTestFolder("NewFolder2", "mail"); - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>2</SyncKey> - </FolderSync> - EOF; - $response = $this->request($request, 'FolderSync'); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame('3', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame(strval(1), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); - - //And finally make sure we can't go back two synckeys (because that has been cleaned up meanwhile) - $this->createTestFolder("NewFolder2", "mail"); - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>1</SyncKey> - </FolderSync> - EOF; - $response = $this->request($request, 'FolderSync'); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $this->assertSame('9', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - - // Cleanup for the other tests - $this->deleteTestFolder('NewFolder', 'mail'); - $this->deleteTestFolder('NewFolder2', 'mail'); - } - - /** - * Test FolderSync command - */ - public function testFolderSync() - { - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>0</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - // Note: We're expecting activesync_init_subscriptions=0 here. - if ($this->isStorageDriver('kolab4')) { - $folders = - 'Calendar', Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR, - 'Contacts', Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT, - 'INBOX', Syncroton_Command_FolderSync::FOLDERTYPE_INBOX, - 'Drafts', Syncroton_Command_FolderSync::FOLDERTYPE_DRAFTS, - 'Sent', Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL, - 'Trash', Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS, - 'Tasks', Syncroton_Command_FolderSync::FOLDERTYPE_TASK, - ; - - } else { - $folders = - 'Calendar', Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR, - 'Contacts', Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT, - 'INBOX', Syncroton_Command_FolderSync::FOLDERTYPE_INBOX, - 'Drafts', Syncroton_Command_FolderSync::FOLDERTYPE_DRAFTS, - 'Sent', Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL, - 'Trash', Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS, - 'Notes', Syncroton_Command_FolderSync::FOLDERTYPE_NOTE, - 'Tasks', Syncroton_Command_FolderSync::FOLDERTYPE_TASK, - ; - } - - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame(strval(count($folders)), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); - - foreach ($folders as $idx => $folder) { - $this->assertSame($folder0, $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:DisplayName")->item($idx)->nodeValue); - $this->assertSame((string) $folder1, $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:Type")->item($idx)->nodeValue); - $this->assertSame('0', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ParentId")->item($idx)->nodeValue); - } - - // Test with multi-folder support enabled - self::$deviceType = 'iphone'; - - $response = $this->request($request, 'FolderSync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - if ($this->isStorageDriver('kolab4')) { - $folders = - 'Calendar', Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR, - // Note: Kolab 4 with Cyrus DAV uses Addressbook, but Kolab 3 with iRony would use 'Contacts' - '/^(Contacts|Addressbook)$/', Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT, - 'INBOX', Syncroton_Command_FolderSync::FOLDERTYPE_INBOX, - 'Drafts', Syncroton_Command_FolderSync::FOLDERTYPE_DRAFTS, - 'Sent', Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL, - 'Trash', Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS, - // Note: For now Kolab 4 uses the same Calendar folder for calendar and tasks - '/^(Tasks|Calendar)$/', Syncroton_Command_FolderSync::FOLDERTYPE_TASK, - ; - } - - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame(strval(count($folders)), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); - - foreach ($folders as $idx => $folder) { - $displayName = $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:DisplayName")->item($idx)->nodeValue; - if (str_starts_with($folder0, '/')) { - $this->assertMatchesRegularExpression($folder0, $displayName); - } else { - $this->assertSame($folder0, $displayName); - } - $this->assertSame((string) $folder1, $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:Type")->item($idx)->nodeValue); - $this->assertSame('0', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ParentId")->item($idx)->nodeValue); - $idx++; - } - - // After we switched to multi-folder supported mode we expect next FolderSync - // to delete the old "collective" folders - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>1</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $deleted = $this->isStorageDriver('kolab4') ? 3 : 4; // No Notes folder in Kolab4 - $syncKey = 2; - - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval($syncKey), $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame(strval($deleted), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); - $this->assertSame($deleted, $xpath->query("//ns:FolderSync/ns:Changes/ns:Delete")->length); - - return $syncKey; - } - - /** - * Test FolderCreate command - * - * @depends testFolderSync - */ - public function testFolderCreate($syncKey) - { - // Multi-folder mode - self::$deviceType = 'iphone'; - - // Create a mail folder - $folderName1 = 'Test Folder'; - $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderCreate xmlns="uri:FolderHierarchy"> - <SyncKey>{$syncKey}</SyncKey> - <ParentId>0</ParentId> - <DisplayName>{$folderName1}</DisplayName> - <Type>{$folderType}</Type> - </FolderCreate> - EOF; - - $response = $this->request($request, 'FolderCreate'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:FolderCreate/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("//ns:FolderCreate/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("//ns:FolderCreate/ns:ServerId")->count()); - $folder1 = $xpath->query("//ns:FolderCreate/ns:ServerId")->item(0)->nodeValue; - - // Note: After FolderCreate there are no changes in the following FolderSync expected - - // Create a contacts folder - $folderName2 = 'Test Contacts Folder'; - $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderCreate xmlns="uri:FolderHierarchy"> - <SyncKey>{$syncKey}</SyncKey> - <ParentId>0</ParentId> - <DisplayName>{$folderName2}</DisplayName> - <Type>{$folderType}</Type> - </FolderCreate> - EOF; - - $response = $this->request($request, 'FolderCreate'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:FolderCreate/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("//ns:FolderCreate/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("//ns:FolderCreate/ns:ServerId")->count()); - $folder2 = $xpath->query("//ns:FolderCreate/ns:ServerId")->item(0)->nodeValue; - - // Note: After FolderCreate there are no changes in the following FolderSync expected - - // TODO: Test folder with a parent - - return - 'SyncKey' => $syncKey, - 'folders' => - $folder1, - $folder2, - , - ; - } - - /** - * Test FolderUpdate command - * - * @depends testFolderCreate - */ - public function testFolderUpdate($params) - { - // Multi-folder mode - self::$deviceType = 'iphone'; - - // Test renaming a mail folder - $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderUpdate xmlns="uri:FolderHierarchy"> - <SyncKey>{$params'SyncKey'}</SyncKey> - <ServerId>{$params'folders'0}</ServerId> - <ParentId/> - <DisplayName>Test Folder New</DisplayName> - <Type>{$folderType}</Type> - </FolderUpdate> - EOF; - - $response = $this->request($request, 'FolderUpdate'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:FolderUpdate/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$params'SyncKey'), $xpath->query("//ns:FolderUpdate/ns:SyncKey")->item(0)->nodeValue); - - // Test FolderSync after folder update, get the new folder id (for delete test) - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>{$params'SyncKey'}</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - // Note we expect Add+Delete here, instead of Update (but this could change in the future) - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$params'SyncKey'), $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("//ns:FolderSync/ns:Changes/ns:Add")->length); - $this->assertSame(1, $xpath->query("//ns:FolderSync/ns:Changes/ns:Delete")->length); - $this->assertSame($params'folders'0, $xpath->query("//ns:FolderSync/ns:Changes/ns:Delete/ns:ServerId")->item(0)->nodeValue); - $this->assertSame('0', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ParentId")->item(0)->nodeValue); - $this->assertSame('Test Folder New', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:DisplayName")->item(0)->nodeValue); - $this->assertSame(strval($folderType), $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:Type")->item(0)->nodeValue); - $params'folders'0 = $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ServerId")->item(0)->nodeValue; - - // Test renaming a contacts folder - $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderUpdate xmlns="uri:FolderHierarchy"> - <SyncKey>{$params'SyncKey'}</SyncKey> - <ServerId>{$params'folders'1}</ServerId> - <ParentId/> - <DisplayName>Test Contacts New</DisplayName> - <Type>{$folderType}</Type> - </FolderUpdate> - EOF; - - $response = $this->request($request, 'FolderUpdate'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:FolderUpdate/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$params'SyncKey'), $xpath->query("//ns:FolderUpdate/ns:SyncKey")->item(0)->nodeValue); - - // Test FolderSync after folder update, get the new folder id (for delete test) - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>{$params'SyncKey'}</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$params'SyncKey'), $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); - - if ($this->isStorageDriver('kolab4')) { - // Note we expect Update here, not Add+Delete, folder ID does not change - $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); - $this->assertSame($params'folders'1, $xpath->query("//ns:FolderSync/ns:Changes/ns:Update/ns:ServerId")->item(0)->nodeValue); - $this->assertSame('Test Contacts New', $xpath->query("//ns:FolderSync/ns:Changes/ns:Update/ns:DisplayName")->item(0)->nodeValue); - $this->assertSame(strval($folderType), $xpath->query("//ns:FolderSync/ns:Changes/ns:Update/ns:Type")->item(0)->nodeValue); - } else { - // Note we expect Add+Delete here, instead of Update (but this could change in the future) - $this->assertSame('2', $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); - $this->assertSame($params'folders'1, $xpath->query("//ns:FolderSync/ns:Changes/ns:Delete/ns:ServerId")->item(0)->nodeValue); - $this->assertSame('0', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ParentId")->item(0)->nodeValue); - $this->assertSame('Test Contacts New', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:DisplayName")->item(0)->nodeValue); - $this->assertSame(strval($folderType), $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:Type")->item(0)->nodeValue); - $params'folders'1 = $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ServerId")->item(0)->nodeValue; - } - - // TODO: Test folder with a parent change - // TODO: Assert the folder name has changed in the storage - // TODO: Test Sync after a DAV folder rename made in another client - - return $params; - } - - /** - * Test FolderDelete command - * - * @depends testFolderUpdate - */ - public function testFolderDelete($params) - { - // Multi-folder mode - self::$deviceType = 'iphone'; - - // Delete mail folder - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderDelete xmlns="uri:FolderHierarchy"> - <SyncKey>{$params'SyncKey'}</SyncKey> - <ServerId>{$params'folders'0}</ServerId> - </FolderDelete> - EOF; - - $response = $this->request($request, 'FolderDelete'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:FolderDelete/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$params'SyncKey'), $xpath->query("//ns:FolderDelete/ns:SyncKey")->item(0)->nodeValue); - - // Note: After FolderDelete there are no changes in the following FolderSync expected - - // Delete contacts folder - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderDelete xmlns="uri:FolderHierarchy"> - <SyncKey>{$params'SyncKey'}</SyncKey> - <ServerId>{$params'folders'1}</ServerId> - </FolderDelete> - EOF; - - $response = $this->request($request, 'FolderDelete'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:FolderDelete/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$params'SyncKey'), $xpath->query("//ns:FolderDelete/ns:SyncKey")->item(0)->nodeValue); - - // Note: After FolderDelete there are no changes in the following FolderSync expected - - // TODO: Assert the folders no longer exist - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/ItemOperationsTest.php
Deleted
@@ -1,81 +0,0 @@ -<?php - -class ItemOperationsTest extends Tests\SyncTestCase -{ - /** - * Test ItemOperations::EmptyFolderContents request - */ - public function testEmptyFolderContents() - { - $this->registerDevice(); - - // TODO: Test invalid folder ID - $collectionId = 'AAAAAAAAAAAA'; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <ItemOperations xmlns="uri:ItemOperations" xmlns:AirSync="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <EmptyFolderContents> - <AirSync:CollectionId>{$collectionId}</AirSync:CollectionId> - <Options><DeleteSubFolders/></Options> - </EmptyFolderContents> - </ItemOperations> - EOF; - - $response = $this->request($request, 'ItemOperations'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:ItemOperations/ns:Status")->item(0)->nodeValue); - $this->assertSame( - strval(Syncroton_Exception_Status_ItemOperations::ITEM_SERVER_ERROR), - $xpath->query("//ns:ItemOperations/ns:Response/ns:EmptyFolderContents/ns:Status")->item(0)->nodeValue - ); - $this->assertSame( - $collectionId, - $xpath->query("//ns:ItemOperations/ns:Response/ns:EmptyFolderContents/AirSync:CollectionId")->item(0)->nodeValue - ); - - // Test Trash folder - $collectionId = array_search('Trash', $this->folders); - $this->assertIsString($collectionId); - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <ItemOperations xmlns="uri:ItemOperations" xmlns:AirSync="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <EmptyFolderContents> - <AirSync:CollectionId>{$collectionId}</AirSync:CollectionId> - <Options><DeleteSubFolders/></Options> - </EmptyFolderContents> - </ItemOperations> - EOF; - - $response = $this->request($request, 'ItemOperations'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:ItemOperations/ns:Status")->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("//ns:ItemOperations/ns:Response/ns:EmptyFolderContents/ns:Status")->item(0)->nodeValue); - $this->assertSame($collectionId, $xpath->query("//ns:ItemOperations/ns:Response/ns:EmptyFolderContents/AirSync:CollectionId")->item(0)->nodeValue); - - // TODO: Test DAV folder - // TODO: Test a folder with subfolders - // TODO: Test non-empty folder and assert that all objects are gone - $this->markTestIncomplete(); - } - - /** - * Test ItemOperations::Fetch request - */ - public function testFetch() - { - $this->markTestIncomplete(); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/MeetingResponseTest.php
Deleted
@@ -1,131 +0,0 @@ -<?php - -namespace Tests\Sync; - -class MeetingResponseTest extends \Tests\SyncTestCase -{ - /** - * Test MeetingResponse command - */ - public function testAcceptingInvitation() - { - $this->emptyTestFolder($davFolder = 'Calendar', 'event'); - $this->emptyTestFolder('INBOX', 'mail'); - - $this->registerDevice(); - - // Do the initial INBOX sync - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; // INBOX - $syncKey = 0; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:Sync/ns:Collections/ns:Collection/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("//ns:Sync/ns:Collections/ns:Collection/ns:SyncKey")->item(0)->nodeValue); - - // Append an invitation email, and sync it - $sync = \kolab_sync::get_instance(); - $replace = - '$from' => 'test.test@domain.tld', - '$to' => $sync->config->get('activesync_test_username'), - ; - $this->appendMail('INBOX', 'mail.itip1', $replace); - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <WindowSize>1</WindowSize> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0); - $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("ns:SyncKey", $root)->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("ns:Commands/ns:Add", $root)->count()); - - $serverId = $xpath->query("ns:Commands/ns:Add/ns:ServerId", $root)->item(0)->nodeValue; - - $root = $xpath->query("ns:Commands/ns:Add/ns:ApplicationData", $root)->item(0); - $this->assertSame('You\'ve been invited to "Test"', $xpath->query("Email:Subject", $root)->item(0)->nodeValue); - $this->assertSame('Organizer <test.test@domain.tld>', $xpath->query("Email:From", $root)->item(0)->nodeValue); - $this->assertSame($replace'$to', $xpath->query("Email:To", $root)->item(0)->nodeValue); - $this->assertSame('0', $xpath->query("Email:Read", $root)->item(0)->nodeValue); - $this->assertSame('IPM.Schedule.Meeting.Request', $xpath->query("Email:MessageClass", $root)->item(0)->nodeValue); - $this->assertSame('urn:content-classes:calendarmessage', $xpath->query("Email:ContentClass", $root)->item(0)->nodeValue); - $root = $xpath->query("Email:MeetingRequest", $root)->item(0); - $this->assertSame('0', $xpath->query("Email:AllDayEvent", $root)->item(0)->nodeValue); - $this->assertSame('2023-12-07T13:00:00.000Z', $xpath->query("Email:StartTime", $root)->item(0)->nodeValue); - $this->assertSame('2023-12-07T13:30:00.000Z', $xpath->query("Email:EndTime", $root)->item(0)->nodeValue); - $this->assertSame('test.test@domain.tld', $xpath->query("Email:Organizer", $root)->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("Email:ResponseRequested", $root)->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("Email:DisallowNewTimeProposal", $root)->item(0)->nodeValue); - - // Accept the invitation - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <MeetingResponse xmlns="uri:MeetingResponse" xmlns:Search="uri:Search"> - <Request> - <UserResponse>1</UserResponse> - <CollectionId>{$folderId}</CollectionId> - <RequestId>{$serverId}</RequestId> - </Request> - </MeetingResponse> - EOF; - - $response = $this->request($request, 'MeetingResponse'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $xpath->registerNamespace('MeetingResponse', 'uri:MeetingResponse'); - - $root = $xpath->query("//MeetingResponse:MeetingResponse/MeetingResponse:Result")->item(0); - $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue); - $this->assertSame($serverId, $xpath->query("ns:RequestId", $root)->item(0)->nodeValue); - $this->assertStringMatchesFormat("CRC%s", $xpath->query("ns:CalendarId", $root)->item(0)->nodeValue); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/MoveItemsTest.php
Deleted
@@ -1,402 +0,0 @@ -<?php - -class MoveItemsTest extends Tests\SyncTestCase -{ - /** - * Test moving an email message - */ - public function testMoveEmail() - { - $this->emptyTestFolder('INBOX', 'mail'); - $this->emptyTestFolder('Trash', 'mail'); - $uid = $this->appendMail('INBOX', 'mail.sync1'); - $this->registerDevice(); - - $inbox = array_search('INBOX', $this->folders); - $trash = array_search('Trash', $this->folders); - - // Initial sync - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync"> - <Collections> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>{$inbox}</CollectionId> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>{$trash}</CollectionId> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - // Sync mail from INBOX and Trash - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>1</SyncKey> - <CollectionId>{$inbox}</CollectionId> - <GetChanges>1</GetChanges> - </Collection> - <Collection> - <SyncKey>1</SyncKey> - <CollectionId>{$trash}</CollectionId> - <GetChanges>1</GetChanges> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame(1, $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->count()); - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0); - $this->assertSame(1, $xpath->query("ns:Commands/ns:Add", $root)->count()); - $root = $xpath->query("ns:Commands/ns:Add", $root)->item(0); - $this->assertSame('test sync', $xpath->query("ns:ApplicationData/Email:Subject", $root)->item(0)->nodeValue); - - // Move the message to $trash - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <MoveItems xmlns="uri:Move"> - <Move> - <SrcMsgId>{$inbox}::{$uid}</SrcMsgId> - <SrcFldId>{$inbox}</SrcFldId> - <DstFldId>{$trash}</DstFldId> - </Move> - </MoveItems> - EOF; - - $response = $this->request($request, 'MoveItems'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $xpath->registerNamespace('Move', 'uri:Move'); - - $root = $xpath->query("//Move:MoveItems/Move:Response")->item(0); - $this->assertSame('3', $xpath->query("Move:Status", $root)->item(0)->nodeValue); - $this->assertSame("{$inbox}::{$uid}", $xpath->query("Move:SrcMsgId", $root)->item(0)->nodeValue); - $serverId = $xpath->query("Move:DstMsgId", $root)->item(0)->nodeValue; - - // Sync mail from INBOX and Trash - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>2</SyncKey> - <CollectionId>{$inbox}</CollectionId> - <GetChanges>1</GetChanges> - </Collection> - <Collection> - <SyncKey>1</SyncKey> - <CollectionId>{$trash}</CollectionId> - <GetChanges>1</GetChanges> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0); // INBOX - $this->assertSame($inbox, $xpath->query("ns:CollectionId", $root)->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("ns:Commands/ns:Delete", $root)->count()); - $this->assertSame("$inbox::$uid", $xpath->query("ns:Commands/ns:Delete/ns:ServerId", $root)->item(0)->nodeValue); - - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(1); // Trash - $this->assertSame($trash, $xpath->query("ns:CollectionId", $root)->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("ns:Commands/ns:Add", $root)->count()); - $this->assertSame('test sync', $xpath->query("ns:Commands/ns:Add/ns:ApplicationData/Email:Subject", $root)->item(0)->nodeValue); - } - - public function testInvalidMove() - { - $this->emptyTestFolder('INBOX', 'mail'); - $this->emptyTestFolder('Trash', 'mail'); - $uid = $this->appendMail('INBOX', 'mail.sync1'); - $this->registerDevice(); - $inbox = array_search('INBOX', $this->folders); - $trash = array_search('Trash', $this->folders); - - // Move item that doesn't exist - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <MoveItems xmlns="uri:Move"> - <Move> - <SrcMsgId>foobar::99999</SrcMsgId> - <SrcFldId>foobar</SrcFldId> - <DstFldId>foobar</DstFldId> - </Move> - </MoveItems> - EOF; - - $response = $this->request($request, 'MoveItems'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $xpath->registerNamespace('Move', 'uri:Move'); - - $root = $xpath->query("//Move:MoveItems/Move:Response")->item(0); - $this->assertSame('1', $xpath->query("Move:Status", $root)->item(0)->nodeValue); - - // Move item that doesn't exist - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <MoveItems xmlns="uri:Move"> - <Move> - <SrcMsgId>{$inbox}::99999</SrcMsgId> - <SrcFldId>{$inbox}</SrcFldId> - <DstFldId>{$trash}</DstFldId> - </Move> - </MoveItems> - EOF; - - $response = $this->request($request, 'MoveItems'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $xpath->registerNamespace('Move', 'uri:Move'); - - $root = $xpath->query("//Move:MoveItems/Move:Response")->item(0); - $this->assertSame('1', $xpath->query("Move:Status", $root)->item(0)->nodeValue); - } - - /** - * Test moving a contact - */ - public function testMoveContact() - { - if ($this->isStorageDriver('kolab')) { - // The Contacts folder is not available, and consequently appendObject fails - $this->markTestSkipped('This test only works with the DAV backend.'); - } - - // Test with multi-folder support enabled - self::$deviceType = 'iphone'; - - // @phpstan-ignore-next-line - $davFolder = $this->isStorageDriver('kolab') ? 'Contacts' : 'Addressbook'; - $this->emptyTestFolder($davFolder, 'contact'); - $this->deleteTestFolder($folderName = 'Test Contacts Folder', 'contact'); - $this->appendObject($davFolder, 'contact.vcard1', 'contact'); - - $this->registerDevice(); - - $srcFolderId = array_search($davFolder, $this->folders); - $this->assertTrue(!empty($srcFolderId)); - - // Create a contacts folder - $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderCreate xmlns="uri:FolderHierarchy"> - <SyncKey>1</SyncKey> - <ParentId>0</ParentId> - <DisplayName>{$folderName}</DisplayName> - <Type>{$folderType}</Type> - </FolderCreate> - EOF; - - $response = $this->request($request, 'FolderCreate'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $dstFolderId = $xpath->query("//ns:FolderCreate/ns:ServerId")->item(0)->nodeValue; - - // Sync both folders - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <Class>Contacts</Class> - <SyncKey>0</SyncKey> - <CollectionId>{$srcFolderId}</CollectionId> - </Collection> - <Collection> - <Class>Contacts</Class> - <SyncKey>0</SyncKey> - <CollectionId>{$dstFolderId}</CollectionId> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0); - $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue); - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <Class>Contacts</Class> - <SyncKey>1</SyncKey> - <CollectionId>{$srcFolderId}</CollectionId> - <DeletesAsMoves/> - <GetChanges/> - <Options> - <AirSyncBase:BodyPreference> - <AirSyncBase:Type>1</AirSyncBase:Type> - <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize> - </AirSyncBase:BodyPreference> - <Conflict>1</Conflict> - </Options> - </Collection> - <Collection> - <Class>Contacts</Class> - <SyncKey>1</SyncKey> - <CollectionId>{$dstFolderId}</CollectionId> - <DeletesAsMoves/> - <GetChanges/> - <Options> - <AirSyncBase:BodyPreference> - <AirSyncBase:Type>1</AirSyncBase:Type> - <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize> - </AirSyncBase:BodyPreference> - <Conflict>1</Conflict> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0); - $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue); - $this->assertSame($srcFolderId, $xpath->query("ns:CollectionId", $root)->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("ns:Commands/ns:Add", $root)->count()); - $this->assertSame('Jane', $xpath->query("ns:Commands/ns:Add/ns:ApplicationData/Contacts:FirstName", $root)->item(0)->nodeValue); - $srcMsgId = $xpath->query("ns:Commands/ns:Add/ns:ServerId", $root)->item(0)->nodeValue; - - // Move the message to the other folder - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <MoveItems xmlns="uri:Move"> - <Move> - <SrcMsgId>{$srcMsgId}</SrcMsgId> - <SrcFldId>{$srcFolderId}</SrcFldId> - <DstFldId>{$dstFolderId}</DstFldId> - </Move> - </MoveItems> - EOF; - - $response = $this->request($request, 'MoveItems'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $xpath->registerNamespace('Move', 'uri:Move'); - - $root = $xpath->query("//Move:MoveItems/Move:Response")->item(0); - $this->assertSame('3', $xpath->query("Move:Status", $root)->item(0)->nodeValue); - $this->assertSame($srcMsgId, $xpath->query("Move:SrcMsgId", $root)->item(0)->nodeValue); - $dstMsgId = $xpath->query("Move:DstMsgId", $root)->item(0)->nodeValue; - - // Sync the folders again - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <Class>Contacts</Class> - <SyncKey>2</SyncKey> - <CollectionId>{$srcFolderId}</CollectionId> - <DeletesAsMoves/> - <GetChanges/> - <Options> - <AirSyncBase:BodyPreference> - <AirSyncBase:Type>1</AirSyncBase:Type> - <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize> - </AirSyncBase:BodyPreference> - <Conflict>1</Conflict> - </Options> - </Collection> - <Collection> - <Class>Contacts</Class> - <SyncKey>1</SyncKey> - <CollectionId>{$dstFolderId}</CollectionId> - <DeletesAsMoves/> - <GetChanges/> - <Options> - <AirSyncBase:BodyPreference> - <AirSyncBase:Type>1</AirSyncBase:Type> - <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize> - </AirSyncBase:BodyPreference> - <Conflict>1</Conflict> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0); // src folder - $this->assertSame($srcFolderId, $xpath->query("ns:CollectionId", $root)->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("ns:Commands/ns:Delete", $root)->count()); - $this->assertSame($srcMsgId, $xpath->query("ns:Commands/ns:Delete/ns:ServerId", $root)->item(0)->nodeValue); - - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(1); // dst folder - $this->assertSame($dstFolderId, $xpath->query("ns:CollectionId", $root)->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("ns:Commands/ns:Add", $root)->count()); - $this->assertSame('Jane', $xpath->query("ns:Commands/ns:Add/ns:ApplicationData/Contacts:FirstName", $root)->item(0)->nodeValue); - $this->assertSame($dstMsgId, $xpath->query("ns:Commands/ns:Add/ns:ServerId", $root)->item(0)->nodeValue); - - $this->deleteTestFolder($folderName, 'contact'); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/OptionsTest.php
Deleted
@@ -1,16 +0,0 @@ -<?php - -class OptionsTest extends Tests\SyncTestCase -{ - /** - * Test Options command/request - */ - public function testOptions() - { - $response = self::$client->request('OPTIONS', '', 'auth' => null); - $this->assertEquals(200, $response->getStatusCode()); - $this->assertStringContainsString('14', $response->getHeader('MS-Server-ActiveSync')0); - $this->assertStringContainsString('14.1', $response->getHeader('MS-ASProtocolVersions')0); - $this->assertStringContainsString('FolderSync', $response->getHeader('MS-ASProtocolCommands')0); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/PingTest.php
Deleted
@@ -1,102 +0,0 @@ -<?php - -class PingTest extends Tests\SyncTestCase -{ - - /** - * Test Ping command - */ - public function testFolderSyncBasic() - { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Ping xmlns="uri:Ping"> - <HeartbeatInterval>900</HeartbeatInterval> - <Folders> - <Folder> - <Id>38b950ebd62cd9a66929c89615d0fc04</Id> - <Class>Email</Class> - </Folder> - </Folders> - </Ping> - EOF; - - $response = $this->request($request, 'Ping'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $this->printDom($dom); - - //Initially we know no folders - $this->assertSame('7', $xpath->query("//ns:Ping/ns:Status")->item(0)->nodeValue); - - - //We discover folders with a foldersync - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>0</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - $this->assertEquals(200, $response->getStatusCode()); - - //Now we get to the actual ping - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Ping xmlns="uri:Ping"> - <HeartbeatInterval>0</HeartbeatInterval> - <Folders> - <Folder> - <Id>38b950ebd62cd9a66929c89615d0fc04</Id> - <Class>Email</Class> - </Folder> - </Folders> - </Ping> - EOF; - - $response = $this->request($request, 'Ping'); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - // $this->printDom($dom); - //Initially we know no folders - $this->assertSame('2', $xpath->query("//ns:Ping/ns:Status")->item(0)->nodeValue); - } - - /** - * Test Ping command - */ - public function testUnknownFolder() - { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Ping xmlns="uri:Ping"> - <HeartbeatInterval>900</HeartbeatInterval> - <Folders> - <Folder> - <Id>foobar</Id> - <Class>Email</Class> - </Folder> - </Folders> - </Ping> - EOF; - - $response = $this->request($request, 'Ping'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - // $this->printDom($dom); - - $this->assertSame('7', $xpath->query("//ns:Ping/ns:Status")->item(0)->nodeValue); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/ProvisionTest.php
Deleted
@@ -1,45 +0,0 @@ -<?php - -class ProvisionTest extends Tests\SyncTestCase -{ - /** - * Test Provision command - */ - public function testProvision() - { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Provision xmlns="uri:Provision" xmlns:Settings="uri:Settings"> - <DeviceInformation xmlns="uri:Settings"> - <Set> - <Model>moto e(6) plus</Model> - <IMEI>000000000000000</IMEI> - <FriendlyName>pokerp_reteu_64</FriendlyName> - <OS>Android 9.58-8</OS> - <OSLanguage>Polish (Poland)</OSLanguage> - <MobileOperator/> - </Set> - </DeviceInformation> - <Policies> - <Policy> - <PolicyType>MS-EAS-Provisioning-WBXML</PolicyType> - </Policy> - </Policies> - </Provision> - EOF; - - $response = $this->request($request, 'Provision'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:Provision/ns:Status")->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("//ns:Provision/Settings:DeviceInformation/Settings:Status")->item(0)->nodeValue); - $this->assertSame('2', $xpath->query("//ns:Provision/ns:Policies/ns:Policy/ns:Status")->item(0)->nodeValue); - - // TODO: Assert the properties have been set - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/SettingsTest.php
Deleted
@@ -1,80 +0,0 @@ -<?php - -class SettingsTest extends Tests\SyncTestCase -{ - /** - * Test Settings command - */ - public function testSettingsUserInformation() - { - // Test retrieving the settings - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Settings xmlns="uri:Settings"> - <UserInformation> - <Get/> - </UserInformation> - </Settings> - EOF; - - $response = $this->request($request, 'Settings'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = self::fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:Settings/ns:Status")->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("//ns:Settings/ns:UserInformation/ns:Status")->item(0)->nodeValue); - $this->assertSame( - self::$username, - $xpath->query("//ns:Settings/ns:UserInformation/ns:Get/ns:Accounts/ns:Account/ns:EmailAddresses/ns:PrimarySmtpAddress")->item(0)->nodeValue - ); - } - - /** - * Test Settings command - */ - public function testSettingsDeviceInfomation() - { - // Test device info update - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Settings xmlns="uri:Settings"> - <DeviceInformation> - <Set> - <Model>moto plus</Model> - <IMEI>111111111</IMEI> - <FriendlyName>fn</FriendlyName> - <OS>Android 10</OS> - <OSLanguage>English</OSLanguage> - <MobileOperator/> - </Set> - </DeviceInformation> - </Settings> - EOF; - - $response = $this->request($request, 'Settings'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:Settings/ns:Status")->item(0)->nodeValue); - $this->assertSame('1', $xpath->query("//ns:Settings/ns:DeviceInformation/ns:Set/ns:Status")->item(0)->nodeValue); - - // TODO: Assert the properties have been set - } - - /** - * Test Settings command regarding OOF - */ - public function testSettingsOOF() - { - // TODO: Test OOF settings - $this->markTestIncomplete(); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/Sync
Deleted
-(directory)
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/Sync/CalendarTest.php
Deleted
@@ -1,75 +0,0 @@ -<?php - -namespace Tests\Sync\Sync; - -class CalendarTest extends \Tests\SyncTestCase -{ - /** - * Test Sync command - */ - public function testSync() - { - $this->emptyTestFolder($davFolder = 'Calendar', 'event'); - $this->registerDevice(); - - // Test empty folder - $folderId = 'Calendar::Syncroton'; - $syncKey = 0; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <Class>Calendar</Class> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves/> - <GetChanges/> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - - // Append two event objects and sync them - $this->appendObject($davFolder, 'event.ics1', 'event'); - $this->appendObject($davFolder, 'event.ics2', 'event'); - - $request = str_replace("<SyncKey>0</SyncKey>", "<SyncKey>{$syncKey}</SyncKey>", $request); - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(2, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - - $root .= "/ns:Commands/ns:Add"; - $this->assertStringMatchesFormat("CRC%s", $xpath->query("{$root}/ns:ServerId")->item(0)->nodeValue); - $this->assertSame('20240715T170000Z', $xpath->query("{$root}/ns:ApplicationData/Calendar:StartTime")->item(0)->nodeValue); - $this->assertSame('Meeting', $xpath->query("{$root}/ns:ApplicationData/Calendar:Subject")->item(0)->nodeValue); - $this->assertSame('20240714T170000Z', $xpath->query("{$root}/ns:ApplicationData/Calendar:StartTime")->item(1)->nodeValue); - $this->assertSame('Party', $xpath->query("{$root}/ns:ApplicationData/Calendar:Subject")->item(1)->nodeValue); - - return $syncKey; - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/Sync/ContactsTest.php
Deleted
@@ -1,250 +0,0 @@ -<?php - -namespace Tests\Sync\Sync; - -class ContactsTest extends \Tests\SyncTestCase -{ - /** - * Test Sync command - */ - public function testSync() - { - $davFolder = $this->isStorageDriver('kolab') ? 'Contacts' : 'Addressbook'; - $this->emptyTestFolder($davFolder, 'contact'); - $this->deleteTestFolder('Test Contacts Folder', 'contact'); // from other test files - $this->registerDevice(); - - // Test empty contacts folder - $folderId = 'Contacts::Syncroton'; - $syncKey = 0; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <Class>Contacts</Class> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves/> - <GetChanges/> - <Options> - <AirSyncBase:BodyPreference> - <AirSyncBase:Type>1</AirSyncBase:Type> - <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize> - </AirSyncBase:BodyPreference> - <Conflict>1</Conflict> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - - // Append two contact objects and sync them - // TODO: Test a folder with contact groups inside - $this->appendObject($davFolder, 'contact.vcard1', 'contact'); - $this->appendObject($davFolder, 'contact.vcard2', 'contact'); - - $request = str_replace("<SyncKey>0</SyncKey>", "<SyncKey>{$syncKey}</SyncKey>", $request); - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(2, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - - $root .= "/ns:Commands/ns:Add"; - $this->assertStringMatchesFormat("CRC%s", $xpath->query("{$root}/ns:ServerId")->item(0)->nodeValue); - $this->assertSame('Jack', $xpath->query("{$root}/ns:ApplicationData/Contacts:FirstName")->item(0)->nodeValue); - $this->assertSame('Strong', $xpath->query("{$root}/ns:ApplicationData/Contacts:LastName")->item(0)->nodeValue); - $this->assertSame('Jane', $xpath->query("{$root}/ns:ApplicationData/Contacts:FirstName")->item(1)->nodeValue); - $this->assertSame('Doe', $xpath->query("{$root}/ns:ApplicationData/Contacts:LastName")->item(1)->nodeValue); - - return $syncKey; - } - - /** - * Test adding objects from client - * - * @depends testSync - */ - public function testAddFromClient($syncKey) - { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Contacts="uri:Contacts"> - <Collections> - <Collection> - <Class>Contacts</Class> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>Contacts::Syncroton</CollectionId> - <DeletesAsMoves/> - <GetChanges/> - <Options> - <AirSyncBase:BodyPreference> - <AirSyncBase:Type>1</AirSyncBase:Type> - <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize> - </AirSyncBase:BodyPreference> - <Conflict>1</Conflict> - </Options> - <Commands> - <Add> - <ClientId>42</ClientId> - <ApplicationData> - <Contacts:FirstName>Lars</Contacts:FirstName> - </ApplicationData> - </Add> - </Commands> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0); - $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("ns:SyncKey", $root)->item(0)->nodeValue); - $root = $xpath->query("ns:Responses/ns:Add", $root)->item(0); - $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue); - $this->assertSame('42', $xpath->query("ns:ClientId", $root)->item(0)->nodeValue); - $serverId = $xpath->query("ns:ServerId", $root)->item(0)->nodeValue; - $this->assertStringMatchesFormat("CRC%s", $serverId); - - // TODO: Test the content on the server - - return $syncKey, $serverId; - } - - /** - * Test updating objects from client - * - * @depends testAddFromClient - */ - public function testChangeFromClient($params) - { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Contacts="uri:Contacts"> - <Collections> - <Collection> - <Class>Contacts</Class> - <SyncKey>{$params0}</SyncKey> - <CollectionId>Contacts::Syncroton</CollectionId> - <DeletesAsMoves/> - <GetChanges/> - <Options> - <AirSyncBase:BodyPreference> - <AirSyncBase:Type>1</AirSyncBase:Type> - <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize> - </AirSyncBase:BodyPreference> - <Conflict>1</Conflict> - </Options> - <Commands> - <Change> - <ServerId>{$params1}</ServerId> - <ApplicationData> - <Contacts:FirstName>First</Contacts:FirstName> - <Contacts:LastName>Last</Contacts:LastName> - </ApplicationData> - </Change> - </Commands> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0); - $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue); - $this->assertSame(strval(++$params0), $xpath->query("ns:SyncKey", $root)->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("ns:Responses", $root)->length); - - // TODO: Assert updated content on the server - - return $params; - } - - /** - * Test deleting objects from client - * - * @depends testChangeFromClient - */ - public function testDeleteFromClient($params) - { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Contacts="uri:Contacts"> - <Collections> - <Collection> - <Class>Contacts</Class> - <SyncKey>{$params0}</SyncKey> - <CollectionId>Contacts::Syncroton</CollectionId> - <DeletesAsMoves/> - <GetChanges/> - <Options> - <AirSyncBase:BodyPreference> - <AirSyncBase:Type>1</AirSyncBase:Type> - <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize> - </AirSyncBase:BodyPreference> - <Conflict>1</Conflict> - </Options> - <Commands> - <Delete> - <ServerId>{$params1}</ServerId> - </Delete> - </Commands> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0); - $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue); - $this->assertSame(strval(++$params0), $xpath->query("ns:SyncKey", $root)->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("ns:Responses", $root)->length); - - // TODO: Assert deleted contact on the server - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/Sync/EmailExtraDataMigrationTest.php
Deleted
@@ -1,115 +0,0 @@ -<?php - -namespace Tests\Sync\Sync; - -class EmailExtraDataMigrationTest extends \Tests\SyncTestCase -{ - /** - * Test Sync command - */ - public function testSync() - { - $this->emptyTestFolder('INBOX', 'mail'); - $this->registerDevice(); - - - // Test INBOX - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $syncKey = 0; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - $this->assertEquals(200, $response->getStatusCode()); - $syncKey++; - - // List mail in INBOX - // Append two mail messages - $this->appendMail('INBOX', 'mail.sync1'); - $this->appendMail('INBOX', 'mail.sync2'); - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(2, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - - // Simulate migration by clearing extra_data - $this->runSQLQuery("UPDATE syncroton_synckey SET extra_data = null;"); - - // List the rest of the mail - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - // We expect an empty response without a change - $this->assertEquals(0, $response->getBody()->getSize()); - - return $syncKey; - } - - -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/Sync/EmailITipTest.php
Deleted
@@ -1,81 +0,0 @@ -<?php - -namespace Tests\Sync\Sync; - -class EmailITipTest extends \Tests\SyncTestCase -{ - /** - * Test Sync with invalid itip - */ - public function testSyncWithInvalidITip() - { - $this->emptyTestFolder('INBOX', 'mail'); - $this->registerDevice(); - - // Test INBOX - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $syncKey = 0; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - $this->assertEquals(200, $response->getStatusCode()); - $syncKey++; - - // Append messages - $this->appendMail('INBOX', 'mail.itip1'); - $this->appendMail('INBOX', 'mail.itip.invalid'); - $this->appendMail('INBOX', 'mail.sync2'); - - // Test that the synchornization works with the invalid itip in the middle - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - // print($dom->saveXML()); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - // We expect all three messages to synchronize, even if we fail to parse the invitation in the middle - $this->assertSame(3, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/Sync/EmailTest.php
Deleted
@@ -1,473 +0,0 @@ -<?php - -namespace Tests\Sync\Sync; - -class EmailTest extends \Tests\SyncTestCase -{ - /** - * Test Sync command - */ - public function testSync() - { - $this->emptyTestFolder('INBOX', 'mail'); - $this->registerDevice(); - - // Test invalid collection identifier - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync"> - <Collections> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>1111111111</CollectionId> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('12', $xpath->query("//ns:Sync/ns:Status")->item(0)->nodeValue); - - // Test INBOX - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $syncKey = 0; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:Sync/ns:Collections/ns:Collection/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("//ns:Sync/ns:Collections/ns:Collection/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame('Email', $xpath->query("//ns:Sync/ns:Collections/ns:Collection/ns:Class")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("//ns:Sync/ns:Collections/ns:Collection/ns:CollectionId")->item(0)->nodeValue); - - // Test listing mail in INBOX, use WindowSize=1 - // Append two mail messages - $this->appendMail('INBOX', 'mail.sync1'); - $this->appendMail('INBOX', 'mail.sync2'); - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <WindowSize>1</WindowSize> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - - // Note: We assume messages are in IMAP default order, it may change in future - $root .= "/ns:Commands/ns:Add"; - $this->assertStringMatchesFormat("{$folderId}::%d", $xpath->query("{$root}/ns:ServerId")->item(0)->nodeValue); - $this->assertSame('test sync', $xpath->query("{$root}/ns:ApplicationData/Email:Subject")->item(0)->nodeValue); - - // List the rest of the mail - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - - // Note: We assume messages are in IMAP default order, it may change in future - $root .= "/ns:Commands/ns:Add"; - $this->assertStringMatchesFormat("{$folderId}::%d", $xpath->query("{$root}/ns:ServerId")->item(0)->nodeValue); - $this->assertSame('sync test with attachment', $xpath->query("{$root}/ns:ApplicationData/Email:Subject")->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("{$root}/ns:ApplicationData/AirSyncBase:Body")->count()); - - return $syncKey; - } - - /** - * Test empty sync response - * - * @depends testSync - */ - public function testEmptySync($syncKey) - { - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - // We expect an empty response without a change - $this->assertEquals(0, $response->getBody()->getSize()); - - return $syncKey; - } - - /** - * Test flag change - * - * @depends testEmptySync - */ - public function testFlagChange($syncKey) - { - $this->assertTrue($this->markMailAsRead('INBOX', '*')); - - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - // print($dom->saveXML()); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - $this->assertSame(2, $xpath->query("{$root}/ns:Commands/ns:Change")->count()); - $this->assertSame(2, $xpath->query("{$root}/ns:Commands/ns:Change/ns:ApplicationData/Email:Read")->count()); - $this->assertSame('0', $xpath->query("{$root}/ns:Commands/ns:Change/ns:ApplicationData/Email:Read")->item(0)->nodeValue); - $this->assertSame('0', $xpath->query("{$root}/ns:Commands/ns:Change/ns:ApplicationData/Email:Read")->item(1)->nodeValue); - - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Change/ns:ApplicationData/AirSyncBase:Body")->count()); - return $syncKey; - } - - /** - * Retry flag change - * Resending the same syncKey should result in the same changes. - * - * @depends testFlagChange - */ - public function testRetryFlagChange($syncKey) - { - $syncKey--; - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - // print($dom->saveXML()); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - //FIXME I'm not sure why we get syncKey + 2, I suppose we just always increase the current synckey by one. - $this->assertSame(strval($syncKey += 2), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - $this->assertSame(2, $xpath->query("{$root}/ns:Commands/ns:Change")->count()); - - $serverId1 = $xpath->query("{$root}/ns:Commands/ns:Change/ns:ServerId")->item(0)->nodeValue; - - return - 'syncKey' => $syncKey, - 'serverId' => $serverId1, - ; - } - - /** - * Test updating message properties from client - * - * @depends testRetryFlagChange - */ - public function testChangeFromClient($values) - { - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $syncKey = $values'syncKey'; - $serverId = $values'serverId'; - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:Syncroton="uri:Syncroton" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Email="uri:Email" xmlns:Email2="uri:Email2" xmlns:Tasks="uri:Tasks"> - <Collections> - <Collection xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <Commands xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <Change xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <ServerId>{$serverId}</ServerId> - <ApplicationData> - <Email:Read xmlns="uri:Email">0</Email:Read> - <Email:Flag xmlns="uri:Email"/> - </ApplicationData> - </Change> - </Commands> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - // print($dom->saveXML()); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - //The server doesn't have to report back successful changes - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Change")->count()); - - $emails = $this->listEmails('INBOX', '*'); - $uid = explode("::", $serverId)1; - $this->assertSame(2, count($emails)); - $this->assertTrue(!array_key_exists('SEEN', $emails$uid)); - - return - 'syncKey' => $syncKey, - 'serverId' => $serverId, - ; - } - - /** - * Test deleting messages from client - * - * @depends testChangeFromClient - */ - public function testDeleteFromClient($values) - { - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $syncKey = $values'syncKey'; - $serverId = $values'serverId'; - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:Syncroton="uri:Syncroton" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Email="uri:Email" xmlns:Email2="uri:Email2" xmlns:Tasks="uri:Tasks"> - <Collections> - <Collection xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <Commands xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <Delete xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <ServerId>{$serverId}</ServerId> - </Delete> - </Commands> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - // print($dom->saveXML()); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Change")->count()); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Delete")->count()); - - $emails = $this->listEmails('INBOX', '*'); - $uid = explode("::", $serverId)1; - $this->assertSame(2, count($emails)); - $this->assertTrue($emails$uid'DELETED'); - - return $syncKey; - } - - - /** - * Test a sync key that doesn't exist yet. - * @depends testDeleteFromClient - */ - public function testInvalidSyncKey($syncKey) - { - $syncKey++; - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - // print($dom->saveXML()); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('3', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame('0', $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - - //We have to start over after this. The sync state was removed. - return 0; - } - -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/Sync/InconsistencyTest.php
Deleted
@@ -1,146 +0,0 @@ -<?php - -namespace Tests\Sync\Sync; - -class InconsistencyTest extends \Tests\SyncTestCase -{ - /** - * Test Sync command - */ - public function testSync() - { - $this->emptyTestFolder('INBOX', 'mail'); - $this->registerDevice(); - - // Append two mail messages - $uid1 = $this->appendMail('INBOX', 'mail.sync1'); - $this->appendMail('INBOX', 'mail.sync2'); - - // Initial sync - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $syncKey = 0; - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - $this->assertEquals(200, $response->getStatusCode()); - $syncKey++; - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <WindowSize>2</WindowSize> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(2, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - - // Initial sync is complete - // We now artifically create a sync inconsistency be deleting the content part of the first mail. - // This replicates a situation that we've seen, but don't know yet how it was created in the first place. - $rcube = \rcube::get_instance(); - $db = $rcube->get_dbh(); - $result = $db->query( - "DELETE FROM `syncroton_content`" - . " WHERE `contentid` = ?", - "$folderId::$uid1" - ); - $this->assertNull($db->is_error($result)); - - // Now sync again - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - - $response = $this->request($request, 'Sync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(1, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - - - //Assert that we have all content parts back - $sync = \kolab_sync::get_instance(); - $device = $sync->storage()->device_get(self::$deviceId); - - $result = $db->query( - "SELECT `contentid` FROM `syncroton_content`" - . " WHERE `device_id` = ?", - $device'ID' - ); - $data = ; - while ($state = $db->fetch_assoc($result)) { - $data = $state; - } - $this->assertSame(2, count($data)); - - return $syncKey; - } - -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Sync/Sync/RelationsTest.php
Deleted
@@ -1,279 +0,0 @@ -<?php - -namespace Tests\Sync\Sync; - -class RelationsTest extends \Tests\SyncTestCase -{ - protected function initialSyncRequest($folderId) - { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync"> - <Collections> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>{$folderId}</CollectionId> - </Collection> - </Collections> - </Sync> - EOF; - return $this->request($request, 'Sync'); - } - - protected function syncRequest($syncKey, $folderId, $windowSize = null) - { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"> - <Collections> - <Collection> - <SyncKey>{$syncKey}</SyncKey> - <CollectionId>{$folderId}</CollectionId> - <DeletesAsMoves>1</DeletesAsMoves> - <GetChanges>1</GetChanges> - <WindowSize>{$windowSize}</WindowSize> - <Options> - <FilterType>0</FilterType> - <Conflict>1</Conflict> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>2</Type> - <TruncationSize>51200</TruncationSize> - <AllOrNone>0</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - </Sync> - EOF; - return $this->request($request, 'Sync'); - } - - private function getRelationsState($device_id, $folderId) - { - $db = \rcube::get_instance()->get_dbh(); - $result = $db->query( - "SELECT `data`, `synctime` FROM `syncroton_relations_state`" - . " WHERE `device_id` = ? AND `folder_id` = ?" - . " ORDER BY `synctime` DESC", - $device_id, - $folderId - ); - $data = ; - while ($state = $db->fetch_assoc($result)) { - $data = $state; - } - return $data; - } - - /** - * Test Sync command - */ - public function testRelationsSync() - { - $sync = \kolab_sync::get_instance(); - if (!$sync->storage()->relationSupport) { - $this->markTestSkipped('No relation support'); - } - - $this->emptyTestFolder('INBOX', 'mail'); - $this->emptyTestFolder('Configuration', 'configuration'); - $this->registerDevice(); - - // Test INBOX - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $syncKey = 0; - $response = $this->initialSyncRequest($folderId); - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $this->assertSame('1', $xpath->query("//ns:Sync/ns:Collections/ns:Collection/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("//ns:Sync/ns:Collections/ns:Collection/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame('Email', $xpath->query("//ns:Sync/ns:Collections/ns:Collection/ns:Class")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("//ns:Sync/ns:Collections/ns:Collection/ns:CollectionId")->item(0)->nodeValue); - - // First we append - $uid1 = $this->appendMail('INBOX', 'mail.sync1'); - $uid2 = $this->appendMail('INBOX', 'mail.sync2'); - $this->appendMail('INBOX', 'mail.sync1', 'sync1' => 'sync3'); - $this->appendMail('INBOX', 'mail.sync1', 'sync1' => 'sync4'); - - $sync = \kolab_sync::get_instance(); - - $device = $sync->storage()->device_get(self::$deviceId); - - //Add a tag - $sync->storage()->updateItem($folderId, $device'ID', \kolab_sync_storage::MODEL_EMAIL, $uid1, null, 'categories' => 'test1'); - sleep(1); - - $response = $this->syncRequest($syncKey, $folderId, 10); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(4, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - - $root .= "/ns:Commands/ns:Add"; - $this->assertSame(1, $xpath->query("{$root}/ns:ApplicationData/Email:Categories")->count()); - $this->assertSame("test1", $xpath->query("{$root}/ns:ApplicationData/Email:Categories")->item(0)->nodeValue); - - //Add a second tag - $sync->storage()->updateItem($folderId, $device'ID', \kolab_sync_storage::MODEL_EMAIL, $uid1, null, 'categories' => 'test1', 'test2'); - sleep(1); // Necessary to make sure we pick up on the tag. - - $response = $this->syncRequest($syncKey, $folderId, 10); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - $this->assertSame(1, $xpath->query("{$root}/ns:Commands/ns:Change")->count()); - $root .= "/ns:Commands/ns:Change"; - $this->assertSame(1, $xpath->query("{$root}/ns:ApplicationData/Email:Categories")->count()); - //FIXME not sure what I'm doing wrong, but the xml looks ok - $this->assertSame("test1test2", $xpath->query("{$root}/ns:ApplicationData/Email:Categories")->item(0)->nodeValue); - - $retries = 2; - $syncKey--; - // Rerun the same command and make sure we get the same result - for ($i = 0; $i < $retries; $i++) { - $response = $this->syncRequest($syncKey, $folderId, 10); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - $this->assertSame(1, $xpath->query("{$root}/ns:Commands/ns:Change")->count()); - $root .= "/ns:Commands/ns:Change"; - $this->assertSame(1, $xpath->query("{$root}/ns:ApplicationData/Email:Categories")->count()); - //FIXME not sure what I'm doing wrong, but the xml looks ok - $this->assertSame("test1test2", $xpath->query("{$root}/ns:ApplicationData/Email:Categories")->item(0)->nodeValue); - - // Assert the db state - $this->assertSame(2, count($this->getRelationsState($device'ID', $folderId))); - // Make sure we have a new timestamp after the first iteration. - // This way we can potentially catch errors when we end up using the same or a different timestamp. - sleep(1); - } - $syncKey += ($retries + 1); - - // Reset to no tags - $sync->storage()->updateItem($folderId, $device'ID', \kolab_sync_storage::MODEL_EMAIL, $uid1, null, 'categories' => ); - sleep(1); // Necessary to make sure we pick up on the tag. - - $response = $this->syncRequest($syncKey, $folderId, 10); - $this->assertEquals(200, $response->getStatusCode()); - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - $root = "//ns:Sync/ns:Collections/ns:Collection"; - $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue); - $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue); - $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue); - $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Add")->count()); - $this->assertSame(1, $xpath->query("{$root}/ns:Commands/ns:Change")->count()); - $root .= "/ns:Commands/ns:Change"; - $this->assertSame(0, $xpath->query("{$root}/ns:ApplicationData/Email:Categories")->count()); - //FIXME this currently fails because we omit the empty categories element - // $this->assertSame("", $xpath->query("{$root}/ns:ApplicationData/Email:Categories")->item(0)->nodeValue); - - - // Assert the db state - $this->assertSame(2, count($this->getRelationsState($device'ID', $folderId))); - - $response = $this->syncRequest($syncKey, $folderId, 10); - $this->assertEquals(200, $response->getStatusCode()); - // We expect an empty response without a change - $this->assertEquals(0, $response->getBody()->getSize()); - // print($dom->saveXML()); - - return $syncKey; - } - - public function testPing() - { - // Setup with a tag and an initial sync completed - $folderId = '38b950ebd62cd9a66929c89615d0fc04'; - $sync = \kolab_sync::get_instance(); - $device = $sync->storage()->device_get(self::$deviceId); - - $uid1 = $this->appendMail('INBOX', 'mail.sync1'); - $sync->storage()->updateItem($folderId, $device'ID', \kolab_sync_storage::MODEL_EMAIL, $uid1, null, 'categories' => 'test1'); - sleep(1); - - $response = $this->syncRequest(0, $folderId, 10); - $this->assertEquals(200, $response->getStatusCode()); - $response = $this->syncRequest(1, $folderId, 10); - $this->assertEquals(200, $response->getStatusCode()); - - - $this->assertSame(2, count($this->getRelationsState($device'ID', $folderId))); - - // Make sure the timestamp changes - sleep(1); - - // Pings should not change the number of relation states - for ($i=0; $i < 2; $i++) { - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Ping xmlns="uri:Ping"> - <HeartbeatInterval>0</HeartbeatInterval> - <Folders> - <Folder> - <Id>$folderId</Id> - <Class>Email</Class> - </Folder> - </Folders> - </Ping> - EOF; - - $response = $this->request($request, 'Ping'); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertSame(1, count($this->getRelationsState($device'ID', $folderId))); - } - - // This simulates a specific case where we had: - // * An old lastsync timestamp (because the folders were not actively synchronized) - // * The folder was still included in the ping command - // => This resulted in the relations code never finding a relation, and thus not cleaning up, but it still inserted new entries - $db = \rcube::get_instance()->get_dbh(); - $result = $db->query( - "UPDATE `syncroton_synckey` SET `lastsync` = '2023-06-23 13:15:03'" - ); - - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Ping xmlns="uri:Ping"> - <HeartbeatInterval>0</HeartbeatInterval> - <Folders> - <Folder> - <Id>$folderId</Id> - <Class>Email</Class> - </Folder> - </Folders> - </Ping> - EOF; - - $response = $this->request($request, 'Ping'); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertSame(1, count($this->getRelationsState($device'ID', $folderId))); - - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/SyncTestCase.php
Deleted
@@ -1,436 +0,0 @@ -<?php - -namespace Tests; - -class SyncTestCase extends \PHPUnit\Framework\TestCase -{ - protected static ?\GuzzleHttp\Client $client; - protected static ?string $deviceId; - protected static ?string $deviceType; - protected static ?string $host; - protected static ?string $username; - protected static ?string $password; - protected static bool $authenticated = false; - - protected array $folders = ; - - /** - * {@inheritDoc} - */ - public function setUp(): void - { - if (empty(self::$username)) { - $this->markTestSkipped('Not setup'); - } - - self::$deviceType = null; - } - - /** - * {@inheritDoc} - */ - public static function setUpBeforeClass(): void - { - $sync = \kolab_sync::get_instance(); - $config = $sync->config; - $db = $sync->get_dbh(); - - self::$username = $config->get('activesync_test_username'); - self::$password = $config->get('activesync_test_password'); - self::$host = $config->get('activesync_test_host', 'http://localhost:8000'); - - if (empty(self::$username)) { - return; - } - - self::$deviceId = 'test' . time(); - - $db->query('DELETE FROM syncroton_device'); - $db->query('DELETE FROM syncroton_synckey'); - $db->query('DELETE FROM syncroton_folder'); - $db->query('DELETE FROM syncroton_data'); - $db->query('DELETE FROM syncroton_data_folder'); - $db->query('DELETE FROM syncroton_content'); - $db->query('DELETE FROM syncroton_relations_state'); - - self::$client = new \GuzzleHttp\Client( - 'http_errors' => false, - 'base_uri' => self::$host, - 'verify' => false, - 'auth' => self::$username, self::$password, - 'connect_timeout' => 10, - 'timeout' => 10, - 'headers' => - 'Content-Type' => 'application/xml; charset=utf-8', - 'Depth' => '1', - , - ); - - // TODO: execute: php -S localhost:8000 - } - - /** - * {@inheritDoc} - */ - public static function tearDownAfterClass(): void - { - if (self::$deviceId) { - $sync = \kolab_sync::get_instance(); - - if (self::$authenticated || $sync->authenticate(self::$username, self::$password)) { - $sync->password = self::$password; - - $storage = $sync->storage(); - $storage->device_delete(self::$deviceId); - } - - $db = $sync->get_dbh(); - $db->query('DELETE FROM syncroton_device'); - $db->query('DELETE FROM syncroton_synckey'); - $db->query('DELETE FROM syncroton_folder'); - $db->query('DELETE FROM syncroton_relations_state'); - } - } - - /** - * Append an email message to the IMAP folder - */ - protected function appendMail($folder, $filename, $replace = ) - { - $imap = $this->getImapStorage(); - - $source = __DIR__ . '/src/' . $filename; - - if (!file_exists($source)) { - exit("File does not exist: {$source}"); - } - - $is_file = true; - - if (!empty($replace)) { - $is_file = false; - $source = file_get_contents($source); - foreach ($replace as $token => $value) { - $source = str_replace($token, $value, $source); - } - } - - $uid = $imap->save_message($folder, $source, '', $is_file); - - if ($uid === false) { - exit("Failed to append mail {$filename} into {$folder}"); - } - - return $uid; - } - - /** - * Run A SQL query - */ - protected function runSQLQuery($query) - { - $sync = \kolab_sync::get_instance(); - $db = $sync->get_dbh(); - $db->query($query); - } - - /** - * Mark an email message as read over IMAP - */ - protected function markMailAsRead($folder, $uids) - { - $imap = $this->getImapStorage(); - return $imap->set_flag($uids, 'SEEN', $folder); - } - - /** - * List emails over IMAP - */ - protected function listEmails($folder, $uids) - { - $imap = $this->getImapStorage(); - return $imap->list_flags($folder, $uids); - } - - /** - * Append an DAV object to a DAV/IMAP folder - */ - protected function appendObject($foldername, $filename, $type) - { - $path = __DIR__ . '/src/' . $filename; - - if (!file_exists($path)) { - exit("File does not exist: {$path}"); - } - - $content = file_get_contents($path); - $uid = preg_match('/UID:(?:urn:uuid:)?(a-z0-9-+)/', $content, $m) ? $m1 : null; - - if (empty($uid)) { - exit("Filed to find UID in {$path}"); - } - - if ($this->isStorageDriver('kolab')) { - $imap = $this->getImapStorage(); - if ($imap->folder_exists($foldername)) { - // TODO - exit("Not implemented for Kolab v3 storage driver"); - } else { - exit("Folder is missing"); - } - } - - $dav = $this->getDavStorage(); - - foreach ($dav->get_folders($type) as $folder) { - if ($folder->get_name() === $foldername) { - $dav_type = $folder->get_dav_type(); - $location = $folder->object_location($uid); - - if ($folder->dav->create($location, $content, $dav_type) !== false) { - return; - } - } - } - - exit("Failed to append object into {$foldername}"); - } - - /** - * Delete a folder - */ - protected function deleteTestFolder($name, $type) - { - // Deleting IMAP folders - if ($type == 'mail' || $this->isStorageDriver('kolab')) { - $imap = $this->getImapStorage(); - if ($imap->folder_exists($name)) { - $imap->delete_folder($name); - } - - return; - } - - // Deleting DAV folders - $dav = $this->getDavStorage(); - - foreach ($dav->get_folders($type) as $folder) { - if ($folder->get_name() === $name) { - $dav->folder_delete($folder->id, $type); - } - } - } - - /** - * Create a folder - */ - protected function createTestFolder($name, $type) - { - // Create IMAP folders - if ($type == 'mail' || $this->isStorageDriver('kolab')) { - $imap = $this->getImapStorage(); - //TODO set type if not mail - $imap->create_folder($name, true); - - $metadata = ; - $metadata'FOLDER' = ; - $metadata'FOLDER'self::$deviceId = ; - $metadata'FOLDER'self::$deviceId'S' = '1'; - $imap->set_metadata($name, '/private/vendor/kolab/activesync' => json_encode($metadata)); - - return; - } - } - - /** - * Remove all objects from a folder - */ - protected function emptyTestFolder($name, $type) - { - // Deleting in IMAP folders - if ($type == 'mail' || $this->isStorageDriver('kolab')) { - $imap = $this->getImapStorage(); - $imap->delete_message('*', $name); - return; - } - - // Deleting in DAV folders - $dav = $this->getDavStorage(); - - foreach ($dav->get_folders($type) as $folder) { - if ($folder->get_name() === $name) { - $folder->delete_all(); - } - } - } - - /** - * Convert WBXML binary content into XML - */ - protected function fromWbxml($binary) - { - $stream = fopen('php://memory', 'r+'); - fwrite($stream, $binary); - rewind($stream); - $decoder = new \Syncroton_Wbxml_Decoder($stream); - - return $decoder->decode(); - } - - /** - * Initialize DAV storage - */ - protected function getDavStorage() - { - $sync = \kolab_sync::get_instance(); - $url = $sync->config->get('activesync_dav_server', 'http://localhost'); - - if (strpos($url, '://') === false) { - $url = 'http://' . $url; - } - - // Inject user+password to the URL, there's no other way to pass it to the DAV client - $url = str_replace('://', '://' . rawurlencode(self::$username) . ':' . rawurlencode(self::$password) . '@', $url); - - // Make sure user is authenticated - $this->getImapStorage(); - if (!empty($sync->user)) { - // required e.g. for DAV client cache use - \rcube::get_instance()->user = $sync->user; - } - - return new \kolab_storage_dav($url); - } - - /** - * Initialize IMAP storage - */ - protected function getImapStorage() - { - $sync = \kolab_sync::get_instance(); - - if (!self::$authenticated) { - if ($sync->authenticate(self::$username, self::$password)) { - self::$authenticated = true; - $sync->password = self::$password; - } - } - - return $sync->get_storage(); - } - - /** - * Check the configured activesync_storage driver - */ - protected function isStorageDriver($name) - { - return $name === \kolab_sync::get_instance()->config->get('activesync_storage', 'kolab'); - } - - /** - * Make a HTTP request to the ActiveSync server - */ - protected function request($body, $cmd, $type = 'POST') - { - $username = self::$username; - $deviceId = self::$deviceId; - $deviceType = self::$deviceType ?: 'WindowsOutlook15'; - - $body = $this->toWbxml($body); - - return self::$client->request( - $type, - "?Cmd={$cmd}&User={$username}&DeviceId={$deviceId}&DeviceType={$deviceType}", - - 'headers' => - 'Content-Type' => 'application/vnd.ms-sync.wbxml', - 'MS-ASProtocolVersion' => '14.0', - , - 'body' => $body, - - ); - } - - /** - * Register the device for tests, some commands do not work until device/folders are registered - */ - protected function registerDevice() - { - // Execute initial FolderSync, it is required before executing some commands - $request = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy"> - <SyncKey>0</SyncKey> - </FolderSync> - EOF; - - $response = $this->request($request, 'FolderSync'); - - $this->assertEquals(200, $response->getStatusCode()); - - $dom = $this->fromWbxml($response->getBody()); - $xpath = $this->xpath($dom); - - foreach ($xpath->query("//ns:FolderSync/ns:Changes/ns:Add") as $idx => $folder) { - $serverId = $folder->getElementsByTagName('ServerId')->item(0)->nodeValue; - $displayName = $folder->getElementsByTagName('DisplayName')->item(0)->nodeValue; - $this->folders$serverId = $displayName; - } - } - - /** - * Convert XML into WBXML binary content - */ - protected function toWbxml($xml) - { - $outputStream = fopen('php://temp', 'r+'); - $encoder = new \Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3); - $dom = new \DOMDocument(); - $dom->loadXML($xml); - $encoder->encode($dom); - rewind($outputStream); - - return stream_get_contents($outputStream); - } - - /** - * Get XPath from a DOM - */ - protected function xpath($dom) - { - $xpath = new \DOMXpath($dom); - $xpath->registerNamespace("ns", $dom->documentElement->namespaceURI); - $xpath->registerNamespace("AirSync", "uri:AirSync"); - $xpath->registerNamespace("AirSyncBase", "uri:AirSyncBase"); - $xpath->registerNamespace("Calendar", "uri:Calendar"); - $xpath->registerNamespace("Contacts", "uri:Contacts"); - $xpath->registerNamespace("Email", "uri:Email"); - $xpath->registerNamespace("Email2", "uri:Email2"); - $xpath->registerNamespace("Settings", "uri:Settings"); - $xpath->registerNamespace("Tasks", "uri:Tasks"); - - return $xpath; - } - - /** - * Pretty print the DOM - */ - protected function printDom($dom) - { - $dom->formatOutput = true; - print($dom->saveXML()); - } - - /** - * adapter for phpunit < 9 - */ - public static function assertMatchesRegularExpression(string $arg1, string $arg2, string $message = ''): void - { - if (method_exists("PHPUnit\Framework\TestCase", "assertMatchesRegularExpression")) { - parent::assertMatchesRegularExpression($arg1, $arg2, $message); - } else { - parent::assertRegExp($arg1, $arg2); - } - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Unit
Deleted
-(directory)
View file
kolab-syncroton-2.4.2.tar.gz/tests/Unit/BodyConverterTest.php
Deleted
@@ -1,41 +0,0 @@ -<?php - -class BodyConverterTest extends PHPUnit\Framework\TestCase -{ - public function data_html_to_text() - { - return - '', '', - '<div></div>', '', - '<div>a</div>', 'a', - '<html><head><title>title</title></head></html>', '', - ; - } - - /** - * @dataProvider data_html_to_text - */ - public function test_html_to_text($html, $text) - { - $converter = new kolab_sync_body_converter($html, Syncroton_Model_EmailBody::TYPE_HTML); - $output = $converter->convert(Syncroton_Model_EmailBody::TYPE_PLAINTEXT); - - $this->assertEquals(trim($text), trim($output)); - } - - /** - * Test RTF convertion to HTML and Plain text - */ - public function test_rtf_to_text() - { - $rtf = file_get_contents(__DIR__ . '/../src/sample.rtf'); - - $converter = new kolab_sync_body_converter($rtf, Syncroton_Model_EmailBody::TYPE_RTF); - - $output = $converter->convert(Syncroton_Model_EmailBody::TYPE_PLAINTEXT); - $this->assertStringContainsString('This is text', trim($output)); - - $output = $converter->convert(Syncroton_Model_EmailBody::TYPE_HTML); - $this->assertStringContainsString('<span style="font-family:Helvetica,sans-serif;color:#0000ff;">anchor</span>', trim($output)); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Unit/DataCalendarTest.php
Deleted
@@ -1,126 +0,0 @@ -<?php - -class DataCalendarTest extends PHPUnit\Framework\TestCase -{ - /** - * Test for kolab_sync_data_calendar::from_kolab_alarm() - */ - public function test_from_kolab_alarm() - { - $obj = new kolab_sync_data_calendar_test(); - - $result = $obj->from_kolab_alarm(); - $this->assertSame(null, $result); - - $event = 'valarms' => - 'action' => 'DISPLAY', - 'trigger' => 'PT5M', - ; - $result = $obj->from_kolab_alarm($event); - $this->assertSame(null, $result); - - $event = 'valarms' => - 'action' => 'DISPLAY', - 'trigger' => '-PT5M', - ; - $result = $obj->from_kolab_alarm($event); - $this->assertSame(5, $result); - - $event = 'valarms' => - 'action' => 'DISPLAY', - 'trigger' => 'PT0M', - ; - $result = $obj->from_kolab_alarm($event); - $this->assertSame(0, $result); - - $event = 'valarms' => - 'action' => 'DISPLAY', - 'trigger' => '-PT0M', - ; - $result = $obj->from_kolab_alarm($event); - $this->assertSame(0, $result); - - $event = 'valarms' => - 'action' => 'DISPLAY', - 'trigger' => 'PT0S', - ; - $result = $obj->from_kolab_alarm($event); - $this->assertSame(0, $result); - - // alarms on specified DateTime (T2420) - - $event = - // no start datetime defined - 'valarms' => - - 'action' => 'DISPLAY', - 'trigger' => new DateTime('now + 1 hour'), - , - , - ; - $result = $obj->from_kolab_alarm($event); - $this->assertSame(null, $result); - - $event = - 'start' => new DateTime('now + 10 minutes'), - 'valarms' => - - 'action' => 'DISPLAY', - 'trigger' => new DateTime('now + 1 hour'), - , - , - ; - $result = $obj->from_kolab_alarm($event); - $this->assertSame(null, $result); - - $event = - 'start' => new DateTime('now + 60 minutes'), - 'valarms' => - - 'action' => 'DISPLAY', - 'trigger' => new DateTime('now + 50 minutes'), - , - , - ; - $result = $obj->from_kolab_alarm($event); - $this->assertSame(10, $result); - } - - /** - * Test for kolab_sync_data_calendar::to_kolab_alarm() - */ - public function test_to_kolab_alarm() - { - $obj = new kolab_sync_data_calendar_test(); - - $result = $obj->to_kolab_alarm(null, ); - $this->assertSame(, $result); - - $result = $obj->to_kolab_alarm(0, ); - $this->assertSame('-PT0M', $result0'trigger'); - - $result = $obj->to_kolab_alarm(15, ); - $this->assertSame('-PT15M', $result0'trigger'); - $this->assertSame('DISPLAY', $result0'action'); - } -} - -/** - * kolab_sync_data_calendar wrapper, so we can test protected methods too - */ -class kolab_sync_data_calendar_test extends kolab_sync_data_calendar -{ - public function __construct() - { - } - - public function from_kolab_alarm($value) - { - return parent::from_kolab_alarm($value); - } - - public function to_kolab_alarm($value, $event) - { - return parent::to_kolab_alarm($value, $event); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Unit/DataEmailTest.php
Deleted
@@ -1,37 +0,0 @@ -<?php - -class DataEmailTest extends PHPUnit\Framework\TestCase -{ - /** - * Test GlobalObjId encoding/decoding - */ - public function test_globalobjid() - { - // https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-asemail/e7424ddc-dd10-431e-a0b7-5c794863370e - $input = 'BAAAAIIA4AB0xbcQGoLgCAAAAAAAAAAAAAAAAAAAAAAAAAAAMwAAAHZDYWwtVWlkAQAAAHs4MTQxMkQzQy0yQTI0LTRFOUQtQjIwRS0xMUY3QkJFOTI3OTl9AA=='; - $output = kolab_sync_data_email::decodeGlobalObjId($input); - - $this->assertSame(51, $output'bytecount'); - $this->assertSame('{81412D3C-2A24-4E9D-B20E-11F7BBE92799}', $output'uid'); - - $encoded = kolab_sync_data_email::encodeGlobalObjId($output); - $this->assertSame($encoded, $input); - - $input = 'BAAAAIIA4AB0xbcQGoLgCAfUCRDgQMnBJoXEAQAAAAAAAAAAEAAAAAvw7UtuTulOnjnjhns3jvM='; - $output = kolab_sync_data_email::decodeGlobalObjId($input); - - $this->assertSame(16, $output'bytecount'); - $this->assertSame(2004, $output'year'); - $this->assertSame(9, $output'month'); - $this->assertSame(16, $output'day'); - $this->assertSame(127373090979660000, $output'now'); - - // This is how the "now" value is interpreted - // $winSecs = (int)($output'now' / 10000000); // convert microseconds to seconds - // $unixTimestamp = ($winSecs - 11644473600); // subtract 1.1.1600 - 1.1.1970 difference in seconds - // print(date(DateTime::RFC822, $unixTimestamp)); - - $encoded = kolab_sync_data_email::encodeGlobalObjId($output); - $this->assertSame($encoded, $input); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Unit/DataTasksTest.php
Deleted
@@ -1,78 +0,0 @@ -<?php - -class DataTasksTest extends PHPUnit\Framework\TestCase -{ - public function data_prio() - { - return - 0, null, - 1, 2, - 2, 2, - 3, 2, - 4, 2, - 5, 1, - 6, 0, - 7, 0, - 8, 0, - 9, 0, - // invalid input - 10, null, - ; - } - - public function data_importance() - { - return - 0, 9, - 1, 5, - 2, 1, - // invalid input - null, null, - 5, null, - ; - } - - /** - * Test for kolab_sync_data_tasks::prio_to_importance() - * @dataProvider data_prio() - */ - public function test_prio_to_importance($input, $output) - { - $data = new kolab_sync_data_tasks_test(); - $result = $data->prio_to_importance($input); - - $this->assertEquals($output, $result); - } - - /** - * Test for kolab_sync_data_tasks::importance_to_prio() - * @dataProvider data_importance() - */ - public function test_importance_to_prio($input, $output) - { - $data = new kolab_sync_data_tasks_test(); - $result = $data->importance_to_prio($input); - - $this->assertEquals($output, $result); - } -} - -/** - * kolab_sync_data_tasks wrapper, so we can test preotected methods too - */ -class kolab_sync_data_tasks_test extends kolab_sync_data_tasks -{ - public function __construct() - { - } - - public function prio_to_importance($value) - { - return parent::prio_to_importance($value); - } - - public function importance_to_prio($value) - { - return parent::importance_to_prio($value); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Unit/DataTest.php
Deleted
@@ -1,152 +0,0 @@ -<?php - -class DataTest extends PHPUnit\Framework\TestCase -{ - /** - * Test for kolab_sync_data::recurrence_to_kolab() - */ - public function test_recurrence_to_kolab() - { - $xml = '<!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar"> - <ApplicationData> - <Calendar:Recurrence> - <Calendar:Type>0</Calendar:Type> - <Calendar:Interval>1</Calendar:Interval> - <Calendar:Until>20101128T225959Z</Calendar:Until> - </Calendar:Recurrence> - </ApplicationData> - </Sync>'; - - $xml = new SimpleXMLElement($xml); - $event = new Syncroton_Model_Event($xml->ApplicationData); - $data = new kolab_sync_data_test(); - - $result = $data->recurrence_to_kolab($event); - - $this->assertEquals('DAILY', $result'FREQ'); - $this->assertEquals(1, $result'INTERVAL'); - $this->assertEquals('20101128T225959Z', $result'UNTIL'->format("Ymd\THis\Z")); - - $xml = '<!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar"> - <ApplicationData> - <Calendar:Recurrence> - <Calendar:Type>1</Calendar:Type> - <Calendar:Interval>1</Calendar:Interval> - <Calendar:DayOfWeek>8</Calendar:DayOfWeek> - </Calendar:Recurrence> - </ApplicationData> - </Sync>'; - - $xml = new SimpleXMLElement($xml); - $event = new Syncroton_Model_Event($xml->ApplicationData); - - $result = $data->recurrence_to_kolab($event, null); - - $this->assertEquals('WEEKLY', $result'FREQ'); - $this->assertEquals(1, $result'INTERVAL'); - $this->assertEquals('WE', $result'BYDAY'); - } - - /** - * Test for kolab_sync_data::recurrence_from_kolab() - */ - public function test_recurrence_from_kolab() - { - $event = - 'uid' => '52A09F6151F020312D99779F86838CF5-93BC4FC398A3FD52', - '_type' => 'event', - 'priority' => 0, - 'attendees' => - - 'rsvp' => false, - 'email' => 'bartek.machniak@nestle.kolab.ch', - 'role' => 'ORGANIZER', - 'status' => 'ACCEPTED', - , - - 'name' => 'Machniak, Aleksander', - 'status' => 'ACCEPTED', - 'cutype' => 'INDIVIDUAL', - 'rsvp' => false, - 'email' => 'aleksander.machniak@nestle.kolab.ch', - , - , - 'created' => new DateTime('2023-10-20 09:49:26.000000'), - 'changed' => new DateTime('2023-10-20 09:49:34.000000'), - 'description' => 'description', - 'end' => new DateTime('2023-10-20 14:30:00.000000'), - 'start' => new DateTime('2023-10-20 14:00:00.000000'), - 'location' => '', - 'organizer' => - 'rsvp' => false, - 'email' => 'bartek.machniak@nestle.kolab.ch', - 'role' => 'ORGANIZER', - 'status' => 'ACCEPTED', - , - 'sequence' => 0, - 'status' => 'CONFIRMED', - 'free_busy' => 'busy', - 'allday' => false, - 'recurrence' => - 'FREQ' => 'WEEKLY', - 'INTERVAL' => '1', - , - ; - - $data = new kolab_sync_data_test(); - - $data->recurrence_from_kolab(null, $event, $result); - - $this->assertEquals($data::RECUR_TYPE_WEEKLY, $result'recurrence'->type); - $this->assertEquals($data::RECUR_DOW_FRIDAY, $result'recurrence'->dayOfWeek); - $this->assertEquals(1, $result'recurrence'->interval); - - $event'recurrence' = - 'FREQ' => 'MONTHLY', - 'BYMONTHDAY' => '2,15', - 'INTERVAL' => '5', - 'COUNT' => 3, - ; - - $data->recurrence_from_kolab(null, $event, $result); - - $this->assertEquals($data::RECUR_TYPE_MONTHLY, $result'recurrence'->type); - $this->assertEquals(2, $result'recurrence'->dayOfMonth); - $this->assertEquals(5, $result'recurrence'->interval); - $this->assertEquals(3, $result'recurrence'->occurrences); - - // TODO: More cases - } -} - -/** - * kolab_sync_data wrapper, so we can test preotected methods too - */ -class kolab_sync_data_test extends kolab_sync_data -{ - public function __construct() - { - } - - public function recurrence_to_kolab($data, $dummy1 = null, $dummy2 = null) - { - return parent::recurrence_to_kolab($data, null); - } - - public function recurrence_from_kolab($collection, $data, &$result, $type = 'Event') - { - return parent::recurrence_from_kolab($collection, $data, $result, $type); - } - - public function toKolab($data, $folderId, $entry = null, $timezone = null) - { - return ; - } - - public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId, $as_array = false) - { - throw new Syncroton_Exception_NotFound("Not implemented"); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Unit/MessageTest.php
Deleted
@@ -1,146 +0,0 @@ -<?php - -class MessageTest extends PHPUnit\Framework\TestCase -{ - /** - * Test message parsing and headers setting - */ - public function test_headers() - { - $source = file_get_contents(TESTS_DIR . '/src/mail.plain'); - $message = new kolab_sync_message($source); - $headers = $message->headers(); - - $this->assertArrayHasKey('MIME-Version', $headers); - $this->assertCount(8, $headers); - $this->assertEquals('kolab@domain.tld', $headers'To'); - - // test set_header() - $message->set_header('to', 'test@domain.tld'); - $headers = $message->headers(); - - $this->assertCount(8, $headers); - $this->assertEquals('test@domain.tld', $headers'To'); - } - - /** - * Test message parsing - */ - public function test_source() - { - $source = file_get_contents(TESTS_DIR . '/src/mail.plain'); - $message = new kolab_sync_message($source); - $result = $message->source(); - - $this->assertEquals($source, str_replace("\r\n", "\n", $result)); - } - - /** - * Test adding attachments to the message - */ - public function test_attachment() - { - $source = file_get_contents(TESTS_DIR . '/src/mail.plain'); - $mixed = file_get_contents(TESTS_DIR . '/src/mail.plain.mixed'); - $mixed2 = file_get_contents(TESTS_DIR . '/src/mail.mixed'); - - // test adding attachment to text/plain message - $message = new kolab_sync_message($source); - $message->add_attachment('aaa', - 'content_type' => 'text/plain', - 'encoding' => '8bit', - ); - - $result = $message->source(); - $result = str_replace("\r\n", "\n", $result); - if (preg_match('/boundary="(^"+)"/', $result, $m)) { - $mixed = str_replace('BOUNDARY', $m1, $mixed); - } - - $this->assertEquals($mixed, $result); - - // test adding attachment to multipart/mixed message - $message = new kolab_sync_message($mixed); - $message->add_attachment('aaa', - 'content_type' => 'text/plain', - 'encoding' => 'base64', - ); - - $result = $message->source(); - $result = str_replace("\r\n", "\n", $result); - if (preg_match('/boundary="(^"+)"/', $result, $m)) { - $mixed2 = str_replace('BOUNDARY', $m1, $mixed2); - } - - $this->assertEquals($mixed2, $result); - } - - /** - * Test appending a text to the message - */ - public function test_append() - { - // test appending text to text/plain message - $source = file_get_contents(TESTS_DIR . '/src/mail.plain'); - $append = file_get_contents(TESTS_DIR . '/src/mail.plain.append'); - - $message = new kolab_sync_message($source); - $message->append('a'); - - $result = $message->source(); - $result = str_replace("\r\n", "\n", $result); - $this->assertEquals($append, $result); - } - - /** - * Test recoding the message - */ - public function test_recode_message_1() - { - $source = file_get_contents(TESTS_DIR . '/src/mail.recode1'); - $result = file_get_contents(TESTS_DIR . '/src/mail.recode1.out'); - - $message = kolab_sync_message::recode_message($source); - - $this->assertEquals($result, $message); - } - - /** - * Test recoding the message - */ - public function test_recode_message_2() - { - $source = file_get_contents(TESTS_DIR . '/src/mail.recode2'); - $result = file_get_contents(TESTS_DIR . '/src/mail.recode2.out'); - - $message = kolab_sync_message::recode_message($source); - - $this->assertEquals($result, $message); - } - - /** - * Test recoding the message - */ - public function test_recode_message_3() - { - $source = file_get_contents(TESTS_DIR . '/src/mail.recode3'); - $result = file_get_contents(TESTS_DIR . '/src/mail.recode3.out'); - - $message = kolab_sync_message::recode_message($source); - - $this->assertEquals($result, $message); - } - - /** - * Test recoding the message - */ - public function test_recode_message_4() - { - $source = file_get_contents(TESTS_DIR . '/src/mail.recode4'); - $result = file_get_contents(TESTS_DIR . '/src/mail.recode4.out'); - - $message = kolab_sync_message::recode_message($source); - - $this->assertEquals($result, $message); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Unit/TimezoneConverterTest.php
Deleted
@@ -1,174 +0,0 @@ -<?php - -class TimezoneConverterTest extends PHPUnit\Framework\TestCase -{ - public function test_list_timezones() - { - // date_default_timezone_set('America/Los_Angeles'); - - $converter = kolab_sync_timezone_converter::getInstance(); - $output = $converter->getListOfTimezones('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAEAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAEAAAAAAAAAxP///w=='); - - $this->assertTrue(is_array($output)); - - $converter = kolab_sync_timezone_converter::getInstance(); - $output = $converter->getListOfTimezones('xP///0MAZQBuAHQAcgBhAGwAIABFAHUAcgBvAHAAZQAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAEMAZQBuAHQAcgBhAGwAIABFAHUAcgBvAHAAZQAgAEQAYQB5AGwAaQBnAGgAdAAgAFQAaQBtAGUAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w=='); - - $this->assertTrue(is_array($output)); - $this->assertTrue(isset($output'Europe/Warsaw')); - - $converter = kolab_sync_timezone_converter::getInstance(); - $output = $converter->getListOfTimezones('4AEAAFAAYQBjAGkAZgBpAGMAIABTAHQAYQBuAGQAYQByAGQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAFAAYQBjAGkAZgBpAGMAIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w=='); - - $this->assertTrue(is_array($output)); - $this->assertTrue(isset($output'America/Los_Angeles')); - - $converter = kolab_sync_timezone_converter::getInstance(); - $output = $converter->getListOfTimezones('Lv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=='); - - $this->assertTrue(is_array($output)); - $this->assertTrue(isset($output'Asia/Tehran')); - - // As seen in outlook - $converter = kolab_sync_timezone_converter::getInstance(); - $output = $converter->getListOfTimezones('Lv///0kAcgBhAG4AIABTAHQAYQBuAGQAYQByAGQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkABAADABcAOwA7AOcDAAAAAEkAcgBhAG4AIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAwAEAAAAAAAAAAAAxP///w=='); - - $this->assertTrue(is_array($output)); - $this->assertTrue(isset($output'Asia/Tehran')); - } - - public function data_get_timezone() - { - return - 'UTC', - 'Europe/Warsaw', - 'Europe/Zurich', - 'America/Los_Angeles', - 'Asia/Tehran', - ; - } - - /** - * @dataProvider data_get_timezone - */ - public function test_get_timezone($tzName) - { - date_default_timezone_set('America/Los_Angeles'); - - $converter = kolab_sync_timezone_converter::getInstance(); - $datetime = '2017-01-01T12:00:00Z'; - - $offsets = $converter->getOffsetsForTimezone($tzName, $datetime); - $output = $converter->getTimezone($offsets, $tzName); - $this->assertSame($tzName, $output); - } - - public function test_get_offsets_for_timezone() - { - date_default_timezone_set('America/Los_Angeles'); - - $converter = kolab_sync_timezone_converter::getInstance(); - $datetime = '2017-01-01T12:00:00Z'; - - $output = $converter->getOffsetsForTimezone('UTC', $datetime); - - $this->assertSame($output'bias', 0); - $this->assertSame($output'standardBias', 0); - $this->assertSame($output'daylightBias', 0); - $this->assertSame($output'standardMonth', 0); - $this->assertSame($output'daylightMonth', 0); - - $output = $converter->getOffsetsForTimezone('Europe/Warsaw', $datetime); - - $this->assertSame($output'standardBias', 0); - $this->assertSame($output'standardMonth', 10); - $this->assertSame($output'standardWeek', 5); - $this->assertSame($output'standardHour', 3); - $this->assertSame($output'daylightBias', -60); - $this->assertSame($output'daylightMonth', 3); - $this->assertSame($output'daylightWeek', 5); - $this->assertSame($output'daylightHour', 2); - - $output = $converter->getOffsetsForTimezone('America/Los_Angeles', $datetime); - - $this->assertSame($output'bias', 480); - $this->assertSame($output'standardBias', 0); - $this->assertSame($output'standardMonth', 11); - $this->assertSame($output'standardWeek', 1); - $this->assertSame($output'standardHour', 2); - $this->assertSame($output'daylightBias', -60); - $this->assertSame($output'daylightMonth', 3); - $this->assertSame($output'daylightWeek', 2); - $this->assertSame($output'daylightHour', 2); - - $output = $converter->getOffsetsForTimezone('Atlantic/Azores', $datetime); - - $this->assertSame($output'bias', 60); - $this->assertSame($output'standardBias', 0); - $this->assertSame($output'standardMonth', 10); - $this->assertSame($output'standardWeek', 5); - $this->assertSame($output'standardHour', 1); - $this->assertSame($output'daylightBias', -60); - $this->assertSame($output'daylightMonth', 3); - $this->assertSame($output'daylightWeek', 5); - $this->assertSame($output'daylightHour', 0); - - //Check before dst change - $output = $converter->getOffsetsForTimezone('Asia/Tehran', $datetime); - - $this->assertSame($output'bias', -210); - $this->assertSame($output'standardBias', 0); - $this->assertSame($output'standardMonth', 9); - $this->assertSame($output'standardWeek', 3); - $this->assertSame($output'standardDayOfWeek', 4); - $this->assertSame($output'standardHour', 24); - $this->assertSame($output'daylightBias', -60); - $this->assertSame($output'daylightMonth', 3); - $this->assertSame($output'daylightWeek', 4); - $this->assertSame($output'daylightDayOfWeek', 3); - $this->assertSame($output'daylightHour', 0); - - //Check after dst change - $output = $converter->getOffsetsForTimezone('Asia/Tehran', '2023-01-01T12:00:00Z'); - - $this->assertSame($output'bias', -210); - $this->assertSame($output'standardBias', 0); - $this->assertSame($output'standardMonth', 0); - $this->assertSame($output'standardWeek', 0); - $this->assertSame($output'standardDayOfWeek', 0); - $this->assertSame($output'standardHour', 0); - $this->assertSame($output'daylightBias', 0); - $this->assertSame($output'daylightMonth', 0); - $this->assertSame($output'daylightWeek', 0); - $this->assertSame($output'daylightDayOfWeek', 0); - $this->assertSame($output'daylightHour', 0); - } - - public function data_timezone_conversion() - { - return - //Pre dst change - 'Asia/Tehran', 'Lv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAAgADABcAOwA7AOcDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAQAEAAAAAAAAAAAAxP///w==', '2021-07-01T12:00:00Z', - //Post dst change - 'Asia/Tehran', 'Lv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==', '2023-04-01T12:00:00Z', - 'Pacific/Pago_Pago', 'lAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==', '2021-07-01T12:00:00Z', - 'Europe/Warsaw', 'xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==', '2021-07-01T12:00:00Z', - ; - } - - /** - * @dataProvider data_timezone_conversion - */ - public function test_timezone_conversion($tz, $expected, $datetime) - { - $converter = kolab_sync_timezone_converter::getInstance(); - $output = $converter->encodeTimezone($tz, $datetime); - - $this->assertSame($expected, $output); - - $output = $converter->getListOfTimezones($output); - - $this->assertTrue(is_array($output)); - $this->assertTrue(isset($output$tz)); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/Unit/WbxmlTest.php
Deleted
@@ -1,909 +0,0 @@ -<?php - -class WbxmlTest extends PHPUnit\Framework\TestCase -{ - //function testDecode() - //{ - // //TODO input some wbxml document - // // - // $dom = new DOMDocument(); - // $dom->loadXML($lastSyncCollection'lastXML'); - // // - // try { - // $decoder = new Syncroton_Wbxml_Decoder($dom); - // $requestBody = $decoder->decode(); - // if ($this->_logger instanceof Zend_Log) { - // $requestBody->formatOutput = true; - // $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " xml request:\n" . $requestBody->saveXML()); - // } - // } catch(Syncroton_Wbxml_Exception_UnexpectedEndOfFile $e) { - // $requestBody = NULL; - // } - // //TODO validate output - //} - - - - public function testEncode() - { - $outputStream = fopen("php://temp", 'r+'); - - $encoder = new Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3); - - $xml = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Tasks="uri:Tasks"> - <Collections> - <Collection> - <SyncKey>2</SyncKey> - <CollectionId>tasksId</CollectionId> - <Commands> - <Add> - <ClientId>clientId2</ClientId> - <ApplicationData> - <Subject xmlns="uri:Tasks">task2</Subject> - <Complete xmlns="uri:Tasks">0</Complete> - <DueDate xmlns="uri:Tasks">2020-11-04T00:00:00.000Z</DueDate> - <UtcDueDate xmlns="uri:Tasks">2020-11-03T23:00:00.000Z</UtcDueDate> - </ApplicationData> - </Add> - <Add> - <ClientId>clientId3</ClientId> - <ApplicationData> - <Subject xmlns="uri:Tasks">task3</Subject> - <Complete xmlns="uri:Tasks">0</Complete> - <DueDate xmlns="uri:Tasks">2020-11-04T00:00:00.000Z</DueDate> - <UtcDueDate xmlns="uri:Tasks">2020-11-03T23:00:00.000Z</UtcDueDate> - </ApplicationData> - </Add> - </Commands> - </Collection> - </Collections> - <WindowSize>16</WindowSize> - </Sync> - EOF; - - - $dom = new DOMDocument(); - $dom->loadXML($xml); - - $encoder->encode($dom); - - rewind($outputStream); - $output = stream_get_contents($outputStream); - // print("----"); - // print(var_export($output, true)); - // print("----"); - $this->assertEquals( - base64_decode('AwFqAEVcT0sDMgABUgN0YXNrc0lkAAFWR0wDY2xpZW50SWQyAAFdAAlgA3Rhc2syAAFKAzAAAUwDMjAyMC0xMS0wNFQwMDowMDowMC4wMDBaAAFNAzIwMjAtMTEtMDNUMjM6MDA6MDAuMDAwWgABAQEAAEdMA2NsaWVudElkMwABXQAJYAN0YXNrMwABSgMwAAFMAzIwMjAtMTEtMDRUMDA6MDA6MDAuMDAwWgABTQMyMDIwLTExLTAzVDIzOjAwOjAwLjAwMFoAAQEBAQEBAABVAzE2AAEB'), - $output - ); - } - - public function testEncodeFolderSync() - { - $outputStream = fopen("php://temp", 'r+'); - - $encoder = new Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3); - - $xml = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <FolderSync xmlns="uri:FolderHierarchy" xmlns:Syncroton="uri:Syncroton" xmlns:Internal="uri:Internal"> - <Status>1</Status> - <SyncKey>1</SyncKey> - <Changes> - <Count>18</Count> - <Add> - <ServerId>2685b302b79f58d2753199545e3cb8be</ServerId> - <ParentId>0</ParentId> - <DisplayName>Test2</DisplayName> - <Type>13</Type> - </Add> - <Add> - <ServerId>9770b083c68e8584f396d15a116d6608</ServerId> - <ParentId>0</ParentId> - <DisplayName>DavidCalendar</DisplayName> - <Type>13</Type> - </Add> - <Add> - <ServerId>0f66388806743c514b8063bf0dc87486</ServerId> - <ParentId>0</ParentId> - <DisplayName>SergeyCalendar</DisplayName> - <Type>13</Type> - </Add> - <Add> - <ServerId>cca1b81c734abbcd669bea90d23e08ae</ServerId> - <ParentId>0</ParentId> - <DisplayName>Calendar</DisplayName> - <Type>8</Type> - </Add> - <Add> - <ServerId>ab1ddb4ef8e8f8fcc2c9f5a7f9062452</ServerId> - <ParentId>0</ParentId> - <DisplayName>PubCal</DisplayName> - <Type>13</Type> - </Add> - <Add> - <ServerId>d98bd8721371544ed095841ead941893</ServerId> - <ParentId>0</ParentId> - <DisplayName>(david) Test2</DisplayName> - <Type>13</Type> - </Add> - <Add> - <ServerId>9e7b9656ef61d4af2fb2fdcabe600079</ServerId> - <ParentId>0</ParentId> - <DisplayName>(david) DavidCalendar</DisplayName> - <Type>13</Type> - </Add> - <Add> - <ServerId>384cf2d877c39a622fdc2a16898052e2</ServerId> - <ParentId>0</ParentId> - <DisplayName>(david) Calendar</DisplayName> - <Type>13</Type> - </Add> - <Add> - <ServerId>Contacts::Syncroton</ServerId> - <ParentId>0</ParentId> - <DisplayName>Contacts</DisplayName> - <Type>9</Type> - </Add> - <Add> - <ServerId>1bb8c55fe84d52c6968db2571f7dc124</ServerId> - <ParentId>0</ParentId> - <DisplayName>Archive</DisplayName> - <Type>12</Type> - </Add> - <Add> - <ServerId>b51abe73e9e98fe200a4afe409050502</ServerId> - <ParentId>38b950ebd62cd9a66929c89615d0fc04</ParentId> - <DisplayName>Spam</DisplayName> - <Type>12</Type> - </Add> - <Add> - <ServerId>cf529c792fc87d1f207435b3921bb02e</ServerId> - <ParentId>0</ParentId> - <DisplayName>Sent</DisplayName> - <Type>5</Type> - </Add> - <Add> - <ServerId>715ed9ea29b8a5377a69c1f758037c65</ServerId> - <ParentId>0</ParentId> - <DisplayName>Spam</DisplayName> - <Type>12</Type> - </Add> - <Add> - <ServerId>db0d959a3aeb21757f8849a830947a7a</ServerId> - <ParentId>0</ParentId> - <DisplayName>Trash</DisplayName> - <Type>4</Type> - </Add> - <Add> - <ServerId>5ac9ec2e1a9d99e2e10cabe4abf26729</ServerId> - <ParentId>0</ParentId> - <DisplayName>Drafts</DisplayName> - <Type>3</Type> - </Add> - <Add> - <ServerId>38b950ebd62cd9a66929c89615d0fc04</ServerId> - <ParentId>0</ParentId> - <DisplayName>INBOX</DisplayName> - <Type>2</Type> - </Add> - <Add> - <ServerId>fc56f4c7ffe0aefa622db9f8d9186c4a</ServerId> - <ParentId>0</ParentId> - <DisplayName>Notes</DisplayName> - <Type>10</Type> - </Add> - <Add> - <ServerId>90335880f65deff6e521acea2b71a773</ServerId> - <ParentId>0</ParentId> - <DisplayName>Tasks</DisplayName> - <Type>7</Type> - </Add> - </Changes> - </FolderSync> - EOF; - - - $dom = new DOMDocument(); - $dom->loadXML($xml); - - $encoder->encode($dom); - - rewind($outputStream); - $output = stream_get_contents($outputStream); - // print("----"); - // print(var_export(base64_encode($output), true)); - // print("----"); - $this->assertEquals( - base64_decode('AwFqAAAHVkwDMQABUgMxAAFOVwMxOAABT0gDMjY4NWIzMDJiNzlmNThkMjc1MzE5OTU0NWUzY2I4YmUAAUkDMAABRwNUZXN0MgABSgMxMwABAU9IAzk3NzBiMDgzYzY4ZTg1ODRmMzk2ZDE1YTExNmQ2NjA4AAFJAzAAAUcDRGF2aWRDYWxlbmRhcgABSgMxMwABAU9IAzBmNjYzODg4MDY3NDNjNTE0YjgwNjNiZjBkYzg3NDg2AAFJAzAAAUcDU2VyZ2V5Q2FsZW5kYXIAAUoDMTMAAQFPSANjY2ExYjgxYzczNGFiYmNkNjY5YmVhOTBkMjNlMDhhZQABSQMwAAFHA0NhbGVuZGFyAAFKAzgAAQFPSANhYjFkZGI0ZWY4ZThmOGZjYzJjOWY1YTdmOTA2MjQ1MgABSQMwAAFHA1B1YkNhbAABSgMxMwABAU9IA2Q5OGJkODcyMTM3MTU0NGVkMDk1ODQxZWFkOTQxODkzAAFJAzAAAUcDKGRhdmlkKSBUZXN0MgABSgMxMwABAU9IAzllN2I5NjU2ZWY2MWQ0YWYyZmIyZmRjYWJlNjAwMDc5AAFJAzAAAUcDKGRhdmlkKSBEYXZpZENhbGVuZGFyAAFKAzEzAAEBT0gDMzg0Y2YyZDg3N2MzOWE2MjJmZGMyYTE2ODk4MDUyZTIAAUkDMAABRwMoZGF2aWQpIENhbGVuZGFyAAFKAzEzAAEBT0gDQ29udGFjdHM6OlN5bmNyb3RvbgABSQMwAAFHA0NvbnRhY3RzAAFKAzkAAQFPSAMxYmI4YzU1ZmU4NGQ1MmM2OTY4ZGIyNTcxZjdkYzEyNAABSQMwAAFHA0FyY2hpdmUAAUoDMTIAAQFPSANiNTFhYmU3M2U5ZTk4ZmUyMDBhNGFmZTQwOTA1MDUwMgABSQMzOGI5NTBlYmQ2MmNkOWE2NjkyOWM4OTYxNWQwZmMwNAABRwNTcGFtAAFKAzEyAAEBT0gDY2Y1MjljNzkyZmM4N2QxZjIwNzQzNWIzOTIxYmIwMmUAAUkDMAABRwNTZW50AAFKAzUAAQFPSAM3MTVlZDllYTI5YjhhNTM3N2E2OWMxZjc1ODAzN2M2NQABSQMwAAFHA1NwYW0AAUoDMTIAAQFPSANkYjBkOTU5YTNhZWIyMTc1N2Y4ODQ5YTgzMDk0N2E3YQABSQMwAAFHA1RyYXNoAAFKAzQAAQFPSAM1YWM5ZWMyZTFhOWQ5OWUyZTEwY2FiZTRhYmYyNjcyOQABSQMwAAFHA0RyYWZ0cwABSgMzAAEBT0gDMzhiOTUwZWJkNjJjZDlhNjY5MjljODk2MTVkMGZjMDQAAUkDMAABRwNJTkJPWAABSgMyAAEBT0gDZmM1NmY0YzdmZmUwYWVmYTYyMmRiOWY4ZDkxODZjNGEAAUkDMAABRwNOb3RlcwABSgMxMAABAU9IAzkwMzM1ODgwZjY1ZGVmZjZlNTIxYWNlYTJiNzFhNzczAAFJAzAAAUcDVGFza3MAAUoDNwABAQEB'), - $output - ); - } - - public function testEncodeCalendar() - { - $outputStream = fopen("php://temp", 'r+'); - - $encoder = new Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3); - - $xml = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Calendar="uri:Calendar"> - <Collections> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>38b950ebd62cd9a66929c89615d0fc04</CollectionId> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <MIMESupport>2</MIMESupport> - <MIMETruncation>8</MIMETruncation> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>4</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>cca1b81c734abbcd669bea90d23e08ae</CollectionId> - <Supported> - <DtStamp xmlns="uri:Calendar"/> - <Categories xmlns="uri:Calendar"/> - <Sensitivity xmlns="uri:Calendar"/> - <BusyStatus xmlns="uri:Calendar"/> - <UID xmlns="uri:Calendar"/> - <Timezone xmlns="uri:Calendar"/> - <StartTime xmlns="uri:Calendar"/> - <Subject xmlns="uri:Calendar"/> - <Location xmlns="uri:Calendar"/> - <EndTime xmlns="uri:Calendar"/> - <Recurrence xmlns="uri:Calendar"/> - <AllDayEvent xmlns="uri:Calendar"/> - <Reminder xmlns="uri:Calendar"/> - <Exceptions xmlns="uri:Calendar"/> - <Attendees xmlns="uri:Calendar"/> - <MeetingStatus xmlns="uri:Calendar"/> - <ResponseRequested xmlns="uri:Calendar"/> - <DisallowNewTimeProposal xmlns="uri:Calendar"/> - </Supported> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>1</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>Contacts::Syncroton</CollectionId> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>1</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>db0d959a3aeb21757f8849a830947a7a</CollectionId> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <MIMESupport>2</MIMESupport> - <MIMETruncation>8</MIMETruncation> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>4</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>cf529c792fc87d1f207435b3921bb02e</CollectionId> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <MIMESupport>2</MIMESupport> - <MIMETruncation>8</MIMETruncation> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>4</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>90335880f65deff6e521acea2b71a773</CollectionId> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>1</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>1bb8c55fe84d52c6968db2571f7dc124</CollectionId> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <MIMESupport>2</MIMESupport> - <MIMETruncation>8</MIMETruncation> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>4</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>715ed9ea29b8a5377a69c1f758037c65</CollectionId> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <MIMESupport>2</MIMESupport> - <MIMETruncation>8</MIMETruncation> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>4</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>b51abe73e9e98fe200a4afe409050502</CollectionId> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <MIMESupport>2</MIMESupport> - <MIMETruncation>8</MIMETruncation> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>4</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>0f66388806743c514b8063bf0dc87486</CollectionId> - <Supported> - <DtStamp xmlns="uri:Calendar"/> - <Categories xmlns="uri:Calendar"/> - <Sensitivity xmlns="uri:Calendar"/> - <BusyStatus xmlns="uri:Calendar"/> - <UID xmlns="uri:Calendar"/> - <Timezone xmlns="uri:Calendar"/> - <StartTime xmlns="uri:Calendar"/> - <Subject xmlns="uri:Calendar"/> - <Location xmlns="uri:Calendar"/> - <EndTime xmlns="uri:Calendar"/> - <Recurrence xmlns="uri:Calendar"/> - <AllDayEvent xmlns="uri:Calendar"/> - <Reminder xmlns="uri:Calendar"/> - <Exceptions xmlns="uri:Calendar"/> - <Attendees xmlns="uri:Calendar"/> - <MeetingStatus xmlns="uri:Calendar"/> - <ResponseRequested xmlns="uri:Calendar"/> - <DisallowNewTimeProposal xmlns="uri:Calendar"/> - </Supported> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>1</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>2685b302b79f58d2753199545e3cb8be</CollectionId> - <Supported> - <DtStamp xmlns="uri:Calendar"/> - <Categories xmlns="uri:Calendar"/> - <Sensitivity xmlns="uri:Calendar"/> - <BusyStatus xmlns="uri:Calendar"/> - <UID xmlns="uri:Calendar"/> - <Timezone xmlns="uri:Calendar"/> - <StartTime xmlns="uri:Calendar"/> - <Subject xmlns="uri:Calendar"/> - <Location xmlns="uri:Calendar"/> - <EndTime xmlns="uri:Calendar"/> - <Recurrence xmlns="uri:Calendar"/> - <AllDayEvent xmlns="uri:Calendar"/> - <Reminder xmlns="uri:Calendar"/> - <Exceptions xmlns="uri:Calendar"/> - <Attendees xmlns="uri:Calendar"/> - <MeetingStatus xmlns="uri:Calendar"/> - <ResponseRequested xmlns="uri:Calendar"/> - <DisallowNewTimeProposal xmlns="uri:Calendar"/> - </Supported> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>1</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>384cf2d877c39a622fdc2a16898052e2</CollectionId> - <Supported> - <DtStamp xmlns="uri:Calendar"/> - <Categories xmlns="uri:Calendar"/> - <Sensitivity xmlns="uri:Calendar"/> - <BusyStatus xmlns="uri:Calendar"/> - <UID xmlns="uri:Calendar"/> - <Timezone xmlns="uri:Calendar"/> - <StartTime xmlns="uri:Calendar"/> - <Subject xmlns="uri:Calendar"/> - <Location xmlns="uri:Calendar"/> - <EndTime xmlns="uri:Calendar"/> - <Recurrence xmlns="uri:Calendar"/> - <AllDayEvent xmlns="uri:Calendar"/> - <Reminder xmlns="uri:Calendar"/> - <Exceptions xmlns="uri:Calendar"/> - <Attendees xmlns="uri:Calendar"/> - <MeetingStatus xmlns="uri:Calendar"/> - <ResponseRequested xmlns="uri:Calendar"/> - <DisallowNewTimeProposal xmlns="uri:Calendar"/> - </Supported> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>1</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>9770b083c68e8584f396d15a116d6608</CollectionId> - <Supported> - <DtStamp xmlns="uri:Calendar"/> - <Categories xmlns="uri:Calendar"/> - <Sensitivity xmlns="uri:Calendar"/> - <BusyStatus xmlns="uri:Calendar"/> - <UID xmlns="uri:Calendar"/> - <Timezone xmlns="uri:Calendar"/> - <StartTime xmlns="uri:Calendar"/> - <Subject xmlns="uri:Calendar"/> - <Location xmlns="uri:Calendar"/> - <EndTime xmlns="uri:Calendar"/> - <Recurrence xmlns="uri:Calendar"/> - <AllDayEvent xmlns="uri:Calendar"/> - <Reminder xmlns="uri:Calendar"/> - <Exceptions xmlns="uri:Calendar"/> - <Attendees xmlns="uri:Calendar"/> - <MeetingStatus xmlns="uri:Calendar"/> - <ResponseRequested xmlns="uri:Calendar"/> - <DisallowNewTimeProposal xmlns="uri:Calendar"/> - </Supported> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>1</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>9e7b9656ef61d4af2fb2fdcabe600079</CollectionId> - <Supported> - <DtStamp xmlns="uri:Calendar"/> - <Categories xmlns="uri:Calendar"/> - <Sensitivity xmlns="uri:Calendar"/> - <BusyStatus xmlns="uri:Calendar"/> - <UID xmlns="uri:Calendar"/> - <Timezone xmlns="uri:Calendar"/> - <StartTime xmlns="uri:Calendar"/> - <Subject xmlns="uri:Calendar"/> - <Location xmlns="uri:Calendar"/> - <EndTime xmlns="uri:Calendar"/> - <Recurrence xmlns="uri:Calendar"/> - <AllDayEvent xmlns="uri:Calendar"/> - <Reminder xmlns="uri:Calendar"/> - <Exceptions xmlns="uri:Calendar"/> - <Attendees xmlns="uri:Calendar"/> - <MeetingStatus xmlns="uri:Calendar"/> - <ResponseRequested xmlns="uri:Calendar"/> - <DisallowNewTimeProposal xmlns="uri:Calendar"/> - </Supported> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>1</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>ab1ddb4ef8e8f8fcc2c9f5a7f9062452</CollectionId> - <Supported> - <DtStamp xmlns="uri:Calendar"/> - <Categories xmlns="uri:Calendar"/> - <Sensitivity xmlns="uri:Calendar"/> - <BusyStatus xmlns="uri:Calendar"/> - <UID xmlns="uri:Calendar"/> - <Timezone xmlns="uri:Calendar"/> - <StartTime xmlns="uri:Calendar"/> - <Subject xmlns="uri:Calendar"/> - <Location xmlns="uri:Calendar"/> - <EndTime xmlns="uri:Calendar"/> - <Recurrence xmlns="uri:Calendar"/> - <AllDayEvent xmlns="uri:Calendar"/> - <Reminder xmlns="uri:Calendar"/> - <Exceptions xmlns="uri:Calendar"/> - <Attendees xmlns="uri:Calendar"/> - <MeetingStatus xmlns="uri:Calendar"/> - <ResponseRequested xmlns="uri:Calendar"/> - <DisallowNewTimeProposal xmlns="uri:Calendar"/> - </Supported> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>1</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - <Collection> - <SyncKey>0</SyncKey> - <CollectionId>d98bd8721371544ed095841ead941893</CollectionId> - <Supported> - <DtStamp xmlns="uri:Calendar"/> - <Categories xmlns="uri:Calendar"/> - <Sensitivity xmlns="uri:Calendar"/> - <BusyStatus xmlns="uri:Calendar"/> - <UID xmlns="uri:Calendar"/> - <Timezone xmlns="uri:Calendar"/> - <StartTime xmlns="uri:Calendar"/> - <Subject xmlns="uri:Calendar"/> - <Location xmlns="uri:Calendar"/> - <EndTime xmlns="uri:Calendar"/> - <Recurrence xmlns="uri:Calendar"/> - <AllDayEvent xmlns="uri:Calendar"/> - <Reminder xmlns="uri:Calendar"/> - <Exceptions xmlns="uri:Calendar"/> - <Attendees xmlns="uri:Calendar"/> - <MeetingStatus xmlns="uri:Calendar"/> - <ResponseRequested xmlns="uri:Calendar"/> - <DisallowNewTimeProposal xmlns="uri:Calendar"/> - </Supported> - <DeletesAsMoves>0</DeletesAsMoves> - <GetChanges>0</GetChanges> - <WindowSize>512</WindowSize> - <Options> - <FilterType>0</FilterType> - <BodyPreference xmlns="uri:AirSyncBase"> - <Type>1</Type> - <AllOrNone>1</AllOrNone> - </BodyPreference> - </Options> - </Collection> - </Collections> - <WindowSize>16</WindowSize> - </Sync> - EOF; - - - $dom = new DOMDocument(); - $dom->loadXML($xml); - - $encoder->encode($dom); - - rewind($outputStream); - $output = stream_get_contents($outputStream); - // print("----"); - // print(var_export(base64_encode($output), true)); - // print("----"); - - $this->assertEquals( - base64_decode('AwFqAEVcT0sDMAABUgMzOGI5NTBlYmQ2MmNkOWE2NjkyOWM4OTYxNWQwZmMwNAABXgMwAAFTAzAAAVUDNTEyAAFXWAMwAAFiAzIAAWMDOAABABFFRgM0AAFIAzEAAQEBAQAAT0sDMAABUgNjY2ExYjgxYzczNGFiYmNkNjY5YmVhOTBkMjNlMDhhZQABYAAEEQ4lDSgFJyYXEhsGJBQHGDQzAQAAXgMwAAFTAzAAAVUDNTEyAAFXWAMwAAEAEUVGAzEAAUgDMQABAQEBAABPSwMwAAFSA0NvbnRhY3RzOjpTeW5jcm90b24AAV4DMAABUwMwAAFVAzUxMgABV1gDMAABABFFRgMxAAFIAzEAAQEBAQAAT0sDMAABUgNkYjBkOTU5YTNhZWIyMTc1N2Y4ODQ5YTgzMDk0N2E3YQABXgMwAAFTAzAAAVUDNTEyAAFXWAMwAAFiAzIAAWMDOAABABFFRgM0AAFIAzEAAQEBAQAAT0sDMAABUgNjZjUyOWM3OTJmYzg3ZDFmMjA3NDM1YjM5MjFiYjAyZQABXgMwAAFTAzAAAVUDNTEyAAFXWAMwAAFiAzIAAWMDOAABABFFRgM0AAFIAzEAAQEBAQAAT0sDMAABUgM5MDMzNTg4MGY2NWRlZmY2ZTUyMWFjZWEyYjcxYTc3MwABXgMwAAFTAzAAAVUDNTEyAAFXWAMwAAEAEUVGAzEAAUgDMQABAQEBAABPSwMwAAFSAzFiYjhjNTVmZTg0ZDUyYzY5NjhkYjI1NzFmN2RjMTI0AAFeAzAAAVMDMAABVQM1MTIAAVdYAzAAAWIDMgABYwM4AAEAEUVGAzQAAUgDMQABAQEBAABPSwMwAAFSAzcxNWVkOWVhMjliOGE1Mzc3YTY5YzFmNzU4MDM3YzY1AAFeAzAAAVMDMAABVQM1MTIAAVdYAzAAAWIDMgABYwM4AAEAEUVGAzQAAUgDMQABAQEBAABPSwMwAAFSA2I1MWFiZTczZTllOThmZTIwMGE0YWZlNDA5MDUwNTAyAAFeAzAAAVMDMAABVQM1MTIAAVdYAzAAAWIDMgABYwM4AAEAEUVGAzQAAUgDMQABAQEBAABPSwMwAAFSAzBmNjYzODg4MDY3NDNjNTE0YjgwNjNiZjBkYzg3NDg2AAFgAAQRDiUNKAUnJhcSGwYkFAcYNDMBAABeAzAAAVMDMAABVQM1MTIAAVdYAzAAAQARRUYDMQABSAMxAAEBAQEAAE9LAzAAAVIDMjY4NWIzMDJiNzlmNThkMjc1MzE5OTU0NWUzY2I4YmUAAWAABBEOJQ0oBScmFxIbBiQUBxg0MwEAAF4DMAABUwMwAAFVAzUxMgABV1gDMAABABFFRgMxAAFIAzEAAQEBAQAAT0sDMAABUgMzODRjZjJkODc3YzM5YTYyMmZkYzJhMTY4OTgwNTJlMgABYAAEEQ4lDSgFJyYXEhsGJBQHGDQzAQAAXgMwAAFTAzAAAVUDNTEyAAFXWAMwAAEAEUVGAzEAAUgDMQABAQEBAABPSwMwAAFSAzk3NzBiMDgzYzY4ZTg1ODRmMzk2ZDE1YTExNmQ2NjA4AAFgAAQRDiUNKAUnJhcSGwYkFAcYNDMBAABeAzAAAVMDMAABVQM1MTIAAVdYAzAAAQARRUYDMQABSAMxAAEBAQEAAE9LAzAAAVIDOWU3Yjk2NTZlZjYxZDRhZjJmYjJmZGNhYmU2MDAwNzkAAWAABBEOJQ0oBScmFxIbBiQUBxg0MwEAAF4DMAABUwMwAAFVAzUxMgABV1gDMAABABFFRgMxAAFIAzEAAQEBAQAAT0sDMAABUgNhYjFkZGI0ZWY4ZThmOGZjYzJjOWY1YTdmOTA2MjQ1MgABYAAEEQ4lDSgFJyYXEhsGJBQHGDQzAQAAXgMwAAFTAzAAAVUDNTEyAAFXWAMwAAEAEUVGAzEAAUgDMQABAQEBAABPSwMwAAFSA2Q5OGJkODcyMTM3MTU0NGVkMDk1ODQxZWFkOTQxODkzAAFgAAQRDiUNKAUnJhcSGwYkFAcYNDMBAABeAzAAAVMDMAABVQM1MTIAAVdYAzAAAQARRUYDMQABSAMxAAEBAQEBAABVAzE2AAEB'), - $output - ); - } - - public function testEncodeEmail() - { - $outputStream = fopen("php://temp", 'r+'); - - $encoder = new Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3); - - $xml = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:Syncroton="uri:Syncroton" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Email="uri:Email" xmlns:Email2="uri:Email2" xmlns:Tasks="uri:Tasks"> - <Collections> - <Collection xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <Class>Email</Class> - <SyncKey>2</SyncKey> - <CollectionId>38b950ebd62cd9a66929c89615d0fc04</CollectionId> - <Status>1</Status> - <MoreAvailable/> - <Commands xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <Add xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <ServerId>38b950ebd62cd9a66929c89615d0fc04::1</ServerId> - <ApplicationData> - <Email:DateReceived xmlns="uri:Email">2023-05-06T14:51:40.000Z</Email:DateReceived> - <Email:From xmlns="uri:Email">"Mollekopf, Christian" <christian@example.ch></Email:From> - <Email:InternetCPID xmlns="uri:Email">65001</Email:InternetCPID> - <Email:Subject xmlns="uri:Email">Foobar 1</Email:Subject> - <Email:To xmlns="uri:Email">christian@example.ch</Email:To> - <Email:Read xmlns="uri:Email">0</Email:Read> - <Email:Flag xmlns="uri:Email"/> - <AirSyncBase:Body xmlns="uri:AirSyncBase"> - <AirSyncBase:Type>4</AirSyncBase:Type> - <AirSyncBase:Data>Return-Path: <christian@example.ch> - Received: from imapb010.mykolab.com (unix socket) - by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; - Wed, 09 Aug 2017 18:37:01 +0200 - X-Sieve: CMU Sieve 2.4 - Received: from int-mx002.mykolab.com (unknown 10.9.13.2) - by imapb010.mykolab.com (Postfix) with ESMTPS id 0A93910A25047 - for <christian@example.ch>; Wed, 9 Aug 2017 18:37:01 +0200 (CEST) - Received: from int-subm002.mykolab.com (unknown 10.9.37.2) - by int-mx002.mykolab.com (Postfix) with ESMTPS id EC06AF6E - for <christian@example.ch>; Wed, 9 Aug 2017 18:37:00 +0200 (CEST) - MIME-Version: 1.0 - Content-Type: multipart/mixed; - boundary="=_291b8e96564265636432c6d494e02322" - Date: Sat, 06 May 2023 14:41:40 - From: "Mollekopf, Christian" <christian@example.ch> - To: christian@example.ch - Subject: Foobar 1 - Message-ID: <foobar1@example.org> - - --=_291b8e96564265636432c6d494e02322 - Content-Type: multipart/alternative; - boundary="=_ceff0fd19756f45ed1295ee2069ff8e0" - - --=_ceff0fd19756f45ed1295ee2069ff8e0 - Content-Transfer-Encoding: 7bit - Content-Type: text/plain; charset=US-ASCII - - sdlkjsdjf - --=_ceff0fd19756f45ed1295ee2069ff8e0 - Content-Transfer-Encoding: quoted-printable - Content-Type: text/html; charset=UTF-8 - - <html><head><meta http-equiv=3D"Content-Type" content=3D"text/html; charset= - =3DUTF-8" /></head><body style=3D'font-size: 10pt; font-family: Verdana,Gen= - eva,sans-serif'> - <p>sdlkjsdjf</p> - - </body></html> - - --=_ceff0fd19756f45ed1295ee2069ff8e0-- - - --=_291b8e96564265636432c6d494e02322 - Content-Transfer-Encoding: base64 - Content-Type: text/plain; - name=xorg.conf - Content-Disposition: attachment; - filename=xorg.conf; - size=211 - - U2VjdGlvbiAiRGV2aWNlIgogICAgSWRlbnRpZmllciAgICAgIkRldmljZTAiCiAgICBEcml2ZXIg - ICAgIEJvYXJkTmFtZSAgICAgICJOVlMgNDIwME0iCiAgICBPcHRpb24gIk5vTG9nbyIgInRydWUi - CiAgICBPcHRpb24gIlVzZUVESUQiICJ0cnVlIgpFbmRTZWN0aW9uCg== - --=_291b8e96564265636432c6d494e02322--</AirSyncBase:Data> - </AirSyncBase:Body> - <AirSyncBase:NativeBodyType xmlns="uri:AirSyncBase">2</AirSyncBase:NativeBodyType> - <Email:MessageClass xmlns="uri:Email">IPM.Note</Email:MessageClass> - <Email:ContentClass xmlns="uri:Email">urn:content-classes:message</Email:ContentClass> - <AirSyncBase:Attachments xmlns="uri:AirSyncBase"> - <AirSyncBase:Attachment> - <AirSyncBase:DisplayName>xorg.conf</AirSyncBase:DisplayName> - <AirSyncBase:FileReference>38b950ebd62cd9a66929c89615d0fc04::5::2</AirSyncBase:FileReference> - <AirSyncBase:Method>1</AirSyncBase:Method> - <AirSyncBase:EstimatedDataSize>35100212</AirSyncBase:EstimatedDataSize> - </AirSyncBase:Attachment> - </AirSyncBase:Attachments> - </ApplicationData> - </Add> - </Commands> - </Collection> - </Collections> - </Sync> - EOF; - - $dom = new DOMDocument(); - $dom->loadXML($xml); - - $encoder->encode($dom); - - rewind($outputStream); - $output = stream_get_contents($outputStream); - // print("----"); - // print(var_export(base64_encode($output), true)); - // print("----"); - - $this->assertEquals( - base64_decode('AwFqAEVcT1ADRW1haWwAAUsDMgABUgMzOGI5NTBlYmQ2MmNkOWE2NjkyOWM4OTYxNWQwZmMwNAABTgMxAAEUVkdNAzM4Yjk1MGViZDYyY2Q5YTY2OTI5Yzg5NjE1ZDBmYzA0OjoxAAFdAAJPAzIwMjMtMDUtMDZUMTQ6NTE6NDAuMDAwWgABWAMiTW9sbGVrb3BmLCBDaHJpc3RpYW4iIDxjaHJpc3RpYW5AZXhhbXBsZS5jaD4AAXkDNjUwMDEAAVQDRm9vYmFyIDEAAVYDY2hyaXN0aWFuQGV4YW1wbGUuY2gAAVUDMAABOgARSkYDNAABSwNSZXR1cm4tUGF0aDogPGNocmlzdGlhbkBleGFtcGxlLmNoPg0KUmVjZWl2ZWQ6IGZyb20gaW1hcGIwMTAubXlrb2xhYi5jb20gKFt1bml4IHNvY2tldF0pDQogICAgICAgIGJ5IGltYXBiMDEwLm15a29sYWIuY29tIChDeXJ1cyAyLjUuMTAtNDktZzJlMjE0YjQtS29sYWItMi41LjEwLTguMS5lbDcua29sYWJfMTQpIHdpdGggTE1UUEE7DQogICAgICAgIFdlZCwgMDkgQXVnIDIwMTcgMTg6Mzc6MDEgKzAyMDANClgtU2lldmU6IENNVSBTaWV2ZSAyLjQNClJlY2VpdmVkOiBmcm9tIGludC1teDAwMi5teWtvbGFiLmNvbSAodW5rbm93biBbMTAuOS4xMy4yXSkNCiAgICAgICAgYnkgaW1hcGIwMTAubXlrb2xhYi5jb20gKFBvc3RmaXgpIHdpdGggRVNNVFBTIGlkIDBBOTM5MTBBMjUwNDcNCiAgICAgICAgZm9yIDxjaHJpc3RpYW5AZXhhbXBsZS5jaD47IFdlZCwgIDkgQXVnIDIwMTcgMTg6Mzc6MDEgKzAyMDAgKENFU1QpDQpSZWNlaXZlZDogZnJvbSBpbnQtc3VibTAwMi5teWtvbGFiLmNvbSAodW5rbm93biBbMTAuOS4zNy4yXSkNCiAgICAgICAgYnkgaW50LW14MDAyLm15a29sYWIuY29tIChQb3N0Zml4KSB3aXRoIEVTTVRQUyBpZCBFQzA2QUY2RQ0KICAgICAgICBmb3IgPGNocmlzdGlhbkBleGFtcGxlLmNoPjsgV2VkLCAgOSBBdWcgMjAxNyAxODozNzowMCArMDIwMCAoQ0VTVCkNCk1JTUUtVmVyc2lvbjogMS4wDQpDb250ZW50LVR5cGU6IG11bHRpcGFydC9taXhlZDsNCmJvdW5kYXJ5PSI9XzI5MWI4ZTk2NTY0MjY1NjM2NDMyYzZkNDk0ZTAyMzIyIg0KRGF0ZTogU2F0LCAwNiBNYXkgMjAyMyAxNDo0MTo0MCANCkZyb206ICJNb2xsZWtvcGYsIENocmlzdGlhbiIgPGNocmlzdGlhbkBleGFtcGxlLmNoPg0KVG86IGNocmlzdGlhbkBleGFtcGxlLmNoDQpTdWJqZWN0OiBGb29iYXIgMQ0KTWVzc2FnZS1JRDogPGZvb2JhcjFAZXhhbXBsZS5vcmc+DQoNCi0tPV8yOTFiOGU5NjU2NDI2NTYzNjQzMmM2ZDQ5NGUwMjMyMg0KQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvYWx0ZXJuYXRpdmU7DQpib3VuZGFyeT0iPV9jZWZmMGZkMTk3NTZmNDVlZDEyOTVlZTIwNjlmZjhlMCINCg0KLS09X2NlZmYwZmQxOTc1NmY0NWVkMTI5NWVlMjA2OWZmOGUwDQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA3Yml0DQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9VVMtQVNDSUkNCg0Kc2Rsa2pzZGpmDQotLT1fY2VmZjBmZDE5NzU2ZjQ1ZWQxMjk1ZWUyMDY5ZmY4ZTANCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCkNvbnRlbnQtVHlwZTogdGV4dC9odG1sOyBjaGFyc2V0PVVURi04DQoNCjxodG1sPjxoZWFkPjxtZXRhIGh0dHAtZXF1aXY9M0QiQ29udGVudC1UeXBlIiBjb250ZW50PTNEInRleHQvaHRtbDsgY2hhcnNldD0NCj0zRFVURi04IiAvPjwvaGVhZD48Ym9keSBzdHlsZT0zRCdmb250LXNpemU6IDEwcHQ7IGZvbnQtZmFtaWx5OiBWZXJkYW5hLEdlbj0NCmV2YSxzYW5zLXNlcmlmJz4NCjxwPnNkbGtqc2RqZjwvcD4NCg0KPC9ib2R5PjwvaHRtbD4NCg0KLS09X2NlZmYwZmQxOTc1NmY0NWVkMTI5NWVlMjA2OWZmOGUwLS0NCg0KLS09XzI5MWI4ZTk2NTY0MjY1NjM2NDMyYzZkNDk0ZTAyMzIyDQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsNCm5hbWU9eG9yZy5jb25mDQpDb250ZW50LURpc3Bvc2l0aW9uOiBhdHRhY2htZW50Ow0KZmlsZW5hbWU9eG9yZy5jb25mOw0Kc2l6ZT0yMTENCg0KVTJWamRHbHZiaUFpUkdWMmFXTmxJZ29nSUNBZ1NXUmxiblJwWm1sbGNpQWdJQ0FnSWtSbGRtbGpaVEFpQ2lBZ0lDQkVjbWwyWlhJZw0KSUNBZ0lFSnZZWEprVG1GdFpTQWdJQ0FnSUNKT1ZsTWdOREl3TUUwaUNpQWdJQ0JQY0hScGIyNGdJazV2VEc5bmJ5SWdJblJ5ZFdVaQ0KQ2lBZ0lDQlBjSFJwYjI0Z0lsVnpaVVZFU1VRaUlDSjBjblZsSWdwRmJtUlRaV04wYVc5dUNnPT0NCi0tPV8yOTFiOGU5NjU2NDI2NTYzNjQzMmM2ZDQ5NGUwMjMyMi0tAAEBVgMyAAEAAlMDSVBNLk5vdGUAAXwDdXJuOmNvbnRlbnQtY2xhc3NlczptZXNzYWdlAAEAEU5PUAN4b3JnLmNvbmYAAVEDMzhiOTUwZWJkNjJjZDlhNjY5MjljODk2MTVkMGZjMDQ6OjU6OjIAAVIDMQABTAMzNTEwMDIxMgABAQEBAQEBAQE='), - $output - ); - } - - public function testEncodeEmailPerformanceTest() - { - $outputStream = fopen("php://temp", 'r+'); - - $encoder = new Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3); - $attachment = str_repeat("ICAgIEJvYXJkTmFtZSAgICAgICJOVlMgNDIwME0iCiAgICBPcHRpb24gIk5vTG9nbyIgInRydWUi \n", 100000); - $xml = <<<EOF - <?xml version="1.0" encoding="utf-8"?> - <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/"> - <Sync xmlns="uri:AirSync" xmlns:Syncroton="uri:Syncroton" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Email="uri:Email" xmlns:Email2="uri:Email2" xmlns:Tasks="uri:Tasks"> - <Collections> - <Collection xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <Class>Email</Class> - <SyncKey>2</SyncKey> - <CollectionId>38b950ebd62cd9a66929c89615d0fc04</CollectionId> - <Status>1</Status> - <MoreAvailable/> - <Commands xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <Add xmlns:default="uri:Email" xmlns:default1="uri:AirSyncBase"> - <ServerId>38b950ebd62cd9a66929c89615d0fc04::1</ServerId> - <ApplicationData> - <Email:DateReceived xmlns="uri:Email">2023-05-06T14:51:40.000Z</Email:DateReceived> - <Email:From xmlns="uri:Email">"Mollekopf, Christian" <christian@example.ch></Email:From> - <Email:InternetCPID xmlns="uri:Email">65001</Email:InternetCPID> - <Email:Subject xmlns="uri:Email">Foobar 1</Email:Subject> - <Email:To xmlns="uri:Email">christian@example.ch</Email:To> - <Email:Read xmlns="uri:Email">0</Email:Read> - <Email:Flag xmlns="uri:Email"/> - <AirSyncBase:Body xmlns="uri:AirSyncBase"> - <AirSyncBase:Type>4</AirSyncBase:Type> - <AirSyncBase:Data>Return-Path: <christian@example.ch> - Received: from imapb010.mykolab.com (unix socket) - by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; - Wed, 09 Aug 2017 18:37:01 +0200 - X-Sieve: CMU Sieve 2.4 - Received: from int-mx002.mykolab.com (unknown 10.9.13.2) - by imapb010.mykolab.com (Postfix) with ESMTPS id 0A93910A25047 - for <christian@example.ch>; Wed, 9 Aug 2017 18:37:01 +0200 (CEST) - Received: from int-subm002.mykolab.com (unknown 10.9.37.2) - by int-mx002.mykolab.com (Postfix) with ESMTPS id EC06AF6E - for <christian@example.ch>; Wed, 9 Aug 2017 18:37:00 +0200 (CEST) - MIME-Version: 1.0 - Content-Type: multipart/mixed; - boundary="=_291b8e96564265636432c6d494e02322" - Date: Sat, 06 May 2023 14:41:40 - From: "Mollekopf, Christian" <christian@example.ch> - To: christian@example.ch - Subject: Foobar 1 - Message-ID: <foobar1@example.org> - - --=_291b8e96564265636432c6d494e02322 - Content-Type: multipart/alternative; - boundary="=_ceff0fd19756f45ed1295ee2069ff8e0" - - --=_ceff0fd19756f45ed1295ee2069ff8e0 - Content-Transfer-Encoding: 7bit - Content-Type: text/plain; charset=US-ASCII - - sdlkjsdjf - --=_ceff0fd19756f45ed1295ee2069ff8e0 - Content-Transfer-Encoding: quoted-printable - Content-Type: text/html; charset=UTF-8 - - <html><head><meta http-equiv=3D"Content-Type" content=3D"text/html; charset= - =3DUTF-8" /></head><body style=3D'font-size: 10pt; font-family: Verdana,Gen= - eva,sans-serif'> - <p>sdlkjsdjf</p> - - </body></html> - - --=_ceff0fd19756f45ed1295ee2069ff8e0-- - - --=_291b8e96564265636432c6d494e02322 - Content-Transfer-Encoding: base64 - Content-Type: text/plain; - name=xorg.conf - Content-Disposition: attachment; - filename=xorg.conf; - size=211 - - U2VjdGlvbiAiRGV2aWNlIgogICAgSWRlbnRpZmllciAgICAgIkRldmljZTAiCiAgICBEcml2ZXIg - {$attachment} - CiAgICBPcHRpb24gIlVzZUVESUQiICJ0cnVlIgpFbmRTZWN0aW9uCg== - --=_291b8e96564265636432c6d494e02322--</AirSyncBase:Data> - </AirSyncBase:Body> - <AirSyncBase:NativeBodyType xmlns="uri:AirSyncBase">2</AirSyncBase:NativeBodyType> - <Email:MessageClass xmlns="uri:Email">IPM.Note</Email:MessageClass> - <Email:ContentClass xmlns="uri:Email">urn:content-classes:message</Email:ContentClass> - <AirSyncBase:Attachments xmlns="uri:AirSyncBase"> - <AirSyncBase:Attachment> - <AirSyncBase:DisplayName>xorg.conf</AirSyncBase:DisplayName> - <AirSyncBase:FileReference>38b950ebd62cd9a66929c89615d0fc04::5::2</AirSyncBase:FileReference> - <AirSyncBase:Method>1</AirSyncBase:Method> - <AirSyncBase:EstimatedDataSize>35100212</AirSyncBase:EstimatedDataSize> - </AirSyncBase:Attachment> - </AirSyncBase:Attachments> - </ApplicationData> - </Add> - </Commands> - </Collection> - </Collections> - </Sync> - EOF; - - $dom = new DOMDocument(); - $dom->loadXML($xml); - - $start = microtime(true); - $encoder->encode($dom); - $end = microtime(true); - - $this->assertTrue($end - $start < 0.05); - } - - public function testDecoder() - { - $inputStream = fopen("php://memory", 'r+'); - $input = "\x03\x01j\x00\x00\x07VR\x030\x00\x01\x01"; - fwrite($inputStream, $input); - rewind($inputStream); - - $decoder = new Syncroton_Wbxml_Decoder($inputStream); - $dom = $decoder->decode(); - $xml = $dom->saveXML(); - - $expected = '<?xml version="1.0" encoding="utf-8"?>' - . '<!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">' - . '<FolderSync xmlns="uri:FolderHierarchy"><SyncKey>0</SyncKey></FolderSync>'; - - $this->assertSame($expected, str_replace("\n", '', $xml)); - } -}
View file
kolab-syncroton-2.4.2.tar.gz/tests/src/contact.vcard1
Deleted
@@ -1,6 +0,0 @@ -BEGIN:VCARD -VERSION:3.0 -UID:urn:uuid:abcdef-0123-4567-89ab-abcdefabcdef -FN:Jane Doe -N:Doe;Jane;J.;; -END:VCARD
View file
kolab-syncroton-2.4.2.tar.gz/tests/src/contact.vcard2
Deleted
@@ -1,6 +0,0 @@ -BEGIN:VCARD -VERSION:3.0 -UID:urn:uuid:abcdef-0123-4567-89ab-abcdefabc123 -FN:Jack Strong -N:Strong;Jack;;; -END:VCARD
View file
kolab-syncroton-2.4.2.tar.gz/tests/src/event.ics1
Deleted
@@ -1,12 +0,0 @@ -BEGIN:VCALENDAR -VERSION:2.0 -PRODID:-//test/test//NONSGML v1.0//EN -BEGIN:VEVENT -UID:abcdef -DTSTAMP:19970714T170000Z -ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com -DTSTART:20240714T170000Z -DTEND:20240714T180000Z -SUMMARY:Party -END:VEVENT -END:VCALENDAR
View file
kolab-syncroton-2.4.2.tar.gz/tests/src/event.ics2
Deleted
@@ -1,12 +0,0 @@ -BEGIN:VCALENDAR -VERSION:2.0 -PRODID:-//test/test//NONSGML v1.0//EN -BEGIN:VEVENT -UID:123456 -DTSTAMP:19970714T170000Z -ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com -DTSTART:20240715T170000Z -DTEND:20240715T180000Z -SUMMARY:Meeting -END:VEVENT -END:VCALENDAR
View file
kolab-syncroton-2.4.2.tar.gz/tests/src/mail.itip.invalid
Deleted
@@ -1,51 +0,0 @@ -MIME-Version: 1.0 -Date: Thu, 07 Dec 2023 13:29:14 +0100 -Message-ID: <14ab307198d32cee00b38ffb54c9e577@nestle.kolab.ch> -From: "Organizer" <$from> -To: <$to> -Subject: Invalid itip invitation -Content-Type: multipart/alternative; - boundary="=_f39ac9438326f676a8d562e163aa31e0" - ---=_f39ac9438326f676a8d562e163aa31e0 -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain; charset=UTF-8; - format=flowed - -*Test* ---=_f39ac9438326f676a8d562e163aa31e0 -Content-Transfer-Encoding: 8bit -Content-Type: text/calendar; charset=UTF-8; method=REQUEST; name=event.ics - -BEGIN:VCALENDAR -VERSION:2.0 -PRODID:-//Roundcube 1.5-git//Sabre VObject 4.5.3//EN -CALSCALE:GREGORIAN -METHOD:REQUEST -BEGIN:VTIMEZONE -TZID:Europe/Warsaw -BEGIN:DAYLIGHT -DTSTART:20230326T010000 -TZOFFSETFROM:+0100 -TZOFFSETTO:+0200 -TZNAME:CEST -END:DAYLIGHT -BEGIN:DAYLIGHT -DTSTART:20240331T010000 -TZOFFSETFROM:+0100 -TZOFFSETTO:+0200 -TZNAME:CEST -END:DAYLIGHT -BEGIN:STANDARD -DTSTART:20231029T010000 -TZOFFSETFROM:+0200 -TZOFFSETTO:+0100 -TZNAME:CET -END:STANDARD -END:VTIMEZONE -BEGIN:VEVENT -DTSTART;TZID=Europe/Warsaw:20231207T140000 -END:VEVENT -END:VCALENDAR - ---=_f39ac9438326f676a8d562e163aa31e0--
View file
kolab-syncroton-2.4.2.tar.gz/tests/src/mail.itip1
Deleted
@@ -1,62 +0,0 @@ -MIME-Version: 1.0 -Date: Thu, 07 Dec 2023 13:29:14 +0100 -Message-ID: <14ab307198d32cee00b38ffb54c9e577@nestle.kolab.ch> -From: "Organizer" <$from> -To: <$to> -Subject: You've been invited to "Test" -Content-Type: multipart/alternative; - boundary="=_f39ac9438326f676a8d562e163aa31e0" - ---=_f39ac9438326f676a8d562e163aa31e0 -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain; charset=UTF-8; - format=flowed - -*Test* ---=_f39ac9438326f676a8d562e163aa31e0 -Content-Transfer-Encoding: 8bit -Content-Type: text/calendar; charset=UTF-8; method=REQUEST; name=event.ics - -BEGIN:VCALENDAR -VERSION:2.0 -PRODID:-//Roundcube 1.5-git//Sabre VObject 4.5.3//EN -CALSCALE:GREGORIAN -METHOD:REQUEST -BEGIN:VTIMEZONE -TZID:Europe/Warsaw -BEGIN:DAYLIGHT -DTSTART:20230326T010000 -TZOFFSETFROM:+0100 -TZOFFSETTO:+0200 -TZNAME:CEST -END:DAYLIGHT -BEGIN:DAYLIGHT -DTSTART:20240331T010000 -TZOFFSETFROM:+0100 -TZOFFSETTO:+0200 -TZNAME:CEST -END:DAYLIGHT -BEGIN:STANDARD -DTSTART:20231029T010000 -TZOFFSETFROM:+0200 -TZOFFSETTO:+0100 -TZNAME:CET -END:STANDARD -END:VTIMEZONE -BEGIN:VEVENT -UID:1154B829349633D80E143AAB5641170A-93BC4FC398A3FD52 -DTSTAMP:20231207T122914Z -CREATED:20231207T122914Z -LAST-MODIFIED:20231207T122914Z -DTSTART;TZID=Europe/Warsaw:20231207T140000 -DTEND;TZID=Europe/Warsaw:20231207T143000 -SUMMARY:Test -SEQUENCE:0 -TRANSP:OPAQUE -ATTENDEE;CN="Attendee Name";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPA - NT;CUTYPE=INDIVIDUAL;RSVP=TRUE:mailto:$to -ORGANIZER;CN="Organizer Name":mailto:$from -END:VEVENT -END:VCALENDAR - ---=_f39ac9438326f676a8d562e163aa31e0--
View file
kolab-syncroton-2.4.2.tar.gz/tests/src/mail.sync1
Deleted
@@ -1,10 +0,0 @@ -Date: Thu, 09 Aug 2012 13:18:31 +0000 -Subject: test sync -Message-ID: <sync1@domain.tld> -From: "Sync 1" <user@domain.tld> -To: "To 1" <kolab1@domain.tld>, "To 2" <kolab2@domain.tld> -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf-8 -Content-Transfer-Encoding: base64 - -ZWVlYQ==
View file
kolab-syncroton-2.4.2.tar.gz/tests/src/mail.sync2
Deleted
@@ -1,20 +0,0 @@ -Date: Thu, 10 Aug 2012 13:18:31 +0000 -Subject: sync test with attachment -Message-ID: <sync2@domain.tld> -From: user@domain.tld -To: kolab@domain.tld -MIME-Version: 1.0 -Content-Type: multipart/mixed; boundary="BOUNDARY" - ---BOUNDARY -Content-Type: text/plain; charset=utf-8 -Content-Transfer-Encoding: base64 - -ZWVl ---BOUNDARY -Content-Transfer-Encoding: base64 -Content-Type: image/jpeg; name=logo.gif -Content-Disposition: inline; filename=logo.gif; size=2574 - -/9j/4AAQSkZJRgABAgEASABIAAD/4QqARXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUA ---BOUNDARY--
View file
kolab-syncroton-2.4.2.tar.gz/tests/src/sample.rtf
Deleted
@@ -1,18 +0,0 @@ -{\rtf1\mac\deff2 {\fonttbl{\f0\fswiss Chicago;}{\f2\froman New York;}{\f3\fswiss Geneva;}{\f4\fmodern Monaco;}{\f11\fnil Cairo;}{\f13\fnil Zapf Dingbats;}{\f14\fnil Bookman;}{\f15\fnil N Helvetica Narrow;}{\f16\fnil Palatino;}{\f18\fnil Zapf Chancery;} -{\f20\froman Times;}{\f21\fswiss Helvetica;}{\f22\fmodern Courier;}{\f23\ftech Symbol;}{\f33\fnil Avant Garde;}{\f34\fnil New Century Schlbk;}{\f1297\fnil GoudyHundred;}{\f1602\fnil BlackChancery;}{\f2515\fnil MT Extra;}{\f4950\fnil TTYFont;} -{\f11132\fnil InsigniaLQmono;}{\f11133\fnil InsigniaLQprop;}{\f32500\fnil VT320;}{\f32525\fnil VT100;}}{\colortbl\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0; -\red255\green255\blue0;\red255\green255\blue255;}{\stylesheet{\s250\li720 \f21\fs20\ul \sbasedon0\snext0 heading 6;}{\s251\li720 \b\f21\fs20 \sbasedon0\snext0 heading 5;}{\s252\li360 \f21\ul \sbasedon0\snext0 heading 4;}{\s253\li360 \b\f21 -\sbasedon0\snext0 heading 3;}{\s254\sb120 \b\f21 \sbasedon0\snext0 heading 2;}{\s255\sb240 \b\f21\ul \sbasedon0\snext0 heading 1;}{\f21 \sbasedon222\snext0 Normal;}{\s2 \b\f21\cf1 \sbasedon0\snext2 Anchor;}}{\info{\author Chuck Shotton}} -\margl720\margr720\ftnbj\fracwidth \sectd \sbknone\linemod0\linex0\cols1\endnhere \pard\plain \s255\sb240 \b\f21\ul Heading 1\par -\pard\plain \f21 This is the first normal paragraph!\par -\pard\plain \s254\sb120 \b\f21 Heading 2\par -\pard\plain \s253\li360 \b\f21 Heading 3\par -\pard\plain \s252\li360 \f21\ul Heading 4\par -\pard\plain \s251\li720 \b\f21\fs20 Heading 5\par -\pard\plain \s250\li720 \f21\fs20\ul Heading 6\par -\pard\plain \f21 This is a chunk of normal text.\par -This is a chunk of normal text with specials, &, <, and >.\par -This is a second paragraph.\par -This is text with embedded {\b bold}, {\i italic}, and {\ul underline} styles.\par -Here is the {\cf1 anchor} style. And here is the {\cf5 Image} style.\par -} \ No newline at end of file
View file
kolab-syncroton.dsc
Changed
@@ -2,7 +2,7 @@ Source: kolab-syncroton Binary: kolab-syncroton Architecture: all -Version: 1:2.4.2.36-1~kolab1 +Version: 2.3.22-0~kolab1 Maintainer: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Uploaders: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Homepage: http://www.kolab.org/ @@ -12,5 +12,5 @@ Package-List: kolab-syncroton deb utils extra Files: - 00000000000000000000000000000000 0 kolab-syncroton-2.4.0.tar.gz + 00000000000000000000000000000000 0 kolab-syncroton-2.3.22.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
View file
plesk.kolab_syncroton.inc.php
Changed
@@ -118,6 +118,8 @@ $config'activesync_multifolder_blacklist_note' = null; $config'activesync_multifolder_blacklist_task' = null; +$config'activesync_protected_folders' = array('windowsoutlook' => array('INBOX', 'Sent', 'Trash')); + // 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' = true; +$config'activesync_fix_from' = false;
View file
release.sh
Deleted
@@ -1,15 +0,0 @@ -#!/bin/bash - -./buildtarball.sh - -# Autobump the version -CURRENT_VERSION=$(grep '^Version: ' ./*.spec | sed 's/Version: //') -NEW_VERSION=$(echo "$CURRENT_VERSION" | awk -F. '/0-9+\./{$NF++;print}' OFS=.) -echo "Bumping from $CURRENT_VERSION to $NEW_VERSION" - -sed -i "s/$CURRENT_VERSION/$NEW_VERSION/" debian.changelog -sed -i "s/^Version:.*/Version: 1:$NEW_VERSION-1~kolab1/" ./*.dsc -sed -i "s/^Version:.*/Version: $NEW_VERSION/" ./*.spec - -osc ci -m "New release $NEW_VERSION" -osc sr Kolab:16 --yes -m "New release $NEW_VERSION"
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
.