diff options
author | Remko Tronçon <git@el-tramo.be> | 2010-10-23 21:08:19 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2010-11-03 12:17:40 (GMT) |
commit | 9d9fb66aefef85a1c5ad432391014d15011747d1 (patch) | |
tree | 55b1ebe7dcb0108008a28ebf8fee773b27e60547 /Swiften | |
parent | d509598b0f0edf5e103caedbab8662edc834445e (diff) | |
download | swift-9d9fb66aefef85a1c5ad432391014d15011747d1.zip swift-9d9fb66aefef85a1c5ad432391014d15011747d1.tar.bz2 |
Added ClientDiscoManager.
Diffstat (limited to 'Swiften')
-rw-r--r-- | Swiften/Client/Client.cpp | 5 | ||||
-rw-r--r-- | Swiften/Client/Client.h | 6 | ||||
-rw-r--r-- | Swiften/Client/DummyStanzaChannel.h | 4 | ||||
-rw-r--r-- | Swiften/Disco/ClientDiscoManager.cpp | 39 | ||||
-rw-r--r-- | Swiften/Disco/ClientDiscoManager.h | 67 | ||||
-rw-r--r-- | Swiften/Disco/DiscoInfoResponder.cpp | 5 | ||||
-rw-r--r-- | Swiften/Disco/DiscoInfoResponder.h | 6 | ||||
-rw-r--r-- | Swiften/Disco/SConscript | 1 | ||||
-rw-r--r-- | Swiften/Elements/Body.h | 7 | ||||
-rw-r--r-- | Swiften/Elements/CapsInfo.h | 5 | ||||
-rw-r--r-- | Swiften/Elements/Payload.h | 9 | ||||
-rw-r--r-- | Swiften/Presence/PayloadAddingPresenceSender.cpp | 44 | ||||
-rw-r--r-- | Swiften/Presence/PayloadAddingPresenceSender.h | 34 | ||||
-rw-r--r-- | Swiften/Presence/SConscript | 11 | ||||
-rw-r--r-- | Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp | 131 | ||||
-rw-r--r-- | Swiften/SConscript | 7 |
16 files changed, 362 insertions, 19 deletions
diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp index 7dbcb70..fd01e25 100644 --- a/Swiften/Client/Client.cpp +++ b/Swiften/Client/Client.cpp @@ -20,6 +20,7 @@ #include "Swiften/Avatars/AvatarManagerImpl.h" #include "Swiften/Disco/CapsManager.h" #include "Swiften/Disco/EntityCapsManager.h" +#include "Swiften/Disco/ClientDiscoManager.h" #include "Swiften/Client/NickResolver.h" #include "Swiften/Presence/SubscriptionManager.h" @@ -41,6 +42,7 @@ Client::Client(EventLoop* eventLoop, const JID& jid, const String& password, Sto stanzaChannelPresenceSender = new StanzaChannelPresenceSender(getStanzaChannel()); directedPresenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender); + discoManager = new ClientDiscoManager(getIQRouter(), directedPresenceSender); mucRegistry = new MUCRegistry(); mucManager = new MUCManager(getStanzaChannel(), getIQRouter(), directedPresenceSender, mucRegistry); @@ -64,6 +66,7 @@ Client::~Client() { delete mucManager; delete mucRegistry; + delete discoManager; delete directedPresenceSender; delete stanzaChannelPresenceSender; @@ -106,7 +109,7 @@ Storages* Client::getStorages() const { } PresenceSender* Client::getPresenceSender() const { - return directedPresenceSender; + return discoManager->getPresenceSender(); } } diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h index adfd549..a17fe24 100644 --- a/Swiften/Client/Client.h +++ b/Swiften/Client/Client.h @@ -27,6 +27,7 @@ namespace Swift { class EntityCapsManager; class NickResolver; class SubscriptionManager; + class ClientDiscoManager; /** * Provides the core functionality for writing XMPP client software. @@ -122,6 +123,10 @@ namespace Swift { return subscriptionManager; } + ClientDiscoManager* getDiscoManager() const { + return discoManager; + } + public: /** * This signal is emitted when a JID changes presence. @@ -151,5 +156,6 @@ namespace Swift { NickResolver* nickResolver; SubscriptionManager* subscriptionManager; MUCManager* mucManager; + ClientDiscoManager* discoManager; }; } diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h index b8ae545..d9fb138 100644 --- a/Swiften/Client/DummyStanzaChannel.h +++ b/Swiften/Client/DummyStanzaChannel.h @@ -56,6 +56,10 @@ namespace Swift { return iqStanza && iqStanza->getType() == type && iqStanza->getTo() == jid && iqStanza->getPayload<T>(); } + template<typename T> boost::shared_ptr<T> getStanzaAtIndex(size_t index) { + return boost::dynamic_pointer_cast<T>(sentStanzas[index]); + } + std::vector<boost::shared_ptr<Stanza> > sentStanzas; bool available_; }; diff --git a/Swiften/Disco/ClientDiscoManager.cpp b/Swiften/Disco/ClientDiscoManager.cpp new file mode 100644 index 0000000..6753df2 --- /dev/null +++ b/Swiften/Disco/ClientDiscoManager.cpp @@ -0,0 +1,39 @@ +/* + * 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/ClientDiscoManager.h" + +#include "Swiften/Disco/DiscoInfoResponder.h" +#include "Swiften/Disco/CapsInfoGenerator.h" +#include "Swiften/Presence/PayloadAddingPresenceSender.h" + +namespace Swift { + +ClientDiscoManager::ClientDiscoManager(IQRouter* iqRouter, PresenceSender* presenceSender) { + discoInfoResponder = new DiscoInfoResponder(iqRouter); + discoInfoResponder->start(); + this->presenceSender = new PayloadAddingPresenceSender(presenceSender); +} + +ClientDiscoManager::~ClientDiscoManager() { + delete presenceSender; + discoInfoResponder->stop(); + delete discoInfoResponder; +} + +void ClientDiscoManager::setCapsNode(const String& node) { + capsNode = node; +} + +void ClientDiscoManager::setDiscoInfo(const DiscoInfo& discoInfo) { + capsInfo = CapsInfo::ref(new CapsInfo(CapsInfoGenerator(capsNode).generateCapsInfo(discoInfo))); + discoInfoResponder->clearDiscoInfo(); + discoInfoResponder->setDiscoInfo(discoInfo); + discoInfoResponder->setDiscoInfo(capsInfo->getNode() + "#" + capsInfo->getVersion(), discoInfo); + presenceSender->setPayload(capsInfo); +} + +} diff --git a/Swiften/Disco/ClientDiscoManager.h b/Swiften/Disco/ClientDiscoManager.h new file mode 100644 index 0000000..b997374 --- /dev/null +++ b/Swiften/Disco/ClientDiscoManager.h @@ -0,0 +1,67 @@ +/* + * 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/Elements/CapsInfo.h" +#include "Swiften/Elements/DiscoInfo.h" +#include "Swiften/Presence/PayloadAddingPresenceSender.h" + +namespace Swift { + class IQRouter; + class DiscoInfoResponder; + class PayloadAddingPresenceSender; + class PresenceSender; + + /** + * Class responsible for managing outgoing disco information for a client. + * + * The manager will respond to disco#info requests, and add entity capabilities information + * to outgoing presence. + * + * To use this class, call setCapsNode() once with the caps URI of the client. After this, + * call setDiscoInfo() with the capabilities for the client. This can be + * called whenever the capabilities change. + */ + class ClientDiscoManager { + public: + /** + * Constructs the manager + * + * \param iqRouter the router on which requests will be answered + * \param presenceSender the presence sender to which all outgoing presence + * (with caps information) will be sent. + */ + ClientDiscoManager(IQRouter* iqRouter, PresenceSender* presenceSender); + ~ClientDiscoManager(); + + /** + * Needs to be called before calling setDiscoInfo(). + */ + void setCapsNode(const String& node); + + /** + * Sets the capabilities of the client. + */ + void setDiscoInfo(const DiscoInfo& info); + + /** + * Returns the presence sender through which all outgoing presence + * should be sent. + * The manager will add the necessary caps information, and forward it to + * the presence sender passed at construction time. + */ + PresenceSender* getPresenceSender() const { + return presenceSender; + } + + private: + PayloadAddingPresenceSender* presenceSender; + DiscoInfoResponder* discoInfoResponder; + String capsNode; + CapsInfo::ref capsInfo; + }; +} diff --git a/Swiften/Disco/DiscoInfoResponder.cpp b/Swiften/Disco/DiscoInfoResponder.cpp index 154eded..2e686c7 100644 --- a/Swiften/Disco/DiscoInfoResponder.cpp +++ b/Swiften/Disco/DiscoInfoResponder.cpp @@ -13,6 +13,11 @@ namespace Swift { DiscoInfoResponder::DiscoInfoResponder(IQRouter* router) : GetResponder<DiscoInfo>(router) { } +void DiscoInfoResponder::clearDiscoInfo() { + info_ = DiscoInfo(); + nodeInfo_.clear(); +} + void DiscoInfoResponder::setDiscoInfo(const DiscoInfo& info) { info_ = info; } diff --git a/Swiften/Disco/DiscoInfoResponder.h b/Swiften/Disco/DiscoInfoResponder.h index 4a7d271..0dc1172 100644 --- a/Swiften/Disco/DiscoInfoResponder.h +++ b/Swiften/Disco/DiscoInfoResponder.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_DiscoInfoResponder_H -#define SWIFTEN_DiscoInfoResponder_H +#pragma once #include <map> @@ -19,6 +18,7 @@ namespace Swift { public: DiscoInfoResponder(IQRouter* router); + void clearDiscoInfo(); void setDiscoInfo(const DiscoInfo& info); void setDiscoInfo(const String& node, const DiscoInfo& info); @@ -30,5 +30,3 @@ namespace Swift { std::map<String, DiscoInfo> nodeInfo_; }; } - -#endif diff --git a/Swiften/Disco/SConscript b/Swiften/Disco/SConscript index 3838d0e..a791946 100644 --- a/Swiften/Disco/SConscript +++ b/Swiften/Disco/SConscript @@ -7,6 +7,7 @@ objects = swiften_env.StaticObject([ "EntityCapsProvider.cpp", "CapsStorage.cpp", "CapsFileStorage.cpp", + "ClientDiscoManager.cpp", "DiscoInfoResponder.cpp", ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Elements/Body.h b/Swiften/Elements/Body.h index e3610c8..8262e09 100644 --- a/Swiften/Elements/Body.h +++ b/Swiften/Elements/Body.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_Body_H -#define SWIFTEN_Body_H +#pragma once #include "Swiften/Elements/Payload.h" #include "Swiften/Base/String.h" @@ -13,6 +12,8 @@ namespace Swift { class Body : public Payload { public: + typedef boost::shared_ptr<Body> ref; + Body(const String& text = "") : text_(text) { } @@ -28,5 +29,3 @@ namespace Swift { String text_; }; } - -#endif diff --git a/Swiften/Elements/CapsInfo.h b/Swiften/Elements/CapsInfo.h index 1968a29..dc3cc2e 100644 --- a/Swiften/Elements/CapsInfo.h +++ b/Swiften/Elements/CapsInfo.h @@ -6,13 +6,16 @@ #pragma once -#include "Swiften/Base/String.h" +#include <boost/shared_ptr.hpp> +#include "Swiften/Base/String.h" #include "Swiften/Elements/Payload.h" namespace Swift { class CapsInfo : public Payload { public: + typedef boost::shared_ptr<CapsInfo> ref; + CapsInfo(const String& node = "", const String& version = "", const String& hash = "sha-1") : node_(node), version_(version), hash_(hash) {} bool operator==(const CapsInfo& o) const { diff --git a/Swiften/Elements/Payload.h b/Swiften/Elements/Payload.h index 9d7ed16..c87b899 100644 --- a/Swiften/Elements/Payload.h +++ b/Swiften/Elements/Payload.h @@ -4,14 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_PAYLOAD_H -#define SWIFTEN_PAYLOAD_H +#pragma once + +#include <boost/shared_ptr.hpp> namespace Swift { class Payload { public: + typedef boost::shared_ptr<Payload> ref; + virtual ~Payload(); }; } - -#endif diff --git a/Swiften/Presence/PayloadAddingPresenceSender.cpp b/Swiften/Presence/PayloadAddingPresenceSender.cpp new file mode 100644 index 0000000..c3d1638 --- /dev/null +++ b/Swiften/Presence/PayloadAddingPresenceSender.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Presence/PayloadAddingPresenceSender.h" + +namespace Swift { + +PayloadAddingPresenceSender::PayloadAddingPresenceSender(PresenceSender* sender) : sender(sender) { +} + +void PayloadAddingPresenceSender::sendPresence(Presence::ref presence) { + if (presence->isAvailable()) { + if (!presence->getTo().isValid()) { + lastSentPresence = presence; + } + } + else { + lastSentPresence.reset(); + } + if (payload) { + Presence::ref sentPresence = Presence::create(presence); + sentPresence->updatePayload(payload); + sender->sendPresence(sentPresence); + } + else { + sender->sendPresence(presence); + } +} + +bool PayloadAddingPresenceSender::isAvailable() const { + return sender->isAvailable(); +} + +void PayloadAddingPresenceSender::setPayload(Payload::ref payload) { + this->payload = payload; + if (lastSentPresence) { + sendPresence(lastSentPresence); + } +} + +} diff --git a/Swiften/Presence/PayloadAddingPresenceSender.h b/Swiften/Presence/PayloadAddingPresenceSender.h new file mode 100644 index 0000000..5602ebe --- /dev/null +++ b/Swiften/Presence/PayloadAddingPresenceSender.h @@ -0,0 +1,34 @@ +/* + * 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/Presence/PresenceSender.h" +#include "Swiften/Elements/Payload.h" + +namespace Swift { + class StanzaChannel; + + /** + * This presence sender adds payloads to outgoing presences. + * + * + */ + class PayloadAddingPresenceSender : public PresenceSender { + public: + PayloadAddingPresenceSender(PresenceSender*); + + void sendPresence(Presence::ref); + bool isAvailable() const; + + void setPayload(Payload::ref); + + private: + Presence::ref lastSentPresence; + PresenceSender* sender; + Payload::ref payload; + }; +} diff --git a/Swiften/Presence/SConscript b/Swiften/Presence/SConscript new file mode 100644 index 0000000..6911d45 --- /dev/null +++ b/Swiften/Presence/SConscript @@ -0,0 +1,11 @@ +Import("swiften_env") + +objects = swiften_env.StaticObject([ + "PresenceOracle.cpp", + "PresenceSender.cpp", + "DirectedPresenceSender.cpp", + "PayloadAddingPresenceSender.cpp", + "StanzaChannelPresenceSender.cpp", + "SubscriptionManager.cpp", + ]) +swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp b/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp new file mode 100644 index 0000000..3a6487a --- /dev/null +++ b/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <vector> +#include <boost/bind.hpp> + +#include "Swiften/Presence/PayloadAddingPresenceSender.h" +#include "Swiften/Presence/StanzaChannelPresenceSender.h" +#include "Swiften/Elements/Body.h" +#include "Swiften/Client/DummyStanzaChannel.h" + +using namespace Swift; + +class PayloadAddingPresenceSenderTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(PayloadAddingPresenceSenderTest); + CPPUNIT_TEST(testSetPayloadAddsPayloadOnPresenceSend); + CPPUNIT_TEST(testSetNullPayloadDoesNotAddPayloadOnPresenceSend); + CPPUNIT_TEST(testSendPresenceDoesNotAlterOriginalPayload); + CPPUNIT_TEST(testSetPayloadAfterInitialPresenceResendsPresence); + CPPUNIT_TEST(testSetPayloadAfterUnavailablePresenceDoesNotResendPresence); + CPPUNIT_TEST(testSendDirectedPresenceIsNotResent); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + stanzaChannel = new DummyStanzaChannel(); + presenceSender = new StanzaChannelPresenceSender(stanzaChannel); + } + + void tearDown() { + delete presenceSender; + delete stanzaChannel; + } + + void testSetPayloadAddsPayloadOnPresenceSend() { + std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + + testling->setPayload(MyPayload::create("foo")); + testling->sendPresence(Presence::create("bar")); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(String("bar"), stanzaChannel->getStanzaAtIndex<Presence>(0)->getStatus()); + CPPUNIT_ASSERT(stanzaChannel->getStanzaAtIndex<Presence>(0)->getPayload<MyPayload>()); + } + + void testSetNullPayloadDoesNotAddPayloadOnPresenceSend() { + std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + + testling->setPayload(MyPayload::ref()); + testling->sendPresence(Presence::create("bar")); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(String("bar"), stanzaChannel->getStanzaAtIndex<Presence>(0)->getStatus()); + CPPUNIT_ASSERT(!stanzaChannel->getStanzaAtIndex<Presence>(0)->getPayload<MyPayload>()); + } + + void testSendPresenceDoesNotAlterOriginalPayload() { + std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + + testling->setPayload(MyPayload::create("foo")); + Presence::ref presence(Presence::create("bar")); + testling->sendPresence(presence); + + CPPUNIT_ASSERT(!presence->getPayload<MyPayload>()); + } + + void testSetPayloadAfterInitialPresenceResendsPresence() { + std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + + testling->sendPresence(Presence::create("bar")); + testling->setPayload(MyPayload::create("foo")); + + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(String("bar"), stanzaChannel->getStanzaAtIndex<Presence>(1)->getStatus()); + CPPUNIT_ASSERT(stanzaChannel->getStanzaAtIndex<Presence>(1)->getPayload<MyPayload>()); + } + + void testSetPayloadAfterUnavailablePresenceDoesNotResendPresence() { + std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + + Presence::ref presence = Presence::create("bar"); + presence->setType(Presence::Unavailable); + testling->sendPresence(presence); + + testling->setPayload(MyPayload::create("foo")); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + } + + void testSendDirectedPresenceIsNotResent() { + std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + + testling->sendPresence(Presence::create("bar")); + Presence::ref directedPresence = Presence::create("baz"); + directedPresence->setTo(JID("foo@bar.com")); + testling->sendPresence(directedPresence); + testling->setPayload(MyPayload::create("foo")); + + CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(String("bar"), stanzaChannel->getStanzaAtIndex<Presence>(2)->getStatus()); + } + + private: + std::auto_ptr<PayloadAddingPresenceSender> createSender() { + std::auto_ptr<PayloadAddingPresenceSender> sender(new PayloadAddingPresenceSender(presenceSender)); + return sender; + } + + struct MyPayload : public Payload { + typedef boost::shared_ptr<MyPayload> ref; + + MyPayload(const String& body) : body(body) {} + + static ref create(const String& body) { + return ref(new MyPayload(body)); + } + + String body; + }; + + private: + DummyStanzaChannel* stanzaChannel; + StanzaChannelPresenceSender* presenceSender; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(PayloadAddingPresenceSenderTest); diff --git a/Swiften/SConscript b/Swiften/SConscript index 5790672..9744f45 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -51,11 +51,6 @@ if env["SCONS_STAGE"] == "build" : "MUC/MUCOccupant.cpp", "MUC/MUCRegistry.cpp", "MUC/MUCBookmarkManager.cpp", - "Presence/PresenceOracle.cpp", - "Presence/PresenceSender.cpp", - "Presence/DirectedPresenceSender.cpp", - "Presence/StanzaChannelPresenceSender.cpp", - "Presence/SubscriptionManager.cpp", "Queries/IQChannel.cpp", "Queries/IQHandler.cpp", "Queries/IQRouter.cpp", @@ -139,6 +134,7 @@ if env["SCONS_STAGE"] == "build" : "Disco", "VCards", "Network", + "Presence", "FileTransfer", "History", "StreamStack", @@ -223,6 +219,7 @@ if env["SCONS_STAGE"] == "build" : File("Parser/UnitTest/XMPPParserTest.cpp"), File("Presence/UnitTest/PresenceOracleTest.cpp"), File("Presence/UnitTest/DirectedPresenceSenderTest.cpp"), + File("Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp"), File("Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp"), File("Disco/UnitTest/DiscoInfoResponderTest.cpp"), File("Queries/UnitTest/IQRouterTest.cpp"), |