summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2016-04-21 09:02:07 (GMT)
committerKevin Smith <kevin.smith@isode.com>2016-11-10 11:09:16 (GMT)
commitd2ba1ab8a36333523bf794c23226bd044e1717c2 (patch)
tree737ac14bc1dfcec4b80192ea23e7b0e860a2f8d3 /Swiften
parent41c771ec02682c2b344263d29f68eb6452c42dbe (diff)
downloadswift-d2ba1ab8a36333523bf794c23226bd044e1717c2.zip
swift-d2ba1ab8a36333523bf794c23226bd044e1717c2.tar.bz2
Use FeatureOracle to detect file-transfer support in roster
The FeatureOracle provides tri-state feature lookup functionality for bare JIDs. It returns Yes if a feature is supported by all resources of the bare JID, Maybe if some support it, and No if none of the resources support it. If passed a full JID, it returns the specific features supported by that end-point. Sending a file to a bare JID, will send a file to the resource of the bare JID with the highest availability by presence, show status and priority and which supports the features required for a Jingle file-transfer. Test-Information: Added unit test verifying new behavior. All tests pass on OS X 10.11.6. Added new unit tests for FeatureOracle. Manually verified that the roster and chat window both use the same mechanism to detect support for file-transfers. Manually verified that file-transfers via the contact list goes to already bound full JIDs if there is an existing ChatController. Change-Id: I0175ac42ecb73f1d54f9c96ffbba773eb5e24296
Diffstat (limited to 'Swiften')
-rw-r--r--Swiften/Base/SConscript18
-rw-r--r--Swiften/Disco/FeatureOracle.cpp194
-rw-r--r--Swiften/Disco/FeatureOracle.h16
-rw-r--r--Swiften/Disco/UnitTest/FeatureOracleTest.cpp151
-rw-r--r--Swiften/Elements/Stanza.h5
-rw-r--r--Swiften/FileTransfer/FileTransferManager.cpp15
-rw-r--r--Swiften/FileTransfer/FileTransferManager.h2
-rw-r--r--Swiften/FileTransfer/FileTransferManagerImpl.cpp31
-rw-r--r--Swiften/Presence/PresenceOracle.cpp21
-rw-r--r--Swiften/SConscript3
10 files changed, 345 insertions, 111 deletions
diff --git a/Swiften/Base/SConscript b/Swiften/Base/SConscript
index 92e3da8..de502c2 100644
--- a/Swiften/Base/SConscript
+++ b/Swiften/Base/SConscript
@@ -1,23 +1,23 @@
Import("swiften_env")
objects = swiften_env.SwiftenObject([
+ "BoostRandomGenerator.cpp",
"ByteArray.cpp",
"DateTime.cpp",
- "SafeByteArray.cpp",
- "SafeAllocator.cpp",
"Error.cpp",
+ "FileSize.cpp",
+ "IDGenerator.cpp",
"Log.cpp",
"LogSerializers.cpp",
"Path.cpp",
"Paths.cpp",
- "String.cpp",
- "IDGenerator.cpp",
- "SimpleIDGenerator.cpp",
"RandomGenerator.cpp",
- "BoostRandomGenerator.cpp",
- "sleep.cpp",
- "URL.cpp",
"Regex.cpp",
- "FileSize.cpp"
+ "SafeAllocator.cpp",
+ "SafeByteArray.cpp",
+ "SimpleIDGenerator.cpp",
+ "String.cpp",
+ "URL.cpp",
+ "sleep.cpp",
])
swiften_env.Append(SWIFTEN_OBJECTS = [objects])
diff --git a/Swiften/Disco/FeatureOracle.cpp b/Swiften/Disco/FeatureOracle.cpp
index 8328984..2baf87c 100644
--- a/Swiften/Disco/FeatureOracle.cpp
+++ b/Swiften/Disco/FeatureOracle.cpp
@@ -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;
+ 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 {
- return Maybe;
+ 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);
}
-DiscoInfo::ref FeatureOracle::getDiscoResultForJID(const JID& jid) {
- DiscoInfo::ref discoInfo;
+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;
+}
+
+std::unordered_map<std::string, Tristate> FeatureOracle::getFeaturesForJID(const JID& jid) {
+ std::unordered_map<std::string, Tristate> supportedFeatures;
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());
- }
+ // 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());
}
}
}
- discoInfo = std::make_shared<DiscoInfo>();
- foreach(const std::string& commonFeature, commonFeatures) {
- discoInfo->addFeature(commonFeature);
+ // 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.
- discoInfo = capsProvider_->getCaps(jid);
+ auto discoInfo = capsProvider_->getCaps(jid);
+ if (discoInfo) {
+ for (auto&& feature : discoInfo->getFeatures()) {
+ supportedFeatures[feature] = Yes;
+ }
+ }
}
- return discoInfo;
+ 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 d434e86..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>
@@ -27,16 +30,19 @@ class SWIFTEN_API FeatureOracle {
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 the DiscoInfo::ref for.
- * @return DiscoResult::ref
+ * @param jid The JID to return an std::unordered_map<std::string, Tristate> for.
+ * @return std::unordered_map<std::string, Tristate>
*/
- DiscoInfo::ref getDiscoResultForJID(const JID& jid);
+ std::unordered_map<std::string, Tristate> getFeaturesForJID(const JID& jid);
- Tristate isFeatureSupported(const JID& jid, const std::string& feature);
+ Tristate isFeatureSupported(const std::unordered_map<std::string, Tristate>& supportedFeatures, const std::string& feature);
private:
EntityCapsProvider* capsProvider_;
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/Elements/Stanza.h b/Swiften/Elements/Stanza.h
index 9a69696..9284bc3 100644
--- a/Swiften/Elements/Stanza.h
+++ b/Swiften/Elements/Stanza.h
@@ -68,6 +68,11 @@ namespace Swift {
payloads_.insert(payloads_.end(), begin, end);
}
+ template<typename Container>
+ void addPayloads(const Container& container) {
+ payloads_.insert(payloads_.end(), std::begin(container), std::end(container));
+ }
+
void updatePayload(std::shared_ptr<Payload> payload);
void removePayloadOfSameType(std::shared_ptr<Payload>);
diff --git a/Swiften/FileTransfer/FileTransferManager.cpp b/Swiften/FileTransfer/FileTransferManager.cpp
index 94f4ab7..a5d7313 100644
--- a/Swiften/FileTransfer/FileTransferManager.cpp
+++ b/Swiften/FileTransfer/FileTransferManager.cpp
@@ -4,6 +4,12 @@
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
#include <Swiften/FileTransfer/FileTransferManager.h>
namespace Swift {
@@ -11,13 +17,4 @@ namespace Swift {
FileTransferManager::~FileTransferManager() {
}
-bool FileTransferManager::isSupportedBy(const DiscoInfo::ref info) {
- if (info) {
- return info->hasFeature(DiscoInfo::JingleFeature)
- && info->hasFeature(DiscoInfo::JingleFTFeature)
- && (info->hasFeature(DiscoInfo::JingleTransportsIBBFeature) || info->hasFeature(DiscoInfo::JingleTransportsS5BFeature));
- }
- return false;
-}
-
}
diff --git a/Swiften/FileTransfer/FileTransferManager.h b/Swiften/FileTransfer/FileTransferManager.h
index e315c67..07cfc90 100644
--- a/Swiften/FileTransfer/FileTransferManager.h
+++ b/Swiften/FileTransfer/FileTransferManager.h
@@ -47,8 +47,6 @@ namespace Swift {
std::shared_ptr<ReadBytestream> bytestream,
const FileTransferOptions& = FileTransferOptions()) = 0;
- static bool isSupportedBy(const DiscoInfo::ref info);
-
boost::signals2::signal<void (IncomingFileTransfer::ref)> onIncomingFileTransfer;
};
}
diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.cpp b/Swiften/FileTransfer/FileTransferManagerImpl.cpp
index d449179..05dd3bb 100644
--- a/Swiften/FileTransfer/FileTransferManagerImpl.cpp
+++ b/Swiften/FileTransfer/FileTransferManagerImpl.cpp
@@ -19,8 +19,8 @@
#include <Swiften/Base/BoostFilesystemVersion.h>
#include <Swiften/Base/Log.h>
#include <Swiften/Base/Path.h>
-#include <Swiften/Base/foreach.h>
#include <Swiften/Disco/EntityCapsProvider.h>
+#include <Swiften/Disco/FeatureOracle.h>
#include <Swiften/Elements/JingleFileTransferFileInfo.h>
#include <Swiften/Elements/Presence.h>
#include <Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h>
@@ -99,28 +99,6 @@ void FileTransferManagerImpl::stop() {
s5bServerManager->stop();
}
-boost::optional<JID> FileTransferManagerImpl::highestPriorityJIDSupportingFileTransfer(const JID& bareJID) {
- JID fullReceipientJID;
- int priority = INT_MIN;
-
- //getAllPresence(bareJID) gives you all presences for the bare JID (i.e. all resources) Isode Limited. @ 11:11
- std::vector<Presence::ref> presences = presenceOracle->getAllPresence(bareJID);
-
- //iterate over them
- foreach(Presence::ref pres, presences) {
- if (pres->getPriority() > priority) {
- // look up caps from the jid
- DiscoInfo::ref info = capsProvider->getCaps(pres->getFrom());
- if (isSupportedBy(info)) {
- priority = pres->getPriority();
- fullReceipientJID = pres->getFrom();
- }
- }
- }
-
- return fullReceipientJID.isValid() ? boost::optional<JID>(fullReceipientJID) : boost::optional<JID>();
-}
-
OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer(
const JID& to,
const boost::filesystem::path& filepath,
@@ -155,9 +133,10 @@ OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer(
JID receipient = to;
if(receipient.isBare()) {
- boost::optional<JID> fullJID = highestPriorityJIDSupportingFileTransfer(receipient);
- if (fullJID.is_initialized()) {
- receipient = fullJID.get();
+ auto featureOracle = FeatureOracle(capsProvider, presenceOracle);
+ JID fullJID = featureOracle.getMostAvailableClientForFileTrasfer(receipient);
+ if (!fullJID.toString().empty()) {
+ receipient = fullJID;
} else {
return OutgoingFileTransfer::ref();
}
diff --git a/Swiften/Presence/PresenceOracle.cpp b/Swiften/Presence/PresenceOracle.cpp
index c2c1152..1c9d0ea 100644
--- a/Swiften/Presence/PresenceOracle.cpp
+++ b/Swiften/Presence/PresenceOracle.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.
*/
@@ -10,7 +10,6 @@
#include <boost/bind.hpp>
-#include <Swiften/Base/foreach.h>
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Elements/StatusShow.h>
#include <Swiften/Roster/XMPPRoster.h>
@@ -101,11 +100,10 @@ std::vector<Presence::ref> PresenceOracle::getAllPresence(const JID& bareJID) co
if (i == entries_.end()) {
return results;
}
- PresenceMap presenceMap = i->second;
- PresenceMap::const_iterator j = presenceMap.begin();
- for (; j != presenceMap.end(); ++j) {
- Presence::ref current = j->second;
- results.push_back(current);
+ for (const auto& jidPresence : i->second) {
+ if (jidPresence.second) {
+ results.push_back(jidPresence.second);
+ }
}
return results;
}
@@ -153,7 +151,7 @@ Presence::ref PresenceOracle::getActivePresence(const std::vector<Presence::ref>
PresenceAccountPriorityQueue away;
PresenceAccountPriorityQueue offline;
- foreach(Presence::ref presence, presences) {
+ for (auto&& presence : presences) {
switch (presence->getShow()) {
case StatusShow::Online:
online.push(presence);
@@ -200,18 +198,15 @@ Presence::ref PresenceOracle::getHighestPriorityPresence(const JID& bareJID) con
if (i == entries_.end()) {
return Presence::ref();
}
- PresenceMap presenceMap = i->second;
- PresenceMap::const_iterator j = presenceMap.begin();
Presence::ref highest;
- for (; j != presenceMap.end(); ++j) {
- Presence::ref current = j->second;
+ for (const auto& jidPresence : i->second) {
+ Presence::ref current = jidPresence.second;
if (!highest
|| current->getPriority() > highest->getPriority()
|| (current->getPriority() == highest->getPriority()
&& StatusShow::typeToAvailabilityOrdering(current->getShow()) > StatusShow::typeToAvailabilityOrdering(highest->getShow()))) {
highest = current;
}
-
}
return highest;
}
diff --git a/Swiften/SConscript b/Swiften/SConscript
index eb7ae19..a8fb88a 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -387,9 +387,10 @@ if env["SCONS_STAGE"] == "build" :
File("Component/UnitTest/ComponentSessionTest.cpp"),
File("Disco/UnitTest/CapsInfoGeneratorTest.cpp"),
File("Disco/UnitTest/CapsManagerTest.cpp"),
+ File("Disco/UnitTest/DiscoInfoResponderTest.cpp"),
File("Disco/UnitTest/EntityCapsManagerTest.cpp"),
+ File("Disco/UnitTest/FeatureOracleTest.cpp"),
File("Disco/UnitTest/JIDDiscoInfoResponderTest.cpp"),
- File("Disco/UnitTest/DiscoInfoResponderTest.cpp"),
File("Elements/UnitTest/IQTest.cpp"),
File("Elements/UnitTest/StanzaTest.cpp"),
File("Elements/UnitTest/FormTest.cpp"),