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 /Swiften
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
Diffstat (limited to 'Swiften')
-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
6 files changed, 48 insertions, 18 deletions
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
@@ -49,7 +49,7 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net
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());
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,26 +1,28 @@
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) {
@@ -29,7 +31,6 @@ void PresenceOracle::handleStanzaChannelAvailableChanged(bool available) {
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) {
@@ -43,7 +44,7 @@ void PresenceOracle::handleIncomingPresence(Presence::ref presence) {
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();
@@ -61,6 +62,20 @@ void PresenceOracle::handleIncomingPresence(Presence::ref presence) {
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()) {
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,5 +1,5 @@
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 */
@@ -7,19 +7,19 @@
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;
@@ -32,12 +32,14 @@ namespace Swift {
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,17 +1,20 @@
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
@@ -30,7 +33,9 @@ class PresenceOracleTest : public CppUnit::TestFixture {
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));
@@ -42,6 +47,7 @@ class PresenceOracleTest : public CppUnit::TestFixture {
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
@@ -186,6 +192,7 @@ class PresenceOracleTest : public CppUnit::TestFixture {
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;
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,10 +1,11 @@
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 {
@@ -12,6 +13,10 @@ namespace Swift {
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);
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,5 +1,5 @@
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 */
@@ -16,6 +16,7 @@ namespace 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);