summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften')
-rw-r--r--Swiften/Client/Client.cpp5
-rw-r--r--Swiften/Client/Client.h6
-rw-r--r--Swiften/Client/DummyStanzaChannel.h4
-rw-r--r--Swiften/Disco/ClientDiscoManager.cpp39
-rw-r--r--Swiften/Disco/ClientDiscoManager.h67
-rw-r--r--Swiften/Disco/DiscoInfoResponder.cpp5
-rw-r--r--Swiften/Disco/DiscoInfoResponder.h6
-rw-r--r--Swiften/Disco/SConscript1
-rw-r--r--Swiften/Elements/Body.h7
-rw-r--r--Swiften/Elements/CapsInfo.h5
-rw-r--r--Swiften/Elements/Payload.h9
-rw-r--r--Swiften/Presence/PayloadAddingPresenceSender.cpp44
-rw-r--r--Swiften/Presence/PayloadAddingPresenceSender.h34
-rw-r--r--Swiften/Presence/SConscript11
-rw-r--r--Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp131
-rw-r--r--Swiften/SConscript7
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"),