Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117754410
D5044.1775199305.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
9 KB
Referenced Files
None
Subscribers
None
D5044.1775199305.diff
View Options
diff --git a/lib/ext/Syncroton/Backend/Folder.php b/lib/ext/Syncroton/Backend/Folder.php
--- a/lib/ext/Syncroton/Backend/Folder.php
+++ b/lib/ext/Syncroton/Backend/Folder.php
@@ -134,4 +134,9 @@
return parent::_toCamelCase($string, $ucFirst);
}
}
+
+ public function exists($deviceid, $folderid);
+ {
+ return false; // not implemented
+ }
}
diff --git a/lib/ext/Syncroton/Backend/IFolder.php b/lib/ext/Syncroton/Backend/IFolder.php
--- a/lib/ext/Syncroton/Backend/IFolder.php
+++ b/lib/ext/Syncroton/Backend/IFolder.php
@@ -53,4 +53,14 @@
* @return bool True if folders hierarchy changed, False otherwise
*/
public function hasHierarchyChanges($device);
+
+ /**
+ * Check if the folder already exists
+ *
+ * @param Syncroton_Model_Device|string $deviceid Device object or identifier
+ * @param string $folderid Folder identifier
+ *
+ * @return bool true if it exists
+ */
+ public function exists($deviceid, $folderid);
}
diff --git a/lib/ext/Syncroton/Command/FolderSync.php b/lib/ext/Syncroton/Command/FolderSync.php
--- a/lib/ext/Syncroton/Command/FolderSync.php
+++ b/lib/ext/Syncroton/Command/FolderSync.php
@@ -68,6 +68,11 @@
*/
protected $_syncKey;
+ /**
+ * @var bool
+ */
+ protected $_syncKeyReused = false;
+
/**
* Parse FolderSync request
*/
@@ -92,11 +97,19 @@
$this->_syncStateBackend->resetState($this->_device, 'FolderSync');
return;
+ } else {
+ // The synckey that is sent to us should already be existing, because we create it at the end,
+ // however, the next one shouldn't
+ if ($this->_syncStateBackend->haveNext($this->_device, 'FolderSync', $syncKey)) {
+ $this->_syncKeyReused = true;
+ if ($this->_logger instanceof Zend_Log) {
+ $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " already known synckey $syncKey provided");
+ }
+ }
}
-
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->_logger->warn(__METHOD__ . '::' . __LINE__ . " invalid synckey $syncKey provided, invalidating sync state");
}
$this->_syncStateBackend->resetState($this->_device, 'FolderSync');
}
@@ -243,6 +256,11 @@
// 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); }));
+ if (!empty($forceDeleteIds)) {
+ if ($this->_logger instanceof Zend_Log) {
+ $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " forcing resync of: " . var_export($forceDeleteIds, true));
+ }
+ }
$serverFoldersIds = array_diff($serverFoldersIds, $forceDeleteIds);
// calculate deleted entries
@@ -254,14 +272,14 @@
$folderSync->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Status', self::STATUS_SUCCESS));
+ $newSyncKey = $this->_syncState->counter;
$count = count($adds) + count($updates) + count($deletes);
if ($count > 0) {
- $this->_syncState->counter++;
- $this->_syncState->lastsync = $this->_syncTimeStamp;
+ $newSyncKey++;
}
// create xml output
- $folderSync->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'SyncKey', $this->_syncState->counter));
+ $folderSync->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'SyncKey', $newSyncKey));
$changes = $folderSync->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Changes'));
$changes->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Count', $count));
@@ -271,12 +289,11 @@
$folder->appendXML($add, $this->_device);
- // store folder in backend
- if (empty($folder->id)) {
- try {
+ if (!$this->_syncKeyReused && empty($folder->id)) {
+ // The folder could exist in the backend if we e.g. delete the same name and then recreate,
+ // or disable/reenable for syncing.
+ if (!$this->_folderBackend->exists($this->_device->id, $folder->serverId)) {
$this->_folderBackend->create($folder);
- } catch (Exception $zdse) {
- //This can happen if we rerun a previous sync-key
}
}
}
@@ -285,7 +302,6 @@
$update = $changes->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Update'));
$folder->appendXML($update, $this->_device);
-
$this->_folderBackend->update($folder);
}
@@ -296,9 +312,12 @@
$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
+ if ($this->_syncState->counter != $newSyncKey) {
+ $this->_syncState->counter = $newSyncKey;
+ $this->_syncState->lastsync = $this->_syncTimeStamp;
+ // Keep previous sync states in case a sync key is re-sent.
+ // We always insert because deleteOtherStates is executed from _syncStateBackend->validate,
+ // which means we remove and re-insert the latest state on key resend.
$this->_syncStateBackend->create($this->_syncState, true); // @phpstan-ignore-line
}
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
@@ -102,6 +102,26 @@
return $this->get_object($folder);
}
+ /**
+ * Check if the folder already exists
+ *
+ * @param Syncroton_Model_Device|string $deviceid Device object or identifier
+ * @param string $folderid Folder identifier
+ *
+ * @return bool true if it exists
+ */
+ public function exists($deviceid, $folderid)
+ {
+ $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);
+
+ $select = $this->db->query('SELECT 1 FROM `' . $this->table_name . '` WHERE ' . implode(' AND ', $where));
+ $folder = $this->db->fetch_assoc($select);
+ return !empty($folder);
+ }
+
/**
* Find out if the folder hierarchy changed since the last FolderSync
*
diff --git a/tests/Sync/FoldersTest.php b/tests/Sync/FoldersTest.php
--- a/tests/Sync/FoldersTest.php
+++ b/tests/Sync/FoldersTest.php
@@ -214,6 +214,52 @@
$this->assertSame('9', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue);
}
+ /**
+ * This test recreates a previously deleted folder.
+ * Currently similar to disabling/reenabling a folder for sync, but should perhaps be tested separately
+ *
+ * @depends testSyncKeyResend
+ */
+ public function testRecreatePreviousFolder()
+ {
+ $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);
+
+ // Cleanup for the other tests
+ $this->deleteTestFolder('NewFolder', 'mail');
+ $this->deleteTestFolder('NewFolder2', 'mail');
+ }
+
/**
* Test FolderSync command
*/
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 3, 6:55 AM (16 h, 38 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18822932
Default Alt Text
D5044.1775199305.diff (9 KB)
Attached To
Mode
D5044: Warning on FolderSync synckey reuse, but then don't try to create in the backend
Attached
Detach File
Event Timeline