summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2015-09-14 15:08:39 (GMT)
committerKevin Smith <kevin.smith@isode.com>2015-10-16 14:58:03 (GMT)
commit9e6ee0f262e7dc663f4c706b16a346a268f425aa (patch)
tree5926fd9cc9dec1233f95239b259a7730f99a5a72
parent8da6e35afab55d7232d47575faea2bde7cd44ece (diff)
downloadswift-9e6ee0f262e7dc663f4c706b16a346a268f425aa.zip
swift-9e6ee0f262e7dc663f4c706b16a346a268f425aa.tar.bz2
Mark removed contacts as unavailable in Swift
When removing a contact, a XMPP client will not receive an explicit unavailable presence stanza for the contact from the server. Because of that Swift used to show removed contacts still with their old presence in the Chats tab or the chat view. With this patch, the PresenceOracle will flush all known presence of a contact as soon as the JID is removed from the roster. An unavailable presence will stored under the removed bare JID and is emitted via the PresenceOracle::onPresenceChange signal. Test-Information: Added a unit test verifying this behavior. Tested the behavior with two scenarios: a) Account A and B adding each other and accepting the subscription request. Starting a chat between A and B. After removing B in A's account, B used to be shown as available in the chat view and the Chats tab. With this patch B is shown as unavailable. b) Account A and B adding each other and accepting the subscription request. A removing B, and B removing A. After A adds B again, B used to be shown with the old presence even before B accepted the subscription request. This behavior is also fixed with this patch, not showing B as online until B accepted the subscription request. Change-Id: Iba97d3bedd0ac962ea00b25a0d2ed6106ed55a55
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp2
-rw-r--r--Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp6
-rw-r--r--Swift/Controllers/Roster/RosterController.cpp16
-rw-r--r--Swift/Controllers/Roster/RosterController.h44
-rw-r--r--Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp34
-rw-r--r--Swift/Controllers/UnitTest/PresenceNotifierTest.cpp30
-rw-r--r--Swiften/Client/Client.cpp2
-rw-r--r--Swiften/Presence/PresenceOracle.cpp27
-rw-r--r--Swiften/Presence/PresenceOracle.h10
-rw-r--r--Swiften/Presence/UnitTest/PresenceOracleTest.cpp17
-rw-r--r--Swiften/Roster/XMPPRosterImpl.cpp7
-rw-r--r--Swiften/Roster/XMPPRosterImpl.h3
12 files changed, 132 insertions, 66 deletions
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index 487f0f9..f276e92 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -83,19 +83,19 @@ public:
iqChannel_ = new DummyIQChannel();
iqRouter_ = new IQRouter(iqChannel_);
// capsProvider_ = new DummyCapsProvider();
eventController_ = new EventController();
chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
joinMUCWindowFactory_ = mocks_->InterfaceMock<JoinMUCWindowFactory>();
xmppRoster_ = new XMPPRosterImpl();
mucRegistry_ = new MUCRegistry();
nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_);
- presenceOracle_ = new PresenceOracle(stanzaChannel_);
+ presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
serverDiscoInfo_ = boost::make_shared<DiscoInfo>();
presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_);
uiEventStream_ = new UIEventStream();
// entityCapsManager_ = new EntityCapsManager(capsProvider_, stanzaChannel_);
entityCapsProvider_ = new DummyEntityCapsProvider();
chatListWindowFactory_ = mocks_->InterfaceMock<ChatListWindowFactory>();
mucSearchWindowFactory_ = mocks_->InterfaceMock<MUCSearchWindowFactory>();
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index cc4045a..bc6ada2 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -21,18 +21,19 @@
#include <Swiften/Elements/MUCUserPayload.h>
#include <Swiften/MUC/MUCBookmarkManager.h>
#include <Swiften/MUC/UnitTest/MockMUC.h>
#include <Swiften/Network/TimerFactory.h>
#include <Swiften/Presence/DirectedPresenceSender.h>
#include <Swiften/Presence/PresenceOracle.h>
#include <Swiften/Presence/StanzaChannelPresenceSender.h>
#include <Swiften/Queries/DummyIQChannel.h>
#include <Swiften/Roster/XMPPRoster.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
#include <Swiften/VCards/VCardManager.h>
#include <Swiften/VCards/VCardMemoryStorage.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
#include <Swift/Controllers/Chat/MUCController.h>
#include <Swift/Controllers/Chat/UserSearchController.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/Roster/Roster.h>
#include <Swift/Controllers/Settings/DummySettingsProvider.h>
@@ -66,19 +67,20 @@ public:
nick_ = "aLiCe";
mucJID_ = JID("teaparty@rooms.wonderland.lit");
mocks_ = new MockRepository();
stanzaChannel_ = new DummyStanzaChannel();
iqChannel_ = new DummyIQChannel();
iqRouter_ = new IQRouter(iqChannel_);
eventController_ = new EventController();
chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
userSearchWindowFactory_ = mocks_->InterfaceMock<UserSearchWindowFactory>();
- presenceOracle_ = new PresenceOracle(stanzaChannel_);
+ xmppRoster_ = new XMPPRosterImpl();
+ presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
uiEventStream_ = new UIEventStream();
avatarManager_ = new NullAvatarManager();
TimerFactory* timerFactory = NULL;
window_ = new MockChatWindow();
mucRegistry_ = new MUCRegistry();
entityCapsProvider_ = new DummyEntityCapsProvider();
settings_ = new DummySettingsProvider();
@@ -98,18 +100,19 @@ public:
delete mucBookmarkManager_;
delete clientBlockListManager_;
delete vcardManager_;
delete vcardStorage_;
delete highlightManager_;
delete settings_;
delete entityCapsProvider_;
delete eventController_;
delete presenceOracle_;
+ delete xmppRoster_;
delete mocks_;
delete uiEventStream_;
delete stanzaChannel_;
delete presenceSender_;
delete directedPresenceSender_;
delete iqRouter_;
delete iqChannel_;
delete mucRegistry_;
delete avatarManager_;
@@ -436,13 +439,14 @@ private:
DummyEntityCapsProvider* entityCapsProvider_;
DummySettingsProvider* settings_;
HighlightManager* highlightManager_;
boost::shared_ptr<ChatMessageParser> chatMessageParser_;
boost::shared_ptr<CryptoProvider> crypto_;
VCardManager* vcardManager_;
VCardMemoryStorage* vcardStorage_;
ClientBlockListManager* clientBlockListManager_;
MUCBookmarkManager* mucBookmarkManager_;
+ XMPPRoster* xmppRoster_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest);
diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp
index 2d35b6a..73efa43 100644
--- a/Swift/Controllers/Roster/RosterController.cpp
+++ b/Swift/Controllers/Roster/RosterController.cpp
@@ -1,51 +1,55 @@
/*
- * Copyright (c) 2010-2014 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/Controllers/Roster/RosterController.h>
#include <boost/bind.hpp>
#include <boost/smart_ptr/make_shared.hpp>
+#include <Swiften/Avatars/AvatarManager.h>
+#include <Swiften/Base/Path.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Base/format.h>
-#include <Swiften/Base/Path.h>
#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/NickManager.h>
#include <Swiften/Client/NickResolver.h>
#include <Swiften/Disco/EntityCapsManager.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/FileTransfer/FileTransferManager.h>
#include <Swiften/JID/JID.h>
#include <Swiften/Jingle/JingleSessionManager.h>
#include <Swiften/Presence/PresenceOracle.h>
#include <Swiften/Presence/SubscriptionManager.h>
#include <Swiften/Queries/IQRouter.h>
#include <Swiften/Roster/GetRosterRequest.h>
#include <Swiften/Roster/SetRosterRequest.h>
#include <Swiften/Roster/XMPPRoster.h>
#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/OfflineRosterFilter.h>
-#include <Swift/Controllers/Roster/Roster.h>
-#include <Swift/Controllers/Roster/RosterVCardProvider.h>
#include <Swift/Controllers/Roster/ItemOperations/AppearOffline.h>
-#include <Swift/Controllers/Roster/ItemOperations/SetAvatar.h>
#include <Swift/Controllers/Roster/ItemOperations/SetAvailableFeatures.h>
+#include <Swift/Controllers/Roster/ItemOperations/SetAvatar.h>
#include <Swift/Controllers/Roster/ItemOperations/SetBlockingState.h>
#include <Swift/Controllers/Roster/ItemOperations/SetName.h>
#include <Swift/Controllers/Roster/ItemOperations/SetPresence.h>
#include <Swift/Controllers/Roster/ItemOperations/SetVCard.h>
+#include <Swift/Controllers/Roster/OfflineRosterFilter.h>
+#include <Swift/Controllers/Roster/Roster.h>
+#include <Swift/Controllers/Roster/RosterGroupExpandinessPersister.h>
+#include <Swift/Controllers/Roster/RosterVCardProvider.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/UIEvents/AddContactUIEvent.h>
#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>
diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h
index f4ae581..545abfc 100644
--- a/Swift/Controllers/Roster/RosterController.h
+++ b/Swift/Controllers/Roster/RosterController.h
@@ -1,59 +1,61 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
-#include <string>
#include <set>
+#include <string>
#include <boost/shared_ptr.hpp>
+#include <Swiften/Avatars/AvatarManager.h>
#include <Swiften/Base/boost_bsignals.h>
-#include <Swiften/JID/JID.h>
-#include <Swiften/Elements/Presence.h>
#include <Swiften/Elements/ErrorPayload.h>
+#include <Swiften/Elements/Presence.h>
#include <Swiften/Elements/RosterPayload.h>
-#include <Swiften/Avatars/AvatarManager.h>
-#include <Swiften/VCards/VCardManager.h>
+#include <Swiften/Elements/VCard.h>
+#include <Swiften/JID/JID.h>
+#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swift/Controllers/UIEvents/UIEvent.h>
-#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
-#include <Swift/Controllers/Roster/RosterGroupExpandinessPersister.h>
namespace Swift {
+ class AvatarManager;
+ class ClientBlockListManager;
+ class EntityCapsProvider;
+ class EventController;
+ class FileTransferManager;
+ class FileTransferOverview;
class IQRouter;
- class Roster;
- class XMPPRoster;
- class XMPPRosterItem;
class MainWindow;
class MainWindowFactory;
- class OfflineRosterFilter;
+ class NickManager;
class NickResolver;
+ class OfflineRosterFilter;
class PresenceOracle;
+ class Roster;
+ class RosterGroupExpandinessPersister;
+ class RosterVCardProvider;
+ class SettingsProvider;
class SubscriptionManager;
- class EventController;
class SubscriptionRequestEvent;
class UIEventStream;
- class IQRouter;
- class SettingsProvider;
- class NickManager;
- class EntityCapsProvider;
- class FileTransferManager;
- class ClientBlockListManager;
- class RosterVCardProvider;
+ class VCardManager;
+ class XMPPRoster;
+ class XMPPRosterItem;
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, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager);
~RosterController();
void showRosterWindow();
void setJID(const JID& jid) { myJID_ = jid; }
MainWindow* getWindow() {return mainWindow_;}
boost::signal<void (StatusShow::Type, const std::string&)> onChangeStatusRequest;
boost::signal<void ()> onSignOutRequest;
void handleOwnVCardChanged(VCard::ref vcard);
void handleAvatarChanged(const JID& jid);
void handlePresenceChanged(Presence::ref presence);
diff --git a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
index c396e48..9320af1 100644
--- a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
@@ -1,12 +1,11 @@
-
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <Swiften/Avatars/NullAvatarManager.h>
#include <Swiften/Base/Algorithm.h>
@@ -22,23 +21,22 @@
#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>
#include <Swiften/Presence/SubscriptionManager.h>
#include <Swiften/Queries/DummyIQChannel.h>
#include <Swiften/Queries/IQRouter.h>
#include <Swiften/Roster/XMPPRosterImpl.h>
+#include <Swiften/VCards/VCardManager.h>
#include <Swiften/VCards/VCardMemoryStorage.h>
-// #include <Swiften/Elements/Payload.h>
-// #include <Swiften/Elements/RosterItemPayload.h>
-// #include <Swiften/Elements/RosterPayload.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>
#include <Swift/Controllers/Roster/RosterController.h>
#include <Swift/Controllers/Settings/DummySettingsProvider.h>
#include <Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UnitTest/MockMainWindowFactory.h>
#include <Swift/Controllers/XMPPEvents/EventController.h>
@@ -56,32 +54,33 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testAdd);
CPPUNIT_TEST(testAddSubscription);
CPPUNIT_TEST(testReceiveRename);
CPPUNIT_TEST(testReceiveRegroup);
CPPUNIT_TEST(testSendRename);
CPPUNIT_TEST(testPresence);
CPPUNIT_TEST(testHighestPresence);
CPPUNIT_TEST(testNotHighestPresence);
CPPUNIT_TEST(testUnavailablePresence);
+ CPPUNIT_TEST(testRemoveResultsInUnavailablePresence);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
jid_ = JID("testjid@swift.im/swift");
xmppRoster_ = new XMPPRosterImpl();
avatarManager_ = new NullAvatarManager();
mainWindowFactory_ = new MockMainWindowFactory();
mucRegistry_ = new MUCRegistry();
nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_);
channel_ = new DummyIQChannel();
router_ = new IQRouter(channel_);
stanzaChannel_ = new DummyStanzaChannel();
- presenceOracle_ = new PresenceOracle(stanzaChannel_);
+ presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
subscriptionManager_ = new SubscriptionManager(stanzaChannel_);
eventController_ = new EventController();
uiEventStream_ = new UIEventStream();
settings_ = new DummySettingsProvider();
nickManager_ = new DummyNickManager();
capsProvider_ = new DummyCapsProvider();
entityCapsManager_ = new EntityCapsManager(capsProvider_, stanzaChannel_);
jingleSessionManager_ = new JingleSessionManager(router_);
@@ -313,18 +312,41 @@ class RosterControllerTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), payload->getItems().size());
RosterItemPayload item = payload->getItems()[0];
CPPUNIT_ASSERT_EQUAL(jid, item.getJID());
CPPUNIT_ASSERT_EQUAL(std::string("Robert"), item.getName());
CPPUNIT_ASSERT_EQUAL(groups.size(), item.getGroups().size());
assertVectorsEqual(groups, item.getGroups(), __LINE__);
}
+ void testRemoveResultsInUnavailablePresence() {
+ std::vector<std::string> groups;
+ groups.push_back("testGroup1");
+ JID from("test@testdomain.com");
+ xmppRoster_->addContact(from, "name", groups, RosterItemPayload::Both);
+ Presence::ref lowPresence(new Presence());
+ lowPresence->setFrom(withResource(from, "bob"));
+ lowPresence->setPriority(2);
+ lowPresence->setStatus("Not here");
+ Presence::ref highPresence(new Presence());
+ highPresence->setFrom(withResource(from, "bert"));
+ highPresence->setPriority(10);
+ highPresence->setStatus("So totally here");
+ stanzaChannel_->onPresenceReceived(highPresence);
+ stanzaChannel_->onPresenceReceived(lowPresence);
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), presenceOracle_->getAllPresence("test@testdomain.com").size());
+
+ xmppRoster_->onJIDRemoved(JID("test@testdomain.com"));
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), presenceOracle_->getAllPresence("test@testdomain.com").size());
+ CPPUNIT_ASSERT_EQUAL(Presence::Unavailable, presenceOracle_->getAllPresence("test@testdomain.com")[0]->getType());
+ }
+
void assertVectorsEqual(const std::vector<std::string>& v1, const std::vector<std::string>& v2, int line) {
foreach (const std::string& entry, v1) {
if (std::find(v2.begin(), v2.end(), entry) == v2.end()) {
std::stringstream stream;
stream << "Couldn't find " << entry << " in v2 (line " << line << ")";
CPPUNIT_FAIL(stream.str());
}
}
}
diff --git a/Swift/Controllers/UnitTest/PresenceNotifierTest.cpp b/Swift/Controllers/UnitTest/PresenceNotifierTest.cpp
index 681177a..40530dc 100644
--- a/Swift/Controllers/UnitTest/PresenceNotifierTest.cpp
+++ b/Swift/Controllers/UnitTest/PresenceNotifierTest.cpp
@@ -1,29 +1,33 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
#include <vector>
+
#include <boost/bind.hpp>
-#include "Swift/Controllers/PresenceNotifier.h"
-#include "Swiften/Client/NickResolver.h"
-#include "SwifTools/Notifier/LoggingNotifier.h"
-#include "Swiften/Client/DummyStanzaChannel.h"
-#include "Swiften/MUC/MUCRegistry.h"
-#include "Swiften/Roster/XMPPRosterImpl.h"
-#include "Swiften/Presence/PresenceOracle.h"
-#include "Swiften/Avatars/DummyAvatarManager.h"
-#include "Swiften/Network/DummyTimerFactory.h"
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <Swiften/Avatars/DummyAvatarManager.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/MUC/MUCRegistry.h>
+#include <Swiften/Network/DummyTimerFactory.h>
+#include <Swiften/Presence/PresenceOracle.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
+
+#include <Swift/Controllers/PresenceNotifier.h>
+
+#include <SwifTools/Notifier/LoggingNotifier.h>
using namespace Swift;
class PresenceNotifierTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(PresenceNotifierTest);
CPPUNIT_TEST(testReceiveFirstPresenceCreatesAvailableNotification);
CPPUNIT_TEST(testReceiveSecondPresenceCreatesStatusChangeNotification);
CPPUNIT_TEST(testReceiveUnavailablePresenceAfterAvailablePresenceCreatesUnavailableNotification);
CPPUNIT_TEST(testReceiveUnavailablePresenceWithoutAvailableDoesNotCreateNotification);
@@ -48,19 +52,19 @@ class PresenceNotifierTest : public CppUnit::TestFixture {
void setUp() {
stanzaChannel = new DummyStanzaChannel();
notifier = new LoggingNotifier();
mucRegistry = new MUCRegistry();
user1 = JID("user1@bar.com/bla");
user2 = JID("user2@foo.com/baz");
avatarManager = new DummyAvatarManager();
roster = new XMPPRosterImpl();
nickResolver = new NickResolver(JID("foo@bar.com"), roster, NULL, mucRegistry);
- presenceOracle = new PresenceOracle(stanzaChannel);
+ presenceOracle = new PresenceOracle(stanzaChannel, roster);
timerFactory = new DummyTimerFactory();
}
void tearDown() {
delete timerFactory;
delete presenceOracle;
delete nickResolver;
delete roster;
delete avatarManager;
diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp
index 3bfdd3f..f1266e9 100644
--- a/Swiften/Client/Client.cpp
+++ b/Swiften/Client/Client.cpp
@@ -43,19 +43,19 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net
softwareVersionResponder = new SoftwareVersionResponder(getIQRouter());
softwareVersionResponder->start();
roster = new XMPPRosterImpl();
rosterController = new XMPPRosterController(getIQRouter(), roster, getStorages()->getRosterStorage());
subscriptionManager = new SubscriptionManager(getStanzaChannel());
- presenceOracle = new PresenceOracle(getStanzaChannel());
+ presenceOracle = new PresenceOracle(getStanzaChannel(), roster);
presenceOracle->onPresenceChange.connect(boost::ref(onPresenceChange));
stanzaChannelPresenceSender = new StanzaChannelPresenceSender(getStanzaChannel());
directedPresenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender);
discoManager = new ClientDiscoManager(getIQRouter(), directedPresenceSender, networkFactories->getCryptoProvider());
mucRegistry = new MUCRegistry();
mucManager = new MUCManager(getStanzaChannel(), getIQRouter(), directedPresenceSender, mucRegistry);
diff --git a/Swiften/Presence/PresenceOracle.cpp b/Swiften/Presence/PresenceOracle.cpp
index 59dff41..e4129fb 100644
--- a/Swiften/Presence/PresenceOracle.cpp
+++ b/Swiften/Presence/PresenceOracle.cpp
@@ -1,72 +1,87 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#include "PresenceOracle.h"
+#include <Swiften/Presence/PresenceOracle.h>
#include <boost/bind.hpp>
#include <Swiften/Client/StanzaChannel.h>
+#include <Swiften/Roster/XMPPRoster.h>
namespace Swift {
-PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel) {
- stanzaChannel_ = stanzaChannel;
+PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster) : stanzaChannel_(stanzaChannel), xmppRoster_(roster) {
stanzaChannel_->onPresenceReceived.connect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1));
stanzaChannel_->onAvailableChanged.connect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1));
+ xmppRoster_->onJIDRemoved.connect(boost::bind(&PresenceOracle::handleJIDRemoved, this, _1));
}
PresenceOracle::~PresenceOracle() {
stanzaChannel_->onPresenceReceived.disconnect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1));
stanzaChannel_->onAvailableChanged.disconnect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1));
+ xmppRoster_->onJIDRemoved.disconnect(boost::bind(&PresenceOracle::handleJIDRemoved, this, _1));
}
void PresenceOracle::handleStanzaChannelAvailableChanged(bool available) {
if (available) {
entries_.clear();
}
}
-
void PresenceOracle::handleIncomingPresence(Presence::ref presence) {
JID bareJID(presence->getFrom().toBare());
if (presence->getType() == Presence::Subscribe) {
}
else {
Presence::ref passedPresence = presence;
if (presence->getType() == Presence::Unsubscribe) {
/* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */
passedPresence = Presence::ref(new Presence());
passedPresence->setType(Presence::Unavailable);
passedPresence->setFrom(bareJID);
passedPresence->setStatus(presence->getStatus());
}
- std::map<JID, boost::shared_ptr<Presence> > jidMap = entries_[bareJID];
+ PresenceMap jidMap = entries_[bareJID];
if (passedPresence->getFrom().isBare() && presence->getType() == Presence::Unavailable) {
/* Have a bare-JID only presence of offline */
jidMap.clear();
} else if (passedPresence->getType() == Presence::Available) {
/* Don't have a bare-JID only offline presence once there are available presences */
jidMap.erase(bareJID);
}
if (passedPresence->getType() == Presence::Unavailable && jidMap.size() > 1) {
jidMap.erase(passedPresence->getFrom());
} else {
jidMap[passedPresence->getFrom()] = passedPresence;
}
entries_[bareJID] = jidMap;
onPresenceChange(passedPresence);
}
}
+void PresenceOracle::handleJIDRemoved(const JID& removedJID) {
+ /* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */
+ Presence::ref unavailablePresence = Presence::ref(new Presence());
+ unavailablePresence->setType(Presence::Unavailable);
+ unavailablePresence->setFrom(removedJID);
+
+ if (entries_.find(removedJID) != entries_.end()) {
+ entries_[removedJID].clear();
+ entries_[removedJID][removedJID] = unavailablePresence;
+ }
+
+ onPresenceChange(unavailablePresence);
+}
+
Presence::ref PresenceOracle::getLastPresence(const JID& jid) const {
PresencesMap::const_iterator i = entries_.find(jid.toBare());
if (i == entries_.end()) {
return Presence::ref();
}
PresenceMap presenceMap = i->second;
PresenceMap::const_iterator j = presenceMap.find(jid);
if (j != presenceMap.end()) {
return j->second;
diff --git a/Swiften/Presence/PresenceOracle.h b/Swiften/Presence/PresenceOracle.h
index 84d5b3c..f312506 100644
--- a/Swiften/Presence/PresenceOracle.h
+++ b/Swiften/Presence/PresenceOracle.h
@@ -1,43 +1,45 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <map>
-
#include <string>
-#include <Swiften/Elements/Presence.h>
#include <Swiften/Base/API.h>
#include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/Elements/Presence.h>
namespace Swift {
class StanzaChannel;
+ class XMPPRoster;
class SWIFTEN_API PresenceOracle {
public:
- PresenceOracle(StanzaChannel* stanzaChannel);
+ PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster);
~PresenceOracle();
Presence::ref getLastPresence(const JID&) const;
Presence::ref getHighestPriorityPresence(const JID& bareJID) const;
std::vector<Presence::ref> getAllPresence(const JID& bareJID) const;
public:
boost::signal<void (Presence::ref)> onPresenceChange;
private:
void handleIncomingPresence(Presence::ref presence);
void handleStanzaChannelAvailableChanged(bool);
+ void handleJIDRemoved(const JID& removedJID);
private:
typedef std::map<JID, Presence::ref> PresenceMap;
typedef std::map<JID, PresenceMap> PresencesMap;
PresencesMap entries_;
StanzaChannel* stanzaChannel_;
+ XMPPRoster* xmppRoster_;
};
}
diff --git a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp
index 41857e1..85dcca9 100644
--- a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp
+++ b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp
@@ -1,53 +1,59 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
-#include <Swiften/Presence/PresenceOracle.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Presence/PresenceOracle.h>
#include <Swiften/Presence/SubscriptionManager.h>
+#include <Swiften/Roster/XMPPRoster.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
using namespace Swift;
class PresenceOracleTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(PresenceOracleTest);
CPPUNIT_TEST(testReceivePresence);
CPPUNIT_TEST(testReceivePresenceFromDifferentResources);
CPPUNIT_TEST(testSubscriptionRequest);
CPPUNIT_TEST(testReconnectResetsPresences);
CPPUNIT_TEST(testHighestPresenceSingle);
CPPUNIT_TEST(testHighestPresenceMultiple);
CPPUNIT_TEST(testHighestPresenceGlobal);
CPPUNIT_TEST(testHighestPresenceChangePriority);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
stanzaChannel_ = new DummyStanzaChannel();
- oracle_ = new PresenceOracle(stanzaChannel_);
+ xmppRoster_ = new XMPPRosterImpl();
+
+ oracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
oracle_->onPresenceChange.connect(boost::bind(&PresenceOracleTest::handlePresenceChange, this, _1));
subscriptionManager_ = new SubscriptionManager(stanzaChannel_);
subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2));
user1 = JID("user1@foo.com/Foo");
user1alt = JID("user1@foo.com/Bar");
user2 = JID("user2@bar.com/Bar");
}
void tearDown() {
delete subscriptionManager_;
delete oracle_;
+ delete xmppRoster_;
delete stanzaChannel_;
}
void testHighestPresenceSingle() {
JID bareJID("alice@wonderland.lit");
Presence::ref fiveOn = makeOnline("blah", 5);
Presence::ref fiveOff = makeOffline("/blah");
CPPUNIT_ASSERT_EQUAL(Presence::ref(), oracle_->getHighestPriorityPresence(bareJID));
stanzaChannel_->onPresenceReceived(fiveOn);
@@ -180,18 +186,19 @@ class PresenceOracleTest : public CppUnit::TestFixture {
private:
struct SubscriptionRequestInfo {
JID jid;
std::string reason;
};
PresenceOracle* oracle_;
SubscriptionManager* subscriptionManager_;
DummyStanzaChannel* stanzaChannel_;
+ XMPPRoster* xmppRoster_;
std::vector<Presence::ref> changes;
std::vector<SubscriptionRequestInfo> subscriptionRequests;
JID user1;
JID user1alt;
JID user2;
};
CPPUNIT_TEST_SUITE_REGISTRATION(PresenceOracleTest);
diff --git a/Swiften/Roster/XMPPRosterImpl.cpp b/Swiften/Roster/XMPPRosterImpl.cpp
index d438f69..96b9949 100644
--- a/Swiften/Roster/XMPPRosterImpl.cpp
+++ b/Swiften/Roster/XMPPRosterImpl.cpp
@@ -1,23 +1,28 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swiften/Roster/XMPPRosterImpl.h>
+
#include <Swiften/Base/foreach.h>
namespace Swift {
XMPPRosterImpl::XMPPRosterImpl() {
}
+XMPPRosterImpl::~XMPPRosterImpl() {
+
+}
+
void XMPPRosterImpl::addContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, RosterItemPayload::Subscription subscription) {
JID bareJID(jid.toBare());
std::map<JID, XMPPRosterItem>::iterator i = entries_.find(bareJID);
if (i != entries_.end()) {
std::string oldName = i->second.getName();
std::vector<std::string> oldGroups = i->second.getGroups();
i->second = XMPPRosterItem(jid, name, groups, subscription);
onJIDUpdated(bareJID, oldName, oldGroups);
}
diff --git a/Swiften/Roster/XMPPRosterImpl.h b/Swiften/Roster/XMPPRosterImpl.h
index 6a11b36..284b18a 100644
--- a/Swiften/Roster/XMPPRosterImpl.h
+++ b/Swiften/Roster/XMPPRosterImpl.h
@@ -1,27 +1,28 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <map>
#include <set>
#include <Swiften/Base/API.h>
#include <Swiften/Roster/XMPPRoster.h>
namespace Swift {
class SWIFTEN_API XMPPRosterImpl : public XMPPRoster {
public:
XMPPRosterImpl();
+ virtual ~XMPPRosterImpl();
void addContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, RosterItemPayload::Subscription subscription);
void removeContact(const JID& jid);
void clear();
bool containsJID(const JID& jid);
RosterItemPayload::Subscription getSubscriptionStateForJID(const JID& jid);
std::string getNameForJID(const JID& jid) const;
std::vector<std::string> getGroupsForJID(const JID& jid);