From bc160637631a2586307d68108a85141f1e5aee6a Mon Sep 17 00:00:00 2001
From: Matthieu Gallien <matthieu.gallien@nextcloud.com>
Date: Thu, 19 Sep 2024 18:50:33 +0200
Subject: [PATCH] receive and decode tokens for locks

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
---
 src/libsync/discovery.cpp      | 4 +++-
 src/libsync/discoveryphase.cpp | 7 +++++--
 src/libsync/discoveryphase.h   | 1 +
 src/libsync/lockfilejobs.cpp   | 4 ++++
 src/libsync/lockfilejobs.h     | 1 +
 src/libsync/syncengine.cpp     | 1 +
 src/libsync/syncfileitem.cpp   | 3 +++
 src/libsync/syncfileitem.h     | 1 +
 8 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp
index 57699bee5d77a..dc1a0312ffd5a 100644
--- a/src/libsync/discovery.cpp
+++ b/src/libsync/discovery.cpp
@@ -668,6 +668,7 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(const SyncFileItemPtr &it
     item->_lockEditorApp = serverEntry.lockEditorApp;
     item->_lockTime = serverEntry.lockTime;
     item->_lockTimeout = serverEntry.lockTimeout;
+    item->_lockToken = serverEntry.lockToken;
 
     qCDebug(lcDisco()) << "item lock for:" << item->_file
                        << item->_locked
@@ -676,7 +677,8 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(const SyncFileItemPtr &it
                        << item->_lockOwnerType
                        << item->_lockEditorApp
                        << item->_lockTime
-                       << item->_lockTimeout;
+                       << item->_lockTimeout
+                       << item->_lockToken;
 
     // Check for missing server data
     {
diff --git a/src/libsync/discoveryphase.cpp b/src/libsync/discoveryphase.cpp
index 0041205c6ca62..02722ceedac9b 100644
--- a/src/libsync/discoveryphase.cpp
+++ b/src/libsync/discoveryphase.cpp
@@ -415,7 +415,8 @@ void DiscoverySingleDirectoryJob::start()
               << "http://nextcloud.org/ns:lock-owner-type"
               << "http://nextcloud.org/ns:lock-owner-editor"
               << "http://nextcloud.org/ns:lock-time"
-              << "http://nextcloud.org/ns:lock-timeout";
+              << "http://nextcloud.org/ns:lock-timeout"
+              << "http://nextcloud.org/ns:lock-token";
     }
     props << "http://nextcloud.org/ns:is-mount-root";
 
@@ -545,7 +546,9 @@ static void propertyMapToRemoteInfo(const QMap<QString, QString> &map, RemotePer
                 result.lockTimeout = 0;
             }
         }
-
+        if (property == "lock-token") {
+            result.lockToken = value;
+        }
     }
 
     if (result.isDirectory && map.contains("size")) {
diff --git a/src/libsync/discoveryphase.h b/src/libsync/discoveryphase.h
index 7d53f1336d698..ff38d739118ae 100644
--- a/src/libsync/discoveryphase.h
+++ b/src/libsync/discoveryphase.h
@@ -86,6 +86,7 @@ struct RemoteInfo
     QString lockEditorApp;
     qint64 lockTime = 0;
     qint64 lockTimeout = 0;
+    QString lockToken;
 };
 
 struct LocalInfo
diff --git a/src/libsync/lockfilejobs.cpp b/src/libsync/lockfilejobs.cpp
index aa4b8af428731..77e48afcbc66f 100644
--- a/src/libsync/lockfilejobs.cpp
+++ b/src/libsync/lockfilejobs.cpp
@@ -115,6 +115,7 @@ void LockFileJob::setFileRecordLocked(SyncJournalFileRecord &record) const
     record._lockstate._lockEditorApp = _editorName;
     record._lockstate._lockTime = _lockTime;
     record._lockstate._lockTimeout = _lockTimeout;
+    record._lockstate._lockToken = _lockToken;
     if (!_etag.isEmpty()) {
         record._etag = _etag;
     }
@@ -129,6 +130,7 @@ void LockFileJob::resetState()
     _userId.clear();
     _lockTime = 0;
     _lockTimeout = 0;
+    _lockToken.clear();
 }
 
 SyncJournalFileRecord LockFileJob::handleReply()
@@ -241,6 +243,8 @@ void LockFileJob::decodeStartElement(const QString &name,
         _editorName = reader.readElementText();
     } else if (name == QStringLiteral("getetag")) {
         _etag = reader.readElementText().toUtf8();
+    } else if (name == QStringLiteral("lock-token")) {
+        _lockToken = reader.readElementText();
     }
 }
 
diff --git a/src/libsync/lockfilejobs.h b/src/libsync/lockfilejobs.h
index 8b2e287f6d4c0..9b8be46c5523f 100644
--- a/src/libsync/lockfilejobs.h
+++ b/src/libsync/lockfilejobs.h
@@ -59,6 +59,7 @@ class OWNCLOUDSYNC_EXPORT LockFileJob : public AbstractNetworkJob
     QByteArray _etag;
     qint64 _lockTime = 0;
     qint64 _lockTimeout = 0;
+    QString _lockToken;
     QString _remoteSyncPathWithTrailingSlash;
     QString _localSyncPath;
 };
diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp
index 592078dda140c..086a025dee4fa 100644
--- a/src/libsync/syncengine.cpp
+++ b/src/libsync/syncengine.cpp
@@ -445,6 +445,7 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
             lockInfo._lockOwnerType = static_cast<qint64>(item->_lockOwnerType);
             lockInfo._lockOwnerDisplayName = item->_lockOwnerDisplayName;
             lockInfo._lockEditorApp = item->_lockOwnerDisplayName;
+            lockInfo._lockToken = item->_lockToken;
 
             if (!_journal->updateLocalMetadata(item->_file, item->_modtime, item->_size, item->_inode, lockInfo)) {
                 qCWarning(lcEngine) << "Could not update local metadata for file" << item->_file;
diff --git a/src/libsync/syncfileitem.cpp b/src/libsync/syncfileitem.cpp
index 7ac7ca15378c3..6b32a5fae1ceb 100644
--- a/src/libsync/syncfileitem.cpp
+++ b/src/libsync/syncfileitem.cpp
@@ -125,6 +125,7 @@ SyncJournalFileRecord SyncFileItem::toSyncJournalFileRecordWithInode(const QStri
     rec._lockstate._lockEditorApp = _lockEditorApp;
     rec._lockstate._lockTime = _lockTime;
     rec._lockstate._lockTimeout = _lockTimeout;
+    rec._lockstate._lockToken = _lockToken;
 
     // Update the inode if possible
     rec._inode = _inode;
@@ -163,6 +164,7 @@ SyncFileItemPtr SyncFileItem::fromSyncJournalFileRecord(const SyncJournalFileRec
     item->_lockEditorApp = rec._lockstate._lockEditorApp;
     item->_lockTime = rec._lockstate._lockTime;
     item->_lockTimeout = rec._lockstate._lockTimeout;
+    item->_lockToken = rec._lockstate._lockToken;
     item->_sharedByMe = rec._sharedByMe;
     item->_isShared = rec._isShared;
     item->_lastShareStateFetchedTimestamp = rec._lastShareStateFetchedTimestamp;
@@ -251,6 +253,7 @@ void SyncFileItem::updateLockStateFromDbRecord(const SyncJournalFileRecord &dbRe
     _lockEditorApp = dbRecord._lockstate._lockEditorApp;
     _lockTime = dbRecord._lockstate._lockTime;
     _lockTimeout = dbRecord._lockstate._lockTimeout;
+    _lockToken = dbRecord._lockstate._lockToken;
 }
 
 }
diff --git a/src/libsync/syncfileitem.h b/src/libsync/syncfileitem.h
index 3f6a52898611d..4bf481a138c86 100644
--- a/src/libsync/syncfileitem.h
+++ b/src/libsync/syncfileitem.h
@@ -326,6 +326,7 @@ class OWNCLOUDSYNC_EXPORT SyncFileItem
     QString _lockEditorApp;
     qint64 _lockTime = 0;
     qint64 _lockTimeout = 0;
+    QString _lockToken;
 
     bool _isShared = false;
     time_t _lastShareStateFetchedTimestamp = 0;