summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2015-10-27 16:20:09 (GMT)
committerTobias Markmann <tm@ayena.de>2015-10-30 12:34:52 (GMT)
commit0f5ef716a50c8d9761cafda12aacf818cdfd6353 (patch)
tree4ed80dedc2fa8b04036eb7567282094ea8fe07f1
parent4320235bef1b601856b295a8d6411d1898048802 (diff)
downloadswift-0f5ef716a50c8d9761cafda12aacf818cdfd6353.zip
swift-0f5ef716a50c8d9761cafda12aacf818cdfd6353.tar.bz2
Change bare JID presence lookup code to ignore priorities
Before presence handling code was handled by both, the ContactRosterItem in Swift and the PresenceOracle in Swiften. The ContactRosterItem also considered the presence priority for deciding what presence to show for a bare JID. With this code all full or bare JID presence requests are finally handled by the PresenceOracle. For bare JIDs it is looked up to a presence of one of the available resources of that JID regardless of the priorities. Test-Information: Adjusted tests according to above description and documentation in PresenceOracle. Change-Id: I972a4574f476cdf4d4b5593a035eb1c25ef2f8ba
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp22
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp4
-rw-r--r--Swift/Controllers/Chat/UserSearchController.cpp2
-rw-r--r--Swift/Controllers/ContactsFromXMPPRoster.cpp7
-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
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp12
-rw-r--r--Swiften/Presence/PresenceOracle.cpp89
-rw-r--r--Swiften/Presence/PresenceOracle.h33
-rw-r--r--Swiften/Presence/UnitTest/PresenceOracleTest.cpp63
12 files changed, 245 insertions, 96 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index bedc427..51c7349 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -69,11 +69,11 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ
69 if (isInMUC) { 69 if (isInMUC) {
70 startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% in chatroom %2%")) % nick % contact.toBare().toString()); 70 startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% in chatroom %2%")) % nick % contact.toBare().toString());
71 theirPresence = presenceOracle->getLastPresence(contact); 71 theirPresence = presenceOracle->getLastPresence(contact);
72 } else { 72 } else {
73 startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% - %2%")) % nick % contact.toBare().toString()); 73 startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% - %2%")) % nick % contact.toBare().toString());
74 theirPresence = contact.isBare() ? presenceOracle->getHighestPriorityPresence(contact.toBare()) : presenceOracle->getLastPresence(contact); 74 theirPresence = contact.isBare() ? presenceOracle->getAccountPresence(contact) : presenceOracle->getLastPresence(contact);
75 } 75 }
76 Idle::ref idle; 76 Idle::ref idle;
77 if (theirPresence && (idle = theirPresence->getPayload<Idle>())) { 77 if (theirPresence && (idle = theirPresence->getPayload<Idle>())) {
78 startMessage += str(format(QT_TRANSLATE_NOOP("", ", who has been idle since %1%")) % dateTimeToLocalString(idle->getSince())); 78 startMessage += str(format(QT_TRANSLATE_NOOP("", ", who has been idle since %1%")) % dateTimeToLocalString(idle->getSince()));
79 } 79 }
@@ -141,11 +141,11 @@ void ChatController::setToJID(const JID& jid) {
141 ChatControllerBase::setToJID(jid); 141 ChatControllerBase::setToJID(jid);
142 Presence::ref presence; 142 Presence::ref presence;
143 if (isInMUC_) { 143 if (isInMUC_) {
144 presence = presenceOracle_->getLastPresence(jid); 144 presence = presenceOracle_->getLastPresence(jid);
145 } else { 145 } else {
146 presence = jid.isBare() ? presenceOracle_->getHighestPriorityPresence(jid.toBare()) : presenceOracle_->getLastPresence(jid); 146 presence = jid.isBare() ? presenceOracle_->getAccountPresence(jid.toBare()) : presenceOracle_->getLastPresence(jid);
147 } 147 }
148 chatStateNotifier_->setContactIsOnline(presence && presence->getType() == Presence::Available); 148 chatStateNotifier_->setContactIsOnline(presence && presence->getType() == Presence::Available);
149 handleBareJIDCapsChanged(toJID_); 149 handleBareJIDCapsChanged(toJID_);
150} 150}
151 151
@@ -462,22 +462,22 @@ std::string ChatController::getStatusChangeString(boost::shared_ptr<Presence> pr
462 } 462 }
463 return response + "."; 463 return response + ".";
464} 464}
465 465
466void ChatController::handlePresenceChange(boost::shared_ptr<Presence> newPresence) { 466void ChatController::handlePresenceChange(boost::shared_ptr<Presence> newPresence) {
467 bool me = false; 467 bool relevantPresence = false;
468 if (toJID_.isBare()) { 468
469 newPresence = presenceOracle_->getHighestPriorityPresence(toJID_); 469 if (toJID_.equals(newPresence->getFrom(), JID::WithoutResource)) {
470 if ((newPresence ? newPresence->getShow() : StatusShow::None) != lastShownStatus_) { 470 // Presence matches ChatController JID.
471 me = true; 471 newPresence = presenceOracle_->getAccountPresence(toJID_);
472 } 472 relevantPresence = true;
473 } else if (toJID_.equals(newPresence->getFrom(), JID::WithResource)) {
474 me = true;
475 } 473 }
476 if (!me) { 474
475 if (!relevantPresence) {
477 return; 476 return;
478 } 477 }
478
479 if (!newPresence) { 479 if (!newPresence) {
480 newPresence = boost::make_shared<Presence>(); 480 newPresence = boost::make_shared<Presence>();
481 newPresence->setType(Presence::Unavailable); 481 newPresence->setType(Presence::Unavailable);
482 } 482 }
483 lastShownStatus_ = newPresence->getShow(); 483 lastShownStatus_ = newPresence->getShow();
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 343f490..8a06333 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -285,11 +285,11 @@ ChatListWindow::Chat ChatsManager::updateChatStatusAndAvatarHelper(const ChatLis
285 } 285 }
286 } else { 286 } else {
287 if (avatarManager_) { 287 if (avatarManager_) {
288 fixedChat.avatarPath = avatarManager_->getAvatarPath(fixedChat.jid); 288 fixedChat.avatarPath = avatarManager_->getAvatarPath(fixedChat.jid);
289 } 289 }
290 Presence::ref presence = presenceOracle_->getHighestPriorityPresence(fixedChat.jid.toBare()); 290 Presence::ref presence = presenceOracle_->getAccountPresence(fixedChat.jid.toBare());
291 fixedChat.statusType = presence ? presence->getShow() : StatusShow::None; 291 fixedChat.statusType = presence ? presence->getShow() : StatusShow::None;
292 } 292 }
293 return fixedChat; 293 return fixedChat;
294} 294}
295 295
@@ -407,11 +407,11 @@ ChatListWindow::Chat ChatsManager::createChatListChatItem(const JID& jid, const
407 ChatController* controller = getChatControllerIfExists(jid, false); 407 ChatController* controller = getChatControllerIfExists(jid, false);
408 if (controller) { 408 if (controller) {
409 unreadCount = controller->getUnreadCount(); 409 unreadCount = controller->getUnreadCount();
410 } 410 }
411 JID bareishJID = mucRegistry_->isMUC(jid.toBare()) ? jid : jid.toBare(); 411 JID bareishJID = mucRegistry_->isMUC(jid.toBare()) ? jid : jid.toBare();
412 Presence::ref presence = presenceOracle_->getHighestPriorityPresence(bareishJID); 412 Presence::ref presence = presenceOracle_->getAccountPresence(bareishJID);
413 StatusShow::Type type = presence ? presence->getShow() : StatusShow::None; 413 StatusShow::Type type = presence ? presence->getShow() : StatusShow::None;
414 boost::filesystem::path avatarPath = avatarManager_ ? avatarManager_->getAvatarPath(bareishJID) : boost::filesystem::path(); 414 boost::filesystem::path avatarPath = avatarManager_ ? avatarManager_->getAvatarPath(bareishJID) : boost::filesystem::path();
415 return ChatListWindow::Chat(bareishJID, nickResolver_->jidToNick(bareishJID), activity, unreadCount, type, avatarPath, false, privateMessage); 415 return ChatListWindow::Chat(bareishJID, nickResolver_->jidToNick(bareishJID), activity, unreadCount, type, avatarPath, false, privateMessage);
416 } 416 }
417} 417}
diff --git a/Swift/Controllers/Chat/UserSearchController.cpp b/Swift/Controllers/Chat/UserSearchController.cpp
index 454a110..291472f 100644
--- a/Swift/Controllers/Chat/UserSearchController.cpp
+++ b/Swift/Controllers/Chat/UserSearchController.cpp
@@ -303,11 +303,11 @@ Contact::ref UserSearchController::convertJIDtoContact(const JID& jid) {
303 contact->name = jid.toString(); 303 contact->name = jid.toString();
304 } 304 }
305 } 305 }
306 306
307 // presence lookup 307 // presence lookup
308 Presence::ref presence = presenceOracle_->getHighestPriorityPresence(jid); 308 Presence::ref presence = presenceOracle_->getAccountPresence(jid);
309 if (presence) { 309 if (presence) {
310 contact->statusType = presence->getShow(); 310 contact->statusType = presence->getShow();
311 } else { 311 } else {
312 contact->statusType = StatusShow::None; 312 contact->statusType = StatusShow::None;
313 } 313 }
diff --git a/Swift/Controllers/ContactsFromXMPPRoster.cpp b/Swift/Controllers/ContactsFromXMPPRoster.cpp
index d3d7364..1cab9b1 100644
--- a/Swift/Controllers/ContactsFromXMPPRoster.cpp
+++ b/Swift/Controllers/ContactsFromXMPPRoster.cpp
@@ -3,20 +3,19 @@
3 * Licensed under the simplified BSD license. 3 * Licensed under the simplified BSD license.
4 * See Documentation/Licenses/BSD-simplified.txt for more information. 4 * See Documentation/Licenses/BSD-simplified.txt for more information.
5 */ 5 */
6 6
7/* 7/*
8 * Copyright (c) 2014 Isode Limited. 8 * Copyright (c) 2014-2015 Isode Limited.
9 * All rights reserved. 9 * All rights reserved.
10 * See the COPYING file for more information. 10 * See the COPYING file for more information.
11 */ 11 */
12 12
13#include <Swift/Controllers/ContactsFromXMPPRoster.h> 13#include <Swift/Controllers/ContactsFromXMPPRoster.h>
14 14
15#include <Swiften/Base/foreach.h>
16
17#include <Swiften/Avatars/AvatarManager.h> 15#include <Swiften/Avatars/AvatarManager.h>
16#include <Swiften/Base/foreach.h>
18#include <Swiften/Presence/PresenceOracle.h> 17#include <Swiften/Presence/PresenceOracle.h>
19#include <Swiften/Roster/XMPPRoster.h> 18#include <Swiften/Roster/XMPPRoster.h>
20#include <Swiften/Roster/XMPPRosterItem.h> 19#include <Swiften/Roster/XMPPRosterItem.h>
21 20
22namespace Swift { 21namespace Swift {
@@ -30,11 +29,11 @@ ContactsFromXMPPRoster::~ContactsFromXMPPRoster() {
30std::vector<Contact::ref> ContactsFromXMPPRoster::getContacts(bool /*withMUCNicks*/) { 29std::vector<Contact::ref> ContactsFromXMPPRoster::getContacts(bool /*withMUCNicks*/) {
31 std::vector<Contact::ref> results; 30 std::vector<Contact::ref> results;
32 std::vector<XMPPRosterItem> rosterItems = roster_->getItems(); 31 std::vector<XMPPRosterItem> rosterItems = roster_->getItems();
33 foreach(const XMPPRosterItem& rosterItem, rosterItems) { 32 foreach(const XMPPRosterItem& rosterItem, rosterItems) {
34 Contact::ref contact = boost::make_shared<Contact>(rosterItem.getName().empty() ? rosterItem.getJID().toString() : rosterItem.getName(), rosterItem.getJID(), StatusShow::None,""); 33 Contact::ref contact = boost::make_shared<Contact>(rosterItem.getName().empty() ? rosterItem.getJID().toString() : rosterItem.getName(), rosterItem.getJID(), StatusShow::None,"");
35 contact->statusType = presenceOracle_->getHighestPriorityPresence(contact->jid) ? presenceOracle_->getHighestPriorityPresence(contact->jid)->getShow() : StatusShow::None; 34 contact->statusType = presenceOracle_->getAccountPresence(contact->jid) ? presenceOracle_->getAccountPresence(contact->jid)->getShow() : StatusShow::None;
36 contact->avatarPath = avatarManager_->getAvatarPath(contact->jid); 35 contact->avatarPath = avatarManager_->getAvatarPath(contact->jid);
37 results.push_back(contact); 36 results.push_back(contact);
38 } 37 }
39 return results; 38 return results;
40} 39}
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() {
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp
index 05aaedf..56143ef 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp
+++ b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp
@@ -11,20 +11,19 @@
11 */ 11 */
12 12
13#include <cppunit/extensions/HelperMacros.h> 13#include <cppunit/extensions/HelperMacros.h>
14#include <cppunit/extensions/TestFactoryRegistry.h> 14#include <cppunit/extensions/TestFactoryRegistry.h>
15 15
16#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> 16#include <Swiften/Base/DateTime.h>
17#include <Swiften/Elements/JinglePayload.h> 17#include <Swiften/Elements/JingleFileTransferDescription.h>
18#include <Swiften/Elements/JingleFileTransferHash.h>
18#include <Swiften/Elements/JingleIBBTransportPayload.h> 19#include <Swiften/Elements/JingleIBBTransportPayload.h>
20#include <Swiften/Elements/JinglePayload.h>
19#include <Swiften/Elements/JingleS5BTransportPayload.h> 21#include <Swiften/Elements/JingleS5BTransportPayload.h>
20#include <Swiften/Elements/JingleFileTransferDescription.h>
21#include <Swiften/Elements/StreamInitiationFileInfo.h> 22#include <Swiften/Elements/StreamInitiationFileInfo.h>
22#include <Swiften/Elements/JingleFileTransferHash.h> 23#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h>
23#include <Swiften/Base/DateTime.h>
24#include <Swiften/StringCodecs/Base64.h> 24#include <Swiften/StringCodecs/Base64.h>
25#include <Swiften/Base/Log.h>
26 25
27using namespace Swift; 26using namespace Swift;
28 27
29class JingleParserTest : public CppUnit::TestFixture { 28class JingleParserTest : public CppUnit::TestFixture {
30 CPPUNIT_TEST_SUITE(JingleParserTest); 29 CPPUNIT_TEST_SUITE(JingleParserTest);
@@ -411,11 +410,10 @@ class JingleParserTest : public CppUnit::TestFixture {
411 CPPUNIT_ASSERT_EQUAL(std::string("VS2nSZMIUsaa5dIUHTdmsQ=="), Base64::encode(hash->getFileInfo().getHash("sha-1").get())); 410 CPPUNIT_ASSERT_EQUAL(std::string("VS2nSZMIUsaa5dIUHTdmsQ=="), Base64::encode(hash->getFileInfo().getHash("sha-1").get()));
412 } 411 }
413 412
414 // http://xmpp.org/extensions/xep-0234.html#example-10 413 // http://xmpp.org/extensions/xep-0234.html#example-10
415 void testParse_Xep0234_Example10() { 414 void testParse_Xep0234_Example10() {
416 Log::setLogLevel(Log::debug);
417 PayloadsParserTester parser; 415 PayloadsParserTester parser;
418 CPPUNIT_ASSERT(parser.parse( 416 CPPUNIT_ASSERT(parser.parse(
419 "<jingle xmlns='urn:xmpp:jingle:1'\n" 417 "<jingle xmlns='urn:xmpp:jingle:1'\n"
420 " action='session-initiate'\n" 418 " action='session-initiate'\n"
421 " initiator='romeo@montague.lit/orchard'\n" 419 " initiator='romeo@montague.lit/orchard'\n"
diff --git a/Swiften/Presence/PresenceOracle.cpp b/Swiften/Presence/PresenceOracle.cpp
index e4129fb..8623529 100644
--- a/Swiften/Presence/PresenceOracle.cpp
+++ b/Swiften/Presence/PresenceOracle.cpp
@@ -4,13 +4,17 @@
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
6 6
7#include <Swiften/Presence/PresenceOracle.h> 7#include <Swiften/Presence/PresenceOracle.h>
8 8
9#include <queue>
10
9#include <boost/bind.hpp> 11#include <boost/bind.hpp>
10 12
13#include <Swiften/Base/foreach.h>
11#include <Swiften/Client/StanzaChannel.h> 14#include <Swiften/Client/StanzaChannel.h>
15#include <Swiften/Elements/StatusShow.h>
12#include <Swiften/Roster/XMPPRoster.h> 16#include <Swiften/Roster/XMPPRoster.h>
13 17
14namespace Swift { 18namespace Swift {
15 19
16PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster) : stanzaChannel_(stanzaChannel), xmppRoster_(roster) { 20PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster) : stanzaChannel_(stanzaChannel), xmppRoster_(roster) {
@@ -104,10 +108,95 @@ std::vector<Presence::ref> PresenceOracle::getAllPresence(const JID& bareJID) co
104 results.push_back(current); 108 results.push_back(current);
105 } 109 }
106 return results; 110 return results;
107} 111}
108 112
113struct PresenceAccountCmp {
114 static int preferenceFromStatusShow(StatusShow::Type showType) {
115 switch (showType) {
116 case StatusShow::FFC:
117 return 5;
118 case StatusShow::Online:
119 return 4;
120 case StatusShow::DND:
121 return 3;
122 case StatusShow::Away:
123 return 2;
124 case StatusShow::XA:
125 return 1;
126 case StatusShow::None:
127 return 0;
128 }
129 assert(false);
130 return -1;
131 }
132
133 bool operator()(const Presence::ref& a, const Presence::ref& b) {
134 int aPreference = preferenceFromStatusShow(a->getShow());
135 int bPreference = preferenceFromStatusShow(b->getShow());
136
137 if (aPreference != bPreference) {
138 return aPreference < bPreference;
139 }
140 if (a->getPriority() != b->getPriority()) {
141 return a->getPriority() < b->getPriority();
142 }
143 return a->getFrom().getResource() < b->getFrom().getResource();
144 }
145};
146
147typedef std::priority_queue<Presence::ref, std::vector<Presence::ref>, PresenceAccountCmp> PresenceAccountPriorityQueue;
148
149Presence::ref PresenceOracle::getActivePresence(const std::vector<Presence::ref> presences) {
150 Presence::ref accountPresence;
151
152 PresenceAccountPriorityQueue online;
153 PresenceAccountPriorityQueue away;
154 PresenceAccountPriorityQueue offline;
155
156 foreach(Presence::ref presence, presences) {
157 switch (presence->getShow()) {
158 case StatusShow::Online:
159 online.push(presence);
160 break;
161 case StatusShow::Away:
162 away.push(presence);
163 break;
164 case StatusShow::FFC:
165 online.push(presence);
166 break;
167 case StatusShow::XA:
168 away.push(presence);
169 break;
170 case StatusShow::DND:
171 away.push(presence);
172 break;
173 case StatusShow::None:
174 offline.push(presence);
175 break;
176 }
177 }
178
179 if (!online.empty()) {
180 accountPresence = online.top();
181 }
182 else if (!away.empty()) {
183 accountPresence = away.top();
184 }
185 else if (!offline.empty()) {
186 accountPresence = offline.top();
187 }
188 return accountPresence;
189}
190
191Presence::ref PresenceOracle::getAccountPresence(const JID& jid) const {
192 Presence::ref accountPresence;
193 std::vector<Presence::ref> allPresences = getAllPresence(jid.toBare());
194 accountPresence = getActivePresence(allPresences);
195 return accountPresence;
196}
197
109Presence::ref PresenceOracle::getHighestPriorityPresence(const JID& bareJID) const { 198Presence::ref PresenceOracle::getHighestPriorityPresence(const JID& bareJID) const {
110 PresencesMap::const_iterator i = entries_.find(bareJID); 199 PresencesMap::const_iterator i = entries_.find(bareJID);
111 if (i == entries_.end()) { 200 if (i == entries_.end()) {
112 return Presence::ref(); 201 return Presence::ref();
113 } 202 }
diff --git a/Swiften/Presence/PresenceOracle.h b/Swiften/Presence/PresenceOracle.h
index f312506..a010e8e 100644
--- a/Swiften/Presence/PresenceOracle.h
+++ b/Swiften/Presence/PresenceOracle.h
@@ -15,19 +15,52 @@
15 15
16namespace Swift { 16namespace Swift {
17 class StanzaChannel; 17 class StanzaChannel;
18 class XMPPRoster; 18 class XMPPRoster;
19 19
20 /**
21 * The PresenceOracle class observes all received presence stanzas for
22 * the \ref StanzaChannel class passed in the constructor and maintains a
23 * cache.
24 */
20 class SWIFTEN_API PresenceOracle { 25 class SWIFTEN_API PresenceOracle {
21 public: 26 public:
22 PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster); 27 PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster);
23 ~PresenceOracle(); 28 ~PresenceOracle();
24 29
25 Presence::ref getLastPresence(const JID&) const; 30 Presence::ref getLastPresence(const JID&) const;
26 Presence::ref getHighestPriorityPresence(const JID& bareJID) const; 31 Presence::ref getHighestPriorityPresence(const JID& bareJID) const;
27 std::vector<Presence::ref> getAllPresence(const JID& bareJID) const; 32 std::vector<Presence::ref> getAllPresence(const JID& bareJID) const;
28 33
34 /**
35 * \brief Returns the relevant presence for a list of resource presences.
36 *
37 * It only takes the presence show type into account. Priorities are
38 * ignored as various clients set them to arbitrary values unrelated
39 * to actual end point availability.
40 *
41 * The presences of the resources are group by availablilty and sorted
42 * by show type in the following order:
43 *
44 * -# Online
45 * -# Free for Chat
46 * -# Available
47 * -# Away
48 * -# DND
49 * -# Extended Away
50 * -# Away
51 * -# Offline
52 * -# Unavailable
53 */
54 static Presence::ref getActivePresence(const std::vector<Presence::ref> presences);
55
56 /**
57 * \brief This considers all online resources of a bare JID and returns
58 * the value returned by \ref getActivePresence when passing this list.
59 */
60 Presence::ref getAccountPresence(const JID& jid) const;
61
29 public: 62 public:
30 boost::signal<void (Presence::ref)> onPresenceChange; 63 boost::signal<void (Presence::ref)> onPresenceChange;
31 64
32 private: 65 private:
33 void handleIncomingPresence(Presence::ref presence); 66 void handleIncomingPresence(Presence::ref presence);
diff --git a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp
index 85dcca9..6d16d80 100644
--- a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp
+++ b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp
@@ -26,10 +26,11 @@ class PresenceOracleTest : public CppUnit::TestFixture {
26 CPPUNIT_TEST(testReconnectResetsPresences); 26 CPPUNIT_TEST(testReconnectResetsPresences);
27 CPPUNIT_TEST(testHighestPresenceSingle); 27 CPPUNIT_TEST(testHighestPresenceSingle);
28 CPPUNIT_TEST(testHighestPresenceMultiple); 28 CPPUNIT_TEST(testHighestPresenceMultiple);
29 CPPUNIT_TEST(testHighestPresenceGlobal); 29 CPPUNIT_TEST(testHighestPresenceGlobal);
30 CPPUNIT_TEST(testHighestPresenceChangePriority); 30 CPPUNIT_TEST(testHighestPresenceChangePriority);
31 CPPUNIT_TEST(testGetActivePresence);
31 CPPUNIT_TEST_SUITE_END(); 32 CPPUNIT_TEST_SUITE_END();
32 33
33 public: 34 public:
34 void setUp() { 35 void setUp() {
35 stanzaChannel_ = new DummyStanzaChannel(); 36 stanzaChannel_ = new DummyStanzaChannel();
@@ -50,19 +51,19 @@ class PresenceOracleTest : public CppUnit::TestFixture {
50 delete xmppRoster_; 51 delete xmppRoster_;
51 delete stanzaChannel_; 52 delete stanzaChannel_;
52 } 53 }
53 54
54 void testHighestPresenceSingle() { 55 void testHighestPresenceSingle() {
55 JID bareJID("alice@wonderland.lit"); 56 JID bareJID("alice@wonderland.lit");
56 Presence::ref fiveOn = makeOnline("blah", 5); 57 Presence::ref fiveOn = makeOnline("blah", 5);
57 Presence::ref fiveOff = makeOffline("/blah"); 58 Presence::ref fiveOff = makeOffline("/blah");
58 CPPUNIT_ASSERT_EQUAL(Presence::ref(), oracle_->getHighestPriorityPresence(bareJID)); 59 CPPUNIT_ASSERT_EQUAL(Presence::ref(), oracle_->getHighestPriorityPresence(bareJID));
59 stanzaChannel_->onPresenceReceived(fiveOn); 60 stanzaChannel_->onPresenceReceived(fiveOn);
60 CPPUNIT_ASSERT_EQUAL(fiveOn, oracle_->getHighestPriorityPresence(bareJID)); 61 CPPUNIT_ASSERT_EQUAL(fiveOn, oracle_->getHighestPriorityPresence(bareJID));
61 stanzaChannel_->onPresenceReceived(fiveOff); 62 stanzaChannel_->onPresenceReceived(fiveOff);
62 CPPUNIT_ASSERT_EQUAL(fiveOff, oracle_->getHighestPriorityPresence(bareJID)); 63 CPPUNIT_ASSERT_EQUAL(fiveOff, oracle_->getHighestPriorityPresence(bareJID));
63 } 64 }
64 65
65 void testHighestPresenceMultiple() { 66 void testHighestPresenceMultiple() {
66 JID bareJID("alice@wonderland.lit"); 67 JID bareJID("alice@wonderland.lit");
67 Presence::ref fiveOn = makeOnline("blah", 5); 68 Presence::ref fiveOn = makeOnline("blah", 5);
68 Presence::ref fiveOff = makeOffline("/blah"); 69 Presence::ref fiveOff = makeOffline("/blah");
@@ -149,12 +150,56 @@ class PresenceOracleTest : public CppUnit::TestFixture {
149 stanzaChannel_->setAvailable(false); 150 stanzaChannel_->setAvailable(false);
150 stanzaChannel_->setAvailable(true); 151 stanzaChannel_->setAvailable(true);
151 152
152 CPPUNIT_ASSERT(!oracle_->getLastPresence(user1)); 153 CPPUNIT_ASSERT(!oracle_->getLastPresence(user1));
153 } 154 }
155
156 void testGetActivePresence() {
157 {
158 std::vector<Presence::ref> presenceList;
159 presenceList.push_back(createPresence("alice@wonderland.lit/resourceA", 10, Presence::Available, StatusShow::Away));
160 presenceList.push_back(createPresence("alice@wonderland.lit/resourceB", 5, Presence::Available, StatusShow::Online));
161
162 CPPUNIT_ASSERT_EQUAL(StatusShow::Online, PresenceOracle::getActivePresence(presenceList)->getShow());
163 }
164
165 {
166 std::vector<Presence::ref> presenceList;
167 presenceList.push_back(createPresence("alice@wonderland.lit/resourceA", 10, Presence::Available, StatusShow::Away));
168 presenceList.push_back(createPresence("alice@wonderland.lit/resourceB", 5, Presence::Available, StatusShow::DND));
169
170 CPPUNIT_ASSERT_EQUAL(StatusShow::DND, PresenceOracle::getActivePresence(presenceList)->getShow());
171 }
172
173 {
174 std::vector<Presence::ref> presenceList;
175 presenceList.push_back(createPresence("alice@wonderland.lit/resourceA", 0, Presence::Available, StatusShow::Online));
176 presenceList.push_back(createPresence("alice@wonderland.lit/resourceB", 0, Presence::Available, StatusShow::DND));
177
178 CPPUNIT_ASSERT_EQUAL(StatusShow::Online, PresenceOracle::getActivePresence(presenceList)->getShow());
179 }
180
181 {
182 std::vector<Presence::ref> presenceList;
183 presenceList.push_back(createPresence("alice@wonderland.lit/resourceA", 1, Presence::Available, StatusShow::Online));
184 presenceList.push_back(createPresence("alice@wonderland.lit/resourceB", 0, Presence::Available, StatusShow::Online));
185
186 CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/resourceA"), PresenceOracle::getActivePresence(presenceList)->getFrom());
187 }
188 }
154 189
155 private: 190 private:
191 Presence::ref createPresence(const JID &jid, int priority, Presence::Type type, const StatusShow::Type& statusShow) {
192 Presence::ref presence = boost::make_shared<Presence>();
193 presence->setFrom(jid);
194 presence->setPriority(priority);
195 presence->setType(type);
196 presence->setShow(statusShow);
197 return presence;
198 }
199
200
156 Presence::ref makeOnline(const std::string& resource, int priority) { 201 Presence::ref makeOnline(const std::string& resource, int priority) {
157 Presence::ref presence(new Presence()); 202 Presence::ref presence(new Presence());
158 presence->setPriority(priority); 203 presence->setPriority(priority);
159 presence->setFrom(JID("alice@wonderland.lit/" + resource)); 204 presence->setFrom(JID("alice@wonderland.lit/" + resource));
160 return presence; 205 return presence;