summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften')
-rw-r--r--Swiften/Chat/ChatStateMessageSender.cpp28
-rw-r--r--Swiften/Chat/ChatStateMessageSender.h26
-rw-r--r--Swiften/Chat/ChatStateNotifier.cpp61
-rw-r--r--Swiften/Chat/ChatStateNotifier.h26
-rw-r--r--Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp135
-rw-r--r--Swiften/Disco/DummyEntityCapsProvider.h29
-rw-r--r--Swiften/Disco/EntityCapsManager.h8
-rw-r--r--Swiften/Disco/EntityCapsProvider.cpp14
-rw-r--r--Swiften/Disco/EntityCapsProvider.h33
-rw-r--r--Swiften/Disco/SConscript1
-rw-r--r--Swiften/SConscript1
11 files changed, 218 insertions, 144 deletions
diff --git a/Swiften/Chat/ChatStateMessageSender.cpp b/Swiften/Chat/ChatStateMessageSender.cpp
deleted file mode 100644
index e150d29..0000000
--- a/Swiften/Chat/ChatStateMessageSender.cpp
+++ /dev/null
@@ -1,28 +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/Chat/ChatStateMessageSender.h"
-
-#include <boost/bind.hpp>
-
-#include "Swiften/Client/StanzaChannel.h"
-
-namespace Swift {
-
-ChatStateMessageSender::ChatStateMessageSender(ChatStateNotifier* notifier, StanzaChannel* stanzaChannel, const JID& contact) : contact_(contact) {
- notifier_ = notifier;
- stanzaChannel_ = stanzaChannel;
- notifier_->onChatStateChanged.connect(boost::bind(&ChatStateMessageSender::handleChatStateChanged, this, _1));
-}
-
-void ChatStateMessageSender::handleChatStateChanged(ChatState::ChatStateType state) {
- boost::shared_ptr<Message> message(new Message());
- message->setTo(contact_);
- message->addPayload(boost::shared_ptr<Payload>(new ChatState(state)));
- stanzaChannel_->sendMessage(message);
-}
-
-}
diff --git a/Swiften/Chat/ChatStateMessageSender.h b/Swiften/Chat/ChatStateMessageSender.h
deleted file mode 100644
index d6ce40d..0000000
--- a/Swiften/Chat/ChatStateMessageSender.h
+++ /dev/null
@@ -1,26 +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 "Swiften/Chat/ChatStateNotifier.h"
-#include "Swiften/Elements/ChatState.h"
-#include "Swiften/JID/JID.h"
-
-namespace Swift {
- class StanzaChannel;
- class ChatStateMessageSender {
- public:
- ChatStateMessageSender(ChatStateNotifier* notifier, StanzaChannel* stanzaChannel, const JID& contact);
- void setContact(const JID& contact) {contact_ = contact;};
-
- private:
- void handleChatStateChanged(ChatState::ChatStateType state);
- ChatStateNotifier* notifier_;
- StanzaChannel* stanzaChannel_;
- JID contact_;
- };
-}
diff --git a/Swiften/Chat/ChatStateNotifier.cpp b/Swiften/Chat/ChatStateNotifier.cpp
index 1aee9cf..cb7fa9a 100644
--- a/Swiften/Chat/ChatStateNotifier.cpp
+++ b/Swiften/Chat/ChatStateNotifier.cpp
@@ -6,32 +6,41 @@
#include "Swiften/Chat/ChatStateNotifier.h"
-namespace Swift {
+#include <boost/bind.hpp>
-ChatStateNotifier::ChatStateNotifier() {
- contactJIDHasChanged();
-}
+#include "Swiften/Elements/Message.h"
+#include "Swiften/Elements/ChatState.h"
+#include "Swiften/Client/StanzaChannel.h"
+#include "Swiften/Disco/EntityCapsProvider.h"
-void ChatStateNotifier::setContactHas85Caps(bool hasCaps) {
- contactHas85Caps_ = hasCaps;
+namespace Swift {
+
+ChatStateNotifier::ChatStateNotifier(StanzaChannel* stanzaChannel, const JID& contact, EntityCapsProvider* entityCapsManager) : stanzaChannel_(stanzaChannel), entityCapsManager_(entityCapsManager), contact_(contact) {
+ setContact(contact);
+ entityCapsManager_->onCapsChanged.connect(boost::bind(&ChatStateNotifier::handleCapsChanged, this, _1));
}
-void ChatStateNotifier::setContactIsOnline(bool online) {
- contactIsOnline_ = online;
+ChatStateNotifier::~ChatStateNotifier() {
+ entityCapsManager_->onCapsChanged.disconnect(boost::bind(&ChatStateNotifier::handleCapsChanged, this, _1));
}
-void ChatStateNotifier::contactJIDHasChanged() {
+void ChatStateNotifier::setContact(const JID& contact) {
contactHasSentActive_ = false;
- contactHas85Caps_ = false;
userIsTyping_ = false;
contactIsOnline_ = false;
+ contact_ = contact;
+ handleCapsChanged(contact_);
+}
+
+void ChatStateNotifier::setContactIsOnline(bool online) {
+ contactIsOnline_ = online;
}
void ChatStateNotifier::setUserIsTyping() {
bool should = contactShouldReceiveStates();
if (should && !userIsTyping_) {
userIsTyping_ = true;
- onChatStateChanged(ChatState::Composing);
+ changeState(ChatState::Composing);
}
}
@@ -42,7 +51,7 @@ void ChatStateNotifier::userSentMessage() {
void ChatStateNotifier::userCancelledNewMessage() {
if (userIsTyping_) {
userIsTyping_ = false;
- onChatStateChanged(ChatState::Active);
+ changeState(ChatState::Active);
}
}
@@ -52,10 +61,32 @@ void ChatStateNotifier::receivedMessageFromContact(bool hasActiveElement) {
bool ChatStateNotifier::contactShouldReceiveStates() {
/* So, yes, the XEP says to look at caps, but it also says that once you've
- heard from the contact, the active state overrides this.
- *HOWEVER* it says that the MUST NOT send csn if you haven't received
- active is OPTIONAL behaviour for if you haven't got caps.*/
+ heard from the contact, the active state overrides this.
+ *HOWEVER* it says that the MUST NOT send csn if you haven't received
+ active is OPTIONAL behaviour for if you haven't got caps.*/
return contactIsOnline_ && (contactHasSentActive_ || contactHas85Caps_);
}
+void ChatStateNotifier::changeState(ChatState::ChatStateType state) {
+ boost::shared_ptr<Message> message(new Message());
+ message->setTo(contact_);
+ message->addPayload(boost::shared_ptr<Payload>(new ChatState(state)));
+ stanzaChannel_->sendMessage(message);
+}
+
+void ChatStateNotifier::addChatStateRequest(Message::ref message) {
+ if (contactShouldReceiveStates()) {
+ message->addPayload(boost::shared_ptr<Payload>(new ChatState(ChatState::Active)));
+ }
+}
+
+
+void ChatStateNotifier::handleCapsChanged(const JID& jid) {
+ if (jid == contact_) {
+ DiscoInfo::ref caps = entityCapsManager_->getCaps(contact_);
+ bool hasCSN = caps && caps->hasFeature(ChatState::getFeatureNamespace());
+ contactHas85Caps_ = hasCSN;
+ }
+}
+
}
diff --git a/Swiften/Chat/ChatStateNotifier.h b/Swiften/Chat/ChatStateNotifier.h
index 3889b9c..1185ed0 100644
--- a/Swiften/Chat/ChatStateNotifier.h
+++ b/Swiften/Chat/ChatStateNotifier.h
@@ -9,23 +9,39 @@
#include "Swiften/Base/boost_bsignals.h"
#include <boost/shared_ptr.hpp>
+#include "Swiften/Elements/Message.h"
#include "Swiften/Elements/ChatState.h"
+#include "Swiften/JID/JID.h"
namespace Swift {
+ class StanzaChannel;
+ class EntityCapsProvider;
+
class ChatStateNotifier {
public:
- ChatStateNotifier();
- void setContactHas85Caps(bool hasCaps);
+ ChatStateNotifier(StanzaChannel* stanzaChannel, const JID& contact, EntityCapsProvider* entityCapsManager);
+ ~ChatStateNotifier();
+
+ void setContact(const JID& contact);
+
+ void addChatStateRequest(Message::ref message);
+
void setUserIsTyping();
- void setContactIsOnline(bool online);
void userSentMessage();
void userCancelledNewMessage();
+
void receivedMessageFromContact(bool hasActiveElement);
+ void setContactIsOnline(bool online);
+
+ private:
bool contactShouldReceiveStates();
- void contactJIDHasChanged();
+ void changeState(ChatState::ChatStateType type);
+ void handleCapsChanged(const JID& contact);
- boost::signal<void (ChatState::ChatStateType)> onChatStateChanged;
private:
+ StanzaChannel* stanzaChannel_;
+ EntityCapsProvider* entityCapsManager_;
+ JID contact_;
bool contactHas85Caps_;
bool contactHasSentActive_;
bool userIsTyping_;
diff --git a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
index 045a245..8380330 100644
--- a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
+++ b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
@@ -9,41 +9,11 @@
#include <boost/bind.hpp>
#include "Swiften/Chat/ChatStateNotifier.h"
+#include "Swiften/Client/DummyStanzaChannel.h"
+#include "Swiften/Disco/DummyEntityCapsProvider.h"
using namespace Swift;
-
-class ChatStateMonitor {
-public:
- ChatStateMonitor(ChatStateNotifier* notifier) {
- notifier_ = notifier;
- composingCallCount = 0;
- activeCallCount = 0;
- notifier->onChatStateChanged.connect(boost::bind(&ChatStateMonitor::handleChatStateChanged, this, _1));
- };
-
- int composingCallCount;
- int activeCallCount;
- ChatState::ChatStateType currentState;
-
-private:
- void handleChatStateChanged(ChatState::ChatStateType newState) {
- switch (newState) {
- case ChatState::Composing:
- composingCallCount++;
- break;
- case ChatState::Active:
- activeCallCount++;
- break;
- default:
- break;
- }
- currentState = newState;
- };
-
- ChatStateNotifier* notifier_;
-};
-
class ChatStateNotifierTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ChatStateNotifierTest);
CPPUNIT_TEST(testStartTypingReply_CapsNotIncluded);
@@ -57,101 +27,140 @@ class ChatStateNotifierTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testContactShouldReceiveStates_ActiveOverrideOff);
CPPUNIT_TEST_SUITE_END();
-private:
- ChatStateNotifier* notifier_;
- ChatStateMonitor* monitor_;
-
public:
void setUp() {
- notifier_ = new ChatStateNotifier();
+ stanzaChannel = new DummyStanzaChannel();
+ stanzaChannel->setAvailable(true);
+ entityCapsProvider = new DummyEntityCapsProvider();
+ notifier_ = new ChatStateNotifier(stanzaChannel, JID("foo@bar.com/baz"), entityCapsProvider);
notifier_->setContactIsOnline(true);
- monitor_ = new ChatStateMonitor(notifier_);
}
void tearDown() {
delete notifier_;
- delete monitor_;
+ delete stanzaChannel;
}
void testStartTypingReply_CapsNotIncluded() {
- notifier_->setContactHas85Caps(false);
notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(0, monitor_->composingCallCount);
+ CPPUNIT_ASSERT_EQUAL(0, getComposingCount());
}
void testSendTwoMessages() {
- notifier_->setContactHas85Caps(true);
+ setContactHas85Caps();
notifier_->setUserIsTyping();
notifier_->userSentMessage();
notifier_->setUserIsTyping();
notifier_->userSentMessage();
- CPPUNIT_ASSERT_EQUAL(2, monitor_->composingCallCount);
+ CPPUNIT_ASSERT_EQUAL(2, getComposingCount());
}
void testCancelledNewMessage() {
- notifier_->setContactHas85Caps(true);
+ setContactHas85Caps();
notifier_->setUserIsTyping();
notifier_->userCancelledNewMessage();
- CPPUNIT_ASSERT_EQUAL(1, monitor_->composingCallCount);
- CPPUNIT_ASSERT_EQUAL(1, monitor_->activeCallCount);
- CPPUNIT_ASSERT_EQUAL(ChatState::Active, monitor_->currentState);
+ CPPUNIT_ASSERT_EQUAL(1, getComposingCount());
+ CPPUNIT_ASSERT_EQUAL(1, getActiveCount());
+ CPPUNIT_ASSERT_EQUAL(ChatState::Active, stanzaChannel->sentStanzas[stanzaChannel->sentStanzas.size()-1]->getPayload<ChatState>()->getChatState());
}
void testContactShouldReceiveStates_CapsOnly() {
- notifier_->setContactHas85Caps(true);
- CPPUNIT_ASSERT_EQUAL(true, notifier_->contactShouldReceiveStates());
+ setContactHas85Caps();
+ boost::shared_ptr<Message> message(new Message());
+ notifier_->addChatStateRequest(message);
+ CPPUNIT_ASSERT(message->getPayload<ChatState>());
+ CPPUNIT_ASSERT_EQUAL(ChatState::Active, message->getPayload<ChatState>()->getChatState());
}
void testContactShouldReceiveStates_CapsNorActive() {
- CPPUNIT_ASSERT_EQUAL(false, notifier_->contactShouldReceiveStates());
+ boost::shared_ptr<Message> message(new Message());
+ notifier_->addChatStateRequest(message);
+ CPPUNIT_ASSERT(!message->getPayload<ChatState>());
}
void testContactShouldReceiveStates_ActiveOverrideOn() {
- notifier_->setContactHas85Caps(false);
notifier_->receivedMessageFromContact(true);
- CPPUNIT_ASSERT_EQUAL(true, notifier_->contactShouldReceiveStates());
+ boost::shared_ptr<Message> message(new Message());
+ notifier_->addChatStateRequest(message);
+ CPPUNIT_ASSERT(message->getPayload<ChatState>());
+ CPPUNIT_ASSERT_EQUAL(ChatState::Active, message->getPayload<ChatState>()->getChatState());
}
void testContactShouldReceiveStates_ActiveOverrideOff() {
- notifier_->setContactHas85Caps(true);
+ setContactHas85Caps();
notifier_->receivedMessageFromContact(false);
/* I originally read the MUST NOT send after receiving without Active and
* thought this should check for false, but I later found it was OPTIONAL
* (MAY) behaviour only for if you didn't receive caps.
*/
- CPPUNIT_ASSERT_EQUAL(true, notifier_->contactShouldReceiveStates());
+ boost::shared_ptr<Message> message(new Message());
+ notifier_->addChatStateRequest(message);
+ CPPUNIT_ASSERT(message->getPayload<ChatState>());
+ CPPUNIT_ASSERT_EQUAL(ChatState::Active, message->getPayload<ChatState>()->getChatState());
}
void testStartTypingReply_CapsIncluded() {
- notifier_->setContactHas85Caps(true);
+ setContactHas85Caps();
notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(1, monitor_->composingCallCount);
+ CPPUNIT_ASSERT_EQUAL(1, getComposingCount());
}
void testContinueTypingReply_CapsIncluded() {
- notifier_->setContactHas85Caps(true);
+ setContactHas85Caps();
notifier_->setUserIsTyping();
notifier_->setUserIsTyping();
notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(1, monitor_->composingCallCount);
+ CPPUNIT_ASSERT_EQUAL(1, getComposingCount());
notifier_->userSentMessage();
notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(2, monitor_->composingCallCount);
+ CPPUNIT_ASSERT_EQUAL(2, getComposingCount());
}
void testTypeReplies_WentOffline() {
- notifier_->setContactHas85Caps(true);
+ setContactHas85Caps();
notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(1, monitor_->composingCallCount);
+ CPPUNIT_ASSERT_EQUAL(1, getComposingCount());
notifier_->setContactIsOnline(false);
notifier_->userSentMessage();
notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(1, monitor_->composingCallCount);
+ CPPUNIT_ASSERT_EQUAL(1, getComposingCount());
}
-
+
+ private:
+ void setContactHas85Caps() {
+ DiscoInfo::ref caps(new DiscoInfo());
+ caps->addFeature(ChatState::getFeatureNamespace());
+ entityCapsProvider->caps[JID("foo@bar.com/baz")] = caps;
+ entityCapsProvider->onCapsChanged(JID("foo@bar.com/baz"));
+ }
+
+ int getComposingCount() const {
+ int result = 0;
+ foreach(boost::shared_ptr<Stanza> stanza, stanzaChannel->sentStanzas) {
+ if (stanza->getPayload<ChatState>() && stanza->getPayload<ChatState>()->getChatState() == ChatState::Composing) {
+ result++;
+ }
+ }
+ return result;
+ }
+
+ int getActiveCount() const {
+ int result = 0;
+ foreach(boost::shared_ptr<Stanza> stanza, stanzaChannel->sentStanzas) {
+ if (stanza->getPayload<ChatState>() && stanza->getPayload<ChatState>()->getChatState() == ChatState::Active) {
+ result++;
+ }
+ }
+ return result;
+ }
+
+ private:
+ DummyStanzaChannel* stanzaChannel;
+ DummyEntityCapsProvider* entityCapsProvider;
+ ChatStateNotifier* notifier_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(ChatStateNotifierTest);
diff --git a/Swiften/Disco/DummyEntityCapsProvider.h b/Swiften/Disco/DummyEntityCapsProvider.h
new file mode 100644
index 0000000..68cef2f
--- /dev/null
+++ b/Swiften/Disco/DummyEntityCapsProvider.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <map>
+#include <iostream>
+#include "Swiften/Disco/EntityCapsProvider.h"
+
+namespace Swift {
+ class DummyEntityCapsProvider : public EntityCapsProvider {
+ public:
+ DummyEntityCapsProvider() {
+ }
+
+ DiscoInfo::ref getCaps(const JID& jid) const {
+ std::map<JID, DiscoInfo::ref>::const_iterator i = caps.find(jid);
+ if (i != caps.end()) {
+ return i->second;
+ }
+ return DiscoInfo::ref();
+ }
+
+ std::map<JID, DiscoInfo::ref> caps;
+ };
+}
diff --git a/Swiften/Disco/EntityCapsManager.h b/Swiften/Disco/EntityCapsManager.h
index ecfcdea..f507a1d 100644
--- a/Swiften/Disco/EntityCapsManager.h
+++ b/Swiften/Disco/EntityCapsManager.h
@@ -12,6 +12,7 @@
#include "Swiften/Elements/Presence.h"
#include "Swiften/Elements/DiscoInfo.h"
#include "Swiften/Elements/ErrorPayload.h"
+#include "Swiften/Disco/EntityCapsProvider.h"
namespace Swift {
class StanzaChannel;
@@ -23,7 +24,7 @@ namespace Swift {
* This information is provided in the form of service discovery
* information.
*/
- class EntityCapsManager : public boost::bsignals::trackable {
+ class EntityCapsManager : public EntityCapsProvider, public boost::bsignals::trackable {
public:
EntityCapsManager(CapsProvider*, StanzaChannel*);
@@ -32,11 +33,6 @@ namespace Swift {
*/
DiscoInfo::ref getCaps(const JID&) const;
- /**
- * Emitted when the capabilities of a JID changes.
- */
- boost::signal<void (const JID&)> onCapsChanged;
-
private:
void handlePresenceReceived(boost::shared_ptr<Presence>);
void handleStanzaChannelAvailableChanged(bool);
diff --git a/Swiften/Disco/EntityCapsProvider.cpp b/Swiften/Disco/EntityCapsProvider.cpp
new file mode 100644
index 0000000..a337328
--- /dev/null
+++ b/Swiften/Disco/EntityCapsProvider.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swiften/Disco/EntityCapsProvider.h"
+
+namespace Swift {
+
+EntityCapsProvider::~EntityCapsProvider() {
+}
+
+}
diff --git a/Swiften/Disco/EntityCapsProvider.h b/Swiften/Disco/EntityCapsProvider.h
new file mode 100644
index 0000000..07fa452
--- /dev/null
+++ b/Swiften/Disco/EntityCapsProvider.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swiften/Base/boost_bsignals.h"
+#include "Swiften/JID/JID.h"
+#include "Swiften/Elements/DiscoInfo.h"
+
+namespace Swift {
+ /**
+ * This class provides information about capabilities of entities on the network.
+ * This information is provided in the form of service discovery
+ * information.
+ */
+ class EntityCapsProvider {
+ public:
+ virtual ~EntityCapsProvider();
+
+ /**
+ * Returns the service discovery information of the given JID.
+ */
+ virtual DiscoInfo::ref getCaps(const JID&) const = 0;
+
+ /**
+ * Emitted when the capabilities of a JID changes.
+ */
+ boost::signal<void (const JID&)> onCapsChanged;
+ };
+}
diff --git a/Swiften/Disco/SConscript b/Swiften/Disco/SConscript
index d07d490..3838d0e 100644
--- a/Swiften/Disco/SConscript
+++ b/Swiften/Disco/SConscript
@@ -4,6 +4,7 @@ objects = swiften_env.StaticObject([
"CapsInfoGenerator.cpp",
"CapsManager.cpp",
"EntityCapsManager.cpp",
+ "EntityCapsProvider.cpp",
"CapsStorage.cpp",
"CapsFileStorage.cpp",
"DiscoInfoResponder.cpp",
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 90f8d98..886051f 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -28,7 +28,6 @@ if env["SCONS_STAGE"] == "build" :
sources = [
"Chat/ChatStateTracker.cpp",
"Chat/ChatStateNotifier.cpp",
- "Chat/ChatStateMessageSender.cpp",
"Client/ClientSessionStanzaChannel.cpp",
"Client/CoreClient.cpp",
"Client/Client.cpp",