Page MenuHomePhorge

D5187.1775360991.diff
No OneTemporary

Authored By
Unknown
Size
14 KB
Referenced Files
None
Subscribers
None

D5187.1775360991.diff

diff --git a/lib/ext/Syncroton/Command/Ping.php b/lib/ext/Syncroton/Command/Ping.php
--- a/lib/ext/Syncroton/Command/Ping.php
+++ b/lib/ext/Syncroton/Command/Ping.php
@@ -65,6 +65,7 @@
$intervalStart = time();
$status = self::STATUS_NO_CHANGES_FOUND;
+ $pingTimeout = Syncroton_Registry::getPingTimeout();
// 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);
@@ -72,6 +73,11 @@
if (isset($xml->HeartbeatInterval)) {
$this->_device->pinglifetime = (int)$xml->HeartbeatInterval;
+ // Magic value for testing
+ if ($this->_device->pinglifetime == 9999) {
+ $pingTimeout = 1;
+ $this->_device->pinglifetime = 900;
+ }
}
if (isset($xml->Folders->Folder)) {
@@ -264,10 +270,10 @@
// 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
- if ($secondsLeft < (Syncroton_Registry::getPingTimeout() + 10)) {
+ if ($secondsLeft < ($pingTimeout + 10)) {
break;
} else {
- $this->goToSleep(Syncroton_Registry::getPingTimeout());
+ $this->goToSleep($pingTimeout);
}
} while (Syncroton_Server::validateSession());
diff --git a/lib/kolab_sync_backend_folder.php b/lib/kolab_sync_backend_folder.php
--- a/lib/kolab_sync_backend_folder.php
+++ b/lib/kolab_sync_backend_folder.php
@@ -144,8 +144,12 @@
Syncroton_Data_Factory::CLASS_TASKS,
];
- // Reset imap cache so we work with up-to-date folders list
+ // Reset imap cache, metadata cache and the folder list cache so we work with up-to-date folders lists
rcube::get_instance()->get_storage()->clear_cache('mailboxes', true);
+ kolab_sync::storage()->reset();
+ foreach ($folder_classes as $class) {
+ Syncroton_Data_Factory::factory($class, $device, $timestamp)->clearCache();
+ }
// Retrieve all folders already sent to the client
$select = $this->db->query("SELECT * FROM `{$this->table_name}` WHERE `device_id` = ?", $device->id);
diff --git a/lib/kolab_sync_data.php b/lib/kolab_sync_data.php
--- a/lib/kolab_sync_data.php
+++ b/lib/kolab_sync_data.php
@@ -747,6 +747,14 @@
return $folders;
}
+ /**
+ * Clear the internal folder list cache
+ */
+ public function clearCache()
+ {
+ $this->folders = [];
+ }
+
/**
* List of all IMAP folders (or subtree)
*
diff --git a/lib/kolab_sync_storage.php b/lib/kolab_sync_storage.php
--- a/lib/kolab_sync_storage.php
+++ b/lib/kolab_sync_storage.php
@@ -124,6 +124,7 @@
public function reset()
{
$this->folders = [];
+ $this->folder_meta = null;
}
/**
@@ -265,7 +266,7 @@
{
if (!isset($this->folder_meta)) {
// get folders activesync config
- $folderdata = $this->storage->get_metadata("*", self::ASYNC_KEY);
+ $folderdata = $this->storage->get_metadata("*", self::ASYNC_KEY, [], true);
if (!is_array($folderdata)) {
return $this->folder_meta = false;
diff --git a/tests/Sync/PingTest.php b/tests/Sync/PingTest.php
--- a/tests/Sync/PingTest.php
+++ b/tests/Sync/PingTest.php
@@ -63,12 +63,62 @@
$this->assertEquals(200, $response->getStatusCode());
$dom = $this->fromWbxml($response->getBody());
$xpath = $this->xpath($dom);
- // Initially we know no folders
+ // We don't find the folder state because it was never synced
$this->assertSame('2', $xpath->query("//ns:Ping/ns:Status")->item(0)->nodeValue);
+
+ // Sync inbox
+ $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>0</SyncKey>
+ <CollectionId>38b950ebd62cd9a66929c89615d0fc04</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());
+
+ //Now we should get no change
+ $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);
+ // We don't find the folder state because it was never synced
+ $this->assertSame('1', $xpath->query("//ns:Ping/ns:Status")->item(0)->nodeValue);
}
/**
- * Test Ping command
+ * Test Unknown Folder
*/
public function testUnknownFolder()
{
@@ -95,4 +145,148 @@
$this->assertSame('7', $xpath->query("//ns:Ping/ns:Status")->item(0)->nodeValue);
}
+
+ /**
+ * Test New Folder
+ */
+ public function testNewFolder()
+ {
+ //Initialize the folder state
+ $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());
+
+ $this->createTestFolder("NewFolder", "mail");
+ $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->assertSame('7', $xpath->query("//ns:Ping/ns:Status")->item(0)->nodeValue);
+ }
+
+ /**
+ * Test Changed Subscription Folder
+ */
+ public function testNewFolderSubscriptionState()
+ {
+ //Initialize the folder state
+ $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());
+
+ $this->setSubscriptionState("NewFolder", null);
+ $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->assertSame('7', $xpath->query("//ns:Ping/ns:Status")->item(0)->nodeValue);
+ }
+
+ /**
+ * Test changed subscription while ping is running
+ */
+ public function testNewFolderSubscriptionStateDuringPing()
+ {
+ //Initialize the folder state
+ $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());
+
+ $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());
+
+ // Set the metadata via a background script, while Ping is running.
+ // This is essential to trigger a bug where the initial Ping seeds the roundcube metadata cache,
+ // and then subsequent checks don't update the cache. We have to use a separate process to set
+ // the metadata, because otherwise we update the cache (we could also not use the roundcube
+ // infrastructure instead).
+ $deviceId = self::$deviceId;
+ $username = self::$username;
+ $password = self::$password;
+ exec("php setmetadata.php $deviceId NewFolder $username $password > /dev/null 2>&1 &");
+
+ $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>9999</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->assertSame('7', $xpath->query("//ns:Ping/ns:Status")->item(0)->nodeValue);
+ }
}
diff --git a/tests/SyncTestCase.php b/tests/SyncTestCase.php
--- a/tests/SyncTestCase.php
+++ b/tests/SyncTestCase.php
@@ -224,22 +224,31 @@
/**
* Create a folder
*/
- protected function createTestFolder($name, $type)
+ protected function createTestFolder($name, $type, $subscriptionState = '1')
{
// Create IMAP folders
if ($type == 'mail' || $this->isStorageDriver('kolab')) {
$imap = $this->getImapStorage();
//TODO set type if not mail
$imap->create_folder($name, true);
+ $this->setSubscriptionState($name, $subscriptionState);
+ }
+ }
+ /**
+ * Subscribe test folder
+ */
+ protected function setSubscriptionState($name, $subscriptionState)
+ {
+ $metadata = null;
+ if ($subscriptionState) {
$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;
+ $metadata['FOLDER'][self::$deviceId]['S'] = $subscriptionState;
+ $metadata = json_encode($metadata);
}
+ $this->getImapStorage()->set_metadata($name, ['/private/vendor/kolab/activesync' => $metadata]);
}
/**
diff --git a/tests/setmetadata.php b/tests/setmetadata.php
new file mode 100644
--- /dev/null
+++ b/tests/setmetadata.php
@@ -0,0 +1,21 @@
+<?php
+
+define('TESTS_DIR', dirname(__FILE__) . '/');
+require_once(TESTS_DIR . '/../lib/init.php');
+
+sleep(5);
+
+$deviceid=$argv[1] ;
+$folderName=$argv[2] ;
+
+$metadata = [];
+$metadata['FOLDER'] = [];
+$metadata['FOLDER'][$deviceid] = [];
+$metadata['FOLDER'][$deviceid]['S'] = '1';
+$metadata = json_encode($metadata);
+\kolab_sync::get_instance()->authenticate($argv[3], $argv[4]);
+if (\kolab_sync::get_instance()->get_storage()->set_metadata($folderName, ['/private/vendor/kolab/activesync' => $metadata])) {
+ print("Set metdata on $deviceid on $folderName");
+} else {
+ print("Failed to set metdata on $deviceid on $folderName");
+}

File Metadata

Mime Type
text/plain
Expires
Sun, Apr 5, 3:49 AM (17 h, 17 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18832254
Default Alt Text
D5187.1775360991.diff (14 KB)

Event Timeline