From b6a34463dfcedd454ab42230a47cdb7294a76f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Sun, 22 Aug 2010 10:55:08 +0200 Subject: Implemented VCardManager. diff --git a/.cproject b/.cproject index 5473cea..b9de4c5 100644 --- a/.cproject +++ b/.cproject @@ -307,22 +307,23 @@ + - + - + - - - + + + - + - + diff --git a/.project b/.project index 06cc260..17363c7 100644 --- a/.project +++ b/.project @@ -18,7 +18,7 @@ org.eclipse.cdt.make.core.autoBuildTarget - dist=1 + check=1 QA org.eclipse.cdt.make.core.buildArguments @@ -54,7 +54,7 @@ org.eclipse.cdt.make.core.fullBuildTarget - dist=1 + check=1 QA org.eclipse.cdt.make.core.stopOnError diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index 2204366..d5686bd 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -18,7 +18,10 @@ #include "Swift/Controllers/EventController.h" #include "Swift/Controllers/Chat/MUCController.h" #include "Swiften/Presence/PresenceSender.h" -#include "Swiften/Avatars/UnitTest/MockAvatarManager.h" +#include "Swiften/Avatars/AvatarManager.h" +#include "Swiften/Avatars/AvatarMemoryStorage.h" +#include "Swiften/VCards/VCardManager.h" +#include "Swiften/VCards/VCardMemoryStorage.h" #include "Swift/Controllers/NickResolver.h" #include "Swiften/Roster/XMPPRoster.h" #include "Swift/Controllers/UnitTest/MockChatWindow.h" @@ -65,12 +68,19 @@ public: chatListWindowFactory_ = mocks_->InterfaceMock(); mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createWindow).With(uiEventStream_).Return(NULL); manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL); - avatarManager_ = new MockAvatarManager(); + + vcardStorage_ = new VCardMemoryStorage(); + vcardManager_ = new VCardManager(jid_, iqRouter_, vcardStorage_); + avatarStorage_ = new AvatarMemoryStorage(); + avatarManager_ = new AvatarManager(vcardManager_, stanzaChannel_, avatarStorage_, NULL); manager_->setAvatarManager(avatarManager_); }; void tearDown() { delete avatarManager_; + delete avatarStorage_; + delete vcardManager_; + delete vcardStorage_; delete manager_; delete presenceSender_; delete presenceOracle_; @@ -303,6 +313,9 @@ private: ChatWindowFactory* chatWindowFactory_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; + VCardStorage* vcardStorage_; + VCardManager* vcardManager_; + AvatarStorage* avatarStorage_; AvatarManager* avatarManager_; boost::shared_ptr serverDiscoInfo_; boost::shared_ptr xmppRoster_; diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index 6eb3a2c..1032de1 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -20,6 +20,8 @@ #include "Swift/Controllers/BuildVersion.h" #include "Swift/Controllers/Chat/ChatController.h" #include "Swiften/VCards/VCardStorageFactory.h" +#include "Swiften/VCards/VCardManager.h" +#include "Swiften/VCards/VCardStorage.h" #include "Swift/Controllers/Chat/MUCSearchController.h" #include "Swift/Controllers/Chat/ChatsManager.h" #include "Swift/Controllers/EventController.h" @@ -85,16 +87,16 @@ MainController::MainController( mainWindowFactory_(mainWindowFactory), loginWindowFactory_(loginWindowFactory), settings_(settings), - loginWindow_(NULL), vcardStorageFactory_(vcardStorageFactory), - useDelayForLatency_(useDelayForLatency) { + loginWindow_(NULL) , + useDelayForLatency_(useDelayForLatency) { presenceOracle_ = NULL; - avatarManager_ = NULL; chatsManager_ = NULL; eventController_ = NULL; eventWindowController_ = NULL; nickResolver_ = NULL; avatarManager_ = NULL; + vcardManager_ = NULL; rosterController_ = NULL; xmppRosterController_ = NULL; clientVersionResponder_ = NULL; @@ -153,11 +155,13 @@ MainController::MainController( MainController::~MainController() { delete systemTrayController_; delete soundEventController_; - delete avatarStorage_; delete xmlConsoleController_; delete uiEventStream_; delete eventController_; resetClient(); + for(VCardStorageMap::iterator i = vcardStorages_.begin(); i != vcardStorages_.end(); ++i) { + delete i->second; + } } void MainController::resetClient() { @@ -173,6 +177,8 @@ void MainController::resetClient() { nickResolver_ = NULL; delete avatarManager_; avatarManager_ = NULL; + delete vcardManager_; + vcardManager_ = NULL; delete eventWindowController_; eventWindowController_ = NULL; delete rosterController_; @@ -223,7 +229,9 @@ void MainController::handleConnected() { presenceOracle_ = new PresenceOracle(client_); nickResolver_ = new NickResolver(xmppRoster_); - avatarManager_ = new AvatarManager(client_, client_, avatarStorage_); + vcardManager_ = new VCardManager(jid_, client_, getVCardStorageForProfile(jid_)); + vcardManager_->onOwnVCardChanged.connect(boost::bind(&MainController::handleOwnVCardReceived, this, _1)); + avatarManager_ = new AvatarManager(vcardManager_, client_, avatarStorage_); rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickResolver_, presenceOracle_, eventController_, uiEventStream_, client_); rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2)); @@ -261,10 +269,7 @@ void MainController::handleConnected() { discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2)); discoInfoRequest->send(); - boost::shared_ptr vCardRequest(new GetVCardRequest(JID(), client_)); - vCardRequest->onResponse.connect(boost::bind(&MainController::handleOwnVCardReceived, this, _1, _2)); - vCardRequest->send(); - + vcardManager_->requestOwnVCard(); setManagersEnabled(true); //Send presence last to catch all the incoming presences. @@ -480,17 +485,24 @@ void MainController::handleServerDiscoInfoResponse(boost::shared_ptr } } -void MainController::handleOwnVCardReceived(boost::shared_ptr vCard, const boost::optional& error) { - if (!vCard) { +void MainController::handleOwnVCardReceived(VCard::ref vCard) { + if (!vCard || vCard->getPhoto().isEmpty()) { return; } - if (!error && !vCard->getPhoto().isEmpty()) { - vCardPhotoHash_ = Hexify::hexify(SHA1::getHash(vCard->getPhoto())); - if (client_ && client_->isAvailable()) { - sendPresence(statusTracker_->getNextPresence()); - } - avatarManager_->setAvatar(jid_, vCard->getPhoto()); + vCardPhotoHash_ = Hexify::hexify(SHA1::getHash(vCard->getPhoto())); + if (client_ && client_->isAvailable()) { + sendPresence(statusTracker_->getNextPresence()); } } +VCardStorage* MainController::getVCardStorageForProfile(const JID& jid) { + String profile = jid.toBare().toString(); + std::pair r = vcardStorages_.insert(std::make_pair(profile, NULL)); + if (r.second) { + r.first->second = vcardStorageFactory_->createVCardStorage(profile); + } + return r.first->second; +} + + } diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index a612175..cf04e59 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -29,6 +29,8 @@ namespace Swift { class AvatarStorage; + class VCardStorage; + class VCardManager; class Application; class Client; class ChatWindowFactory; @@ -94,7 +96,7 @@ namespace Swift { void handleError(const ClientError& error); void handleServerDiscoInfoResponse(boost::shared_ptr, const boost::optional&); void handleEventQueueLengthChange(int count); - void handleOwnVCardReceived(boost::shared_ptr vCard, const boost::optional& error); + void handleOwnVCardReceived(VCard::ref vCard); void sendPresence(boost::shared_ptr presence); void handleInputIdleChanged(bool); void logout(); @@ -107,6 +109,9 @@ namespace Swift { void reconnectAfterError(); void setManagersEnabled(bool enabled); + VCardStorage* getVCardStorageForProfile(const JID& jid); + + private: BoostIOServiceThread boostIOServiceThread_; BoostTimerFactory timerFactory_; PlatformIdleQuerier idleQuerier_; @@ -121,6 +126,7 @@ namespace Swift { ProfileSettingsProvider* profileSettings_; AvatarStorage* avatarStorage_; VCardStorageFactory* vcardStorageFactory_; + VCardManager* vcardManager_; ApplicationMessageDisplay* applicationMessageDisplay_; ChatController* chatController_; XMPPRosterController* xmppRosterController_; @@ -153,5 +159,8 @@ namespace Swift { int timeBeforeNextReconnect_; Timer::ref reconnectTimer_; StatusTracker* statusTracker_; + + typedef std::map VCardStorageMap; + VCardStorageMap vcardStorages_; }; } diff --git a/Swiften/Avatars/AvatarFileStorage.cpp b/Swiften/Avatars/AvatarFileStorage.cpp index a0ebd21..57bb1be 100644 --- a/Swiften/Avatars/AvatarFileStorage.cpp +++ b/Swiften/Avatars/AvatarFileStorage.cpp @@ -34,4 +34,11 @@ boost::filesystem::path AvatarFileStorage::getAvatarPath(const String& hash) con return path_ / hash.getUTF8String(); } +ByteArray AvatarFileStorage::getAvatar(const String& hash) const { + ByteArray data; + data.readFromFile(getAvatarPath(hash).string()); + return data; +} + + } diff --git a/Swiften/Avatars/AvatarFileStorage.h b/Swiften/Avatars/AvatarFileStorage.h index 6318c60..5ade779 100644 --- a/Swiften/Avatars/AvatarFileStorage.h +++ b/Swiften/Avatars/AvatarFileStorage.h @@ -20,6 +20,7 @@ namespace Swift { virtual bool hasAvatar(const String& hash) const; virtual void addAvatar(const String& hash, const ByteArray& avatar); + virtual ByteArray getAvatar(const String& hash) const; virtual boost::filesystem::path getAvatarPath(const String& hash) const; diff --git a/Swiften/Avatars/AvatarManager.cpp b/Swiften/Avatars/AvatarManager.cpp index 3861520..33b1bee 100644 --- a/Swiften/Avatars/AvatarManager.cpp +++ b/Swiften/Avatars/AvatarManager.cpp @@ -15,18 +15,13 @@ #include "Swiften/StringCodecs/Hexify.h" #include "Swiften/Avatars/AvatarStorage.h" #include "Swiften/MUC/MUCRegistry.h" +#include "Swiften/VCards/VCardManager.h" namespace Swift { -AvatarManager::AvatarManager(StanzaChannel* stanzaChannel, IQRouter* iqRouter, AvatarStorage* avatarStorage, MUCRegistry* mucRegistry) : stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), avatarStorage_(avatarStorage), mucRegistry_(mucRegistry) { +AvatarManager::AvatarManager(VCardManager* vcardManager, StanzaChannel* stanzaChannel, AvatarStorage* avatarStorage, MUCRegistry* mucRegistry) : vcardManager_(vcardManager), stanzaChannel_(stanzaChannel), avatarStorage_(avatarStorage), mucRegistry_(mucRegistry) { stanzaChannel->onPresenceReceived.connect(boost::bind(&AvatarManager::handlePresenceReceived, this, _1)); -} - -AvatarManager::AvatarManager() { - stanzaChannel_ = NULL; - iqRouter_ = NULL; - avatarStorage_ = NULL; - mucRegistry_ = NULL; + vcardManager_->onVCardChanged.connect(boost::bind(&AvatarManager::handleVCardChanged, this, _1, _2)); } AvatarManager::~AvatarManager() { @@ -39,50 +34,30 @@ void AvatarManager::setMUCRegistry(MUCRegistry* mucRegistry) { void AvatarManager::handlePresenceReceived(boost::shared_ptr presence) { boost::shared_ptr update = presence->getPayload(); - if (!update) { + if (!update || presence->getPayload()) { return; } - if (presence->getPayload()) { + JID from = getAvatarJID(presence->getFrom()); + if (getAvatarHash(from) == update->getPhotoHash()) { return; } - JID from = getAvatarJID(presence->getFrom()); - String& hash = avatarHashes_[from]; - if (hash != update->getPhotoHash()) { - String newHash = update->getPhotoHash(); - if (avatarStorage_->hasAvatar(newHash)) { - setAvatarHash(from, newHash); - } - else { - boost::shared_ptr request(new GetVCardRequest(from, iqRouter_)); - request->onResponse.connect(boost::bind(&AvatarManager::handleVCardReceived, this, from, newHash, _1, _2)); - request->send(); - } + if (avatarStorage_->hasAvatar(update->getPhotoHash())) { + setAvatarHash(from, update->getPhotoHash()); + } + else { + vcardManager_->requestVCard(from); } } -void AvatarManager::handleVCardReceived(const JID& from, const String& promisedHash, boost::shared_ptr vCard, const boost::optional& error) { - if (error) { - // FIXME: What to do here? - std::cerr << "Warning: " << from << ": Could not get vCard" << std::endl; - return; - } +void AvatarManager::handleVCardChanged(const JID& from, VCard::ref vCard) { if (!vCard) { std::cerr << "Warning: " << from << ": null vcard payload" << std::endl; - //FIXME: Why could this happen? return; } - String realHash = Hexify::hexify(SHA1::getHash(vCard->getPhoto())); - if (promisedHash != realHash) { - std::cerr << "Warning: " << from << ": Got different vCard photo hash (" << promisedHash << " != " << realHash << ")" << std::endl; - } - avatarStorage_->addAvatar(realHash, vCard->getPhoto()); - setAvatarHash(from, realHash); -} -void AvatarManager::setAvatar(const JID& jid, const ByteArray& avatar) { - String hash = Hexify::hexify(SHA1::getHash(avatar)); - avatarStorage_->addAvatar(hash, avatar); - setAvatarHash(getAvatarJID(jid), hash); + String hash = Hexify::hexify(SHA1::getHash(vCard->getPhoto())); + avatarStorage_->addAvatar(hash, vCard->getPhoto()); + setAvatarHash(from, hash); } void AvatarManager::setAvatarHash(const JID& from, const String& hash) { @@ -90,6 +65,14 @@ void AvatarManager::setAvatarHash(const JID& from, const String& hash) { onAvatarChanged(from, hash); } +/* +void AvatarManager::setAvatar(const JID& jid, const ByteArray& avatar) { + String hash = Hexify::hexify(SHA1::getHash(avatar)); + avatarStorage_->addAvatar(hash, avatar); + setAvatarHash(getAvatarJID(jid), hash); +} +*/ + String AvatarManager::getAvatarHash(const JID& jid) const { std::map::const_iterator i = avatarHashes_.find(getAvatarJID(jid)); if (i != avatarHashes_.end()) { diff --git a/Swiften/Avatars/AvatarManager.h b/Swiften/Avatars/AvatarManager.h index ad4b30f..543d167 100644 --- a/Swiften/Avatars/AvatarManager.h +++ b/Swiften/Avatars/AvatarManager.h @@ -9,9 +9,9 @@ #include #include #include -#include "Swiften/Base/boost_bsignals.h" #include +#include "Swiften/Base/boost_bsignals.h" #include "Swiften/JID/JID.h" #include "Swiften/Elements/Presence.h" #include "Swiften/Elements/VCard.h" @@ -21,35 +21,32 @@ namespace Swift { class MUCRegistry; class AvatarStorage; class StanzaChannel; - class IQRouter; + class VCardManager; class AvatarManager { public: - AvatarManager(StanzaChannel*, IQRouter*, AvatarStorage*, MUCRegistry* = NULL); + AvatarManager(VCardManager*, StanzaChannel*, AvatarStorage*, MUCRegistry* = NULL); virtual ~AvatarManager(); virtual void setMUCRegistry(MUCRegistry*); - virtual String getAvatarHash(const JID&) const; virtual boost::filesystem::path getAvatarPath(const JID&) const; - virtual void setAvatar(const JID&, const ByteArray& avatar); - public: - boost::signal onAvatarChanged; +// virtual void setAvatar(const JID&, const ByteArray& avatar);*/ - protected: - /** Used only for testing. Leads to a non-functional object. */ - AvatarManager(); + public: + boost::signal onAvatarChanged; private: void handlePresenceReceived(boost::shared_ptr); - void handleVCardReceived(const JID& from, const String& hash, boost::shared_ptr, const boost::optional&); + void handleVCardChanged(const JID& from, VCard::ref); void setAvatarHash(const JID& from, const String& hash); JID getAvatarJID(const JID& o) const; + String getAvatarHash(const JID&) const; private: + VCardManager* vcardManager_; StanzaChannel* stanzaChannel_; - IQRouter* iqRouter_; AvatarStorage* avatarStorage_; MUCRegistry* mucRegistry_; std::map avatarHashes_; diff --git a/Swiften/Avatars/AvatarMemoryStorage.h b/Swiften/Avatars/AvatarMemoryStorage.h new file mode 100644 index 0000000..f60f603 --- /dev/null +++ b/Swiften/Avatars/AvatarMemoryStorage.h @@ -0,0 +1,32 @@ +/* + * 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 + +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/Avatars/AvatarStorage.h" + +namespace Swift { + class AvatarMemoryStorage : public AvatarStorage { + public: + virtual bool hasAvatar(const String& hash) const { return avatars.find(hash) != avatars.end(); } + virtual void addAvatar(const String& hash, const ByteArray& avatar) { avatars[hash] = avatar; } + virtual ByteArray getAvatar(const String& hash) const { + std::map::const_iterator i = avatars.find(hash); + return i == avatars.end() ? ByteArray() : i->second; + } + + virtual boost::filesystem::path getAvatarPath(const String& hash) const { + return boost::filesystem::path(); + } + + private: + std::map avatars; + }; +} diff --git a/Swiften/Avatars/AvatarStorage.h b/Swiften/Avatars/AvatarStorage.h index bd8aa49..d699f40 100644 --- a/Swiften/Avatars/AvatarStorage.h +++ b/Swiften/Avatars/AvatarStorage.h @@ -18,6 +18,7 @@ namespace Swift { virtual bool hasAvatar(const String& hash) const = 0; virtual void addAvatar(const String& hash, const ByteArray& avatar) = 0; + virtual ByteArray getAvatar(const String& hash) const = 0; virtual boost::filesystem::path getAvatarPath(const String& hash) const = 0; }; diff --git a/Swiften/Avatars/UnitTest/AvatarManagerTest.cpp b/Swiften/Avatars/UnitTest/AvatarManagerTest.cpp index f954aa1..858d257 100644 --- a/Swiften/Avatars/UnitTest/AvatarManagerTest.cpp +++ b/Swiften/Avatars/UnitTest/AvatarManagerTest.cpp @@ -6,24 +6,32 @@ #include #include +#include #include "Swiften/Elements/VCardUpdate.h" #include "Swiften/Avatars/AvatarManager.h" -#include "Swiften/Avatars/AvatarStorage.h" +#include "Swiften/Avatars/AvatarMemoryStorage.h" +#include "Swiften/VCards/VCardMemoryStorage.h" +#include "Swiften/VCards/VCardManager.h" #include "Swiften/MUC/MUCRegistry.h" #include "Swiften/Queries/IQRouter.h" #include "Swiften/Client/DummyStanzaChannel.h" +#include "Swiften/StringCodecs/SHA1.h" +#include "Swiften/StringCodecs/Hexify.h" using namespace Swift; class AvatarManagerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(AvatarManagerTest); - CPPUNIT_TEST(testUpdate_UpdateNewHash); + CPPUNIT_TEST(testUpdate_NewHashNewVCardRequestsVCard); + CPPUNIT_TEST(testUpdate_NewHashStoresAvatarAndEmitsNotificationOnVCardReceive); + CPPUNIT_TEST(testUpdate_KnownHash); + CPPUNIT_TEST(testUpdate_KnownHashFromDifferentUserDoesNotRequestVCardButTriggersNotification); /*& CPPUNIT_TEST(testUpdate_UpdateNewHashAlreadyHaveAvatar); CPPUNIT_TEST(testUpdate_UpdateNewHashFromMUC); CPPUNIT_TEST(testUpdate_UpdateSameHash);*/ - CPPUNIT_TEST(testUpdate_UpdateWithError); + //CPPUNIT_TEST(testUpdate_UpdateWithError); /* CPPUNIT_TEST(testUpdate_UpdateNewHashSameThanOtherUser); CPPUNIT_TEST(testReceiveVCard); @@ -33,99 +41,135 @@ class AvatarManagerTest : public CppUnit::TestFixture { public: void setUp() { - stanzaChannel_ = new DummyStanzaChannel(); - iqRouter_ = new IQRouter(stanzaChannel_); - mucRegistry_ = new DummyMUCRegistry(); - avatarStorage_ = new DummyAvatarStorage(); + ownJID = JID("foo@fum.com/bum"); + stanzaChannel = new DummyStanzaChannel(); + iqRouter = new IQRouter(stanzaChannel); + mucRegistry = new DummyMUCRegistry(); + avatarStorage = new AvatarMemoryStorage(); + vcardStorage = new VCardMemoryStorage(); + vcardManager = new VCardManager(ownJID, iqRouter, vcardStorage); + avatar1 = ByteArray("abcdefg"); + avatar1Hash = Hexify::hexify(SHA1::getHash(avatar1)); + user1 = JID("user1@bar.com/bla"); + user2 = JID("user2@foo.com/baz"); } void tearDown() { - delete avatarStorage_; - delete mucRegistry_; - delete iqRouter_; - delete stanzaChannel_; + delete vcardManager; + delete vcardStorage; + delete avatarStorage; + delete mucRegistry; + delete iqRouter; + delete stanzaChannel; } - void testUpdate_UpdateNewHash() { + void testUpdate_NewHashNewVCardRequestsVCard() { std::auto_ptr testling = createManager(); - stanzaChannel_->onPresenceReceived(createPresenceWithPhotoHash()); + stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); - CPPUNIT_ASSERT_EQUAL(1, static_cast(stanzaChannel_->sentStanzas.size())); - CPPUNIT_ASSERT(stanzaChannel_->isRequestAtIndex(0, JID("foo@bar.com"), IQ::Get)); + CPPUNIT_ASSERT_EQUAL(1, static_cast(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex(0, user1.toBare(), IQ::Get)); } - void testUpdate_UpdateNewHashAlreadyHaveAvatar() { - avatarStorage_->addAvatar("aef56135bcce35eb24a43fcd684005b4ca286497", ByteArray("ghij")); - std::auto_ptr testling = createManager(); - stanzaChannel_->onPresenceReceived(createPresenceWithPhotoHash()); - - CPPUNIT_ASSERT_EQUAL(0, static_cast(stanzaChannel_->sentStanzas.size())); - } -/* - void testUpdate_UpdateNewHashFromMUC() { + void testUpdate_NewHashStoresAvatarAndEmitsNotificationOnVCardReceive() { std::auto_ptr testling = createManager(); + stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); + stanzaChannel->onIQReceived(createVCardResult(avatar1)); + + CPPUNIT_ASSERT_EQUAL(1, static_cast(changes.size())); + CPPUNIT_ASSERT_EQUAL(user1.toBare(), changes[0].first); + CPPUNIT_ASSERT_EQUAL(avatar1Hash, changes[0].second); + CPPUNIT_ASSERT(avatarStorage->hasAvatar(avatar1Hash)); + CPPUNIT_ASSERT_EQUAL(avatar1, avatarStorage->getAvatar(avatar1Hash)); } - void testUpdate_UpdateSameHash() { + void testUpdate_KnownHash() { std::auto_ptr testling = createManager(); - } + stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); + stanzaChannel->onIQReceived(createVCardResult(avatar1)); + changes.clear(); + stanzaChannel->sentStanzas.clear(); - void testUpdate_UpdateNewHashSameThanOtherUser() { - std::auto_ptr testling = createManager(); - } + stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); - void testReceiveVCard() { - std::auto_ptr testling = createManager(); + CPPUNIT_ASSERT_EQUAL(0, static_cast(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast(changes.size())); } - void testGetAvatarPath() { + void testUpdate_KnownHashFromDifferentUserDoesNotRequestVCardButTriggersNotification() { std::auto_ptr testling = createManager(); + stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); + stanzaChannel->onIQReceived(createVCardResult(avatar1)); + changes.clear(); + stanzaChannel->sentStanzas.clear(); + + stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user2, avatar1Hash)); + + CPPUNIT_ASSERT_EQUAL(0, static_cast(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast(changes.size())); + CPPUNIT_ASSERT_EQUAL(user2.toBare(), changes[0].first); + CPPUNIT_ASSERT_EQUAL(avatar1Hash, changes[0].second); } - void testGetAvatarPathFromMUC() { +/* + void testUpdate_UpdateNewHashFromMUC() { std::auto_ptr testling = createManager(); } + */ - void testUpdate_UpdateWithError() { + /*void testUpdate_UpdateWithError() { std::auto_ptr testling = createManager(); boost::shared_ptr update = createPresenceWithPhotoHash(); update->addPayload(boost::shared_ptr(new ErrorPayload())); stanzaChannel_->onPresenceReceived(update); CPPUNIT_ASSERT_EQUAL(0, static_cast(stanzaChannel_->sentStanzas.size())); - } + }*/ private: std::auto_ptr createManager() { - return std::auto_ptr(new AvatarManager(stanzaChannel_, iqRouter_, avatarStorage_, mucRegistry_)); + std::auto_ptr result(new AvatarManager(vcardManager, stanzaChannel, avatarStorage, mucRegistry)); + result->onAvatarChanged.connect(boost::bind(&AvatarManagerTest::handleAvatarChanged, this, _1, _2)); + return result; } - boost::shared_ptr createPresenceWithPhotoHash() { + boost::shared_ptr createPresenceWithPhotoHash(const JID& jid, const String& hash) { boost::shared_ptr presence(new Presence()); - presence->setFrom(JID("foo@bar.com/baz")); - presence->addPayload(boost::shared_ptr(new VCardUpdate("aef56135bcce35eb24a43fcd684005b4ca286497"))); + presence->setFrom(jid); + presence->addPayload(boost::shared_ptr(new VCardUpdate(hash))); return presence; } + IQ::ref createVCardResult(const ByteArray& avatar) { + VCard::ref vcard(new VCard()); + vcard->setPhoto(avatar); + return IQ::createResult(JID("baz@fum.com"), stanzaChannel->sentStanzas[0]->getID(), vcard); + } + + void handleAvatarChanged(const JID& jid, const String& hash) { + changes.push_back(std::pair(jid, hash)); + } + private: struct DummyMUCRegistry : public MUCRegistry { bool isMUC(const JID& jid) const { return std::find(mucs_.begin(), mucs_.end(), jid) != mucs_.end(); } std::vector mucs_; }; - struct DummyAvatarStorage : public AvatarStorage { - virtual bool hasAvatar(const String& hash) const { return avatars.find(hash) != avatars.end(); } - virtual void addAvatar(const String& hash, const ByteArray& avatar) { avatars[hash] = avatar; } - virtual boost::filesystem::path getAvatarPath(const String& hash) const { - return boost::filesystem::path("/avatars") / hash.getUTF8String(); - } - std::map avatars; - }; - DummyStanzaChannel* stanzaChannel_; - IQRouter* iqRouter_; - DummyMUCRegistry* mucRegistry_; - DummyAvatarStorage* avatarStorage_; + + JID ownJID; + DummyStanzaChannel* stanzaChannel; + IQRouter* iqRouter; + DummyMUCRegistry* mucRegistry; + AvatarMemoryStorage* avatarStorage; + VCardManager* vcardManager; + VCardMemoryStorage* vcardStorage; + ByteArray avatar1; + String avatar1Hash; + std::vector > changes; + JID user1; + JID user2; }; CPPUNIT_TEST_SUITE_REGISTRATION(AvatarManagerTest); diff --git a/Swiften/Avatars/UnitTest/MockAvatarManager.cpp b/Swiften/Avatars/UnitTest/MockAvatarManager.cpp deleted file mode 100644 index 4a96e01..0000000 --- a/Swiften/Avatars/UnitTest/MockAvatarManager.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include "Swiften/Avatars/UnitTest/MockAvatarManager.h" - -namespace Swift { - -MockAvatarManager::MockAvatarManager() { - -} - -MockAvatarManager::~MockAvatarManager() { - -} - -String MockAvatarManager::getAvatarHash(const JID& jid) const { - return jid.toBare(); -} - -boost::filesystem::path MockAvatarManager::getAvatarPath(const JID& jid) const { - return jid.getResource().getUTF8String(); -} - -void MockAvatarManager::setAvatar(const JID&, const ByteArray&) { - -} - -} - diff --git a/Swiften/Avatars/UnitTest/MockAvatarManager.h b/Swiften/Avatars/UnitTest/MockAvatarManager.h deleted file mode 100644 index 9f31f12..0000000 --- a/Swiften/Avatars/UnitTest/MockAvatarManager.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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 "Swiften/Avatars/AvatarManager.h" -#include "Swiften/Client/DummyStanzaChannel.h" - -namespace Swift { - class MockAvatarManager : public AvatarManager { - public: - MockAvatarManager(); - virtual ~MockAvatarManager(); - virtual String getAvatarHash(const JID&) const; - virtual boost::filesystem::path getAvatarPath(const JID&) const; - virtual void setAvatar(const JID&, const ByteArray& avatar); - private: - DummyStanzaChannel channel_; - }; -} diff --git a/Swiften/Elements/IQ.h b/Swiften/Elements/IQ.h index 790d032..2bb55e1 100644 --- a/Swiften/Elements/IQ.h +++ b/Swiften/Elements/IQ.h @@ -8,10 +8,11 @@ #include "Swiften/Elements/Stanza.h" #include "Swiften/Elements/ErrorPayload.h" +#include "Swiften/Base/Shared.h" namespace Swift { - class IQ : public Stanza + class IQ : public Stanza, public Shared { public: enum Type { Get, Set, Result, Error }; @@ -33,8 +34,8 @@ namespace Swift static boost::shared_ptr createError( const JID& to, const String& id, - ErrorPayload::Condition condition, - ErrorPayload::Type type); + ErrorPayload::Condition condition = ErrorPayload::BadRequest, + ErrorPayload::Type type = ErrorPayload::Cancel); private: Type type_; diff --git a/Swiften/QA/StorageTest/SConscript b/Swiften/QA/StorageTest/SConscript index c7401e0..c35d5b3 100644 --- a/Swiften/QA/StorageTest/SConscript +++ b/Swiften/QA/StorageTest/SConscript @@ -10,6 +10,7 @@ if env["TEST"] : myenv.MergeFlags(myenv["BOOST_FLAGS"]) myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) myenv.MergeFlags(myenv.get("EXPAT_FLAGS", {})) + myenv.MergeFlags(myenv.get("LIBXML_FLAGS", {})) tester = myenv.Program("StorageTest", [ "VCardFileStorageTest.cpp", diff --git a/Swiften/QA/StorageTest/VCardFileStorageTest.cpp b/Swiften/QA/StorageTest/VCardFileStorageTest.cpp index 9704409..694e13b 100644 --- a/Swiften/QA/StorageTest/VCardFileStorageTest.cpp +++ b/Swiften/QA/StorageTest/VCardFileStorageTest.cpp @@ -39,9 +39,9 @@ class VCardFileStorageTest : public CppUnit::TestFixture { vcard->setFullName("Alice In Wonderland"); vcard->setEMail("alice@wonderland.lit"); - testling->setVCard(JID("alice@wonderland.lit"), vcard); + testling->setVCard(JID("alice@wonderland.lit/TeaRoom"), vcard); - boost::filesystem::path vcardFile(vcardsPath / "alice@wonderland.lit.xml"); + boost::filesystem::path vcardFile(vcardsPath / "alice@wonderland.lit%2fTeaRoom.xml"); CPPUNIT_ASSERT(boost::filesystem::exists(vcardFile)); ByteArray data; data.readFromFile(vcardFile.string()); diff --git a/Swiften/Queries/Requests/GetVCardRequest.h b/Swiften/Queries/Requests/GetVCardRequest.h index 7ebacdf..f369cdc 100644 --- a/Swiften/Queries/Requests/GetVCardRequest.h +++ b/Swiften/Queries/Requests/GetVCardRequest.h @@ -8,9 +8,10 @@ #include "Swiften/Queries/GenericRequest.h" #include "Swiften/Elements/VCard.h" +#include "Swiften/Base/Shared.h" namespace Swift { - class GetVCardRequest : public GenericRequest { + class GetVCardRequest : public GenericRequest, public Shared { public: GetVCardRequest(const JID& jid, IQRouter* router) : GenericRequest(IQ::Get, jid, boost::shared_ptr(new VCard()), router) { } diff --git a/Swiften/SConscript b/Swiften/SConscript index f206dd0..6e2628a 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -140,7 +140,6 @@ if env["SCONS_STAGE"] == "build" : env.Append(UNITTEST_SOURCES = [ File("Application/UnitTest/ApplicationPathProviderTest.cpp"), - File("Avatars/UnitTest/MockAvatarManager.cpp"), File("Avatars/UnitTest/AvatarManagerTest.cpp"), File("Base/UnitTest/IDGeneratorTest.cpp"), File("Base/UnitTest/StringTest.cpp"), @@ -233,4 +232,5 @@ if env["SCONS_STAGE"] == "build" : File("StringCodecs/UnitTest/HexifyTest.cpp"), File("StringCodecs/UnitTest/HMACSHA1Test.cpp"), File("StringCodecs/UnitTest/PBKDF2Test.cpp"), + File("VCards/UnitTest/VCardManagerTest.cpp"), ]) diff --git a/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp b/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp index 19a6b6e..8975818 100644 --- a/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp @@ -10,6 +10,7 @@ #include "Swiften/Serializer/XML/XMLElement.h" #include "Swiften/Serializer/XML/XMLTextNode.h" +#include "Swiften/StringCodecs/Hexify.h" namespace Swift { @@ -49,7 +50,20 @@ String VCardSerializer::serializePayload(boost::shared_ptr vcard) const nickElement->addNode(boost::shared_ptr(new XMLTextNode(vcard->getNickname()))); queryElement.addNode(nickElement); } - // TODO + if (!vcard->getPhoto().isEmpty() || !vcard->getPhotoType().isEmpty()) { + XMLElement::ref photoElement(new XMLElement("PHOTO")); + if (!vcard->getPhotoType().isEmpty()) { + XMLElement::ref typeElement(new XMLElement("TYPE")); + typeElement->addNode(XMLTextNode::ref(new XMLTextNode(vcard->getPhotoType()))); + photoElement->addNode(typeElement); + } + if (!vcard->getPhoto().isEmpty()) { + XMLElement::ref binvalElement(new XMLElement("BINVAL")); + binvalElement->addNode(XMLTextNode::ref(new XMLTextNode(Hexify::hexify(vcard->getPhoto())))); + photoElement->addNode(binvalElement); + } + queryElement.addNode(photoElement); + } return queryElement.serialize(); } diff --git a/Swiften/Serializer/XML/XMLElement.h b/Swiften/Serializer/XML/XMLElement.h index 373a939..8447ab1 100644 --- a/Swiften/Serializer/XML/XMLElement.h +++ b/Swiften/Serializer/XML/XMLElement.h @@ -4,18 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_XMLElement_H -#define SWIFTEN_XMLElement_H +#pragma once #include #include #include #include "Swiften/Base/String.h" +#include "Swiften/Base/Shared.h" #include "Swiften/Serializer/XML/XMLNode.h" namespace Swift { - class XMLElement : public XMLNode { + class XMLElement : public XMLNode, public Shared { public: XMLElement(const String& tag, const String& xmlns = ""); @@ -30,4 +30,3 @@ namespace Swift { std::vector< boost::shared_ptr > childNodes_; }; } -#endif diff --git a/Swiften/Serializer/XML/XMLTextNode.h b/Swiften/Serializer/XML/XMLTextNode.h index c1d13ef..e158916 100644 --- a/Swiften/Serializer/XML/XMLTextNode.h +++ b/Swiften/Serializer/XML/XMLTextNode.h @@ -7,9 +7,10 @@ #pragma once #include "Swiften/Serializer/XML/XMLNode.h" +#include "Swiften/Base/Shared.h" namespace Swift { - class XMLTextNode : public XMLNode { + class XMLTextNode : public XMLNode, public Shared { public: typedef boost::shared_ptr ref; 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 +#include +#include +#include + +#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 testling = createManager(); + VCard::ref result = testling->getVCardAndRequestWhenNeeded(JID("foo@bar.com/baz")); + + CPPUNIT_ASSERT(!result); + CPPUNIT_ASSERT_EQUAL(1, static_cast(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex(0, JID("foo@bar.com/baz"), IQ::Get)); + } + + void testGet_ExistingVCard() { + std::auto_ptr 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(stanzaChannel->sentStanzas.size())); + } + + void testRequest_RequestsVCard() { + std::auto_ptr testling = createManager(); + testling->requestVCard(JID("foo@bar.com/baz")); + + CPPUNIT_ASSERT_EQUAL(1, static_cast(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex(0, JID("foo@bar.com/baz"), IQ::Get)); + } + + void testRequest_ReceiveEmitsNotification() { + std::auto_ptr testling = createManager(); + testling->requestVCard(JID("foo@bar.com/baz")); + stanzaChannel->onIQReceived(createVCardResult()); + + CPPUNIT_ASSERT_EQUAL(1, static_cast(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 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(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 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(stanzaChannel->sentStanzas.size())); + } + + void testRequest_AfterPreviousRequest() { + std::auto_ptr 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(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex(1, JID("foo@bar.com/baz"), IQ::Get)); + } + + void testRequestOwnVCard() { + std::auto_ptr testling = createManager(); + testling->requestVCard(ownJID); + stanzaChannel->onIQReceived(createOwnVCardResult()); + + CPPUNIT_ASSERT_EQUAL(1, static_cast(stanzaChannel->sentStanzas.size())); + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex(0, JID(), IQ::Get)); + CPPUNIT_ASSERT_EQUAL(1, static_cast(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 createManager() { + std::auto_ptr 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)); + } + + 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 > 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 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 getVCard(const JID& jid) const; - virtual void setVCard(const JID& jid, boost::shared_ptr 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 + +#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 VCardManager::getVCardAndRequestWhenNeeded(const JID& jid) const { - boost::shared_ptr 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& 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 +#include + +#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 getVCardAndRequestWhenNeeded(const JID& jid) const ; + VCard::ref getVCardAndRequestWhenNeeded(const JID& jid); + void requestVCard(const JID& jid); + void requestOwnVCard(); public: - boost::signal onVCardChanged; + /** + * The JID will always be bare. + */ + boost::signal onVCardChanged; + boost::signal onOwnVCardChanged; + + private: + void handleVCardReceived(const JID& from, VCard::ref, const boost::optional&); private: + JID ownJID; IQRouter* iqRouter; VCardStorage* storage; + std::set 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 +#include + +#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 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 getVCard(const JID& jid) const = 0; - virtual void setVCard(const JID&, boost::shared_ptr) = 0; + virtual VCard::ref getVCard(const JID& jid) const = 0; + virtual void setVCard(const JID&, VCard::ref) = 0; }; } -- cgit v0.10.2-6-g49f6