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
@@ -87,11 +87,11 @@ public:
87 chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>(); 87 chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
88 joinMUCWindowFactory_ = mocks_->InterfaceMock<JoinMUCWindowFactory>(); 88 joinMUCWindowFactory_ = mocks_->InterfaceMock<JoinMUCWindowFactory>();
89 xmppRoster_ = new XMPPRosterImpl(); 89 xmppRoster_ = new XMPPRosterImpl();
90 mucRegistry_ = new MUCRegistry(); 90 mucRegistry_ = new MUCRegistry();
91 nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_); 91 nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_);
92 presenceOracle_ = new PresenceOracle(stanzaChannel_); 92 presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
93 serverDiscoInfo_ = boost::make_shared<DiscoInfo>(); 93 serverDiscoInfo_ = boost::make_shared<DiscoInfo>();
94 presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_); 94 presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
95 directedPresenceSender_ = new DirectedPresenceSender(presenceSender_); 95 directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
96 mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_); 96 mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_);
97 uiEventStream_ = new UIEventStream(); 97 uiEventStream_ = new UIEventStream();
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
@@ -25,10 +25,11 @@
25#include <Swiften/Presence/DirectedPresenceSender.h> 25#include <Swiften/Presence/DirectedPresenceSender.h>
26#include <Swiften/Presence/PresenceOracle.h> 26#include <Swiften/Presence/PresenceOracle.h>
27#include <Swiften/Presence/StanzaChannelPresenceSender.h> 27#include <Swiften/Presence/StanzaChannelPresenceSender.h>
28#include <Swiften/Queries/DummyIQChannel.h> 28#include <Swiften/Queries/DummyIQChannel.h>
29#include <Swiften/Roster/XMPPRoster.h> 29#include <Swiften/Roster/XMPPRoster.h>
30#include <Swiften/Roster/XMPPRosterImpl.h>
30#include <Swiften/VCards/VCardManager.h> 31#include <Swiften/VCards/VCardManager.h>
31#include <Swiften/VCards/VCardMemoryStorage.h> 32#include <Swiften/VCards/VCardMemoryStorage.h>
32 33
33#include <Swift/Controllers/Chat/ChatMessageParser.h> 34#include <Swift/Controllers/Chat/ChatMessageParser.h>
34#include <Swift/Controllers/Chat/MUCController.h> 35#include <Swift/Controllers/Chat/MUCController.h>
@@ -70,11 +71,12 @@ public:
70 iqChannel_ = new DummyIQChannel(); 71 iqChannel_ = new DummyIQChannel();
71 iqRouter_ = new IQRouter(iqChannel_); 72 iqRouter_ = new IQRouter(iqChannel_);
72 eventController_ = new EventController(); 73 eventController_ = new EventController();
73 chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>(); 74 chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
74 userSearchWindowFactory_ = mocks_->InterfaceMock<UserSearchWindowFactory>(); 75 userSearchWindowFactory_ = mocks_->InterfaceMock<UserSearchWindowFactory>();
75 presenceOracle_ = new PresenceOracle(stanzaChannel_); 76 xmppRoster_ = new XMPPRosterImpl();
77 presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
76 presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_); 78 presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
77 directedPresenceSender_ = new DirectedPresenceSender(presenceSender_); 79 directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
78 uiEventStream_ = new UIEventStream(); 80 uiEventStream_ = new UIEventStream();
79 avatarManager_ = new NullAvatarManager(); 81 avatarManager_ = new NullAvatarManager();
80 TimerFactory* timerFactory = NULL; 82 TimerFactory* timerFactory = NULL;
@@ -102,10 +104,11 @@ public:
102 delete highlightManager_; 104 delete highlightManager_;
103 delete settings_; 105 delete settings_;
104 delete entityCapsProvider_; 106 delete entityCapsProvider_;
105 delete eventController_; 107 delete eventController_;
106 delete presenceOracle_; 108 delete presenceOracle_;
109 delete xmppRoster_;
107 delete mocks_; 110 delete mocks_;
108 delete uiEventStream_; 111 delete uiEventStream_;
109 delete stanzaChannel_; 112 delete stanzaChannel_;
110 delete presenceSender_; 113 delete presenceSender_;
111 delete directedPresenceSender_; 114 delete directedPresenceSender_;
@@ -440,9 +443,10 @@ private:
440 boost::shared_ptr<CryptoProvider> crypto_; 443 boost::shared_ptr<CryptoProvider> crypto_;
441 VCardManager* vcardManager_; 444 VCardManager* vcardManager_;
442 VCardMemoryStorage* vcardStorage_; 445 VCardMemoryStorage* vcardStorage_;
443 ClientBlockListManager* clientBlockListManager_; 446 ClientBlockListManager* clientBlockListManager_;
444 MUCBookmarkManager* mucBookmarkManager_; 447 MUCBookmarkManager* mucBookmarkManager_;
448 XMPPRoster* xmppRoster_;
445}; 449};
446 450
447CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest); 451CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest);
448 452
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,19 +1,20 @@
1/* 1/*
2 * Copyright (c) 2010-2014 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
6 6
7#include <Swift/Controllers/Roster/RosterController.h> 7#include <Swift/Controllers/Roster/RosterController.h>
8 8
9#include <boost/bind.hpp> 9#include <boost/bind.hpp>
10#include <boost/smart_ptr/make_shared.hpp> 10#include <boost/smart_ptr/make_shared.hpp>
11 11
12#include <Swiften/Avatars/AvatarManager.h>
13#include <Swiften/Base/Path.h>
12#include <Swiften/Base/foreach.h> 14#include <Swiften/Base/foreach.h>
13#include <Swiften/Base/format.h> 15#include <Swiften/Base/format.h>
14#include <Swiften/Base/Path.h>
15#include <Swiften/Client/ClientBlockListManager.h> 16#include <Swiften/Client/ClientBlockListManager.h>
16#include <Swiften/Client/NickManager.h> 17#include <Swiften/Client/NickManager.h>
17#include <Swiften/Client/NickResolver.h> 18#include <Swiften/Client/NickResolver.h>
18#include <Swiften/Disco/EntityCapsManager.h> 19#include <Swiften/Disco/EntityCapsManager.h>
19#include <Swiften/Elements/DiscoInfo.h> 20#include <Swiften/Elements/DiscoInfo.h>
@@ -25,23 +26,26 @@
25#include <Swiften/Queries/IQRouter.h> 26#include <Swiften/Queries/IQRouter.h>
26#include <Swiften/Roster/GetRosterRequest.h> 27#include <Swiften/Roster/GetRosterRequest.h>
27#include <Swiften/Roster/SetRosterRequest.h> 28#include <Swiften/Roster/SetRosterRequest.h>
28#include <Swiften/Roster/XMPPRoster.h> 29#include <Swiften/Roster/XMPPRoster.h>
29#include <Swiften/Roster/XMPPRosterItem.h> 30#include <Swiften/Roster/XMPPRosterItem.h>
31#include <Swiften/VCards/VCardManager.h>
30 32
33#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
31#include <Swift/Controllers/Intl.h> 34#include <Swift/Controllers/Intl.h>
32#include <Swift/Controllers/Roster/GroupRosterItem.h> 35#include <Swift/Controllers/Roster/GroupRosterItem.h>
33#include <Swift/Controllers/Roster/OfflineRosterFilter.h>
34#include <Swift/Controllers/Roster/Roster.h>
35#include <Swift/Controllers/Roster/RosterVCardProvider.h>
36#include <Swift/Controllers/Roster/ItemOperations/AppearOffline.h> 36#include <Swift/Controllers/Roster/ItemOperations/AppearOffline.h>
37#include <Swift/Controllers/Roster/ItemOperations/SetAvatar.h>
38#include <Swift/Controllers/Roster/ItemOperations/SetAvailableFeatures.h> 37#include <Swift/Controllers/Roster/ItemOperations/SetAvailableFeatures.h>
38#include <Swift/Controllers/Roster/ItemOperations/SetAvatar.h>
39#include <Swift/Controllers/Roster/ItemOperations/SetBlockingState.h> 39#include <Swift/Controllers/Roster/ItemOperations/SetBlockingState.h>
40#include <Swift/Controllers/Roster/ItemOperations/SetName.h> 40#include <Swift/Controllers/Roster/ItemOperations/SetName.h>
41#include <Swift/Controllers/Roster/ItemOperations/SetPresence.h> 41#include <Swift/Controllers/Roster/ItemOperations/SetPresence.h>
42#include <Swift/Controllers/Roster/ItemOperations/SetVCard.h> 42#include <Swift/Controllers/Roster/ItemOperations/SetVCard.h>
43#include <Swift/Controllers/Roster/OfflineRosterFilter.h>
44#include <Swift/Controllers/Roster/Roster.h>
45#include <Swift/Controllers/Roster/RosterGroupExpandinessPersister.h>
46#include <Swift/Controllers/Roster/RosterVCardProvider.h>
43#include <Swift/Controllers/SettingConstants.h> 47#include <Swift/Controllers/SettingConstants.h>
44#include <Swift/Controllers/UIEvents/AddContactUIEvent.h> 48#include <Swift/Controllers/UIEvents/AddContactUIEvent.h>
45#include <Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h> 49#include <Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h>
46#include <Swift/Controllers/UIEvents/RenameGroupUIEvent.h> 50#include <Swift/Controllers/UIEvents/RenameGroupUIEvent.h>
47#include <Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h> 51#include <Swift/Controllers/UIEvents/RenameRosterItemUIEvent.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,55 +1,57 @@
1/* 1/*
2 * Copyright (c) 2010 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
6 6
7#pragma once 7#pragma once
8 8
9#include <string>
10#include <set> 9#include <set>
10#include <string>
11 11
12#include <boost/shared_ptr.hpp> 12#include <boost/shared_ptr.hpp>
13 13
14#include <Swiften/Avatars/AvatarManager.h>
14#include <Swiften/Base/boost_bsignals.h> 15#include <Swiften/Base/boost_bsignals.h>
15#include <Swiften/JID/JID.h>
16#include <Swiften/Elements/Presence.h>
17#include <Swiften/Elements/ErrorPayload.h> 16#include <Swiften/Elements/ErrorPayload.h>
17#include <Swiften/Elements/Presence.h>
18#include <Swiften/Elements/RosterPayload.h> 18#include <Swiften/Elements/RosterPayload.h>
19#include <Swiften/Avatars/AvatarManager.h> 19#include <Swiften/Elements/VCard.h>
20#include <Swiften/VCards/VCardManager.h> 20#include <Swiften/JID/JID.h>
21 21
22#include <Swift/Controllers/Roster/ContactRosterItem.h>
22#include <Swift/Controllers/UIEvents/UIEvent.h> 23#include <Swift/Controllers/UIEvents/UIEvent.h>
23#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
24#include <Swift/Controllers/Roster/RosterGroupExpandinessPersister.h>
25 24
26namespace Swift { 25namespace Swift {
26 class AvatarManager;
27 class ClientBlockListManager;
28 class EntityCapsProvider;
29 class EventController;
30 class FileTransferManager;
31 class FileTransferOverview;
27 class IQRouter; 32 class IQRouter;
28 class Roster;
29 class XMPPRoster;
30 class XMPPRosterItem;
31 class MainWindow; 33 class MainWindow;
32 class MainWindowFactory; 34 class MainWindowFactory;
33 class OfflineRosterFilter; 35 class NickManager;
34 class NickResolver; 36 class NickResolver;
37 class OfflineRosterFilter;
35 class PresenceOracle; 38 class PresenceOracle;
39 class Roster;
40 class RosterGroupExpandinessPersister;
41 class RosterVCardProvider;
42 class SettingsProvider;
36 class SubscriptionManager; 43 class SubscriptionManager;
37 class EventController;
38 class SubscriptionRequestEvent; 44 class SubscriptionRequestEvent;
39 class UIEventStream; 45 class UIEventStream;
40 class IQRouter; 46 class VCardManager;
41 class SettingsProvider; 47 class XMPPRoster;
42 class NickManager; 48 class XMPPRosterItem;
43 class EntityCapsProvider;
44 class FileTransferManager;
45 class ClientBlockListManager;
46 class RosterVCardProvider;
47 49
48 class RosterController { 50 class RosterController {
49 public: 51 public:
50 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); 52 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);
51 ~RosterController(); 53 ~RosterController();
52 void showRosterWindow(); 54 void showRosterWindow();
53 void setJID(const JID& jid) { myJID_ = jid; } 55 void setJID(const JID& jid) { myJID_ = jid; }
54 MainWindow* getWindow() {return mainWindow_;} 56 MainWindow* getWindow() {return mainWindow_;}
55 boost::signal<void (StatusShow::Type, const std::string&)> onChangeStatusRequest; 57 boost::signal<void (StatusShow::Type, const std::string&)> onChangeStatusRequest;
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,8 +1,7 @@
1
2/* 1/*
3 * Copyright (c) 2010 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
4 * All rights reserved. 3 * All rights reserved.
5 * See the COPYING file for more information. 4 * See the COPYING file for more information.
6 */ 5 */
7 6
8#include <cppunit/extensions/HelperMacros.h> 7#include <cppunit/extensions/HelperMacros.h>
@@ -26,15 +25,14 @@
26#include <Swiften/Presence/PresenceOracle.h> 25#include <Swiften/Presence/PresenceOracle.h>
27#include <Swiften/Presence/SubscriptionManager.h> 26#include <Swiften/Presence/SubscriptionManager.h>
28#include <Swiften/Queries/DummyIQChannel.h> 27#include <Swiften/Queries/DummyIQChannel.h>
29#include <Swiften/Queries/IQRouter.h> 28#include <Swiften/Queries/IQRouter.h>
30#include <Swiften/Roster/XMPPRosterImpl.h> 29#include <Swiften/Roster/XMPPRosterImpl.h>
30#include <Swiften/VCards/VCardManager.h>
31#include <Swiften/VCards/VCardMemoryStorage.h> 31#include <Swiften/VCards/VCardMemoryStorage.h>
32// #include <Swiften/Elements/Payload.h>
33// #include <Swiften/Elements/RosterItemPayload.h>
34// #include <Swiften/Elements/RosterPayload.h>
35 32
33#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
36#include <Swift/Controllers/Roster/ContactRosterItem.h> 34#include <Swift/Controllers/Roster/ContactRosterItem.h>
37#include <Swift/Controllers/Roster/GroupRosterItem.h> 35#include <Swift/Controllers/Roster/GroupRosterItem.h>
38#include <Swift/Controllers/Roster/Roster.h> 36#include <Swift/Controllers/Roster/Roster.h>
39#include <Swift/Controllers/Roster/RosterController.h> 37#include <Swift/Controllers/Roster/RosterController.h>
40#include <Swift/Controllers/Settings/DummySettingsProvider.h> 38#include <Swift/Controllers/Settings/DummySettingsProvider.h>
@@ -60,10 +58,11 @@ class RosterControllerTest : public CppUnit::TestFixture {
60 CPPUNIT_TEST(testSendRename); 58 CPPUNIT_TEST(testSendRename);
61 CPPUNIT_TEST(testPresence); 59 CPPUNIT_TEST(testPresence);
62 CPPUNIT_TEST(testHighestPresence); 60 CPPUNIT_TEST(testHighestPresence);
63 CPPUNIT_TEST(testNotHighestPresence); 61 CPPUNIT_TEST(testNotHighestPresence);
64 CPPUNIT_TEST(testUnavailablePresence); 62 CPPUNIT_TEST(testUnavailablePresence);
63 CPPUNIT_TEST(testRemoveResultsInUnavailablePresence);
65 CPPUNIT_TEST_SUITE_END(); 64 CPPUNIT_TEST_SUITE_END();
66 65
67 public: 66 public:
68 void setUp() { 67 void setUp() {
69 jid_ = JID("testjid@swift.im/swift"); 68 jid_ = JID("testjid@swift.im/swift");
@@ -73,11 +72,11 @@ class RosterControllerTest : public CppUnit::TestFixture {
73 mucRegistry_ = new MUCRegistry(); 72 mucRegistry_ = new MUCRegistry();
74 nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_); 73 nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_);
75 channel_ = new DummyIQChannel(); 74 channel_ = new DummyIQChannel();
76 router_ = new IQRouter(channel_); 75 router_ = new IQRouter(channel_);
77 stanzaChannel_ = new DummyStanzaChannel(); 76 stanzaChannel_ = new DummyStanzaChannel();
78 presenceOracle_ = new PresenceOracle(stanzaChannel_); 77 presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
79 subscriptionManager_ = new SubscriptionManager(stanzaChannel_); 78 subscriptionManager_ = new SubscriptionManager(stanzaChannel_);
80 eventController_ = new EventController(); 79 eventController_ = new EventController();
81 uiEventStream_ = new UIEventStream(); 80 uiEventStream_ = new UIEventStream();
82 settings_ = new DummySettingsProvider(); 81 settings_ = new DummySettingsProvider();
83 nickManager_ = new DummyNickManager(); 82 nickManager_ = new DummyNickManager();
@@ -317,10 +316,33 @@ class RosterControllerTest : public CppUnit::TestFixture {
317 316
318 CPPUNIT_ASSERT_EQUAL(groups.size(), item.getGroups().size()); 317 CPPUNIT_ASSERT_EQUAL(groups.size(), item.getGroups().size());
319 assertVectorsEqual(groups, item.getGroups(), __LINE__); 318 assertVectorsEqual(groups, item.getGroups(), __LINE__);
320 } 319 }
321 320
321 void testRemoveResultsInUnavailablePresence() {
322 std::vector<std::string> groups;
323 groups.push_back("testGroup1");
324 JID from("test@testdomain.com");
325 xmppRoster_->addContact(from, "name", groups, RosterItemPayload::Both);
326 Presence::ref lowPresence(new Presence());
327 lowPresence->setFrom(withResource(from, "bob"));
328 lowPresence->setPriority(2);
329 lowPresence->setStatus("Not here");
330 Presence::ref highPresence(new Presence());
331 highPresence->setFrom(withResource(from, "bert"));
332 highPresence->setPriority(10);
333 highPresence->setStatus("So totally here");
334 stanzaChannel_->onPresenceReceived(highPresence);
335 stanzaChannel_->onPresenceReceived(lowPresence);
336
337 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), presenceOracle_->getAllPresence("test@testdomain.com").size());
338
339 xmppRoster_->onJIDRemoved(JID("test@testdomain.com"));
340 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), presenceOracle_->getAllPresence("test@testdomain.com").size());
341 CPPUNIT_ASSERT_EQUAL(Presence::Unavailable, presenceOracle_->getAllPresence("test@testdomain.com")[0]->getType());
342 }
343
322 void assertVectorsEqual(const std::vector<std::string>& v1, const std::vector<std::string>& v2, int line) { 344 void assertVectorsEqual(const std::vector<std::string>& v1, const std::vector<std::string>& v2, int line) {
323 foreach (const std::string& entry, v1) { 345 foreach (const std::string& entry, v1) {
324 if (std::find(v2.begin(), v2.end(), entry) == v2.end()) { 346 if (std::find(v2.begin(), v2.end(), entry) == v2.end()) {
325 std::stringstream stream; 347 std::stringstream stream;
326 stream << "Couldn't find " << entry << " in v2 (line " << line << ")"; 348 stream << "Couldn't find " << entry << " in v2 (line " << line << ")";
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,25 +1,29 @@
1/* 1/*
2 * Copyright (c) 2010 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
6 6
7#include <cppunit/extensions/HelperMacros.h>
8#include <cppunit/extensions/TestFactoryRegistry.h>
9#include <vector> 7#include <vector>
8
10#include <boost/bind.hpp> 9#include <boost/bind.hpp>
11 10
12#include "Swift/Controllers/PresenceNotifier.h" 11#include <cppunit/extensions/HelperMacros.h>
13#include "Swiften/Client/NickResolver.h" 12#include <cppunit/extensions/TestFactoryRegistry.h>
14#include "SwifTools/Notifier/LoggingNotifier.h" 13
15#include "Swiften/Client/DummyStanzaChannel.h" 14#include <Swiften/Avatars/DummyAvatarManager.h>
16#include "Swiften/MUC/MUCRegistry.h" 15#include <Swiften/Client/DummyStanzaChannel.h>
17#include "Swiften/Roster/XMPPRosterImpl.h" 16#include <Swiften/Client/NickResolver.h>
18#include "Swiften/Presence/PresenceOracle.h" 17#include <Swiften/MUC/MUCRegistry.h>
19#include "Swiften/Avatars/DummyAvatarManager.h" 18#include <Swiften/Network/DummyTimerFactory.h>
20#include "Swiften/Network/DummyTimerFactory.h" 19#include <Swiften/Presence/PresenceOracle.h>
20#include <Swiften/Roster/XMPPRosterImpl.h>
21
22#include <Swift/Controllers/PresenceNotifier.h>
23
24#include <SwifTools/Notifier/LoggingNotifier.h>
21 25
22using namespace Swift; 26using namespace Swift;
23 27
24class PresenceNotifierTest : public CppUnit::TestFixture { 28class PresenceNotifierTest : public CppUnit::TestFixture {
25 CPPUNIT_TEST_SUITE(PresenceNotifierTest); 29 CPPUNIT_TEST_SUITE(PresenceNotifierTest);
@@ -52,11 +56,11 @@ class PresenceNotifierTest : public CppUnit::TestFixture {
52 user1 = JID("user1@bar.com/bla"); 56 user1 = JID("user1@bar.com/bla");
53 user2 = JID("user2@foo.com/baz"); 57 user2 = JID("user2@foo.com/baz");
54 avatarManager = new DummyAvatarManager(); 58 avatarManager = new DummyAvatarManager();
55 roster = new XMPPRosterImpl(); 59 roster = new XMPPRosterImpl();
56 nickResolver = new NickResolver(JID("foo@bar.com"), roster, NULL, mucRegistry); 60 nickResolver = new NickResolver(JID("foo@bar.com"), roster, NULL, mucRegistry);
57 presenceOracle = new PresenceOracle(stanzaChannel); 61 presenceOracle = new PresenceOracle(stanzaChannel, roster);
58 timerFactory = new DummyTimerFactory(); 62 timerFactory = new DummyTimerFactory();
59 } 63 }
60 64
61 void tearDown() { 65 void tearDown() {
62 delete timerFactory; 66 delete timerFactory;
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
@@ -47,11 +47,11 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net
47 roster = new XMPPRosterImpl(); 47 roster = new XMPPRosterImpl();
48 rosterController = new XMPPRosterController(getIQRouter(), roster, getStorages()->getRosterStorage()); 48 rosterController = new XMPPRosterController(getIQRouter(), roster, getStorages()->getRosterStorage());
49 49
50 subscriptionManager = new SubscriptionManager(getStanzaChannel()); 50 subscriptionManager = new SubscriptionManager(getStanzaChannel());
51 51
52 presenceOracle = new PresenceOracle(getStanzaChannel()); 52 presenceOracle = new PresenceOracle(getStanzaChannel(), roster);
53 presenceOracle->onPresenceChange.connect(boost::ref(onPresenceChange)); 53 presenceOracle->onPresenceChange.connect(boost::ref(onPresenceChange));
54 54
55 stanzaChannelPresenceSender = new StanzaChannelPresenceSender(getStanzaChannel()); 55 stanzaChannelPresenceSender = new StanzaChannelPresenceSender(getStanzaChannel());
56 directedPresenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender); 56 directedPresenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender);
57 discoManager = new ClientDiscoManager(getIQRouter(), directedPresenceSender, networkFactories->getCryptoProvider()); 57 discoManager = new ClientDiscoManager(getIQRouter(), directedPresenceSender, networkFactories->getCryptoProvider());
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,37 +1,38 @@
1/* 1/*
2 * Copyright (c) 2010 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
6 6
7#include "PresenceOracle.h" 7#include <Swiften/Presence/PresenceOracle.h>
8 8
9#include <boost/bind.hpp> 9#include <boost/bind.hpp>
10 10
11#include <Swiften/Client/StanzaChannel.h> 11#include <Swiften/Client/StanzaChannel.h>
12#include <Swiften/Roster/XMPPRoster.h>
12 13
13namespace Swift { 14namespace Swift {
14 15
15PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel) { 16PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster) : stanzaChannel_(stanzaChannel), xmppRoster_(roster) {
16 stanzaChannel_ = stanzaChannel;
17 stanzaChannel_->onPresenceReceived.connect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1)); 17 stanzaChannel_->onPresenceReceived.connect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1));
18 stanzaChannel_->onAvailableChanged.connect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1)); 18 stanzaChannel_->onAvailableChanged.connect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1));
19 xmppRoster_->onJIDRemoved.connect(boost::bind(&PresenceOracle::handleJIDRemoved, this, _1));
19} 20}
20 21
21PresenceOracle::~PresenceOracle() { 22PresenceOracle::~PresenceOracle() {
22 stanzaChannel_->onPresenceReceived.disconnect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1)); 23 stanzaChannel_->onPresenceReceived.disconnect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1));
23 stanzaChannel_->onAvailableChanged.disconnect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1)); 24 stanzaChannel_->onAvailableChanged.disconnect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1));
25 xmppRoster_->onJIDRemoved.disconnect(boost::bind(&PresenceOracle::handleJIDRemoved, this, _1));
24} 26}
25 27
26void PresenceOracle::handleStanzaChannelAvailableChanged(bool available) { 28void PresenceOracle::handleStanzaChannelAvailableChanged(bool available) {
27 if (available) { 29 if (available) {
28 entries_.clear(); 30 entries_.clear();
29 } 31 }
30} 32}
31 33
32
33void PresenceOracle::handleIncomingPresence(Presence::ref presence) { 34void PresenceOracle::handleIncomingPresence(Presence::ref presence) {
34 JID bareJID(presence->getFrom().toBare()); 35 JID bareJID(presence->getFrom().toBare());
35 if (presence->getType() == Presence::Subscribe) { 36 if (presence->getType() == Presence::Subscribe) {
36 } 37 }
37 else { 38 else {
@@ -41,11 +42,11 @@ void PresenceOracle::handleIncomingPresence(Presence::ref presence) {
41 passedPresence = Presence::ref(new Presence()); 42 passedPresence = Presence::ref(new Presence());
42 passedPresence->setType(Presence::Unavailable); 43 passedPresence->setType(Presence::Unavailable);
43 passedPresence->setFrom(bareJID); 44 passedPresence->setFrom(bareJID);
44 passedPresence->setStatus(presence->getStatus()); 45 passedPresence->setStatus(presence->getStatus());
45 } 46 }
46 std::map<JID, boost::shared_ptr<Presence> > jidMap = entries_[bareJID]; 47 PresenceMap jidMap = entries_[bareJID];
47 if (passedPresence->getFrom().isBare() && presence->getType() == Presence::Unavailable) { 48 if (passedPresence->getFrom().isBare() && presence->getType() == Presence::Unavailable) {
48 /* Have a bare-JID only presence of offline */ 49 /* Have a bare-JID only presence of offline */
49 jidMap.clear(); 50 jidMap.clear();
50 } else if (passedPresence->getType() == Presence::Available) { 51 } else if (passedPresence->getType() == Presence::Available) {
51 /* Don't have a bare-JID only offline presence once there are available presences */ 52 /* Don't have a bare-JID only offline presence once there are available presences */
@@ -59,10 +60,24 @@ void PresenceOracle::handleIncomingPresence(Presence::ref presence) {
59 entries_[bareJID] = jidMap; 60 entries_[bareJID] = jidMap;
60 onPresenceChange(passedPresence); 61 onPresenceChange(passedPresence);
61 } 62 }
62} 63}
63 64
65void PresenceOracle::handleJIDRemoved(const JID& removedJID) {
66 /* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */
67 Presence::ref unavailablePresence = Presence::ref(new Presence());
68 unavailablePresence->setType(Presence::Unavailable);
69 unavailablePresence->setFrom(removedJID);
70
71 if (entries_.find(removedJID) != entries_.end()) {
72 entries_[removedJID].clear();
73 entries_[removedJID][removedJID] = unavailablePresence;
74 }
75
76 onPresenceChange(unavailablePresence);
77}
78
64Presence::ref PresenceOracle::getLastPresence(const JID& jid) const { 79Presence::ref PresenceOracle::getLastPresence(const JID& jid) const {
65 PresencesMap::const_iterator i = entries_.find(jid.toBare()); 80 PresencesMap::const_iterator i = entries_.find(jid.toBare());
66 if (i == entries_.end()) { 81 if (i == entries_.end()) {
67 return Presence::ref(); 82 return Presence::ref();
68 } 83 }
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,27 +1,27 @@
1/* 1/*
2 * Copyright (c) 2010 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
6 6
7#pragma once 7#pragma once
8 8
9#include <map> 9#include <map>
10
11#include <string> 10#include <string>
12#include <Swiften/Elements/Presence.h>
13 11
14#include <Swiften/Base/API.h> 12#include <Swiften/Base/API.h>
15#include <Swiften/Base/boost_bsignals.h> 13#include <Swiften/Base/boost_bsignals.h>
14#include <Swiften/Elements/Presence.h>
16 15
17namespace Swift { 16namespace Swift {
18 class StanzaChannel; 17 class StanzaChannel;
18 class XMPPRoster;
19 19
20 class SWIFTEN_API PresenceOracle { 20 class SWIFTEN_API PresenceOracle {
21 public: 21 public:
22 PresenceOracle(StanzaChannel* stanzaChannel); 22 PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster);
23 ~PresenceOracle(); 23 ~PresenceOracle();
24 24
25 Presence::ref getLastPresence(const JID&) const; 25 Presence::ref getLastPresence(const JID&) const;
26 Presence::ref getHighestPriorityPresence(const JID& bareJID) const; 26 Presence::ref getHighestPriorityPresence(const JID& bareJID) const;
27 std::vector<Presence::ref> getAllPresence(const JID& bareJID) const; 27 std::vector<Presence::ref> getAllPresence(const JID& bareJID) const;
@@ -30,14 +30,16 @@ namespace Swift {
30 boost::signal<void (Presence::ref)> onPresenceChange; 30 boost::signal<void (Presence::ref)> onPresenceChange;
31 31
32 private: 32 private:
33 void handleIncomingPresence(Presence::ref presence); 33 void handleIncomingPresence(Presence::ref presence);
34 void handleStanzaChannelAvailableChanged(bool); 34 void handleStanzaChannelAvailableChanged(bool);
35 void handleJIDRemoved(const JID& removedJID);
35 36
36 private: 37 private:
37 typedef std::map<JID, Presence::ref> PresenceMap; 38 typedef std::map<JID, Presence::ref> PresenceMap;
38 typedef std::map<JID, PresenceMap> PresencesMap; 39 typedef std::map<JID, PresenceMap> PresencesMap;
39 PresencesMap entries_; 40 PresencesMap entries_;
40 StanzaChannel* stanzaChannel_; 41 StanzaChannel* stanzaChannel_;
42 XMPPRoster* xmppRoster_;
41 }; 43 };
42} 44}
43 45
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,19 +1,22 @@
1/* 1/*
2 * Copyright (c) 2010 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
6 6
7#include <cppunit/extensions/HelperMacros.h>
8#include <cppunit/extensions/TestFactoryRegistry.h>
9#include <boost/bind.hpp> 7#include <boost/bind.hpp>
10#include <boost/shared_ptr.hpp> 8#include <boost/shared_ptr.hpp>
11 9
12#include <Swiften/Presence/PresenceOracle.h> 10#include <cppunit/extensions/HelperMacros.h>
11#include <cppunit/extensions/TestFactoryRegistry.h>
12
13#include <Swiften/Client/DummyStanzaChannel.h> 13#include <Swiften/Client/DummyStanzaChannel.h>
14#include <Swiften/Presence/PresenceOracle.h>
14#include <Swiften/Presence/SubscriptionManager.h> 15#include <Swiften/Presence/SubscriptionManager.h>
16#include <Swiften/Roster/XMPPRoster.h>
17#include <Swiften/Roster/XMPPRosterImpl.h>
15 18
16using namespace Swift; 19using namespace Swift;
17 20
18class PresenceOracleTest : public CppUnit::TestFixture { 21class PresenceOracleTest : public CppUnit::TestFixture {
19 CPPUNIT_TEST_SUITE(PresenceOracleTest); 22 CPPUNIT_TEST_SUITE(PresenceOracleTest);
@@ -28,11 +31,13 @@ class PresenceOracleTest : public CppUnit::TestFixture {
28 CPPUNIT_TEST_SUITE_END(); 31 CPPUNIT_TEST_SUITE_END();
29 32
30 public: 33 public:
31 void setUp() { 34 void setUp() {
32 stanzaChannel_ = new DummyStanzaChannel(); 35 stanzaChannel_ = new DummyStanzaChannel();
33 oracle_ = new PresenceOracle(stanzaChannel_); 36 xmppRoster_ = new XMPPRosterImpl();
37
38 oracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
34 oracle_->onPresenceChange.connect(boost::bind(&PresenceOracleTest::handlePresenceChange, this, _1)); 39 oracle_->onPresenceChange.connect(boost::bind(&PresenceOracleTest::handlePresenceChange, this, _1));
35 subscriptionManager_ = new SubscriptionManager(stanzaChannel_); 40 subscriptionManager_ = new SubscriptionManager(stanzaChannel_);
36 subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2)); 41 subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2));
37 user1 = JID("user1@foo.com/Foo"); 42 user1 = JID("user1@foo.com/Foo");
38 user1alt = JID("user1@foo.com/Bar"); 43 user1alt = JID("user1@foo.com/Bar");
@@ -40,10 +45,11 @@ class PresenceOracleTest : public CppUnit::TestFixture {
40 } 45 }
41 46
42 void tearDown() { 47 void tearDown() {
43 delete subscriptionManager_; 48 delete subscriptionManager_;
44 delete oracle_; 49 delete oracle_;
50 delete xmppRoster_;
45 delete stanzaChannel_; 51 delete stanzaChannel_;
46 } 52 }
47 53
48 void testHighestPresenceSingle() { 54 void testHighestPresenceSingle() {
49 JID bareJID("alice@wonderland.lit"); 55 JID bareJID("alice@wonderland.lit");
@@ -184,10 +190,11 @@ class PresenceOracleTest : public CppUnit::TestFixture {
184 std::string reason; 190 std::string reason;
185 }; 191 };
186 PresenceOracle* oracle_; 192 PresenceOracle* oracle_;
187 SubscriptionManager* subscriptionManager_; 193 SubscriptionManager* subscriptionManager_;
188 DummyStanzaChannel* stanzaChannel_; 194 DummyStanzaChannel* stanzaChannel_;
195 XMPPRoster* xmppRoster_;
189 std::vector<Presence::ref> changes; 196 std::vector<Presence::ref> changes;
190 std::vector<SubscriptionRequestInfo> subscriptionRequests; 197 std::vector<SubscriptionRequestInfo> subscriptionRequests;
191 JID user1; 198 JID user1;
192 JID user1alt; 199 JID user1alt;
193 JID user2; 200 JID user2;
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,19 +1,24 @@
1/* 1/*
2 * Copyright (c) 2010 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
6 6
7#include <Swiften/Roster/XMPPRosterImpl.h> 7#include <Swiften/Roster/XMPPRosterImpl.h>
8
8#include <Swiften/Base/foreach.h> 9#include <Swiften/Base/foreach.h>
9 10
10namespace Swift { 11namespace Swift {
11 12
12XMPPRosterImpl::XMPPRosterImpl() { 13XMPPRosterImpl::XMPPRosterImpl() {
13} 14}
14 15
16XMPPRosterImpl::~XMPPRosterImpl() {
17
18}
19
15void XMPPRosterImpl::addContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, RosterItemPayload::Subscription subscription) { 20void XMPPRosterImpl::addContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, RosterItemPayload::Subscription subscription) {
16 JID bareJID(jid.toBare()); 21 JID bareJID(jid.toBare());
17 std::map<JID, XMPPRosterItem>::iterator i = entries_.find(bareJID); 22 std::map<JID, XMPPRosterItem>::iterator i = entries_.find(bareJID);
18 if (i != entries_.end()) { 23 if (i != entries_.end()) {
19 std::string oldName = i->second.getName(); 24 std::string oldName = i->second.getName();
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,7 +1,7 @@
1/* 1/*
2 * Copyright (c) 2010 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
6 6
7#pragma once 7#pragma once
@@ -14,10 +14,11 @@
14 14
15namespace Swift { 15namespace Swift {
16 class SWIFTEN_API XMPPRosterImpl : public XMPPRoster { 16 class SWIFTEN_API XMPPRosterImpl : public XMPPRoster {
17 public: 17 public:
18 XMPPRosterImpl(); 18 XMPPRosterImpl();
19 virtual ~XMPPRosterImpl();
19 20
20 void addContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, RosterItemPayload::Subscription subscription); 21 void addContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, RosterItemPayload::Subscription subscription);
21 void removeContact(const JID& jid); 22 void removeContact(const JID& jid);
22 void clear(); 23 void clear();
23 24