diff options
author | Remko Tronçon <git@el-tramo.be> | 2011-04-08 21:58:03 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2011-04-18 19:11:40 (GMT) |
commit | 01385d84f07466550fff702079555c65963463a8 (patch) | |
tree | d995334b205737b2402a8f5778642342b9b3ab02 /Swiften/Roster | |
parent | 1a92834490cda1352a46eaef02a4e7ff76ab94e3 (diff) | |
download | swift-contrib-01385d84f07466550fff702079555c65963463a8.zip swift-contrib-01385d84f07466550fff702079555c65963463a8.tar.bz2 |
Added XEP-0237 Roster Versioning support.
Resolves: #803
Release-Notes: Added support for XEP-0237 Roster Versioning
Diffstat (limited to 'Swiften/Roster')
-rw-r--r-- | Swiften/Roster/GetRosterRequest.h | 6 | ||||
-rw-r--r-- | Swiften/Roster/RosterFileStorage.cpp | 24 | ||||
-rw-r--r-- | Swiften/Roster/RosterFileStorage.h | 29 | ||||
-rw-r--r-- | Swiften/Roster/RosterMemoryStorage.cpp | 23 | ||||
-rw-r--r-- | Swiften/Roster/RosterMemoryStorage.h | 25 | ||||
-rw-r--r-- | Swiften/Roster/RosterStorage.cpp | 14 | ||||
-rw-r--r-- | Swiften/Roster/RosterStorage.h | 21 | ||||
-rw-r--r-- | Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp | 173 | ||||
-rw-r--r-- | Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp | 3 | ||||
-rw-r--r-- | Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h | 8 | ||||
-rw-r--r-- | Swiften/Roster/XMPPRosterController.cpp | 47 | ||||
-rw-r--r-- | Swiften/Roster/XMPPRosterController.h | 12 |
12 files changed, 370 insertions, 15 deletions
diff --git a/Swiften/Roster/GetRosterRequest.h b/Swiften/Roster/GetRosterRequest.h index 00cf77f..a3486f0 100644 --- a/Swiften/Roster/GetRosterRequest.h +++ b/Swiften/Roster/GetRosterRequest.h @@ -19,6 +19,12 @@ namespace Swift { return ref(new GetRosterRequest(router)); } + static ref create(IQRouter* router, const std::string& version) { + ref result(new GetRosterRequest(router)); + result->getPayloadGeneric()->setVersion(version); + return result; + } + private: GetRosterRequest(IQRouter* router) : GenericRequest<RosterPayload>(IQ::Get, JID(), boost::shared_ptr<Payload>(new RosterPayload()), router) { diff --git a/Swiften/Roster/RosterFileStorage.cpp b/Swiften/Roster/RosterFileStorage.cpp new file mode 100644 index 0000000..de7b442 --- /dev/null +++ b/Swiften/Roster/RosterFileStorage.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Roster/RosterFileStorage.h> + +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + +RosterFileStorage::RosterFileStorage(const boost::filesystem::path& path) : path(path) { +} + +// FIXME +void RosterFileStorage::setRoster(boost::shared_ptr<RosterPayload> r) { + roster.reset(); + if (r) { + roster = boost::make_shared<RosterPayload>(*r); + } +} + +} diff --git a/Swiften/Roster/RosterFileStorage.h b/Swiften/Roster/RosterFileStorage.h new file mode 100644 index 0000000..dc91c27 --- /dev/null +++ b/Swiften/Roster/RosterFileStorage.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/filesystem/path.hpp> + +#include <Swiften/Roster/RosterStorage.h> + +namespace Swift { + class RosterFileStorage : public RosterStorage { + public: + RosterFileStorage(const boost::filesystem::path& path); + + // FIXME + virtual boost::shared_ptr<RosterPayload> getRoster() const { + return roster; + } + + virtual void setRoster(boost::shared_ptr<RosterPayload>); + + private: + boost::filesystem::path path; + boost::shared_ptr<RosterPayload> roster; + }; +} diff --git a/Swiften/Roster/RosterMemoryStorage.cpp b/Swiften/Roster/RosterMemoryStorage.cpp new file mode 100644 index 0000000..cbf4563 --- /dev/null +++ b/Swiften/Roster/RosterMemoryStorage.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Roster/RosterMemoryStorage.h> + +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + +RosterMemoryStorage::RosterMemoryStorage() { +} + +void RosterMemoryStorage::setRoster(boost::shared_ptr<RosterPayload> r) { + roster.reset(); + if (r) { + roster = boost::make_shared<RosterPayload>(*r); + } +} + +} diff --git a/Swiften/Roster/RosterMemoryStorage.h b/Swiften/Roster/RosterMemoryStorage.h new file mode 100644 index 0000000..b659d77 --- /dev/null +++ b/Swiften/Roster/RosterMemoryStorage.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Roster/RosterStorage.h> + +namespace Swift { + class RosterMemoryStorage : public RosterStorage { + public: + RosterMemoryStorage(); + + virtual boost::shared_ptr<RosterPayload> getRoster() const { + return roster; + } + + virtual void setRoster(boost::shared_ptr<RosterPayload>); + + private: + boost::shared_ptr<RosterPayload> roster; + }; +} diff --git a/Swiften/Roster/RosterStorage.cpp b/Swiften/Roster/RosterStorage.cpp new file mode 100644 index 0000000..6bf58de --- /dev/null +++ b/Swiften/Roster/RosterStorage.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Roster/RosterStorage.h> + +namespace Swift { + +RosterStorage::~RosterStorage() { +} + +} diff --git a/Swiften/Roster/RosterStorage.h b/Swiften/Roster/RosterStorage.h new file mode 100644 index 0000000..ba24cb3 --- /dev/null +++ b/Swiften/Roster/RosterStorage.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/RosterPayload.h> + +namespace Swift { + class RosterStorage { + public: + virtual ~RosterStorage(); + + virtual boost::shared_ptr<RosterPayload> getRoster() const = 0; + virtual void setRoster(boost::shared_ptr<RosterPayload>) = 0; + }; +} diff --git a/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp b/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp index 4ef1cc1..4c98673 100644 --- a/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp +++ b/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp @@ -16,15 +16,24 @@ #include "Swiften/Client/DummyStanzaChannel.h" #include "Swiften/Queries/IQRouter.h" #include "Swiften/Roster/XMPPRosterImpl.h" +#include <Swiften/Roster/RosterMemoryStorage.h> using namespace Swift; class XMPPRosterControllerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(XMPPRosterControllerTest); + CPPUNIT_TEST(testGet_Response); CPPUNIT_TEST(testGet_EmptyResponse); + CPPUNIT_TEST(testGet_NoRosterInStorage); + CPPUNIT_TEST(testGet_NoVersionInStorage); + CPPUNIT_TEST(testGet_VersionInStorage); + CPPUNIT_TEST(testGet_ServerDoesNotSupportVersion); + CPPUNIT_TEST(testGet_ResponseWithoutNewVersion); + CPPUNIT_TEST(testGet_ResponseWithNewVersion); CPPUNIT_TEST(testAdd); CPPUNIT_TEST(testModify); CPPUNIT_TEST(testRemove); + CPPUNIT_TEST(testRemove_RosterStorageUpdated); CPPUNIT_TEST(testMany); CPPUNIT_TEST_SUITE_END(); @@ -34,20 +43,36 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { router_ = new IQRouter(channel_); xmppRoster_ = new XMPPRosterImpl(); handler_ = new XMPPRosterSignalHandler(xmppRoster_); + rosterStorage_ = new RosterMemoryStorage(); jid1_ = JID("foo@bar.com"); jid2_ = JID("alice@wonderland.lit"); jid3_ = JID("jane@austen.lit"); } void tearDown() { + delete rosterStorage_; delete handler_; delete xmppRoster_; delete router_; delete channel_; } + void testGet_Response() { + std::auto_ptr<XMPPRosterController> testling(createController()); + + testling->requestRoster(); + boost::shared_ptr<RosterPayload> payload = boost::make_shared<RosterPayload>(); + payload->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + payload->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), payload)); + + CPPUNIT_ASSERT_EQUAL(2, handler_->getEventCount()); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid1_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid2_)); + } + void testGet_EmptyResponse() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); controller.requestRoster(); @@ -55,7 +80,7 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { } void testAdd() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload(new RosterPayload()); payload->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); @@ -68,8 +93,115 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("Bob"), xmppRoster_->getNameForJID(jid1_)); } + void testGet_NoRosterInStorage() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(roster->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string(""), *roster->getVersion()); + } + + void testGet_NoVersionInStorage() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + rosterStorage_->setRoster(boost::make_shared<RosterPayload>()); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(roster->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string(""), *roster->getVersion()); + } + + void testGet_VersionInStorage() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> payload(new RosterPayload()); + payload->setVersion("foover"); + rosterStorage_->setRoster(payload); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(roster->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("foover"), *roster->getVersion()); + } + + void testGet_ServerDoesNotSupportVersion() { + std::auto_ptr<XMPPRosterController> testling(createController()); + boost::shared_ptr<RosterPayload> payload(new RosterPayload()); + payload->setVersion("foover"); + rosterStorage_->setRoster(payload); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(!roster->getVersion()); + } + + void testGet_ResponseWithoutNewVersion() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> storedRoster(new RosterPayload()); + storedRoster->setVersion("version10"); + storedRoster->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + storedRoster->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + rosterStorage_->setRoster(storedRoster); + testling->requestRoster(); + + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), boost::shared_ptr<RosterPayload>())); + + CPPUNIT_ASSERT_EQUAL(2, handler_->getEventCount()); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid1_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid2_)); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid2_, handler_->getLastJID()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("version10"), *rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid1_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid2_)); + } + + void testGet_ResponseWithNewVersion() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> storedRoster(new RosterPayload()); + storedRoster->setVersion("version10"); + storedRoster->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + rosterStorage_->setRoster(storedRoster); + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> serverRoster(new RosterPayload()); + serverRoster->setVersion("version12"); + serverRoster->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + std::vector<std::string> groups; + groups.push_back("foo"); + groups.push_back("bar"); + serverRoster->addItem(RosterItemPayload(jid3_, "Rabbit", RosterItemPayload::Both, groups)); + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), serverRoster)); + + + CPPUNIT_ASSERT_EQUAL(2, handler_->getEventCount()); + CPPUNIT_ASSERT(!xmppRoster_->getItem(jid1_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid2_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid3_)); + CPPUNIT_ASSERT_EQUAL(jid3_, handler_->getLastJID()); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("version12"), *rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT(!rosterStorage_->getRoster()->getItem(jid1_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid2_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid3_)); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(rosterStorage_->getRoster()->getItem(jid3_)->getGroups().size())); + } + void testModify() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload1(new RosterPayload()); payload1->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id1", payload1)); @@ -87,9 +219,9 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("Bob2"), xmppRoster_->getNameForJID(jid1_)); } - + void testRemove() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload1(new RosterPayload()); payload1->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id1", payload1)); @@ -107,8 +239,31 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { } + void testRemove_RosterStorageUpdated() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> storedRoster(new RosterPayload()); + storedRoster->setVersion("version10"); + storedRoster->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + storedRoster->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + rosterStorage_->setRoster(storedRoster); + testling->requestRoster(); + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), boost::shared_ptr<RosterPayload>())); + + boost::shared_ptr<RosterPayload> payload2(new RosterPayload()); + payload2->setVersion("version15"); + payload2->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Remove)); + channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id2", payload2)); + + CPPUNIT_ASSERT(rosterStorage_->getRoster()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("version15"), *rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT(!rosterStorage_->getRoster()->getItem(jid1_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid2_)); + } + void testMany() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload1(new RosterPayload()); payload1->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id1", payload1)); @@ -171,12 +326,18 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { handler_->reset(); } + + private: + XMPPRosterController* createController() { + return new XMPPRosterController(router_, xmppRoster_, rosterStorage_); + } private: DummyStanzaChannel* channel_; IQRouter* router_; XMPPRosterImpl* xmppRoster_; XMPPRosterSignalHandler* handler_; + RosterMemoryStorage* rosterStorage_; JID jid1_; JID jid2_; JID jid3_; diff --git a/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp index 983bc22..d89644a 100644 --- a/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp +++ b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp @@ -11,7 +11,7 @@ using namespace Swift; -XMPPRosterSignalHandler::XMPPRosterSignalHandler(Swift::XMPPRoster* roster) { +XMPPRosterSignalHandler::XMPPRosterSignalHandler(Swift::XMPPRoster* roster) : eventCount(0) { lastEvent_ = None; roster->onJIDAdded.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDAdded, this, _1)); roster->onJIDRemoved.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDRemoved, this, _1)); @@ -24,4 +24,5 @@ void XMPPRosterSignalHandler::handleJIDUpdated(const Swift::JID& jid, const std: lastOldName_ = oldName; lastOldGroups_ = oldGroups; lastEvent_ = Update; + eventCount++; } diff --git a/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h index c59b4c6..2cf1159 100644 --- a/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h +++ b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h @@ -37,15 +37,21 @@ public: lastEvent_ = None; } + int getEventCount() const { + return eventCount; + } + private: void handleJIDAdded(const Swift::JID& jid) { lastJID_ = jid; lastEvent_ = Add; + eventCount++; } void handleJIDRemoved(const Swift::JID& jid) { lastJID_ = jid; lastEvent_ = Remove; + eventCount++; } void handleJIDUpdated(const Swift::JID& jid, const std::string& oldName, const std::vector<std::string>& oldGroups); @@ -54,5 +60,5 @@ private: Swift::JID lastJID_; std::string lastOldName_; std::vector<std::string> lastOldGroups_; - + int eventCount; }; diff --git a/Swiften/Roster/XMPPRosterController.cpp b/Swiften/Roster/XMPPRosterController.cpp index a294d35..baa74ff 100644 --- a/Swiften/Roster/XMPPRosterController.cpp +++ b/Swiften/Roster/XMPPRosterController.cpp @@ -13,14 +13,15 @@ #include "Swiften/Queries/IQRouter.h" #include "Swiften/Roster/GetRosterRequest.h" #include "Swiften/Roster/XMPPRosterImpl.h" +#include <Swiften/Roster/RosterStorage.h> namespace Swift { /** * The controller does not gain ownership of these parameters. */ -XMPPRosterController::XMPPRosterController(IQRouter* iqRouter, XMPPRosterImpl* xmppRoster) : iqRouter_(iqRouter), rosterPushResponder_(iqRouter), xmppRoster_(xmppRoster) { - rosterPushResponder_.onRosterReceived.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, false)); +XMPPRosterController::XMPPRosterController(IQRouter* iqRouter, XMPPRosterImpl* xmppRoster, RosterStorage* rosterStorage) : iqRouter_(iqRouter), rosterPushResponder_(iqRouter), xmppRoster_(xmppRoster), rosterStorage_(rosterStorage), useVersioning(false) { + rosterPushResponder_.onRosterReceived.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, false, boost::shared_ptr<RosterPayload>())); rosterPushResponder_.start(); } @@ -30,12 +31,24 @@ XMPPRosterController::~XMPPRosterController() { void XMPPRosterController::requestRoster() { xmppRoster_->clear(); - GetRosterRequest::ref rosterRequest = GetRosterRequest::create(iqRouter_); - rosterRequest->onResponse.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, true)); + + boost::shared_ptr<RosterPayload> storedRoster = rosterStorage_->getRoster(); + GetRosterRequest::ref rosterRequest; + if (useVersioning) { + std::string version = ""; + if (storedRoster && storedRoster->getVersion()) { + version = *storedRoster->getVersion(); + } + rosterRequest = GetRosterRequest::create(iqRouter_, version); + } + else { + rosterRequest = GetRosterRequest::create(iqRouter_); + } + rosterRequest->onResponse.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, true, storedRoster)); rosterRequest->send(); } -void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial) { +void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial, boost::shared_ptr<RosterPayload> previousRoster) { if (rosterPayload) { foreach(const RosterItemPayload& item, rosterPayload->getItems()) { //Don't worry about the updated case, the XMPPRoster sorts that out. @@ -46,9 +59,33 @@ void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> } } } + else if (previousRoster) { + // The cached version hasn't changed; emit all items + foreach(const RosterItemPayload& item, previousRoster->getItems()) { + if (item.getSubscription() != RosterItemPayload::Remove) { + xmppRoster_->addContact(item.getJID(), item.getName(), item.getGroups(), item.getSubscription()); + } + else { + std::cerr << "ERROR: Stored invalid roster item" << std::endl; + } + } + } if (initial) { xmppRoster_->onInitialRosterPopulated(); } + if (rosterPayload && rosterPayload->getVersion() && useVersioning) { + saveRoster(*rosterPayload->getVersion()); + } +} + +void XMPPRosterController::saveRoster(const std::string& version) { + std::vector<XMPPRosterItem> items = xmppRoster_->getItems(); + boost::shared_ptr<RosterPayload> roster(new RosterPayload()); + roster->setVersion(version); + foreach(const XMPPRosterItem& item, items) { + roster->addItem(RosterItemPayload(item.getJID(), item.getName(), item.getSubscription(), item.getGroups())); + } + rosterStorage_->setRoster(roster); } } diff --git a/Swiften/Roster/XMPPRosterController.h b/Swiften/Roster/XMPPRosterController.h index eeb84f6..9313bb6 100644 --- a/Swiften/Roster/XMPPRosterController.h +++ b/Swiften/Roster/XMPPRosterController.h @@ -18,21 +18,29 @@ namespace Swift { class IQRouter; class XMPPRosterImpl; + class RosterStorage; class XMPPRosterController { public: - XMPPRosterController(IQRouter *iqRouter, XMPPRosterImpl* xmppRoster); + XMPPRosterController(IQRouter *iqRouter, XMPPRosterImpl* xmppRoster, RosterStorage* storage); ~XMPPRosterController(); void requestRoster(); + void setUseVersioning(bool b) { + useVersioning = b; + } + private: - void handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial); + void handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial, boost::shared_ptr<RosterPayload> previousRoster); + void saveRoster(const std::string& version); private: IQRouter* iqRouter_; RosterPushResponder rosterPushResponder_; XMPPRosterImpl* xmppRoster_; + RosterStorage* rosterStorage_; + bool useVersioning; }; } |