summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften')
-rw-r--r--Swiften/JID/JID.h8
-rw-r--r--Swiften/MUC/MUC.h4
-rw-r--r--Swiften/MUC/MUCImpl.cpp41
-rw-r--r--Swiften/MUC/MUCImpl.h6
-rw-r--r--Swiften/MUC/UnitTest/MUCTest.cpp74
-rw-r--r--Swiften/MUC/UnitTest/MockMUC.h1
6 files changed, 122 insertions, 12 deletions
diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h
index 126a7b1..aefd3df 100644
--- a/Swiften/JID/JID.h
+++ b/Swiften/JID/JID.h
@@ -131,12 +131,20 @@ namespace Swift {
JID result(*this);
result.hasResource_ = false;
result.resource_ = "";
return result;
}
+ /**
+ * Get the full JID with the supplied resource.
+ */
+ JID withResource(const std::string& resource) const {
+ JID result(this->getNode(), this->getDomain(), resource);
+ return result;
+ }
+
std::string toString() const;
bool equals(const JID& o, CompareType compareType) const {
return compare(o, compareType) == 0;
}
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,8 +1,8 @@
/*
- * 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.
*/
#pragma once
@@ -52,12 +52,13 @@ namespace Swift {
virtual void joinAs(const std::string &nick) = 0;
virtual void joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since) = 0;
/*virtual void queryRoomInfo(); */
/*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 */
virtual void handleUserLeft(LeavingType) = 0;
/** Get occupant information*/
virtual const MUCOccupant& getOccupant(const std::string& nick) = 0;
@@ -84,12 +85,13 @@ namespace Swift {
boost::signal<void (ErrorPayload::ref)> onConfigurationFailed;
boost::signal<void (ErrorPayload::ref)> onAffiliationListFailed;
boost::signal<void (Presence::ref)> onOccupantPresenceChange;
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;
boost::signal<void ()> onUnlocked;
/* boost::signal<void (const MUCInfo&)> onInfoResult; */
/* boost::signal<void (const blah&)> onItemsResult; */
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,8 +1,8 @@
/*
- * 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.
*/
#include <Swiften/MUC/MUCImpl.h>
@@ -87,12 +87,18 @@ void MUCImpl::internalJoin(const std::string &nick) {
}
joinPresence->addPayload(mucPayload);
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());
}
void MUCImpl::handleUserLeft(LeavingType type) {
@@ -151,12 +157,13 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) {
//100 is non-anonymous
//TODO: 100 may also be specified in a <message/>
//170 is room logging to http
//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;
}
else foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) {
if (status.code == 307) {
@@ -165,26 +172,42 @@ void MUCImpl::handleIncomingPresence(Presence::ref presence) {
else if (status.code == 301) {
type = LeaveBan;
}
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, "");
+ }
}
}
}
else if (presence->getType() == Presence::Available) {
std::map<std::string, MUCOccupant>::iterator it = occupants.find(nick);
MUCOccupant occupant(nick, role, affiliation);
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
@@ -55,12 +55,18 @@ namespace Swift {
virtual void joinAs(const std::string &nick);
virtual void joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since);
/*virtual void queryRoomInfo(); */
/*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 */
virtual void handleUserLeft(LeavingType);
/** Get occupant information*/
virtual const MUCOccupant& getOccupant(const std::string& nick);
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,8 +1,8 @@
/*
- * 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.
*/
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
@@ -27,23 +27,25 @@ class MUCTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(MUCTest);
CPPUNIT_TEST(testJoin);
CPPUNIT_TEST(testJoin_ChangePresenceDuringJoinDoesNotSendPresenceBeforeJoinSuccess);
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();
public:
void setUp() {
channel = new DummyStanzaChannel();
router = new IQRouter(channel);
mucRegistry = new MUCRegistry();
stanzaChannelPresenceSender = new StanzaChannelPresenceSender(channel);
presenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender);
+ nickChanges = 0;
}
void tearDown() {
delete presenceSender;
delete stanzaChannelPresenceSender;
delete mucRegistry;
@@ -138,12 +140,73 @@ class MUCTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(iq);
CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>());
CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()->getForm());
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));
testling->joinAs("Alice");
receivePresence(JID("foo@bar.com/Rabbit"), "Here");
@@ -155,13 +218,15 @@ class MUCTest : public CppUnit::TestFixture {
void testJoin_Fail() {
//CPPUNIT_ASSERT(!mucRegistry->isMUC(JID("foo@bar.com")));
}*/
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) {
JoinResult r;
r.nick = nick;
r.error = error;
@@ -174,20 +239,25 @@ class MUCTest : public CppUnit::TestFixture {
//MUCUserPayload::ref mucUserPayload = boost::make_shared<MUCUserPayload>();
//mucUserPayload->addItem(item);
//p->addPayload(mucUserPayload);
channel->onPresenceReceived(p);
}
+ void handleOccupantNicknameChanged(const std::string&, const std::string&) {
+ nickChanges++;
+ }
+
private:
DummyStanzaChannel* channel;
IQRouter* router;
MUCRegistry* mucRegistry;
StanzaChannelPresenceSender* stanzaChannelPresenceSender;
DirectedPresenceSender* presenceSender;
struct JoinResult {
std::string nick;
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
@@ -55,12 +55,13 @@ namespace Swift {
virtual void joinAs(const std::string&) {}
virtual void joinWithContextSince(const std::string&, const boost::posix_time::ptime&) {}
/*virtual void queryRoomInfo(); */
/*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 */
virtual void handleUserLeft(LeavingType) {}
/** Get occupant information*/
virtual const MUCOccupant& getOccupant(const std::string&);