diff options
| author | Tobias Markmann <tm@ayena.de> | 2015-10-27 16:20:09 (GMT) |
|---|---|---|
| committer | Tobias Markmann <tm@ayena.de> | 2015-10-30 12:34:52 (GMT) |
| commit | 0f5ef716a50c8d9761cafda12aacf818cdfd6353 (patch) | |
| tree | 4ed80dedc2fa8b04036eb7567282094ea8fe07f1 | |
| parent | 4320235bef1b601856b295a8d6411d1898048802 (diff) | |
| download | swift-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.cpp | 22 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatsManager.cpp | 4 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/UserSearchController.cpp | 2 | ||||
| -rw-r--r-- | Swift/Controllers/ContactsFromXMPPRoster.cpp | 7 | ||||
| -rw-r--r-- | Swift/Controllers/Roster/ContactRosterItem.cpp | 52 | ||||
| -rw-r--r-- | Swift/Controllers/Roster/ContactRosterItem.h | 13 | ||||
| -rw-r--r-- | Swift/Controllers/Roster/RosterController.cpp | 7 | ||||
| -rw-r--r-- | Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp | 37 | ||||
| -rw-r--r-- | Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp | 12 | ||||
| -rw-r--r-- | Swiften/Presence/PresenceOracle.cpp | 89 | ||||
| -rw-r--r-- | Swiften/Presence/PresenceOracle.h | 33 | ||||
| -rw-r--r-- | Swiften/Presence/UnitTest/PresenceOracleTest.cpp | 63 |
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 | ||
| 466 | void ChatController::handlePresenceChange(boost::shared_ptr<Presence> newPresence) { | 466 | void 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 | ||
| 22 | namespace Swift { | 21 | namespace Swift { |
| @@ -30,11 +29,11 @@ ContactsFromXMPPRoster::~ContactsFromXMPPRoster() { | |||
| 30 | std::vector<Contact::ref> ContactsFromXMPPRoster::getContacts(bool /*withMUCNicks*/) { | 29 | std::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 | ||
| 17 | namespace Swift { | 18 | namespace Swift { |
| 18 | 19 | ||
| @@ -24,15 +25,15 @@ ContactRosterItem::ContactRosterItem(const JID& jid, const JID& displayJID, cons | |||
| 24 | 25 | ||
| 25 | ContactRosterItem::~ContactRosterItem() { | 26 | ContactRosterItem::~ContactRosterItem() { |
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | StatusShow::Type ContactRosterItem::getStatusShow() const { | 29 | StatusShow::Type ContactRosterItem::getStatusShow() const { |
| 29 | return shownPresence_ ? shownPresence_->getShow() : StatusShow::None; | 30 | return presence_ ? presence_->getShow() : StatusShow::None; |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | StatusShow::Type ContactRosterItem::getSimplifiedStatusShow() const { | 33 | StatusShow::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 | ||
| 45 | std::string ContactRosterItem::getStatusText() const { | 46 | std::string ContactRosterItem::getStatusText() const { |
| 46 | return shownPresence_ ? shownPresence_->getStatus() : ""; | 47 | return presence_ ? presence_->getStatus() : ""; |
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | std::string ContactRosterItem::getIdleText() const { | 50 | std::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 | ||
| 58 | std::string ContactRosterItem::getOfflineSinceText() const { | 59 | std::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 | ||
| 89 | typedef std::pair<std::string, boost::shared_ptr<Presence> > StringPresencePair; | 90 | typedef std::pair<std::string, boost::shared_ptr<Presence> > StringPresencePair; |
| 90 | 91 | ||
| 91 | void 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 | |||
| 101 | void ContactRosterItem::clearPresence() { | 92 | void ContactRosterItem::clearPresence() { |
| 102 | presences_.clear(); | 93 | presence_.reset(); |
| 103 | calculateShownPresence(); | ||
| 104 | onDataChanged(); | 94 | onDataChanged(); |
| 105 | } | 95 | } |
| 106 | 96 | ||
| 107 | void ContactRosterItem::applyPresence(const std::string& resource, boost::shared_ptr<Presence> presence) { | 97 | void 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 | ||
| 130 | const std::vector<std::string>& ContactRosterItem::getGroups() const { | 102 | const 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 | ||
| 333 | void RosterController::handleIncomingPresence(Presence::ref newPresence) { | 332 | void 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 | ||
| 340 | void RosterController::handleSubscriptionRequest(const JID& jid, const std::string& message) { | 340 | void 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) { | |||
| 378 | void RosterController::handlePresenceChanged(Presence::ref presence) { | 378 | void 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 | ||
| 385 | boost::optional<XMPPRosterItem> RosterController::getItem(const JID& jid) const { | 388 | boost::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 | ||
| 27 | using namespace Swift; | 26 | using namespace Swift; |
| 28 | 27 | ||
| 29 | class JingleParserTest : public CppUnit::TestFixture { | 28 | class 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 | ||
| 14 | namespace Swift { | 18 | namespace Swift { |
| 15 | 19 | ||
| 16 | PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster) : stanzaChannel_(stanzaChannel), xmppRoster_(roster) { | 20 | PresenceOracle::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 | ||
| 113 | struct 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 | |||
| 147 | typedef std::priority_queue<Presence::ref, std::vector<Presence::ref>, PresenceAccountCmp> PresenceAccountPriorityQueue; | ||
| 148 | |||
| 149 | Presence::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 | |||
| 191 | Presence::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 | |||
| 109 | Presence::ref PresenceOracle::getHighestPriorityPresence(const JID& bareJID) const { | 198 | Presence::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 | ||
| 16 | namespace Swift { | 16 | namespace 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; |
Swift