summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/Disco')
-rw-r--r--Swiften/Disco/CapsInfoGenerator.cpp77
-rw-r--r--Swiften/Disco/CapsInfoGenerator.h23
-rw-r--r--Swiften/Disco/CapsManager.cpp100
-rw-r--r--Swiften/Disco/CapsManager.h77
-rw-r--r--Swiften/Disco/CapsMemoryStorage.h44
-rw-r--r--Swiften/Disco/CapsProvider.h21
-rw-r--r--Swiften/Disco/CapsStorage.h18
-rw-r--r--Swiften/Disco/ClientDiscoManager.cpp30
-rw-r--r--Swiften/Disco/ClientDiscoManager.h115
-rw-r--r--Swiften/Disco/DiscoInfoResponder.cpp49
-rw-r--r--Swiften/Disco/DiscoInfoResponder.h30
-rw-r--r--Swiften/Disco/DiscoServiceWalker.cpp195
-rw-r--r--Swiften/Disco/DiscoServiceWalker.h103
-rw-r--r--Swiften/Disco/DummyEntityCapsProvider.cpp14
-rw-r--r--Swiften/Disco/DummyEntityCapsProvider.h14
-rw-r--r--Swiften/Disco/EntityCapsManager.cpp102
-rw-r--r--Swiften/Disco/EntityCapsManager.h63
-rw-r--r--Swiften/Disco/EntityCapsProvider.h41
-rw-r--r--Swiften/Disco/FeatureOracle.cpp224
-rw-r--r--Swiften/Disco/FeatureOracle.h50
-rw-r--r--Swiften/Disco/GetDiscoInfoRequest.h50
-rw-r--r--Swiften/Disco/GetDiscoItemsRequest.h50
-rw-r--r--Swiften/Disco/JIDDiscoInfoResponder.cpp63
-rw-r--r--Swiften/Disco/JIDDiscoInfoResponder.h46
-rw-r--r--Swiften/Disco/SConscript24
-rw-r--r--Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp122
-rw-r--r--Swiften/Disco/UnitTest/CapsManagerTest.cpp543
-rw-r--r--Swiften/Disco/UnitTest/DiscoInfoResponderTest.cpp159
-rw-r--r--Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp348
-rw-r--r--Swiften/Disco/UnitTest/FeatureOracleTest.cpp151
-rw-r--r--Swiften/Disco/UnitTest/JIDDiscoInfoResponderTest.cpp203
31 files changed, 1707 insertions, 1442 deletions
diff --git a/Swiften/Disco/CapsInfoGenerator.cpp b/Swiften/Disco/CapsInfoGenerator.cpp
index d2354ea..961ef43 100644
--- a/Swiften/Disco/CapsInfoGenerator.cpp
+++ b/Swiften/Disco/CapsInfoGenerator.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -8,16 +8,15 @@
#include <algorithm>
-#include <Swiften/Base/foreach.h>
+#include <Swiften/Crypto/CryptoProvider.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/FormField.h>
-#include <Swiften/Crypto/CryptoProvider.h>
#include <Swiften/StringCodecs/Base64.h>
namespace {
- bool compareFields(Swift::FormField::ref f1, Swift::FormField::ref f2) {
- return f1->getName() < f2->getName();
- }
+ bool compareFields(Swift::FormField::ref f1, Swift::FormField::ref f2) {
+ return f1->getName() < f2->getName();
+ }
}
namespace Swift {
@@ -26,39 +25,39 @@ CapsInfoGenerator::CapsInfoGenerator(const std::string& node, CryptoProvider* cr
}
CapsInfo CapsInfoGenerator::generateCapsInfo(const DiscoInfo& discoInfo) const {
- std::string serializedCaps;
-
- std::vector<DiscoInfo::Identity> identities(discoInfo.getIdentities());
- std::sort(identities.begin(), identities.end());
- foreach (const DiscoInfo::Identity& identity, identities) {
- serializedCaps += identity.getCategory() + "/" + identity.getType() + "/" + identity.getLanguage() + "/" + identity.getName() + "<";
- }
-
- std::vector<std::string> features(discoInfo.getFeatures());
- std::sort(features.begin(), features.end());
- foreach (const std::string& feature, features) {
- serializedCaps += feature + "<";
- }
-
- foreach(Form::ref extension, discoInfo.getExtensions()) {
- serializedCaps += extension->getFormType() + "<";
- std::vector<FormField::ref> fields(extension->getFields());
- std::sort(fields.begin(), fields.end(), &compareFields);
- foreach(FormField::ref field, fields) {
- if (field->getName() == "FORM_TYPE") {
- continue;
- }
- serializedCaps += field->getName() + "<";
- std::vector<std::string> values(field->getValues());
- std::sort(values.begin(), values.end());
- foreach(const std::string& value, values) {
- serializedCaps += value + "<";
- }
- }
- }
-
- std::string version(Base64::encode(crypto_->getSHA1Hash(createByteArray(serializedCaps))));
- return CapsInfo(node_, version, "sha-1");
+ std::string serializedCaps;
+
+ std::vector<DiscoInfo::Identity> identities(discoInfo.getIdentities());
+ std::sort(identities.begin(), identities.end());
+ for (const auto& identity : identities) {
+ serializedCaps += identity.getCategory() + "/" + identity.getType() + "/" + identity.getLanguage() + "/" + identity.getName() + "<";
+ }
+
+ std::vector<std::string> features(discoInfo.getFeatures());
+ std::sort(features.begin(), features.end());
+ for (const auto& feature : features) {
+ serializedCaps += feature + "<";
+ }
+
+ for (const auto& extension : discoInfo.getExtensions()) {
+ serializedCaps += extension->getFormType() + "<";
+ std::vector<FormField::ref> fields(extension->getFields());
+ std::sort(fields.begin(), fields.end(), &compareFields);
+ for (const auto& field : fields) {
+ if (field->getName() == "FORM_TYPE") {
+ continue;
+ }
+ serializedCaps += field->getName() + "<";
+ std::vector<std::string> values(field->getValues());
+ std::sort(values.begin(), values.end());
+ for (const auto& value : values) {
+ serializedCaps += value + "<";
+ }
+ }
+ }
+
+ std::string version(Base64::encode(crypto_->getSHA1Hash(createByteArray(serializedCaps))));
+ return CapsInfo(node_, version, "sha-1");
}
}
diff --git a/Swiften/Disco/CapsInfoGenerator.h b/Swiften/Disco/CapsInfoGenerator.h
index ebcb8fa..ed1b1bd 100644
--- a/Swiften/Disco/CapsInfoGenerator.h
+++ b/Swiften/Disco/CapsInfoGenerator.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -7,21 +7,22 @@
#pragma once
#include <string>
+
#include <Swiften/Base/API.h>
#include <Swiften/Elements/CapsInfo.h>
namespace Swift {
- class DiscoInfo;
- class CryptoProvider;
+ class DiscoInfo;
+ class CryptoProvider;
- class SWIFTEN_API CapsInfoGenerator {
- public:
- CapsInfoGenerator(const std::string& node, CryptoProvider* crypto);
+ class SWIFTEN_API CapsInfoGenerator {
+ public:
+ CapsInfoGenerator(const std::string& node, CryptoProvider* crypto);
- CapsInfo generateCapsInfo(const DiscoInfo& discoInfo) const;
+ CapsInfo generateCapsInfo(const DiscoInfo& discoInfo) const;
- private:
- std::string node_;
- CryptoProvider* crypto_;
- };
+ private:
+ std::string node_;
+ CryptoProvider* crypto_;
+ };
}
diff --git a/Swiften/Disco/CapsManager.cpp b/Swiften/Disco/CapsManager.cpp
index 2f2f909..794cf74 100644
--- a/Swiften/Disco/CapsManager.cpp
+++ b/Swiften/Disco/CapsManager.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -7,77 +7,77 @@
#include <Swiften/Disco/CapsManager.h>
#include <boost/bind.hpp>
-#include <iostream>
+#include <Swiften/Base/Log.h>
#include <Swiften/Client/StanzaChannel.h>
-#include <Swiften/Disco/CapsStorage.h>
#include <Swiften/Disco/CapsInfoGenerator.h>
-#include <Swiften/Elements/CapsInfo.h>
+#include <Swiften/Disco/CapsStorage.h>
#include <Swiften/Disco/GetDiscoInfoRequest.h>
+#include <Swiften/Elements/CapsInfo.h>
namespace Swift {
CapsManager::CapsManager(CapsStorage* capsStorage, StanzaChannel* stanzaChannel, IQRouter* iqRouter, CryptoProvider* crypto) : iqRouter(iqRouter), crypto(crypto), capsStorage(capsStorage), warnOnInvalidHash(true) {
- stanzaChannel->onPresenceReceived.connect(boost::bind(&CapsManager::handlePresenceReceived, this, _1));
- stanzaChannel->onAvailableChanged.connect(boost::bind(&CapsManager::handleStanzaChannelAvailableChanged, this, _1));
+ stanzaChannel->onPresenceReceived.connect(boost::bind(&CapsManager::handlePresenceReceived, this, _1));
+ stanzaChannel->onAvailableChanged.connect(boost::bind(&CapsManager::handleStanzaChannelAvailableChanged, this, _1));
}
-void CapsManager::handlePresenceReceived(boost::shared_ptr<Presence> presence) {
- boost::shared_ptr<CapsInfo> capsInfo = presence->getPayload<CapsInfo>();
- if (!capsInfo || capsInfo->getHash() != "sha-1" || presence->getPayload<ErrorPayload>()) {
- return;
- }
- std::string hash = capsInfo->getVersion();
- if (capsStorage->getDiscoInfo(hash)) {
- return;
- }
- if (failingCaps.find(std::make_pair(presence->getFrom(), hash)) != failingCaps.end()) {
- return;
- }
- if (requestedDiscoInfos.find(hash) != requestedDiscoInfos.end()) {
- fallbacks[hash].insert(std::make_pair(presence->getFrom(), capsInfo->getNode()));
- return;
- }
- requestDiscoInfo(presence->getFrom(), capsInfo->getNode(), hash);
+void CapsManager::handlePresenceReceived(std::shared_ptr<Presence> presence) {
+ std::shared_ptr<CapsInfo> capsInfo = presence->getPayload<CapsInfo>();
+ if (!capsInfo || capsInfo->getHash() != "sha-1" || presence->getPayload<ErrorPayload>()) {
+ return;
+ }
+ std::string hash = capsInfo->getVersion();
+ if (capsStorage->getDiscoInfo(hash)) {
+ return;
+ }
+ if (failingCaps.find(std::make_pair(presence->getFrom(), hash)) != failingCaps.end()) {
+ return;
+ }
+ if (requestedDiscoInfos.find(hash) != requestedDiscoInfos.end()) {
+ fallbacks[hash].insert(std::make_pair(presence->getFrom(), capsInfo->getNode()));
+ return;
+ }
+ requestDiscoInfo(presence->getFrom(), capsInfo->getNode(), hash);
}
void CapsManager::handleStanzaChannelAvailableChanged(bool available) {
- if (available) {
- failingCaps.clear();
- fallbacks.clear();
- requestedDiscoInfos.clear();
- }
+ if (available) {
+ failingCaps.clear();
+ fallbacks.clear();
+ requestedDiscoInfos.clear();
+ }
}
void CapsManager::handleDiscoInfoReceived(const JID& from, const std::string& hash, DiscoInfo::ref discoInfo, ErrorPayload::ref error) {
- requestedDiscoInfos.erase(hash);
- if (error || !discoInfo || CapsInfoGenerator("", crypto).generateCapsInfo(*discoInfo.get()).getVersion() != hash) {
- if (warnOnInvalidHash && !error && discoInfo) {
- std::cerr << "Warning: Caps from " << from.toString() << " do not verify" << std::endl;
- }
- failingCaps.insert(std::make_pair(from, hash));
- std::map<std::string, std::set< std::pair<JID, std::string> > >::iterator i = fallbacks.find(hash);
- if (i != fallbacks.end() && !i->second.empty()) {
- std::pair<JID,std::string> fallbackAndNode = *i->second.begin();
- i->second.erase(i->second.begin());
- requestDiscoInfo(fallbackAndNode.first, fallbackAndNode.second, hash);
- }
- return;
- }
- fallbacks.erase(hash);
- capsStorage->setDiscoInfo(hash, discoInfo);
- onCapsAvailable(hash);
+ requestedDiscoInfos.erase(hash);
+ if (error || !discoInfo || CapsInfoGenerator("", crypto).generateCapsInfo(*discoInfo.get()).getVersion() != hash) {
+ if (warnOnInvalidHash && !error && discoInfo) {
+ SWIFT_LOG(warning) << "Caps from " << from.toString() << " do not verify" << std::endl;
+ }
+ failingCaps.insert(std::make_pair(from, hash));
+ std::map<std::string, std::set< std::pair<JID, std::string> > >::iterator i = fallbacks.find(hash);
+ if (i != fallbacks.end() && !i->second.empty()) {
+ std::pair<JID,std::string> fallbackAndNode = *i->second.begin();
+ i->second.erase(i->second.begin());
+ requestDiscoInfo(fallbackAndNode.first, fallbackAndNode.second, hash);
+ }
+ return;
+ }
+ fallbacks.erase(hash);
+ capsStorage->setDiscoInfo(hash, discoInfo);
+ onCapsAvailable(hash);
}
void CapsManager::requestDiscoInfo(const JID& jid, const std::string& node, const std::string& hash) {
- GetDiscoInfoRequest::ref request = GetDiscoInfoRequest::create(jid, node + "#" + hash, iqRouter);
- request->onResponse.connect(boost::bind(&CapsManager::handleDiscoInfoReceived, this, jid, hash, _1, _2));
- requestedDiscoInfos.insert(hash);
- request->send();
+ GetDiscoInfoRequest::ref request = GetDiscoInfoRequest::create(jid, node + "#" + hash, iqRouter);
+ request->onResponse.connect(boost::bind(&CapsManager::handleDiscoInfoReceived, this, jid, hash, _1, _2));
+ requestedDiscoInfos.insert(hash);
+ request->send();
}
DiscoInfo::ref CapsManager::getCaps(const std::string& hash) const {
- return capsStorage->getDiscoInfo(hash);
+ return capsStorage->getDiscoInfo(hash);
}
diff --git a/Swiften/Disco/CapsManager.h b/Swiften/Disco/CapsManager.h
index 095fe1f..e57730e 100644
--- a/Swiften/Disco/CapsManager.h
+++ b/Swiften/Disco/CapsManager.h
@@ -1,53 +1,54 @@
/*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
-#include <set>
#include <map>
+#include <set>
+
+#include <boost/signals2.hpp>
#include <Swiften/Base/API.h>
-#include <Swiften/Base/boost_bsignals.h>
-#include <Swiften/Elements/Presence.h>
-#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Disco/CapsProvider.h>
#include <Swiften/Elements/CapsInfo.h>
+#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/ErrorPayload.h>
-#include <Swiften/Disco/CapsProvider.h>
+#include <Swiften/Elements/Presence.h>
namespace Swift {
- class StanzaChannel;
- class IQRouter;
- class JID;
- class CapsStorage;
- class CryptoProvider;
-
- class SWIFTEN_API CapsManager : public CapsProvider, public boost::bsignals::trackable {
- public:
- CapsManager(CapsStorage*, StanzaChannel*, IQRouter*, CryptoProvider*);
-
- DiscoInfo::ref getCaps(const std::string&) const;
-
- // Mainly for testing purposes
- void setWarnOnInvalidHash(bool b) {
- warnOnInvalidHash = b;
- }
-
- private:
- void handlePresenceReceived(boost::shared_ptr<Presence>);
- void handleStanzaChannelAvailableChanged(bool);
- void handleDiscoInfoReceived(const JID&, const std::string& hash, DiscoInfo::ref, ErrorPayload::ref);
- void requestDiscoInfo(const JID& jid, const std::string& node, const std::string& hash);
-
- private:
- IQRouter* iqRouter;
- CryptoProvider* crypto;
- CapsStorage* capsStorage;
- bool warnOnInvalidHash;
- std::set<std::string> requestedDiscoInfos;
- std::set< std::pair<JID, std::string> > failingCaps;
- std::map<std::string, std::set< std::pair<JID, std::string> > > fallbacks;
- };
+ class StanzaChannel;
+ class IQRouter;
+ class JID;
+ class CapsStorage;
+ class CryptoProvider;
+
+ class SWIFTEN_API CapsManager : public CapsProvider, public boost::signals2::trackable {
+ public:
+ CapsManager(CapsStorage*, StanzaChannel*, IQRouter*, CryptoProvider*);
+
+ DiscoInfo::ref getCaps(const std::string&) const;
+
+ // Mainly for testing purposes
+ void setWarnOnInvalidHash(bool b) {
+ warnOnInvalidHash = b;
+ }
+
+ private:
+ void handlePresenceReceived(std::shared_ptr<Presence>);
+ void handleStanzaChannelAvailableChanged(bool);
+ void handleDiscoInfoReceived(const JID&, const std::string& hash, DiscoInfo::ref, ErrorPayload::ref);
+ void requestDiscoInfo(const JID& jid, const std::string& node, const std::string& hash);
+
+ private:
+ IQRouter* iqRouter;
+ CryptoProvider* crypto;
+ CapsStorage* capsStorage;
+ bool warnOnInvalidHash;
+ std::set<std::string> requestedDiscoInfos;
+ std::set< std::pair<JID, std::string> > failingCaps;
+ std::map<std::string, std::set< std::pair<JID, std::string> > > fallbacks;
+ };
}
diff --git a/Swiften/Disco/CapsMemoryStorage.h b/Swiften/Disco/CapsMemoryStorage.h
index 2a81554..15a1fd3 100644
--- a/Swiften/Disco/CapsMemoryStorage.h
+++ b/Swiften/Disco/CapsMemoryStorage.h
@@ -1,39 +1,39 @@
/*
- * Copyright (c) 2010-2015 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
-#include <boost/shared_ptr.hpp>
#include <map>
-
+#include <memory>
#include <string>
+
#include <Swiften/Base/API.h>
#include <Swiften/Disco/CapsStorage.h>
namespace Swift {
- class SWIFTEN_API CapsMemoryStorage : public CapsStorage {
- public:
- CapsMemoryStorage() {}
+ class SWIFTEN_API CapsMemoryStorage : public CapsStorage {
+ public:
+ CapsMemoryStorage() {}
- virtual DiscoInfo::ref getDiscoInfo(const std::string& hash) const {
- CapsMap::const_iterator i = caps.find(hash);
- if (i != caps.end()) {
- return i->second;
- }
- else {
- return DiscoInfo::ref();
- }
- }
+ virtual DiscoInfo::ref getDiscoInfo(const std::string& hash) const {
+ CapsMap::const_iterator i = caps.find(hash);
+ if (i != caps.end()) {
+ return i->second;
+ }
+ else {
+ return DiscoInfo::ref();
+ }
+ }
- virtual void setDiscoInfo(const std::string& hash, DiscoInfo::ref discoInfo) {
- caps[hash] = discoInfo;
- }
+ virtual void setDiscoInfo(const std::string& hash, DiscoInfo::ref discoInfo) {
+ caps[hash] = discoInfo;
+ }
- private:
- typedef std::map<std::string, DiscoInfo::ref> CapsMap;
- CapsMap caps;
- };
+ private:
+ typedef std::map<std::string, DiscoInfo::ref> CapsMap;
+ CapsMap caps;
+ };
}
diff --git a/Swiften/Disco/CapsProvider.h b/Swiften/Disco/CapsProvider.h
index 08202a7..b9e2d21 100644
--- a/Swiften/Disco/CapsProvider.h
+++ b/Swiften/Disco/CapsProvider.h
@@ -1,25 +1,26 @@
/*
- * Copyright (c) 2010-2015 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
-#include <Swiften/Base/boost_bsignals.h>
+#include <boost/signals2.hpp>
+
#include <Swiften/Base/API.h>
-#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/CapsInfo.h>
+#include <Swiften/Elements/DiscoInfo.h>
namespace Swift {
-
- class SWIFTEN_API CapsProvider {
- public:
- virtual ~CapsProvider() {}
- virtual DiscoInfo::ref getCaps(const std::string&) const = 0;
+ class SWIFTEN_API CapsProvider {
+ public:
+ virtual ~CapsProvider() {}
+
+ virtual DiscoInfo::ref getCaps(const std::string&) const = 0;
- boost::signal<void (const std::string&)> onCapsAvailable;
- };
+ boost::signals2::signal<void (const std::string&)> onCapsAvailable;
+ };
}
diff --git a/Swiften/Disco/CapsStorage.h b/Swiften/Disco/CapsStorage.h
index 85b8d5d..ebfd3f3 100644
--- a/Swiften/Disco/CapsStorage.h
+++ b/Swiften/Disco/CapsStorage.h
@@ -1,22 +1,22 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
-#include <boost/shared_ptr.hpp>
+#include <memory>
-#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Base/API.h>
+#include <Swiften/Elements/DiscoInfo.h>
namespace Swift {
- class SWIFTEN_API CapsStorage {
- public:
- virtual ~CapsStorage();
+ class SWIFTEN_API CapsStorage {
+ public:
+ virtual ~CapsStorage();
- virtual DiscoInfo::ref getDiscoInfo(const std::string&) const = 0;
- virtual void setDiscoInfo(const std::string&, DiscoInfo::ref) = 0;
- };
+ virtual DiscoInfo::ref getDiscoInfo(const std::string&) const = 0;
+ virtual void setDiscoInfo(const std::string&, DiscoInfo::ref) = 0;
+ };
}
diff --git a/Swiften/Disco/ClientDiscoManager.cpp b/Swiften/Disco/ClientDiscoManager.cpp
index 74336a5..8c90d2d 100644
--- a/Swiften/Disco/ClientDiscoManager.cpp
+++ b/Swiften/Disco/ClientDiscoManager.cpp
@@ -1,43 +1,43 @@
/*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swiften/Disco/ClientDiscoManager.h>
-#include <Swiften/Disco/DiscoInfoResponder.h>
#include <Swiften/Disco/CapsInfoGenerator.h>
+#include <Swiften/Disco/DiscoInfoResponder.h>
#include <Swiften/Presence/PayloadAddingPresenceSender.h>
namespace Swift {
ClientDiscoManager::ClientDiscoManager(IQRouter* iqRouter, PresenceSender* presenceSender, CryptoProvider* crypto) : crypto(crypto) {
- discoInfoResponder = new DiscoInfoResponder(iqRouter);
- discoInfoResponder->start();
- this->presenceSender = new PayloadAddingPresenceSender(presenceSender);
+ discoInfoResponder = new DiscoInfoResponder(iqRouter);
+ discoInfoResponder->start();
+ this->presenceSender = new PayloadAddingPresenceSender(presenceSender);
}
ClientDiscoManager::~ClientDiscoManager() {
- delete presenceSender;
- discoInfoResponder->stop();
- delete discoInfoResponder;
+ delete presenceSender;
+ discoInfoResponder->stop();
+ delete discoInfoResponder;
}
void ClientDiscoManager::setCapsNode(const std::string& node) {
- capsNode = node;
+ capsNode = node;
}
void ClientDiscoManager::setDiscoInfo(const DiscoInfo& discoInfo) {
- capsInfo = CapsInfo::ref(new CapsInfo(CapsInfoGenerator(capsNode, crypto).generateCapsInfo(discoInfo)));
- discoInfoResponder->clearDiscoInfo();
- discoInfoResponder->setDiscoInfo(discoInfo);
- discoInfoResponder->setDiscoInfo(capsInfo->getNode() + "#" + capsInfo->getVersion(), discoInfo);
- presenceSender->setPayload(capsInfo);
+ capsInfo = CapsInfo::ref(new CapsInfo(CapsInfoGenerator(capsNode, crypto).generateCapsInfo(discoInfo)));
+ discoInfoResponder->clearDiscoInfo();
+ discoInfoResponder->setDiscoInfo(discoInfo);
+ discoInfoResponder->setDiscoInfo(capsInfo->getNode() + "#" + capsInfo->getVersion(), discoInfo);
+ presenceSender->setPayload(capsInfo);
}
void ClientDiscoManager::handleConnected() {
- presenceSender->reset();
+ presenceSender->reset();
}
}
diff --git a/Swiften/Disco/ClientDiscoManager.h b/Swiften/Disco/ClientDiscoManager.h
index 560c69a..595beeb 100644
--- a/Swiften/Disco/ClientDiscoManager.h
+++ b/Swiften/Disco/ClientDiscoManager.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -12,66 +12,67 @@
#include <Swiften/Presence/PayloadAddingPresenceSender.h>
namespace Swift {
- class IQRouter;
- class DiscoInfoResponder;
- class PayloadAddingPresenceSender;
- class PresenceSender;
- class CryptoProvider;
+ class IQRouter;
+ class DiscoInfoResponder;
+ class PayloadAddingPresenceSender;
+ class PresenceSender;
+ class CryptoProvider;
- /**
- * 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 SWIFTEN_API 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, CryptoProvider* crypto);
- ~ClientDiscoManager();
+ /**
+ * 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 SWIFTEN_API 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.
+ * \param crypto the crypto provider used for cryptographic hash computations.
+ */
+ ClientDiscoManager(IQRouter* iqRouter, PresenceSender* presenceSender, CryptoProvider* crypto);
+ ~ClientDiscoManager();
- /**
- * Needs to be called before calling setDiscoInfo().
- */
- void setCapsNode(const std::string& node);
+ /**
+ * Needs to be called before calling setDiscoInfo().
+ */
+ void setCapsNode(const std::string& node);
- /**
- * Sets the capabilities of the client.
- */
- void setDiscoInfo(const DiscoInfo& info);
+ /**
+ * 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;
- }
+ /**
+ * 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;
+ }
- /**
- * Called when the client is connected.
- * This resets the presence sender, such that it assumes initial presence
- * hasn't been sent yet.
- */
- void handleConnected();
+ /**
+ * Called when the client is connected.
+ * This resets the presence sender, such that it assumes initial presence
+ * hasn't been sent yet.
+ */
+ void handleConnected();
- private:
- PayloadAddingPresenceSender* presenceSender;
- CryptoProvider* crypto;
- DiscoInfoResponder* discoInfoResponder;
- std::string capsNode;
- CapsInfo::ref capsInfo;
- };
+ private:
+ PayloadAddingPresenceSender* presenceSender;
+ CryptoProvider* crypto;
+ DiscoInfoResponder* discoInfoResponder;
+ std::string capsNode;
+ CapsInfo::ref capsInfo;
+ };
}
diff --git a/Swiften/Disco/DiscoInfoResponder.cpp b/Swiften/Disco/DiscoInfoResponder.cpp
index 3c477c3..c94d299 100644
--- a/Swiften/Disco/DiscoInfoResponder.cpp
+++ b/Swiften/Disco/DiscoInfoResponder.cpp
@@ -1,14 +1,15 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#include <boost/smart_ptr/make_shared.hpp>
-
#include <Swiften/Disco/DiscoInfoResponder.h>
-#include <Swiften/Queries/IQRouter.h>
+
+#include <memory>
+
#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Queries/IQRouter.h>
namespace Swift {
@@ -16,34 +17,34 @@ DiscoInfoResponder::DiscoInfoResponder(IQRouter* router) : GetResponder<DiscoInf
}
void DiscoInfoResponder::clearDiscoInfo() {
- info_ = DiscoInfo();
- nodeInfo_.clear();
+ info_ = DiscoInfo();
+ nodeInfo_.clear();
}
void DiscoInfoResponder::setDiscoInfo(const DiscoInfo& info) {
- info_ = info;
+ info_ = info;
}
void DiscoInfoResponder::setDiscoInfo(const std::string& node, const DiscoInfo& info) {
- DiscoInfo newInfo(info);
- newInfo.setNode(node);
- nodeInfo_[node] = newInfo;
+ DiscoInfo newInfo(info);
+ newInfo.setNode(node);
+ nodeInfo_[node] = newInfo;
}
-bool DiscoInfoResponder::handleGetRequest(const JID& from, const JID&, const std::string& id, boost::shared_ptr<DiscoInfo> info) {
- if (info->getNode().empty()) {
- sendResponse(from, id, boost::make_shared<DiscoInfo>(info_));
- }
- else {
- std::map<std::string,DiscoInfo>::const_iterator i = nodeInfo_.find(info->getNode());
- if (i != nodeInfo_.end()) {
- sendResponse(from, id, boost::make_shared<DiscoInfo>((*i).second));
- }
- else {
- sendError(from, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel);
- }
- }
- return true;
+bool DiscoInfoResponder::handleGetRequest(const JID& from, const JID&, const std::string& id, std::shared_ptr<DiscoInfo> info) {
+ if (info->getNode().empty()) {
+ sendResponse(from, id, std::make_shared<DiscoInfo>(info_));
+ }
+ else {
+ std::map<std::string,DiscoInfo>::const_iterator i = nodeInfo_.find(info->getNode());
+ if (i != nodeInfo_.end()) {
+ sendResponse(from, id, std::make_shared<DiscoInfo>((*i).second));
+ }
+ else {
+ sendError(from, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel);
+ }
+ }
+ return true;
}
}
diff --git a/Swiften/Disco/DiscoInfoResponder.h b/Swiften/Disco/DiscoInfoResponder.h
index 0ca6336..9995695 100644
--- a/Swiften/Disco/DiscoInfoResponder.h
+++ b/Swiften/Disco/DiscoInfoResponder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -9,25 +9,25 @@
#include <map>
#include <Swiften/Base/API.h>
-#include <Swiften/Queries/GetResponder.h>
#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Queries/GetResponder.h>
namespace Swift {
- class IQRouter;
+ class IQRouter;
- class SWIFTEN_API DiscoInfoResponder : public GetResponder<DiscoInfo> {
- public:
- DiscoInfoResponder(IQRouter* router);
+ class SWIFTEN_API DiscoInfoResponder : public GetResponder<DiscoInfo> {
+ public:
+ DiscoInfoResponder(IQRouter* router);
- void clearDiscoInfo();
- void setDiscoInfo(const DiscoInfo& info);
- void setDiscoInfo(const std::string& node, const DiscoInfo& info);
+ void clearDiscoInfo();
+ void setDiscoInfo(const DiscoInfo& info);
+ void setDiscoInfo(const std::string& node, const DiscoInfo& info);
- private:
- virtual bool handleGetRequest(const JID& from, const JID& to, const std::string& id, boost::shared_ptr<DiscoInfo> payload);
+ private:
+ virtual bool handleGetRequest(const JID& from, const JID& to, const std::string& id, std::shared_ptr<DiscoInfo> payload);
- private:
- DiscoInfo info_;
- std::map<std::string, DiscoInfo> nodeInfo_;
- };
+ private:
+ DiscoInfo info_;
+ std::map<std::string, DiscoInfo> nodeInfo_;
+ };
}
diff --git a/Swiften/Disco/DiscoServiceWalker.cpp b/Swiften/Disco/DiscoServiceWalker.cpp
index 5803602..a3f95d2 100644
--- a/Swiften/Disco/DiscoServiceWalker.cpp
+++ b/Swiften/Disco/DiscoServiceWalker.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2015 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -9,7 +9,6 @@
#include <boost/bind.hpp>
#include <Swiften/Base/Log.h>
-#include <Swiften/Base/foreach.h>
namespace Swift {
@@ -18,118 +17,118 @@ DiscoServiceWalker::DiscoServiceWalker(const JID& service, IQRouter* iqRouter, s
}
void DiscoServiceWalker::beginWalk() {
- SWIFT_LOG(debug) << "Starting walk to " << service_ << std::endl;
- assert(!active_);
- assert(servicesBeingSearched_.empty());
- active_ = true;
- walkNode(service_);
+ SWIFT_LOG(debug) << "Starting walk to " << service_ << std::endl;
+ assert(!active_);
+ assert(servicesBeingSearched_.empty());
+ active_ = true;
+ walkNode(service_);
}
void DiscoServiceWalker::endWalk() {
- if (active_) {
- SWIFT_LOG(debug) << "Ending walk to " << service_ << std::endl;
- foreach (GetDiscoInfoRequest::ref request, pendingDiscoInfoRequests_) {
- request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoInfoResponse, this, _1, _2, request));
- }
- foreach (GetDiscoItemsRequest::ref request, pendingDiscoItemsRequests_) {
- request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoItemsResponse, this, _1, _2, request));
- }
- active_ = false;
- onWalkAborted();
- }
+ if (active_) {
+ SWIFT_LOG(debug) << "Ending walk to " << service_ << std::endl;
+ for (auto&& request : pendingDiscoInfoRequests_) {
+ request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoInfoResponse, this, _1, _2, request));
+ }
+ for (auto&& request : pendingDiscoItemsRequests_) {
+ request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoItemsResponse, this, _1, _2, request));
+ }
+ active_ = false;
+ onWalkAborted();
+ }
}
void DiscoServiceWalker::walkNode(const JID& jid) {
- SWIFT_LOG(debug) << "Walking node " << jid << std::endl;
- servicesBeingSearched_.insert(jid);
- searchedServices_.insert(jid);
- GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(jid, iqRouter_);
- discoInfoRequest->onResponse.connect(boost::bind(&DiscoServiceWalker::handleDiscoInfoResponse, this, _1, _2, discoInfoRequest));
- pendingDiscoInfoRequests_.insert(discoInfoRequest);
- discoInfoRequest->send();
+ SWIFT_LOG(debug) << "Walking node " << jid << std::endl;
+ servicesBeingSearched_.insert(jid);
+ searchedServices_.insert(jid);
+ GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(jid, iqRouter_);
+ discoInfoRequest->onResponse.connect(boost::bind(&DiscoServiceWalker::handleDiscoInfoResponse, this, _1, _2, discoInfoRequest));
+ pendingDiscoInfoRequests_.insert(discoInfoRequest);
+ discoInfoRequest->send();
}
-void DiscoServiceWalker::handleDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, ErrorPayload::ref error, GetDiscoInfoRequest::ref request) {
- /* If we got canceled, don't do anything */
- if (!active_) {
- return;
- }
-
- SWIFT_LOG(debug) << "Disco info response from " << request->getReceiver() << std::endl;
-
- request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoInfoResponse, this, _1, _2, request));
- pendingDiscoInfoRequests_.erase(request);
- if (error) {
- handleDiscoError(request->getReceiver(), error);
- return;
- }
-
- bool couldContainServices = false;
- foreach (DiscoInfo::Identity identity, info->getIdentities()) {
- if (identity.getCategory() == "server") {
- couldContainServices = true;
- }
- }
- bool completed = false;
- if (couldContainServices) {
- GetDiscoItemsRequest::ref discoItemsRequest = GetDiscoItemsRequest::create(request->getReceiver(), iqRouter_);
- discoItemsRequest->onResponse.connect(boost::bind(&DiscoServiceWalker::handleDiscoItemsResponse, this, _1, _2, discoItemsRequest));
- pendingDiscoItemsRequests_.insert(discoItemsRequest);
- discoItemsRequest->send();
- } else {
- completed = true;
- }
- onServiceFound(request->getReceiver(), info);
- if (completed) {
- markNodeCompleted(request->getReceiver());
- }
+void DiscoServiceWalker::handleDiscoInfoResponse(std::shared_ptr<DiscoInfo> info, ErrorPayload::ref error, GetDiscoInfoRequest::ref request) {
+ /* If we got canceled, don't do anything */
+ if (!active_) {
+ return;
+ }
+
+ SWIFT_LOG(debug) << "Disco info response from " << request->getReceiver() << std::endl;
+
+ request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoInfoResponse, this, _1, _2, request));
+ pendingDiscoInfoRequests_.erase(request);
+ if (error) {
+ handleDiscoError(request->getReceiver(), error);
+ return;
+ }
+
+ bool couldContainServices = false;
+ for (const auto& identity : info->getIdentities()) {
+ if (identity.getCategory() == "server") {
+ couldContainServices = true;
+ }
+ }
+ bool completed = false;
+ if (couldContainServices) {
+ GetDiscoItemsRequest::ref discoItemsRequest = GetDiscoItemsRequest::create(request->getReceiver(), iqRouter_);
+ discoItemsRequest->onResponse.connect(boost::bind(&DiscoServiceWalker::handleDiscoItemsResponse, this, _1, _2, discoItemsRequest));
+ pendingDiscoItemsRequests_.insert(discoItemsRequest);
+ discoItemsRequest->send();
+ } else {
+ completed = true;
+ }
+ onServiceFound(request->getReceiver(), info);
+ if (completed) {
+ markNodeCompleted(request->getReceiver());
+ }
}
-void DiscoServiceWalker::handleDiscoItemsResponse(boost::shared_ptr<DiscoItems> items, ErrorPayload::ref error, GetDiscoItemsRequest::ref request) {
- /* If we got canceled, don't do anything */
- if (!active_) {
- return;
- }
-
- SWIFT_LOG(debug) << "Received disco items from " << request->getReceiver() << std::endl;
- request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoItemsResponse, this, _1, _2, request));
- pendingDiscoItemsRequests_.erase(request);
- if (error) {
- handleDiscoError(request->getReceiver(), error);
- return;
- }
- foreach (DiscoItems::Item item, items->getItems()) {
- if (item.getNode().empty()) {
- /* Don't look at noded items. It's possible that this will exclude some services,
- * but I've never seen one in the wild, and it's an easy fix for not looping.
- */
- if (std::find(searchedServices_.begin(), searchedServices_.end(), item.getJID()) == searchedServices_.end()) { /* Don't recurse infinitely */
- SWIFT_LOG(debug) << "Received disco item " << item.getJID() << std::endl;
- walkNode(item.getJID());
- }
- }
- }
- markNodeCompleted(request->getReceiver());
+void DiscoServiceWalker::handleDiscoItemsResponse(std::shared_ptr<DiscoItems> items, ErrorPayload::ref error, GetDiscoItemsRequest::ref request) {
+ /* If we got canceled, don't do anything */
+ if (!active_) {
+ return;
+ }
+
+ SWIFT_LOG(debug) << "Received disco items from " << request->getReceiver() << std::endl;
+ request->onResponse.disconnect(boost::bind(&DiscoServiceWalker::handleDiscoItemsResponse, this, _1, _2, request));
+ pendingDiscoItemsRequests_.erase(request);
+ if (error) {
+ handleDiscoError(request->getReceiver(), error);
+ return;
+ }
+ for (auto&& item : items->getItems()) {
+ if (item.getNode().empty()) {
+ /* Don't look at noded items. It's possible that this will exclude some services,
+ * but I've never seen one in the wild, and it's an easy fix for not looping.
+ */
+ if (std::find(searchedServices_.begin(), searchedServices_.end(), item.getJID()) == searchedServices_.end()) { /* Don't recurse infinitely */
+ SWIFT_LOG(debug) << "Received disco item " << item.getJID() << std::endl;
+ walkNode(item.getJID());
+ }
+ }
+ }
+ markNodeCompleted(request->getReceiver());
}
void DiscoServiceWalker::handleDiscoError(const JID& jid, ErrorPayload::ref /*error*/) {
- SWIFT_LOG(debug) << "Disco error from " << jid << std::endl;
- markNodeCompleted(jid);
+ SWIFT_LOG(debug) << "Disco error from " << jid << std::endl;
+ markNodeCompleted(jid);
}
void DiscoServiceWalker::markNodeCompleted(const JID& jid) {
- SWIFT_LOG(debug) << "Node completed " << jid << std::endl;
- servicesBeingSearched_.erase(jid);
- /* All results are in */
- if (servicesBeingSearched_.empty()) {
- active_ = false;
- onWalkComplete();
- }
- /* Check if we're on a rampage */
- else if (searchedServices_.size() >= maxSteps_) {
- active_ = false;
- onWalkComplete();
- }
+ SWIFT_LOG(debug) << "Node completed " << jid << std::endl;
+ servicesBeingSearched_.erase(jid);
+ /* All results are in */
+ if (servicesBeingSearched_.empty()) {
+ active_ = false;
+ onWalkComplete();
+ }
+ /* Check if we're on a rampage */
+ else if (searchedServices_.size() >= maxSteps_) {
+ active_ = false;
+ onWalkComplete();
+ }
}
}
diff --git a/Swiften/Disco/DiscoServiceWalker.h b/Swiften/Disco/DiscoServiceWalker.h
index 643096d..f7e1e6d 100644
--- a/Swiften/Disco/DiscoServiceWalker.h
+++ b/Swiften/Disco/DiscoServiceWalker.h
@@ -1,75 +1,76 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
-#include <vector>
+#include <memory>
#include <set>
+#include <string>
+#include <vector>
+
+#include <boost/signals2.hpp>
#include <Swiften/Base/API.h>
-#include <boost/shared_ptr.hpp>
-#include <Swiften/Base/boost_bsignals.h>
-#include <string>
-#include <Swiften/JID/JID.h>
+#include <Swiften/Disco/GetDiscoInfoRequest.h>
+#include <Swiften/Disco/GetDiscoItemsRequest.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/DiscoItems.h>
#include <Swiften/Elements/ErrorPayload.h>
-#include <Swiften/Disco/GetDiscoInfoRequest.h>
-#include <Swiften/Disco/GetDiscoItemsRequest.h>
+#include <Swiften/JID/JID.h>
namespace Swift {
- class IQRouter;
- /**
- * Recursively walk service discovery trees to find all services offered.
- * This stops on any disco item that's not reporting itself as a server.
- */
- class SWIFTEN_API DiscoServiceWalker {
- public:
- DiscoServiceWalker(const JID& service, IQRouter* iqRouter, size_t maxSteps = 200);
+ class IQRouter;
+ /**
+ * Recursively walk service discovery trees to find all services offered.
+ * This stops on any disco item that's not reporting itself as a server.
+ */
+ class SWIFTEN_API DiscoServiceWalker {
+ public:
+ DiscoServiceWalker(const JID& service, IQRouter* iqRouter, size_t maxSteps = 200);
- /**
- * Start the walk.
- *
- * Call this exactly once.
- */
- void beginWalk();
+ /**
+ * Start the walk.
+ *
+ * Call this exactly once.
+ */
+ void beginWalk();
- /**
- * End the walk.
- */
- void endWalk();
+ /**
+ * End the walk.
+ */
+ void endWalk();
- bool isActive() const {
- return active_;
- }
+ bool isActive() const {
+ return active_;
+ }
- /** Emitted for each service found. */
- boost::signal<void(const JID&, boost::shared_ptr<DiscoInfo>)> onServiceFound;
+ /** Emitted for each service found. */
+ boost::signals2::signal<void(const JID&, std::shared_ptr<DiscoInfo>)> onServiceFound;
- /** Emitted when walking is aborted. */
- boost::signal<void()> onWalkAborted;
+ /** Emitted when walking is aborted. */
+ boost::signals2::signal<void()> onWalkAborted;
- /** Emitted when walking is complete.*/
- boost::signal<void()> onWalkComplete;
+ /** Emitted when walking is complete.*/
+ boost::signals2::signal<void()> onWalkComplete;
- private:
- void walkNode(const JID& jid);
- void markNodeCompleted(const JID& jid);
- void handleDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, ErrorPayload::ref error, GetDiscoInfoRequest::ref request);
- void handleDiscoItemsResponse(boost::shared_ptr<DiscoItems> items, ErrorPayload::ref error, GetDiscoItemsRequest::ref request);
- void handleDiscoError(const JID& jid, ErrorPayload::ref error);
+ private:
+ void walkNode(const JID& jid);
+ void markNodeCompleted(const JID& jid);
+ void handleDiscoInfoResponse(std::shared_ptr<DiscoInfo> info, ErrorPayload::ref error, GetDiscoInfoRequest::ref request);
+ void handleDiscoItemsResponse(std::shared_ptr<DiscoItems> items, ErrorPayload::ref error, GetDiscoItemsRequest::ref request);
+ void handleDiscoError(const JID& jid, ErrorPayload::ref error);
- private:
- JID service_;
- IQRouter* iqRouter_;
- size_t maxSteps_;
- bool active_;
- std::set<JID> servicesBeingSearched_;
- std::set<JID> searchedServices_;
- std::set<GetDiscoInfoRequest::ref> pendingDiscoInfoRequests_;
- std::set<GetDiscoItemsRequest::ref> pendingDiscoItemsRequests_;
- };
+ private:
+ JID service_;
+ IQRouter* iqRouter_;
+ size_t maxSteps_;
+ bool active_;
+ std::set<JID> servicesBeingSearched_;
+ std::set<JID> searchedServices_;
+ std::set<GetDiscoInfoRequest::ref> pendingDiscoInfoRequests_;
+ std::set<GetDiscoItemsRequest::ref> pendingDiscoItemsRequests_;
+ };
}
diff --git a/Swiften/Disco/DummyEntityCapsProvider.cpp b/Swiften/Disco/DummyEntityCapsProvider.cpp
index 65baf7a..fce38fe 100644
--- a/Swiften/Disco/DummyEntityCapsProvider.cpp
+++ b/Swiften/Disco/DummyEntityCapsProvider.cpp
@@ -1,21 +1,19 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swiften/Disco/DummyEntityCapsProvider.h>
-#include <iostream>
-
namespace Swift {
DiscoInfo::ref DummyEntityCapsProvider::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>::const_iterator i = caps.find(jid);
+ if (i != caps.end()) {
+ return i->second;
+ }
+ return DiscoInfo::ref();
}
}
diff --git a/Swiften/Disco/DummyEntityCapsProvider.h b/Swiften/Disco/DummyEntityCapsProvider.h
index d6b2c82..5171c91 100644
--- a/Swiften/Disco/DummyEntityCapsProvider.h
+++ b/Swiften/Disco/DummyEntityCapsProvider.h
@@ -12,13 +12,13 @@
#include <Swiften/Disco/EntityCapsProvider.h>
namespace Swift {
- class SWIFTEN_API DummyEntityCapsProvider : public EntityCapsProvider {
- public:
- DummyEntityCapsProvider() {
- }
+ class SWIFTEN_API DummyEntityCapsProvider : public EntityCapsProvider {
+ public:
+ DummyEntityCapsProvider() {
+ }
- DiscoInfo::ref getCaps(const JID& jid) const;
+ DiscoInfo::ref getCaps(const JID& jid) const;
- std::map<JID, DiscoInfo::ref> caps;
- };
+ std::map<JID, DiscoInfo::ref> caps;
+ };
}
diff --git a/Swiften/Disco/EntityCapsManager.cpp b/Swiften/Disco/EntityCapsManager.cpp
index 09519ba..64d90be 100644
--- a/Swiften/Disco/EntityCapsManager.cpp
+++ b/Swiften/Disco/EntityCapsManager.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -8,72 +8,72 @@
#include <boost/bind.hpp>
-#include <Swiften/Disco/CapsProvider.h>
#include <Swiften/Client/StanzaChannel.h>
+#include <Swiften/Disco/CapsProvider.h>
namespace Swift {
EntityCapsManager::EntityCapsManager(CapsProvider* capsProvider, StanzaChannel* stanzaChannel) : capsProvider(capsProvider) {
- stanzaChannel->onPresenceReceived.connect(boost::bind(&EntityCapsManager::handlePresenceReceived, this, _1));
- stanzaChannel->onAvailableChanged.connect(boost::bind(&EntityCapsManager::handleStanzaChannelAvailableChanged, this, _1));
- capsProvider->onCapsAvailable.connect(boost::bind(&EntityCapsManager::handleCapsAvailable, this, _1));
+ stanzaChannel->onPresenceReceived.connect(boost::bind(&EntityCapsManager::handlePresenceReceived, this, _1));
+ stanzaChannel->onAvailableChanged.connect(boost::bind(&EntityCapsManager::handleStanzaChannelAvailableChanged, this, _1));
+ capsProvider->onCapsAvailable.connect(boost::bind(&EntityCapsManager::handleCapsAvailable, this, _1));
}
-void EntityCapsManager::handlePresenceReceived(boost::shared_ptr<Presence> presence) {
- JID from = presence->getFrom();
- if (presence->isAvailable()) {
- boost::shared_ptr<CapsInfo> capsInfo = presence->getPayload<CapsInfo>();
- if (!capsInfo || capsInfo->getHash() != "sha-1" || presence->getPayload<ErrorPayload>()) {
- return;
- }
- std::string hash = capsInfo->getVersion();
- std::map<JID, std::string>::iterator i = caps.find(from);
- if (i == caps.end() || i->second != hash) {
- caps.insert(std::make_pair(from, hash));
- DiscoInfo::ref disco = capsProvider->getCaps(hash);
- if (disco) {
- onCapsChanged(from);
- }
- else if (i != caps.end()) {
- caps.erase(i);
- onCapsChanged(from);
- }
- }
- }
- else {
- std::map<JID, std::string>::iterator i = caps.find(from);
- if (i != caps.end()) {
- caps.erase(i);
- onCapsChanged(from);
- }
- }
+void EntityCapsManager::handlePresenceReceived(std::shared_ptr<Presence> presence) {
+ JID from = presence->getFrom();
+ if (presence->isAvailable()) {
+ std::shared_ptr<CapsInfo> capsInfo = presence->getPayload<CapsInfo>();
+ if (!capsInfo || capsInfo->getHash() != "sha-1" || presence->getPayload<ErrorPayload>()) {
+ return;
+ }
+ std::string hash = capsInfo->getVersion();
+ std::map<JID, std::string>::iterator i = caps.find(from);
+ if (i == caps.end() || i->second != hash) {
+ caps.insert(std::make_pair(from, hash));
+ DiscoInfo::ref disco = capsProvider->getCaps(hash);
+ if (disco) {
+ onCapsChanged(from);
+ }
+ else if (i != caps.end()) {
+ caps.erase(i);
+ onCapsChanged(from);
+ }
+ }
+ }
+ else {
+ std::map<JID, std::string>::iterator i = caps.find(from);
+ if (i != caps.end()) {
+ caps.erase(i);
+ onCapsChanged(from);
+ }
+ }
}
void EntityCapsManager::handleStanzaChannelAvailableChanged(bool available) {
- if (available) {
- std::map<JID, std::string> capsCopy;
- capsCopy.swap(caps);
- for (std::map<JID,std::string>::const_iterator i = capsCopy.begin(); i != capsCopy.end(); ++i) {
- onCapsChanged(i->first);
- }
- }
+ if (available) {
+ std::map<JID, std::string> capsCopy;
+ capsCopy.swap(caps);
+ for (std::map<JID,std::string>::const_iterator i = capsCopy.begin(); i != capsCopy.end(); ++i) {
+ onCapsChanged(i->first);
+ }
+ }
}
void EntityCapsManager::handleCapsAvailable(const std::string& hash) {
- // TODO: Use Boost.Bimap ?
- for (std::map<JID,std::string>::const_iterator i = caps.begin(); i != caps.end(); ++i) {
- if (i->second == hash) {
- onCapsChanged(i->first);
- }
- }
+ // TODO: Use Boost.Bimap ?
+ for (std::map<JID,std::string>::const_iterator i = caps.begin(); i != caps.end(); ++i) {
+ if (i->second == hash) {
+ onCapsChanged(i->first);
+ }
+ }
}
DiscoInfo::ref EntityCapsManager::getCaps(const JID& jid) const {
- std::map<JID, std::string>::const_iterator i = caps.find(jid);
- if (i != caps.end()) {
- return capsProvider->getCaps(i->second);
- }
- return DiscoInfo::ref();
+ std::map<JID, std::string>::const_iterator i = caps.find(jid);
+ if (i != caps.end()) {
+ return capsProvider->getCaps(i->second);
+ }
+ return DiscoInfo::ref();
}
}
diff --git a/Swiften/Disco/EntityCapsManager.h b/Swiften/Disco/EntityCapsManager.h
index 2f6982f..4236326 100644
--- a/Swiften/Disco/EntityCapsManager.h
+++ b/Swiften/Disco/EntityCapsManager.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -8,39 +8,40 @@
#include <map>
+#include <boost/signals2.hpp>
+
#include <Swiften/Base/API.h>
-#include <Swiften/Base/boost_bsignals.h>
-#include <Swiften/Elements/Presence.h>
+#include <Swiften/Disco/EntityCapsProvider.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/ErrorPayload.h>
-#include <Swiften/Disco/EntityCapsProvider.h>
+#include <Swiften/Elements/Presence.h>
namespace Swift {
- class StanzaChannel;
- class CapsProvider;
-
- /**
- * This class is responsible for gathering and providing
- * information about capabilities of entities on the network.
- * This information is provided in the form of service discovery
- * information.
- */
- class SWIFTEN_API EntityCapsManager : public EntityCapsProvider, public boost::bsignals::trackable {
- public:
- EntityCapsManager(CapsProvider*, StanzaChannel*);
-
- /**
- * Returns the service discovery information of the given JID.
- */
- DiscoInfo::ref getCaps(const JID&) const;
-
- private:
- void handlePresenceReceived(boost::shared_ptr<Presence>);
- void handleStanzaChannelAvailableChanged(bool);
- void handleCapsAvailable(const std::string&);
-
- private:
- CapsProvider* capsProvider;
- std::map<JID, std::string> caps;
- };
+ class StanzaChannel;
+ class CapsProvider;
+
+ /**
+ * This class is responsible for gathering and providing
+ * information about capabilities of entities on the network.
+ * This information is provided in the form of service discovery
+ * information.
+ */
+ class SWIFTEN_API EntityCapsManager : public EntityCapsProvider, public boost::signals2::trackable {
+ public:
+ EntityCapsManager(CapsProvider*, StanzaChannel*);
+
+ /**
+ * Returns the service discovery information of the given JID.
+ */
+ DiscoInfo::ref getCaps(const JID&) const;
+
+ private:
+ void handlePresenceReceived(std::shared_ptr<Presence>);
+ void handleStanzaChannelAvailableChanged(bool);
+ void handleCapsAvailable(const std::string&);
+
+ private:
+ CapsProvider* capsProvider;
+ std::map<JID, std::string> caps;
+ };
}
diff --git a/Swiften/Disco/EntityCapsProvider.h b/Swiften/Disco/EntityCapsProvider.h
index 0e34f02..5f4af18 100644
--- a/Swiften/Disco/EntityCapsProvider.h
+++ b/Swiften/Disco/EntityCapsProvider.h
@@ -1,34 +1,35 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
+#include <boost/signals2.hpp>
+
#include <Swiften/Base/API.h>
-#include <Swiften/Base/boost_bsignals.h>
-#include <Swiften/JID/JID.h>
#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/JID/JID.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 SWIFTEN_API EntityCapsProvider {
- public:
- virtual ~EntityCapsProvider();
+ /**
+ * This class provides information about capabilities of entities on the network.
+ * This information is provided in the form of service discovery
+ * information.
+ */
+ class SWIFTEN_API EntityCapsProvider {
+ public:
+ virtual ~EntityCapsProvider();
- /**
- * Returns the service discovery information of the given JID.
- */
- virtual DiscoInfo::ref getCaps(const JID&) const = 0;
+ /**
+ * 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;
- };
+ /**
+ * Emitted when the capabilities of a JID changes.
+ */
+ boost::signals2::signal<void (const JID&)> onCapsChanged;
+ };
}
diff --git a/Swiften/Disco/FeatureOracle.cpp b/Swiften/Disco/FeatureOracle.cpp
index 4e61aa9..2baf87c 100644
--- a/Swiften/Disco/FeatureOracle.cpp
+++ b/Swiften/Disco/FeatureOracle.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015 Isode Limited.
+ * Copyright (c) 2015-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -8,10 +8,12 @@
#include <algorithm>
#include <iterator>
+#include <unordered_set>
#include <vector>
-#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/Log.h>
#include <Swiften/Disco/EntityCapsProvider.h>
+#include <Swiften/Elements/Idle.h>
#include <Swiften/Elements/Presence.h>
#include <Swiften/FileTransfer/FileTransferManager.h>
#include <Swiften/JID/JID.h>
@@ -20,78 +22,178 @@
namespace Swift {
FeatureOracle::FeatureOracle(EntityCapsProvider* capsProvider, PresenceOracle* presenceOracle) : capsProvider_(capsProvider), presenceOracle_(presenceOracle) {
-
}
Tristate FeatureOracle::isFileTransferSupported(const JID& jid) {
- DiscoInfo::ref discoInfo = getDiscoResultForJID(jid);
- if (discoInfo) {
- return FileTransferManager::isSupportedBy(discoInfo) ? Yes : No;
- }
- else {
- return Maybe;
- }
+ Tristate fileTransferSupported = No;
+
+ auto isYesOrMaybe = [](Tristate tristate) { return tristate == Yes || tristate == Maybe; };
+ auto isYes = [](Tristate tristate) { return tristate == Yes; };
+
+ auto supportedFeatures = getFeaturesForJID(jid);
+
+ auto jingleSupported = isFeatureSupported(supportedFeatures, DiscoInfo::JingleFeature);
+ auto jingleFTSupported = isFeatureSupported(supportedFeatures, DiscoInfo::JingleFTFeature);
+ auto jingleTransportIBBSupported = isFeatureSupported(supportedFeatures, DiscoInfo::JingleTransportsIBBFeature);
+ auto jingleTransportS5BSupported = isFeatureSupported(supportedFeatures, DiscoInfo::JingleTransportsS5BFeature);
+
+ if (isYes(jingleSupported) && isYes(jingleFTSupported) && (isYes(jingleTransportIBBSupported) || isYes(jingleTransportS5BSupported))) {
+ fileTransferSupported = Yes;
+ }
+ else if (isYesOrMaybe(jingleSupported) && isYesOrMaybe(jingleFTSupported) && (isYesOrMaybe(jingleTransportIBBSupported) || isYesOrMaybe(jingleTransportS5BSupported))) {
+ fileTransferSupported = Maybe;
+ }
+
+ return fileTransferSupported;
}
Tristate FeatureOracle::isMessageReceiptsSupported(const JID& jid) {
- return isFeatureSupported(jid, DiscoInfo::MessageDeliveryReceiptsFeature);
+ return isFeatureSupported(getFeaturesForJID(jid), DiscoInfo::MessageDeliveryReceiptsFeature);
}
Tristate FeatureOracle::isMessageCorrectionSupported(const JID& jid) {
- return isFeatureSupported(jid, DiscoInfo::MessageCorrectionFeature);
+ return isFeatureSupported(getFeaturesForJID(jid), DiscoInfo::MessageCorrectionFeature);
+}
+
+Tristate FeatureOracle::isWhiteboardSupported(const JID& jid) {
+ return isFeatureSupported(getFeaturesForJID(jid), DiscoInfo::WhiteboardFeature);
+}
+
+class PresenceFeatureAvailablityComparator {
+ public:
+ static int preferenceFromStatusShow(StatusShow::Type showType) {
+ switch (showType) {
+ case StatusShow::FFC:
+ return 5;
+ case StatusShow::Online:
+ return 4;
+ case StatusShow::DND:
+ return 3;
+ case StatusShow::Away:
+ return 2;
+ case StatusShow::XA:
+ return 1;
+ case StatusShow::None:
+ return 0;
+ }
+ assert(false);
+ return -1;
+ }
+
+ static int compareWithoutResource(const Presence::ref& a, const Presence::ref& b) {
+ int aPreference = preferenceFromStatusShow(a->getShow());
+ int bPreference = preferenceFromStatusShow(b->getShow());
+
+ if (aPreference != bPreference) {
+ return aPreference < bPreference ? 1 : -1;
+ }
+
+ Idle::ref aIdle = a->getPayload<Idle>();
+ Idle::ref bIdle = b->getPayload<Idle>();
+
+ if (aIdle && !bIdle) {
+ return -1;
+ }
+ else if (!aIdle && bIdle) {
+ return 1;
+ }
+
+ if (a->getPriority() != b->getPriority()) {
+ return a->getPriority() < b->getPriority() ? 1 : -1;
+ }
+
+ return 0;
+ }
+
+ /*
+ * This method returns true, if \ref Presence \p b is more available than
+ * \ref Presence \p a.
+ * Going by \ref StatusShow::Type first, then by idle state, then by
+ * presence priority and finally by resource name.
+ */
+ bool operator()(const Presence::ref& a, const Presence::ref& b) {
+ int aMoreAvailableThanB = compareWithoutResource(a, b);
+ if (aMoreAvailableThanB < 0) {
+ return true;
+ }
+ else if (aMoreAvailableThanB > 0) {
+ return false;
+ }
+
+ return a->getFrom().getResource() < b->getFrom().getResource();
+ }
+};
+
+JID FeatureOracle::getMostAvailableClientForFileTrasfer(const JID& bareJID) {
+ JID fullJID;
+ assert(bareJID.isBare());
+
+ std::vector<Presence::ref> allPresences = presenceOracle_->getAllPresence(bareJID);
+ std::sort(allPresences.begin(), allPresences.end(), PresenceFeatureAvailablityComparator());
+
+ for (const auto& presence : allPresences) {
+ if (presence->isAvailable()) {
+ if (isFileTransferSupported(presence->getFrom()) == Yes) {
+ fullJID = presence->getFrom();
+ break;
+ }
+ }
+ }
+
+ SWIFT_LOG_ASSERT(!fullJID.isBare(), error);
+ return fullJID;
}
-DiscoInfo::ref FeatureOracle::getDiscoResultForJID(const JID& jid) {
- DiscoInfo::ref discoInfo;
- if (jid.isBare()) {
- // Calculate the common subset of disco features of all available results and return that.
- std::vector<Presence::ref> availablePresences = presenceOracle_->getAllPresence(jid);
-
- bool commonFeaturesInitialized = false;
- std::vector<std::string> commonFeatures;
- foreach(Presence::ref presence, availablePresences) {
- DiscoInfo::ref presenceDiscoInfo = capsProvider_->getCaps(presence->getFrom());
- if (presenceDiscoInfo) {
- std::vector<std::string> features = presenceDiscoInfo->getFeatures();
- if (!commonFeaturesInitialized) {
- commonFeatures = features;
- commonFeaturesInitialized = true;
- }
- else {
- std::vector<std::string> featuresToRemove;
- foreach(const std::string& feature, commonFeatures) {
- if (std::find(features.begin(), features.end(), feature) == features.end()) {
- featuresToRemove.push_back(feature);
- }
- }
- foreach(const std::string& featureToRemove, featuresToRemove) {
- commonFeatures.erase(std::remove(commonFeatures.begin(), commonFeatures.end(), featureToRemove), commonFeatures.end());
- }
- }
- }
- }
- discoInfo = boost::make_shared<DiscoInfo>();
-
- foreach(const std::string& commonFeature, commonFeatures) {
- discoInfo->addFeature(commonFeature);
- }
- }
- else {
- // Return the disco result of the full JID.
- discoInfo = capsProvider_->getCaps(jid);
- }
-
- return discoInfo;
+std::unordered_map<std::string, Tristate> FeatureOracle::getFeaturesForJID(const JID& jid) {
+ std::unordered_map<std::string, Tristate> supportedFeatures;
+ if (jid.isBare()) {
+ // Calculate the union of disco features of all most available results and return that.
+ std::vector<DiscoInfo::ref> onlineDiscoInfos;
+ std::unordered_set<std::string> features;
+
+ // Collect relevant disco info results and the set of features.
+ for (auto&& presence : presenceOracle_->getAllPresence(jid)) {
+ if (presence->getType() == Presence::Available) {
+ DiscoInfo::ref presenceDiscoInfo = capsProvider_->getCaps(presence->getFrom());
+ if (presenceDiscoInfo) {
+ onlineDiscoInfos.push_back(presenceDiscoInfo);
+ features.insert(presenceDiscoInfo->getFeatures().begin(), presenceDiscoInfo->getFeatures().end());
+ }
+ }
+ }
+
+ // Calculate supportedFeaturesMap.
+ for (auto&& feature : features) {
+ Tristate supported = Yes;
+ for (auto&& discoInfo : onlineDiscoInfos) {
+ if (!discoInfo->hasFeature(feature)) {
+ supported = Maybe;
+ break;
+ }
+ }
+ supportedFeatures[feature] = supported;
+ }
+ }
+ else {
+ // Return the disco result of the full JID.
+ auto discoInfo = capsProvider_->getCaps(jid);
+ if (discoInfo) {
+ for (auto&& feature : discoInfo->getFeatures()) {
+ supportedFeatures[feature] = Yes;
+ }
+ }
+ }
+
+ return supportedFeatures;
}
-Tristate FeatureOracle::isFeatureSupported(const JID& jid, const std::string& feature) {
- DiscoInfo::ref discoInfo = getDiscoResultForJID(jid);
- if (discoInfo) {
- return discoInfo->hasFeature(feature) ? Yes : No;
- }
- else {
- return Maybe;
- }
+Tristate FeatureOracle::isFeatureSupported(const std::unordered_map<std::string, Tristate>& supportedFeatures, const std::string& feature) {
+ Tristate supported = No;
+ auto lookupResult = supportedFeatures.find(feature);
+ if (lookupResult != supportedFeatures.end()) {
+ supported = lookupResult->second;
+ }
+ return supported;
}
}
diff --git a/Swiften/Disco/FeatureOracle.h b/Swiften/Disco/FeatureOracle.h
index d579e5a..be0cd6f 100644
--- a/Swiften/Disco/FeatureOracle.h
+++ b/Swiften/Disco/FeatureOracle.h
@@ -1,11 +1,14 @@
/*
- * Copyright (c) 2015 Isode Limited.
+ * Copyright (c) 2015-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
+#include <unordered_map>
+#include <unordered_set>
+
#include <Swiften/Base/API.h>
#include <Swiften/Base/Tristate.h>
#include <Swiften/Elements/DiscoInfo.h>
@@ -20,27 +23,30 @@ class PresenceOracle;
* @brief The FeatureOracle class enables direct feature support lookup for client features supported by Swiften.
*/
class SWIFTEN_API FeatureOracle {
- public:
- FeatureOracle(EntityCapsProvider* capsProvider, PresenceOracle* presenceOracle);
-
- public:
- Tristate isFileTransferSupported(const JID& jid);
- Tristate isMessageReceiptsSupported(const JID& jid);
- Tristate isMessageCorrectionSupported(const JID& jid);
-
- private:
- /**
- * @brief getDiscoResultForJID returns a shared reference to a DiscoInfo representing features supported by the jid.
- * @param jid The JID to return the DiscoInfo::ref for.
- * @return DiscoResult::ref
- */
- DiscoInfo::ref getDiscoResultForJID(const JID& jid);
-
- Tristate isFeatureSupported(const JID& jid, const std::string& feature);
-
- private:
- EntityCapsProvider* capsProvider_;
- PresenceOracle* presenceOracle_;
+ public:
+ FeatureOracle(EntityCapsProvider* capsProvider, PresenceOracle* presenceOracle);
+
+ public:
+ Tristate isFileTransferSupported(const JID& jid);
+ Tristate isMessageReceiptsSupported(const JID& jid);
+ Tristate isMessageCorrectionSupported(const JID& jid);
+ Tristate isWhiteboardSupported(const JID& jid);
+
+ JID getMostAvailableClientForFileTrasfer(const JID& bareJID);
+
+ private:
+ /**
+ * @brief getDiscoResultForJID returns a shared reference to a DiscoInfo representing features supported by the jid.
+ * @param jid The JID to return an std::unordered_map<std::string, Tristate> for.
+ * @return std::unordered_map<std::string, Tristate>
+ */
+ std::unordered_map<std::string, Tristate> getFeaturesForJID(const JID& jid);
+
+ Tristate isFeatureSupported(const std::unordered_map<std::string, Tristate>& supportedFeatures, const std::string& feature);
+
+ private:
+ EntityCapsProvider* capsProvider_;
+ PresenceOracle* presenceOracle_;
};
}
diff --git a/Swiften/Disco/GetDiscoInfoRequest.h b/Swiften/Disco/GetDiscoInfoRequest.h
index a3c1415..1d86c14 100644
--- a/Swiften/Disco/GetDiscoInfoRequest.h
+++ b/Swiften/Disco/GetDiscoInfoRequest.h
@@ -1,38 +1,38 @@
/*
- * Copyright (c) 2010-2015 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
-#include <boost/smart_ptr/make_shared.hpp>
+#include <memory>
#include <Swiften/Base/API.h>
-#include <Swiften/Queries/GenericRequest.h>
#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Queries/GenericRequest.h>
namespace Swift {
- class SWIFTEN_API GetDiscoInfoRequest : public GenericRequest<DiscoInfo> {
- public:
- typedef boost::shared_ptr<GetDiscoInfoRequest> ref;
-
- static ref create(const JID& jid, IQRouter* router) {
- return ref(new GetDiscoInfoRequest(jid, router));
- }
-
- static ref create(const JID& jid, const std::string& node, IQRouter* router) {
- return ref(new GetDiscoInfoRequest(jid, node, router));
- }
-
- private:
- GetDiscoInfoRequest(const JID& jid, IQRouter* router) :
- GenericRequest<DiscoInfo>(IQ::Get, jid, boost::make_shared<DiscoInfo>(), router) {
- }
-
- GetDiscoInfoRequest(const JID& jid, const std::string& node, IQRouter* router) :
- GenericRequest<DiscoInfo>(IQ::Get, jid, boost::make_shared<DiscoInfo>(), router) {
- getPayloadGeneric()->setNode(node);
- }
- };
+ class SWIFTEN_API GetDiscoInfoRequest : public GenericRequest<DiscoInfo> {
+ public:
+ typedef std::shared_ptr<GetDiscoInfoRequest> ref;
+
+ static ref create(const JID& jid, IQRouter* router) {
+ return ref(new GetDiscoInfoRequest(jid, router));
+ }
+
+ static ref create(const JID& jid, const std::string& node, IQRouter* router) {
+ return ref(new GetDiscoInfoRequest(jid, node, router));
+ }
+
+ private:
+ GetDiscoInfoRequest(const JID& jid, IQRouter* router) :
+ GenericRequest<DiscoInfo>(IQ::Get, jid, std::make_shared<DiscoInfo>(), router) {
+ }
+
+ GetDiscoInfoRequest(const JID& jid, const std::string& node, IQRouter* router) :
+ GenericRequest<DiscoInfo>(IQ::Get, jid, std::make_shared<DiscoInfo>(), router) {
+ getPayloadGeneric()->setNode(node);
+ }
+ };
}
diff --git a/Swiften/Disco/GetDiscoItemsRequest.h b/Swiften/Disco/GetDiscoItemsRequest.h
index a9cf38b..5b1ccf2 100644
--- a/Swiften/Disco/GetDiscoItemsRequest.h
+++ b/Swiften/Disco/GetDiscoItemsRequest.h
@@ -1,38 +1,38 @@
/*
- * Copyright (c) 2010-2015 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
-#include <boost/smart_ptr/make_shared.hpp>
+#include <memory>
#include <Swiften/Base/API.h>
-#include <Swiften/Queries/GenericRequest.h>
#include <Swiften/Elements/DiscoItems.h>
+#include <Swiften/Queries/GenericRequest.h>
namespace Swift {
- class SWIFTEN_API GetDiscoItemsRequest : public GenericRequest<DiscoItems> {
- public:
- typedef boost::shared_ptr<GetDiscoItemsRequest> ref;
-
- static ref create(const JID& jid, IQRouter* router) {
- return ref(new GetDiscoItemsRequest(jid, router));
- }
-
- static ref create(const JID& jid, const std::string& node, IQRouter* router) {
- return ref(new GetDiscoItemsRequest(jid, node, router));
- }
-
- private:
- GetDiscoItemsRequest(const JID& jid, IQRouter* router) :
- GenericRequest<DiscoItems>(IQ::Get, jid, boost::make_shared<DiscoItems>(), router) {
- }
-
- GetDiscoItemsRequest(const JID& jid, const std::string& node, IQRouter* router) :
- GenericRequest<DiscoItems>(IQ::Get, jid, boost::make_shared<DiscoItems>(), router) {
- getPayloadGeneric()->setNode(node);
- }
- };
+ class SWIFTEN_API GetDiscoItemsRequest : public GenericRequest<DiscoItems> {
+ public:
+ typedef std::shared_ptr<GetDiscoItemsRequest> ref;
+
+ static ref create(const JID& jid, IQRouter* router) {
+ return ref(new GetDiscoItemsRequest(jid, router));
+ }
+
+ static ref create(const JID& jid, const std::string& node, IQRouter* router) {
+ return ref(new GetDiscoItemsRequest(jid, node, router));
+ }
+
+ private:
+ GetDiscoItemsRequest(const JID& jid, IQRouter* router) :
+ GenericRequest<DiscoItems>(IQ::Get, jid, std::make_shared<DiscoItems>(), router) {
+ }
+
+ GetDiscoItemsRequest(const JID& jid, const std::string& node, IQRouter* router) :
+ GenericRequest<DiscoItems>(IQ::Get, jid, std::make_shared<DiscoItems>(), router) {
+ getPayloadGeneric()->setNode(node);
+ }
+ };
}
diff --git a/Swiften/Disco/JIDDiscoInfoResponder.cpp b/Swiften/Disco/JIDDiscoInfoResponder.cpp
index 6a632cf..8802bce 100644
--- a/Swiften/Disco/JIDDiscoInfoResponder.cpp
+++ b/Swiften/Disco/JIDDiscoInfoResponder.cpp
@@ -1,14 +1,15 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#include <boost/smart_ptr/make_shared.hpp>
-
#include <Swiften/Disco/JIDDiscoInfoResponder.h>
-#include <Swiften/Queries/IQRouter.h>
+
+#include <memory>
+
#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Queries/IQRouter.h>
namespace Swift {
@@ -16,41 +17,41 @@ JIDDiscoInfoResponder::JIDDiscoInfoResponder(IQRouter* router) : GetResponder<Di
}
void JIDDiscoInfoResponder::clearDiscoInfo(const JID& jid) {
- info.erase(jid);
+ info.erase(jid);
}
void JIDDiscoInfoResponder::setDiscoInfo(const JID& jid, const DiscoInfo& discoInfo) {
- JIDDiscoInfoMap::iterator i = info.insert(std::make_pair(jid, JIDDiscoInfo())).first;
- i->second.discoInfo = discoInfo;
+ JIDDiscoInfoMap::iterator i = info.insert(std::make_pair(jid, JIDDiscoInfo())).first;
+ i->second.discoInfo = discoInfo;
}
void JIDDiscoInfoResponder::setDiscoInfo(const JID& jid, const std::string& node, const DiscoInfo& discoInfo) {
- JIDDiscoInfoMap::iterator i = info.insert(std::make_pair(jid, JIDDiscoInfo())).first;
- DiscoInfo newInfo(discoInfo);
- newInfo.setNode(node);
- i->second.nodeDiscoInfo[node] = newInfo;
+ JIDDiscoInfoMap::iterator i = info.insert(std::make_pair(jid, JIDDiscoInfo())).first;
+ DiscoInfo newInfo(discoInfo);
+ newInfo.setNode(node);
+ i->second.nodeDiscoInfo[node] = newInfo;
}
-bool JIDDiscoInfoResponder::handleGetRequest(const JID& from, const JID& to, const std::string& id, boost::shared_ptr<DiscoInfo> discoInfo) {
- JIDDiscoInfoMap::const_iterator i = info.find(to);
- if (i != info.end()) {
- if (discoInfo->getNode().empty()) {
- sendResponse(from, to, id, boost::make_shared<DiscoInfo>(i->second.discoInfo));
- }
- else {
- std::map<std::string,DiscoInfo>::const_iterator j = i->second.nodeDiscoInfo.find(discoInfo->getNode());
- if (j != i->second.nodeDiscoInfo.end()) {
- sendResponse(from, to, id, boost::make_shared<DiscoInfo>(j->second));
- }
- else {
- sendError(from, to, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel);
- }
- }
- }
- else {
- sendError(from, to, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel);
- }
- return true;
+bool JIDDiscoInfoResponder::handleGetRequest(const JID& from, const JID& to, const std::string& id, std::shared_ptr<DiscoInfo> discoInfo) {
+ JIDDiscoInfoMap::const_iterator i = info.find(to);
+ if (i != info.end()) {
+ if (discoInfo->getNode().empty()) {
+ sendResponse(from, to, id, std::make_shared<DiscoInfo>(i->second.discoInfo));
+ }
+ else {
+ std::map<std::string,DiscoInfo>::const_iterator j = i->second.nodeDiscoInfo.find(discoInfo->getNode());
+ if (j != i->second.nodeDiscoInfo.end()) {
+ sendResponse(from, to, id, std::make_shared<DiscoInfo>(j->second));
+ }
+ else {
+ sendError(from, to, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel);
+ }
+ }
+ }
+ else {
+ sendError(from, to, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel);
+ }
+ return true;
}
}
diff --git a/Swiften/Disco/JIDDiscoInfoResponder.h b/Swiften/Disco/JIDDiscoInfoResponder.h
index 2f184bf..1eb6228 100644
--- a/Swiften/Disco/JIDDiscoInfoResponder.h
+++ b/Swiften/Disco/JIDDiscoInfoResponder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -9,30 +9,30 @@
#include <map>
#include <Swiften/Base/API.h>
-#include <Swiften/Queries/GetResponder.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/JID/JID.h>
+#include <Swiften/Queries/GetResponder.h>
namespace Swift {
- class IQRouter;
-
- class SWIFTEN_API JIDDiscoInfoResponder : public GetResponder<DiscoInfo> {
- public:
- JIDDiscoInfoResponder(IQRouter* router);
-
- void clearDiscoInfo(const JID& jid);
- void setDiscoInfo(const JID& jid, const DiscoInfo& info);
- void setDiscoInfo(const JID& jid, const std::string& node, const DiscoInfo& info);
-
- private:
- virtual bool handleGetRequest(const JID& from, const JID& to, const std::string& id, boost::shared_ptr<DiscoInfo> payload);
-
- private:
- struct JIDDiscoInfo {
- DiscoInfo discoInfo;
- std::map<std::string, DiscoInfo> nodeDiscoInfo;
- };
- typedef std::map<JID, JIDDiscoInfo> JIDDiscoInfoMap;
- JIDDiscoInfoMap info;
- };
+ class IQRouter;
+
+ class SWIFTEN_API JIDDiscoInfoResponder : public GetResponder<DiscoInfo> {
+ public:
+ JIDDiscoInfoResponder(IQRouter* router);
+
+ void clearDiscoInfo(const JID& jid);
+ void setDiscoInfo(const JID& jid, const DiscoInfo& info);
+ void setDiscoInfo(const JID& jid, const std::string& node, const DiscoInfo& info);
+
+ private:
+ virtual bool handleGetRequest(const JID& from, const JID& to, const std::string& id, std::shared_ptr<DiscoInfo> payload);
+
+ private:
+ struct JIDDiscoInfo {
+ DiscoInfo discoInfo;
+ std::map<std::string, DiscoInfo> nodeDiscoInfo;
+ };
+ typedef std::map<JID, JIDDiscoInfo> JIDDiscoInfoMap;
+ JIDDiscoInfoMap info;
+ };
}
diff --git a/Swiften/Disco/SConscript b/Swiften/Disco/SConscript
index 1779e26..15137ae 100644
--- a/Swiften/Disco/SConscript
+++ b/Swiften/Disco/SConscript
@@ -1,16 +1,16 @@
Import("swiften_env")
objects = swiften_env.SwiftenObject([
- "CapsInfoGenerator.cpp",
- "CapsManager.cpp",
- "EntityCapsManager.cpp",
- "EntityCapsProvider.cpp",
- "DummyEntityCapsProvider.cpp",
- "CapsStorage.cpp",
- "ClientDiscoManager.cpp",
- "DiscoInfoResponder.cpp",
- "JIDDiscoInfoResponder.cpp",
- "DiscoServiceWalker.cpp",
- "FeatureOracle.cpp",
- ])
+ "CapsInfoGenerator.cpp",
+ "CapsManager.cpp",
+ "EntityCapsManager.cpp",
+ "EntityCapsProvider.cpp",
+ "DummyEntityCapsProvider.cpp",
+ "CapsStorage.cpp",
+ "ClientDiscoManager.cpp",
+ "DiscoInfoResponder.cpp",
+ "JIDDiscoInfoResponder.cpp",
+ "DiscoServiceWalker.cpp",
+ "FeatureOracle.cpp",
+ ])
swiften_env.Append(SWIFTEN_OBJECTS = [objects])
diff --git a/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp b/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp
index 328c367..8d27ec5 100644
--- a/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp
+++ b/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -7,80 +7,80 @@
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
-#include <Swiften/Elements/DiscoInfo.h>
-#include <Swiften/Disco/CapsInfoGenerator.h>
#include <Swiften/Crypto/CryptoProvider.h>
#include <Swiften/Crypto/PlatformCryptoProvider.h>
+#include <Swiften/Disco/CapsInfoGenerator.h>
+#include <Swiften/Elements/DiscoInfo.h>
using namespace Swift;
class CapsInfoGeneratorTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(CapsInfoGeneratorTest);
- CPPUNIT_TEST(testGenerate_XEP0115SimpleExample);
- CPPUNIT_TEST(testGenerate_XEP0115ComplexExample);
- CPPUNIT_TEST_SUITE_END();
+ CPPUNIT_TEST_SUITE(CapsInfoGeneratorTest);
+ CPPUNIT_TEST(testGenerate_XEP0115SimpleExample);
+ CPPUNIT_TEST(testGenerate_XEP0115ComplexExample);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ crypto = std::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
+ }
- public:
- void setUp() {
- crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
- }
+ void testGenerate_XEP0115SimpleExample() {
+ DiscoInfo discoInfo;
+ discoInfo.addIdentity(DiscoInfo::Identity("Exodus 0.9.1", "client", "pc"));
+ discoInfo.addFeature("http://jabber.org/protocol/disco#items");
+ discoInfo.addFeature("http://jabber.org/protocol/caps");
+ discoInfo.addFeature("http://jabber.org/protocol/disco#info");
+ discoInfo.addFeature("http://jabber.org/protocol/muc");
- void testGenerate_XEP0115SimpleExample() {
- DiscoInfo discoInfo;
- discoInfo.addIdentity(DiscoInfo::Identity("Exodus 0.9.1", "client", "pc"));
- discoInfo.addFeature("http://jabber.org/protocol/disco#items");
- discoInfo.addFeature("http://jabber.org/protocol/caps");
- discoInfo.addFeature("http://jabber.org/protocol/disco#info");
- discoInfo.addFeature("http://jabber.org/protocol/muc");
+ CapsInfoGenerator testling("http://code.google.com/p/exodus", crypto.get());
+ CapsInfo result = testling.generateCapsInfo(discoInfo);
- CapsInfoGenerator testling("http://code.google.com/p/exodus", crypto.get());
- CapsInfo result = testling.generateCapsInfo(discoInfo);
+ CPPUNIT_ASSERT_EQUAL(std::string("http://code.google.com/p/exodus"), result.getNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), result.getHash());
+ CPPUNIT_ASSERT_EQUAL(std::string("QgayPKawpkPSDYmwT/WM94uAlu0="), result.getVersion());
+ }
- CPPUNIT_ASSERT_EQUAL(std::string("http://code.google.com/p/exodus"), result.getNode());
- CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), result.getHash());
- CPPUNIT_ASSERT_EQUAL(std::string("QgayPKawpkPSDYmwT/WM94uAlu0="), result.getVersion());
- }
+ void testGenerate_XEP0115ComplexExample() {
+ DiscoInfo discoInfo;
+ discoInfo.addIdentity(DiscoInfo::Identity("Psi 0.11", "client", "pc", "en"));
+ discoInfo.addIdentity(DiscoInfo::Identity("\xce\xa8 0.11", "client", "pc", "el"));
+ discoInfo.addFeature("http://jabber.org/protocol/disco#items");
+ discoInfo.addFeature("http://jabber.org/protocol/caps");
+ discoInfo.addFeature("http://jabber.org/protocol/disco#info");
+ discoInfo.addFeature("http://jabber.org/protocol/muc");
- void testGenerate_XEP0115ComplexExample() {
- DiscoInfo discoInfo;
- discoInfo.addIdentity(DiscoInfo::Identity("Psi 0.11", "client", "pc", "en"));
- discoInfo.addIdentity(DiscoInfo::Identity("\xce\xa8 0.11", "client", "pc", "el"));
- discoInfo.addFeature("http://jabber.org/protocol/disco#items");
- discoInfo.addFeature("http://jabber.org/protocol/caps");
- discoInfo.addFeature("http://jabber.org/protocol/disco#info");
- discoInfo.addFeature("http://jabber.org/protocol/muc");
+ Form::ref extension(new Form(Form::ResultType));
+ FormField::ref field = std::make_shared<FormField>(FormField::HiddenType, "urn:xmpp:dataforms:softwareinfo");
+ field->setName("FORM_TYPE");
+ extension->addField(field);
+ field = std::make_shared<FormField>(FormField::ListMultiType);
+ field->addValue("ipv6");
+ field->addValue("ipv4");
+ field->setName("ip_version");
+ extension->addField(field);
+ field = std::make_shared<FormField>(FormField::TextSingleType, "Psi");
+ field->setName("software");
+ extension->addField(field);
+ field = std::make_shared<FormField>(FormField::TextSingleType, "0.11");
+ field->setName("software_version");
+ extension->addField(field);
+ field = std::make_shared<FormField>(FormField::TextSingleType, "Mac");
+ field->setName("os");
+ extension->addField(field);
+ field = std::make_shared<FormField>(FormField::TextSingleType, "10.5.1");
+ field->setName("os_version");
+ extension->addField(field);
+ discoInfo.addExtension(extension);
- Form::ref extension(new Form(Form::ResultType));
- FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "urn:xmpp:dataforms:softwareinfo");
- field->setName("FORM_TYPE");
- extension->addField(field);
- field = boost::make_shared<FormField>(FormField::ListMultiType);
- field->addValue("ipv6");
- field->addValue("ipv4");
- field->setName("ip_version");
- extension->addField(field);
- field = boost::make_shared<FormField>(FormField::TextSingleType, "Psi");
- field->setName("software");
- extension->addField(field);
- field = boost::make_shared<FormField>(FormField::TextSingleType, "0.11");
- field->setName("software_version");
- extension->addField(field);
- field = boost::make_shared<FormField>(FormField::TextSingleType, "Mac");
- field->setName("os");
- extension->addField(field);
- field = boost::make_shared<FormField>(FormField::TextSingleType, "10.5.1");
- field->setName("os_version");
- extension->addField(field);
- discoInfo.addExtension(extension);
+ CapsInfoGenerator testling("http://psi-im.org", crypto.get());
+ CapsInfo result = testling.generateCapsInfo(discoInfo);
- CapsInfoGenerator testling("http://psi-im.org", crypto.get());
- CapsInfo result = testling.generateCapsInfo(discoInfo);
+ CPPUNIT_ASSERT_EQUAL(std::string("q07IKJEyjvHSyhy//CH0CxmKi8w="), result.getVersion());
+ }
- CPPUNIT_ASSERT_EQUAL(std::string("q07IKJEyjvHSyhy//CH0CxmKi8w="), result.getVersion());
- }
-
- private:
- boost::shared_ptr<CryptoProvider> crypto;
+ private:
+ std::shared_ptr<CryptoProvider> crypto;
};
CPPUNIT_TEST_SUITE_REGISTRATION(CapsInfoGeneratorTest);
diff --git a/Swiften/Disco/UnitTest/CapsManagerTest.cpp b/Swiften/Disco/UnitTest/CapsManagerTest.cpp
index 5841ef4..153e821 100644
--- a/Swiften/Disco/UnitTest/CapsManagerTest.cpp
+++ b/Swiften/Disco/UnitTest/CapsManagerTest.cpp
@@ -1,290 +1,291 @@
/*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <memory>
#include <vector>
+
#include <boost/bind.hpp>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Crypto/CryptoProvider.h>
+#include <Swiften/Crypto/PlatformCryptoProvider.h>
+#include <Swiften/Disco/CapsInfoGenerator.h>
#include <Swiften/Disco/CapsManager.h>
#include <Swiften/Disco/CapsMemoryStorage.h>
-#include <Swiften/Disco/CapsInfoGenerator.h>
-#include <Swiften/Queries/IQRouter.h>
#include <Swiften/Elements/CapsInfo.h>
#include <Swiften/Elements/DiscoInfo.h>
-#include <Swiften/Client/DummyStanzaChannel.h>
-#include <Swiften/Crypto/CryptoProvider.h>
-#include <Swiften/Crypto/PlatformCryptoProvider.h>
+#include <Swiften/Queries/IQRouter.h>
using namespace Swift;
class CapsManagerTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(CapsManagerTest);
- CPPUNIT_TEST(testReceiveNewHashRequestsDisco);
- CPPUNIT_TEST(testReceiveSameHashDoesNotRequestDisco);
- CPPUNIT_TEST(testReceiveLegacyCapsDoesNotRequestDisco);
- CPPUNIT_TEST(testReceiveSameHashFromSameUserAfterFailedDiscoDoesNotRequestDisco);
- CPPUNIT_TEST(testReceiveSameHashFromDifferentUserAfterFailedDiscoRequestsDisco);
- CPPUNIT_TEST(testReceiveSameHashFromDifferentUserAfterIncorrectVerificationRequestsDisco);
- CPPUNIT_TEST(testReceiveDifferentHashFromSameUserAfterFailedDiscoDoesNotRequestDisco);
- CPPUNIT_TEST(testReceiveSameHashAfterSuccesfulDiscoDoesNotRequestDisco);
- CPPUNIT_TEST(testReceiveSuccesfulDiscoStoresCaps);
- CPPUNIT_TEST(testReceiveIncorrectVerificationDiscoDoesNotStoreCaps);
- CPPUNIT_TEST(testReceiveFailingDiscoFallsBack);
- CPPUNIT_TEST(testReceiveNoDiscoFallsBack);
- CPPUNIT_TEST(testReceiveFailingFallbackDiscoFallsBack);
- CPPUNIT_TEST(testReceiveSameHashFromFailingUserAfterReconnectRequestsDisco);
- CPPUNIT_TEST(testReconnectResetsFallback);
- CPPUNIT_TEST(testReconnectResetsRequests);
- CPPUNIT_TEST_SUITE_END();
-
- public:
- void setUp() {
- crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
- stanzaChannel = new DummyStanzaChannel();
- iqRouter = new IQRouter(stanzaChannel);
- storage = new CapsMemoryStorage();
- user1 = JID("user1@bar.com/bla");
- discoInfo1 = boost::make_shared<DiscoInfo>();
- discoInfo1->addFeature("http://swift.im/feature1");
- capsInfo1 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node1.im", crypto.get()).generateCapsInfo(*discoInfo1.get()));
- capsInfo1alt = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo1.get()));
- user2 = JID("user2@foo.com/baz");
- discoInfo2 = boost::make_shared<DiscoInfo>();
- discoInfo2->addFeature("http://swift.im/feature2");
- capsInfo2 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo2.get()));
- user3 = JID("user3@foo.com/baz");
- legacyCapsInfo = boost::make_shared<CapsInfo>("http://swift.im", "ver1", "");
- }
-
- void tearDown() {
- delete storage;
- delete iqRouter;
- delete stanzaChannel;
- }
-
- void testReceiveNewHashRequestsDisco() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
-
- CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get));
- boost::shared_ptr<DiscoInfo> discoInfo(stanzaChannel->sentStanzas[0]->getPayload<DiscoInfo>());
- CPPUNIT_ASSERT(discoInfo);
- CPPUNIT_ASSERT_EQUAL("http://node1.im#" + capsInfo1->getVersion(), discoInfo->getNode());
- }
-
- void testReceiveSameHashDoesNotRequestDisco() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- stanzaChannel->sentStanzas.clear();
- sendPresenceWithCaps(user1, capsInfo1);
-
- CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
- }
-
- void testReceiveLegacyCapsDoesNotRequestDisco() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, legacyCapsInfo);
-
- CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
- }
-
- void testReceiveSameHashAfterSuccesfulDiscoDoesNotRequestDisco() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- sendDiscoInfoResult(discoInfo1);
-
- stanzaChannel->sentStanzas.clear();
- sendPresenceWithCaps(user1, capsInfo1);
-
- CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
- }
-
- void testReceiveSameHashFromSameUserAfterFailedDiscoDoesNotRequestDisco() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getID()));
-
- stanzaChannel->sentStanzas.clear();
- sendPresenceWithCaps(user1, capsInfo1);
-
- CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
- }
-
- void testReceiveSameHashFromSameUserAfterIncorrectVerificationDoesNotRequestDisco() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- sendDiscoInfoResult(discoInfo2);
-
- stanzaChannel->sentStanzas.clear();
- sendPresenceWithCaps(user1, capsInfo1);
-
- CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
- }
-
- void testReceiveSameHashFromDifferentUserAfterFailedDiscoRequestsDisco() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID()));
-
- stanzaChannel->sentStanzas.clear();
- sendPresenceWithCaps(user2, capsInfo1);
- CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user2, IQ::Get));
- }
-
- void testReceiveSameHashFromDifferentUserAfterIncorrectVerificationRequestsDisco() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- sendDiscoInfoResult(discoInfo2);
-
- stanzaChannel->sentStanzas.clear();
- sendPresenceWithCaps(user2, capsInfo1);
- CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user2, IQ::Get));
- }
-
- void testReceiveDifferentHashFromSameUserAfterFailedDiscoDoesNotRequestDisco() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getID()));
-
- stanzaChannel->sentStanzas.clear();
- sendPresenceWithCaps(user1, capsInfo2);
-
- CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get));
- }
-
- void testReceiveSuccesfulDiscoStoresCaps() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- sendDiscoInfoResult(discoInfo1);
-
- boost::shared_ptr<DiscoInfo> discoInfo(storage->getDiscoInfo(capsInfo1->getVersion()));
- CPPUNIT_ASSERT(discoInfo);
- CPPUNIT_ASSERT(discoInfo->hasFeature("http://swift.im/feature1"));
- }
-
- void testReceiveIncorrectVerificationDiscoDoesNotStoreCaps() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- sendDiscoInfoResult(discoInfo2);
-
- boost::shared_ptr<DiscoInfo> discoInfo(storage->getDiscoInfo(capsInfo1->getVersion()));
- CPPUNIT_ASSERT(!discoInfo);
- }
-
- void testReceiveFailingDiscoFallsBack() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- sendPresenceWithCaps(user2, capsInfo1alt);
- stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID()));
-
- CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(1, user2, IQ::Get));
- boost::shared_ptr<DiscoInfo> discoInfo(stanzaChannel->sentStanzas[1]->getPayload<DiscoInfo>());
- CPPUNIT_ASSERT(discoInfo);
- CPPUNIT_ASSERT_EQUAL("http://node2.im#" + capsInfo1alt->getVersion(), discoInfo->getNode());
- }
-
- void testReceiveNoDiscoFallsBack() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- sendPresenceWithCaps(user2, capsInfo1alt);
- stanzaChannel->onIQReceived(IQ::createResult(JID("baz@fum.com/dum"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), boost::shared_ptr<DiscoInfo>()));
-
- CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(1, user2, IQ::Get));
- boost::shared_ptr<DiscoInfo> discoInfo(stanzaChannel->sentStanzas[1]->getPayload<DiscoInfo>());
- CPPUNIT_ASSERT(discoInfo);
- CPPUNIT_ASSERT_EQUAL("http://node2.im#" + capsInfo1alt->getVersion(), discoInfo->getNode());
- }
-
- void testReceiveFailingFallbackDiscoFallsBack() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- sendPresenceWithCaps(user2, capsInfo1alt);
- sendPresenceWithCaps(user3, capsInfo1);
- stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID()));
- stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[1]->getTo(), stanzaChannel->sentStanzas[1]->getID()));
-
- CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(2, user3, IQ::Get));
- }
-
- void testReceiveSameHashFromFailingUserAfterReconnectRequestsDisco() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID()));
- stanzaChannel->setAvailable(false);
- stanzaChannel->setAvailable(true);
- stanzaChannel->sentStanzas.clear();
-
- sendPresenceWithCaps(user1, capsInfo1);
-
- CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get));
- }
-
- void testReconnectResetsFallback() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- sendPresenceWithCaps(user2, capsInfo1alt);
- stanzaChannel->setAvailable(false);
- stanzaChannel->setAvailable(true);
- stanzaChannel->sentStanzas.clear();
- sendPresenceWithCaps(user1, capsInfo1);
- stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID()));
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size()));
- }
-
- void testReconnectResetsRequests() {
- boost::shared_ptr<CapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
- stanzaChannel->sentStanzas.clear();
- stanzaChannel->setAvailable(false);
- stanzaChannel->setAvailable(true);
- sendPresenceWithCaps(user1, capsInfo1);
-
- CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get));
- }
-
- private:
- boost::shared_ptr<CapsManager> createManager() {
- boost::shared_ptr<CapsManager> manager(new CapsManager(storage, stanzaChannel, iqRouter, crypto.get()));
- manager->setWarnOnInvalidHash(false);
- //manager->onCapsChanged.connect(boost::bind(&CapsManagerTest::handleCapsChanged, this, _1));
- return manager;
- }
-
- void handleCapsChanged(const JID& jid) {
- changes.push_back(jid);
- }
-
- void sendPresenceWithCaps(const JID& jid, boost::shared_ptr<CapsInfo> caps) {
- boost::shared_ptr<Presence> presence(new Presence());
- presence->setFrom(jid);
- presence->addPayload(caps);
- stanzaChannel->onPresenceReceived(presence);
- }
-
- void sendDiscoInfoResult(boost::shared_ptr<DiscoInfo> discoInfo) {
- stanzaChannel->onIQReceived(IQ::createResult(JID("baz@fum.com/dum"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), discoInfo));
- }
-
- private:
- DummyStanzaChannel* stanzaChannel;
- IQRouter* iqRouter;
- CapsStorage* storage;
- std::vector<JID> changes;
- JID user1;
- boost::shared_ptr<DiscoInfo> discoInfo1;
- boost::shared_ptr<CapsInfo> capsInfo1;
- boost::shared_ptr<CapsInfo> capsInfo1alt;
- JID user2;
- boost::shared_ptr<DiscoInfo> discoInfo2;
- boost::shared_ptr<CapsInfo> capsInfo2;
- boost::shared_ptr<CapsInfo> legacyCapsInfo;
- JID user3;
- boost::shared_ptr<CryptoProvider> crypto;
+ CPPUNIT_TEST_SUITE(CapsManagerTest);
+ CPPUNIT_TEST(testReceiveNewHashRequestsDisco);
+ CPPUNIT_TEST(testReceiveSameHashDoesNotRequestDisco);
+ CPPUNIT_TEST(testReceiveLegacyCapsDoesNotRequestDisco);
+ CPPUNIT_TEST(testReceiveSameHashFromSameUserAfterFailedDiscoDoesNotRequestDisco);
+ CPPUNIT_TEST(testReceiveSameHashFromDifferentUserAfterFailedDiscoRequestsDisco);
+ CPPUNIT_TEST(testReceiveSameHashFromDifferentUserAfterIncorrectVerificationRequestsDisco);
+ CPPUNIT_TEST(testReceiveDifferentHashFromSameUserAfterFailedDiscoDoesNotRequestDisco);
+ CPPUNIT_TEST(testReceiveSameHashAfterSuccesfulDiscoDoesNotRequestDisco);
+ CPPUNIT_TEST(testReceiveSuccesfulDiscoStoresCaps);
+ CPPUNIT_TEST(testReceiveIncorrectVerificationDiscoDoesNotStoreCaps);
+ CPPUNIT_TEST(testReceiveFailingDiscoFallsBack);
+ CPPUNIT_TEST(testReceiveNoDiscoFallsBack);
+ CPPUNIT_TEST(testReceiveFailingFallbackDiscoFallsBack);
+ CPPUNIT_TEST(testReceiveSameHashFromFailingUserAfterReconnectRequestsDisco);
+ CPPUNIT_TEST(testReconnectResetsFallback);
+ CPPUNIT_TEST(testReconnectResetsRequests);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ crypto = std::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
+ stanzaChannel = std::unique_ptr<DummyStanzaChannel>(new DummyStanzaChannel());
+ iqRouter = std::unique_ptr<IQRouter>(new IQRouter(stanzaChannel.get()));
+ storage = std::unique_ptr<CapsMemoryStorage>(new CapsMemoryStorage());
+ user1 = JID("user1@bar.com/bla");
+ discoInfo1 = std::make_shared<DiscoInfo>();
+ discoInfo1->addFeature("http://swift.im/feature1");
+ capsInfo1 = std::make_shared<CapsInfo>(CapsInfoGenerator("http://node1.im", crypto.get()).generateCapsInfo(*discoInfo1.get()));
+ capsInfo1alt = std::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo1.get()));
+ user2 = JID("user2@foo.com/baz");
+ discoInfo2 = std::make_shared<DiscoInfo>();
+ discoInfo2->addFeature("http://swift.im/feature2");
+ capsInfo2 = std::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo2.get()));
+ user3 = JID("user3@foo.com/baz");
+ legacyCapsInfo = std::make_shared<CapsInfo>("http://swift.im", "ver1", "");
+ }
+
+ void tearDown() {
+ iqRouter.reset();
+ }
+
+ void testReceiveNewHashRequestsDisco() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get));
+ std::shared_ptr<DiscoInfo> discoInfo(stanzaChannel->sentStanzas[0]->getPayload<DiscoInfo>());
+ CPPUNIT_ASSERT(discoInfo);
+ CPPUNIT_ASSERT_EQUAL("http://node1.im#" + capsInfo1->getVersion(), discoInfo->getNode());
+ }
+
+ void testReceiveSameHashDoesNotRequestDisco() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ stanzaChannel->sentStanzas.clear();
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ }
+
+ void testReceiveLegacyCapsDoesNotRequestDisco() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, legacyCapsInfo);
+
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ }
+
+ void testReceiveSameHashAfterSuccesfulDiscoDoesNotRequestDisco() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ sendDiscoInfoResult(discoInfo1);
+
+ stanzaChannel->sentStanzas.clear();
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ }
+
+ void testReceiveSameHashFromSameUserAfterFailedDiscoDoesNotRequestDisco() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getID()));
+
+ stanzaChannel->sentStanzas.clear();
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ }
+
+ void testReceiveSameHashFromSameUserAfterIncorrectVerificationDoesNotRequestDisco() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ sendDiscoInfoResult(discoInfo2);
+
+ stanzaChannel->sentStanzas.clear();
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ }
+
+ void testReceiveSameHashFromDifferentUserAfterFailedDiscoRequestsDisco() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID()));
+
+ stanzaChannel->sentStanzas.clear();
+ sendPresenceWithCaps(user2, capsInfo1);
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user2, IQ::Get));
+ }
+
+ void testReceiveSameHashFromDifferentUserAfterIncorrectVerificationRequestsDisco() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ sendDiscoInfoResult(discoInfo2);
+
+ stanzaChannel->sentStanzas.clear();
+ sendPresenceWithCaps(user2, capsInfo1);
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user2, IQ::Get));
+ }
+
+ void testReceiveDifferentHashFromSameUserAfterFailedDiscoDoesNotRequestDisco() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getID()));
+
+ stanzaChannel->sentStanzas.clear();
+ sendPresenceWithCaps(user1, capsInfo2);
+
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get));
+ }
+
+ void testReceiveSuccesfulDiscoStoresCaps() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ sendDiscoInfoResult(discoInfo1);
+
+ std::shared_ptr<DiscoInfo> discoInfo(storage->getDiscoInfo(capsInfo1->getVersion()));
+ CPPUNIT_ASSERT(discoInfo);
+ CPPUNIT_ASSERT(discoInfo->hasFeature("http://swift.im/feature1"));
+ }
+
+ void testReceiveIncorrectVerificationDiscoDoesNotStoreCaps() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ sendDiscoInfoResult(discoInfo2);
+
+ std::shared_ptr<DiscoInfo> discoInfo(storage->getDiscoInfo(capsInfo1->getVersion()));
+ CPPUNIT_ASSERT(!discoInfo);
+ }
+
+ void testReceiveFailingDiscoFallsBack() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ sendPresenceWithCaps(user2, capsInfo1alt);
+ stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID()));
+
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(1, user2, IQ::Get));
+ std::shared_ptr<DiscoInfo> discoInfo(stanzaChannel->sentStanzas[1]->getPayload<DiscoInfo>());
+ CPPUNIT_ASSERT(discoInfo);
+ CPPUNIT_ASSERT_EQUAL("http://node2.im#" + capsInfo1alt->getVersion(), discoInfo->getNode());
+ }
+
+ void testReceiveNoDiscoFallsBack() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ sendPresenceWithCaps(user2, capsInfo1alt);
+ stanzaChannel->onIQReceived(IQ::createResult(JID("baz@fum.com/dum"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), std::shared_ptr<DiscoInfo>()));
+
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(1, user2, IQ::Get));
+ std::shared_ptr<DiscoInfo> discoInfo(stanzaChannel->sentStanzas[1]->getPayload<DiscoInfo>());
+ CPPUNIT_ASSERT(discoInfo);
+ CPPUNIT_ASSERT_EQUAL("http://node2.im#" + capsInfo1alt->getVersion(), discoInfo->getNode());
+ }
+
+ void testReceiveFailingFallbackDiscoFallsBack() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ sendPresenceWithCaps(user2, capsInfo1alt);
+ sendPresenceWithCaps(user3, capsInfo1);
+ stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID()));
+ stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[1]->getTo(), stanzaChannel->sentStanzas[1]->getID()));
+
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(2, user3, IQ::Get));
+ }
+
+ void testReceiveSameHashFromFailingUserAfterReconnectRequestsDisco() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID()));
+ stanzaChannel->setAvailable(false);
+ stanzaChannel->setAvailable(true);
+ stanzaChannel->sentStanzas.clear();
+
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get));
+ }
+
+ void testReconnectResetsFallback() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ sendPresenceWithCaps(user2, capsInfo1alt);
+ stanzaChannel->setAvailable(false);
+ stanzaChannel->setAvailable(true);
+ stanzaChannel->sentStanzas.clear();
+ sendPresenceWithCaps(user1, capsInfo1);
+ stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID()));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ }
+
+ void testReconnectResetsRequests() {
+ std::shared_ptr<CapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+ stanzaChannel->sentStanzas.clear();
+ stanzaChannel->setAvailable(false);
+ stanzaChannel->setAvailable(true);
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get));
+ }
+
+ private:
+ std::shared_ptr<CapsManager> createManager() {
+ std::shared_ptr<CapsManager> manager(new CapsManager(storage.get(), stanzaChannel.get(), iqRouter.get(), crypto.get()));
+ manager->setWarnOnInvalidHash(false);
+ //manager->onCapsChanged.connect(boost::bind(&CapsManagerTest::handleCapsChanged, this, _1));
+ return manager;
+ }
+
+ void handleCapsChanged(const JID& jid) {
+ changes.push_back(jid);
+ }
+
+ void sendPresenceWithCaps(const JID& jid, std::shared_ptr<CapsInfo> caps) {
+ std::shared_ptr<Presence> presence(new Presence());
+ presence->setFrom(jid);
+ presence->addPayload(caps);
+ stanzaChannel->onPresenceReceived(presence);
+ }
+
+ void sendDiscoInfoResult(std::shared_ptr<DiscoInfo> discoInfo) {
+ stanzaChannel->onIQReceived(IQ::createResult(JID("baz@fum.com/dum"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), discoInfo));
+ }
+
+ private:
+ std::unique_ptr<DummyStanzaChannel> stanzaChannel;
+ std::unique_ptr<IQRouter> iqRouter;
+ std::unique_ptr<CapsStorage> storage;
+ std::vector<JID> changes;
+ JID user1;
+ std::shared_ptr<DiscoInfo> discoInfo1;
+ std::shared_ptr<CapsInfo> capsInfo1;
+ std::shared_ptr<CapsInfo> capsInfo1alt;
+ JID user2;
+ std::shared_ptr<DiscoInfo> discoInfo2;
+ std::shared_ptr<CapsInfo> capsInfo2;
+ std::shared_ptr<CapsInfo> legacyCapsInfo;
+ JID user3;
+ std::shared_ptr<CryptoProvider> crypto;
};
CPPUNIT_TEST_SUITE_REGISTRATION(CapsManagerTest);
diff --git a/Swiften/Disco/UnitTest/DiscoInfoResponderTest.cpp b/Swiften/Disco/UnitTest/DiscoInfoResponderTest.cpp
index 62760f0..45dc959 100644
--- a/Swiften/Disco/UnitTest/DiscoInfoResponderTest.cpp
+++ b/Swiften/Disco/UnitTest/DiscoInfoResponderTest.cpp
@@ -1,96 +1,97 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
+#include <typeinfo>
+
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
-#include <typeinfo>
#include <Swiften/Disco/DiscoInfoResponder.h>
-#include <Swiften/Queries/IQRouter.h>
#include <Swiften/Queries/DummyIQChannel.h>
+#include <Swiften/Queries/IQRouter.h>
using namespace Swift;
class DiscoInfoResponderTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(DiscoInfoResponderTest);
- CPPUNIT_TEST(testHandleRequest_GetToplevelInfo);
- CPPUNIT_TEST(testHandleRequest_GetNodeInfo);
- CPPUNIT_TEST(testHandleRequest_GetInvalidNodeInfo);
- CPPUNIT_TEST_SUITE_END();
-
- public:
- void setUp() {
- channel_ = new DummyIQChannel();
- router_ = new IQRouter(channel_);
- }
-
- void tearDown() {
- delete router_;
- delete channel_;
- }
-
- void testHandleRequest_GetToplevelInfo() {
- DiscoInfoResponder testling(router_);
- testling.start();
- DiscoInfo discoInfo;
- discoInfo.addFeature("foo");
- testling.setDiscoInfo(discoInfo);
-
- boost::shared_ptr<DiscoInfo> query(new DiscoInfo());
- channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com"), "id-1", query));
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
- boost::shared_ptr<DiscoInfo> payload(channel_->iqs_[0]->getPayload<DiscoInfo>());
- CPPUNIT_ASSERT(payload);
- CPPUNIT_ASSERT_EQUAL(std::string(""), payload->getNode());
- CPPUNIT_ASSERT(payload->hasFeature("foo"));
-
- testling.stop();
- }
-
- void testHandleRequest_GetNodeInfo() {
- DiscoInfoResponder testling(router_);
- testling.start();
- DiscoInfo discoInfo;
- discoInfo.addFeature("foo");
- testling.setDiscoInfo(discoInfo);
- DiscoInfo discoInfoBar;
- discoInfoBar.addFeature("bar");
- testling.setDiscoInfo("bar-node", discoInfoBar);
-
- boost::shared_ptr<DiscoInfo> query(new DiscoInfo());
- query->setNode("bar-node");
- channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com"), "id-1", query));
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
- boost::shared_ptr<DiscoInfo> payload(channel_->iqs_[0]->getPayload<DiscoInfo>());
- CPPUNIT_ASSERT(payload);
- CPPUNIT_ASSERT_EQUAL(std::string("bar-node"), payload->getNode());
- CPPUNIT_ASSERT(payload->hasFeature("bar"));
-
- testling.stop();
- }
-
- void testHandleRequest_GetInvalidNodeInfo() {
- DiscoInfoResponder testling(router_);
- boost::shared_ptr<DiscoInfo> query(new DiscoInfo());
- query->setNode("bar-node");
- channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com"), "id-1", query));
- testling.start();
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
- boost::shared_ptr<ErrorPayload> payload(channel_->iqs_[0]->getPayload<ErrorPayload>());
- CPPUNIT_ASSERT(payload);
-
- testling.stop();
- }
-
- private:
- IQRouter* router_;
- DummyIQChannel* channel_;
+ CPPUNIT_TEST_SUITE(DiscoInfoResponderTest);
+ CPPUNIT_TEST(testHandleRequest_GetToplevelInfo);
+ CPPUNIT_TEST(testHandleRequest_GetNodeInfo);
+ CPPUNIT_TEST(testHandleRequest_GetInvalidNodeInfo);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ channel_ = new DummyIQChannel();
+ router_ = new IQRouter(channel_);
+ }
+
+ void tearDown() {
+ delete router_;
+ delete channel_;
+ }
+
+ void testHandleRequest_GetToplevelInfo() {
+ DiscoInfoResponder testling(router_);
+ testling.start();
+ DiscoInfo discoInfo;
+ discoInfo.addFeature("foo");
+ testling.setDiscoInfo(discoInfo);
+
+ std::shared_ptr<DiscoInfo> query(new DiscoInfo());
+ channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com"), "id-1", query));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
+ std::shared_ptr<DiscoInfo> payload(channel_->iqs_[0]->getPayload<DiscoInfo>());
+ CPPUNIT_ASSERT(payload);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), payload->getNode());
+ CPPUNIT_ASSERT(payload->hasFeature("foo"));
+
+ testling.stop();
+ }
+
+ void testHandleRequest_GetNodeInfo() {
+ DiscoInfoResponder testling(router_);
+ testling.start();
+ DiscoInfo discoInfo;
+ discoInfo.addFeature("foo");
+ testling.setDiscoInfo(discoInfo);
+ DiscoInfo discoInfoBar;
+ discoInfoBar.addFeature("bar");
+ testling.setDiscoInfo("bar-node", discoInfoBar);
+
+ std::shared_ptr<DiscoInfo> query(new DiscoInfo());
+ query->setNode("bar-node");
+ channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com"), "id-1", query));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
+ std::shared_ptr<DiscoInfo> payload(channel_->iqs_[0]->getPayload<DiscoInfo>());
+ CPPUNIT_ASSERT(payload);
+ CPPUNIT_ASSERT_EQUAL(std::string("bar-node"), payload->getNode());
+ CPPUNIT_ASSERT(payload->hasFeature("bar"));
+
+ testling.stop();
+ }
+
+ void testHandleRequest_GetInvalidNodeInfo() {
+ DiscoInfoResponder testling(router_);
+ std::shared_ptr<DiscoInfo> query(new DiscoInfo());
+ query->setNode("bar-node");
+ channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com"), "id-1", query));
+ testling.start();
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
+ std::shared_ptr<ErrorPayload> payload(channel_->iqs_[0]->getPayload<ErrorPayload>());
+ CPPUNIT_ASSERT(payload);
+
+ testling.stop();
+ }
+
+ private:
+ IQRouter* router_;
+ DummyIQChannel* channel_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(DiscoInfoResponderTest);
diff --git a/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp b/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp
index d5ad27a..8c59741 100644
--- a/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp
+++ b/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp
@@ -1,193 +1,191 @@
/*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <memory>
#include <vector>
+
#include <boost/bind.hpp>
-#include <Swiften/Disco/EntityCapsManager.h>
-#include <Swiften/Disco/CapsProvider.h>
-#include <Swiften/Elements/CapsInfo.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
#include <Swiften/Client/DummyStanzaChannel.h>
-#include <Swiften/Disco/CapsInfoGenerator.h>
#include <Swiften/Crypto/CryptoProvider.h>
#include <Swiften/Crypto/PlatformCryptoProvider.h>
+#include <Swiften/Disco/CapsInfoGenerator.h>
+#include <Swiften/Disco/CapsProvider.h>
+#include <Swiften/Disco/EntityCapsManager.h>
+#include <Swiften/Elements/CapsInfo.h>
using namespace Swift;
class EntityCapsManagerTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(EntityCapsManagerTest);
- CPPUNIT_TEST(testReceiveKnownHash);
- CPPUNIT_TEST(testReceiveKnownHashTwiceDoesNotTriggerChange);
- CPPUNIT_TEST(testReceiveUnknownHashDoesNotTriggerChange);
- CPPUNIT_TEST(testReceiveUnknownHashAfterKnownHashTriggersChangeAndClearsCaps);
- CPPUNIT_TEST(testReceiveUnavailablePresenceAfterKnownHashTriggersChangeAndClearsCaps);
- CPPUNIT_TEST(testReconnectTriggersChangeAndClearsCaps);
- CPPUNIT_TEST(testHashAvailable);
- CPPUNIT_TEST_SUITE_END();
-
- public:
- void setUp() {
- crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
-
- stanzaChannel = new DummyStanzaChannel();
- capsProvider = new DummyCapsProvider();
-
- user1 = JID("user1@bar.com/bla");
- discoInfo1 = boost::make_shared<DiscoInfo>();
- discoInfo1->addFeature("http://swift.im/feature1");
- capsInfo1 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node1.im", crypto.get()).generateCapsInfo(*discoInfo1.get()));
- capsInfo1alt = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo1.get()));
- user2 = JID("user2@foo.com/baz");
- discoInfo2 = boost::make_shared<DiscoInfo>();
- discoInfo2->addFeature("http://swift.im/feature2");
- capsInfo2 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo2.get()));
- user3 = JID("user3@foo.com/baz");
- legacyCapsInfo = boost::make_shared<CapsInfo>("http://swift.im", "ver1", "");
- }
-
- void tearDown() {
- delete capsProvider;
- delete stanzaChannel;
- }
-
- void testReceiveKnownHash() {
- boost::shared_ptr<EntityCapsManager> testling = createManager();
- capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
- sendPresenceWithCaps(user1, capsInfo1);
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
- CPPUNIT_ASSERT_EQUAL(user1, changes[0]);
- CPPUNIT_ASSERT_EQUAL(discoInfo1, testling->getCaps(user1));
- }
-
- void testReceiveKnownHashTwiceDoesNotTriggerChange() {
- boost::shared_ptr<EntityCapsManager> testling = createManager();
- capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
- sendPresenceWithCaps(user1, capsInfo1);
- changes.clear();
-
- sendPresenceWithCaps(user1, capsInfo1);
-
- CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size()));
- }
-
- void testReceiveUnknownHashDoesNotTriggerChange() {
- boost::shared_ptr<EntityCapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
-
- CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size()));
- }
-
- void testHashAvailable() {
- boost::shared_ptr<EntityCapsManager> testling = createManager();
- sendPresenceWithCaps(user1, capsInfo1);
-
- capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
- capsProvider->onCapsAvailable(capsInfo1->getVersion());
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
- CPPUNIT_ASSERT_EQUAL(user1, changes[0]);
- CPPUNIT_ASSERT_EQUAL(discoInfo1, testling->getCaps(user1));
- }
-
- void testReceiveUnknownHashAfterKnownHashTriggersChangeAndClearsCaps() {
- boost::shared_ptr<EntityCapsManager> testling = createManager();
- capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
- sendPresenceWithCaps(user1, capsInfo1);
- changes.clear();
- sendPresenceWithCaps(user1, capsInfo2);
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
- CPPUNIT_ASSERT_EQUAL(user1, changes[0]);
- CPPUNIT_ASSERT(!testling->getCaps(user1));
- }
-
- void testReceiveUnavailablePresenceAfterKnownHashTriggersChangeAndClearsCaps() {
- boost::shared_ptr<EntityCapsManager> testling = createManager();
- capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
- sendPresenceWithCaps(user1, capsInfo1);
- changes.clear();
- sendUnavailablePresence(user1);
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
- CPPUNIT_ASSERT_EQUAL(user1, changes[0]);
- CPPUNIT_ASSERT(!testling->getCaps(user1));
- }
-
- void testReconnectTriggersChangeAndClearsCaps() {
- boost::shared_ptr<EntityCapsManager> testling = createManager();
- capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
- capsProvider->caps[capsInfo2->getVersion()] = discoInfo2;
- sendPresenceWithCaps(user1, capsInfo1);
- sendPresenceWithCaps(user2, capsInfo2);
- changes.clear();
- stanzaChannel->setAvailable(false);
- stanzaChannel->setAvailable(true);
-
- CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(changes.size()));
- CPPUNIT_ASSERT_EQUAL(user1, changes[0]);
- CPPUNIT_ASSERT(!testling->getCaps(user1));
- CPPUNIT_ASSERT_EQUAL(user2, changes[1]);
- CPPUNIT_ASSERT(!testling->getCaps(user2));
- }
-
- private:
- boost::shared_ptr<EntityCapsManager> createManager() {
- boost::shared_ptr<EntityCapsManager> manager(new EntityCapsManager(capsProvider, stanzaChannel));
- manager->onCapsChanged.connect(boost::bind(&EntityCapsManagerTest::handleCapsChanged, this, _1));
- return manager;
- }
-
- void handleCapsChanged(const JID& jid) {
- changes.push_back(jid);
- }
-
- void sendPresenceWithCaps(const JID& jid, boost::shared_ptr<CapsInfo> caps) {
- boost::shared_ptr<Presence> presence(new Presence());
- presence->setFrom(jid);
- presence->addPayload(caps);
- stanzaChannel->onPresenceReceived(presence);
- }
-
- void sendUnavailablePresence(const JID& jid) {
- boost::shared_ptr<Presence> presence(new Presence());
- presence->setFrom(jid);
- presence->setType(Presence::Unavailable);
- stanzaChannel->onPresenceReceived(presence);
- }
-
- private:
- struct DummyCapsProvider : public CapsProvider {
- virtual DiscoInfo::ref getCaps(const std::string& hash) const {
- std::map<std::string, DiscoInfo::ref>::const_iterator i = caps.find(hash);
- if (i != caps.end()) {
- return i->second;
- }
- return DiscoInfo::ref();
- }
-
- std::map<std::string, DiscoInfo::ref> caps;
- };
-
- private:
- DummyStanzaChannel* stanzaChannel;
- DummyCapsProvider* capsProvider;
- JID user1;
- boost::shared_ptr<DiscoInfo> discoInfo1;
- boost::shared_ptr<CapsInfo> capsInfo1;
- boost::shared_ptr<CapsInfo> capsInfo1alt;
- JID user2;
- boost::shared_ptr<DiscoInfo> discoInfo2;
- boost::shared_ptr<CapsInfo> capsInfo2;
- boost::shared_ptr<CapsInfo> legacyCapsInfo;
- JID user3;
- std::vector<JID> changes;
- boost::shared_ptr<CryptoProvider> crypto;
+ CPPUNIT_TEST_SUITE(EntityCapsManagerTest);
+ CPPUNIT_TEST(testReceiveKnownHash);
+ CPPUNIT_TEST(testReceiveKnownHashTwiceDoesNotTriggerChange);
+ CPPUNIT_TEST(testReceiveUnknownHashDoesNotTriggerChange);
+ CPPUNIT_TEST(testReceiveUnknownHashAfterKnownHashTriggersChangeAndClearsCaps);
+ CPPUNIT_TEST(testReceiveUnavailablePresenceAfterKnownHashTriggersChangeAndClearsCaps);
+ CPPUNIT_TEST(testReconnectTriggersChangeAndClearsCaps);
+ CPPUNIT_TEST(testHashAvailable);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ crypto = std::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
+
+ stanzaChannel = std::unique_ptr<DummyStanzaChannel>(new DummyStanzaChannel());
+ capsProvider = std::unique_ptr<DummyCapsProvider>(new DummyCapsProvider());
+
+ user1 = JID("user1@bar.com/bla");
+ discoInfo1 = std::make_shared<DiscoInfo>();
+ discoInfo1->addFeature("http://swift.im/feature1");
+ capsInfo1 = std::make_shared<CapsInfo>(CapsInfoGenerator("http://node1.im", crypto.get()).generateCapsInfo(*discoInfo1.get()));
+ capsInfo1alt = std::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo1.get()));
+ user2 = JID("user2@foo.com/baz");
+ discoInfo2 = std::make_shared<DiscoInfo>();
+ discoInfo2->addFeature("http://swift.im/feature2");
+ capsInfo2 = std::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo2.get()));
+ user3 = JID("user3@foo.com/baz");
+ legacyCapsInfo = std::make_shared<CapsInfo>("http://swift.im", "ver1", "");
+ }
+
+ void testReceiveKnownHash() {
+ std::shared_ptr<EntityCapsManager> testling = createManager();
+ capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
+ CPPUNIT_ASSERT_EQUAL(user1, changes[0]);
+ CPPUNIT_ASSERT_EQUAL(discoInfo1, testling->getCaps(user1));
+ }
+
+ void testReceiveKnownHashTwiceDoesNotTriggerChange() {
+ std::shared_ptr<EntityCapsManager> testling = createManager();
+ capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
+ sendPresenceWithCaps(user1, capsInfo1);
+ changes.clear();
+
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size()));
+ }
+
+ void testReceiveUnknownHashDoesNotTriggerChange() {
+ std::shared_ptr<EntityCapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size()));
+ }
+
+ void testHashAvailable() {
+ std::shared_ptr<EntityCapsManager> testling = createManager();
+ sendPresenceWithCaps(user1, capsInfo1);
+
+ capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
+ capsProvider->onCapsAvailable(capsInfo1->getVersion());
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
+ CPPUNIT_ASSERT_EQUAL(user1, changes[0]);
+ CPPUNIT_ASSERT_EQUAL(discoInfo1, testling->getCaps(user1));
+ }
+
+ void testReceiveUnknownHashAfterKnownHashTriggersChangeAndClearsCaps() {
+ std::shared_ptr<EntityCapsManager> testling = createManager();
+ capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
+ sendPresenceWithCaps(user1, capsInfo1);
+ changes.clear();
+ sendPresenceWithCaps(user1, capsInfo2);
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
+ CPPUNIT_ASSERT_EQUAL(user1, changes[0]);
+ CPPUNIT_ASSERT(!testling->getCaps(user1));
+ }
+
+ void testReceiveUnavailablePresenceAfterKnownHashTriggersChangeAndClearsCaps() {
+ std::shared_ptr<EntityCapsManager> testling = createManager();
+ capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
+ sendPresenceWithCaps(user1, capsInfo1);
+ changes.clear();
+ sendUnavailablePresence(user1);
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
+ CPPUNIT_ASSERT_EQUAL(user1, changes[0]);
+ CPPUNIT_ASSERT(!testling->getCaps(user1));
+ }
+
+ void testReconnectTriggersChangeAndClearsCaps() {
+ std::shared_ptr<EntityCapsManager> testling = createManager();
+ capsProvider->caps[capsInfo1->getVersion()] = discoInfo1;
+ capsProvider->caps[capsInfo2->getVersion()] = discoInfo2;
+ sendPresenceWithCaps(user1, capsInfo1);
+ sendPresenceWithCaps(user2, capsInfo2);
+ changes.clear();
+ stanzaChannel->setAvailable(false);
+ stanzaChannel->setAvailable(true);
+
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(changes.size()));
+ CPPUNIT_ASSERT_EQUAL(user1, changes[0]);
+ CPPUNIT_ASSERT(!testling->getCaps(user1));
+ CPPUNIT_ASSERT_EQUAL(user2, changes[1]);
+ CPPUNIT_ASSERT(!testling->getCaps(user2));
+ }
+
+ private:
+ std::shared_ptr<EntityCapsManager> createManager() {
+ std::shared_ptr<EntityCapsManager> manager(new EntityCapsManager(capsProvider.get(), stanzaChannel.get()));
+ manager->onCapsChanged.connect(boost::bind(&EntityCapsManagerTest::handleCapsChanged, this, _1));
+ return manager;
+ }
+
+ void handleCapsChanged(const JID& jid) {
+ changes.push_back(jid);
+ }
+
+ void sendPresenceWithCaps(const JID& jid, std::shared_ptr<CapsInfo> caps) {
+ std::shared_ptr<Presence> presence(new Presence());
+ presence->setFrom(jid);
+ presence->addPayload(caps);
+ stanzaChannel->onPresenceReceived(presence);
+ }
+
+ void sendUnavailablePresence(const JID& jid) {
+ std::shared_ptr<Presence> presence(new Presence());
+ presence->setFrom(jid);
+ presence->setType(Presence::Unavailable);
+ stanzaChannel->onPresenceReceived(presence);
+ }
+
+ private:
+ struct DummyCapsProvider : public CapsProvider {
+ virtual DiscoInfo::ref getCaps(const std::string& hash) const {
+ std::map<std::string, DiscoInfo::ref>::const_iterator i = caps.find(hash);
+ if (i != caps.end()) {
+ return i->second;
+ }
+ return DiscoInfo::ref();
+ }
+
+ std::map<std::string, DiscoInfo::ref> caps;
+ };
+
+ private:
+ std::unique_ptr<DummyStanzaChannel> stanzaChannel;
+ std::unique_ptr<DummyCapsProvider> capsProvider;
+ JID user1;
+ std::shared_ptr<DiscoInfo> discoInfo1;
+ std::shared_ptr<CapsInfo> capsInfo1;
+ std::shared_ptr<CapsInfo> capsInfo1alt;
+ JID user2;
+ std::shared_ptr<DiscoInfo> discoInfo2;
+ std::shared_ptr<CapsInfo> capsInfo2;
+ std::shared_ptr<CapsInfo> legacyCapsInfo;
+ JID user3;
+ std::vector<JID> changes;
+ std::shared_ptr<CryptoProvider> crypto;
};
CPPUNIT_TEST_SUITE_REGISTRATION(EntityCapsManagerTest);
diff --git a/Swiften/Disco/UnitTest/FeatureOracleTest.cpp b/Swiften/Disco/UnitTest/FeatureOracleTest.cpp
new file mode 100644
index 0000000..e5ff09b
--- /dev/null
+++ b/Swiften/Disco/UnitTest/FeatureOracleTest.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <vector>
+
+#include <boost/bind.hpp>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <Swiften/Base/Tristate.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Crypto/CryptoProvider.h>
+#include <Swiften/Crypto/PlatformCryptoProvider.h>
+#include <Swiften/Disco/CapsInfoGenerator.h>
+#include <Swiften/Disco/CapsProvider.h>
+#include <Swiften/Disco/EntityCapsManager.h>
+#include <Swiften/Disco/FeatureOracle.h>
+#include <Swiften/Elements/CapsInfo.h>
+#include <Swiften/Presence/PresenceOracle.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
+
+using namespace Swift;
+
+class FeatureOracleTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(FeatureOracleTest);
+ CPPUNIT_TEST(testMergeAvailableResourcesForFeatures);
+ CPPUNIT_TEST(testMostAvailableFileTransferClient);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ crypto_ = std::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
+ dummyStanzaChannel_ = new DummyStanzaChannel();
+ xmppRosterImpl_ = new XMPPRosterImpl();
+ dummyCapsProvider_ = new DummyCapsProvider();
+ entityCapsManager_ = new EntityCapsManager(dummyCapsProvider_, dummyStanzaChannel_);
+ presenceOracle_ = new PresenceOracle(dummyStanzaChannel_, xmppRosterImpl_);
+ featureOracle_ = new FeatureOracle(entityCapsManager_, presenceOracle_);
+ }
+
+ void tearDown() {
+ delete featureOracle_;
+ delete presenceOracle_;
+ delete entityCapsManager_;
+ delete dummyCapsProvider_;
+ delete xmppRosterImpl_;
+ delete dummyStanzaChannel_;
+ }
+
+ void simulateIncomingPresence(const JID& from, Presence::Type type, StatusShow::Type status, const DiscoInfo::ref& disco, const std::vector<Payload::ref>& additionalPayloads = {}) {
+ auto capsInfo = std::make_shared<CapsInfo>(CapsInfoGenerator("http://example.com", crypto_.get()).generateCapsInfo(*disco.get()));
+ dummyCapsProvider_->caps[capsInfo->getVersion()] = disco;
+
+ Presence::ref capsNotifyPresence = std::make_shared<Presence>();
+ capsNotifyPresence->setType(type);
+ capsNotifyPresence->setFrom(from);
+ capsNotifyPresence->setShow(status);
+ capsNotifyPresence->addPayload(capsInfo);
+
+ capsNotifyPresence->addPayloads(additionalPayloads);
+
+ xmppRosterImpl_->addContact(from, "Foo", {}, RosterItemPayload::Both);
+ dummyStanzaChannel_->onPresenceReceived(capsNotifyPresence);
+ }
+
+ DiscoInfo::ref fileTransferSupportingDisco() {
+ DiscoInfo::ref discoInfo = std::make_shared<DiscoInfo>();
+ discoInfo->addFeature(DiscoInfo::JingleFeature);
+ discoInfo->addFeature(DiscoInfo::JingleFTFeature);
+ discoInfo->addFeature(DiscoInfo::JingleTransportsS5BFeature);
+ discoInfo->addFeature(DiscoInfo::JingleTransportsIBBFeature);
+ return discoInfo;
+ }
+
+ DiscoInfo::ref noFileTransferSupportingDisco() {
+ DiscoInfo::ref discoInfo = std::make_shared<DiscoInfo>();
+ discoInfo->addFeature(DiscoInfo::JingleFeature);
+ return discoInfo;
+ }
+
+ void testMergeAvailableResourcesForFeatures() {
+ CPPUNIT_ASSERT_EQUAL(No, featureOracle_->isFileTransferSupported(baseJID));
+
+ simulateIncomingPresence(noFileTransferJID, Presence::Available, StatusShow::Online, noFileTransferSupportingDisco());
+
+ CPPUNIT_ASSERT_EQUAL(size_t(1), presenceOracle_->getAllPresence(baseJID).size());
+ CPPUNIT_ASSERT_EQUAL(No, featureOracle_->isFileTransferSupported(baseJID));
+
+ simulateIncomingPresence(fileTransferJID, Presence::Available, StatusShow::Online, fileTransferSupportingDisco());
+
+ CPPUNIT_ASSERT_EQUAL(size_t(2), presenceOracle_->getAllPresence(baseJID).size());
+ CPPUNIT_ASSERT_EQUAL(Maybe, featureOracle_->isFileTransferSupported(baseJID));
+
+ simulateIncomingPresence(noFileTransferJID, Presence::Unavailable, StatusShow::None, noFileTransferSupportingDisco());
+
+ CPPUNIT_ASSERT_EQUAL(size_t(1), presenceOracle_->getAllPresence(baseJID).size());
+ CPPUNIT_ASSERT_EQUAL(Yes, featureOracle_->isFileTransferSupported(baseJID));
+
+ simulateIncomingPresence(fileTransferJID, Presence::Unavailable, StatusShow::None, fileTransferSupportingDisco());
+
+ CPPUNIT_ASSERT_EQUAL(size_t(1), presenceOracle_->getAllPresence(baseJID).size());
+ CPPUNIT_ASSERT_EQUAL(No, featureOracle_->isFileTransferSupported(baseJID));
+ }
+
+ void testMostAvailableFileTransferClient() {
+ simulateIncomingPresence(fileTransferJID, Presence::Available, StatusShow::DND, fileTransferSupportingDisco());
+
+ CPPUNIT_ASSERT_EQUAL(fileTransferJID, featureOracle_->getMostAvailableClientForFileTrasfer(baseJID));
+
+ simulateIncomingPresence(noFileTransferJID, Presence::Available, StatusShow::Online, noFileTransferSupportingDisco());
+
+ CPPUNIT_ASSERT_EQUAL(fileTransferJID, featureOracle_->getMostAvailableClientForFileTrasfer(baseJID));
+
+ auto moreAvailableJID = baseJID.withResource("moreAvailableFt");
+ simulateIncomingPresence(moreAvailableJID, Presence::Available, StatusShow::Online, fileTransferSupportingDisco());
+
+ CPPUNIT_ASSERT_EQUAL(moreAvailableJID, featureOracle_->getMostAvailableClientForFileTrasfer(baseJID));
+ }
+
+ private:
+ struct DummyCapsProvider : public CapsProvider {
+ virtual DiscoInfo::ref getCaps(const std::string& hash) const {
+ std::map<std::string, DiscoInfo::ref>::const_iterator i = caps.find(hash);
+ if (i != caps.end()) {
+ return i->second;
+ }
+ return DiscoInfo::ref();
+ }
+
+ std::map<std::string, DiscoInfo::ref> caps;
+ };
+
+ private:
+ JID baseJID = "test@example.com";
+ JID fileTransferJID = baseJID.withResource("fileTransfer");
+ JID noFileTransferJID = baseJID.withResource("noFileTransfer");
+
+ std::shared_ptr<CryptoProvider> crypto_;
+ DummyCapsProvider* dummyCapsProvider_;
+ DummyStanzaChannel* dummyStanzaChannel_;
+ EntityCapsManager* entityCapsManager_;
+ FeatureOracle* featureOracle_;
+ PresenceOracle* presenceOracle_;
+ XMPPRosterImpl* xmppRosterImpl_;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(FeatureOracleTest);
diff --git a/Swiften/Disco/UnitTest/JIDDiscoInfoResponderTest.cpp b/Swiften/Disco/UnitTest/JIDDiscoInfoResponderTest.cpp
index adf709e..9369a04 100644
--- a/Swiften/Disco/UnitTest/JIDDiscoInfoResponderTest.cpp
+++ b/Swiften/Disco/UnitTest/JIDDiscoInfoResponderTest.cpp
@@ -1,118 +1,119 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
+#include <typeinfo>
+
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
-#include <typeinfo>
#include <Swiften/Disco/JIDDiscoInfoResponder.h>
-#include <Swiften/Queries/IQRouter.h>
#include <Swiften/Queries/DummyIQChannel.h>
+#include <Swiften/Queries/IQRouter.h>
using namespace Swift;
class JIDDiscoInfoResponderTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(JIDDiscoInfoResponderTest);
- CPPUNIT_TEST(testHandleRequest_GetToplevelInfo);
- CPPUNIT_TEST(testHandleRequest_GetNodeInfo);
- CPPUNIT_TEST(testHandleRequest_GetInvalidNodeInfo);
- CPPUNIT_TEST(testHandleRequest_GetUnknownJID);
- CPPUNIT_TEST_SUITE_END();
-
- public:
- void setUp() {
- channel_ = new DummyIQChannel();
- router_ = new IQRouter(channel_);
- }
-
- void tearDown() {
- delete router_;
- delete channel_;
- }
-
- void testHandleRequest_GetToplevelInfo() {
- JIDDiscoInfoResponder testling(router_);
- testling.start();
- DiscoInfo discoInfo;
- discoInfo.addFeature("foo");
- testling.setDiscoInfo(JID("foo@bar.com/baz"), discoInfo);
-
- boost::shared_ptr<DiscoInfo> query(new DiscoInfo());
- channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com/baz"), "id-1", query));
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
- boost::shared_ptr<DiscoInfo> payload(channel_->iqs_[0]->getPayload<DiscoInfo>());
- CPPUNIT_ASSERT(payload);
- CPPUNIT_ASSERT_EQUAL(std::string(""), payload->getNode());
- CPPUNIT_ASSERT(payload->hasFeature("foo"));
-
- testling.stop();
- }
-
- void testHandleRequest_GetNodeInfo() {
- JIDDiscoInfoResponder testling(router_);
- testling.start();
- DiscoInfo discoInfo;
- discoInfo.addFeature("foo");
- testling.setDiscoInfo(JID("foo@bar.com/baz"), discoInfo);
- DiscoInfo discoInfoBar;
- discoInfoBar.addFeature("bar");
- testling.setDiscoInfo(JID("foo@bar.com/baz"), "bar-node", discoInfoBar);
-
- boost::shared_ptr<DiscoInfo> query(new DiscoInfo());
- query->setNode("bar-node");
- channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com/baz"), "id-1", query));
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
- boost::shared_ptr<DiscoInfo> payload(channel_->iqs_[0]->getPayload<DiscoInfo>());
- CPPUNIT_ASSERT(payload);
- CPPUNIT_ASSERT_EQUAL(std::string("bar-node"), payload->getNode());
- CPPUNIT_ASSERT(payload->hasFeature("bar"));
-
- testling.stop();
- }
-
- void testHandleRequest_GetInvalidNodeInfo() {
- JIDDiscoInfoResponder testling(router_);
- DiscoInfo discoInfo;
- discoInfo.addFeature("foo");
- testling.setDiscoInfo(JID("foo@bar.com/baz"), discoInfo);
- testling.start();
-
- boost::shared_ptr<DiscoInfo> query(new DiscoInfo());
- query->setNode("bar-node");
- channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com/baz"), "id-1", query));
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
- boost::shared_ptr<ErrorPayload> payload(channel_->iqs_[0]->getPayload<ErrorPayload>());
- CPPUNIT_ASSERT(payload);
-
- testling.stop();
- }
-
- void testHandleRequest_GetUnknownJID() {
- JIDDiscoInfoResponder testling(router_);
- DiscoInfo discoInfo;
- discoInfo.addFeature("foo");
- testling.setDiscoInfo(JID("foo@bar.com/baz"), discoInfo);
- testling.start();
-
- boost::shared_ptr<DiscoInfo> query(new DiscoInfo());
- channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com/fum"), "id-1", query));
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
- boost::shared_ptr<ErrorPayload> payload(channel_->iqs_[0]->getPayload<ErrorPayload>());
- CPPUNIT_ASSERT(payload);
-
- testling.stop();
- }
-
- private:
- IQRouter* router_;
- DummyIQChannel* channel_;
+ CPPUNIT_TEST_SUITE(JIDDiscoInfoResponderTest);
+ CPPUNIT_TEST(testHandleRequest_GetToplevelInfo);
+ CPPUNIT_TEST(testHandleRequest_GetNodeInfo);
+ CPPUNIT_TEST(testHandleRequest_GetInvalidNodeInfo);
+ CPPUNIT_TEST(testHandleRequest_GetUnknownJID);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ channel_ = new DummyIQChannel();
+ router_ = new IQRouter(channel_);
+ }
+
+ void tearDown() {
+ delete router_;
+ delete channel_;
+ }
+
+ void testHandleRequest_GetToplevelInfo() {
+ JIDDiscoInfoResponder testling(router_);
+ testling.start();
+ DiscoInfo discoInfo;
+ discoInfo.addFeature("foo");
+ testling.setDiscoInfo(JID("foo@bar.com/baz"), discoInfo);
+
+ std::shared_ptr<DiscoInfo> query(new DiscoInfo());
+ channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com/baz"), "id-1", query));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
+ std::shared_ptr<DiscoInfo> payload(channel_->iqs_[0]->getPayload<DiscoInfo>());
+ CPPUNIT_ASSERT(payload);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), payload->getNode());
+ CPPUNIT_ASSERT(payload->hasFeature("foo"));
+
+ testling.stop();
+ }
+
+ void testHandleRequest_GetNodeInfo() {
+ JIDDiscoInfoResponder testling(router_);
+ testling.start();
+ DiscoInfo discoInfo;
+ discoInfo.addFeature("foo");
+ testling.setDiscoInfo(JID("foo@bar.com/baz"), discoInfo);
+ DiscoInfo discoInfoBar;
+ discoInfoBar.addFeature("bar");
+ testling.setDiscoInfo(JID("foo@bar.com/baz"), "bar-node", discoInfoBar);
+
+ std::shared_ptr<DiscoInfo> query(new DiscoInfo());
+ query->setNode("bar-node");
+ channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com/baz"), "id-1", query));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
+ std::shared_ptr<DiscoInfo> payload(channel_->iqs_[0]->getPayload<DiscoInfo>());
+ CPPUNIT_ASSERT(payload);
+ CPPUNIT_ASSERT_EQUAL(std::string("bar-node"), payload->getNode());
+ CPPUNIT_ASSERT(payload->hasFeature("bar"));
+
+ testling.stop();
+ }
+
+ void testHandleRequest_GetInvalidNodeInfo() {
+ JIDDiscoInfoResponder testling(router_);
+ DiscoInfo discoInfo;
+ discoInfo.addFeature("foo");
+ testling.setDiscoInfo(JID("foo@bar.com/baz"), discoInfo);
+ testling.start();
+
+ std::shared_ptr<DiscoInfo> query(new DiscoInfo());
+ query->setNode("bar-node");
+ channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com/baz"), "id-1", query));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
+ std::shared_ptr<ErrorPayload> payload(channel_->iqs_[0]->getPayload<ErrorPayload>());
+ CPPUNIT_ASSERT(payload);
+
+ testling.stop();
+ }
+
+ void testHandleRequest_GetUnknownJID() {
+ JIDDiscoInfoResponder testling(router_);
+ DiscoInfo discoInfo;
+ discoInfo.addFeature("foo");
+ testling.setDiscoInfo(JID("foo@bar.com/baz"), discoInfo);
+ testling.start();
+
+ std::shared_ptr<DiscoInfo> query(new DiscoInfo());
+ channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com/fum"), "id-1", query));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
+ std::shared_ptr<ErrorPayload> payload(channel_->iqs_[0]->getPayload<ErrorPayload>());
+ CPPUNIT_ASSERT(payload);
+
+ testling.stop();
+ }
+
+ private:
+ IQRouter* router_;
+ DummyIQChannel* channel_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(JIDDiscoInfoResponderTest);