summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers/Roster')
-rw-r--r--Swift/Controllers/Roster/ContactRosterItem.cpp52
-rw-r--r--Swift/Controllers/Roster/ContactRosterItem.h13
-rw-r--r--Swift/Controllers/Roster/RosterController.cpp7
-rw-r--r--Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp37
4 files changed, 47 insertions, 62 deletions
diff --git a/Swift/Controllers/Roster/ContactRosterItem.cpp b/Swift/Controllers/Roster/ContactRosterItem.cpp
index fd6d1cd..ae05aee 100644
--- a/Swift/Controllers/Roster/ContactRosterItem.cpp
+++ b/Swift/Controllers/Roster/ContactRosterItem.cpp
@@ -1,18 +1,19 @@
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 <Swift/Controllers/Roster/ContactRosterItem.h> 7#include <Swift/Controllers/Roster/ContactRosterItem.h>
8 8
9#include <boost/date_time/posix_time/posix_time.hpp> 9#include <boost/date_time/posix_time/posix_time.hpp>
10 10
11#include <Swiften/Base/foreach.h>
12#include <Swiften/Base/DateTime.h> 11#include <Swiften/Base/DateTime.h>
12#include <Swiften/Base/foreach.h>
13#include <Swiften/Elements/Idle.h> 13#include <Swiften/Elements/Idle.h>
14
14#include <Swift/Controllers/Intl.h> 15#include <Swift/Controllers/Intl.h>
15#include <Swift/Controllers/Roster/GroupRosterItem.h> 16#include <Swift/Controllers/Roster/GroupRosterItem.h>
16 17
17namespace Swift { 18namespace Swift {
18 19
@@ -24,15 +25,15 @@ ContactRosterItem::ContactRosterItem(const JID& jid, const JID& displayJID, cons
24 25
25ContactRosterItem::~ContactRosterItem() { 26ContactRosterItem::~ContactRosterItem() {
26} 27}
27 28
28StatusShow::Type ContactRosterItem::getStatusShow() const { 29StatusShow::Type ContactRosterItem::getStatusShow() const {
29 return shownPresence_ ? shownPresence_->getShow() : StatusShow::None; 30 return presence_ ? presence_->getShow() : StatusShow::None;
30} 31}
31 32
32StatusShow::Type ContactRosterItem::getSimplifiedStatusShow() const { 33StatusShow::Type ContactRosterItem::getSimplifiedStatusShow() const {
33 switch (shownPresence_ ? shownPresence_->getShow() : StatusShow::None) { 34 switch (presence_ ? presence_->getShow() : StatusShow::None) {
34 case StatusShow::Online: return StatusShow::Online; 35 case StatusShow::Online: return StatusShow::Online;
35 case StatusShow::Away: return StatusShow::Away; 36 case StatusShow::Away: return StatusShow::Away;
36 case StatusShow::XA: return StatusShow::Away; 37 case StatusShow::XA: return StatusShow::Away;
37 case StatusShow::FFC: return StatusShow::Online; 38 case StatusShow::FFC: return StatusShow::Online;
38 case StatusShow::DND: return StatusShow::DND; 39 case StatusShow::DND: return StatusShow::DND;
@@ -41,26 +42,26 @@ StatusShow::Type ContactRosterItem::getSimplifiedStatusShow() const {
41 assert(false); 42 assert(false);
42 return StatusShow::None; 43 return StatusShow::None;
43} 44}
44 45
45std::string ContactRosterItem::getStatusText() const { 46std::string ContactRosterItem::getStatusText() const {
46 return shownPresence_ ? shownPresence_->getStatus() : ""; 47 return presence_ ? presence_->getStatus() : "";
47} 48}
48 49
49std::string ContactRosterItem::getIdleText() const { 50std::string ContactRosterItem::getIdleText() const {
50 Idle::ref idle = shownPresence_ ? shownPresence_->getPayload<Idle>() : Idle::ref(); 51 Idle::ref idle = presence_ ? presence_->getPayload<Idle>() : Idle::ref();
51 if (!idle || idle->getSince().is_not_a_date_time()) { 52 if (!idle || idle->getSince().is_not_a_date_time()) {
52 return ""; 53 return "";
53 } else { 54 } else {
54 return dateTimeToLocalString(idle->getSince()); 55 return dateTimeToLocalString(idle->getSince());
55 } 56 }
56} 57}
57 58
58std::string ContactRosterItem::getOfflineSinceText() const { 59std::string ContactRosterItem::getOfflineSinceText() const {
59 if (offlinePresence_) { 60 if (presence_ && presence_->getType() == Presence::Unavailable) {
60 boost::optional<boost::posix_time::ptime> delay = offlinePresence_->getTimestamp(); 61 boost::optional<boost::posix_time::ptime> delay = presence_->getTimestamp();
61 if (offlinePresence_->getType() == Presence::Unavailable && delay) { 62 if (delay) {
62 return dateTimeToLocalString(*delay); 63 return dateTimeToLocalString(*delay);
63 } 64 }
64 } 65 }
65 return ""; 66 return "";
66} 67}
@@ -86,46 +87,17 @@ const JID& ContactRosterItem::getDisplayJID() const {
86} 87}
87 88
88 89
89typedef std::pair<std::string, boost::shared_ptr<Presence> > StringPresencePair; 90typedef std::pair<std::string, boost::shared_ptr<Presence> > StringPresencePair;
90 91
91void ContactRosterItem::calculateShownPresence() {
92 shownPresence_ = offlinePresence_;
93 foreach (StringPresencePair presencePair, presences_) {
94 boost::shared_ptr<Presence> presence = presencePair.second;
95 if (!shownPresence_ || presence->getPriority() > shownPresence_->getPriority() || presence->getShow() < shownPresence_->getShow()) {
96 shownPresence_ = presence;
97 }
98 }
99}
100
101void ContactRosterItem::clearPresence() { 92void ContactRosterItem::clearPresence() {
102 presences_.clear(); 93 presence_.reset();
103 calculateShownPresence();
104 onDataChanged(); 94 onDataChanged();
105} 95}
106 96
107void ContactRosterItem::applyPresence(const std::string& resource, boost::shared_ptr<Presence> presence) { 97void ContactRosterItem::applyPresence(const std::string& resource, boost::shared_ptr<Presence> presence) {
108 if (offlinePresence_) { 98 presence_ = presence;
109 offlinePresence_ = boost::shared_ptr<Presence>();
110 }
111 if (presence->getType() == Presence::Unavailable) {
112 if (resource.empty()) {
113 /* Unavailable from the bare JID means all resources are offline.*/
114 presences_.clear();
115 } else {
116 if (presences_.find(resource) != presences_.end()) {
117 presences_.erase(resource);
118 }
119 }
120 if (presences_.empty()) {
121 offlinePresence_ = presence;
122 }
123 } else {
124 presences_[resource] = presence;
125 }
126 calculateShownPresence();
127 onDataChanged(); 99 onDataChanged();
128} 100}
129 101
130const std::vector<std::string>& ContactRosterItem::getGroups() const { 102const std::vector<std::string>& ContactRosterItem::getGroups() const {
131 return groups_; 103 return groups_;
diff --git a/Swift/Controllers/Roster/ContactRosterItem.h b/Swift/Controllers/Roster/ContactRosterItem.h
index 54a6b60..ec04a8c 100644
--- a/Swift/Controllers/Roster/ContactRosterItem.h
+++ b/Swift/Controllers/Roster/ContactRosterItem.h
@@ -1,26 +1,26 @@
1/* 1/*
2 * Copyright (c) 2010-2013 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>
10#include <set> 9#include <set>
11#include <string> 10#include <string>
11#include <vector>
12 12
13#include <boost/bind.hpp> 13#include <boost/bind.hpp>
14#include <boost/date_time/posix_time/ptime.hpp> 14#include <boost/date_time/posix_time/ptime.hpp>
15#include <boost/filesystem/path.hpp> 15#include <boost/filesystem/path.hpp>
16#include <boost/shared_ptr.hpp> 16#include <boost/shared_ptr.hpp>
17 17
18#include <Swiften/Base/boost_bsignals.h> 18#include <Swiften/Base/boost_bsignals.h>
19#include <Swiften/Elements/MUCOccupant.h>
19#include <Swiften/Elements/Presence.h> 20#include <Swiften/Elements/Presence.h>
20#include <Swiften/Elements/StatusShow.h> 21#include <Swiften/Elements/StatusShow.h>
21#include <Swiften/Elements/MUCOccupant.h>
22#include <Swiften/Elements/VCard.h> 22#include <Swiften/Elements/VCard.h>
23#include <Swiften/JID/JID.h> 23#include <Swiften/JID/JID.h>
24 24
25#include <Swift/Controllers/Roster/RosterItem.h> 25#include <Swift/Controllers/Roster/RosterItem.h>
26 26
@@ -54,16 +54,15 @@ class ContactRosterItem : public RosterItem {
54 const boost::filesystem::path& getAvatarPath() const; 54 const boost::filesystem::path& getAvatarPath() const;
55 const JID& getJID() const; 55 const JID& getJID() const;
56 void setDisplayJID(const JID& jid); 56 void setDisplayJID(const JID& jid);
57 const JID& getDisplayJID() const; 57 const JID& getDisplayJID() const;
58 void applyPresence(const std::string& resource, boost::shared_ptr<Presence> presence); 58 void applyPresence(const std::string& resource, boost::shared_ptr<Presence> presence);
59 void clearPresence();
60 void calculateShownPresence();
61 const std::vector<std::string>& getGroups() const; 59 const std::vector<std::string>& getGroups() const;
62 /** Only used so a contact can know about the groups it's in*/ 60 /** Only used so a contact can know about the groups it's in*/
63 void addGroup(const std::string& group); 61 void addGroup(const std::string& group);
64 void removeGroup(const std::string& group); 62 void removeGroup(const std::string& group);
63 void clearPresence();
65 64
66 MUCOccupant::Role getMUCRole() const; 65 MUCOccupant::Role getMUCRole() const;
67 void setMUCRole(const MUCOccupant::Role& role); 66 void setMUCRole(const MUCOccupant::Role& role);
68 MUCOccupant::Affiliation getMUCAffiliation() const; 67 MUCOccupant::Affiliation getMUCAffiliation() const;
69 void setMUCAffiliation(const MUCOccupant::Affiliation& affiliation); 68 void setMUCAffiliation(const MUCOccupant::Affiliation& affiliation);
@@ -83,13 +82,11 @@ class ContactRosterItem : public RosterItem {
83 private: 82 private:
84 JID jid_; 83 JID jid_;
85 JID displayJID_; 84 JID displayJID_;
86 boost::posix_time::ptime lastAvailableTime_; 85 boost::posix_time::ptime lastAvailableTime_;
87 boost::filesystem::path avatarPath_; 86 boost::filesystem::path avatarPath_;
88 std::map<std::string, boost::shared_ptr<Presence> > presences_; 87 boost::shared_ptr<Presence> presence_;
89 boost::shared_ptr<Presence> offlinePresence_;
90 boost::shared_ptr<Presence> shownPresence_;
91 std::vector<std::string> groups_; 88 std::vector<std::string> groups_;
92 MUCOccupant::Role mucRole_; 89 MUCOccupant::Role mucRole_;
93 MUCOccupant::Affiliation mucAffiliation_; 90 MUCOccupant::Affiliation mucAffiliation_;
94 std::set<Feature> features_; 91 std::set<Feature> features_;
95 BlockState blockState_; 92 BlockState blockState_;
diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp
index 73efa43..751ca32 100644
--- a/Swift/Controllers/Roster/RosterController.cpp
+++ b/Swift/Controllers/Roster/RosterController.cpp
@@ -77,11 +77,10 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata
77 xmppRoster_->onJIDAdded.connect(boost::bind(&RosterController::handleOnJIDAdded, this, _1)); 77 xmppRoster_->onJIDAdded.connect(boost::bind(&RosterController::handleOnJIDAdded, this, _1));
78 xmppRoster_->onJIDUpdated.connect(boost::bind(&RosterController::handleOnJIDUpdated, this, _1, _2, _3)); 78 xmppRoster_->onJIDUpdated.connect(boost::bind(&RosterController::handleOnJIDUpdated, this, _1, _2, _3));
79 xmppRoster_->onJIDRemoved.connect(boost::bind(&RosterController::handleOnJIDRemoved, this, _1)); 79 xmppRoster_->onJIDRemoved.connect(boost::bind(&RosterController::handleOnJIDRemoved, this, _1));
80 xmppRoster_->onRosterCleared.connect(boost::bind(&RosterController::handleRosterCleared, this)); 80 xmppRoster_->onRosterCleared.connect(boost::bind(&RosterController::handleRosterCleared, this));
81 subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&RosterController::handleSubscriptionRequest, this, _1, _2)); 81 subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&RosterController::handleSubscriptionRequest, this, _1, _2));
82 presenceOracle_->onPresenceChange.connect(boost::bind(&RosterController::handleIncomingPresence, this, _1));
83 uiEventConnection_ = uiEventStream->onUIEvent.connect(boost::bind(&RosterController::handleUIEvent, this, _1)); 82 uiEventConnection_ = uiEventStream->onUIEvent.connect(boost::bind(&RosterController::handleUIEvent, this, _1));
84 83
85 vcardManager_->onOwnVCardChanged.connect(boost::bind(&RosterController::handleOwnVCardChanged, this, _1)); 84 vcardManager_->onOwnVCardChanged.connect(boost::bind(&RosterController::handleOwnVCardChanged, this, _1));
86 avatarManager_->onAvatarChanged.connect(boost::bind(&RosterController::handleAvatarChanged, this, _1)); 85 avatarManager_->onAvatarChanged.connect(boost::bind(&RosterController::handleAvatarChanged, this, _1));
87 presenceOracle_->onPresenceChange.connect(boost::bind(&RosterController::handlePresenceChanged, this, _1)); 86 presenceOracle_->onPresenceChange.connect(boost::bind(&RosterController::handlePresenceChanged, this, _1));
@@ -332,11 +331,12 @@ void RosterController::handleRosterSetError(ErrorPayload::ref error, boost::shar
332 331
333void RosterController::handleIncomingPresence(Presence::ref newPresence) { 332void RosterController::handleIncomingPresence(Presence::ref newPresence) {
334 if (newPresence->getType() == Presence::Error) { 333 if (newPresence->getType() == Presence::Error) {
335 return; 334 return;
336 } 335 }
337 roster_->applyOnItems(SetPresence(newPresence)); 336 Presence::ref accountPresence = presenceOracle_->getAccountPresence(newPresence->getFrom().toBare());
337 roster_->applyOnItems(SetPresence(accountPresence));
338} 338}
339 339
340void RosterController::handleSubscriptionRequest(const JID& jid, const std::string& message) { 340void RosterController::handleSubscriptionRequest(const JID& jid, const std::string& message) {
341 if (xmppRoster_->containsJID(jid) && (xmppRoster_->getSubscriptionStateForJID(jid) == RosterItemPayload::To || xmppRoster_->getSubscriptionStateForJID(jid) == RosterItemPayload::Both)) { 341 if (xmppRoster_->containsJID(jid) && (xmppRoster_->getSubscriptionStateForJID(jid) == RosterItemPayload::To || xmppRoster_->getSubscriptionStateForJID(jid) == RosterItemPayload::Both)) {
342 subscriptionManager_->confirmSubscription(jid); 342 subscriptionManager_->confirmSubscription(jid);
@@ -378,10 +378,13 @@ void RosterController::handleAvatarChanged(const JID& jid) {
378void RosterController::handlePresenceChanged(Presence::ref presence) { 378void RosterController::handlePresenceChanged(Presence::ref presence) {
379 if (presence->getFrom().equals(myJID_, JID::WithResource)) { 379 if (presence->getFrom().equals(myJID_, JID::WithResource)) {
380 ownContact_->applyPresence(std::string(), presence); 380 ownContact_->applyPresence(std::string(), presence);
381 mainWindow_->setMyContactRosterItem(ownContact_); 381 mainWindow_->setMyContactRosterItem(ownContact_);
382 } 382 }
383 else {
384 handleIncomingPresence(presence);
385 }
383} 386}
384 387
385boost::optional<XMPPRosterItem> RosterController::getItem(const JID& jid) const { 388boost::optional<XMPPRosterItem> RosterController::getItem(const JID& jid) const {
386 return xmppRoster_->getItem(jid); 389 return xmppRoster_->getItem(jid);
387} 390}
diff --git a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
index 9320af1..d774e6d 100644
--- a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
@@ -192,43 +192,56 @@ class RosterControllerTest : public CppUnit::TestFixture {
192 void testUnavailablePresence() { 192 void testUnavailablePresence() {
193 std::vector<std::string> groups; 193 std::vector<std::string> groups;
194 groups.push_back("testGroup1"); 194 groups.push_back("testGroup1");
195 JID from("test@testdomain.com"); 195 JID from("test@testdomain.com");
196 xmppRoster_->addContact(from, "name", groups, RosterItemPayload::Both); 196 xmppRoster_->addContact(from, "name", groups, RosterItemPayload::Both);
197
197 Presence::ref lowPresence(new Presence()); 198 Presence::ref lowPresence(new Presence());
198 lowPresence->setFrom(withResource(from, "bob")); 199 lowPresence->setFrom(withResource(from, "bob"));
199 lowPresence->setPriority(2); 200 lowPresence->setPriority(2);
201 lowPresence->setShow(StatusShow::Away);
200 lowPresence->setStatus("Not here"); 202 lowPresence->setStatus("Not here");
203 Presence::ref lowPresenceOffline(new Presence());
204 lowPresenceOffline->setFrom(withResource(from, "bob"));
205 lowPresenceOffline->setStatus("Signing out");
206 lowPresenceOffline->setType(Presence::Unavailable);
207
201 Presence::ref highPresence(new Presence()); 208 Presence::ref highPresence(new Presence());
202 highPresence->setFrom(withResource(from, "bert")); 209 highPresence->setFrom(withResource(from, "bert"));
203 highPresence->setPriority(10); 210 highPresence->setPriority(10);
204 highPresence->setStatus("So totally here"); 211 highPresence->setStatus("So totally here");
205 Presence::ref highPresenceOffline(new Presence()); 212 Presence::ref highPresenceOffline(new Presence());
206 highPresenceOffline->setFrom(withResource(from, "bert")); 213 highPresenceOffline->setFrom(withResource(from, "bert"));
207 highPresenceOffline->setType(Presence::Unavailable); 214 highPresenceOffline->setType(Presence::Unavailable);
208 Presence::ref lowPresenceOffline(new Presence()); 215
209 lowPresenceOffline->setFrom(withResource(from, "bob"));
210 lowPresenceOffline->setStatus("Signing out");
211 lowPresenceOffline->setType(Presence::Unavailable);
212 stanzaChannel_->onPresenceReceived(lowPresence); 216 stanzaChannel_->onPresenceReceived(lowPresence);
217 Presence::ref accountPresence = presenceOracle_->getAccountPresence(from);
218 CPPUNIT_ASSERT_EQUAL(StatusShow::Away, accountPresence->getShow());
219
213 stanzaChannel_->onPresenceReceived(highPresence); 220 stanzaChannel_->onPresenceReceived(highPresence);
221 accountPresence = presenceOracle_->getAccountPresence(from);
222 CPPUNIT_ASSERT_EQUAL(StatusShow::Online, accountPresence->getShow());
223
214 stanzaChannel_->onPresenceReceived(highPresenceOffline); 224 stanzaChannel_->onPresenceReceived(highPresenceOffline);
225
226 // After this, the roster should show the low presence.
215 ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]); 227 ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]);
216 CPPUNIT_ASSERT(item); 228 CPPUNIT_ASSERT(item);
217 /* A verification that if the test fails, it's the RosterController, not the PresenceOracle. */ 229
218 Presence::ref high = presenceOracle_->getHighestPriorityPresence(from); 230 Presence::ref low = presenceOracle_->getAccountPresence(from);
219 CPPUNIT_ASSERT_EQUAL(Presence::Available, high->getType()); 231
220 CPPUNIT_ASSERT_EQUAL(lowPresence->getStatus(), high->getStatus()); 232 CPPUNIT_ASSERT_EQUAL(Presence::Available, low->getType());
221 CPPUNIT_ASSERT_EQUAL(StatusShow::Online, item->getStatusShow()); 233 CPPUNIT_ASSERT_EQUAL(lowPresence->getStatus(), low->getStatus());
234 CPPUNIT_ASSERT_EQUAL(lowPresence->getShow(), item->getStatusShow());
222 CPPUNIT_ASSERT_EQUAL(lowPresence->getStatus(), item->getStatusText()); 235 CPPUNIT_ASSERT_EQUAL(lowPresence->getStatus(), item->getStatusText());
223 stanzaChannel_->onPresenceReceived(lowPresenceOffline); 236 stanzaChannel_->onPresenceReceived(lowPresenceOffline);
224 item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]); 237 item = dynamic_cast<ContactRosterItem*>(dynamic_cast<GroupRosterItem*>(CHILDREN[0])->getChildren()[0]);
225 CPPUNIT_ASSERT(item); 238 CPPUNIT_ASSERT(item);
226 /* A verification that if the test fails, it's the RosterController, not the PresenceOracle. */ 239 /* A verification that if the test fails, it's the RosterController, not the PresenceOracle. */
227 high = presenceOracle_->getHighestPriorityPresence(from); 240 low = presenceOracle_->getHighestPriorityPresence(from);
228 CPPUNIT_ASSERT_EQUAL(Presence::Unavailable, high->getType()); 241 CPPUNIT_ASSERT_EQUAL(Presence::Unavailable, low->getType());
229 CPPUNIT_ASSERT_EQUAL(lowPresenceOffline->getStatus(), high->getStatus()); 242 CPPUNIT_ASSERT_EQUAL(lowPresenceOffline->getStatus(), low->getStatus());
230 CPPUNIT_ASSERT_EQUAL(StatusShow::None, item->getStatusShow()); 243 CPPUNIT_ASSERT_EQUAL(StatusShow::None, item->getStatusShow());
231 CPPUNIT_ASSERT_EQUAL(lowPresenceOffline->getStatus(), item->getStatusText()); 244 CPPUNIT_ASSERT_EQUAL(lowPresenceOffline->getStatus(), item->getStatusText());
232 } 245 }
233 246
234 void testAdd() { 247 void testAdd() {