From 83f10c23d859b13513d6aff099e64f0a84a63229 Mon Sep 17 00:00:00 2001
From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
Date: Thu, 20 Feb 2020 16:54:53 -0500
Subject: [PATCH] datatransfer: handle unique filenames within acceptTransfer

Change-Id: Id3fbb745f36219e29ae9c8929e78dbcaa00a2c05
---
 src/api/conversationmodel.h |  2 ++
 src/api/datatransfermodel.h |  2 +-
 src/conversationmodel.cpp   | 49 ++++++++++++++++++++-----------------
 src/datatransfermodel.cpp   | 31 ++++++++++++++++++++---
 4 files changed, 57 insertions(+), 27 deletions(-)

diff --git a/src/api/conversationmodel.h b/src/api/conversationmodel.h
index e9bde275..6974272b 100644
--- a/src/api/conversationmodel.h
+++ b/src/api/conversationmodel.h
@@ -211,6 +211,8 @@ public:
 
     void sendFile(const QString& convUid, const QString& path, const QString& filename);
 
+    void acceptTransfer(const QString & convUid, uint64_t interactionId);
+
     void acceptTransfer(const QString& convUid, uint64_t interactionId, const QString& path);
 
     void cancelTransfer(const QString& convUid, uint64_t interactionId);
diff --git a/src/api/datatransfermodel.h b/src/api/datatransfermodel.h
index 2d36c2eb..5fc79de7 100644
--- a/src/api/datatransfermodel.h
+++ b/src/api/datatransfermodel.h
@@ -58,7 +58,7 @@ public:
 
     void bytesProgress(int interactionId, int64_t& total, int64_t& progress);
 
-    void accept(int interactionId, const QString& file_path, std::size_t offset);
+    QString accept(int interactionId, const QString& file_path, std::size_t offset);
 
     void cancel(int interactionId);
 
diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp
index 3e2b2db3..21ff7f35 100644
--- a/src/conversationmodel.cpp
+++ b/src/conversationmodel.cpp
@@ -2025,6 +2025,14 @@ ConversationModel::sendFile(const QString& convUid,
     }
 }
 
+void
+ConversationModel::acceptTransfer(const QString& convUid, uint64_t interactionId)
+{
+    lrc::api::datatransfer::Info info = {};
+    getTransferInfo(interactionId, info);
+    acceptTransfer(convUid, interactionId, info.displayName);
+}
+
 void
 ConversationModel::acceptTransfer(const QString& convUid, uint64_t interactionId, const QString& path)
 {
@@ -2175,31 +2183,17 @@ ConversationModelPimpl::slotTransferStatusAwaitingHost(long long dringId, datatr
         if (emitUpdated) {
             dirtyConversations = {true, true};
             emit linked.interactionStatusUpdated(convId, interactionId, itCopy);
-            // If it's an accepted file type and less than 20 MB, accept transfer.
-
-            // TODO: Use Qt functions
-
-            auto extensionIdx = info.displayName.toStdString().find_last_of(".");
-            if (extensionIdx == std::string::npos)
-                return;
-            auto extension = QString(info.displayName).remove(0, extensionIdx);
+            // Only accept if contact is added
             try {
-                auto contactInfo = linked.owner.contactModel->getContact(conversations[conversationIdx].participants.front());
-                // Only accept if contact is added
+                auto contactUri = conversations[conversationIdx].participants.front();
+                auto contactInfo = linked.owner.contactModel->getContact(contactUri);
                 if (contactInfo.profileInfo.type != profile::Type::RING) return;
             } catch (...) {
                 return;
             }
-            auto destinationDir = lrc.getDataTransferModel().downloadDirectory;
-            if (info.totalSize < 20 * 1024 * 1024 && !destinationDir.isEmpty()) {
-                auto wantedFilename = destinationDir + info.displayName;
-                auto duplicate = 0;
-                while (std::ifstream(wantedFilename.toStdString()).good()) {
-                    ++duplicate;
-                    wantedFilename = destinationDir + info.displayName.left(extensionIdx) +
-                        " (" + toQString(duplicate) + ")" + extension.toLower();
-                }
-                acceptTransfer(convId, interactionId, wantedFilename);
+            // If it's an accepted file type and less than 20 MB, accept transfer.
+            if (info.totalSize < 20 * 1024 * 1024 && info.displayName.contains(".")) {
+                acceptTransfer(convId, interactionId, info.displayName);
             }
         }
     }
@@ -2208,8 +2202,17 @@ ConversationModelPimpl::slotTransferStatusAwaitingHost(long long dringId, datatr
 void
 ConversationModelPimpl::acceptTransfer(const QString& convUid, uint64_t interactionId, const QString& path)
 {
-    lrc.getDataTransferModel().accept(interactionId, path, 0);
-    storage::updateInteractionBody(db, interactionId, path);
+    auto destinationDir = lrc.getDataTransferModel().downloadDirectory;
+    if (destinationDir.isEmpty()) {
+        return;
+    }
+#ifdef Q_OS_WIN
+    if (destinationDir.right(1) != '/') {
+        destinationDir += "/";
+    }
+#endif
+    auto acceptedFilePath = lrc.getDataTransferModel().accept(interactionId, destinationDir + path, 0);
+    storage::updateInteractionBody(db, interactionId, acceptedFilePath);
     storage::updateInteractionStatus(db, interactionId, interaction::Status::TRANSFER_ACCEPTED);
 
     // prepare interaction Info and emit signal for the client
@@ -2221,7 +2224,7 @@ ConversationModelPimpl::acceptTransfer(const QString& convUid, uint64_t interact
         auto& interactions = conversations[conversationIdx].interactions;
         auto it = interactions.find(interactionId);
         if (it != interactions.end()) {
-            it->second.body = path;
+            it->second.body = acceptedFilePath;
             it->second.status = interaction::Status::TRANSFER_ACCEPTED;
             emitUpdated = true;
             itCopy = it->second;
diff --git a/src/datatransfermodel.cpp b/src/datatransfermodel.cpp
index 4c05ac4c..23823d41 100644
--- a/src/datatransfermodel.cpp
+++ b/src/datatransfermodel.cpp
@@ -32,6 +32,7 @@
 
 // Qt
 #include <QUuid>
+#include <QFileInfo>
 
 namespace lrc { namespace api {
 
@@ -64,6 +65,8 @@ class DataTransferModel::Impl : public QObject
 public:
     Impl(DataTransferModel& up_link);
 
+    QString getUniqueFilePath(const QString& filename);
+
     DataTransferModel& upLink;
     std::map<long long, int> dring2lrcIdMap;
     std::map<int, long long> lrc2dringIdMap; // stricly the reverse map of dring2lrcIdMap
@@ -74,10 +77,30 @@ DataTransferModel::Impl::Impl(DataTransferModel& up_link)
     , upLink {up_link}
 {}
 
+QString
+DataTransferModel::Impl::getUniqueFilePath(const QString& filename)
+{
+    if (!QFile::exists(filename)) {
+        return filename;
+    }
+    QString base(filename);
+    QString ext = QFileInfo(filename).completeSuffix();
+    if (!ext.isEmpty()) {
+        ext = ext.prepend(".");
+    }
+    base.chop(ext.size());
+    QString ret;
+    for (int suffix = 1;; suffix++) {
+        ret = QString("%1 (%2)%3").arg(base).arg(suffix).arg(ext);
+        if (!QFile::exists(ret)) {
+            return ret;
+        }
+    }
+}
+
 void
 DataTransferModel::registerTransferId(long long dringId, int interactionId)
 {
-
     pimpl_->dring2lrcIdMap.emplace(dringId, interactionId);
     pimpl_->lrc2dringIdMap.emplace(interactionId, dringId);
 }
@@ -135,13 +158,15 @@ DataTransferModel::bytesProgress(int interactionId, int64_t& total, int64_t& pro
                                                                reinterpret_cast<qlonglong&>(progress));
 }
 
-void
+QString
 DataTransferModel::accept(int interactionId,
                           const QString& file_path,
                           std::size_t offset)
 {
+    auto unique_file_path = pimpl_->getUniqueFilePath(file_path);
     auto dring_id = pimpl_->lrc2dringIdMap.at(interactionId);
-    ConfigurationManager::instance().acceptFileTransfer(dring_id, file_path, offset);
+    ConfigurationManager::instance().acceptFileTransfer(dring_id, unique_file_path, offset);
+    return unique_file_path;
 }
 
 void
-- 
GitLab