summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2010-08-22 08:55:08 (GMT)
committerRemko Tronçon <git@el-tramo.be>2010-08-24 17:10:23 (GMT)
commitb6a34463dfcedd454ab42230a47cdb7294a76f21 (patch)
tree832b0243325451932c0d15e9e33d53948fce0110 /Swiften/VCards
parent6e4b357141a6d09632f1e96d0eaf54f79daf52c9 (diff)
downloadswift-b6a34463dfcedd454ab42230a47cdb7294a76f21.zip
swift-b6a34463dfcedd454ab42230a47cdb7294a76f21.tar.bz2
Implemented VCardManager.
Diffstat (limited to 'Swiften/VCards')
-rw-r--r--Swiften/VCards/SConscript1
-rw-r--r--Swiften/VCards/UnitTest/VCardManagerTest.cpp159
-rw-r--r--Swiften/VCards/VCardFileStorage.cpp4
-rw-r--r--Swiften/VCards/VCardFileStorage.h4
-rw-r--r--Swiften/VCards/VCardFileStorageFactory.h2
-rw-r--r--Swiften/VCards/VCardManager.cpp42
-rw-r--r--Swiften/VCards/VCardManager.h23
-rw-r--r--Swiften/VCards/VCardMemoryStorage.h38
-rw-r--r--Swiften/VCards/VCardStorage.h4
9 files changed, 263 insertions, 14 deletions
diff --git a/Swiften/VCards/SConscript b/Swiften/VCards/SConscript
index 538eb4a..e83e633 100644
--- a/Swiften/VCards/SConscript
+++ b/Swiften/VCards/SConscript
@@ -1,6 +1,7 @@
Import("swiften_env")
objects = swiften_env.StaticObject([
+ "VCardManager.cpp",
"VCardStorage.cpp",
"VCardFileStorage.cpp",
"VCardStorageFactory.cpp",
diff --git a/Swiften/VCards/UnitTest/VCardManagerTest.cpp b/Swiften/VCards/UnitTest/VCardManagerTest.cpp
new file mode 100644
index 0000000..927bcfe
--- /dev/null
+++ b/Swiften/VCards/UnitTest/VCardManagerTest.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <vector>
+#include <boost/bind.hpp>
+
+#include "Swiften/VCards/VCardManager.h"
+#include "Swiften/VCards/VCardMemoryStorage.h"
+#include "Swiften/Queries/IQRouter.h"
+#include "Swiften/Client/DummyStanzaChannel.h"
+
+using namespace Swift;
+
+class VCardManagerTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(VCardManagerTest);
+ CPPUNIT_TEST(testGet_NewVCardRequestsVCard);
+ CPPUNIT_TEST(testGet_ExistingVCard);
+ CPPUNIT_TEST(testRequest_RequestsVCard);
+ CPPUNIT_TEST(testRequest_ReceiveEmitsNotification);
+ CPPUNIT_TEST(testRequest_Error);
+ CPPUNIT_TEST(testRequest_VCardAlreadyRequested);
+ CPPUNIT_TEST(testRequest_AfterPreviousRequest);
+ CPPUNIT_TEST(testRequestOwnVCard);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ ownJID = JID("baz@fum.com/dum");
+ stanzaChannel = new DummyStanzaChannel();
+ iqRouter = new IQRouter(stanzaChannel);
+ vcardStorage = new VCardMemoryStorage();
+ }
+
+ void tearDown() {
+ delete vcardStorage;
+ delete iqRouter;
+ delete stanzaChannel;
+ }
+
+ void testGet_NewVCardRequestsVCard() {
+ std::auto_ptr<VCardManager> testling = createManager();
+ VCard::ref result = testling->getVCardAndRequestWhenNeeded(JID("foo@bar.com/baz"));
+
+ CPPUNIT_ASSERT(!result);
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(0, JID("foo@bar.com/baz"), IQ::Get));
+ }
+
+ void testGet_ExistingVCard() {
+ std::auto_ptr<VCardManager> testling = createManager();
+ VCard::ref vcard(new VCard());
+ vcard->setFullName("Foo Bar");
+ vcardStorage->setVCard(JID("foo@bar.com/baz"), vcard);
+
+ VCard::ref result = testling->getVCardAndRequestWhenNeeded(JID("foo@bar.com/baz"));
+
+ CPPUNIT_ASSERT_EQUAL(String("Foo Bar"), result->getFullName());
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ }
+
+ void testRequest_RequestsVCard() {
+ std::auto_ptr<VCardManager> testling = createManager();
+ testling->requestVCard(JID("foo@bar.com/baz"));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(0, JID("foo@bar.com/baz"), IQ::Get));
+ }
+
+ void testRequest_ReceiveEmitsNotification() {
+ std::auto_ptr<VCardManager> testling = createManager();
+ testling->requestVCard(JID("foo@bar.com/baz"));
+ stanzaChannel->onIQReceived(createVCardResult());
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
+ CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/baz"), changes[0].first);
+ CPPUNIT_ASSERT_EQUAL(String("Foo Bar"), changes[0].second->getFullName());
+ CPPUNIT_ASSERT_EQUAL(String("Foo Bar"), vcardStorage->getVCard(JID("foo@bar.com/baz"))->getFullName());
+ }
+
+ void testRequest_Error() {
+ std::auto_ptr<VCardManager> testling = createManager();
+ testling->requestVCard(JID("foo@bar.com/baz"));
+ stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getID()));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
+ CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/baz"), changes[0].first);
+ CPPUNIT_ASSERT_EQUAL(String(""), changes[0].second->getFullName());
+ CPPUNIT_ASSERT_EQUAL(String(""), vcardStorage->getVCard(JID("foo@bar.com/baz"))->getFullName());
+ }
+
+ void testRequest_VCardAlreadyRequested() {
+ std::auto_ptr<VCardManager> testling = createManager();
+ testling->requestVCard(JID("foo@bar.com/baz"));
+ VCard::ref result = testling->getVCardAndRequestWhenNeeded(JID("foo@bar.com/baz"));
+
+ CPPUNIT_ASSERT(!result);
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ }
+
+ void testRequest_AfterPreviousRequest() {
+ std::auto_ptr<VCardManager> testling = createManager();
+ testling->requestVCard(JID("foo@bar.com/baz"));
+ stanzaChannel->onIQReceived(createVCardResult());
+ testling->requestVCard(JID("foo@bar.com/baz"));
+
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(1, JID("foo@bar.com/baz"), IQ::Get));
+ }
+
+ void testRequestOwnVCard() {
+ std::auto_ptr<VCardManager> testling = createManager();
+ testling->requestVCard(ownJID);
+ stanzaChannel->onIQReceived(createOwnVCardResult());
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size()));
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<VCard>(0, JID(), IQ::Get));
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size()));
+ CPPUNIT_ASSERT_EQUAL(ownJID.toBare(), changes[0].first);
+ CPPUNIT_ASSERT_EQUAL(String("Myself"), changes[0].second->getFullName());
+ CPPUNIT_ASSERT_EQUAL(String("Myself"), vcardStorage->getVCard(ownJID.toBare())->getFullName());
+ }
+
+ private:
+ std::auto_ptr<VCardManager> createManager() {
+ std::auto_ptr<VCardManager> manager(new VCardManager(ownJID, iqRouter, vcardStorage));
+ manager->onVCardChanged.connect(boost::bind(&VCardManagerTest::handleVCardChanged, this, _1, _2));
+ return manager;
+ }
+
+ void handleVCardChanged(const JID& jid, VCard::ref vcard) {
+ changes.push_back(std::pair<JID, VCard::ref>(jid, vcard));
+ }
+
+ IQ::ref createVCardResult() {
+ VCard::ref vcard(new VCard());
+ vcard->setFullName("Foo Bar");
+ return IQ::createResult(JID("baz@fum.com/dum"), stanzaChannel->sentStanzas[0]->getID(), vcard);
+ }
+
+ IQ::ref createOwnVCardResult() {
+ VCard::ref vcard(new VCard());
+ vcard->setFullName("Myself");
+ return IQ::createResult(JID(), stanzaChannel->sentStanzas[0]->getID(), vcard);
+ }
+
+ private:
+ JID ownJID;
+ DummyStanzaChannel* stanzaChannel;
+ IQRouter* iqRouter;
+ VCardMemoryStorage* vcardStorage;
+ std::vector< std::pair<JID, VCard::ref> > changes;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(VCardManagerTest);
diff --git a/Swiften/VCards/VCardFileStorage.cpp b/Swiften/VCards/VCardFileStorage.cpp
index d3163fb..66bae04 100644
--- a/Swiften/VCards/VCardFileStorage.cpp
+++ b/Swiften/VCards/VCardFileStorage.cpp
@@ -47,7 +47,9 @@ void VCardFileStorage::setVCard(const JID& jid, boost::shared_ptr<VCard> v) {
}
boost::filesystem::path VCardFileStorage::getVCardPath(const JID& jid) const {
- return boost::filesystem::path(vcardsPath / (jid.toBare().toString().getUTF8String() + ".xml"));
+ String file(jid.toString());
+ file.replaceAll('/', "%2f");
+ return boost::filesystem::path(vcardsPath / (file.getUTF8String() + ".xml"));
}
}
diff --git a/Swiften/VCards/VCardFileStorage.h b/Swiften/VCards/VCardFileStorage.h
index d75ac92..5f8cb1a 100644
--- a/Swiften/VCards/VCardFileStorage.h
+++ b/Swiften/VCards/VCardFileStorage.h
@@ -16,8 +16,8 @@ namespace Swift {
public:
VCardFileStorage(boost::filesystem::path dir);
- virtual boost::shared_ptr<VCard> getVCard(const JID& jid) const;
- virtual void setVCard(const JID& jid, boost::shared_ptr<VCard> v);
+ virtual VCard::ref getVCard(const JID& jid) const;
+ virtual void setVCard(const JID& jid, VCard::ref v);
private:
boost::filesystem::path getVCardPath(const JID&) const;
diff --git a/Swiften/VCards/VCardFileStorageFactory.h b/Swiften/VCards/VCardFileStorageFactory.h
index 136c6a7..27e50af 100644
--- a/Swiften/VCards/VCardFileStorageFactory.h
+++ b/Swiften/VCards/VCardFileStorageFactory.h
@@ -18,7 +18,7 @@ namespace Swift {
}
virtual VCardStorage* createVCardStorage(const String& profile) {
- return new VCardFileStorage(base / profile.getUTF8String());
+ return new VCardFileStorage(base / profile.getUTF8String() / "vcards");
}
private:
diff --git a/Swiften/VCards/VCardManager.cpp b/Swiften/VCards/VCardManager.cpp
index 0174dea..628f4c8 100644
--- a/Swiften/VCards/VCardManager.cpp
+++ b/Swiften/VCards/VCardManager.cpp
@@ -6,17 +6,49 @@
#include "Swiften/VCards/VCardManager.h"
+#include <boost/bind.hpp>
+
+#include "Swiften/JID/JID.h"
+#include "Swiften/VCards/VCardStorage.h"
+#include "Swiften/Queries/Requests/GetVCardRequest.h"
+
namespace Swift {
-VCardManager::VCardManager(IQRouter* iqRouter, VCardStorage* vcardStorage) : iqRouter(iqRouter), storage(vcardStorage) {
+VCardManager::VCardManager(const JID& ownJID, IQRouter* iqRouter, VCardStorage* vcardStorage) : ownJID(ownJID), iqRouter(iqRouter), storage(vcardStorage) {
}
-boost::shared_ptr<VCard> VCardManager::getVCardAndRequestWhenNeeded(const JID& jid) const {
- boost::shared_ptr<VCard> vcard = storage->getVCard(jid);
+VCard::ref VCardManager::getVCardAndRequestWhenNeeded(const JID& jid) {
+ VCard::ref vcard = storage->getVCard(jid);
if (!vcard) {
- // TODO: Request vcard if necessary
+ requestVCard(jid);
}
return vcard;
}
-
+
+void VCardManager::requestVCard(const JID& requestedJID) {
+ JID jid = requestedJID.equals(ownJID, JID::WithoutResource) ? JID() : requestedJID;
+ if (requestedVCards.find(jid) != requestedVCards.end()) {
+ return;
+ }
+ GetVCardRequest::ref request(new GetVCardRequest(jid, iqRouter));
+ request->onResponse.connect(boost::bind(&VCardManager::handleVCardReceived, this, jid, _1, _2));
+ request->send();
+ requestedVCards.insert(jid);
+}
+
+void VCardManager::requestOwnVCard() {
+ requestVCard(JID());
+}
+
+
+void VCardManager::handleVCardReceived(const JID& actualJID, VCard::ref vcard, const boost::optional<ErrorPayload>& error) {
+ if (error) {
+ vcard = VCard::ref(new VCard());
+ }
+ requestedVCards.erase(actualJID);
+ JID jid = actualJID.isValid() ? actualJID : ownJID.toBare();
+ storage->setVCard(jid, vcard);
+ onVCardChanged(jid, vcard);
+}
+
}
diff --git a/Swiften/VCards/VCardManager.h b/Swiften/VCards/VCardManager.h
index bbf07c0..fc99128 100644
--- a/Swiften/VCards/VCardManager.h
+++ b/Swiften/VCards/VCardManager.h
@@ -6,23 +6,40 @@
#pragma once
+#include <boost/signals.hpp>
+#include <set>
+
+#include "Swiften/JID/JID.h"
#include "Swiften/Elements/VCard.h"
+#include "Swiften/Elements/ErrorPayload.h"
namespace Swift {
class JID;
class VCardStorage;
+ class IQRouter;
class VCardManager {
public:
- VCardManager(IQRouter* iqRouter, VCardStorage* vcardStorage);
+ VCardManager(const JID& ownJID, IQRouter* iqRouter, VCardStorage* vcardStorage);
- virtual boost::shared_ptr<VCard> getVCardAndRequestWhenNeeded(const JID& jid) const ;
+ VCard::ref getVCardAndRequestWhenNeeded(const JID& jid);
+ void requestVCard(const JID& jid);
+ void requestOwnVCard();
public:
- boost::signal<void (const JID&)> onVCardChanged;
+ /**
+ * The JID will always be bare.
+ */
+ boost::signal<void (const JID&, VCard::ref)> onVCardChanged;
+ boost::signal<void (VCard::ref)> onOwnVCardChanged;
+
+ private:
+ void handleVCardReceived(const JID& from, VCard::ref, const boost::optional<ErrorPayload>&);
private:
+ JID ownJID;
IQRouter* iqRouter;
VCardStorage* storage;
+ std::set<JID> requestedVCards;
};
}
diff --git a/Swiften/VCards/VCardMemoryStorage.h b/Swiften/VCards/VCardMemoryStorage.h
new file mode 100644
index 0000000..b2e99c6
--- /dev/null
+++ b/Swiften/VCards/VCardMemoryStorage.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010 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 <map>
+
+#include "Swiften/JID/JID.h"
+#include "Swiften/VCards/VCardStorage.h"
+
+namespace Swift {
+ class VCardMemoryStorage : public VCardStorage {
+ public:
+ VCardMemoryStorage() {}
+
+ virtual VCard::ref getVCard(const JID& jid) const {
+ VCardMap::const_iterator i = vcards.find(jid);
+ if (i != vcards.end()) {
+ return i->second;
+ }
+ else {
+ return VCard::ref();
+ }
+ }
+
+ virtual void setVCard(const JID& jid, VCard::ref v) {
+ vcards[jid] = v;
+ }
+
+ private:
+ typedef std::map<JID, VCard::ref> VCardMap;
+ VCardMap vcards;
+ };
+}
diff --git a/Swiften/VCards/VCardStorage.h b/Swiften/VCards/VCardStorage.h
index 2a9044c..854ccc6 100644
--- a/Swiften/VCards/VCardStorage.h
+++ b/Swiften/VCards/VCardStorage.h
@@ -17,7 +17,7 @@ namespace Swift {
public:
virtual ~VCardStorage();
- virtual boost::shared_ptr<VCard> getVCard(const JID& jid) const = 0;
- virtual void setVCard(const JID&, boost::shared_ptr<VCard>) = 0;
+ virtual VCard::ref getVCard(const JID& jid) const = 0;
+ virtual void setVCard(const JID&, VCard::ref) = 0;
};
}