From b16c6f96d7fc5aa9c5da46fe95f9173fc7f89bfe Mon Sep 17 00:00:00 2001
From: Adrien Beraud <adrien.beraud@savoirfairelinux.com>
Date: Fri, 21 Mar 2025 10:47:45 -0400
Subject: [PATCH] contacts: allow to retrieve Contact object

Change-Id: I9c095d814c4707448ecab56c494dcc683a537414
---
 src/jamidht/account_manager.cpp     | 39 ++++++++++++++------
 src/jamidht/account_manager.h       |  1 +
 src/jamidht/contact_list.cpp        | 11 ++++++
 src/jamidht/contact_list.h          |  2 +
 src/jamidht/conversation_module.cpp | 16 +++-----
 src/jamidht/jamiaccount.cpp         | 57 ++++++++++++++++-------------
 src/jamidht/jamiaccount.h           |  1 +
 7 files changed, 78 insertions(+), 49 deletions(-)

diff --git a/src/jamidht/account_manager.cpp b/src/jamidht/account_manager.cpp
index 60b5bb87d6..bc65a28447 100644
--- a/src/jamidht/account_manager.cpp
+++ b/src/jamidht/account_manager.cpp
@@ -345,19 +345,19 @@ AccountManager::startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dc
                             return;
                         auto conversationId = v.conversationId;
                         // Check if there was an old active conversation.
-                        auto details = info_->contacts->getContactDetails(peer_account);
-                        auto oldConvIt = details.find(libjami::Account::TrustRequest::CONVERSATIONID);
-                        if (oldConvIt != details.end() && oldConvIt->second != "") {
-                            if (conversationId == oldConvIt->second) {
-                                // Here, it's possible that we already have accepted the conversation
-                                // but contact were offline and sync failed.
-                                // So, retrigger the callback so upper layer will clone conversation if needed
-                                // instead of getting stuck in sync.
-                                info_->contacts->acceptConversation(conversationId, v.owner->getLongId().toString());
-                                return;
+                        if (auto details = info_->contacts->getContactInfo(peer_account)) {
+                            if (!details->conversationId.empty()) {
+                                if (details->conversationId == conversationId) {
+                                    // Here, it's possible that we already have accepted the conversation
+                                    // but contact were offline and sync failed.
+                                    // So, retrigger the callback so upper layer will clone conversation if needed
+                                    // instead of getting stuck in sync.
+                                    info_->contacts->acceptConversation(conversationId, v.owner->getLongId().toString());
+                                    return;
+                                }
+                                conversationId = details->conversationId;
+                                JAMI_WARNING("Accept with old convId: {}", conversationId);
                             }
-                            conversationId = oldConvIt->second;
-                            JAMI_WARNING("Accept with old convId: {}", conversationId);
                         }
                         sendTrustRequestConfirm(peer_account, conversationId);
                     }
@@ -588,6 +588,21 @@ AccountManager::getContactDetails(const std::string& uri) const
     return info_->contacts->getContactDetails(h);
 }
 
+std::optional<Contact>
+AccountManager::getContactInfo(const std::string& uri) const
+{
+    if (!info_) {
+        JAMI_ERROR("[Account {}] getContactInfo(): account not loaded", accountId_);
+        return {};
+    }
+    dht::InfoHash h(uri);
+    if (not h) {
+        JAMI_ERROR("[Account {}] getContactInfo: invalid contact URI", accountId_);
+        return {};
+    }
+    return info_->contacts->getContactInfo(h);
+}
+
 bool
 AccountManager::findCertificate(
     const dht::InfoHash& h,
diff --git a/src/jamidht/account_manager.h b/src/jamidht/account_manager.h
index a3b12b4c3b..631e585ac1 100644
--- a/src/jamidht/account_manager.h
+++ b/src/jamidht/account_manager.h
@@ -248,6 +248,7 @@ public:
 
     /** Obtain details about one account contact in serializable form. */
     std::map<std::string, std::string> getContactDetails(const std::string& uri) const;
+    std::optional<Contact> getContactInfo(const std::string& uri) const;
 
     virtual bool findCertificate(
         const dht::InfoHash& h,
diff --git a/src/jamidht/contact_list.cpp b/src/jamidht/contact_list.cpp
index ac7916bf0c..1bd16213d7 100644
--- a/src/jamidht/contact_list.cpp
+++ b/src/jamidht/contact_list.cpp
@@ -172,6 +172,17 @@ ContactList::getContactDetails(const dht::InfoHash& h) const
     return details;
 }
 
+std::optional<Contact>
+ContactList::getContactInfo(const dht::InfoHash& h) const
+{
+    const auto c = contacts_.find(h);
+    if (c == std::end(contacts_)) {
+        JAMI_WARNING("[Account {}] [Contacts] Contact '{}' not found", accountId_, h.to_view());
+        return {};
+    }
+    return c->second;
+}
+
 const std::map<dht::InfoHash, Contact>&
 ContactList::getContacts() const
 {
diff --git a/src/jamidht/contact_list.h b/src/jamidht/contact_list.h
index 3084bee687..753f265139 100644
--- a/src/jamidht/contact_list.h
+++ b/src/jamidht/contact_list.h
@@ -66,6 +66,8 @@ public:
 
     /* Contacts */
     std::map<std::string, std::string> getContactDetails(const dht::InfoHash&) const;
+    std::optional<Contact> getContactInfo(const dht::InfoHash&) const;
+
     bool removeContact(const dht::InfoHash&, bool ban);
     bool removeContactConversation(const dht::InfoHash&);
     bool addContact(const dht::InfoHash&,
diff --git a/src/jamidht/conversation_module.cpp b/src/jamidht/conversation_module.cpp
index 7d1f4b26c8..bab65b47d8 100644
--- a/src/jamidht/conversation_module.cpp
+++ b/src/jamidht/conversation_module.cpp
@@ -900,22 +900,16 @@ ConversationModule::Impl::getRequest(const std::string& id) const
 std::string
 ConversationModule::Impl::getOneToOneConversation(const std::string& uri) const noexcept
 {
-    auto details = accountManager_->getContactDetails(uri);
-    auto itRemoved = details.find("removed");
-    // If contact is removed there is no conversation
-    if (itRemoved != details.end() && itRemoved->second != "0") {
-        auto itBanned = details.find("banned");
+    if (auto details = accountManager_->getContactInfo(uri)) {
+        // If contact is removed there is no conversation
         // If banned, conversation is still on disk
-        if (itBanned == details.end() || itBanned->second == "0") {
+        if (details->removed != 0 && details->banned == 0) {
             // Check if contact is removed
-            auto itAdded = details.find("added");
-            if (std::stoi(itRemoved->second) > std::stoi(itAdded->second))
+            if (details->removed > details->added)
                 return {};
         }
+        return details->conversationId;
     }
-    auto it = details.find(libjami::Account::TrustRequest::CONVERSATIONID);
-    if (it != details.end())
-        return it->second;
     return {};
 }
 
diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp
index bb2c6f0527..6c1798ce74 100644
--- a/src/jamidht/jamiaccount.cpp
+++ b/src/jamidht/jamiaccount.cpp
@@ -1815,33 +1815,31 @@ JamiAccount::onTrackedBuddyOnline(const dht::InfoHash& contactId)
                                                                   "");
     }
 
-    auto details = getContactDetails(id);
-    auto it = details.find("confirmed");
-    if (it == details.end() or it->second == "false") {
-        auto convId = convModule()->getOneToOneConversation(id);
-        if (convId.empty())
-            return;
-        // In this case, the TrustRequest was sent but never confirmed (cause the contact was
-        // offline maybe) To avoid the contact to never receive the conv request, retry there
-        std::lock_guard lock(configurationMutex_);
-        if (accountManager_) {
-            // Retrieve cached payload for trust request.
-            auto requestPath = cachePath_ / "requests" / id;
-            std::vector<uint8_t> payload;
-            try {
-                payload = fileutils::loadFile(requestPath);
-            } catch (...) {
-            }
-
-            if (payload.size() >= 64000) {
-                JAMI_WARNING(
-                    "[Account {:s}] Trust request for contact {:s} is too big, reset payload",
-                    getAccountID(),
-                    id);
-                payload.clear();
+    if (auto details = getContactInfo(id)) {
+        if (!details->confirmed) {
+            auto convId = convModule()->getOneToOneConversation(id);
+            if (convId.empty())
+                return;
+            // In this case, the TrustRequest was sent but never confirmed (cause the contact was
+            // offline maybe) To avoid the contact to never receive the conv request, retry there
+            std::lock_guard lock(configurationMutex_);
+            if (accountManager_) {
+                // Retrieve cached payload for trust request.
+                auto requestPath = cachePath_ / "requests" / id;
+                std::vector<uint8_t> payload;
+                try {
+                    payload = fileutils::loadFile(requestPath);
+                } catch (...) {
+                }
+                if (payload.size() >= 64000) {
+                    JAMI_WARNING(
+                        "[Account {:s}] Trust request for contact {:s} is too big, reset payload",
+                        getAccountID(),
+                        id);
+                    payload.clear();
+                }
+                accountManager_->sendTrustRequest(id, convId, payload);
             }
-
-            accountManager_->sendTrustRequest(id, convId, payload);
         }
     }
 }
@@ -2914,6 +2912,13 @@ JamiAccount::getContactDetails(const std::string& uri) const
                            : std::map<std::string, std::string> {};
 }
 
+std::optional<Contact>
+JamiAccount::getContactInfo(const std::string& uri) const
+{
+    std::lock_guard lock(configurationMutex_);
+    return accountManager_ ? accountManager_->getContactInfo(uri) : std::nullopt;
+}
+
 std::vector<std::map<std::string, std::string>>
 JamiAccount::getContacts(bool includeRemoved) const
 {
diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h
index d0049f6add..1e5fd5b9a4 100644
--- a/src/jamidht/jamiaccount.h
+++ b/src/jamidht/jamiaccount.h
@@ -305,6 +305,7 @@ public:
     /// Obtain details about one account contact in serializable form.
     ///
     std::map<std::string, std::string> getContactDetails(const std::string& uri) const;
+    std::optional<Contact> getContactInfo(const std::string& uri) const;
 
     void sendTrustRequest(const std::string& to, const std::vector<uint8_t>& payload);
     void sendMessage(const std::string& to,
-- 
GitLab