From 225957b2f622f0f69add99aa3928a49de839bd7d Mon Sep 17 00:00:00 2001 From: plfiorini Date: Sun, 30 May 2010 04:26:36 +0000 Subject: [PATCH] Support avatar images for contacts. --- protocols/xmpp/JabberHandler.cpp | 160 +++++++++++++++++++++++++++++-- protocols/xmpp/JabberHandler.h | 17 +++- protocols/xmpp/Jamfile | 9 +- 3 files changed, 175 insertions(+), 11 deletions(-) diff --git a/protocols/xmpp/JabberHandler.cpp b/protocols/xmpp/JabberHandler.cpp index 1f5c196..3b00c3a 100644 --- a/protocols/xmpp/JabberHandler.cpp +++ b/protocols/xmpp/JabberHandler.cpp @@ -6,10 +6,16 @@ * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com */ -//#include +#include +#include +#include +#include +#include #include +#include + #include "JabberHandler.h" @@ -31,6 +37,7 @@ JabberHandler::JabberHandler() fClient(NULL), fVCardManager(NULL) { + fAvatars = new BList(); } @@ -38,6 +45,11 @@ JabberHandler::~JabberHandler() { fVCardManager->cancelVCardOperations(this); Shutdown(); + + BString* item = NULL; + for (int32 i = 0; (item = (BString*)fAvatars->ItemAt(i)); i++) + delete item; + delete fAvatars; } @@ -204,6 +216,138 @@ JabberHandler::_MessageSent(const char* id, const char* subject, } +status_t +JabberHandler::_SetupAvatarCache() +{ + if (fAvatarCachePath.InitCheck() == B_OK) + return B_OK; + + BPath path; + + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) + return B_ERROR; + + path.Append("Caya"); + path.Append("Cache"); + path.Append(kProtocolSignature); + + if (create_directory(path.Path(), 0755) != B_OK) + return B_ERROR; + + fCachePath = path; + + path.Append("avatar-cache"); + + BFile file(path.Path(), B_READ_ONLY); + fAvatarCache.Unflatten(&file); + + fAvatarCachePath = path; + + return B_OK; +} + + +status_t +JabberHandler::_SaveAvatarCache() +{ + if (fAvatarCachePath.InitCheck() != B_OK) + return B_ERROR; + + BFile file(fAvatarCachePath.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE); + return fAvatarCache.Flatten(&file); +} + + +void +JabberHandler::_CacheAvatar(const char* id, const char* binimage, size_t length) +{ + if (!id || !binimage || length <= 0) + return; + + // Calculate avatar hash + CSHA1 s1; + char hash[256]; + s1.Reset(); + s1.Update((uchar*)binimage, length); + s1.Final(); + s1.ReportHash(hash, CSHA1::REPORT_HEX); + + BString sha1; + sha1.SetTo(hash, 256); + + BString oldSha1; + if (fAvatarCache.FindString("id", &oldSha1) != B_OK || oldSha1 == "" || sha1 != oldSha1) { + // Replace old hash and save cache + fAvatarCache.RemoveName(id); + fAvatarCache.AddString(id, sha1); + _SaveAvatarCache(); + + if (oldSha1 != "") { + BPath path(fCachePath); + path.Append(oldSha1); + + // Remove old image file + BEntry entry(path.Path()); + entry.Remove(); + + // Remove old hash from the list + BString* item = NULL; + for (int32 i = 0; (item = (BString*)fAvatars->ItemAt(i)); i++) { + if (item->Compare(oldSha1) == 0) { + fAvatars->RemoveItem(item); + break; + } + } + } + } + + // Determine file path + BPath path(fCachePath); + path.Append(sha1); + + BEntry entry(path.Path()); + if (!entry.Exists()) { + // Save to file + BFile file(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE); + file.Write(binimage, length); + } + + // Do we need to notify Caya? + bool found = false; + BString* item = NULL; + for (int32 i = 0; (item = (BString*)fAvatars->ItemAt(i)); i++) { + if (item->Compare(sha1) == 0) { + found = true; + break; + } + } + + if (!found) { + // Add new hash to the list if needed + fAvatars->AddItem(new BString(sha1)); + + // Notify Caya that the avatar has changed + _AvatarChanged(id, path.Path()); + } +} + + +void +JabberHandler::_AvatarChanged(const char* id, const char* filename) +{ + entry_ref ref; + if (get_ref_for_path(filename, &ref) != B_OK) + return; + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_AVATAR_SET); + msg.AddString("protocol", kProtocolSignature); + msg.AddString("id", id); + msg.AddRef("ref", &ref); + fServerMessenger->SendMessage(&msg); +} + + CayaStatus JabberHandler::_GlooxStatusToCaya(gloox::Presence::PresenceType type) { @@ -456,11 +600,6 @@ JabberHandler::handleVCard(const gloox::JID& jid, const gloox::VCard* card) std::string fullName = name.family + " " + name.given; -#if 0 - BString decoded - = Base64::Decode(BString(photo.binval.c_str())); -#endif - BMessage msg(IM_MESSAGE); msg.AddInt32("im_what", IM_EXTENDED_CONTACT_INFO); msg.AddString("protocol", kProtocolSignature); @@ -473,6 +612,15 @@ JabberHandler::handleVCard(const gloox::JID& jid, const gloox::VCard* card) msg.AddString("suffix", name.suffix.c_str()); msg.AddString("full name", fullName.c_str()); fServerMessenger->SendMessage(&msg); + + // Return if there's no avatar icon + if (!photo.binval.c_str()) + return; + + if (_SetupAvatarCache() == B_OK) + // Cache avatar icon + _CacheAvatar(jid.bare().c_str(), photo.binval.c_str(), + photo.binval.length()); } diff --git a/protocols/xmpp/JabberHandler.h b/protocols/xmpp/JabberHandler.h index bde8582..0747322 100644 --- a/protocols/xmpp/JabberHandler.h +++ b/protocols/xmpp/JabberHandler.h @@ -5,6 +5,7 @@ #ifndef _JABBER_HANDLER_H #define _JABBER_HANDLER_H +#include #include #include @@ -21,8 +22,10 @@ #include #include -#include "CayaProtocol.h" -#include "CayaConstants.h" +#include +#include + +class BList; class JabberHandler : public CayaProtocol, gloox::RosterListener, gloox::ConnectionListener, gloox::LogHandler, gloox::MessageHandler, gloox::VCardHandler { @@ -66,10 +69,20 @@ private: thread_id fRecvThread; + BPath fCachePath; + BPath fAvatarCachePath; + BMessage fAvatarCache; + BList* fAvatars; + void _MessageSent(const char* id, const char* subject, const char* body); CayaStatus _GlooxStatusToCaya(gloox::Presence::PresenceType type); + status_t _SetupAvatarCache(); + status_t _SaveAvatarCache(); + void _CacheAvatar(const char* id, const char* binval, size_t length); + void _AvatarChanged(const char*id, const char* filename); + virtual void onConnect(); virtual void onDisconnect(gloox::ConnectionError); virtual bool onTLSConnect(const gloox::CertInfo&); diff --git a/protocols/xmpp/Jamfile b/protocols/xmpp/Jamfile index abc0e2c..34351ec 100644 --- a/protocols/xmpp/Jamfile +++ b/protocols/xmpp/Jamfile @@ -9,7 +9,7 @@ AddOn jabber : JabberMain.cpp JabberProtocol.cpp JabberHandler.cpp - : be libgloox.a network ssl crypto z $(TARGET_LIBSTDC++) + : be libsupport.a libgloox.a network ssl crypto z $(TARGET_LIBSTDC++) : jabber.rdef jabber_settings.rdef ; @@ -17,7 +17,7 @@ AddOn gtalk : GoogleTalkMain.cpp GoogleTalkProtocol.cpp JabberHandler.cpp - : be libgloox.a network ssl crypto z $(TARGET_LIBSTDC++) + : be libsupport.a libgloox.a network ssl crypto z $(TARGET_LIBSTDC++) : gtalk.rdef gtalk_settings.rdef ; @@ -25,12 +25,15 @@ AddOn facebook : FacebookMain.cpp FacebookProtocol.cpp JabberHandler.cpp - : be libgloox.a network ssl crypto z $(TARGET_LIBSTDC++) + : be libsupport.a libgloox.a network ssl crypto z $(TARGET_LIBSTDC++) : facebook.rdef facebook_settings.rdef ; +Depends jabber : libsupport.a ; Depends jabber : libgloox.a ; +Depends gtalk : libsupport.a ; Depends gtalk : libgloox.a ; +Depends facebook : libsupport.a ; Depends facebook : libgloox.a ; LINKFLAGS on jabber += -L$(OPENSSL_LIBRARY_DIR) ;