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 /Swiften | |
| 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
Diffstat (limited to 'Swiften')
| -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 |
4 files changed, 181 insertions, 16 deletions
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 @@ -10,22 +10,21 @@ * See the COPYING file for more information. */ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> -#include <Swiften/Elements/JinglePayload.h> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> +#include <Swiften/Elements/JingleFileTransferHash.h> #include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JinglePayload.h> #include <Swiften/Elements/JingleS5BTransportPayload.h> -#include <Swiften/Elements/JingleFileTransferDescription.h> #include <Swiften/Elements/StreamInitiationFileInfo.h> -#include <Swiften/Elements/JingleFileTransferHash.h> -#include <Swiften/Base/DateTime.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> #include <Swiften/StringCodecs/Base64.h> -#include <Swiften/Base/Log.h> using namespace Swift; class JingleParserTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(JingleParserTest); CPPUNIT_TEST(testParse_Xep0166_Example3); @@ -410,13 +409,12 @@ class JingleParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(hash); CPPUNIT_ASSERT_EQUAL(std::string("VS2nSZMIUsaa5dIUHTdmsQ=="), Base64::encode(hash->getFileInfo().getHash("sha-1").get())); } // http://xmpp.org/extensions/xep-0234.html#example-10 void testParse_Xep0234_Example10() { - Log::setLogLevel(Log::debug); PayloadsParserTester parser; CPPUNIT_ASSERT(parser.parse( "<jingle xmlns='urn:xmpp:jingle:1'\n" " action='session-initiate'\n" " initiator='romeo@montague.lit/orchard'\n" " sid='uj3b2'>\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 @@ -3,15 +3,19 @@ * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/Presence/PresenceOracle.h> +#include <queue> + #include <boost/bind.hpp> +#include <Swiften/Base/foreach.h> #include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Elements/StatusShow.h> #include <Swiften/Roster/XMPPRoster.h> namespace Swift { PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel, XMPPRoster* roster) : stanzaChannel_(stanzaChannel), xmppRoster_(roster) { stanzaChannel_->onPresenceReceived.connect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1)); @@ -103,12 +107,97 @@ std::vector<Presence::ref> PresenceOracle::getAllPresence(const JID& bareJID) co Presence::ref current = j->second; results.push_back(current); } 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; + + foreach(Presence::ref 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; 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 @@ -14,21 +14,54 @@ #include <Swiften/Elements/Presence.h> namespace Swift { 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::signal<void (Presence::ref)> onPresenceChange; private: void handleIncomingPresence(Presence::ref presence); void handleStanzaChannelAvailableChanged(bool); 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 @@ -25,12 +25,13 @@ class PresenceOracleTest : public CppUnit::TestFixture { 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(); @@ -49,21 +50,21 @@ class PresenceOracleTest : public CppUnit::TestFixture { 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)); - } + 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); @@ -148,14 +149,58 @@ class PresenceOracleTest : public CppUnit::TestFixture { 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 = boost::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; } |
Swift