summaryrefslogtreecommitdiffstats
path: root/Swift
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 /Swift
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 'Swift')
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp21
-rw-r--r--Swift/Controllers/MainController.cpp5
-rw-r--r--Swift/Controllers/Roster/RosterController.cpp30
-rw-r--r--Swift/Controllers/Roster/RosterController.h6
-rw-r--r--Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp135
5 files changed, 139 insertions, 58 deletions
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 232d903..b9e2cf4 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -24,6 +24,7 @@
#include <Swiften/Client/NickResolver.h>
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Disco/DiscoServiceWalker.h>
+#include <Swiften/Disco/FeatureOracle.h>
#include <Swiften/Elements/CarbonsReceived.h>
#include <Swiften/Elements/CarbonsSent.h>
#include <Swiften/Elements/ChatState.h>
@@ -59,6 +60,7 @@
#include <Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/JoinMUCWindow.h>
#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h>
@@ -199,6 +201,7 @@ ChatsManager::~ChatsManager() {
roster_->onJIDRemoved.disconnect(boost::bind(&ChatsManager::handleJIDRemovedFromRoster, this, _1));
roster_->onJIDUpdated.disconnect(boost::bind(&ChatsManager::handleJIDUpdatedInRoster, this, _1));
roster_->onRosterCleared.disconnect(boost::bind(&ChatsManager::handleRosterCleared, this));
+ ftOverview_->onNewFileTransferController.disconnect(boost::bind(&ChatsManager::handleNewFileTransferController, this, _1));
delete joinMUCWindow_;
for (JIDChatControllerPair controllerPair : chatControllers_) {
delete controllerPair.second;
@@ -562,6 +565,24 @@ void ChatsManager::handleUIEvent(std::shared_ptr<UIEvent> event) {
mucBookmarkManager_->addBookmark(addMUCBookmarkEvent->getBookmark());
return;
}
+ std::shared_ptr<SendFileUIEvent> sendFileEvent = std::dynamic_pointer_cast<SendFileUIEvent>(event);
+ if (sendFileEvent) {
+ JID fileReceiver = sendFileEvent->getJID();
+ if (fileReceiver.isBare()) {
+ // See if there is a chat controller for a conversation with a bound
+ // full JID. Check if this JID supports file transfer and use it instead
+ // of the bare JID.
+ ChatController* controller = getChatControllerIfExists(fileReceiver, false);
+ if (controller) {
+ JID controllerJID = controller->getToJID();
+ if (!controllerJID.isBare() && (FeatureOracle(entityCapsProvider_, presenceOracle_).isFileTransferSupported(controllerJID) == Yes)) {
+ fileReceiver = controllerJID;
+ }
+ }
+ }
+ ftOverview_->sendFile(fileReceiver, sendFileEvent->getFilename());
+ return;
+ }
std::shared_ptr<CreateImpromptuMUCUIEvent> createImpromptuMUCEvent = std::dynamic_pointer_cast<CreateImpromptuMUCUIEvent>(event);
if (createImpromptuMUCEvent) {
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index a9d3f5c..0d9f1b8 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -15,7 +15,6 @@
#include <Swiften/Base/Algorithm.h>
#include <Swiften/Base/Log.h>
#include <Swiften/Base/String.h>
-#include <Swiften/Base/foreach.h>
#include <Swiften/Base/format.h>
#include <Swiften/Client/Client.h>
#include <Swiften/Client/ClientBlockListManager.h>
@@ -180,7 +179,7 @@ MainController::MainController(
ClientOptions cachedOptions;
bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS);
if (!eagle) {
- foreach (std::string profile, settings->getAvailableProfiles()) {
+ for (auto&& profile : settings->getAvailableProfiles()) {
ProfileSettingsProvider profileSettings(profile, settings);
std::string password = profileSettings.getStringSetting("pass");
std::string certificate = profileSettings.getStringSetting("certificate");
@@ -349,7 +348,7 @@ void MainController::handleConnected() {
showProfileController_ = new ShowProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
ftOverview_ = new FileTransferOverview(client_->getFileTransferManager());
fileTransferListController_->setFileTransferOverview(ftOverview_);
- rosterController_ = new RosterController(boundJID_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_, client_->getClientBlockListManager(), client_->getVCardManager());
+ rosterController_ = new RosterController(boundJID_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), client_->getClientBlockListManager(), client_->getVCardManager());
rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));
rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this));
rosterController_->getWindow()->onShowCertificateRequest.connect(boost::bind(&MainController::handleShowCertificateRequest, this));
diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp
index 116ef2e..1d20c4a 100644
--- a/Swift/Controllers/Roster/RosterController.cpp
+++ b/Swift/Controllers/Roster/RosterController.cpp
@@ -17,6 +17,7 @@
#include <Swiften/Client/NickManager.h>
#include <Swiften/Client/NickResolver.h>
#include <Swiften/Disco/EntityCapsManager.h>
+#include <Swiften/Disco/FeatureOracle.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/FileTransfer/FileTransferManager.h>
#include <Swiften/JID/JID.h>
@@ -30,7 +31,6 @@
#include <Swiften/Roster/XMPPRosterItem.h>
#include <Swiften/VCards/VCardManager.h>
-#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
#include <Swift/Controllers/Intl.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/Roster/ItemOperations/AppearOffline.h>
@@ -49,7 +49,6 @@
#include <Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h>
#include <Swift/Controllers/UIEvents/RenameGroupUIEvent.h>
#include <Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h>
-#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/UIInterfaces/MainWindow.h>
#include <Swift/Controllers/UIInterfaces/MainWindowFactory.h>
#include <Swift/Controllers/XMPPEvents/ErrorEvent.h>
@@ -61,9 +60,8 @@ namespace Swift {
/**
* The controller does not gain ownership of these parameters.
*/
-RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager)
- : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), vcardManager_(vcardManager), avatarManager_(avatarManager), nickManager_(nickManager), nickResolver_(nickResolver), presenceOracle_(presenceOracle), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), ftOverview_(fileTransferOverview), clientBlockListManager_(clientBlockListManager) {
- assert(fileTransferOverview);
+RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager)
+ : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), vcardManager_(vcardManager), avatarManager_(avatarManager), nickManager_(nickManager), nickResolver_(nickResolver), presenceOracle_(presenceOracle), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), clientBlockListManager_(clientBlockListManager) {
iqRouter_ = iqRouter;
subscriptionManager_ = subscriptionManager;
eventController_ = eventController;
@@ -81,6 +79,8 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata
subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&RosterController::handleSubscriptionRequest, this, _1, _2));
uiEventConnection_ = uiEventStream->onUIEvent.connect(boost::bind(&RosterController::handleUIEvent, this, _1));
+ featureOracle_ = std::unique_ptr<FeatureOracle>(new FeatureOracle(entityCapsManager_, presenceOracle_));
+
vcardManager_->onOwnVCardChanged.connect(boost::bind(&RosterController::handleOwnVCardChanged, this, _1));
avatarManager_->onAvatarChanged.connect(boost::bind(&RosterController::handleAvatarChanged, this, _1));
presenceOracle_->onPresenceChange.connect(boost::bind(&RosterController::handlePresenceChanged, this, _1));
@@ -267,9 +267,6 @@ void RosterController::handleUIEvent(std::shared_ptr<UIEvent> event) {
}
}
}
- else if (std::shared_ptr<SendFileUIEvent> sendFileEvent = std::dynamic_pointer_cast<SendFileUIEvent>(event)) {
- ftOverview_->sendFile(sendFileEvent->getJID(), sendFileEvent->getFilename());
- }
}
void RosterController::setContactGroups(const JID& jid, const std::vector<std::string>& groups) {
@@ -396,17 +393,14 @@ std::set<std::string> RosterController::getGroups() const {
}
void RosterController::handleOnCapsChanged(const JID& jid) {
- DiscoInfo::ref info = entityCapsManager_->getCaps(jid);
- if (info) {
- std::set<ContactRosterItem::Feature> features;
- if (FileTransferManager::isSupportedBy(info)) {
- features.insert(ContactRosterItem::FileTransferFeature);
- }
- if (info->hasFeature(DiscoInfo::WhiteboardFeature)) {
- features.insert(ContactRosterItem::WhiteboardFeature);
- }
- roster_->applyOnItems(SetAvailableFeatures(jid, features));
+ std::set<ContactRosterItem::Feature> features;
+ if (featureOracle_->isFileTransferSupported(jid.toBare()) == Tristate::Yes || featureOracle_->isFileTransferSupported(jid.toBare()) == Tristate::Maybe) {
+ features.insert(ContactRosterItem::FileTransferFeature);
+ }
+ if (featureOracle_->isWhiteboardSupported(jid.toBare()) == Tristate::Yes) {
+ features.insert(ContactRosterItem::WhiteboardFeature);
}
+ roster_->applyOnItems(SetAvailableFeatures(jid, features));
}
}
diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h
index 980c545..ca2ecdc 100644
--- a/Swift/Controllers/Roster/RosterController.h
+++ b/Swift/Controllers/Roster/RosterController.h
@@ -27,8 +27,8 @@ namespace Swift {
class ClientBlockListManager;
class EntityCapsProvider;
class EventController;
+ class FeatureOracle;
class FileTransferManager;
- class FileTransferOverview;
class IQRouter;
class MainWindow;
class MainWindowFactory;
@@ -49,7 +49,7 @@ namespace Swift {
class RosterController {
public:
- RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager);
+ RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager);
~RosterController();
void showRosterWindow();
void setJID(const JID& jid) { myJID_ = jid; }
@@ -111,10 +111,10 @@ namespace Swift {
SettingsProvider* settings_;
UIEventStream* uiEventStream_;
EntityCapsProvider* entityCapsManager_;
- FileTransferOverview* ftOverview_;
ClientBlockListManager* clientBlockListManager_;
RosterVCardProvider* rosterVCardProvider_;
std::shared_ptr<ContactRosterItem> ownContact_;
+ std::unique_ptr<FeatureOracle> featureOracle_;
boost::signals2::scoped_connection blockingOnStateChangedConnection_;
boost::signals2::scoped_connection blockingOnItemAddedConnection_;
diff --git a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
index 0cd4080..ddbd7d3 100644
--- a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
@@ -12,13 +12,16 @@
#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/DummyNickManager.h>
#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Client/MemoryStorages.h>
#include <Swiften/Client/NickResolver.h>
#include <Swiften/Crypto/CryptoProvider.h>
#include <Swiften/Crypto/PlatformCryptoProvider.h>
+#include <Swiften/Disco/CapsInfoGenerator.h>
+#include <Swiften/Disco/CapsManager.h>
#include <Swiften/Disco/CapsProvider.h>
+#include <Swiften/Disco/ClientDiscoManager.h>
#include <Swiften/Disco/EntityCapsManager.h>
#include <Swiften/EventLoop/DummyEventLoop.h>
-#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h>
#include <Swiften/Jingle/JingleSessionManager.h>
#include <Swiften/MUC/MUCRegistry.h>
#include <Swiften/Presence/PresenceOracle.h>
@@ -29,7 +32,6 @@
#include <Swiften/VCards/VCardManager.h>
#include <Swiften/VCards/VCardMemoryStorage.h>
-#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/Roster/Roster.h>
@@ -42,8 +44,6 @@
using namespace Swift;
-#define CHILDREN mainWindow_->roster->getRoot()->getChildren()
-
class DummyCapsProvider : public CapsProvider {
DiscoInfo::ref getCaps(const std::string&) const {return DiscoInfo::ref(new DiscoInfo());}
};
@@ -61,6 +61,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testUnavailablePresence);
CPPUNIT_TEST(testRemoveResultsInUnavailablePresence);
CPPUNIT_TEST(testOwnContactInRosterPresence);
+ CPPUNIT_TEST(testMultiResourceFileTransferFeature);
CPPUNIT_TEST_SUITE_END();
public:
@@ -70,6 +71,8 @@ class RosterControllerTest : public CppUnit::TestFixture {
avatarManager_ = new NullAvatarManager();
mainWindowFactory_ = new MockMainWindowFactory();
mucRegistry_ = new MUCRegistry();
+ crypto_ = PlatformCryptoProvider::create();
+ storages_ = std::unique_ptr<MemoryStorages>(new MemoryStorages(crypto_));
nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, nullptr, mucRegistry_);
channel_ = new DummyIQChannel();
router_ = new IQRouter(channel_);
@@ -80,18 +83,16 @@ class RosterControllerTest : public CppUnit::TestFixture {
uiEventStream_ = new UIEventStream();
settings_ = new DummySettingsProvider();
nickManager_ = new DummyNickManager();
- capsProvider_ = new DummyCapsProvider();
- entityCapsManager_ = new EntityCapsManager(capsProvider_, stanzaChannel_);
+ capsManager_ = std::unique_ptr<CapsManager>(new CapsManager(storages_->getCapsStorage(), stanzaChannel_, router_, crypto_));
+ entityCapsManager_ = new EntityCapsManager(capsManager_.get(), stanzaChannel_);
jingleSessionManager_ = new JingleSessionManager(router_);
- ftManager_ = new DummyFileTransferManager();
- ftOverview_ = new FileTransferOverview(ftManager_);
clientBlockListManager_ = new ClientBlockListManager(router_);
- crypto_ = PlatformCryptoProvider::create();
vcardStorage_ = new VCardMemoryStorage(crypto_);
vcardManager_ = new VCardManager(jid_, router_, vcardStorage_);
- rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, ftOverview_, clientBlockListManager_, vcardManager_);
+ rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, clientBlockListManager_, vcardManager_);
mainWindow_ = mainWindowFactory_->last;
+ capsInfoGenerator_ = std::unique_ptr<CapsInfoGenerator>(new CapsInfoGenerator("", crypto_));
}
void tearDown() {
@@ -100,11 +101,8 @@ class RosterControllerTest : public CppUnit::TestFixture {
delete vcardStorage_;
delete crypto_;
delete clientBlockListManager_;
- delete ftOverview_;
- delete ftManager_;
delete jingleSessionManager_;
delete entityCapsManager_;
- delete capsProvider_;
delete nickManager_;
delete nickResolver_;
delete mucRegistry_;
@@ -122,7 +120,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
}
GroupRosterItem* groupChild(size_t i) {
- return dynamic_cast<GroupRosterItem*>(CHILDREN[i]);
+ return dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[i]);
}
JID withResource(const JID& jid, const std::string& resource) {
@@ -140,10 +138,10 @@ class RosterControllerTest : public CppUnit::TestFixture {
presence->setPriority(2);
presence->setStatus("So totally here");
stanzaChannel_->onPresenceReceived(presence);
- ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]);
+ ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[0])->getChildren()[0]);
CPPUNIT_ASSERT(item);
CPPUNIT_ASSERT_EQUAL(presence->getStatus(), item->getStatusText());
- ContactRosterItem* item2 = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[1])->getChildren()[0]);
+ ContactRosterItem* item2 = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[1])->getChildren()[0]);
CPPUNIT_ASSERT(item2);
CPPUNIT_ASSERT_EQUAL(presence->getStatus(), item2->getStatusText());
}
@@ -163,7 +161,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
highPresence->setStatus("So totally here");
stanzaChannel_->onPresenceReceived(lowPresence);
stanzaChannel_->onPresenceReceived(highPresence);
- ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]);
+ ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[0])->getChildren()[0]);
CPPUNIT_ASSERT(item);
CPPUNIT_ASSERT_EQUAL(highPresence->getStatus(), item->getStatusText());
}
@@ -183,7 +181,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
highPresence->setStatus("So totally here");
stanzaChannel_->onPresenceReceived(highPresence);
stanzaChannel_->onPresenceReceived(lowPresence);
- ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]);
+ ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[0])->getChildren()[0]);
CPPUNIT_ASSERT(item);
CPPUNIT_ASSERT_EQUAL(highPresence->getStatus(), item->getStatusText());
}
@@ -223,7 +221,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
stanzaChannel_->onPresenceReceived(highPresenceOffline);
// After this, the roster should show the low presence.
- ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]);
+ ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[0])->getChildren()[0]);
CPPUNIT_ASSERT(item);
Presence::ref low = presenceOracle_->getAccountPresence(from);
@@ -233,7 +231,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(lowPresence->getShow(), item->getStatusShow());
CPPUNIT_ASSERT_EQUAL(lowPresence->getStatus(), item->getStatusText());
stanzaChannel_->onPresenceReceived(lowPresenceOffline);
- item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]);
+ item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[0])->getChildren()[0]);
CPPUNIT_ASSERT(item);
/* A verification that if the test fails, it's the RosterController, not the PresenceOracle. */
low = presenceOracle_->getHighestPriorityPresence(from);
@@ -249,7 +247,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
groups.push_back("testGroup2");
xmppRoster_->addContact(JID("test@testdomain.com/bob"), "name", groups, RosterItemPayload::Both);
- CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(CHILDREN.size()));
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(getUIRosterChildren().size()));
//CPPUNIT_ASSERT_EQUAL(std::string("Bob"), xmppRoster_->getNameForJID(JID("foo@bar.com")));
}
@@ -258,14 +256,14 @@ class RosterControllerTest : public CppUnit::TestFixture {
JID jid("test@testdomain.com");
xmppRoster_->addContact(jid, "name", groups, RosterItemPayload::None);
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(getUIRosterChildren().size()));
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
xmppRoster_->addContact(jid, "name", groups, RosterItemPayload::To);
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(getUIRosterChildren().size()));
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
xmppRoster_->addContact(jid, "name", groups, RosterItemPayload::Both);
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(getUIRosterChildren().size()));
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
}
@@ -275,11 +273,11 @@ class RosterControllerTest : public CppUnit::TestFixture {
JID jid("test@testdomain.com");
xmppRoster_->addContact(jid, "name", groups, RosterItemPayload::Both);
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(getUIRosterChildren().size()));
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
CPPUNIT_ASSERT_EQUAL(std::string("name"), groupChild(0)->getChildren()[0]->getDisplayName());
xmppRoster_->addContact(jid, "NewName", groups, RosterItemPayload::Both);
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(getUIRosterChildren().size()));
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
CPPUNIT_ASSERT_EQUAL(std::string("NewName"), groupChild(0)->getChildren()[0]->getDisplayName());
}
@@ -293,18 +291,18 @@ class RosterControllerTest : public CppUnit::TestFixture {
JID jid("test@testdomain.com");
xmppRoster_->addContact(jid, "", oldGroups, RosterItemPayload::Both);
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(getUIRosterChildren().size()));
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
CPPUNIT_ASSERT_EQUAL(jid.toString(), groupChild(0)->getChildren()[0]->getDisplayName());
xmppRoster_->addContact(jid, "new name", newGroups, RosterItemPayload::Both);
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(getUIRosterChildren().size()));
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
CPPUNIT_ASSERT_EQUAL(std::string("new name"), groupChild(0)->getChildren()[0]->getDisplayName());
CPPUNIT_ASSERT_EQUAL(std::string("A Group"), groupChild(0)->getDisplayName());
xmppRoster_->addContact(jid, "new name", newestGroups, RosterItemPayload::Both);
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(getUIRosterChildren().size()));
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
CPPUNIT_ASSERT_EQUAL(std::string("new name"), groupChild(0)->getChildren()[0]->getDisplayName());
CPPUNIT_ASSERT_EQUAL(std::string("Best Group"), groupChild(0)->getDisplayName());
@@ -364,14 +362,79 @@ class RosterControllerTest : public CppUnit::TestFixture {
presence->setPriority(2);
presence->setStatus("So totally here");
stanzaChannel_->onPresenceReceived(presence);
- ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]);
+ ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[0])->getChildren()[0]);
CPPUNIT_ASSERT(item);
CPPUNIT_ASSERT_EQUAL(presence->getStatus(), item->getStatusText());
- ContactRosterItem* item2 = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[1])->getChildren()[0]);
+ ContactRosterItem* item2 = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[1])->getChildren()[0]);
CPPUNIT_ASSERT(item2);
CPPUNIT_ASSERT_EQUAL(presence->getStatus(), item2->getStatusText());
}
+ // This tests a scenario of a contact having a resource supporting Jingle File Transfer and
+ // one resource not supporting it, and the contact features being set correctly.
+ void testMultiResourceFileTransferFeature() {
+ JID contact("test@testdomain.com");
+ xmppRoster_->addContact(contact, "Name", {}, RosterItemPayload::Both);
+
+ auto sendPresenceAndAnswerCaps = [=](const JID& from, const DiscoInfo& discoInfo) {
+ auto capsInfo = capsInfoGenerator_->generateCapsInfo(discoInfo);
+
+ auto ftClientPresence = std::make_shared<Presence>();
+ ftClientPresence->setFrom(from);
+ ftClientPresence->setPriority(0);
+ ftClientPresence->setShow(StatusShow::Online);
+ ftClientPresence->addPayload(std::make_shared<CapsInfo>(capsInfo));
+ stanzaChannel_->onPresenceReceived(ftClientPresence);
+
+ // disco reply
+ auto discoRequest = channel_->iqs_.back();
+ CPPUNIT_ASSERT(discoRequest);
+ auto discoReply = IQ::createResult(discoRequest->getFrom(), ftClientPresence->getFrom(), discoRequest->getID(), std::make_shared<DiscoInfo>(discoInfo));
+ channel_->onIQReceived(discoReply);
+ };
+
+ auto ftDiscoInfo = DiscoInfo();
+ ftDiscoInfo.addFeature(DiscoInfo::JingleFeature);
+ ftDiscoInfo.addFeature(DiscoInfo::JingleFTFeature);
+ ftDiscoInfo.addFeature(DiscoInfo::JingleTransportsIBBFeature);
+
+ sendPresenceAndAnswerCaps(contact.withResource("ft-supported"), ftDiscoInfo);
+
+ auto* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[0])->getChildren()[0]);
+ CPPUNIT_ASSERT(item);
+ CPPUNIT_ASSERT_EQUAL(contact, item->getJID());
+ CPPUNIT_ASSERT_EQUAL(true, item->supportsFeature(ContactRosterItem::FileTransferFeature));
+
+ sendPresenceAndAnswerCaps(contact.withResource("ft-unsupported"), DiscoInfo());
+
+ item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[0])->getChildren()[0]);
+ CPPUNIT_ASSERT(item);
+ CPPUNIT_ASSERT_EQUAL(contact, item->getJID());
+ CPPUNIT_ASSERT_EQUAL(true, item->supportsFeature(ContactRosterItem::FileTransferFeature));
+
+ auto unavailablePresence = std::make_shared<Presence>();
+ unavailablePresence->setFrom(contact.withResource("ft-unsupported"));
+ unavailablePresence->setPriority(0);
+ unavailablePresence->setType(Presence::Unavailable);
+ stanzaChannel_->onPresenceReceived(unavailablePresence);
+
+ item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[0])->getChildren()[0]);
+ CPPUNIT_ASSERT(item);
+ CPPUNIT_ASSERT_EQUAL(contact, item->getJID());
+ CPPUNIT_ASSERT_EQUAL(true, item->supportsFeature(ContactRosterItem::FileTransferFeature));
+
+ unavailablePresence = std::make_shared<Presence>();
+ unavailablePresence->setFrom(contact.withResource("ft-supported"));
+ unavailablePresence->setPriority(0);
+ unavailablePresence->setType(Presence::Unavailable);
+ stanzaChannel_->onPresenceReceived(unavailablePresence);
+
+ item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(getUIRosterChildren()[0])->getChildren()[0]);
+ CPPUNIT_ASSERT(item);
+ CPPUNIT_ASSERT_EQUAL(contact, item->getJID());
+ CPPUNIT_ASSERT_EQUAL(false, item->supportsFeature(ContactRosterItem::FileTransferFeature));
+ }
+
void assertVectorsEqual(const std::vector<std::string>& v1, const std::vector<std::string>& v2, int line) {
for (const auto& entry : v1) {
if (std::find(v2.begin(), v2.end(), entry) == v2.end()) {
@@ -382,8 +445,13 @@ class RosterControllerTest : public CppUnit::TestFixture {
}
}
+ const std::vector<RosterItem*>& getUIRosterChildren() const {
+ return mainWindow_->roster->getRoot()->getChildren();
+ }
+
private:
JID jid_;
+ std::unique_ptr<MemoryStorages> storages_;
XMPPRosterImpl* xmppRoster_;
MUCRegistry* mucRegistry_;
AvatarManager* avatarManager_;
@@ -400,15 +468,14 @@ class RosterControllerTest : public CppUnit::TestFixture {
UIEventStream* uiEventStream_;
MockMainWindow* mainWindow_;
DummySettingsProvider* settings_;
- DummyCapsProvider* capsProvider_;
+ std::unique_ptr<CapsManager> capsManager_;
EntityCapsManager* entityCapsManager_;
JingleSessionManager* jingleSessionManager_;
- FileTransferManager* ftManager_;
- FileTransferOverview* ftOverview_;
ClientBlockListManager* clientBlockListManager_;
CryptoProvider* crypto_;
VCardStorage* vcardStorage_;
VCardManager* vcardManager_;
+ std::unique_ptr<CapsInfoGenerator> capsInfoGenerator_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(RosterControllerTest);