From 8159071adb232b68c2ce79479145fbcd04979245 Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Wed, 5 Oct 2011 12:11:29 +0100
Subject: Don't crash with label item without a label


diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index 4bcb4c7..ecb9288 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -78,12 +78,9 @@ void ChatControllerBase::setOnline(bool online) {
 
 void ChatControllerBase::setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info) {
 	if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::SecurityLabelsCatalogFeature)) {
-		//chatWindow_->setSecurityLabelsEnabled(true);
-		//chatWindow_->setSecurityLabelsError();
 		GetSecurityLabelsCatalogRequest::ref request = GetSecurityLabelsCatalogRequest::create(JID(toJID_.toBare()), iqRouter_);
 		request->onResponse.connect(boost::bind(&ChatControllerBase::handleSecurityLabelsCatalogResponse, this, _1, _2));
 		request->send();
-		//labelsEnabled_ = true;
 	} else {
 		chatWindow_->setSecurityLabelsEnabled(false);
 		labelsEnabled_ = false;
@@ -114,7 +111,10 @@ void ChatControllerBase::handleSendMessageRequest(const std::string &body, bool
 	message->setType(Swift::Message::Chat);
 	message->setBody(body);
 	if (labelsEnabled_) {
-		message->addPayload(chatWindow_->getSelectedSecurityLabel().getLabel());
+		SecurityLabelsCatalog::Item labelItem = chatWindow_->getSelectedSecurityLabel();
+		if (labelItem.getLabel()) {
+			message->addPayload(labelItem.getLabel());
+		}
 	}
 	preSendMessageRequest(message);
 	if (useDelayForLatency_) {
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index 16ad999..d4fbcfd 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -37,12 +37,15 @@ class MUCControllerTest : public CppUnit::TestFixture {
 	CPPUNIT_TEST(testAddressedToSelf);
 	CPPUNIT_TEST(testNotAddressedToSelf);
 	CPPUNIT_TEST(testAddressedToSelfBySelf);
+	CPPUNIT_TEST(testMessageWithEmptyLabelItem);
+	CPPUNIT_TEST(testMessageWithLabelItem);
 	CPPUNIT_TEST_SUITE_END();
 
 public:
 	void setUp() {
 		self_ = JID("girl@wonderland.lit/rabbithole");
 		nick_ = "aLiCe";
+		mucJID_ = JID("teaparty@rooms.wonderland.lit");
 		mocks_ = new MockRepository();
 		stanzaChannel_ = new DummyStanzaChannel();
 		iqChannel_ = new DummyIQChannel();
@@ -55,10 +58,10 @@ public:
 		uiEventStream_ = new UIEventStream();
 		avatarManager_ = new NullAvatarManager();
 		TimerFactory* timerFactory = NULL;
-		window_ = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+		window_ = new MockChatWindow();
 		mucRegistry_ = new MUCRegistry();
 		entityCapsProvider_ = new DummyEntityCapsProvider();
-		muc_ = MUC::ref(new MUC(stanzaChannel_, iqRouter_, directedPresenceSender_, JID("teaparty@rooms.wonderland.lit"), mucRegistry_));
+		muc_ = boost::make_shared<MUC>(stanzaChannel_, iqRouter_, directedPresenceSender_, mucJID_, mucRegistry_);
 		mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_);
 		controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_);
 	};
@@ -156,6 +159,57 @@ public:
 		CPPUNIT_ASSERT_EQUAL((size_t)0, eventController_->getEvents().size());
 	}
 
+	void testMessageWithEmptyLabelItem() {
+		SecurityLabelsCatalog::Item label;
+		label.setSelector("Bob");
+		window_->label_ = label;
+		boost::shared_ptr<DiscoInfo> features = boost::make_shared<DiscoInfo>();
+		features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
+		controller_->setAvailableServerFeatures(features);
+		IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
+		SecurityLabelsCatalog::ref labelPayload = boost::make_shared<SecurityLabelsCatalog>();
+		labelPayload->addItem(label);
+		IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
+		iqChannel_->onIQReceived(result);
+		std::string messageBody("agamemnon");
+		window_->onSendMessageRequest(messageBody, false);
+		boost::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+		Message::ref message = boost::dynamic_pointer_cast<Message>(rawStanza);
+		CPPUNIT_ASSERT_EQUAL(iq->getTo(), result->getFrom());
+		CPPUNIT_ASSERT(window_->labelsEnabled_);
+		CPPUNIT_ASSERT(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
+		CPPUNIT_ASSERT(message);
+		CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody());
+		CPPUNIT_ASSERT(!message->getPayload<SecurityLabel>());
+	}
+
+	void testMessageWithLabelItem() {
+		SecurityLabel::ref label = boost::make_shared<SecurityLabel>();
+		label->setLabel("a");
+		SecurityLabelsCatalog::Item labelItem;
+		labelItem.setSelector("Bob");
+		labelItem.setLabel(label);
+		window_->label_ = labelItem;
+		boost::shared_ptr<DiscoInfo> features = boost::make_shared<DiscoInfo>();
+		features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
+		controller_->setAvailableServerFeatures(features);
+		IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
+		SecurityLabelsCatalog::ref labelPayload = boost::make_shared<SecurityLabelsCatalog>();
+		labelPayload->addItem(labelItem);
+		IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
+		iqChannel_->onIQReceived(result);
+		std::string messageBody("agamemnon");
+		window_->onSendMessageRequest(messageBody, false);
+		boost::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+		Message::ref message = boost::dynamic_pointer_cast<Message>(rawStanza);
+		CPPUNIT_ASSERT_EQUAL(iq->getTo(), result->getFrom());
+		CPPUNIT_ASSERT(window_->labelsEnabled_);
+		CPPUNIT_ASSERT(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
+		CPPUNIT_ASSERT(message);
+		CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody());
+		CPPUNIT_ASSERT_EQUAL(label, message->getPayload<SecurityLabel>());
+	}
+
 	void checkEqual(const std::vector<NickJoinPart>& expected, const std::vector<NickJoinPart>& actual) {
 		CPPUNIT_ASSERT_EQUAL(expected.size(), actual.size());
 		for (size_t i = 0; i < expected.size(); i++) {
@@ -226,10 +280,11 @@ public:
 
 private:
 	JID self_;
+	JID mucJID_;
 	MUC::ref muc_;
 	std::string nick_;
-	StanzaChannel* stanzaChannel_;
-	IQChannel* iqChannel_;
+	DummyStanzaChannel* stanzaChannel_;
+	DummyIQChannel* iqChannel_;
 	IQRouter* iqRouter_;
 	EventController* eventController_;
 	ChatWindowFactory* chatWindowFactory_;
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 58e8698..7b90a57 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -34,7 +34,7 @@ namespace Swift {
 			virtual void setUnreadMessageCount(int /*count*/) {};
 			virtual void convertToMUC() {};
 			virtual void setSecurityLabelsError() {};
-			virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() {return SecurityLabelsCatalog::Item();};
+			virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() {return label_;}
 			virtual void setInputEnabled(bool /*enabled*/) {};
 			virtual void setRosterModel(Roster* /*roster*/) {};
 			virtual void setTabComplete(TabComplete*) {};
@@ -50,14 +50,11 @@ namespace Swift {
 			virtual void showRoomConfigurationForm(Form::ref) {}
 			virtual void addMUCInvitation(const JID& /*jid*/, const std::string& /*reason*/, const std::string& /*password*/) {};
 
-			boost::signal<void ()> onClosed;
-			boost::signal<void ()> onAllMessagesRead;
-			boost::signal<void (const std::string&, bool isCorrection)> onSendMessageRequest;
-
 			std::string name_;
 			std::string lastMessageBody_;
 			std::vector<SecurityLabelsCatalog::Item> labels_;
 			bool labelsEnabled_;
+			SecurityLabelsCatalog::Item label_;
 	};
 }
 
diff --git a/Swiften/Elements/SecurityLabel.h b/Swiften/Elements/SecurityLabel.h
index 0487977..a1714c8 100644
--- a/Swiften/Elements/SecurityLabel.h
+++ b/Swiften/Elements/SecurityLabel.h
@@ -14,6 +14,7 @@
 namespace Swift {
 	class SecurityLabel : public Payload {
 		public:
+			typedef boost::shared_ptr<SecurityLabel> ref;
 			SecurityLabel() {}
 
 			const std::string& getDisplayMarking() const { return displayMarking_; }
diff --git a/Swiften/Elements/SecurityLabelsCatalog.h b/Swiften/Elements/SecurityLabelsCatalog.h
index 0f40c13..b9419a9 100644
--- a/Swiften/Elements/SecurityLabelsCatalog.h
+++ b/Swiften/Elements/SecurityLabelsCatalog.h
@@ -17,6 +17,7 @@
 namespace Swift {
 	class SecurityLabelsCatalog : public Payload {
 		public:
+			typedef boost::shared_ptr<SecurityLabelsCatalog> ref;
 			class Item {
 				public:
 					Item() : default_(false) {}
diff --git a/Swiften/EventLoop/EventLoop.cpp b/Swiften/EventLoop/EventLoop.cpp
index 2b8f00d..afb6858 100644
--- a/Swiften/EventLoop/EventLoop.cpp
+++ b/Swiften/EventLoop/EventLoop.cpp
@@ -24,6 +24,9 @@ inline void invokeCallback(const Event& event) {
 	catch (const std::exception& e) {
 		std::cerr << "Uncaught exception in event loop: " << e.what() << std::endl;
 	}
+	catch (...) {
+		std::cerr << "Uncaught non-exception in event loop" << std::endl;	
+	}
 }
 
 EventLoop::EventLoop() : nextEventID_(0), handlingEvents_(false) {
-- 
cgit v0.10.2-6-g49f6