diff --git a/src/jamidht/account_manager.cpp b/src/jamidht/account_manager.cpp index 66e28c374967e01ca65861c315e8310b7f045e0f..8074a284d5c1b1b7073b3dca6a3f2bc7604869d8 100644 --- a/src/jamidht/account_manager.cpp +++ b/src/jamidht/account_manager.cpp @@ -272,24 +272,26 @@ AccountManager::announceFromReceipt(const std::string& receipt) } void -AccountManager::startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dcb) +AccountManager::startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dcb, bool publishPresence) { // Put device announcement if (info_->announce) { auto h = dht::InfoHash(info_->accountId); - dht_->put( - h, - info_->announce, - [dcb = std::move(dcb), h](bool ok) { - if (ok) - JAMI_DEBUG("device announced at {}", h.toString()); - // We do not care about the status, it's a permanent put, if this fail, - // this means the DHT is disconnected but the put will be retried when connected. - if (dcb) - dcb(); - }, - {}, - true); + if (publishPresence) { + dht_->put( + h, + info_->announce, + [dcb = std::move(dcb), h](bool ok) { + if (ok) + JAMI_DEBUG("device announced at {}", h.toString()); + // We do not care about the status, it's a permanent put, if this fail, + // this means the DHT is disconnected but the put will be retried when connected. + if (dcb) + dcb(); + }, + {}, + true); + } for (const auto& crl : info_->identity.second->issuer->getRevocationLists()) dht_->put(h, crl, dht::DoneCallback {}, {}, true); dht_->listen<DeviceAnnouncement>(h, [this, cb = std::move(cb)](DeviceAnnouncement&& dev) { diff --git a/src/jamidht/account_manager.h b/src/jamidht/account_manager.h index cd8e5afcd33007c7c2d90ef696f1c223d4bcb633..9703012f43025ee1c8c9569a8685ec2ea1a8708d 100644 --- a/src/jamidht/account_manager.h +++ b/src/jamidht/account_manager.h @@ -140,7 +140,7 @@ public: void setDht(const std::shared_ptr<dht::DhtRunner>& dht) { dht_ = dht; } - virtual void startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dcb); + virtual void startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dcb, bool publishPresence = true); const AccountInfo* getInfo() const { return info_.get(); } diff --git a/src/jamidht/archive_account_manager.cpp b/src/jamidht/archive_account_manager.cpp index 0b399f99199d9800270cd7a7b9f7e8cda0d3bf85..7cf0edb0f48f596e693d4e11acc24ee5e08524e3 100644 --- a/src/jamidht/archive_account_manager.cpp +++ b/src/jamidht/archive_account_manager.cpp @@ -537,9 +537,9 @@ ArchiveAccountManager::syncDevices() } void -ArchiveAccountManager::startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dcb) +ArchiveAccountManager::startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dcb, bool publishPresence) { - AccountManager::startSync(std::move(cb), std::move(dcb)); + AccountManager::startSync(std::move(cb), std::move(dcb), publishPresence); dht_->listen<DeviceSync>( dht::InfoHash::get("inbox:" + info_->devicePk->getId().toString()), diff --git a/src/jamidht/archive_account_manager.h b/src/jamidht/archive_account_manager.h index 4437dc5e9f1434d4b79469c5ab68e2682967b7ba..55d9b30aea073424d22f9df3ebacf3d9844bc8b1 100644 --- a/src/jamidht/archive_account_manager.h +++ b/src/jamidht/archive_account_manager.h @@ -49,7 +49,7 @@ public: AuthFailureCallback onFailure, const OnChangeCallback& onChange) override; - void startSync(const OnNewDeviceCb&, const OnDeviceAnnouncedCb& dcb = {}) override; + void startSync(const OnNewDeviceCb&, const OnDeviceAnnouncedCb& dcb = {}, bool publishPresence = true) override; bool changePassword(const std::string& password_old, const std::string& password_new) override; diff --git a/src/jamidht/conversation_module.cpp b/src/jamidht/conversation_module.cpp index 40a043f6bd70eb5b44f278f7e8eb79f0424198b5..704e57a485e8c41d21ff12da37ba6b027fc6d4ff 100644 --- a/src/jamidht/conversation_module.cpp +++ b/src/jamidht/conversation_module.cpp @@ -1573,20 +1573,20 @@ ConversationModule::onTrustRequest(const std::string& uri, if (getOneToOneConversation(uri) != "") { // If there is already an active one to one conversation here, it's an active // contact and the contact will reclone this activeConv, so ignore the request - JAMI_WARN("Contact is sending a request for a non active conversation. Ignore. They will " + JAMI_WARNING("Contact is sending a request for a non active conversation. Ignore. They will " "clone the old one"); return; } if (pimpl_->isAcceptedConversation(conversationId)) { - JAMI_INFO("[Account %s] Received a request for a conversation " + JAMI_DEBUG("[Account {}] Received a request for a conversation " "already handled. Ignore", - pimpl_->accountId_.c_str()); + pimpl_->accountId_); return; } if (pimpl_->getRequest(conversationId) != std::nullopt) { - JAMI_INFO("[Account %s] Received a request for a conversation " + JAMI_DEBUG("[Account {}] Received a request for a conversation " "already existing. Ignore", - pimpl_->accountId_.c_str()); + pimpl_->accountId_); return; } ConversationRequest req; @@ -1612,26 +1612,44 @@ void ConversationModule::onConversationRequest(const std::string& from, const Json::Value& value) { ConversationRequest req(value); - JAMI_INFO("[Account %s] Receive a new conversation request for conversation %s from %s", - pimpl_->accountId_.c_str(), - req.conversationId.c_str(), - from.c_str()); + JAMI_DEBUG("[Account {}] Receive a new conversation request for conversation {} from {}", + pimpl_->accountId_, + req.conversationId, + from); auto convId = req.conversationId; req.from = from; // Already accepted request, do nothing - if (pimpl_->isAcceptedConversation(convId)) { + if (pimpl_->isAcceptedConversation(convId)) return; - } if (pimpl_->getRequest(convId) != std::nullopt) { - JAMI_INFO("[Account %s] Received a request for a conversation already existing. " + JAMI_DEBUG("[Account {}] Received a request for a conversation already existing. " "Ignore", - pimpl_->accountId_.c_str()); + pimpl_->accountId_); return; } req.received = std::time(nullptr); auto reqMap = req.toMap(); auto isOneToOne = req.isOneToOne(); + std::string oldConv; + auto acc = pimpl_->account_.lock(); + if (acc && isOneToOne) { + auto oldConv = getOneToOneConversation(from); + if (!oldConv.empty()) { + // Already a conversation with the contact. + if (oldConv != convId && acc->updateConvForContact(from, oldConv, convId)) { + initReplay(oldConv, convId); + cloneConversationFrom(convId, from, oldConv); + return; + } + // If there is already an active one to one conversation here, it's an active + // contact and the contact will reclone this activeConv, so ignore the request + JAMI_WARNING("Contact is sending a request for a non active conversation. Ignore. They will " + "clone the old one"); + return; + } + } + if (pimpl_->addConversationRequest(convId, std::move(req))) { // Note: no need to sync here because other connected devices should receive // the same conversation request. Will sync when the conversation will be added diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index 6f64e3ef026b296a408839359ca100aa0e28eda3..55efcf4dcab563a8f795efc102512d9c829cceea 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -1926,7 +1926,8 @@ JamiAccount::doRegister_() emitSignal<libjami::ConfigurationSignal::VolatileDetailsChanged>( accountID_, getVolatileAccountDetails()); } - }); + }, + publishPresence_); }; setRegistrationState(RegistrationState::TRYING); diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h index edbb3dc78daf69e9c9071036cb52ad1de3da35a9..2747ce442b72c3c3dd2894881bead1fc74a95714 100644 --- a/src/jamidht/jamiaccount.h +++ b/src/jamidht/jamiaccount.h @@ -438,6 +438,10 @@ public: { noSha3sumVerification_ = newValue; } + + void publishPresence(bool newValue) { + publishPresence_ = newValue; + } #endif /** @@ -868,6 +872,7 @@ private: std::atomic_bool deviceAnnounced_ {false}; bool noSha3sumVerification_ {false}; + bool publishPresence_ {true}; std::map<Uri::Scheme, std::unique_ptr<ChannelHandlerInterface>> channelHandlers_ {}; diff --git a/test/unitTest/conversation/conversationRequest.cpp b/test/unitTest/conversation/conversationRequest.cpp index 984f961d4fbf9933f17c035a300631ee43a34e6f..646ddfc7a32cd141893d2554b0767dc0581a4242 100644 --- a/test/unitTest/conversation/conversationRequest.cpp +++ b/test/unitTest/conversation/conversationRequest.cpp @@ -77,6 +77,7 @@ public: void testCacheRequestFromClient(); void testNeedsSyncingWithForCloning(); void testRemoveContactRemoveTrustRequest(); + void testAddConversationNoPresenceThenConnects(); std::string aliceId; std::string bobId; std::string bob2Id; @@ -107,6 +108,7 @@ private: CPPUNIT_TEST(testCacheRequestFromClient); CPPUNIT_TEST(testNeedsSyncingWithForCloning); CPPUNIT_TEST(testRemoveContactRemoveTrustRequest); + CPPUNIT_TEST(testAddConversationNoPresenceThenConnects); CPPUNIT_TEST_SUITE_END(); }; @@ -1591,6 +1593,63 @@ ConversationRequestTest::testRemoveContactRemoveTrustRequest() CPPUNIT_ASSERT(bob2Account->getTrustRequests().size() == 0); } +void +ConversationRequestTest::testAddConversationNoPresenceThenConnects() +{ + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); + auto carlaUri = carlaAccount->getUsername(); + auto aliceUri = aliceAccount->getUsername(); + aliceAccount->trackBuddyPresence(carlaUri, true); + carlaAccount->publishPresence(false); + + std::mutex mtx; + std::unique_lock<std::mutex> lk {mtx}; + std::condition_variable cv; + std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; + std::string convId = ""; + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( + [&](const std::string& accountId, const std::string& conversationId) { + if (accountId == aliceId) { + convId = conversationId; + } + cv.notify_one(); + })); + auto carlaConnected = false; + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( + [&](const std::string&, const std::map<std::string, std::string>&) { + auto details = carlaAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + carlaConnected = true; + } else if (daemonStatus == "UNREGISTERED") { + carlaConnected = false; + } + cv.notify_one(); + })); + libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(carlaUri); + cv.wait_for(lk, 5s); // Wait 5 secs for the put to happen + Manager::instance().sendRegister(carlaId, true); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaConnected; })); + carlaAccount->addContact(aliceUri); + cv.wait_for(lk, 5s); // Wait 5 secs for the put to happen + carlaAccount->publishPresence(true); + + Manager::instance().sendRegister(carlaId, false); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !carlaConnected; })); + convId.clear(); + Manager::instance().sendRegister(carlaId, true); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaConnected; })); + CPPUNIT_ASSERT( + cv.wait_for(lk, 30s, [&]() { return !convId.empty(); })); + + auto carlaDetails = carlaAccount->getContactDetails(aliceUri); + auto aliceDetails = aliceAccount->getContactDetails(carlaUri); + CPPUNIT_ASSERT(carlaDetails["conversationId"] == aliceDetails["conversationId"] && carlaDetails["conversationId"] == convId); +} + } // namespace test } // namespace jami