diff --git a/include/transport/Conversation.h b/include/transport/Conversation.h index 9c268139..ec8fa2c6 100644 --- a/include/transport/Conversation.h +++ b/include/transport/Conversation.h @@ -151,6 +151,8 @@ class Conversation { void sendCachedMessages(const Swift::JID &to = Swift::JID()); + void setMUCEscaping(bool mucEscaping); + private: Swift::Presence::ref generatePresence(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname = ""); void cacheMessage(boost::shared_ptr &message); @@ -165,6 +167,7 @@ class Conversation { std::list m_jids; bool m_sentInitialPresence; bool m_nicknameChanged; + bool m_mucEscaping; // TODO: Move this to some extra class to cache the most used // rooms across different accounts. Just now if we have 10 users diff --git a/libtransport/Conversation.cpp b/libtransport/Conversation.cpp index 08c57be6..bda7f39b 100644 --- a/libtransport/Conversation.cpp +++ b/libtransport/Conversation.cpp @@ -45,6 +45,7 @@ Conversation::Conversation(ConversationManager *conversationManager, const std:: m_jid = m_conversationManager->getUser()->getJID().toBare(); m_sentInitialPresence = false; m_nicknameChanged = false; + m_mucEscaping = false; if (CONFIG_BOOL_DEFAULTED(conversationManager->getComponent()->getConfig(), "features.rawxml", false)) { m_sentInitialPresence = true; @@ -54,11 +55,16 @@ Conversation::Conversation(ConversationManager *conversationManager, const std:: Conversation::~Conversation() { } +void Conversation::setMUCEscaping(bool mucEscaping) { + LOG4CXX_INFO(logger, m_jid.toString() << ": Setting MUC escaping to " << mucEscaping); + m_mucEscaping = mucEscaping; +} + void Conversation::destroyRoom() { if (m_muc) { Swift::Presence::ref presence = Swift::Presence::create(); std::string legacyName = m_legacyName; - if (legacyName.find_last_of("@") != std::string::npos) { + if (!m_mucEscaping && legacyName.find_last_of("@") != std::string::npos) { legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK } legacyName = Swift::JID::getEscapedNode(legacyName); @@ -180,7 +186,7 @@ void Conversation::handleMessage(boost::shared_ptr &message, con } else { std::string legacyName = m_room; - if (legacyName.find_last_of("@") != std::string::npos) { + if (!m_mucEscaping && legacyName.find_last_of("@") != std::string::npos) { legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK } legacyName = Swift::JID::getEscapedNode(legacyName); @@ -190,7 +196,7 @@ void Conversation::handleMessage(boost::shared_ptr &message, con } else { std::string legacyName = m_legacyName; - if (legacyName.find_last_of("@") != std::string::npos) { + if (!m_mucEscaping && legacyName.find_last_of("@") != std::string::npos) { legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK } legacyName = Swift::JID::getEscapedNode(legacyName); @@ -251,7 +257,7 @@ Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int Swift::Presence::ref presence = Swift::Presence::create(); std::string legacyName = m_legacyName; if (m_muc) { - if (legacyName.find_last_of("@") != std::string::npos) { + if (!m_mucEscaping && legacyName.find_last_of("@") != std::string::npos) { legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK } legacyName = Swift::JID::getEscapedNode(legacyName); diff --git a/libtransport/User.cpp b/libtransport/User.cpp index dee06fe4..e8dbacfa 100644 --- a/libtransport/User.cpp +++ b/libtransport/User.cpp @@ -292,6 +292,10 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { conv->setNickname(presence->getTo().getResource()); conv->addJID(presence->getFrom()); + if (presence->getTo().toString().find("\\40") != std::string::npos) { + conv->setMUCEscaping(true); + } + onRawPresenceReceived(presence); onRoomJoined(presence->getFrom(), room, presence->getTo().getResource(), password); diff --git a/tests/libtransport/conversationmanager.cpp b/tests/libtransport/conversationmanager.cpp index 3f860f44..2f711094 100644 --- a/tests/libtransport/conversationmanager.cpp +++ b/tests/libtransport/conversationmanager.cpp @@ -26,6 +26,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_TEST(handleSubjectMessages); CPPUNIT_TEST(handleParticipantChanged); CPPUNIT_TEST(handleParticipantChangedEscaped); + CPPUNIT_TEST(handleParticipantChangedEscaped2); CPPUNIT_TEST(handleParticipantChangedTwoResources); CPPUNIT_TEST(handlePMFromXMPP); CPPUNIT_TEST(handleGroupchatRemoved); @@ -571,6 +572,29 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Participant, *getStanza(received[0])->getPayload()->getItems()[0].role); } + void handleParticipantChangedEscaped2() { + User *user = userManager->getUser("user@localhost"); + TestingConversation *conv = new TestingConversation(user->getConversationManager(), "19:70027094a9c84c518535a610766bed65@thread.skype", true); + conv->setMUCEscaping(true); + + conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2)); + conv->setNickname("nickname"); + conv->addJID("user@localhost/resource"); + + // normal presence + conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message"); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[0]))->getShow()); + CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[0]))->getTo().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("19\\3a70027094a9c84c518535a610766bed65\\40thread.skype@localhost/anotheruser"), dynamic_cast(getStanza(received[0]))->getFrom().toString()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Member, *getStanza(received[0])->getPayload()->getItems()[0].affiliation); + CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Participant, *getStanza(received[0])->getPayload()->getItems()[0].role); + } + void handleParticipantChangedTwoResources() { connectSecondResource(); received2.clear();