Page MenuHomePhorge

D4998.diff
No OneTemporary

D4998.diff

diff --git a/bin/resync.php b/bin/resync.php
new file mode 100755
--- /dev/null
+++ b/bin/resync.php
@@ -0,0 +1,116 @@
+#!/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");
+ }
+}
diff --git a/docs/SQL/mysql/2024101700.sql b/docs/SQL/mysql/2024101700.sql
new file mode 100644
--- /dev/null
+++ b/docs/SQL/mysql/2024101700.sql
@@ -0,0 +1 @@
+ALTER TABLE `syncroton_folder` ADD `resync` tinyint(1) DEFAULT NULL;
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
@@ -234,6 +234,12 @@
}
}
+ // 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) {
diff --git a/lib/ext/Syncroton/Model/Folder.php b/lib/ext/Syncroton/Model/Folder.php
--- a/lib/ext/Syncroton/Model/Folder.php
+++ b/lib/ext/Syncroton/Model/Folder.php
@@ -34,6 +34,7 @@
'class' => ['type' => 'string'],
'creationTime' => ['type' => 'datetime'],
'lastfiltertype' => ['type' => 'number'],
+ 'resync' => ['type' => 'number'],
],
];
}
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
@@ -88,7 +88,7 @@
$select = $this->db->query('SELECT * FROM `' . $this->table_name . '` WHERE ' . implode(' AND ', $where));
$folder = $this->db->fetch_assoc($select);
- if (empty($folder)) {
+ if (empty($folder) || !empty($folder['resync'])) {
throw new Syncroton_Exception_NotFound('Folder not found');
}
@@ -117,6 +117,18 @@
Syncroton_Data_Factory::CLASS_TASKS,
];
+ // 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);
+ }
+
// Reset imap cache so we work with up-to-date folders list
rcube::get_instance()->get_storage()->clear_cache('mailboxes', true);
@@ -132,13 +144,6 @@
}
}
- // 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);

File Metadata

Mime Type
text/plain
Expires
Sat, Oct 19, 5:26 PM (19 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
9890577
Default Alt Text
D4998.diff (7 KB)

Event Timeline