From b70c0fe57150eb5efc0f80ce947fe065d3350913 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
 <sebastien.blin@savoirfairelinux.com>
Date: Thu, 9 Jun 2022 11:23:43 -0400
Subject: [PATCH] conversationmodel: avoid any potential infinite loop

if we have no new messages while loading, we shiould detect it.

https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/738

Change-Id: Ibfb4965cf9742253cd3d272009f7a0422fb04ac9
---
 src/libclient/conversationmodel.cpp | 41 ++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 13 deletions(-)

diff --git a/src/libclient/conversationmodel.cpp b/src/libclient/conversationmodel.cpp
index 06245505b..8feba93df 100644
--- a/src/libclient/conversationmodel.cpp
+++ b/src/libclient/conversationmodel.cpp
@@ -760,7 +760,8 @@ ConversationModel::selectConversation(const QString& uid) const
                 case call::Status::CONNECTING:
                 case call::Status::SEARCHING:
                     // We are currently in a call
-                    Q_EMIT pimpl_->behaviorController.showIncomingCallView(owner.id, conversation.uid);
+                    Q_EMIT pimpl_->behaviorController.showIncomingCallView(owner.id,
+                                                                           conversation.uid);
                     break;
                 case call::Status::PAUSED:
                 case call::Status::CONNECTED:
@@ -769,7 +770,8 @@ ConversationModel::selectConversation(const QString& uid) const
                     Q_EMIT pimpl_->behaviorController.showCallView(owner.id, conversation.uid);
                     break;
                 case call::Status::PEER_BUSY:
-                    Q_EMIT pimpl_->behaviorController.showLeaveMessageView(owner.id, conversation.uid);
+                    Q_EMIT pimpl_->behaviorController.showLeaveMessageView(owner.id,
+                                                                           conversation.uid);
                     break;
                 case call::Status::TIMEOUT:
                 case call::Status::TERMINATING:
@@ -2242,8 +2244,11 @@ ConversationModelPimpl::slotConversationLoaded(uint32_t requestId,
 
     try {
         auto& conversation = getConversationForUid(conversationId).get();
+        QString oldLast; // Used to detect loading loops just in case.
+        if (conversation.interactions->size() != 0)
+            oldLast = conversation.interactions->rbegin()->first;
         for (const auto& message : messages) {
-            if (message["type"].isEmpty() || message["type"] == "application/update-profile") {
+            if (message["type"].isEmpty()) {
                 continue;
             }
             auto msgId = message["id"];
@@ -2300,6 +2305,13 @@ ConversationModelPimpl::slotConversationLoaded(uint32_t requestId,
         }
         if (conversation.lastMessageUid.isEmpty() && !conversation.allMessagesLoaded
             && messages.size() != 0) {
+            QString newLast = conversation.interactions->rbegin()->first;
+            if (newLast == oldLast && !newLast.isEmpty()) { // [[unlikely]] in c++20
+                qCritical() << "Loading loop detected for " << conversationId << "(" << newLast
+                            << ")";
+                return;
+            }
+
             // In this case, we only have loaded merge commits. Load more messages
             ConfigurationManager::instance().loadConversationMessages(linked.owner.id,
                                                                       conversationId,
@@ -2405,9 +2417,9 @@ ConversationModelPimpl::slotMessageReceived(const QString& accountId,
         invalidateModel();
         if (!interaction::isOutgoing(msg)) {
             Q_EMIT behaviorController.newUnreadInteraction(linked.owner.id,
-                                                         conversationId,
-                                                         msgId,
-                                                         msg);
+                                                           conversationId,
+                                                           msgId,
+                                                           msg);
         }
         Q_EMIT linked.newInteraction(conversationId, msgId, msg);
         Q_EMIT linked.modelChanged();
@@ -3467,9 +3479,9 @@ ConversationModelPimpl::slotUpdateInteractionStatus(const QString& accountId,
         }
         if (updateDisplayedUid) {
             Q_EMIT linked.displayedInteractionChanged(conversation.uid,
-                                                    peerId,
-                                                    oldDisplayedUid,
-                                                    msgId);
+                                                      peerId,
+                                                      oldDisplayedUid,
+                                                      msgId);
         }
         if (emitUpdated) {
             invalidateModel();
@@ -3496,7 +3508,10 @@ ConversationModelPimpl::slotUpdateInteractionStatus(const QString& accountId,
                                                                          peerId);
                     Q_EMIT linked.dataChanged(indexOf(conversationId));
                 }
-                Q_EMIT linked.displayedInteractionChanged(conversationId, peerId, previous, messageId);
+                Q_EMIT linked.displayedInteractionChanged(conversationId,
+                                                          peerId,
+                                                          previous,
+                                                          messageId);
             }
         }
     } catch (const std::out_of_range& e) {
@@ -3798,9 +3813,9 @@ ConversationModelPimpl::slotTransferStatusCreated(const QString& fileId, datatra
         conversations[conversationIdx].unreadMessages = getNumberOfUnreadMessagesFor(convId);
     }
     Q_EMIT behaviorController.newUnreadInteraction(linked.owner.id,
-                                                 convId,
-                                                 interactionId,
-                                                 interaction);
+                                                   convId,
+                                                   interactionId,
+                                                   interaction);
     Q_EMIT linked.newInteraction(convId, interactionId, interaction);
 
     invalidateModel();
-- 
GitLab