From 54687078a74156c7ef4857e8df986f2ba03df9f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
 <sebastien.blin@savoirfairelinux.com>
Date: Tue, 28 Jun 2022 14:25:53 -0400
Subject: [PATCH] conversationmodel: avoid duplicated requests when receiving a
 call

Because the call and the conversation's requests are not related,
we can receive a call before the conversation's request. In this
case, a duplicate was created when accepting the call.
Moreover, accepting a call is now separated from accepting a contact,
like the android client (and accepting a conversation needs an explicit
action from the user).

Change-Id: I7c3eb34b7e121b63f1b8c99d084a5165054670d5
---
 src/app/calladapter.cpp             |  3 ---
 src/libclient/conversationmodel.cpp | 36 ++++++++++++++++-------------
 2 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/src/app/calladapter.cpp b/src/app/calladapter.cpp
index 783c5ab9b..c92a238f0 100644
--- a/src/app/calladapter.cpp
+++ b/src/app/calladapter.cpp
@@ -391,9 +391,6 @@ CallAdapter::acceptACall(const QString& accountId, const QString& convUid)
     lrcInstance_->getAccountInfo(accountId).callModel->accept(convInfo.callId);
     auto& accInfo = lrcInstance_->getAccountInfo(convInfo.accountId);
     accInfo.callModel->setCurrentCall(convInfo.callId);
-    if (convInfo.isRequest) {
-        lrcInstance_->makeConversationPermanent(convInfo.uid, accountId);
-    }
 }
 
 void
diff --git a/src/libclient/conversationmodel.cpp b/src/libclient/conversationmodel.cpp
index 879e9f5a7..96b48ce45 100644
--- a/src/libclient/conversationmodel.cpp
+++ b/src/libclient/conversationmodel.cpp
@@ -2749,18 +2749,17 @@ ConversationModelPimpl::addConversationRequest(const MapStringString& convReques
 
     auto peerUri = convRequest["from"];
     auto mode = conversation::to_mode(convRequest["mode"].toInt());
+    QString callId, confId;
     if (mode == conversation::Mode::ONE_TO_ONE) {
         try {
             // check if we have contact request for peer
             auto& conv = getConversationForPeerUri(peerUri).get();
             if (conv.mode == conversation::Mode::NON_SWARM) {
-                // update conversation and remove the invite conversation from db
-                conv.mode = mode;
-                conv.uid = convId;
+                eraseConversation(conv.uid);
                 storage::removeContactConversations(db, peerUri);
                 invalidateModel();
+                Q_EMIT linked.conversationRemoved(conv.uid);
                 Q_EMIT linked.modelChanged();
-                return;
             }
         } catch (std::out_of_range&) {
             qWarning() << "Couldn't find contact request conversation for" << peerUri;
@@ -2779,6 +2778,8 @@ ConversationModelPimpl::addConversationRequest(const MapStringString& convReques
     conversation::Info conversation;
     conversation.uid = convId;
     conversation.infos = details;
+    conversation.callId = callId;
+    conversation.confId = confId;
     conversation.accountId = linked.owner.id;
     conversation.participants = {{linked.owner.profileInfo.uri, member::Role::INVITED},
                                  {peerUri, member::Role::MEMBER}};
@@ -2788,6 +2789,10 @@ ConversationModelPimpl::addConversationRequest(const MapStringString& convReques
     invalidateModel();
     Q_EMIT linked.newConversation(convId);
     Q_EMIT linked.modelChanged();
+    if (!callId.isEmpty()) {
+        // If we replace a non swarm request by a swarm request while having a call.
+        Q_EMIT linked.selectConversation(convId);
+    }
 }
 
 void
@@ -3111,7 +3116,7 @@ ConversationModelPimpl::slotIncomingCall(const QString& fromId, const QString& c
     }
 
     auto& conversation = conversations.at(conversationIndices.at(0));
-    qDebug() << "Add call to conversation with " << fromId;
+    qDebug() << "Add call to conversation " << conversation.uid << " - " << callId;
     conversation.callId = callId;
 
     addOrUpdateCallMessage(callId, fromId, true);
@@ -3208,23 +3213,22 @@ ConversationModelPimpl::addOrUpdateCallMessage(const QString& callId,
                                                const std::time_t& duration)
 {
     // do not save call interaction for swarm conversation
-    auto convIds = storage::getConversationsWithPeer(db, from);
-    if (convIds.empty()) {
-        // in case if we receive call after removing contact add conversation request;
+    try {
+        auto& conv = getConversationForPeerUri(from).get();
+        if (conv.isSwarm())
+            return;
+    } catch (const std::exception&) {
+        // If we have no conversation with peer.
         try {
             auto contact = linked.owner.contactModel->getContact(from);
-            if (contact.profileInfo.type == profile::Type::PENDING && !contact.isBanned) {
+            if (contact.profileInfo.type == profile::Type::PENDING) {
                 addContactRequest(from);
-                convIds.push_back(storage::beginConversationWithPeer(db, contact.profileInfo.uri));
-                auto& conv = getConversationForPeerUri(contact.profileInfo.uri).get();
-                conv.uid = convIds[0];
-            } else {
-                return;
+                storage::beginConversationWithPeer(db, contact.profileInfo.uri);
             }
-        } catch (const std::out_of_range&) {
-            return;
+        } catch (const std::exception&) {
         }
     }
+
     // Get conversation
     auto conv_it = std::find_if(conversations.begin(),
                                 conversations.end(),
-- 
GitLab