From 60074cfedd4a10dbdec43c9c0bbc62d5a75279c5 Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Mon, 30 Nov 2015 14:53:53 +0100
Subject: Do not consult presence oracle for MUC PM presence

Test-Information:

Added unit test verifying the behavior.
Verified with multiple Swift instances in a MUC room that for
MUC PMs only the same full JID presence counts.

Change-Id: I08148221be34c3548f18da634586c828fd60feff

diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 503a050..e2751f7 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -466,10 +466,22 @@ std::string ChatController::getStatusChangeString(boost::shared_ptr<Presence> pr
 void ChatController::handlePresenceChange(boost::shared_ptr<Presence> newPresence) {
 	bool relevantPresence = false;
 
-	if (toJID_.equals(newPresence->getFrom(), JID::WithoutResource)) {
-		// Presence matches ChatController JID.
-		newPresence = presenceOracle_->getAccountPresence(toJID_);
-		relevantPresence = true;
+	if (isInMUC_) {
+		// For MUC participants we only have a single presence to choose one and
+		// even for multi-session nicknames multiple resources are not distinguishable
+		// to other participants.
+		if (toJID_.equals(newPresence->getFrom(), JID::WithResource)) {
+			relevantPresence = true;
+		}
+	}
+	else {
+		// For standard chats we retrieve the account presence from the PresenceOracle,
+		// as there can be multiple presences to choose from.
+		if (toJID_.equals(newPresence->getFrom(), JID::WithoutResource)) {
+			// Presence matches ChatController JID.
+			newPresence = presenceOracle_->getAccountPresence(toJID_);
+			relevantPresence = true;
+		}
 	}
 
 	if (!relevantPresence) {
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index 281783e..5f89f62 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -73,6 +73,7 @@ class ChatsManagerTest : public CppUnit::TestFixture {
 	CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToFrom);
 	CPPUNIT_TEST(testChatControllerFullJIDBindingOnMessageAndNotReceipt);
 	CPPUNIT_TEST(testChatControllerFullJIDBindingOnTypingAndNotActive);
+	CPPUNIT_TEST(testChatControllerPMPresenceHandling);
 	CPPUNIT_TEST_SUITE_END();
 	
 public:
@@ -642,6 +643,36 @@ public:
 		CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex<Message>(3)->getPayload<DeliveryReceiptRequest>());
 	}
 
+	void testChatControllerPMPresenceHandling() {
+		JID participantA = JID("test@rooms.test.com/participantA");
+		JID participantB = JID("test@rooms.test.com/participantB");
+
+		mucRegistry_->addMUC("test@rooms.test.com");
+
+		MockChatWindow* window = new MockChatWindow();
+		mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(participantA, uiEventStream_).Return(window);
+
+		uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(JID(participantA))));
+
+		Presence::ref presence = Presence::create();
+		presence->setFrom(participantA);
+		presence->setShow(StatusShow::Online);
+		stanzaChannel_->onPresenceReceived(presence);
+		CPPUNIT_ASSERT_EQUAL(std::string("participantA has become available."), MockChatWindow::bodyFromMessage(window->lastAddedPresence_));
+
+		presence = Presence::create();
+		presence->setFrom(participantB);
+		presence->setShow(StatusShow::Away);
+		stanzaChannel_->onPresenceReceived(presence);
+
+		presence = Presence::create();
+		presence->setFrom(participantA);
+		presence->setShow(StatusShow::None);
+		presence->setType(Presence::Unavailable);
+		stanzaChannel_->onPresenceReceived(presence);
+		CPPUNIT_ASSERT_EQUAL(std::string("participantA has gone offline."), MockChatWindow::bodyFromMessage(window->lastReplacedMessage_));
+	}
+
 	void testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::Subscription from, RosterItemPayload::Subscription to) {
 		JID messageJID("testling@test.com/resource1");
 		xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), from);
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index c906bfd..ddb7e3e 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -29,12 +29,16 @@ namespace Swift {
 				return "id";
 			}
 
-			virtual void addPresenceMessage(const ChatMessage& /*message*/, Direction /*direction*/) {}
+			virtual void addPresenceMessage(const ChatMessage& message, Direction /*direction*/) {
+				lastAddedPresence_ = message;
+			}
 
 			virtual void addErrorMessage(const ChatMessage& /*message*/) {}
 			virtual void replaceMessage(const ChatMessage& /*message*/, const std::string& /*id*/, const boost::posix_time::ptime& /*time*/, const HighlightAction& /*highlight*/) {}
 			virtual void replaceWithAction(const ChatMessage& /*message*/, const std::string& /*id*/, const boost::posix_time::ptime& /*time*/, const HighlightAction& /*highlight*/) {}
-			virtual void replaceLastMessage(const ChatMessage& /*message*/, const TimestampBehaviour /*timestampBehaviour*/) {}
+			virtual void replaceLastMessage(const ChatMessage& message, const TimestampBehaviour /*timestampBehaviour*/) {
+				lastReplacedMessage_ = message;
+			}
 			virtual void replaceSystemMessage(const ChatMessage& /*message*/, const std::string& /*id*/, const TimestampBehaviour /*timestampBehaviour*/) {}
 
 			// File transfer related stuff
@@ -82,7 +86,7 @@ namespace Swift {
 			virtual void showBookmarkWindow(const MUCBookmark& /*bookmark*/) {}
 			virtual void setBookmarkState(RoomBookmarkState) {}
 
-			std::string bodyFromMessage(const ChatMessage& message) {
+			static std::string bodyFromMessage(const ChatMessage& message) {
 				boost::shared_ptr<ChatTextMessagePart> text;
 				foreach (boost::shared_ptr<ChatMessagePart> part, message.getParts()) {
 					if ((text = boost::dynamic_pointer_cast<ChatTextMessagePart>(part))) {
@@ -94,6 +98,8 @@ namespace Swift {
 
 			std::string name_;
 			std::string lastMessageBody_;
+			ChatMessage lastAddedPresence_;
+			ChatMessage lastReplacedMessage_;
 			std::vector<SecurityLabelsCatalog::Item> labels_;
 			bool labelsEnabled_;
 			SecurityLabelsCatalog::Item label_;
-- 
cgit v0.10.2-6-g49f6