diff options
Diffstat (limited to 'Swiften/Presence')
-rw-r--r-- | Swiften/Presence/DirectedPresenceSender.cpp | 73 | ||||
-rw-r--r-- | Swiften/Presence/DirectedPresenceSender.h | 38 | ||||
-rw-r--r-- | Swiften/Presence/PayloadAddingPresenceSender.cpp | 52 | ||||
-rw-r--r-- | Swiften/Presence/PayloadAddingPresenceSender.h | 76 | ||||
-rw-r--r-- | Swiften/Presence/PresenceOracle.cpp | 267 | ||||
-rw-r--r-- | Swiften/Presence/PresenceOracle.h | 96 | ||||
-rw-r--r-- | Swiften/Presence/PresenceSender.cpp | 6 | ||||
-rw-r--r-- | Swiften/Presence/PresenceSender.h | 19 | ||||
-rw-r--r-- | Swiften/Presence/SConscript | 14 | ||||
-rw-r--r-- | Swiften/Presence/StanzaChannelPresenceSender.cpp | 11 | ||||
-rw-r--r-- | Swiften/Presence/StanzaChannelPresenceSender.h | 24 | ||||
-rw-r--r-- | Swiften/Presence/SubscriptionManager.cpp | 49 | ||||
-rw-r--r-- | Swiften/Presence/SubscriptionManager.h | 73 | ||||
-rw-r--r-- | Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp | 271 | ||||
-rw-r--r-- | Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp | 198 | ||||
-rw-r--r-- | Swiften/Presence/UnitTest/PresenceOracleTest.cpp | 415 |
16 files changed, 935 insertions, 747 deletions
diff --git a/Swiften/Presence/DirectedPresenceSender.cpp b/Swiften/Presence/DirectedPresenceSender.cpp index ec0bd3f..c1134c7 100644 --- a/Swiften/Presence/DirectedPresenceSender.cpp +++ b/Swiften/Presence/DirectedPresenceSender.cpp @@ -1,41 +1,40 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #include <Swiften/Presence/DirectedPresenceSender.h> -#include <Swiften/Base/foreach.h> namespace Swift { DirectedPresenceSender::DirectedPresenceSender(PresenceSender* sender) : sender(sender) { } -void DirectedPresenceSender::sendPresence(boost::shared_ptr<Presence> presence) { - if (!sender->isAvailable()) { - return; - } +void DirectedPresenceSender::sendPresence(std::shared_ptr<Presence> presence) { + if (!sender->isAvailable()) { + return; + } - sender->sendPresence(presence); + sender->sendPresence(presence); - if (!presence->getTo().isValid()) { - boost::shared_ptr<Presence> presenceCopy(new Presence(*presence)); - foreach(const JID& jid, directedPresenceReceivers) { - presenceCopy->setTo(jid); - sender->sendPresence(presenceCopy); - } + if (!presence->getTo().isValid()) { + std::shared_ptr<Presence> presenceCopy(new Presence(*presence)); + for (const auto& jid : directedPresenceReceivers) { + presenceCopy->setTo(jid); + sender->sendPresence(presenceCopy); + } - lastSentUndirectedPresence = presence; - } + lastSentUndirectedPresence = presence; + } } /** - * Gets either the last broadcast presence, or an empty stanza if none has been sent. + * Gets the last broadcast presence, if none has been send the returned optional is not set. */ -boost::shared_ptr<Presence> DirectedPresenceSender::getLastSentUndirectedPresence() { - boost::shared_ptr<Presence> presenceCopy(lastSentUndirectedPresence ? new Presence(*lastSentUndirectedPresence) : new Presence()); - return presenceCopy; +boost::optional<Presence::ref> DirectedPresenceSender::getLastSentUndirectedPresence() const { + boost::optional<Presence::ref> presenceCopy = lastSentUndirectedPresence ? boost::optional<Presence::ref>((*lastSentUndirectedPresence)->clone()) : boost::optional<Presence::ref>(); + return presenceCopy; } /** @@ -44,14 +43,14 @@ boost::shared_ptr<Presence> DirectedPresenceSender::getLastSentUndirectedPresenc * @param sendPresence Also send the current global presence immediately. */ void DirectedPresenceSender::addDirectedPresenceReceiver(const JID& jid, SendPresence sendPresence) { - directedPresenceReceivers.insert(jid); - if (sendPresence == AndSendPresence && sender->isAvailable()) { - if (lastSentUndirectedPresence && lastSentUndirectedPresence->getType() == Presence::Available) { - boost::shared_ptr<Presence> presenceCopy(new Presence(*lastSentUndirectedPresence)); - presenceCopy->setTo(jid); - sender->sendPresence(presenceCopy); - } - } + directedPresenceReceivers.insert(jid); + if (sendPresence == AndSendPresence && sender->isAvailable()) { + if (lastSentUndirectedPresence && (*lastSentUndirectedPresence)->getType() == Presence::Available) { + std::shared_ptr<Presence> presenceCopy((*lastSentUndirectedPresence)->clone()); + presenceCopy->setTo(jid); + sender->sendPresence(presenceCopy); + } + } } /** @@ -60,17 +59,17 @@ void DirectedPresenceSender::addDirectedPresenceReceiver(const JID& jid, SendPre * @param sendPresence Also send presence type=unavailable immediately to jid. */ void DirectedPresenceSender::removeDirectedPresenceReceiver(const JID& jid, SendPresence sendPresence) { - directedPresenceReceivers.erase(jid); - if (sendPresence == AndSendPresence && sender->isAvailable()) { - boost::shared_ptr<Presence> presence(new Presence()); - presence->setType(Presence::Unavailable); - presence->setTo(jid); - sender->sendPresence(presence); - } + directedPresenceReceivers.erase(jid); + if (sendPresence == AndSendPresence && sender->isAvailable()) { + std::shared_ptr<Presence> presence(new Presence()); + presence->setType(Presence::Unavailable); + presence->setTo(jid); + sender->sendPresence(presence); + } } bool DirectedPresenceSender::isAvailable() const { - return sender->isAvailable(); + return sender->isAvailable(); } } diff --git a/Swiften/Presence/DirectedPresenceSender.h b/Swiften/Presence/DirectedPresenceSender.h index 0eb16a4..a397776 100644 --- a/Swiften/Presence/DirectedPresenceSender.h +++ b/Swiften/Presence/DirectedPresenceSender.h @@ -1,35 +1,37 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #pragma once #include <set> +#include <boost/optional.hpp> + +#include <Swiften/Base/API.h> #include <Swiften/Elements/Presence.h> #include <Swiften/Presence/PresenceSender.h> -#include <Swiften/Base/API.h> namespace Swift { - class SWIFTEN_API DirectedPresenceSender : public PresenceSender { - public: - enum SendPresence {AndSendPresence, DontSendPresence}; - DirectedPresenceSender(PresenceSender*); + class SWIFTEN_API DirectedPresenceSender : public PresenceSender { + public: + enum SendPresence {AndSendPresence, DontSendPresence}; + DirectedPresenceSender(PresenceSender*); - void addDirectedPresenceReceiver(const JID&, SendPresence); - void removeDirectedPresenceReceiver(const JID&, SendPresence); + void addDirectedPresenceReceiver(const JID&, SendPresence); + void removeDirectedPresenceReceiver(const JID&, SendPresence); - void sendPresence(Presence::ref); + void sendPresence(Presence::ref); - Presence::ref getLastSentUndirectedPresence(); + boost::optional<Presence::ref> getLastSentUndirectedPresence() const; - bool isAvailable() const; + bool isAvailable() const; - private: - Presence::ref lastSentUndirectedPresence; - PresenceSender* sender; - std::set<JID> directedPresenceReceivers; - }; + private: + boost::optional<Presence::ref> lastSentUndirectedPresence; + PresenceSender* sender; + std::set<JID> directedPresenceReceivers; + }; } diff --git a/Swiften/Presence/PayloadAddingPresenceSender.cpp b/Swiften/Presence/PayloadAddingPresenceSender.cpp index 5e8cd81..e5d2688 100644 --- a/Swiften/Presence/PayloadAddingPresenceSender.cpp +++ b/Swiften/Presence/PayloadAddingPresenceSender.cpp @@ -1,7 +1,7 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #include <Swiften/Presence/PayloadAddingPresenceSender.h> @@ -12,37 +12,37 @@ PayloadAddingPresenceSender::PayloadAddingPresenceSender(PresenceSender* sender) } void PayloadAddingPresenceSender::sendPresence(Presence::ref presence) { - if (presence->isAvailable()) { - if (!presence->getTo().isValid()) { - lastSentPresence = presence; - } - } - else { - lastSentPresence.reset(); - } - if (payload) { - Presence::ref sentPresence = Presence::create(presence); - sentPresence->updatePayload(payload); - sender->sendPresence(sentPresence); - } - else { - sender->sendPresence(presence); - } + if (presence->isAvailable()) { + if (!presence->getTo().isValid()) { + lastSentPresence = presence; + } + } + else { + lastSentPresence.reset(); + } + if (payload) { + Presence::ref sentPresence = Presence::create(presence); + sentPresence->updatePayload(payload); + sender->sendPresence(sentPresence); + } + else { + sender->sendPresence(presence); + } } bool PayloadAddingPresenceSender::isAvailable() const { - return sender->isAvailable(); + return sender->isAvailable(); } -void PayloadAddingPresenceSender::setPayload(boost::shared_ptr<Payload> payload) { - this->payload = payload; - if (lastSentPresence) { - sendPresence(lastSentPresence); - } +void PayloadAddingPresenceSender::setPayload(std::shared_ptr<Payload> payload) { + this->payload = payload; + if (lastSentPresence) { + sendPresence(lastSentPresence); + } } void PayloadAddingPresenceSender::reset() { - lastSentPresence.reset(); + lastSentPresence.reset(); } } diff --git a/Swiften/Presence/PayloadAddingPresenceSender.h b/Swiften/Presence/PayloadAddingPresenceSender.h index 4845865..010b77e 100644 --- a/Swiften/Presence/PayloadAddingPresenceSender.h +++ b/Swiften/Presence/PayloadAddingPresenceSender.h @@ -1,49 +1,47 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2017 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #pragma once #include <Swiften/Base/API.h> -#include <Swiften/Presence/PresenceSender.h> #include <Swiften/Elements/Payload.h> +#include <Swiften/Presence/PresenceSender.h> namespace Swift { - class StanzaChannel; - - /** - * This presence sender adds payloads to outgoing presences. - * - * This class isn't meant to be used with directed presence. - */ - class SWIFTEN_API PayloadAddingPresenceSender : public PresenceSender { - public: - PayloadAddingPresenceSender(PresenceSender*); - - void sendPresence(boost::shared_ptr<Presence>); - bool isAvailable() const; - - /** - * Sets the payload to be added to outgoing presences. - * If initial presence has been sent, this will resend the last sent presence - * with an updated payload. Initial presence is reset when unavailable presence is - * sent, or when reset() is called. - */ - void setPayload(boost::shared_ptr<Payload>); - - /** - * Resets the presence sender. - * This puts the presence sender back in the initial state (before initial - * presence has been sent). - * This also resets the chained sender. - */ - void reset(); - - private: - boost::shared_ptr<Presence> lastSentPresence; - PresenceSender* sender; - boost::shared_ptr<Payload> payload; - }; + /** + * This presence sender adds payloads to outgoing presences. + * + * This class isn't meant to be used with directed presence. + */ + class SWIFTEN_API PayloadAddingPresenceSender : public PresenceSender { + public: + PayloadAddingPresenceSender(PresenceSender*); + + void sendPresence(std::shared_ptr<Presence>); + bool isAvailable() const; + + /** + * Sets the payload to be added to outgoing presences. + * If initial presence has been sent, this will resend the last sent presence + * with an updated payload. Initial presence is reset when unavailable presence is + * sent, or when reset() is called. + */ + void setPayload(std::shared_ptr<Payload>); + + /** + * Resets the presence sender. + * This puts the presence sender back in the initial state (before initial + * presence has been sent). + * This also resets the chained sender. + */ + void reset(); + + private: + std::shared_ptr<Presence> lastSentPresence; + PresenceSender* sender; + std::shared_ptr<Payload> payload; + }; } diff --git a/Swiften/Presence/PresenceOracle.cpp b/Swiften/Presence/PresenceOracle.cpp index bfb5a3d..1c9d0ea 100644 --- a/Swiften/Presence/PresenceOracle.cpp +++ b/Swiften/Presence/PresenceOracle.cpp @@ -1,115 +1,214 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ -#include "PresenceOracle.h" +#include <Swiften/Presence/PresenceOracle.h> + +#include <queue> #include <boost/bind.hpp> #include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Elements/StatusShow.h> +#include <Swiften/Roster/XMPPRoster.h> namespace Swift { -PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel) { - stanzaChannel_ = stanzaChannel; - stanzaChannel_->onPresenceReceived.connect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1)); - stanzaChannel_->onAvailableChanged.connect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1)); +PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster) : stanzaChannel_(stanzaChannel), xmppRoster_(roster) { + stanzaChannel_->onPresenceReceived.connect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1)); + stanzaChannel_->onAvailableChanged.connect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1)); + xmppRoster_->onJIDRemoved.connect(boost::bind(&PresenceOracle::handleJIDRemoved, this, _1)); } PresenceOracle::~PresenceOracle() { - stanzaChannel_->onPresenceReceived.disconnect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1)); - stanzaChannel_->onAvailableChanged.disconnect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1)); + stanzaChannel_->onPresenceReceived.disconnect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1)); + stanzaChannel_->onAvailableChanged.disconnect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1)); + xmppRoster_->onJIDRemoved.disconnect(boost::bind(&PresenceOracle::handleJIDRemoved, this, _1)); } void PresenceOracle::handleStanzaChannelAvailableChanged(bool available) { - if (available) { - entries_.clear(); - } + if (available) { + entries_.clear(); + } } - void PresenceOracle::handleIncomingPresence(Presence::ref presence) { - JID bareJID(presence->getFrom().toBare()); - if (presence->getType() == Presence::Subscribe) { - } - else { - Presence::ref passedPresence = presence; - if (presence->getType() == Presence::Unsubscribe) { - /* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */ - passedPresence = Presence::ref(new Presence()); - passedPresence->setType(Presence::Unavailable); - passedPresence->setFrom(bareJID); - passedPresence->setStatus(presence->getStatus()); - } - std::map<JID, boost::shared_ptr<Presence> > jidMap = entries_[bareJID]; - if (passedPresence->getFrom().isBare() && presence->getType() == Presence::Unavailable) { - /* Have a bare-JID only presence of offline */ - jidMap.clear(); - } else if (passedPresence->getType() == Presence::Available) { - /* Don't have a bare-JID only offline presence once there are available presences */ - jidMap.erase(bareJID); - } - if (passedPresence->getType() == Presence::Unavailable && jidMap.size() > 1) { - jidMap.erase(passedPresence->getFrom()); - } else { - jidMap[passedPresence->getFrom()] = passedPresence; - } - entries_[bareJID] = jidMap; - onPresenceChange(passedPresence); - } + JID bareJID(presence->getFrom().toBare()); + if (presence->getType() == Presence::Subscribe) { + } + else { + Presence::ref passedPresence = presence; + if (presence->getType() == Presence::Unsubscribe) { + /* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */ + passedPresence = Presence::ref(new Presence()); + passedPresence->setType(Presence::Unavailable); + passedPresence->setFrom(bareJID); + passedPresence->setStatus(presence->getStatus()); + } + PresenceMap jidMap = entries_[bareJID]; + if (passedPresence->getFrom().isBare() && presence->getType() == Presence::Unavailable) { + /* Have a bare-JID only presence of offline */ + jidMap.clear(); + } else if (passedPresence->getType() == Presence::Available) { + /* Don't have a bare-JID only offline presence once there are available presences */ + jidMap.erase(bareJID); + } + if (passedPresence->getType() == Presence::Unavailable && jidMap.size() > 1) { + jidMap.erase(passedPresence->getFrom()); + } else { + jidMap[passedPresence->getFrom()] = passedPresence; + } + entries_[bareJID] = jidMap; + onPresenceChange(passedPresence); + } +} + +void PresenceOracle::handleJIDRemoved(const JID& removedJID) { + /* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */ + Presence::ref unavailablePresence = Presence::ref(new Presence()); + unavailablePresence->setType(Presence::Unavailable); + unavailablePresence->setFrom(removedJID); + + if (entries_.find(removedJID) != entries_.end()) { + entries_[removedJID].clear(); + entries_[removedJID][removedJID] = unavailablePresence; + } + + onPresenceChange(unavailablePresence); } Presence::ref PresenceOracle::getLastPresence(const JID& jid) const { - PresencesMap::const_iterator i = entries_.find(jid.toBare()); - if (i == entries_.end()) { - return Presence::ref(); - } - PresenceMap presenceMap = i->second; - PresenceMap::const_iterator j = presenceMap.find(jid); - if (j != presenceMap.end()) { - return j->second; - } - else { - return Presence::ref(); - } + PresencesMap::const_iterator i = entries_.find(jid.toBare()); + if (i == entries_.end()) { + return Presence::ref(); + } + PresenceMap presenceMap = i->second; + PresenceMap::const_iterator j = presenceMap.find(jid); + if (j != presenceMap.end()) { + return j->second; + } + else { + return Presence::ref(); + } } std::vector<Presence::ref> PresenceOracle::getAllPresence(const JID& bareJID) const { - std::vector<Presence::ref> results; - PresencesMap::const_iterator i = entries_.find(bareJID); - if (i == entries_.end()) { - return results; - } - PresenceMap presenceMap = i->second; - PresenceMap::const_iterator j = presenceMap.begin(); - for (; j != presenceMap.end(); ++j) { - Presence::ref current = j->second; - results.push_back(current); - } - return results; + std::vector<Presence::ref> results; + PresencesMap::const_iterator i = entries_.find(bareJID); + if (i == entries_.end()) { + return results; + } + for (const auto& jidPresence : i->second) { + if (jidPresence.second) { + results.push_back(jidPresence.second); + } + } + return results; +} + +struct PresenceAccountCmp { + static int preferenceFromStatusShow(StatusShow::Type showType) { + switch (showType) { + case StatusShow::FFC: + return 5; + case StatusShow::Online: + return 4; + case StatusShow::DND: + return 3; + case StatusShow::Away: + return 2; + case StatusShow::XA: + return 1; + case StatusShow::None: + return 0; + } + assert(false); + return -1; + } + + bool operator()(const Presence::ref& a, const Presence::ref& b) { + int aPreference = preferenceFromStatusShow(a->getShow()); + int bPreference = preferenceFromStatusShow(b->getShow()); + + if (aPreference != bPreference) { + return aPreference < bPreference; + } + if (a->getPriority() != b->getPriority()) { + return a->getPriority() < b->getPriority(); + } + return a->getFrom().getResource() < b->getFrom().getResource(); + } +}; + +typedef std::priority_queue<Presence::ref, std::vector<Presence::ref>, PresenceAccountCmp> PresenceAccountPriorityQueue; + +Presence::ref PresenceOracle::getActivePresence(const std::vector<Presence::ref> presences) { + Presence::ref accountPresence; + + PresenceAccountPriorityQueue online; + PresenceAccountPriorityQueue away; + PresenceAccountPriorityQueue offline; + + for (auto&& presence : presences) { + switch (presence->getShow()) { + case StatusShow::Online: + online.push(presence); + break; + case StatusShow::Away: + away.push(presence); + break; + case StatusShow::FFC: + online.push(presence); + break; + case StatusShow::XA: + away.push(presence); + break; + case StatusShow::DND: + away.push(presence); + break; + case StatusShow::None: + offline.push(presence); + break; + } + } + + if (!online.empty()) { + accountPresence = online.top(); + } + else if (!away.empty()) { + accountPresence = away.top(); + } + else if (!offline.empty()) { + accountPresence = offline.top(); + } + return accountPresence; +} + +Presence::ref PresenceOracle::getAccountPresence(const JID& jid) const { + Presence::ref accountPresence; + std::vector<Presence::ref> allPresences = getAllPresence(jid.toBare()); + accountPresence = getActivePresence(allPresences); + return accountPresence; } Presence::ref PresenceOracle::getHighestPriorityPresence(const JID& bareJID) const { - PresencesMap::const_iterator i = entries_.find(bareJID); - if (i == entries_.end()) { - return Presence::ref(); - } - PresenceMap presenceMap = i->second; - PresenceMap::const_iterator j = presenceMap.begin(); - Presence::ref highest; - for (; j != presenceMap.end(); ++j) { - Presence::ref current = j->second; - if (!highest - || current->getPriority() > highest->getPriority() - || (current->getPriority() == highest->getPriority() - && StatusShow::typeToAvailabilityOrdering(current->getShow()) > StatusShow::typeToAvailabilityOrdering(highest->getShow()))) { - highest = current; - } - - } - return highest; + PresencesMap::const_iterator i = entries_.find(bareJID); + if (i == entries_.end()) { + return Presence::ref(); + } + Presence::ref highest; + for (const auto& jidPresence : i->second) { + Presence::ref current = jidPresence.second; + if (!highest + || current->getPriority() > highest->getPriority() + || (current->getPriority() == highest->getPriority() + && StatusShow::typeToAvailabilityOrdering(current->getShow()) > StatusShow::typeToAvailabilityOrdering(highest->getShow()))) { + highest = current; + } + } + return highest; } } diff --git a/Swiften/Presence/PresenceOracle.h b/Swiften/Presence/PresenceOracle.h index fcf974f..decc0ee 100644 --- a/Swiften/Presence/PresenceOracle.h +++ b/Swiften/Presence/PresenceOracle.h @@ -1,43 +1,79 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #pragma once #include <map> - #include <string> -#include <Swiften/Elements/Presence.h> + +#include <boost/signals2.hpp> #include <Swiften/Base/API.h> -#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/Presence.h> namespace Swift { - class StanzaChannel; - - class SWIFTEN_API PresenceOracle { - public: - PresenceOracle(StanzaChannel* stanzaChannel); - ~PresenceOracle(); - - Presence::ref getLastPresence(const JID&) const; - Presence::ref getHighestPriorityPresence(const JID& bareJID) const; - std::vector<Presence::ref> getAllPresence(const JID& bareJID) const; - - public: - boost::signal<void (Presence::ref)> onPresenceChange; - - private: - void handleIncomingPresence(Presence::ref presence); - void handleStanzaChannelAvailableChanged(bool); - - private: - typedef std::map<JID, Presence::ref> PresenceMap; - typedef std::map<JID, PresenceMap> PresencesMap; - PresencesMap entries_; - StanzaChannel* stanzaChannel_; - }; + class StanzaChannel; + class XMPPRoster; + + /** + * The PresenceOracle class observes all received presence stanzas for + * the \ref StanzaChannel class passed in the constructor and maintains a + * cache. + */ + class SWIFTEN_API PresenceOracle { + public: + PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster); + ~PresenceOracle(); + + Presence::ref getLastPresence(const JID&) const; + Presence::ref getHighestPriorityPresence(const JID& bareJID) const; + std::vector<Presence::ref> getAllPresence(const JID& bareJID) const; + + /** + * \brief Returns the relevant presence for a list of resource presences. + * + * It only takes the presence show type into account. Priorities are + * ignored as various clients set them to arbitrary values unrelated + * to actual end point availability. + * + * The presences of the resources are group by availablilty and sorted + * by show type in the following order: + * + * -# Online + * -# Free for Chat + * -# Available + * -# Away + * -# DND + * -# Extended Away + * -# Away + * -# Offline + * -# Unavailable + */ + static Presence::ref getActivePresence(const std::vector<Presence::ref> presences); + + /** + * \brief This considers all online resources of a bare JID and returns + * the value returned by \ref getActivePresence when passing this list. + */ + Presence::ref getAccountPresence(const JID& jid) const; + + public: + boost::signals2::signal<void (Presence::ref)> onPresenceChange; + + private: + void handleIncomingPresence(Presence::ref presence); + void handleStanzaChannelAvailableChanged(bool); + void handleJIDRemoved(const JID& removedJID); + + private: + typedef std::map<JID, Presence::ref> PresenceMap; + typedef std::map<JID, PresenceMap> PresencesMap; + PresencesMap entries_; + StanzaChannel* stanzaChannel_; + XMPPRoster* xmppRoster_; + }; } diff --git a/Swiften/Presence/PresenceSender.cpp b/Swiften/Presence/PresenceSender.cpp index b75141d..20d284a 100644 --- a/Swiften/Presence/PresenceSender.cpp +++ b/Swiften/Presence/PresenceSender.cpp @@ -1,7 +1,7 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #include <Swiften/Presence/PresenceSender.h> diff --git a/Swiften/Presence/PresenceSender.h b/Swiften/Presence/PresenceSender.h index c302074..9d4e175 100644 --- a/Swiften/Presence/PresenceSender.h +++ b/Swiften/Presence/PresenceSender.h @@ -1,20 +1,21 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Elements/Presence.h> namespace Swift { - class PresenceSender { - public: - virtual ~PresenceSender(); + class SWIFTEN_API PresenceSender { + public: + virtual ~PresenceSender(); - virtual void sendPresence(Presence::ref) = 0; + virtual void sendPresence(Presence::ref) = 0; - virtual bool isAvailable() const = 0; - }; + virtual bool isAvailable() const = 0; + }; } diff --git a/Swiften/Presence/SConscript b/Swiften/Presence/SConscript index 33acbd3..c3e32f2 100644 --- a/Swiften/Presence/SConscript +++ b/Swiften/Presence/SConscript @@ -1,11 +1,11 @@ Import("swiften_env") objects = swiften_env.SwiftenObject([ - "PresenceOracle.cpp", - "PresenceSender.cpp", - "DirectedPresenceSender.cpp", - "PayloadAddingPresenceSender.cpp", - "StanzaChannelPresenceSender.cpp", - "SubscriptionManager.cpp", - ]) + "PresenceOracle.cpp", + "PresenceSender.cpp", + "DirectedPresenceSender.cpp", + "PayloadAddingPresenceSender.cpp", + "StanzaChannelPresenceSender.cpp", + "SubscriptionManager.cpp", + ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Presence/StanzaChannelPresenceSender.cpp b/Swiften/Presence/StanzaChannelPresenceSender.cpp index 5863a2d..a96f40f 100644 --- a/Swiften/Presence/StanzaChannelPresenceSender.cpp +++ b/Swiften/Presence/StanzaChannelPresenceSender.cpp @@ -1,10 +1,11 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #include <Swiften/Presence/StanzaChannelPresenceSender.h> + #include <Swiften/Client/StanzaChannel.h> namespace Swift { @@ -13,11 +14,11 @@ StanzaChannelPresenceSender::StanzaChannelPresenceSender(StanzaChannel* channel) } void StanzaChannelPresenceSender::sendPresence(Presence::ref presence) { - channel->sendPresence(presence); + channel->sendPresence(presence); } bool StanzaChannelPresenceSender::isAvailable() const { - return channel->isAvailable(); + return channel->isAvailable(); } } diff --git a/Swiften/Presence/StanzaChannelPresenceSender.h b/Swiften/Presence/StanzaChannelPresenceSender.h index 8649acb..2112d06 100644 --- a/Swiften/Presence/StanzaChannelPresenceSender.h +++ b/Swiften/Presence/StanzaChannelPresenceSender.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #pragma once @@ -10,17 +10,17 @@ #include <Swiften/Presence/PresenceSender.h> namespace Swift { - class StanzaChannel; + class StanzaChannel; - class SWIFTEN_API StanzaChannelPresenceSender : public PresenceSender { - public: - StanzaChannelPresenceSender(StanzaChannel*); + class SWIFTEN_API StanzaChannelPresenceSender : public PresenceSender { + public: + StanzaChannelPresenceSender(StanzaChannel*); - void sendPresence(Presence::ref); + void sendPresence(Presence::ref); - bool isAvailable() const; + bool isAvailable() const; - private: - StanzaChannel* channel; - }; + private: + StanzaChannel* channel; + }; } diff --git a/Swiften/Presence/SubscriptionManager.cpp b/Swiften/Presence/SubscriptionManager.cpp index 01525dd..83009e9 100644 --- a/Swiften/Presence/SubscriptionManager.cpp +++ b/Swiften/Presence/SubscriptionManager.cpp @@ -1,56 +1,55 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #include <Swiften/Presence/SubscriptionManager.h> #include <boost/bind.hpp> -#include <Swiften/Base/foreach.h> #include <Swiften/Client/StanzaChannel.h> namespace Swift { SubscriptionManager::SubscriptionManager(StanzaChannel* channel) : stanzaChannel(channel) { - stanzaChannel->onPresenceReceived.connect(boost::bind(&SubscriptionManager::handleIncomingPresence, this, _1)); + stanzaChannel->onPresenceReceived.connect(boost::bind(&SubscriptionManager::handleIncomingPresence, this, _1)); } SubscriptionManager::~SubscriptionManager() { - stanzaChannel->onPresenceReceived.disconnect(boost::bind(&SubscriptionManager::handleIncomingPresence, this, _1)); + stanzaChannel->onPresenceReceived.disconnect(boost::bind(&SubscriptionManager::handleIncomingPresence, this, _1)); } void SubscriptionManager::cancelSubscription(const JID& jid) { - Presence::ref stanza(new Presence()); - stanza->setType(Presence::Unsubscribed); - stanza->setTo(jid); - stanzaChannel->sendPresence(stanza); + Presence::ref stanza(new Presence()); + stanza->setType(Presence::Unsubscribed); + stanza->setTo(jid); + stanzaChannel->sendPresence(stanza); } void SubscriptionManager::confirmSubscription(const JID& jid) { - Presence::ref stanza(new Presence()); - stanza->setType(Presence::Subscribed); - stanza->setTo(jid); - stanzaChannel->sendPresence(stanza); + Presence::ref stanza(new Presence()); + stanza->setType(Presence::Subscribed); + stanza->setTo(jid); + stanzaChannel->sendPresence(stanza); } void SubscriptionManager::requestSubscription(const JID& jid) { - Presence::ref stanza(new Presence()); - stanza->setType(Presence::Subscribe); - stanza->setTo(jid); - stanzaChannel->sendPresence(stanza); + Presence::ref stanza(new Presence()); + stanza->setType(Presence::Subscribe); + stanza->setTo(jid); + stanzaChannel->sendPresence(stanza); } void SubscriptionManager::handleIncomingPresence(Presence::ref presence) { - JID bareJID(presence->getFrom().toBare()); - if (presence->getType() == Presence::Subscribe) { - onPresenceSubscriptionRequest(bareJID, presence->getStatus(), presence); - } - else if (presence->getType() == Presence::Unsubscribe) { - onPresenceSubscriptionRevoked(bareJID, presence->getStatus()); - } + JID bareJID(presence->getFrom().toBare()); + if (presence->getType() == Presence::Subscribe) { + onPresenceSubscriptionRequest(bareJID, presence->getStatus(), presence); + } + else if (presence->getType() == Presence::Unsubscribe) { + onPresenceSubscriptionRevoked(bareJID, presence->getStatus()); + } } diff --git a/Swiften/Presence/SubscriptionManager.h b/Swiften/Presence/SubscriptionManager.h index 5fabb04..c1997bd 100644 --- a/Swiften/Presence/SubscriptionManager.h +++ b/Swiften/Presence/SubscriptionManager.h @@ -1,47 +1,48 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #pragma once #include <map> - #include <string> -#include <Swiften/JID/JID.h> -#include <Swiften/Base/boost_bsignals.h> -#include <Swiften/Elements/Presence.h> + +#include <boost/signals2.hpp> + #include <Swiften/Base/API.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/JID/JID.h> namespace Swift { - class StanzaChannel; - - class SWIFTEN_API SubscriptionManager { - public: - SubscriptionManager(StanzaChannel* stanzaChannel); - ~SubscriptionManager(); - - void cancelSubscription(const JID& jid); - void confirmSubscription(const JID& jid); - void requestSubscription(const JID& jid); - - /** - * This signal is emitted when a presence subscription request is - * received. - * - * The third parameter of this signal is the original presence stanza - * received. This is useful when the subscriber adds extensions to - * the request. - */ - boost::signal<void (const JID&, const std::string&, Presence::ref)> onPresenceSubscriptionRequest; - - boost::signal<void (const JID&, const std::string&)> onPresenceSubscriptionRevoked; - - private: - void handleIncomingPresence(Presence::ref presence); - - private: - StanzaChannel* stanzaChannel; - }; + class StanzaChannel; + + class SWIFTEN_API SubscriptionManager { + public: + SubscriptionManager(StanzaChannel* stanzaChannel); + ~SubscriptionManager(); + + void cancelSubscription(const JID& jid); + void confirmSubscription(const JID& jid); + void requestSubscription(const JID& jid); + + /** + * This signal is emitted when a presence subscription request is + * received. + * + * The third parameter of this signal is the original presence stanza + * received. This is useful when the subscriber adds extensions to + * the request. + */ + boost::signals2::signal<void (const JID&, const std::string&, Presence::ref)> onPresenceSubscriptionRequest; + + boost::signals2::signal<void (const JID&, const std::string&)> onPresenceSubscriptionRevoked; + + private: + void handleIncomingPresence(Presence::ref presence); + + private: + StanzaChannel* stanzaChannel; + }; } diff --git a/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp b/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp index 0da78e6..e313124 100644 --- a/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp +++ b/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp @@ -1,9 +1,11 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ +#include <memory> + #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -14,140 +16,135 @@ using namespace Swift; class DirectedPresenceSenderTest : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(DirectedPresenceSenderTest); - CPPUNIT_TEST(testSendPresence); - CPPUNIT_TEST(testSendPresence_UndirectedPresenceWithDirectedPresenceReceivers); - CPPUNIT_TEST(testSendPresence_DirectedPresenceWithDirectedPresenceReceivers); - CPPUNIT_TEST(testAddDirectedPresenceReceiver); - CPPUNIT_TEST(testAddDirectedPresenceReceiver_WithoutSendingPresence); - CPPUNIT_TEST(testAddDirectedPresenceReceiver_AfterSendingDirectedPresence); - CPPUNIT_TEST(testRemoveDirectedPresenceReceiver); - CPPUNIT_TEST(testRemoveDirectedPresenceReceiver_WithoutSendingPresence); - CPPUNIT_TEST_SUITE_END(); - - public: - void setUp() { - channel = new DummyStanzaChannel(); - testPresence = boost::make_shared<Presence>(); - testPresence->setStatus("Foo"); - secondTestPresence = boost::make_shared<Presence>(); - secondTestPresence->setStatus("Bar"); - stanzaChannelPresenceSender = new StanzaChannelPresenceSender(channel); - } - - void tearDown() { - delete stanzaChannelPresenceSender; - delete channel; - } - - void testSendPresence() { - boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); - testling->sendPresence(testPresence); - - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); - boost::shared_ptr<Presence> presence = boost::dynamic_pointer_cast<Presence>(channel->sentStanzas[0]); - CPPUNIT_ASSERT(testPresence == presence); - } - - void testSendPresence_UndirectedPresenceWithDirectedPresenceReceivers() { - boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); - - testling->sendPresence(testPresence); - - CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(channel->sentStanzas.size())); - boost::shared_ptr<Presence> presence = boost::dynamic_pointer_cast<Presence>(channel->sentStanzas[0]); - CPPUNIT_ASSERT(testPresence == presence); - presence = boost::dynamic_pointer_cast<Presence>(channel->sentStanzas[1]); - CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); - CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); - } - - void testSendPresence_DirectedPresenceWithDirectedPresenceReceivers() { - boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); - channel->sentStanzas.clear(); - - testPresence->setTo(JID("foo@bar.com")); - testling->sendPresence(testPresence); - - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); - boost::shared_ptr<Presence> presence = boost::dynamic_pointer_cast<Presence>(channel->sentStanzas[0]); - CPPUNIT_ASSERT(testPresence == presence); - } - - void testAddDirectedPresenceReceiver() { - boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); - testling->sendPresence(testPresence); - channel->sentStanzas.clear(); - - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); - - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); - boost::shared_ptr<Presence> presence = boost::dynamic_pointer_cast<Presence>(channel->sentStanzas[0]); - CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); - CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); - } - - void testAddDirectedPresenceReceiver_WithoutSendingPresence() { - boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); - testling->sendPresence(testPresence); - channel->sentStanzas.clear(); - - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::DontSendPresence); - - CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(channel->sentStanzas.size())); - } - - void testAddDirectedPresenceReceiver_AfterSendingDirectedPresence() { - boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); - testling->sendPresence(testPresence); - secondTestPresence->setTo(JID("foo@bar.com")); - testling->sendPresence(secondTestPresence); - channel->sentStanzas.clear(); - - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); - - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); - boost::shared_ptr<Presence> presence = boost::dynamic_pointer_cast<Presence>(channel->sentStanzas[0]); - CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); - CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); - } - - void testRemoveDirectedPresenceReceiver() { - boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::DontSendPresence); - - testling->removeDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); - testling->sendPresence(testPresence); - - CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(channel->sentStanzas.size())); - CPPUNIT_ASSERT_EQUAL(boost::dynamic_pointer_cast<Presence>(channel->sentStanzas[0])->getType(), Presence::Unavailable); - CPPUNIT_ASSERT(channel->sentStanzas[1] == testPresence); - } - - void testRemoveDirectedPresenceReceiver_WithoutSendingPresence() { - boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); - testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); - channel->sentStanzas.clear(); - - testling->removeDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::DontSendPresence); - testling->sendPresence(testPresence); - - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); - CPPUNIT_ASSERT(channel->sentStanzas[0] == testPresence); - } - - private: - DirectedPresenceSender* createPresenceSender() { - return new DirectedPresenceSender(stanzaChannelPresenceSender); - } - - private: - DummyStanzaChannel* channel; - StanzaChannelPresenceSender* stanzaChannelPresenceSender; - boost::shared_ptr<Presence> testPresence; - boost::shared_ptr<Presence> secondTestPresence; + CPPUNIT_TEST_SUITE(DirectedPresenceSenderTest); + CPPUNIT_TEST(testSendPresence); + CPPUNIT_TEST(testSendPresence_UndirectedPresenceWithDirectedPresenceReceivers); + CPPUNIT_TEST(testSendPresence_DirectedPresenceWithDirectedPresenceReceivers); + CPPUNIT_TEST(testAddDirectedPresenceReceiver); + CPPUNIT_TEST(testAddDirectedPresenceReceiver_WithoutSendingPresence); + CPPUNIT_TEST(testAddDirectedPresenceReceiver_AfterSendingDirectedPresence); + CPPUNIT_TEST(testRemoveDirectedPresenceReceiver); + CPPUNIT_TEST(testRemoveDirectedPresenceReceiver_WithoutSendingPresence); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + channel = std::make_unique<DummyStanzaChannel>(); + testPresence = std::make_shared<Presence>(); + testPresence->setStatus("Foo"); + secondTestPresence = std::make_shared<Presence>(); + secondTestPresence->setStatus("Bar"); + stanzaChannelPresenceSender = std::make_unique<StanzaChannelPresenceSender>(channel.get()); + } + + void testSendPresence() { + std::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); + testling->sendPresence(testPresence); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); + std::shared_ptr<Presence> presence = std::dynamic_pointer_cast<Presence>(channel->sentStanzas[0]); + CPPUNIT_ASSERT(testPresence == presence); + } + + void testSendPresence_UndirectedPresenceWithDirectedPresenceReceivers() { + std::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); + + testling->sendPresence(testPresence); + + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(channel->sentStanzas.size())); + std::shared_ptr<Presence> presence = std::dynamic_pointer_cast<Presence>(channel->sentStanzas[0]); + CPPUNIT_ASSERT(testPresence == presence); + presence = std::dynamic_pointer_cast<Presence>(channel->sentStanzas[1]); + CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); + } + + void testSendPresence_DirectedPresenceWithDirectedPresenceReceivers() { + std::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); + channel->sentStanzas.clear(); + + testPresence->setTo(JID("foo@bar.com")); + testling->sendPresence(testPresence); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); + std::shared_ptr<Presence> presence = std::dynamic_pointer_cast<Presence>(channel->sentStanzas[0]); + CPPUNIT_ASSERT(testPresence == presence); + } + + void testAddDirectedPresenceReceiver() { + std::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); + testling->sendPresence(testPresence); + channel->sentStanzas.clear(); + + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); + std::shared_ptr<Presence> presence = std::dynamic_pointer_cast<Presence>(channel->sentStanzas[0]); + CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); + } + + void testAddDirectedPresenceReceiver_WithoutSendingPresence() { + std::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); + testling->sendPresence(testPresence); + channel->sentStanzas.clear(); + + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::DontSendPresence); + + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(channel->sentStanzas.size())); + } + + void testAddDirectedPresenceReceiver_AfterSendingDirectedPresence() { + std::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); + testling->sendPresence(testPresence); + secondTestPresence->setTo(JID("foo@bar.com")); + testling->sendPresence(secondTestPresence); + channel->sentStanzas.clear(); + + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); + std::shared_ptr<Presence> presence = std::dynamic_pointer_cast<Presence>(channel->sentStanzas[0]); + CPPUNIT_ASSERT_EQUAL(testPresence->getStatus(), presence->getStatus()); + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/teaparty"), presence->getTo()); + } + + void testRemoveDirectedPresenceReceiver() { + std::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::DontSendPresence); + + testling->removeDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); + testling->sendPresence(testPresence); + + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(channel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(std::dynamic_pointer_cast<Presence>(channel->sentStanzas[0])->getType(), Presence::Unavailable); + CPPUNIT_ASSERT(channel->sentStanzas[1] == testPresence); + } + + void testRemoveDirectedPresenceReceiver_WithoutSendingPresence() { + std::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); + testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); + channel->sentStanzas.clear(); + + testling->removeDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::DontSendPresence); + testling->sendPresence(testPresence); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); + CPPUNIT_ASSERT(channel->sentStanzas[0] == testPresence); + } + + private: + DirectedPresenceSender* createPresenceSender() { + return new DirectedPresenceSender(stanzaChannelPresenceSender.get()); + } + + private: + std::unique_ptr<DummyStanzaChannel> channel; + std::unique_ptr<StanzaChannelPresenceSender> stanzaChannelPresenceSender; + std::shared_ptr<Presence> testPresence; + std::shared_ptr<Presence> secondTestPresence; }; CPPUNIT_TEST_SUITE_REGISTRATION(DirectedPresenceSenderTest); diff --git a/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp b/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp index 3a6ab31..234f303 100644 --- a/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp +++ b/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp @@ -1,144 +1,146 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/extensions/TestFactoryRegistry.h> #include <vector> + #include <boost/bind.hpp> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Elements/Body.h> #include <Swiften/Presence/PayloadAddingPresenceSender.h> #include <Swiften/Presence/StanzaChannelPresenceSender.h> -#include <Swiften/Elements/Body.h> -#include <Swiften/Client/DummyStanzaChannel.h> using namespace Swift; class PayloadAddingPresenceSenderTest : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(PayloadAddingPresenceSenderTest); - CPPUNIT_TEST(testSetPayloadAddsPayloadOnPresenceSend); - CPPUNIT_TEST(testSetNullPayloadDoesNotAddPayloadOnPresenceSend); - CPPUNIT_TEST(testSendPresenceDoesNotAlterOriginalPayload); - CPPUNIT_TEST(testSetPayloadAfterInitialPresenceResendsPresence); - CPPUNIT_TEST(testSetPayloadAfterUnavailablePresenceDoesNotResendPresence); - CPPUNIT_TEST(testSetPayloadAfterResetDoesNotResendPresence); - CPPUNIT_TEST(testSendDirectedPresenceIsNotResent); - CPPUNIT_TEST_SUITE_END(); + CPPUNIT_TEST_SUITE(PayloadAddingPresenceSenderTest); + CPPUNIT_TEST(testSetPayloadAddsPayloadOnPresenceSend); + CPPUNIT_TEST(testSetNullPayloadDoesNotAddPayloadOnPresenceSend); + CPPUNIT_TEST(testSendPresenceDoesNotAlterOriginalPayload); + CPPUNIT_TEST(testSetPayloadAfterInitialPresenceResendsPresence); + CPPUNIT_TEST(testSetPayloadAfterUnavailablePresenceDoesNotResendPresence); + CPPUNIT_TEST(testSetPayloadAfterResetDoesNotResendPresence); + CPPUNIT_TEST(testSendDirectedPresenceIsNotResent); + CPPUNIT_TEST_SUITE_END(); - public: - void setUp() { - stanzaChannel = new DummyStanzaChannel(); - presenceSender = new StanzaChannelPresenceSender(stanzaChannel); - } + public: + void setUp() { + stanzaChannel = new DummyStanzaChannel(); + presenceSender = new StanzaChannelPresenceSender(stanzaChannel); + } - void tearDown() { - delete presenceSender; - delete stanzaChannel; - } + void tearDown() { + delete presenceSender; + delete stanzaChannel; + } - void testSetPayloadAddsPayloadOnPresenceSend() { - boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); + void testSetPayloadAddsPayloadOnPresenceSend() { + std::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); - testling->setPayload(MyPayload::create("foo")); - testling->sendPresence(Presence::create("bar")); + testling->setPayload(MyPayload::create("foo")); + testling->sendPresence(Presence::create("bar")); - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); - CPPUNIT_ASSERT_EQUAL(std::string("bar"), stanzaChannel->getStanzaAtIndex<Presence>(0)->getStatus()); - CPPUNIT_ASSERT(stanzaChannel->getStanzaAtIndex<Presence>(0)->getPayload<MyPayload>()); - } + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), stanzaChannel->getStanzaAtIndex<Presence>(0)->getStatus()); + CPPUNIT_ASSERT(stanzaChannel->getStanzaAtIndex<Presence>(0)->getPayload<MyPayload>()); + } - void testSetNullPayloadDoesNotAddPayloadOnPresenceSend() { - boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); + void testSetNullPayloadDoesNotAddPayloadOnPresenceSend() { + std::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); - testling->setPayload(MyPayload::ref()); - testling->sendPresence(Presence::create("bar")); + testling->setPayload(MyPayload::ref()); + testling->sendPresence(Presence::create("bar")); - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); - CPPUNIT_ASSERT_EQUAL(std::string("bar"), stanzaChannel->getStanzaAtIndex<Presence>(0)->getStatus()); - CPPUNIT_ASSERT(!stanzaChannel->getStanzaAtIndex<Presence>(0)->getPayload<MyPayload>()); - } + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), stanzaChannel->getStanzaAtIndex<Presence>(0)->getStatus()); + CPPUNIT_ASSERT(!stanzaChannel->getStanzaAtIndex<Presence>(0)->getPayload<MyPayload>()); + } - void testSendPresenceDoesNotAlterOriginalPayload() { - boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); + void testSendPresenceDoesNotAlterOriginalPayload() { + std::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); - testling->setPayload(MyPayload::create("foo")); - Presence::ref presence(Presence::create("bar")); - testling->sendPresence(presence); + testling->setPayload(MyPayload::create("foo")); + Presence::ref presence(Presence::create("bar")); + testling->sendPresence(presence); - CPPUNIT_ASSERT(!presence->getPayload<MyPayload>()); - } + CPPUNIT_ASSERT(!presence->getPayload<MyPayload>()); + } - void testSetPayloadAfterInitialPresenceResendsPresence() { - boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); + void testSetPayloadAfterInitialPresenceResendsPresence() { + std::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); - testling->sendPresence(Presence::create("bar")); - testling->setPayload(MyPayload::create("foo")); + testling->sendPresence(Presence::create("bar")); + testling->setPayload(MyPayload::create("foo")); - CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(stanzaChannel->sentStanzas.size())); - CPPUNIT_ASSERT_EQUAL(std::string("bar"), stanzaChannel->getStanzaAtIndex<Presence>(1)->getStatus()); - CPPUNIT_ASSERT(stanzaChannel->getStanzaAtIndex<Presence>(1)->getPayload<MyPayload>()); - } + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), stanzaChannel->getStanzaAtIndex<Presence>(1)->getStatus()); + CPPUNIT_ASSERT(stanzaChannel->getStanzaAtIndex<Presence>(1)->getPayload<MyPayload>()); + } - void testSetPayloadAfterUnavailablePresenceDoesNotResendPresence() { - boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); + void testSetPayloadAfterUnavailablePresenceDoesNotResendPresence() { + std::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); - testling->sendPresence(Presence::create("bar")); + testling->sendPresence(Presence::create("bar")); - Presence::ref presence = Presence::create("bar"); - presence->setType(Presence::Unavailable); - testling->sendPresence(presence); + Presence::ref presence = Presence::create("bar"); + presence->setType(Presence::Unavailable); + testling->sendPresence(presence); - testling->setPayload(MyPayload::create("foo")); + testling->setPayload(MyPayload::create("foo")); - CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(stanzaChannel->sentStanzas.size())); - } + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(stanzaChannel->sentStanzas.size())); + } - void testSetPayloadAfterResetDoesNotResendPresence() { - boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); - testling->sendPresence(Presence::create("bar")); + void testSetPayloadAfterResetDoesNotResendPresence() { + std::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); + testling->sendPresence(Presence::create("bar")); - testling->reset(); - testling->setPayload(MyPayload::create("foo")); + testling->reset(); + testling->setPayload(MyPayload::create("foo")); - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); - } + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); + } - void testSendDirectedPresenceIsNotResent() { - boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); + void testSendDirectedPresenceIsNotResent() { + std::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); - testling->sendPresence(Presence::create("bar")); - Presence::ref directedPresence = Presence::create("baz"); - directedPresence->setTo(JID("foo@bar.com")); - testling->sendPresence(directedPresence); - testling->setPayload(MyPayload::create("foo")); + testling->sendPresence(Presence::create("bar")); + Presence::ref directedPresence = Presence::create("baz"); + directedPresence->setTo(JID("foo@bar.com")); + testling->sendPresence(directedPresence); + testling->setPayload(MyPayload::create("foo")); - CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(stanzaChannel->sentStanzas.size())); - CPPUNIT_ASSERT_EQUAL(std::string("bar"), stanzaChannel->getStanzaAtIndex<Presence>(2)->getStatus()); - } + CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), stanzaChannel->getStanzaAtIndex<Presence>(2)->getStatus()); + } - private: - boost::shared_ptr<PayloadAddingPresenceSender> createSender() { - boost::shared_ptr<PayloadAddingPresenceSender> sender(new PayloadAddingPresenceSender(presenceSender)); - return sender; - } + private: + std::shared_ptr<PayloadAddingPresenceSender> createSender() { + std::shared_ptr<PayloadAddingPresenceSender> sender(new PayloadAddingPresenceSender(presenceSender)); + return sender; + } - struct MyPayload : public Payload { - typedef boost::shared_ptr<MyPayload> ref; + struct MyPayload : public Payload { + typedef std::shared_ptr<MyPayload> ref; - MyPayload(const std::string& body) : body(body) {} + MyPayload(const std::string& body) : body(body) {} - static ref create(const std::string& body) { - return ref(new MyPayload(body)); - } + static ref create(const std::string& body) { + return ref(new MyPayload(body)); + } - std::string body; - }; + std::string body; + }; - private: - DummyStanzaChannel* stanzaChannel; - StanzaChannelPresenceSender* presenceSender; + private: + DummyStanzaChannel* stanzaChannel; + StanzaChannelPresenceSender* presenceSender; }; CPPUNIT_TEST_SUITE_REGISTRATION(PayloadAddingPresenceSenderTest); diff --git a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp index 179538e..86a7925 100644 --- a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp +++ b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp @@ -1,196 +1,249 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ +#include <memory> + +#include <boost/bind.hpp> + #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include <boost/bind.hpp> -#include <boost/shared_ptr.hpp> -#include <Swiften/Presence/PresenceOracle.h> #include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Presence/PresenceOracle.h> #include <Swiften/Presence/SubscriptionManager.h> +#include <Swiften/Roster/XMPPRoster.h> +#include <Swiften/Roster/XMPPRosterImpl.h> using namespace Swift; class PresenceOracleTest : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(PresenceOracleTest); - CPPUNIT_TEST(testReceivePresence); - CPPUNIT_TEST(testReceivePresenceFromDifferentResources); - CPPUNIT_TEST(testSubscriptionRequest); - CPPUNIT_TEST(testReconnectResetsPresences); - CPPUNIT_TEST(testHighestPresenceSingle); - CPPUNIT_TEST(testHighestPresenceMultiple); - CPPUNIT_TEST(testHighestPresenceGlobal); - CPPUNIT_TEST(testHighestPresenceChangePriority); - CPPUNIT_TEST_SUITE_END(); - - public: - void setUp() { - stanzaChannel_ = new DummyStanzaChannel(); - oracle_ = new PresenceOracle(stanzaChannel_); - oracle_->onPresenceChange.connect(boost::bind(&PresenceOracleTest::handlePresenceChange, this, _1)); - subscriptionManager_ = new SubscriptionManager(stanzaChannel_); - subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2)); - user1 = JID("user1@foo.com/Foo"); - user1alt = JID("user1@foo.com/Bar"); - user2 = JID("user2@bar.com/Bar"); - } - - void tearDown() { - delete subscriptionManager_; - delete oracle_; - delete stanzaChannel_; - } - - void testHighestPresenceSingle() { - JID bareJID("alice@wonderland.lit"); - Presence::ref fiveOn = makeOnline("blah", 5); - Presence::ref fiveOff = makeOffline("/blah"); - CPPUNIT_ASSERT_EQUAL(Presence::ref(), oracle_->getHighestPriorityPresence(bareJID)); - stanzaChannel_->onPresenceReceived(fiveOn); - CPPUNIT_ASSERT_EQUAL(fiveOn, oracle_->getHighestPriorityPresence(bareJID)); - stanzaChannel_->onPresenceReceived(fiveOff); - CPPUNIT_ASSERT_EQUAL(fiveOff, oracle_->getHighestPriorityPresence(bareJID)); - } - - void testHighestPresenceMultiple() { - JID bareJID("alice@wonderland.lit"); - Presence::ref fiveOn = makeOnline("blah", 5); - Presence::ref fiveOff = makeOffline("/blah"); - Presence::ref tenOn = makeOnline("bert", 10); - Presence::ref tenOff = makeOffline("/bert"); - stanzaChannel_->onPresenceReceived(fiveOn); - stanzaChannel_->onPresenceReceived(tenOn); - CPPUNIT_ASSERT_EQUAL(tenOn, oracle_->getHighestPriorityPresence(bareJID)); - stanzaChannel_->onPresenceReceived(fiveOff); - CPPUNIT_ASSERT_EQUAL(tenOn, oracle_->getHighestPriorityPresence(bareJID)); - stanzaChannel_->onPresenceReceived(fiveOn); - stanzaChannel_->onPresenceReceived(tenOff); - CPPUNIT_ASSERT_EQUAL(fiveOn, oracle_->getHighestPriorityPresence(bareJID)); - } - - void testHighestPresenceGlobal() { - JID bareJID("alice@wonderland.lit"); - Presence::ref fiveOn = makeOnline("blah", 5); - Presence::ref fiveOff = makeOffline("/blah"); - Presence::ref tenOn = makeOnline("bert", 10); - Presence::ref allOff = makeOffline(""); - stanzaChannel_->onPresenceReceived(fiveOn); - stanzaChannel_->onPresenceReceived(tenOn); - stanzaChannel_->onPresenceReceived(allOff); - CPPUNIT_ASSERT_EQUAL(allOff, oracle_->getHighestPriorityPresence(bareJID)); - } - - void testHighestPresenceChangePriority() { - JID bareJID("alice@wonderland.lit"); - Presence::ref fiveOn = makeOnline("blah", 5); - Presence::ref fiveOff = makeOffline("/blah"); - Presence::ref tenOn = makeOnline("bert", 10); - Presence::ref tenOnThree = makeOnline("bert", 3); - Presence::ref tenOff = makeOffline("/bert"); - stanzaChannel_->onPresenceReceived(fiveOn); - stanzaChannel_->onPresenceReceived(tenOn); - stanzaChannel_->onPresenceReceived(tenOnThree); - CPPUNIT_ASSERT_EQUAL(fiveOn, oracle_->getHighestPriorityPresence(bareJID)); - stanzaChannel_->onPresenceReceived(fiveOff); - CPPUNIT_ASSERT_EQUAL(tenOnThree, oracle_->getHighestPriorityPresence(bareJID)); - stanzaChannel_->onPresenceReceived(fiveOn); - CPPUNIT_ASSERT_EQUAL(fiveOn, oracle_->getHighestPriorityPresence(bareJID)); - } - - void testReceivePresence() { - boost::shared_ptr<Presence> sentPresence(createPresence(user1)); - stanzaChannel_->onPresenceReceived(sentPresence); - - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); - CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(subscriptionRequests.size())); - CPPUNIT_ASSERT_EQUAL(sentPresence, changes[0]); - CPPUNIT_ASSERT_EQUAL(sentPresence, oracle_->getLastPresence(user1)); - } - - void testReceivePresenceFromDifferentResources() { - boost::shared_ptr<Presence> sentPresence1(createPresence(user1)); - boost::shared_ptr<Presence> sentPresence2(createPresence(user1alt)); - stanzaChannel_->onPresenceReceived(sentPresence1); - stanzaChannel_->onPresenceReceived(sentPresence2); - - CPPUNIT_ASSERT_EQUAL(sentPresence1, oracle_->getLastPresence(user1)); - CPPUNIT_ASSERT_EQUAL(sentPresence2, oracle_->getLastPresence(user1alt)); - } - - void testSubscriptionRequest() { - std::string reasonText = "Because I want to"; - JID sentJID = JID("me@example.com"); - - boost::shared_ptr<Presence> sentPresence(new Presence()); - sentPresence->setType(Presence::Subscribe); - sentPresence->setFrom(sentJID); - sentPresence->setStatus(reasonText); - stanzaChannel_->onPresenceReceived(sentPresence); - - CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size())); - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(subscriptionRequests.size())); - CPPUNIT_ASSERT_EQUAL(sentJID, subscriptionRequests[0].jid); - CPPUNIT_ASSERT_EQUAL(reasonText, subscriptionRequests[0].reason); - } - - void testReconnectResetsPresences() { - boost::shared_ptr<Presence> sentPresence(createPresence(user1)); - stanzaChannel_->onPresenceReceived(sentPresence); - stanzaChannel_->setAvailable(false); - stanzaChannel_->setAvailable(true); - - CPPUNIT_ASSERT(!oracle_->getLastPresence(user1)); - } - - private: - Presence::ref makeOnline(const std::string& resource, int priority) { - Presence::ref presence(new Presence()); - presence->setPriority(priority); - presence->setFrom(JID("alice@wonderland.lit/" + resource)); - return presence; - } - - Presence::ref makeOffline(const std::string& resource) { - Presence::ref presence(new Presence()); - presence->setFrom(JID("alice@wonderland.lit" + resource)); - presence->setType(Presence::Unavailable); - return presence; - } - - void handlePresenceChange(boost::shared_ptr<Presence> newPresence) { - changes.push_back(newPresence); - } - - void handlePresenceSubscriptionRequest(const JID& jid, const std::string& reason) { - SubscriptionRequestInfo subscriptionRequest; - subscriptionRequest.jid = jid; - subscriptionRequest.reason = reason; - subscriptionRequests.push_back(subscriptionRequest); - } - - boost::shared_ptr<Presence> createPresence(const JID& jid) { - boost::shared_ptr<Presence> sentPresence(new Presence("blarb")); - sentPresence->setFrom(jid); - return sentPresence; - } - - private: - struct SubscriptionRequestInfo { - JID jid; - std::string reason; - }; - PresenceOracle* oracle_; - SubscriptionManager* subscriptionManager_; - DummyStanzaChannel* stanzaChannel_; - std::vector<Presence::ref> changes; - std::vector<SubscriptionRequestInfo> subscriptionRequests; - JID user1; - JID user1alt; - JID user2; + CPPUNIT_TEST_SUITE(PresenceOracleTest); + CPPUNIT_TEST(testReceivePresence); + CPPUNIT_TEST(testReceivePresenceFromDifferentResources); + CPPUNIT_TEST(testSubscriptionRequest); + CPPUNIT_TEST(testReconnectResetsPresences); + CPPUNIT_TEST(testHighestPresenceSingle); + CPPUNIT_TEST(testHighestPresenceMultiple); + CPPUNIT_TEST(testHighestPresenceGlobal); + CPPUNIT_TEST(testHighestPresenceChangePriority); + CPPUNIT_TEST(testGetActivePresence); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + stanzaChannel_ = new DummyStanzaChannel(); + xmppRoster_ = new XMPPRosterImpl(); + + oracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_); + oracle_->onPresenceChange.connect(boost::bind(&PresenceOracleTest::handlePresenceChange, this, _1)); + subscriptionManager_ = new SubscriptionManager(stanzaChannel_); + subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&PresenceOracleTest::handlePresenceSubscriptionRequest, this, _1, _2)); + user1 = JID("user1@foo.com/Foo"); + user1alt = JID("user1@foo.com/Bar"); + user2 = JID("user2@bar.com/Bar"); + } + + void tearDown() { + delete subscriptionManager_; + delete oracle_; + delete xmppRoster_; + delete stanzaChannel_; + } + + void testHighestPresenceSingle() { + JID bareJID("alice@wonderland.lit"); + Presence::ref fiveOn = makeOnline("blah", 5); + Presence::ref fiveOff = makeOffline("/blah"); + CPPUNIT_ASSERT_EQUAL(Presence::ref(), oracle_->getHighestPriorityPresence(bareJID)); + stanzaChannel_->onPresenceReceived(fiveOn); + CPPUNIT_ASSERT_EQUAL(fiveOn, oracle_->getHighestPriorityPresence(bareJID)); + stanzaChannel_->onPresenceReceived(fiveOff); + CPPUNIT_ASSERT_EQUAL(fiveOff, oracle_->getHighestPriorityPresence(bareJID)); + } + + void testHighestPresenceMultiple() { + JID bareJID("alice@wonderland.lit"); + Presence::ref fiveOn = makeOnline("blah", 5); + Presence::ref fiveOff = makeOffline("/blah"); + Presence::ref tenOn = makeOnline("bert", 10); + Presence::ref tenOff = makeOffline("/bert"); + stanzaChannel_->onPresenceReceived(fiveOn); + stanzaChannel_->onPresenceReceived(tenOn); + CPPUNIT_ASSERT_EQUAL(tenOn, oracle_->getHighestPriorityPresence(bareJID)); + stanzaChannel_->onPresenceReceived(fiveOff); + CPPUNIT_ASSERT_EQUAL(tenOn, oracle_->getHighestPriorityPresence(bareJID)); + stanzaChannel_->onPresenceReceived(fiveOn); + stanzaChannel_->onPresenceReceived(tenOff); + CPPUNIT_ASSERT_EQUAL(fiveOn, oracle_->getHighestPriorityPresence(bareJID)); + } + + void testHighestPresenceGlobal() { + JID bareJID("alice@wonderland.lit"); + Presence::ref fiveOn = makeOnline("blah", 5); + Presence::ref fiveOff = makeOffline("/blah"); + Presence::ref tenOn = makeOnline("bert", 10); + Presence::ref allOff = makeOffline(""); + stanzaChannel_->onPresenceReceived(fiveOn); + stanzaChannel_->onPresenceReceived(tenOn); + stanzaChannel_->onPresenceReceived(allOff); + CPPUNIT_ASSERT_EQUAL(allOff, oracle_->getHighestPriorityPresence(bareJID)); + } + + void testHighestPresenceChangePriority() { + JID bareJID("alice@wonderland.lit"); + Presence::ref fiveOn = makeOnline("blah", 5); + Presence::ref fiveOff = makeOffline("/blah"); + Presence::ref tenOn = makeOnline("bert", 10); + Presence::ref tenOnThree = makeOnline("bert", 3); + Presence::ref tenOff = makeOffline("/bert"); + stanzaChannel_->onPresenceReceived(fiveOn); + stanzaChannel_->onPresenceReceived(tenOn); + stanzaChannel_->onPresenceReceived(tenOnThree); + CPPUNIT_ASSERT_EQUAL(fiveOn, oracle_->getHighestPriorityPresence(bareJID)); + stanzaChannel_->onPresenceReceived(fiveOff); + CPPUNIT_ASSERT_EQUAL(tenOnThree, oracle_->getHighestPriorityPresence(bareJID)); + stanzaChannel_->onPresenceReceived(fiveOn); + CPPUNIT_ASSERT_EQUAL(fiveOn, oracle_->getHighestPriorityPresence(bareJID)); + } + + void testReceivePresence() { + std::shared_ptr<Presence> sentPresence(createPresence(user1)); + stanzaChannel_->onPresenceReceived(sentPresence); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(subscriptionRequests.size())); + CPPUNIT_ASSERT_EQUAL(sentPresence, changes[0]); + CPPUNIT_ASSERT_EQUAL(sentPresence, oracle_->getLastPresence(user1)); + } + + void testReceivePresenceFromDifferentResources() { + std::shared_ptr<Presence> sentPresence1(createPresence(user1)); + std::shared_ptr<Presence> sentPresence2(createPresence(user1alt)); + stanzaChannel_->onPresenceReceived(sentPresence1); + stanzaChannel_->onPresenceReceived(sentPresence2); + + CPPUNIT_ASSERT_EQUAL(sentPresence1, oracle_->getLastPresence(user1)); + CPPUNIT_ASSERT_EQUAL(sentPresence2, oracle_->getLastPresence(user1alt)); + } + + void testSubscriptionRequest() { + std::string reasonText = "Because I want to"; + JID sentJID = JID("me@example.com"); + + std::shared_ptr<Presence> sentPresence(new Presence()); + sentPresence->setType(Presence::Subscribe); + sentPresence->setFrom(sentJID); + sentPresence->setStatus(reasonText); + stanzaChannel_->onPresenceReceived(sentPresence); + + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(subscriptionRequests.size())); + CPPUNIT_ASSERT_EQUAL(sentJID, subscriptionRequests[0].jid); + CPPUNIT_ASSERT_EQUAL(reasonText, subscriptionRequests[0].reason); + } + + void testReconnectResetsPresences() { + std::shared_ptr<Presence> sentPresence(createPresence(user1)); + stanzaChannel_->onPresenceReceived(sentPresence); + stanzaChannel_->setAvailable(false); + stanzaChannel_->setAvailable(true); + + CPPUNIT_ASSERT(!oracle_->getLastPresence(user1)); + } + + void testGetActivePresence() { + { + std::vector<Presence::ref> presenceList; + presenceList.push_back(createPresence("alice@wonderland.lit/resourceA", 10, Presence::Available, StatusShow::Away)); + presenceList.push_back(createPresence("alice@wonderland.lit/resourceB", 5, Presence::Available, StatusShow::Online)); + + CPPUNIT_ASSERT_EQUAL(StatusShow::Online, PresenceOracle::getActivePresence(presenceList)->getShow()); + } + + { + std::vector<Presence::ref> presenceList; + presenceList.push_back(createPresence("alice@wonderland.lit/resourceA", 10, Presence::Available, StatusShow::Away)); + presenceList.push_back(createPresence("alice@wonderland.lit/resourceB", 5, Presence::Available, StatusShow::DND)); + + CPPUNIT_ASSERT_EQUAL(StatusShow::DND, PresenceOracle::getActivePresence(presenceList)->getShow()); + } + + { + std::vector<Presence::ref> presenceList; + presenceList.push_back(createPresence("alice@wonderland.lit/resourceA", 0, Presence::Available, StatusShow::Online)); + presenceList.push_back(createPresence("alice@wonderland.lit/resourceB", 0, Presence::Available, StatusShow::DND)); + + CPPUNIT_ASSERT_EQUAL(StatusShow::Online, PresenceOracle::getActivePresence(presenceList)->getShow()); + } + + { + std::vector<Presence::ref> presenceList; + presenceList.push_back(createPresence("alice@wonderland.lit/resourceA", 1, Presence::Available, StatusShow::Online)); + presenceList.push_back(createPresence("alice@wonderland.lit/resourceB", 0, Presence::Available, StatusShow::Online)); + + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/resourceA"), PresenceOracle::getActivePresence(presenceList)->getFrom()); + } + } + + private: + Presence::ref createPresence(const JID &jid, int priority, Presence::Type type, const StatusShow::Type& statusShow) { + Presence::ref presence = std::make_shared<Presence>(); + presence->setFrom(jid); + presence->setPriority(priority); + presence->setType(type); + presence->setShow(statusShow); + return presence; + } + + + Presence::ref makeOnline(const std::string& resource, int priority) { + Presence::ref presence(new Presence()); + presence->setPriority(priority); + presence->setFrom(JID("alice@wonderland.lit/" + resource)); + return presence; + } + + Presence::ref makeOffline(const std::string& resource) { + Presence::ref presence(new Presence()); + presence->setFrom(JID("alice@wonderland.lit" + resource)); + presence->setType(Presence::Unavailable); + return presence; + } + + void handlePresenceChange(std::shared_ptr<Presence> newPresence) { + changes.push_back(newPresence); + } + + void handlePresenceSubscriptionRequest(const JID& jid, const std::string& reason) { + SubscriptionRequestInfo subscriptionRequest; + subscriptionRequest.jid = jid; + subscriptionRequest.reason = reason; + subscriptionRequests.push_back(subscriptionRequest); + } + + std::shared_ptr<Presence> createPresence(const JID& jid) { + std::shared_ptr<Presence> sentPresence(new Presence("blarb")); + sentPresence->setFrom(jid); + return sentPresence; + } + + private: + struct SubscriptionRequestInfo { + JID jid; + std::string reason; + }; + PresenceOracle* oracle_; + SubscriptionManager* subscriptionManager_; + DummyStanzaChannel* stanzaChannel_; + XMPPRoster* xmppRoster_; + std::vector<Presence::ref> changes; + std::vector<SubscriptionRequestInfo> subscriptionRequests; + JID user1; + JID user1alt; + JID user2; }; CPPUNIT_TEST_SUITE_REGISTRATION(PresenceOracleTest); |