diff options
Diffstat (limited to 'Swiften')
-rw-r--r-- | Swiften/Chat/ChatStateMessageSender.cpp | 28 | ||||
-rw-r--r-- | Swiften/Chat/ChatStateMessageSender.h | 26 | ||||
-rw-r--r-- | Swiften/Chat/ChatStateNotifier.cpp | 61 | ||||
-rw-r--r-- | Swiften/Chat/ChatStateNotifier.h | 26 | ||||
-rw-r--r-- | Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp | 135 | ||||
-rw-r--r-- | Swiften/Disco/DummyEntityCapsProvider.h | 29 | ||||
-rw-r--r-- | Swiften/Disco/EntityCapsManager.h | 8 | ||||
-rw-r--r-- | Swiften/Disco/EntityCapsProvider.cpp | 14 | ||||
-rw-r--r-- | Swiften/Disco/EntityCapsProvider.h | 33 | ||||
-rw-r--r-- | Swiften/Disco/SConscript | 1 | ||||
-rw-r--r-- | Swiften/SConscript | 1 |
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", |