summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;