From 694ff33145467a9d8a0f87317124bc5c4251d18d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Wed, 12 Jan 2011 21:15:56 +0100
Subject: Refactored MUC code a bit.


diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index 20bf403..5ce799f 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -18,7 +18,7 @@
 #include "Swiften/Elements/DiscoInfo.h"
 #include "Swiften/JID/JID.h"
 #include "Swiften/MUC/MUC.h"
-#include "Swiften/MUC/MUCOccupant.h"
+#include "Swiften/Elements/MUCOccupant.h"
 
 namespace Swift {
 	class StanzaChannel;
diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h
index d9fb138..5784788 100644
--- a/Swiften/Client/DummyStanzaChannel.h
+++ b/Swiften/Client/DummyStanzaChannel.h
@@ -57,6 +57,9 @@ namespace Swift {
 			}
 
 			template<typename T> boost::shared_ptr<T> getStanzaAtIndex(size_t index) {
+				if (sentStanzas.size() <= index) {
+					return boost::shared_ptr<T>();
+				}
 				return boost::dynamic_pointer_cast<T>(sentStanzas[index]);
 			}
 
diff --git a/Swiften/Elements/MUCOccupant.cpp b/Swiften/Elements/MUCOccupant.cpp
new file mode 100644
index 0000000..0d3773e
--- /dev/null
+++ b/Swiften/Elements/MUCOccupant.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swiften/Elements/MUCOccupant.h"
+
+namespace Swift {
+
+MUCOccupant::MUCOccupant(const String &nick, Role role, Affiliation affiliation) : nick_(nick), role_(role), affiliation_(affiliation) {
+}
+
+MUCOccupant::~MUCOccupant() {
+}
+
+MUCOccupant::MUCOccupant(const MUCOccupant& other) : nick_(other.getNick()), role_(other.getRole()), affiliation_(other.getAffiliation()), realJID_(other.getRealJID()) {
+
+}
+
+String MUCOccupant::getNick() const {
+	return nick_;
+}
+
+MUCOccupant::Role MUCOccupant::getRole() const {
+	return role_;
+}
+
+MUCOccupant::Affiliation MUCOccupant::getAffiliation() const {
+	return affiliation_;
+}
+
+void MUCOccupant::setRealJID(const JID& realJID) {
+	realJID_ = realJID;
+}
+
+void MUCOccupant::setNick(const String& nick) {
+	nick_ = nick;
+}
+
+
+boost::optional<JID> MUCOccupant::getRealJID() const {
+	return realJID_;
+}
+
+}
diff --git a/Swiften/Elements/MUCOccupant.h b/Swiften/Elements/MUCOccupant.h
new file mode 100644
index 0000000..96ac5ad
--- /dev/null
+++ b/Swiften/Elements/MUCOccupant.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/optional.hpp>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/JID/JID.h"
+
+namespace Swift {
+	class Client;
+
+	class MUCOccupant {
+		public:
+			enum Role {Moderator, Participant, Visitor, NoRole};
+			enum Affiliation {Owner, Admin, Member, Outcast, NoAffiliation};
+
+			MUCOccupant(const String &nick, Role role, Affiliation affiliation);
+			MUCOccupant(const MUCOccupant& other);
+			~MUCOccupant();
+
+			String getNick() const;
+			Role getRole() const;
+			Affiliation getAffiliation() const;
+			boost::optional<JID> getRealJID() const;
+			void setRealJID(const JID& jid);
+			void setNick(const String& nick);
+
+		private:
+			String nick_;
+			Role role_;
+			Affiliation affiliation_;
+			boost::optional<JID> realJID_;
+			/* If you add a field, remember to update the const copy constructor */
+	};
+}
+
diff --git a/Swiften/Elements/MUCUserPayload.h b/Swiften/Elements/MUCUserPayload.h
index f55c779..2014bc4 100644
--- a/Swiften/Elements/MUCUserPayload.h
+++ b/Swiften/Elements/MUCUserPayload.h
@@ -12,7 +12,7 @@
 #include "Swiften/JID/JID.h"
 #include "Swiften/Base/String.h"
 #include "Swiften/Elements/Payload.h"
-#include "Swiften/MUC/MUCOccupant.h"
+#include "Swiften/Elements/MUCOccupant.h"
 
 namespace Swift {
 	class MUCUserPayload : public Payload {
@@ -20,7 +20,7 @@ namespace Swift {
 			typedef boost::shared_ptr<MUCUserPayload> ref;
 
 			struct Item {
-				Item() : affiliation(MUCOccupant::NoAffiliation), role(MUCOccupant::NoRole) {}
+				Item(MUCOccupant::Affiliation affiliation = MUCOccupant::NoAffiliation, MUCOccupant::Role role = MUCOccupant::NoRole) : affiliation(affiliation), role(role) {}
 				boost::optional<JID> realJID;
 				boost::optional<String> nick;
 				MUCOccupant::Affiliation affiliation;
diff --git a/Swiften/MUC/MUC.cpp b/Swiften/MUC/MUC.cpp
index 309107c..15a9a4f 100644
--- a/Swiften/MUC/MUC.cpp
+++ b/Swiften/MUC/MUC.cpp
@@ -43,6 +43,7 @@ void MUC::internalJoin(const String &nick) {
 	mucRegistry->addMUC(getJID());
 	joinComplete_ = false;
 	ownMUCJID = JID(ownMUCJID.getNode(), ownMUCJID.getDomain(), nick);
+	presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence);
 	boost::shared_ptr<Presence> joinPresence(presenceSender->getLastSentUndirectedPresence());
 	assert(joinPresence->getType() == Presence::Available);
 	joinPresence->setTo(ownMUCJID);
@@ -93,6 +94,7 @@ void MUC::handleIncomingPresence(boost::shared_ptr<Presence> presence) {
 	if (!joinComplete_) {
 		if (presence->getType() == Presence::Error) {
 			String reason;
+			presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence);
 			onJoinFailed(presence->getPayload<ErrorPayload>());
 			return;
 		}
@@ -156,15 +158,18 @@ void MUC::handleIncomingPresence(boost::shared_ptr<Presence> presence) {
 			if (status.code == 110) {
 				/* Simply knowing this is your presence is enough, 210 doesn't seem to be necessary. */
 				joinComplete_ = true;
+				presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence);
 				ownMUCJID = presence->getFrom();
-				onJoinComplete(getOwnNick());
 				presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence);
+				onJoinComplete(getOwnNick());
 			}
 			if (status.code == 201) {
 				/* Room is created and locked */
 				/* Currently deal with this by making an instant room */
+				presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence);
 				ownMUCJID = presence->getFrom();
 				boost::shared_ptr<MUCOwnerPayload> mucPayload(new MUCOwnerPayload());
+				presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence);
 				mucPayload->setPayload(boost::shared_ptr<Payload>(new Form(Form::SubmitType)));
 				GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Set, getJID(), mucPayload, iqRouter_);
 				request->onResponse.connect(boost::bind(&MUC::handleCreationConfigResponse, this, _1, _2));
@@ -177,10 +182,10 @@ void MUC::handleIncomingPresence(boost::shared_ptr<Presence> presence) {
 
 void MUC::handleCreationConfigResponse(boost::shared_ptr<MUCOwnerPayload> /*unused*/, ErrorPayload::ref error) {
 	if (error) {
+		presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence);
 		onJoinFailed(error);
 	} else {
 		onJoinComplete(getOwnNick()); /* Previously, this wasn't needed here, as the presence duplication bug caused an emit elsewhere. */
-		presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence);
 	}
 }
 
diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h
index 56cd392..44759d5 100644
--- a/Swiften/MUC/MUC.h
+++ b/Swiften/MUC/MUC.h
@@ -10,7 +10,7 @@
 #include "Swiften/Base/String.h"
 #include "Swiften/Elements/Message.h"
 #include "Swiften/Elements/Presence.h"
-#include "Swiften/MUC/MUCOccupant.h"
+#include "Swiften/Elements/MUCOccupant.h"
 #include "Swiften/MUC/MUCRegistry.h"
 #include "Swiften/Elements/MUCOwnerPayload.h"
 
diff --git a/Swiften/MUC/MUCOccupant.cpp b/Swiften/MUC/MUCOccupant.cpp
deleted file mode 100644
index 33a5fcc..0000000
--- a/Swiften/MUC/MUCOccupant.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#include "Swiften/MUC/MUCOccupant.h"
-
-namespace Swift {
-
-MUCOccupant::MUCOccupant(const String &nick, Role role, Affiliation affiliation) : nick_(nick), role_(role), affiliation_(affiliation) {
-}
-
-MUCOccupant::~MUCOccupant() {
-}
-
-MUCOccupant::MUCOccupant(const MUCOccupant& other) : nick_(other.getNick()), role_(other.getRole()), affiliation_(other.getAffiliation()), realJID_(other.getRealJID()) {
-
-}
-
-String MUCOccupant::getNick() const {
-	return nick_;
-}
-
-MUCOccupant::Role MUCOccupant::getRole() const {
-	return role_;
-}
-
-MUCOccupant::Affiliation MUCOccupant::getAffiliation() const {
-	return affiliation_;
-}
-
-void MUCOccupant::setRealJID(const JID& realJID) {
-	realJID_ = realJID;
-}
-
-void MUCOccupant::setNick(const String& nick) {
-	nick_ = nick;
-}
-
-
-boost::optional<JID> MUCOccupant::getRealJID() const {
-	return realJID_;
-}
-
-}
diff --git a/Swiften/MUC/MUCOccupant.h b/Swiften/MUC/MUCOccupant.h
deleted file mode 100644
index 96ac5ad..0000000
--- a/Swiften/MUC/MUCOccupant.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <boost/optional.hpp>
-
-#include "Swiften/Base/String.h"
-#include "Swiften/JID/JID.h"
-
-namespace Swift {
-	class Client;
-
-	class MUCOccupant {
-		public:
-			enum Role {Moderator, Participant, Visitor, NoRole};
-			enum Affiliation {Owner, Admin, Member, Outcast, NoAffiliation};
-
-			MUCOccupant(const String &nick, Role role, Affiliation affiliation);
-			MUCOccupant(const MUCOccupant& other);
-			~MUCOccupant();
-
-			String getNick() const;
-			Role getRole() const;
-			Affiliation getAffiliation() const;
-			boost::optional<JID> getRealJID() const;
-			void setRealJID(const JID& jid);
-			void setNick(const String& nick);
-
-		private:
-			String nick_;
-			Role role_;
-			Affiliation affiliation_;
-			boost::optional<JID> realJID_;
-			/* If you add a field, remember to update the const copy constructor */
-	};
-}
-
diff --git a/Swiften/MUC/UnitTest/MUCTest.cpp b/Swiften/MUC/UnitTest/MUCTest.cpp
new file mode 100644
index 0000000..1e3582b
--- /dev/null
+++ b/Swiften/MUC/UnitTest/MUCTest.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2010 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>
+#include <boost/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/bind.hpp>
+
+#include <Swiften/MUC/MUC.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Presence/StanzaChannelPresenceSender.h>
+#include <Swiften/Presence/DirectedPresenceSender.h>
+#include <Swiften/Queries/IQRouter.h>
+
+using namespace Swift;
+
+class MUCTest : public CppUnit::TestFixture {
+		CPPUNIT_TEST_SUITE(MUCTest);
+		CPPUNIT_TEST(testJoin);
+		CPPUNIT_TEST(testJoin_ChangePresenceDuringJoin);
+		/*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);
+		}
+
+		void tearDown() {
+			delete presenceSender;
+			delete stanzaChannelPresenceSender;
+			delete mucRegistry;
+			delete router;
+			delete channel;
+		}
+
+		void testJoin() {
+			MUC::ref testling = createMUC(JID("foo@bar.com"));
+			testling->joinAs("Alice");
+
+			CPPUNIT_ASSERT(mucRegistry->isMUC(JID("foo@bar.com")));
+			Presence::ref p = channel->getStanzaAtIndex<Presence>(0);
+			CPPUNIT_ASSERT(p);
+			CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/Alice"), p->getTo());
+		}
+
+		void testJoin_ChangePresenceDuringJoin() {
+			MUC::ref testling = createMUC(JID("foo@bar.com"));
+			testling->joinAs("Alice");
+
+			presenceSender->sendPresence(Presence::create("Test"));
+			CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(channel->sentStanzas.size()));
+			Presence::ref p = channel->getStanzaAtIndex<Presence>(2);
+			CPPUNIT_ASSERT(p);
+			CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/Alice"), p->getTo());
+		}
+
+		/*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");
+
+			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(joinResults.size()));
+			CPPUNIT_ASSERT_EQUAL(String("Alice"), joinResults[0].nick);
+			CPPUNIT_ASSERT(joinResults[0].error);
+		}
+
+		void testJoin_Fail() {
+			//CPPUNIT_ASSERT(!mucRegistry->isMUC(JID("foo@bar.com")));
+		}*/
+
+	private:
+		MUC::ref createMUC(const JID& jid) {
+			return boost::make_shared<MUC>(channel, router, presenceSender, jid, mucRegistry);
+		}
+
+		void handleJoinFinished(const String& nick, ErrorPayload::ref error) {
+			JoinResult r;
+			r.nick = nick;
+			r.error = error;
+			joinResults.push_back(r);
+		}
+
+		/*void receivePresence(const JID& jid, const String& status, const MUCUserPayload::Item& item) {
+			Presence::ref p = Presence::create(status);
+			p->setFrom(jid);
+			MUCUserPayload::ref mucUserPayload = boost::make_shared<MUCUserPayload>();
+			mucUserPayload->addItem(item);
+			p->addPayload(mucUserPayload);
+			channel->onPresenceReceived(p);
+		}*/
+
+	private:
+		DummyStanzaChannel* channel;
+		IQRouter* router;
+		MUCRegistry* mucRegistry;
+		StanzaChannelPresenceSender* stanzaChannelPresenceSender;
+		DirectedPresenceSender* presenceSender;
+		struct JoinResult {
+			String nick;
+			ErrorPayload::ref error;
+		};
+		std::vector<JoinResult> joinResults;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(MUCTest);
diff --git a/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp b/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp
index 5bb0e68..65417a7 100644
--- a/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp
+++ b/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp
@@ -8,7 +8,7 @@
 
 #include <boost/lexical_cast.hpp>
 
-#include "Swiften/MUC/MUCOccupant.h"
+#include "Swiften/Elements/MUCOccupant.h"
 
 #include <cassert>
 #include <iostream>
diff --git a/Swiften/SConscript b/Swiften/SConscript
index a9b6f41..8474610 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -62,10 +62,10 @@ if env["SCONS_STAGE"] == "build" :
 			"Elements/RosterPayload.cpp",
 			"Elements/Stanza.cpp",
 			"Elements/VCard.cpp",
+			"Elements/MUCOccupant.cpp",
 			"Entity/Entity.cpp",
 			"MUC/MUC.cpp",
 			"MUC/MUCManager.cpp",
-			"MUC/MUCOccupant.cpp",
 			"MUC/MUCRegistry.cpp",
 			"MUC/MUCBookmarkManager.cpp",
 			"Queries/IQChannel.cpp",
@@ -207,6 +207,7 @@ if env["SCONS_STAGE"] == "build" :
 			File("LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp"),
 			File("LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp"),
 			File("LinkLocal/UnitTest/LinkLocalServiceTest.cpp"),
+			File("MUC/UnitTest/MUCTest.cpp"),
 			File("Network/UnitTest/HostAddressTest.cpp"),
 			File("Network/UnitTest/ConnectorTest.cpp"),
 			File("Parser/PayloadParsers/UnitTest/BodyParserTest.cpp"),
-- 
cgit v0.10.2-6-g49f6