From 88607aff3c0b7df575536c988cbf9a26b407eea6 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 22 Sep 2012 20:19:19 +0200 Subject: [PATCH] Do not disconnect from room when user uses two clients and shutdown one. --- include/transport/conversation.h | 13 +++++++ src/conversation.cpp | 14 ++++--- src/networkpluginserver.cpp | 2 +- src/tests/conversationmanager.cpp | 4 +- src/tests/user.cpp | 63 +++++++++++++++++++++++++++++++ src/user.cpp | 19 ++++++++-- 6 files changed, 104 insertions(+), 11 deletions(-) diff --git a/include/transport/conversation.h b/include/transport/conversation.h index d228099f..7e477ebd 100644 --- a/include/transport/conversation.h +++ b/include/transport/conversation.h @@ -82,6 +82,18 @@ class Conversation { m_jid = jid; } + void addJID(const Swift::JID &jid) { + m_jids.push_back(jid); + } + + void removeJID(const Swift::JID &jid) { + m_jids.remove(jid); + } + + const std::list &getJIDs() { + return m_jids; + } + /// Sends message to Legacy network. /// \param message Message. @@ -123,6 +135,7 @@ class Conversation { std::string m_room; bool m_muc; Swift::JID m_jid; + std::list m_jids; }; } diff --git a/src/conversation.cpp b/src/conversation.cpp index 1578d40d..770a219e 100644 --- a/src/conversation.cpp +++ b/src/conversation.cpp @@ -115,9 +115,11 @@ void Conversation::handleMessage(boost::shared_ptr &message, con if (n.empty()) { n = " "; } - message->setTo(m_jid); - message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n)); - m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message); + BOOST_FOREACH(const Swift::JID &jid, m_jids) { + message->setTo(jid); + message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n)); + m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message); + } } } @@ -131,7 +133,6 @@ void Conversation::handleParticipantChanged(const std::string &nick, int flag, i } } presence->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname)); - presence->setTo(m_jid); presence->setType(Swift::Presence::Available); if (!statusMessage.empty()) @@ -174,7 +175,10 @@ void Conversation::handleParticipantChanged(const std::string &nick, int flag, i p->addItem(item); presence->addPayload(boost::shared_ptr(p)); - m_conversationManager->getComponent()->getStanzaChannel()->sendPresence(presence); + BOOST_FOREACH(const Swift::JID &jid, m_jids) { + presence->setTo(jid); + m_conversationManager->getComponent()->getStanzaChannel()->sendPresence(presence); + } if (!newname.empty()) { handleParticipantChanged(newname, flag, status, statusMessage); } diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 0c133a2c..04b7ff2a 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -1192,7 +1192,7 @@ void NetworkPluginServer::handleRoomJoined(User *user, const Swift::JID &who, co user->getConversationManager()->addConversation(conv); conv->onMessageToSend.connect(boost::bind(&NetworkPluginServer::handleMessageReceived, this, _1, _2)); conv->setNickname(nickname); - conv->setJID(who); + conv->addJID(who); } void NetworkPluginServer::handleRoomLeft(User *user, const std::string &r) { diff --git a/src/tests/conversationmanager.cpp b/src/tests/conversationmanager.cpp index 6fd5ad44..a9ff8011 100644 --- a/src/tests/conversationmanager.cpp +++ b/src/tests/conversationmanager.cpp @@ -158,7 +158,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe user->getConversationManager()->addConversation(conv); conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2)); conv->setNickname("nickname"); - conv->setJID("user@localhost/resource"); + conv->addJID("user@localhost/resource"); // reset resources should not touch this resource user->getConversationManager()->resetResources(); @@ -197,7 +197,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2)); conv->setNickname("nickname"); - conv->setJID("user@localhost/resource"); + conv->addJID("user@localhost/resource"); // normal presence conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message"); diff --git a/src/tests/user.cpp b/src/tests/user.cpp index 114da87b..ac92dc64 100644 --- a/src/tests/user.cpp +++ b/src/tests/user.cpp @@ -25,7 +25,9 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST(sendCurrentPresence); CPPUNIT_TEST(handlePresence); CPPUNIT_TEST(handlePresenceJoinRoom); + CPPUNIT_TEST(handlePresenceJoinRoomTwoResources); CPPUNIT_TEST(handlePresenceLeaveRoom); + CPPUNIT_TEST(handlePresenceLeaveRoomTwoResources); CPPUNIT_TEST(leaveJoinedRoom); CPPUNIT_TEST(handleDisconnected); CPPUNIT_TEST(handleDisconnectedReconnect); @@ -139,6 +141,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { // simulate that backend joined the room TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true); + conv->addJID("user@localhost/resource"); user->getConversationManager()->addConversation(conv); received.clear(); @@ -154,6 +157,24 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); } + void handlePresenceJoinRoomTwoResources() { + handlePresenceJoinRoom(); + connectSecondResource(); + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo("#room@localhost/hanzz"); + response->setFrom("user@localhost/resource2"); + + Swift::MUCPayload *payload = new Swift::MUCPayload(); + payload->setPassword("password"); + response->addPayload(boost::shared_ptr(payload)); + injectPresence(response); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(std::string(""), room); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); + } + void handlePresenceLeaveRoom() { Swift::Presence::ref response = Swift::Presence::create(); response->setTo("#room@localhost/hanzz"); @@ -173,6 +194,48 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); } + void handlePresenceLeaveRoomTwoResources() { + handlePresenceJoinRoomTwoResources(); + received.clear(); + + // User is still connected from resource2, so he should not leave the room + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo("#room@localhost/hanzz"); + response->setFrom("user@localhost/resource"); + response->setType(Swift::Presence::Unavailable); + + Swift::MUCPayload *payload = new Swift::MUCPayload(); + payload->setPassword("password"); + response->addPayload(boost::shared_ptr(payload)); + injectPresence(response); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); + + CPPUNIT_ASSERT_EQUAL(std::string(""), room); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); + + // disconnect also from resource + // User is still connected from resource2, so he should not leave the room + response = Swift::Presence::create(); + response->setTo("#room@localhost/hanzz"); + response->setFrom("user@localhost/resource2"); + response->setType(Swift::Presence::Unavailable); + + payload = new Swift::MUCPayload(); + payload->setPassword("password"); + response->addPayload(boost::shared_ptr(payload)); + injectPresence(response); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); + + CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); + } + void leaveJoinedRoom() { User *user = userManager->getUser("user@localhost"); handlePresenceJoinRoom(); diff --git a/src/user.cpp b/src/user.cpp index 242afbba..82095c5a 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -218,10 +218,17 @@ void User::handlePresence(Swift::Presence::ref presence) { if (isMUC) { if (presence->getType() == Swift::Presence::Unavailable) { std::string room = Buddy::JIDToLegacyName(presence->getTo()); + Conversation *conv = m_conversationManager->getConversation(room); + if (conv) { + conv->removeJID(presence->getFrom()); + if (!conv->getJIDs().empty()) { + return; + } + } + LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << room); onRoomLeft(room); - Conversation *conv = m_conversationManager->getConversation(room); if (conv) { m_conversationManager->removeConversation(conv); delete conv; @@ -235,8 +242,14 @@ void User::handlePresence(Swift::Presence::ref presence) { onReadyToConnect(); } std::string room = Buddy::JIDToLegacyName(presence->getTo()); - if (m_conversationManager->getConversation(room) != NULL) { - LOG4CXX_INFO(logger, m_jid.toString() << ": User has already tried to join room " << room << " as " << presence->getTo().getResource()); + Conversation *conv = m_conversationManager->getConversation(room); + if (conv != NULL) { + if (std::find(conv->getJIDs().begin(), conv->getJIDs().end(), presence->getFrom()) != conv->getJIDs().end()) { + LOG4CXX_INFO(logger, m_jid.toString() << ": User has already tried to join room " << room << " as " << presence->getTo().getResource()); + } + else { + conv->addJID(presence->getFrom()); + } return; }