diff options
Diffstat (limited to 'Swiften/MUC')
-rw-r--r-- | Swiften/MUC/MUC.h | 4 | ||||
-rw-r--r-- | Swiften/MUC/MUCImpl.cpp | 41 | ||||
-rw-r--r-- | Swiften/MUC/MUCImpl.h | 6 | ||||
-rw-r--r-- | Swiften/MUC/UnitTest/MUCTest.cpp | 74 | ||||
-rw-r--r-- | Swiften/MUC/UnitTest/MockMUC.h | 1 |
5 files changed, 114 insertions, 12 deletions
diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h index 0dcccd9..8815489 100644 --- a/Swiften/MUC/MUC.h +++ b/Swiften/MUC/MUC.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -55,6 +55,7 @@ namespace Swift { /*virtual void queryRoomItems(); */ /*virtual std::string getCurrentNick() = 0; */ virtual std::map<std::string, MUCOccupant> getOccupants() const = 0; + virtual void changeNickname(const std::string& newNickname) = 0; virtual void part() = 0; /*virtual void handleIncomingMessage(Message::ref message) = 0; */ /** Expose public so it can be called when e.g. user goes offline */ @@ -87,6 +88,7 @@ namespace Swift { boost::signal<void (const std::string&, const MUCOccupant& /*now*/, const MUCOccupant::Role& /*old*/)> onOccupantRoleChanged; boost::signal<void (const std::string&, const MUCOccupant::Affiliation& /*new*/, const MUCOccupant::Affiliation& /*old*/)> onOccupantAffiliationChanged; boost::signal<void (const MUCOccupant&)> onOccupantJoined; + boost::signal<void (const std::string& /*oldNickname*/, const std::string& /*newNickname*/ )> onOccupantNicknameChanged; boost::signal<void (const MUCOccupant&, LeavingType, const std::string& /*reason*/)> onOccupantLeft; boost::signal<void (Form::ref)> onConfigurationFormReceived; boost::signal<void (MUCOccupant::Affiliation, const std::vector<JID>&)> onAffiliationListReceived; diff --git a/Swiften/MUC/MUCImpl.cpp b/Swiften/MUC/MUCImpl.cpp index a1854e3..ab5faf4 100644 --- a/Swiften/MUC/MUCImpl.cpp +++ b/Swiften/MUC/MUCImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -90,6 +90,12 @@ void MUCImpl::internalJoin(const std::string &nick) { presenceSender->sendPresence(joinPresence); } +void MUCImpl::changeNickname(const std::string& newNickname) { + Presence::ref changeNicknamePresence = boost::make_shared<Presence>(); + changeNicknamePresence->setTo(ownMUCJID.toBare().toString() + std::string("/") + newNickname); + presenceSender->sendPresence(changeNicknamePresence); +} + void MUCImpl::part() { presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); mucRegistry->removeMUC(getJID()); @@ -154,6 +160,7 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) { //TODO: Nick changes if (presence->getType() == Presence::Unavailable) { LeavingType type = LeavePart; + boost::optional<std::string> newNickname; if (mucPayload) { if (boost::dynamic_pointer_cast<MUCDestroyPayload>(mucPayload->getPayload())) { type = LeaveDestroy; @@ -168,20 +175,36 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) { else if (status.code == 321) { type = LeaveNotMember; } + else if (status.code == 303) { + if (mucPayload->getItems().size() == 1) { + newNickname = mucPayload->getItems()[0].nick; + } + } } } - - if (presence->getFrom() == ownMUCJID) { - handleUserLeft(type); - return; - } - else { + if (newNickname) { std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick); if (i != occupants.end()) { - //TODO: part type MUCOccupant occupant = i->second; occupants.erase(i); - onOccupantLeft(occupant, type, ""); + occupant.setNick(newNickname.get()); + occupants.insert(std::make_pair(newNickname.get(), occupant)); + onOccupantNicknameChanged(nick, newNickname.get()); + } + } + else { + if (presence->getFrom() == ownMUCJID) { + handleUserLeft(type); + return; + } + else { + std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick); + if (i != occupants.end()) { + //TODO: part type + MUCOccupant occupant = i->second; + occupants.erase(i); + onOccupantLeft(occupant, type, ""); + } } } } diff --git a/Swiften/MUC/MUCImpl.h b/Swiften/MUC/MUCImpl.h index 846ddcf..8eabb80 100644 --- a/Swiften/MUC/MUCImpl.h +++ b/Swiften/MUC/MUCImpl.h @@ -58,6 +58,12 @@ namespace Swift { /*virtual void queryRoomItems(); */ /*virtual std::string getCurrentNick(); */ virtual std::map<std::string, MUCOccupant> getOccupants() const; + + /** + * Send a new presence to the MUC indicating a nickname change. Any custom status the user had in the is cleared. + * @param newNickname The nickname to change to. + */ + virtual void changeNickname(const std::string& newNickname); virtual void part(); /*virtual void handleIncomingMessage(Message::ref message); */ /** Expose public so it can be called when e.g. user goes offline */ diff --git a/Swiften/MUC/UnitTest/MUCTest.cpp b/Swiften/MUC/UnitTest/MUCTest.cpp index d1a21b0..773edb6 100644 --- a/Swiften/MUC/UnitTest/MUCTest.cpp +++ b/Swiften/MUC/UnitTest/MUCTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -30,6 +30,7 @@ class MUCTest : public CppUnit::TestFixture { CPPUNIT_TEST(testJoin_ChangePresenceDuringJoinResendsPresenceAfterJoinSuccess); CPPUNIT_TEST(testCreateInstant); CPPUNIT_TEST(testReplicateBug); + CPPUNIT_TEST(testNicknameChange); /*CPPUNIT_TEST(testJoin_Success); CPPUNIT_TEST(testJoin_Fail);*/ CPPUNIT_TEST_SUITE_END(); @@ -41,6 +42,7 @@ class MUCTest : public CppUnit::TestFixture { mucRegistry = new MUCRegistry(); stanzaChannelPresenceSender = new StanzaChannelPresenceSender(channel); presenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender); + nickChanges = 0; } void tearDown() { @@ -141,6 +143,67 @@ class MUCTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Form::SubmitType, iq->getPayload<MUCOwnerPayload>()->getForm()->getType()); } + void testNicknameChange() { + MUC::ref testling = createMUC(JID("foo@bar.com")); + // Join as Rabbit + testling->joinAs("Rabbit"); + + // Rabbit joins + Presence::ref rabbitJoins = boost::make_shared<Presence>(); + rabbitJoins->setTo("test@swift.im/6913d576d55f0b67"); + rabbitJoins->setFrom(testling->getJID().toString() + "/Rabbit"); + channel->onPresenceReceived(rabbitJoins); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Rabbit")); + + // Alice joins + Presence::ref aliceJoins = boost::make_shared<Presence>(); + aliceJoins->setTo("test@swift.im/6913d576d55f0b67"); + aliceJoins->setFrom(testling->getJID().toString() + "/Alice"); + channel->onPresenceReceived(aliceJoins); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Alice")); + + // Change nick to Dodo + testling->changeNickname("Dodo"); + Presence::ref stanza = channel->getStanzaAtIndex<Presence>(1); + CPPUNIT_ASSERT(stanza); + CPPUNIT_ASSERT_EQUAL(std::string("Dodo"), stanza->getTo().getResource()); + + // Alice changes nick to Alice2 + stanza = boost::make_shared<Presence>(); + stanza->setFrom(JID("foo@bar.com/Alice")); + stanza->setTo(JID(router->getJID())); + stanza->setType(Presence::Unavailable); + MUCUserPayload::ref mucPayload(new MUCUserPayload()); + MUCItem myItem; + myItem.affiliation = MUCOccupant::Member; + myItem.nick = "Alice2"; + myItem.role = MUCOccupant::Participant; + mucPayload->addItem(myItem); + mucPayload->addStatusCode(303); + stanza->addPayload(mucPayload); + channel->onPresenceReceived(stanza); + CPPUNIT_ASSERT_EQUAL(1, nickChanges); + CPPUNIT_ASSERT_EQUAL(false, testling->hasOccupant("Alice")); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Alice2")); + + // We (Rabbit) change nick to Robot + stanza = boost::make_shared<Presence>(); + stanza->setFrom(JID("foo@bar.com/Rabbit")); + stanza->setTo(JID(router->getJID())); + stanza->setType(Presence::Unavailable); + mucPayload = MUCUserPayload::ref(new MUCUserPayload()); + myItem.affiliation = MUCOccupant::Member; + myItem.nick = "Robot"; + myItem.role = MUCOccupant::Participant; + mucPayload->addItem(myItem); + mucPayload->addStatusCode(303); + stanza->addPayload(mucPayload); + channel->onPresenceReceived(stanza); + CPPUNIT_ASSERT_EQUAL(2, nickChanges); + CPPUNIT_ASSERT_EQUAL(false, testling->hasOccupant("Rabbit")); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Robot")); + } + /*void testJoin_Success() { MUC::ref testling = createMUC(JID("foo@bar.com")); testling->onJoinFinished.connect(boost::bind(&MUCTest::handleJoinFinished, this, _1, _2)); @@ -158,7 +221,9 @@ class MUCTest : public CppUnit::TestFixture { private: MUC::ref createMUC(const JID& jid) { - return boost::make_shared<MUCImpl>(channel, router, presenceSender, jid, mucRegistry); + MUC::ref muc = boost::make_shared<MUCImpl>(channel, router, presenceSender, jid, mucRegistry); + muc->onOccupantNicknameChanged.connect(boost::bind(&MUCTest::handleOccupantNicknameChanged, this, _1, _2)); + return muc; } void handleJoinFinished(const std::string& nick, ErrorPayload::ref error) { @@ -177,6 +242,10 @@ class MUCTest : public CppUnit::TestFixture { channel->onPresenceReceived(p); } + void handleOccupantNicknameChanged(const std::string&, const std::string&) { + nickChanges++; + } + private: DummyStanzaChannel* channel; IQRouter* router; @@ -188,6 +257,7 @@ class MUCTest : public CppUnit::TestFixture { ErrorPayload::ref error; }; std::vector<JoinResult> joinResults; + int nickChanges; }; CPPUNIT_TEST_SUITE_REGISTRATION(MUCTest); diff --git a/Swiften/MUC/UnitTest/MockMUC.h b/Swiften/MUC/UnitTest/MockMUC.h index 78c2fb5..8673a90 100644 --- a/Swiften/MUC/UnitTest/MockMUC.h +++ b/Swiften/MUC/UnitTest/MockMUC.h @@ -58,6 +58,7 @@ namespace Swift { /*virtual void queryRoomItems(); */ /*virtual std::string getCurrentNick() = 0; */ virtual std::map<std::string, MUCOccupant> getOccupants() const { return occupants_; } + virtual void changeNickname(const std::string&) { } virtual void part() {} /*virtual void handleIncomingMessage(Message::ref message) = 0; */ /** Expose public so it can be called when e.g. user goes offline */ |