summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/ChatsManager.cpp38
-rw-r--r--Swift/Controllers/ChatsManager.h4
-rw-r--r--Swift/Controllers/UnitTest/ChatsManagerTest.cpp141
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h3
4 files changed, 166 insertions, 20 deletions
diff --git a/Swift/Controllers/ChatsManager.cpp b/Swift/Controllers/ChatsManager.cpp
index ef187f4..fe8efb3 100644
--- a/Swift/Controllers/ChatsManager.cpp
+++ b/Swift/Controllers/ChatsManager.cpp
@@ -1,5 +1,7 @@
#include "Swift/Controllers/ChatsManager.h"
+#include <boost/bind.hpp>
+
#include "Swiften/Client/Client.h"
#include "Swift/Controllers/ChatController.h"
@@ -23,6 +25,7 @@ ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRo
avatarManager_ = NULL;
serverDiscoInfo_ = serverDiscoInfo;
presenceSender_ = presenceSender;
+ presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1, _2));
}
ChatsManager::~ChatsManager() {
@@ -35,6 +38,20 @@ ChatsManager::~ChatsManager() {
}
+/**
+ * If a resource goes offline, release bound chatdialog to that resource.
+ */
+void ChatsManager::handlePresenceChange(boost::shared_ptr<Presence> /*oldPresence*/, boost::shared_ptr<Presence> newPresence) {
+ if (newPresence->getType() != Presence::Unavailable) return;
+ JID fullJID(newPresence->getFrom());
+ std::map<JID, ChatController*>::iterator it = chatControllers_.find(fullJID);
+ if (it == chatControllers_.end()) return;
+ JID bareJID(fullJID.toBare());
+ //It doesn't make sense to have two unbound dialogs.
+ if (chatControllers_.find(bareJID) != chatControllers_.end()) return;
+ rebindControllerJID(fullJID, bareJID);
+}
+
void ChatsManager::setAvatarManager(AvatarManager* avatarManager) {
avatarManager_ = avatarManager;
}
@@ -83,19 +100,20 @@ void ChatsManager::handleChatRequest(const String &contact) {
}
ChatController* ChatsManager::getChatController(const JID &contact) {
- JID lookupContact(contact);
- if (chatControllers_.find(lookupContact) == chatControllers_.end()) {
- lookupContact = JID(contact.toBare());
- }
- if (chatControllers_.find(lookupContact) == chatControllers_.end()) {
- chatControllers_[contact] = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_);
- chatControllers_[contact]->setAvailableServerFeatures(serverDiscoInfo_);
- lookupContact = contact;
+ if (chatControllers_.find(contact) == chatControllers_.end()) {
+ //Need to look for an unboud window to bind first
+ JID bare(contact.toBare());
+ if (chatControllers_.find(bare) != chatControllers_.end()) {
+ rebindControllerJID(bare, contact);
+ } else {
+ chatControllers_[contact] = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_);
+ chatControllers_[contact]->setAvailableServerFeatures(serverDiscoInfo_);
+ }
}
- return chatControllers_[lookupContact];
+ return chatControllers_[contact];
}
-void ChatsManager::handleChatControllerJIDChanged(const JID& from, const JID& to) {
+void ChatsManager::rebindControllerJID(const JID& from, const JID& to) {
chatControllers_[to] = chatControllers_[from];
chatControllers_.erase(from);
}
diff --git a/Swift/Controllers/ChatsManager.h b/Swift/Controllers/ChatsManager.h
index e897e59..260bd1d 100644
--- a/Swift/Controllers/ChatsManager.h
+++ b/Swift/Controllers/ChatsManager.h
@@ -7,6 +7,7 @@
#include "Swiften/Base/String.h"
#include "Swiften/Elements/DiscoInfo.h"
#include "Swiften/Elements/Message.h"
+#include "Swiften/Elements/Presence.h"
#include "Swiften/JID/JID.h"
#include "Swiften/MUC/MUCRegistry.h"
@@ -33,7 +34,8 @@ namespace Swift {
void handleChatRequest(const String& contact);
void handleJoinMUCRequest(const JID& muc, const String& nick);
private:
- void handleChatControllerJIDChanged(const JID& from, const JID& to);
+ void rebindControllerJID(const JID& from, const JID& to);
+ void handlePresenceChange(boost::shared_ptr<Presence> oldPresence, boost::shared_ptr<Presence> newPresence);
ChatController* getChatController(const JID &contact);
virtual bool isMUC(const JID& muc) const;
diff --git a/Swift/Controllers/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/UnitTest/ChatsManagerTest.cpp
index 071cd5b..9df244f 100644
--- a/Swift/Controllers/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/UnitTest/ChatsManagerTest.cpp
@@ -27,9 +27,12 @@ class ChatsManagerTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(ChatsManagerTest);
CPPUNIT_TEST(testFirstOpenWindowIncoming);
+ CPPUNIT_TEST(testSecondOpenWindowIncoming);
CPPUNIT_TEST(testFirstOpenWindowOutgoing);
CPPUNIT_TEST(testFirstOpenWindowBareToFull);
CPPUNIT_TEST(testSecondWindow);
+ CPPUNIT_TEST(testUnbindRebind);
+ CPPUNIT_TEST(testNoDuplicateUnbind);
CPPUNIT_TEST_SUITE_END();
public:
@@ -70,13 +73,41 @@ public:
void testFirstOpenWindowIncoming() {
JID messageJID("testling@test.com/resource1");
- ChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID).Return(window);
boost::shared_ptr<Message> message(new Message());
message->setFrom(messageJID);
- message->setBody("This is a legible message.");
+ String body("This is a legible message. >HEH@)oeueu");
+ message->setBody(body);
manager_->handleIncomingMessage(message);
+ CPPUNIT_ASSERT_EQUAL(body, window->lastMessageBody_);
+ }
+
+ void testSecondOpenWindowIncoming() {
+ JID messageJID1("testling@test.com/resource1");
+
+ MockChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1).Return(window1);
+
+ boost::shared_ptr<Message> message1(new Message());
+ message1->setFrom(messageJID1);
+ String body1("This is a legible message. >HEH@)oeueu");
+ message1->setBody(body1);
+ manager_->handleIncomingMessage(message1);
+ CPPUNIT_ASSERT_EQUAL(body1, window1->lastMessageBody_);
+
+ JID messageJID2("testling@test.com/resource2");
+
+ MockChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2).Return(window2);
+
+ boost::shared_ptr<Message> message2(new Message());
+ message2->setFrom(messageJID2);
+ String body2("This is a legible message. .cmaulm.chul");
+ message2->setBody(body2);
+ manager_->handleIncomingMessage(message2);
+ CPPUNIT_ASSERT_EQUAL(body2, window2->lastMessageBody_);
}
void testFirstOpenWindowOutgoing() {
@@ -99,28 +130,122 @@ public:
boost::shared_ptr<Message> message(new Message());
message->setFrom(JID(fullJIDString));
- message->setBody("This is a legible message.");
+ String body("This is a legible message. mjuga3089gm8G(*>M)@*(");
+ message->setBody(body);
manager_->handleIncomingMessage(message);
- /*FIXME: check the message got through. For now, checking that there isn't a new window created is useful enough.*/
- //CPPUNIT_ASSERT_EQUAL(fullJIDString, window->name_);
+ CPPUNIT_ASSERT_EQUAL(body, window->lastMessageBody_);
}
void testSecondWindow() {
String messageJIDString1("testling1@test.com");
-
ChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1)).Return(window1);
-
manager_->handleChatRequest(messageJIDString1);
String messageJIDString2("testling2@test.com");
-
ChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2)).Return(window2);
manager_->handleChatRequest(messageJIDString2);
}
+ /** Complete cycle.
+ Create unbound window.
+ Bind it.
+ Unbind it.
+ Rebind it.
+ */
+ void testUnbindRebind() {
+ String bareJIDString("testling@test.com");
+ String fullJIDString1("testling@test.com/resource1");
+ String fullJIDString2("testling@test.com/resource2");
+
+ MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString)).Return(window);
+ manager_->handleChatRequest(bareJIDString);
+
+ boost::shared_ptr<Message> message1(new Message());
+ message1->setFrom(JID(fullJIDString1));
+ String messageBody1("This is a legible message.");
+ message1->setBody(messageBody1);
+ manager_->handleIncomingMessage(message1);
+ CPPUNIT_ASSERT_EQUAL(messageBody1, window->lastMessageBody_);
+
+ boost::shared_ptr<Presence> jid1Online(new Presence());
+ jid1Online->setFrom(JID(fullJIDString1));
+ boost::shared_ptr<Presence> jid1Offline(new Presence());
+ jid1Offline->setFrom(JID(fullJIDString1));
+ jid1Offline->setType(Presence::Unavailable);
+ presenceOracle_->onPresenceChange(jid1Online, jid1Offline);
+
+ boost::shared_ptr<Message> message2(new Message());
+ message2->setFrom(JID(fullJIDString2));
+ String messageBody2("This is another legible message.");
+ message2->setBody(messageBody2);
+ manager_->handleIncomingMessage(message2);
+ CPPUNIT_ASSERT_EQUAL(messageBody2, window->lastMessageBody_);
+ }
+
+ /**
+ Test that a second window isn't unbound where there's already an unbound one.
+ Bind 1
+ Bind 2
+ Unbind 1
+ Unbind 2 (but it doesn't)
+ Sent to bound 2
+ Rebind 1
+ */
+ void testNoDuplicateUnbind() {
+ JID messageJID1("testling@test.com/resource1");
+
+ MockChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1).Return(window1);
+
+ boost::shared_ptr<Message> message1(new Message());
+ message1->setFrom(messageJID1);
+ message1->setBody("This is a legible message1.");
+ manager_->handleIncomingMessage(message1);
+
+ JID messageJID2("testling@test.com/resource2");
+
+ MockChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2).Return(window2);
+
+ boost::shared_ptr<Message> message2(new Message());
+ message2->setFrom(messageJID2);
+ message2->setBody("This is a legible message2.");
+ manager_->handleIncomingMessage(message2);
+
+ boost::shared_ptr<Presence> jid1Online(new Presence());
+ jid1Online->setFrom(JID(messageJID1));
+ boost::shared_ptr<Presence> jid1Offline(new Presence());
+ jid1Offline->setFrom(JID(messageJID1));
+ jid1Offline->setType(Presence::Unavailable);
+ presenceOracle_->onPresenceChange(jid1Online, jid1Offline);
+
+ boost::shared_ptr<Presence> jid2Online(new Presence());
+ jid2Online->setFrom(JID(messageJID2));
+ boost::shared_ptr<Presence> jid2Offline(new Presence());
+ jid2Offline->setFrom(JID(messageJID2));
+ jid2Offline->setType(Presence::Unavailable);
+ presenceOracle_->onPresenceChange(jid2Online, jid2Offline);
+
+ JID messageJID3("testling@test.com/resource3");
+
+ boost::shared_ptr<Message> message3(new Message());
+ message3->setFrom(messageJID3);
+ String body3("This is a legible message3.");
+ message3->setBody(body3);
+ manager_->handleIncomingMessage(message3);
+ CPPUNIT_ASSERT_EQUAL(body3, window1->lastMessageBody_);
+
+ boost::shared_ptr<Message> message2b(new Message());
+ message2b->setFrom(messageJID2);
+ String body2b("This is a legible message2b.");
+ message2b->setBody(body2b);
+ manager_->handleIncomingMessage(message2b);
+ CPPUNIT_ASSERT_EQUAL(body2b, window2->lastMessageBody_);
+ }
private:
JID jid_;
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 015bb9b..2625553 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -8,7 +8,7 @@ namespace Swift {
MockChatWindow() {};
virtual ~MockChatWindow();
- virtual void addMessage(const String& /*message*/, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional<SecurityLabel>& /*label*/, const String& /*avatarPath*/) {};
+ virtual void addMessage(const String& message, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional<SecurityLabel>& /*label*/, const String& /*avatarPath*/) {lastMessageBody_ = message;};
virtual void addSystemMessage(const String& /*message*/) {};
virtual void addErrorMessage(const String& /*message*/) {};
@@ -29,6 +29,7 @@ namespace Swift {
boost::signal<void (const String&)> onSendMessageRequest;
String name_;
+ String lastMessageBody_;
std::vector<SecurityLabel> labels_;
bool labelsEnabled_;
};