diff options
author | Remko Tronçon <git@el-tramo.be> | 2009-06-20 11:47:21 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2009-06-20 14:38:58 (GMT) |
commit | 6eb30e0e1f0a8e7ee936f3c006c7f710785653df (patch) | |
tree | 1e72dd6445d7d8d4e06f71c52299260a941a5be6 | |
parent | 6d50c38e2bc6a17afb19effe06d2103f06c8ea1c (diff) | |
download | swift-6eb30e0e1f0a8e7ee936f3c006c7f710785653df.zip swift-6eb30e0e1f0a8e7ee936f3c006c7f710785653df.tar.bz2 |
Added vCard-based avatars support.
27 files changed, 295 insertions, 26 deletions
diff --git a/Swift/Controllers/ChatController.cpp b/Swift/Controllers/ChatController.cpp index 8c0b8bb..39e9144 100644 --- a/Swift/Controllers/ChatController.cpp +++ b/Swift/Controllers/ChatController.cpp @@ -9,8 +9,8 @@ namespace Swift { /** * The controller does not gain ownership of the stanzaChannel, nor the factory. */ -ChatController::ChatController(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle) - : ChatControllerBase(stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle) { +ChatController::ChatController(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager) + : ChatControllerBase(stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager) { nickResolver_ = nickResolver; } @@ -28,7 +28,7 @@ void ChatController::preHandleIncomingMessage(boost::shared_ptr<Message> message } void ChatController::postSendMessage(const String& body) { - chatWindow_->addMessage(body, "me", true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional<SecurityLabel>()); + chatWindow_->addMessage(body, "me", true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional<SecurityLabel>(), ""); } String ChatController::senderDisplayNameFromMessage(JID from) { diff --git a/Swift/Controllers/ChatController.h b/Swift/Controllers/ChatController.h index 98e66bc..265bc91 100644 --- a/Swift/Controllers/ChatController.h +++ b/Swift/Controllers/ChatController.h @@ -4,17 +4,20 @@ #include "Swift/Controllers/ChatControllerBase.h" namespace Swift { + class AvatarManager; class NickResolver; class ChatController : public ChatControllerBase { public: - ChatController(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle); - ~ChatController() {}; + ChatController(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager*); + //boost::signal<void (const JID&, const JID&)> onJIDChanged; + protected: bool isIncomingMessageFromMe(boost::shared_ptr<Message> message); void postSendMessage(const String &body); void preHandleIncomingMessage(boost::shared_ptr<Message> message); String senderDisplayNameFromMessage(JID from); + private: NickResolver* nickResolver_; JID contact_; diff --git a/Swift/Controllers/ChatControllerBase.cpp b/Swift/Controllers/ChatControllerBase.cpp index 0d22571..e84ee04 100644 --- a/Swift/Controllers/ChatControllerBase.cpp +++ b/Swift/Controllers/ChatControllerBase.cpp @@ -3,6 +3,7 @@ #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> +#include "Swiften/Avatars/AvatarManager.h" #include "Swiften/Client/StanzaChannel.h" #include "Swiften/Base/foreach.h" #include "Swift/Controllers/ChatWindow.h" @@ -11,7 +12,7 @@ namespace Swift { -ChatControllerBase::ChatControllerBase(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle) : stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle) { +ChatControllerBase::ChatControllerBase(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager) : stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager) { chatWindow_ = chatWindowFactory_->createChatWindow(toJID); chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this)); chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1)); @@ -130,7 +131,7 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m boost::shared_ptr<SecurityLabel> label = message->getPayload<SecurityLabel>(); boost::optional<SecurityLabel> maybeLabel = label ? boost::optional<SecurityLabel>(*label) : boost::optional<SecurityLabel>(); JID from = message->getFrom(); - chatWindow_->addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), maybeLabel); + chatWindow_->addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), maybeLabel, String(avatarManager_->getAvatarPath(from).string())); } } diff --git a/Swift/Controllers/ChatControllerBase.h b/Swift/Controllers/ChatControllerBase.h index 1967977..58d3a1d 100644 --- a/Swift/Controllers/ChatControllerBase.h +++ b/Swift/Controllers/ChatControllerBase.h @@ -19,6 +19,7 @@ namespace Swift { class StanzaChannel; class ChatWindow; class ChatWindowFactory; + class AvatarManager; class ChatControllerBase { public: @@ -28,7 +29,8 @@ namespace Swift { void handleIncomingMessage(boost::shared_ptr<MessageEvent> message); protected: - ChatControllerBase(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle); + ChatControllerBase(StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager); + virtual void postSendMessage(const String&) {}; virtual String senderDisplayNameFromMessage(JID from); void handlePresenceChange(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> previousPresence); @@ -36,6 +38,14 @@ namespace Swift { virtual void preHandleIncomingMessage(boost::shared_ptr<Message>) {}; virtual void preSendMessageRequest(boost::shared_ptr<Message>) {}; + private: + void handleSendMessageRequest(const String &body); + String getStatusChangeString(boost::shared_ptr<Presence> presence); + void handleAllMessagesRead(); + void handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog>, const boost::optional<Error>& error); + String getErrorMessage(boost::shared_ptr<Error>); + + protected: std::vector<boost::shared_ptr<MessageEvent> > unreadMessages_; StanzaChannel* stanzaChannel_; IQRouter* iqRouter_; @@ -44,13 +54,7 @@ namespace Swift { JID toJID_; bool labelsEnabled_; PresenceOracle* presenceOracle_; - - private: - void handleSendMessageRequest(const String &body); - String getStatusChangeString(boost::shared_ptr<Presence> presence); - void handleAllMessagesRead(); - void handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog>, const boost::optional<Error>& error); - String getErrorMessage(boost::shared_ptr<Error>); + AvatarManager* avatarManager_; }; } diff --git a/Swift/Controllers/ChatWindow.h b/Swift/Controllers/ChatWindow.h index 04d0007..dd71bf9 100644 --- a/Swift/Controllers/ChatWindow.h +++ b/Swift/Controllers/ChatWindow.h @@ -10,12 +10,15 @@ #include "Swiften/Elements/SecurityLabel.h" namespace Swift { + class AvatarManager; class TreeWidget; + class ChatWindow { public: + ChatWindow() {} virtual ~ChatWindow() {}; - virtual void addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label) = 0; + virtual void addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath) = 0; virtual void addSystemMessage(const String& message) = 0; virtual void addErrorMessage(const String& message) = 0; diff --git a/Swift/Controllers/MUCController.cpp b/Swift/Controllers/MUCController.cpp index 93880c4..27ddcb8 100644 --- a/Swift/Controllers/MUCController.cpp +++ b/Swift/Controllers/MUCController.cpp @@ -23,8 +23,9 @@ MUCController::MUCController ( IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory *treeWidgetFactory, - PresenceOracle* presenceOracle) : - ChatControllerBase(stanzaChannel, iqRouter, chatWindowFactory, muc, presenceOracle), + PresenceOracle* presenceOracle, + AvatarManager* avatarManager) : + ChatControllerBase(stanzaChannel, iqRouter, chatWindowFactory, muc, presenceOracle, avatarManager), muc_(new MUC(stanzaChannel, muc)), nick_(nick), treeWidgetFactory_(treeWidgetFactory) { diff --git a/Swift/Controllers/MUCController.h b/Swift/Controllers/MUCController.h index c87695e..b2f396c 100644 --- a/Swift/Controllers/MUCController.h +++ b/Swift/Controllers/MUCController.h @@ -18,10 +18,11 @@ namespace Swift { class ChatWindowFactory; class Roster; class TreeWidgetFactory; + class AvatarManager; class MUCController : public ChatControllerBase { public: - MUCController(const JID &muc, const String &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory *treeWidgetFactory, PresenceOracle* presenceOracle); + MUCController(const JID &muc, const String &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory *treeWidgetFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager); ~MUCController(); protected: diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index e9177f8..20dfaa1 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -32,6 +32,8 @@ #include "Swiften/Queries/Responders/DiscoInfoResponder.h" #include "Swiften/Disco/CapsInfoGenerator.h" #include "Swiften/Queries/Requests/GetDiscoInfoRequest.h" +#include "Swiften/Avatars/AvatarFileStorage.h" +#include "Swiften/Avatars/AvatarManager.h" namespace Swift { @@ -45,8 +47,11 @@ typedef std::pair<JID, MUCController*> JIDMUCControllerPair; MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, TreeWidgetFactory *treeWidgetFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray) : client_(NULL), chatWindowFactory_(chatWindowFactory), mainWindowFactory_(mainWindowFactory), loginWindowFactory_(loginWindowFactory), treeWidgetFactory_(treeWidgetFactory), settings_(settings), xmppRosterController_(NULL), rosterController_(NULL), loginWindow_(NULL), clientVersionResponder_(NULL), nickResolver_(NULL), discoResponder_(NULL), - serverDiscoInfo_(new DiscoInfo()), presenceOracle_(NULL) { + serverDiscoInfo_(new DiscoInfo()), presenceOracle_(NULL), avatarManager_(NULL) { application_ = application; + + avatarStorage_ = new AvatarFileStorage(application_->getAvatarDir()); + eventController_ = new EventController(); eventController_->onEventQueueLengthChange.connect(boost::bind(&MainController::handleEventQueueLengthChange, this, _1)); systemTrayController_ = new SystemTrayController(eventController_, systemTray); @@ -55,6 +60,7 @@ MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowF } MainController::~MainController() { + delete avatarManager_; delete discoResponder_; delete clientVersionResponder_; delete xmppRosterController_; @@ -69,6 +75,7 @@ MainController::~MainController() { delete nickResolver_; delete client_; delete systemTrayController_; + delete avatarStorage_; } void MainController::handleConnected() { @@ -97,6 +104,9 @@ void MainController::handleConnected() { clientVersionResponder_ = new SoftwareVersionResponder(CLIENT_NAME, CLIENT_VERSION, client_); loginWindow_->morphInto(rosterController_->getWindow()); + delete avatarManager_; + avatarManager_ = new AvatarManager(client_, client_, avatarStorage_); + DiscoInfo discoInfo; discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc")); capsInfo_ = boost::shared_ptr<CapsInfo>(new CapsInfo(CapsInfoGenerator(CLIENT_NODE).generateCapsInfo(discoInfo))); @@ -206,7 +216,7 @@ ChatController* MainController::getChatController(const JID &contact) { lookupContact = JID(contact.toBare()); } if (chatControllers_.find(lookupContact) == chatControllers_.end()) { - chatControllers_[contact] = new ChatController(client_, client_, chatWindowFactory_, contact, nickResolver_, presenceOracle_); + chatControllers_[contact] = new ChatController(client_, client_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_); chatControllers_[contact]->setAvailableServerFeatures(serverDiscoInfo_); lookupContact = contact; } @@ -219,7 +229,7 @@ void MainController::handleChatControllerJIDChanged(const JID& from, const JID& } void MainController::handleJoinMUCRequest(const JID &muc, const String &nick) { - mucControllers_[muc] = new MUCController(muc, nick, client_, client_, chatWindowFactory_, treeWidgetFactory_, presenceOracle_); + mucControllers_[muc] = new MUCController(muc, nick, client_, client_, chatWindowFactory_, treeWidgetFactory_, presenceOracle_, avatarManager_); mucControllers_[muc]->setAvailableServerFeatures(serverDiscoInfo_); } diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index 8b3a702..aa6a85b 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -19,6 +19,7 @@ #include <vector> namespace Swift { + class AvatarStorage; class Application; class Client; class ChatWindowFactory; @@ -30,6 +31,7 @@ namespace Swift { class RosterController; class XMPPRosterController; class DiscoInfoResponder; + class AvatarManager; class LoginWindow; class EventLoop; class SoftwareVersionResponder; @@ -68,6 +70,7 @@ namespace Swift { TreeWidgetFactory* treeWidgetFactory_; SettingsProvider *settings_; Application* application_; + AvatarStorage* avatarStorage_; ChatController* chatController_; XMPPRosterController* xmppRosterController_; RosterController* rosterController_; @@ -82,6 +85,7 @@ namespace Swift { boost::shared_ptr<DiscoInfo> serverDiscoInfo_; PresenceOracle* presenceOracle_; SystemTrayController* systemTrayController_; + AvatarManager* avatarManager_; }; } #endif diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp index 5b63e55..8e916c3 100644 --- a/Swift/QtUI/QtChatWindow.cpp +++ b/Swift/QtUI/QtChatWindow.cpp @@ -126,7 +126,7 @@ void QtChatWindow::updateTitleWithUnreadCount() { emit titleUpdated(); } -void QtChatWindow::addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label) { +void QtChatWindow::addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath) { if (isActiveWindow()) { onAllMessagesRead(); } @@ -141,7 +141,7 @@ void QtChatWindow::addMessage(const String &message, const String &senderName, b htmlString += messageHTML; bool appendToPrevious = !previousMessageWasSystem_ && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_ && previousSenderName_ == P2QSTRING(senderName))); - messageLog_->addMessage(MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), QDateTime::currentDateTime(), "qrc:/icons/avatar.png", senderIsSelf, appendToPrevious)); + messageLog_->addMessage(MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), QDateTime::currentDateTime(), (avatarPath.isEmpty() ? "qrc:/icons/avatar.png" : "file://" + P2QSTRING(avatarPath)), senderIsSelf, appendToPrevious)); previousMessageWasSelf_ = senderIsSelf; previousSenderName_ = P2QSTRING(senderName); diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h index bbb1a7e..20a53b9 100644 --- a/Swift/QtUI/QtChatWindow.h +++ b/Swift/QtUI/QtChatWindow.h @@ -18,7 +18,7 @@ namespace Swift { Q_OBJECT public: QtChatWindow(const QString &contact, QtTreeWidgetFactory* treeWidgetFactory); - void addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label); + void addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath); void addSystemMessage(const String& message); void addErrorMessage(const String& errorMessage); void show(); diff --git a/Swiften/Application/Application.cpp b/Swiften/Application/Application.cpp index e21d9e7..6ffb46f 100644 --- a/Swiften/Application/Application.cpp +++ b/Swiften/Application/Application.cpp @@ -17,6 +17,10 @@ boost::filesystem::path Application::getSettingsFileName() const { return getSettingsDir() / "settings"; } +boost::filesystem::path Application::getAvatarDir() const { + return getSettingsDir() / "avatars"; +} + boost::filesystem::path Application::getHomeDir() const { // FIXME: Does this work on windows? char* homeDirRaw = getenv("HOME"); diff --git a/Swiften/Application/Application.h b/Swiften/Application/Application.h index 4fda7af..a65b1de 100644 --- a/Swiften/Application/Application.h +++ b/Swiften/Application/Application.h @@ -14,6 +14,7 @@ namespace Swift { virtual ~Application(); boost::filesystem::path getSettingsFileName() const; + boost::filesystem::path getAvatarDir() const; boost::filesystem::path getHomeDir() const; virtual boost::filesystem::path getSettingsDir() const = 0; boost::filesystem::path getProfileDir(const String& profile) const; diff --git a/Swiften/Avatars/AvatarFileStorage.cpp b/Swiften/Avatars/AvatarFileStorage.cpp new file mode 100644 index 0000000..1348018 --- /dev/null +++ b/Swiften/Avatars/AvatarFileStorage.cpp @@ -0,0 +1,26 @@ +#include "Swiften/Avatars/AvatarFileStorage.h" + +#include <iostream> +#include <boost/filesystem/fstream.hpp> + +namespace Swift { + +AvatarFileStorage::AvatarFileStorage(const boost::filesystem::path& path) : path_(path) { + boost::filesystem::create_directory(path_); +} + +bool AvatarFileStorage::hasAvatar(const String& hash) const { + return boost::filesystem::exists(getAvatarPath(hash)); +} + +void AvatarFileStorage::addAvatar(const String& hash, const ByteArray& avatar) { + boost::filesystem::ofstream file(getAvatarPath(hash), boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out); + file.write(avatar.getData(), avatar.getSize()); + file.close(); +} + +boost::filesystem::path AvatarFileStorage::getAvatarPath(const String& hash) const { + return path_ / hash.getUTF8String(); +} + +} diff --git a/Swiften/Avatars/AvatarFileStorage.h b/Swiften/Avatars/AvatarFileStorage.h new file mode 100644 index 0000000..1afa703 --- /dev/null +++ b/Swiften/Avatars/AvatarFileStorage.h @@ -0,0 +1,24 @@ +#pragma once + +#include <map> +#include <boost/filesystem.hpp> + +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/Avatars/AvatarStorage.h" + +namespace Swift { + class AvatarFileStorage : public AvatarStorage { + public: + AvatarFileStorage(const boost::filesystem::path& path); + + virtual bool hasAvatar(const String& hash) const; + virtual void addAvatar(const String& hash, const ByteArray& avatar); + + virtual boost::filesystem::path getAvatarPath(const String& hash) const; + + private: + boost::filesystem::path path_; + }; + +} diff --git a/Swiften/Avatars/AvatarManager.cpp b/Swiften/Avatars/AvatarManager.cpp new file mode 100644 index 0000000..f0b04b9 --- /dev/null +++ b/Swiften/Avatars/AvatarManager.cpp @@ -0,0 +1,65 @@ +#include "Swiften/Avatars/AvatarManager.h" + +#include <boost/bind.hpp> + +#include "Swiften/Client/StanzaChannel.h" +#include "Swiften/Elements/VCardUpdate.h" +#include "Swiften/Queries/Requests/GetVCardRequest.h" +#include "Swiften/StringCodecs/SHA1.h" +#include "Swiften/Avatars/AvatarStorage.h" + +namespace Swift { + +AvatarManager::AvatarManager(StanzaChannel* stanzaChannel, IQRouter* iqRouter, AvatarStorage* avatarStorage) : stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), avatarStorage_(avatarStorage) { + stanzaChannel->onPresenceReceived.connect(boost::bind(&AvatarManager::handlePresenceReceived, this, _1)); +} + +void AvatarManager::handlePresenceReceived(boost::shared_ptr<Presence> presence) { + boost::shared_ptr<VCardUpdate> update = presence->getPayload<VCardUpdate>(); + if (!update) { + return; + } + JID from = presence->getFrom().toBare(); + String& hash = avatarHashes_[from]; + if (hash != update->getPhotoHash()) { + hash = update->getPhotoHash(); + if (!avatarStorage_->hasAvatar(hash)) { + boost::shared_ptr<GetVCardRequest> request(new GetVCardRequest(from, iqRouter_)); + request->onResponse.connect(boost::bind(&AvatarManager::handleVCardReceived, this, from, _1, _2)); + request->send(); + } + else { + onAvatarChanged(from, hash); + } + } +} + +void AvatarManager::handleVCardReceived(JID from, boost::shared_ptr<VCard> vCard, const boost::optional<Error>& error) { + if (error) { + // FIXME: What to do here? + return; + } + String hash = SHA1::getHexHash(vCard->getPhoto()); + avatarStorage_->addAvatar(hash, vCard->getPhoto()); + onAvatarChanged(from, hash); +} + +String AvatarManager::getAvatarHash(const JID& jid) const { + std::map<JID, String>::const_iterator i = avatarHashes_.find(jid.toBare()); + if (i != avatarHashes_.end()) { + return i->second; + } + else { + return ""; + } +} + +boost::filesystem::path AvatarManager::getAvatarPath(const JID& jid) const { + String hash = getAvatarHash(jid); + if (!hash.isEmpty()) { + return avatarStorage_->getAvatarPath(hash); + } + return boost::filesystem::path(); +} + +} diff --git a/Swiften/Avatars/AvatarManager.h b/Swiften/Avatars/AvatarManager.h new file mode 100644 index 0000000..0085405 --- /dev/null +++ b/Swiften/Avatars/AvatarManager.h @@ -0,0 +1,39 @@ +#pragma once + +#include <boost/filesystem.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> +#include <boost/signal.hpp> +#include <map> + +#include "Swiften/JID/JID.h" +#include "Swiften/Elements/Presence.h" +#include "Swiften/Elements/VCard.h" +#include "Swiften/Elements/Error.h" + +namespace Swift { + class AvatarStorage; + class StanzaChannel; + class IQRouter; + + class AvatarManager { + public: + AvatarManager(StanzaChannel*, IQRouter*, AvatarStorage*); + + String getAvatarHash(const JID&) const; + boost::filesystem::path getAvatarPath(const JID&) const; + + public: + boost::signal<void (const JID&, const String&)> onAvatarChanged; + + private: + void handlePresenceReceived(boost::shared_ptr<Presence>); + void handleVCardReceived(JID from, boost::shared_ptr<VCard>, const boost::optional<Error>&); + + private: + StanzaChannel* stanzaChannel_; + IQRouter* iqRouter_; + AvatarStorage* avatarStorage_; + std::map<JID, String> avatarHashes_; + }; +} diff --git a/Swiften/Avatars/AvatarStorage.cpp b/Swiften/Avatars/AvatarStorage.cpp new file mode 100644 index 0000000..4c98314 --- /dev/null +++ b/Swiften/Avatars/AvatarStorage.cpp @@ -0,0 +1,8 @@ +#include "Swiften/Avatars/AvatarStorage.h" + +namespace Swift { + +AvatarStorage::~AvatarStorage() { +} + +} diff --git a/Swiften/Avatars/AvatarStorage.h b/Swiften/Avatars/AvatarStorage.h new file mode 100644 index 0000000..b5c0f32 --- /dev/null +++ b/Swiften/Avatars/AvatarStorage.h @@ -0,0 +1,18 @@ +#pragma once + +#include <boost/filesystem.hpp> + +namespace Swift { + class String; + class ByteArray; + + class AvatarStorage { + public: + virtual ~AvatarStorage(); + + virtual bool hasAvatar(const String& hash) const = 0; + virtual void addAvatar(const String& hash, const ByteArray& avatar) = 0; + virtual boost::filesystem::path getAvatarPath(const String& hash) const = 0; + }; + +} diff --git a/Swiften/Avatars/Makefile.inc b/Swiften/Avatars/Makefile.inc new file mode 100644 index 0000000..4887a49 --- /dev/null +++ b/Swiften/Avatars/Makefile.inc @@ -0,0 +1,6 @@ +SWIFTEN_SOURCES += \ + Swiften/Avatars/AvatarManager.cpp \ + Swiften/Avatars/AvatarStorage.cpp \ + Swiften/Avatars/AvatarFileStorage.cpp + +include Swiften/Avatars/UnitTest/Makefile.inc diff --git a/Swiften/Avatars/UnitTest/Makefile.inc b/Swiften/Avatars/UnitTest/Makefile.inc new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Swiften/Avatars/UnitTest/Makefile.inc diff --git a/Swiften/Makefile.inc b/Swiften/Makefile.inc index ce14110..4b09bf3 100644 --- a/Swiften/Makefile.inc +++ b/Swiften/Makefile.inc @@ -20,6 +20,7 @@ include Swiften/Disco/Makefile.inc include Swiften/Presence/Makefile.inc include Swiften/Notifier/Makefile.inc include Swiften/History/Makefile.inc +include Swiften/Avatars/Makefile.inc CPPFLAGS += $(SQLITE_CPPFLAGS) diff --git a/Swiften/Queries/Requests/GetVCardRequest.h b/Swiften/Queries/Requests/GetVCardRequest.h new file mode 100644 index 0000000..e403096 --- /dev/null +++ b/Swiften/Queries/Requests/GetVCardRequest.h @@ -0,0 +1,16 @@ +#pragma once + +#include <cassert> + +#include "Swiften/Queries/GenericRequest.h" +#include "Swiften/Elements/VCard.h" + +namespace Swift { + class GetVCardRequest : public GenericRequest<VCard> { + public: + GetVCardRequest(const JID& jid, IQRouter* router) : + GenericRequest<VCard>(IQ::Get, jid, boost::shared_ptr<Payload>(new VCard()), router) { + assert(jid.isBare()); + } + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp index 9799802..f9a0789 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp @@ -15,6 +15,7 @@ #include "Swiften/Serializer/PayloadSerializers/StartSessionSerializer.h" #include "Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h" #include "Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h" +#include "Swiften/Serializer/PayloadSerializers/VCardSerializer.h" namespace Swift { @@ -33,6 +34,7 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new StartSessionSerializer()); serializers_.push_back(new SecurityLabelSerializer()); serializers_.push_back(new SecurityLabelsCatalogSerializer()); + serializers_.push_back(new VCardSerializer()); foreach(PayloadSerializer* serializer, serializers_) { addSerializer(serializer); } diff --git a/Swiften/Serializer/PayloadSerializers/Makefile.inc b/Swiften/Serializer/PayloadSerializers/Makefile.inc index 61f603a..893da6c 100644 --- a/Swiften/Serializer/PayloadSerializers/Makefile.inc +++ b/Swiften/Serializer/PayloadSerializers/Makefile.inc @@ -8,6 +8,7 @@ SWIFTEN_SOURCES += \ Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.cpp \ Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.cpp \ Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.cpp \ - Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp + Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp \ + Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp include Swiften/Serializer/PayloadSerializers/UnitTest/Makefile.inc diff --git a/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp b/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp new file mode 100644 index 0000000..ce4e399 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp @@ -0,0 +1,18 @@ +#include "Swiften/Serializer/PayloadSerializers/VCardSerializer.h" + +#include <boost/shared_ptr.hpp> + +#include "Swiften/Serializer/XML/XMLElement.h" + +namespace Swift { + +VCardSerializer::VCardSerializer() : GenericPayloadSerializer<VCard>() { +} + +String VCardSerializer::serializePayload(boost::shared_ptr<VCard> discoInfo) const { + XMLElement queryElement("vCard", "vcard-temp"); + // TODO + return queryElement.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/VCardSerializer.h b/Swiften/Serializer/PayloadSerializers/VCardSerializer.h new file mode 100644 index 0000000..baf5947 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/VCardSerializer.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Swiften/Serializer/GenericPayloadSerializer.h" +#include "Swiften/Elements/VCard.h" + +namespace Swift { + class VCardSerializer : public GenericPayloadSerializer<VCard> { + public: + VCardSerializer(); + + virtual String serializePayload(boost::shared_ptr<VCard>) const; + }; +} |