# HG changeset patch # User Richard Laager # Date 1177537736 0 # Node ID 4fc51a87ce42b8eac005e7b228d90c5fadd5774e # Parent 493ca924c19991233311ae9c92dc1fc3ea31d500 Updates for the account buddy icon stuff. This doesn't yet work fully (and maybe not even partly), but it compiles. diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/account.c --- a/libpurple/account.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/account.c Wed Apr 25 21:48:56 2007 +0000 @@ -347,12 +347,6 @@ xmlnode_insert_data(child, tmp, -1); } - if ((tmp = purple_account_get_buddy_icon(account)) != NULL) - { - child = xmlnode_new_child(node, "buddyicon"); - xmlnode_insert_data(child, tmp, -1); - } - if (g_hash_table_size(account->settings) > 0) { child = xmlnode_new_child(node, "settings"); @@ -742,11 +736,11 @@ g_free(data); } - /* Read the buddyicon */ + /* Read an old buddyicon */ child = xmlnode_get_child(node, "buddyicon"); if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL)) { - purple_account_set_buddy_icon(ret, data); + // TODO: Read the file and cache it using the new system g_free(data); } @@ -880,7 +874,6 @@ g_free(account->alias); g_free(account->password); g_free(account->user_info); - g_free(account->buddy_icon); g_free(account->buddy_icon_path); g_free(account->protocol_id); @@ -1316,56 +1309,6 @@ schedule_accounts_save(); } -void -purple_account_set_buddy_icon(PurpleAccount *account, const char *icon) -{ - g_return_if_fail(account != NULL); - - /* Delete an existing icon from the cache. */ - if (account->buddy_icon != NULL && (icon == NULL || strcmp(account->buddy_icon, icon))) - { - const char *dirname = purple_buddy_icons_get_cache_dir(); - - if (g_file_test(account->buddy_icon, G_FILE_TEST_IS_REGULAR)) - { - /* The file exists. This is a full path. */ - - /* XXX: This is a hack so we only delete the file if it's - * in the cache dir. Otherwise, people who upgrade (who - * may have buddy icon filenames set outside of the cache - * dir) could lose files. */ - if (!strncmp(dirname, account->buddy_icon, strlen(dirname))) - g_unlink(account->buddy_icon); - } - else - { - char *filename = g_build_filename(dirname, account->buddy_icon, NULL); - g_unlink(filename); - g_free(filename); - } - } - - g_free(account->buddy_icon); - account->buddy_icon = g_strdup(icon); - if (purple_account_is_connected(account)) - { - PurpleConnection *gc; - PurplePluginProtocolInfo *prpl_info; - - gc = purple_account_get_connection(account); - prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); - - if (prpl_info && prpl_info->set_buddy_icon) - { - char *cached_path = purple_buddy_icons_get_full_path(icon); - prpl_info->set_buddy_icon(gc, cached_path); - g_free(cached_path); - } - } - - schedule_accounts_save(); -} - void purple_account_set_buddy_icon_path(PurpleAccount *account, const char *path) { g_return_if_fail(account != NULL); @@ -1741,14 +1684,6 @@ } const char * -purple_account_get_buddy_icon(const PurpleAccount *account) -{ - g_return_val_if_fail(account != NULL, NULL); - - return account->buddy_icon; -} - -const char * purple_account_get_buddy_icon_path(const PurpleAccount *account) { g_return_val_if_fail(account != NULL, NULL); @@ -2275,7 +2210,7 @@ purple_pounce_destroy_all_by_account(account); /* This will cause the deletion of an old buddy icon. */ - purple_account_set_buddy_icon(account, NULL); + purple_buddy_icons_set_account_icon(account, NULL, 0); purple_account_destroy(account); } diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/account.h --- a/libpurple/account.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/account.h Wed Apr 25 21:48:56 2007 +0000 @@ -75,7 +75,6 @@ char *password; /**< The account password. */ char *user_info; /**< User information. */ - char *buddy_icon; /**< The buddy icon's cached path. */ char *buddy_icon_path; /**< The buddy icon's non-cached path. */ gboolean remember_pass; /**< Remember the password. */ @@ -284,14 +283,6 @@ void purple_account_set_user_info(PurpleAccount *account, const char *user_info); /** - * Sets the account's buddy icon. - * - * @param account The account. - * @param icon The buddy icon file. - */ -void purple_account_set_buddy_icon(PurpleAccount *account, const char *icon); - -/** * Sets the account's buddy icon path. * * @param account The account. @@ -525,15 +516,6 @@ const char *purple_account_get_user_info(const PurpleAccount *account); /** - * Returns the account's buddy icon filename. - * - * @param account The account. - * - * @return The buddy icon filename. - */ -const char *purple_account_get_buddy_icon(const PurpleAccount *account); - -/** * Gets the account's buddy icon path. * * @param account The account. diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/buddyicon.c --- a/libpurple/buddyicon.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/buddyicon.c Wed Apr 25 21:48:56 2007 +0000 @@ -48,7 +48,11 @@ static GHashTable *account_cache = NULL; static GHashTable *icon_data_cache = NULL; static GHashTable *icon_file_cache = NULL; -static GHashTable *custom_icon_cache = NULL; + +/* This one is used for both custom buddy icons + * on PurpleContacts and account icons. */ +static GHashTable *pointer_icon_cache = NULL; + static char *cache_dir = NULL; static gboolean icon_caching = TRUE; @@ -215,7 +219,7 @@ /* We could make this O(1) by using another hash table, but * this is probably good enough. */ - g_hash_table_foreach_remove(custom_icon_cache, value_equals, img); + g_hash_table_foreach_remove(pointer_icon_cache, value_equals, img); } } @@ -514,6 +518,25 @@ } } +char *purple_buddy_icon_get_full_path(PurpleBuddyIcon *icon) +{ + char *path; + + g_return_val_if_fail(icon != NULL, NULL); + + if (icon->img == NULL) + return NULL; + + path = g_build_filename(purple_buddy_icons_get_cache_dir(), + purple_imgstore_get_filename(icon->img), NULL); + if (!g_file_test(path, G_FILE_TEST_EXISTS)) + { + g_free(path); + return NULL; + } + return path; +} + const char * purple_buddy_icons_get_checksum_for_user(PurpleBuddy *buddy) { @@ -607,6 +630,105 @@ } PurpleStoredImage * +purple_buddy_icons_find_account_icon(PurpleAccount *account) +{ + PurpleStoredImage *img; + const char *account_icon_file; + const char *dirname; + char *path; + guchar *data; + size_t len; + + g_return_val_if_fail(account != NULL, NULL); + + if ((img = g_hash_table_lookup(pointer_icon_cache, account))) + { + return purple_imgstore_ref(img); + } + + account_icon_file = purple_account_get_string(account, "buddy_icon", NULL); + + if (account_icon_file == NULL) + return NULL; + + dirname = purple_buddy_icons_get_cache_dir(); + path = g_build_filename(dirname, account_icon_file, NULL); + + if (read_icon_file(path, &data, &len)) + { + g_free(path); + img = purple_buddy_icon_data_new(data, len, account_icon_file); + g_free(data); + g_hash_table_insert(pointer_icon_cache, account, img); + return img; + } + g_free(path); + + return NULL; +} + +PurpleStoredImage * +purple_buddy_icons_set_account_icon(PurpleAccount *account, + guchar *icon_data, size_t icon_len) +{ + PurpleStoredImage *old_img; + PurpleStoredImage *img = NULL; + char *old_icon; + + old_img = g_hash_table_lookup(pointer_icon_cache, account); + + if (icon_data != NULL && icon_len > 0) + { + img = purple_buddy_icon_data_new(icon_data, icon_len, NULL); + g_free(icon_data); + } + + old_icon = g_strdup(purple_account_get_string(account, "buddy_icon", NULL)); + if (img && purple_buddy_icons_is_caching()) + { + const char *filename = purple_imgstore_get_filename(img); + purple_account_set_string(account, "buddy_icon", filename); + ref_filename(filename); + } + else + { + // TODO + // purple_account_remove_setting(account, "buddy_icon"); + } + unref_filename(old_icon); + + if (img) + g_hash_table_insert(pointer_icon_cache, account, img); + else + g_hash_table_remove(pointer_icon_cache, account); + + if (purple_account_is_connected(account)) + { + PurpleConnection *gc; + PurplePluginProtocolInfo *prpl_info; + + gc = purple_account_get_connection(account); + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); + + if (prpl_info && prpl_info->set_buddy_icon) + prpl_info->set_buddy_icon(gc, img); + } + + if (old_img) + purple_imgstore_unref(old_img); + else + { + /* The old icon may not have been loaded into memory. In that + * case, we'll need to uncache the filename. The filenames + * are ref-counted, so this is safe. */ + purple_buddy_icon_data_uncache_file(old_icon); + } + g_free(old_icon); + + return img; +} + +PurpleStoredImage * purple_buddy_icons_find_custom_icon(PurpleContact *contact) { PurpleStoredImage *img; @@ -618,7 +740,7 @@ g_return_val_if_fail(contact != NULL, NULL); - if ((img = g_hash_table_lookup(custom_icon_cache, contact))) + if ((img = g_hash_table_lookup(pointer_icon_cache, contact))) { return purple_imgstore_ref(img); } @@ -636,7 +758,7 @@ g_free(path); img = purple_buddy_icon_data_new(data, len, custom_icon_file); g_free(data); - g_hash_table_insert(custom_icon_cache, contact, img); + g_hash_table_insert(pointer_icon_cache, contact, img); return img; } g_free(path); @@ -644,7 +766,7 @@ return NULL; } -void +PurpleStoredImage * purple_buddy_icons_set_custom_icon(PurpleContact *contact, guchar *icon_data, size_t icon_len) { @@ -653,10 +775,13 @@ char *old_icon; PurpleBlistNode *child; - old_img = g_hash_table_lookup(custom_icon_cache, contact); + old_img = g_hash_table_lookup(pointer_icon_cache, contact); if (icon_data != NULL && icon_len > 0) + { img = purple_buddy_icon_data_new(icon_data, icon_len, NULL); + g_free(icon_data); + } old_icon = g_strdup(purple_blist_node_get_string((PurpleBlistNode *)contact, "custom_buddy_icon")); @@ -675,7 +800,10 @@ } unref_filename(old_icon); - g_hash_table_insert(custom_icon_cache, contact, img); + if (img) + g_hash_table_insert(pointer_icon_cache, contact, img); + else + g_hash_table_remove(pointer_icon_cache, contact); for (child = contact->node.child ; child ; child = child->next) { @@ -706,6 +834,8 @@ purple_buddy_icon_data_uncache_file(old_icon); } g_free(old_icon); + + return img; } void @@ -940,17 +1070,6 @@ return cache_dir; } -// TODO: Deal with this -char *purple_buddy_icons_get_full_path(const char *icon) { - if (icon == NULL) - return NULL; - - if (g_file_test(icon, G_FILE_TEST_IS_REGULAR)) - return g_strdup(icon); - else - return g_build_filename(purple_buddy_icons_get_cache_dir(), icon, NULL); -} - void * purple_buddy_icons_get_handle() { @@ -969,7 +1088,7 @@ icon_data_cache = g_hash_table_new(g_str_hash, g_str_equal); icon_file_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); - custom_icon_cache = g_hash_table_new(g_direct_hash, g_direct_equal); + pointer_icon_cache = g_hash_table_new(g_direct_hash, g_direct_equal); cache_dir = g_build_filename(purple_user_dir(), "icons", NULL); @@ -986,7 +1105,7 @@ g_hash_table_destroy(account_cache); g_hash_table_destroy(icon_data_cache); g_hash_table_destroy(icon_file_cache); - g_hash_table_destroy(custom_icon_cache); + g_hash_table_destroy(pointer_icon_cache); g_free(old_icons_dir); } diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/buddyicon.h --- a/libpurple/buddyicon.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/buddyicon.h Wed Apr 25 21:48:56 2007 +0000 @@ -36,8 +36,6 @@ extern "C" { #endif -// TODO: Deal with this. -char *purple_buddy_icons_get_full_path(const char *icon); /**************************************************************************/ /** @name Buddy Icon API */ @@ -151,6 +149,22 @@ */ const char *purple_buddy_icon_get_extension(const PurpleBuddyIcon *icon); +/** + * Returns a full path to an icon. + * + * If the icon has data and the file exists in the cache, this will return + * a full path to the cache file. + * + * In general, it is not appropriate to be poking in the icon cache + * directly. If you find yourself wanting to use this function, think + * very long and hard about it, and then don't. + * + * @param icon The buddy icon + * + * @return A full path to the file, or @c NULL under various conditions. + */ +char *purple_buddy_icon_get_full_path(PurpleBuddyIcon *icon); + /*@}*/ /**************************************************************************/ @@ -209,8 +223,47 @@ purple_buddy_icons_has_custom_icon(PurpleContact *contact); /** + * Returns the buddy icon image for an account. + * + * The caller owns a reference to the image in the store, and must dereference + * the image with purple_imgstore_unref() for it to be freed. + * + * This function deals with loading the icon from the cache, if + * needed, so it should be called in any case where you want the + * appropriate icon. + * + * @param account The account + * + * @return The account's buddy icon image. + */ +PurpleStoredImage * +purple_buddy_icons_find_account_icon(PurpleAccount *account); + +/** + * Sets a buddy icon for an account. + * + * This function will deal with saving a record of the icon, + * caching the data, etc. + * + * @param account The account for which to set a custom icon. + * @param icon_data The image data of the icon, which the + * buddy icon code will free. + * @param icon_len The length of the data in @a icon_data. + * + * @return The icon that was set. The caller does NOT own + * a reference to this, and must call purple_imgstore_ref() + * if it wants one. + */ +PurpleStoredImage * +purple_buddy_icons_set_account_icon(PurpleAccount *account, + guchar *icon_data, size_t icon_len); + +/** * Returns the custom buddy icon image for a contact. * + * The caller owns a reference to the image in the store, and must dereference + * the image with purple_imgstore_unref() for it to be freed. + * * This function deals with loading the icon from the cache, if * needed, so it should be called in any case where you want the * appropriate icon. @@ -229,10 +282,15 @@ * caching the data, etc. * * @param contact The contact for which to set a custom icon. - * @param icon_data The image data of the icon. + * @param icon_data The image data of the icon, which the + * buddy icon code will free. * @param icon_len The length of the data in @a icon_data. + * + * @return The icon that was set. The caller does NOT own + * a reference to this, and must call purple_imgstore_ref() + * if it wants one. */ -void +PurpleStoredImage * purple_buddy_icons_set_custom_icon(PurpleContact *contact, guchar *icon_data, size_t icon_len); diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/imgstore.c --- a/libpurple/imgstore.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/imgstore.c Wed Apr 25 21:48:56 2007 +0000 @@ -86,21 +86,29 @@ } gconstpointer purple_imgstore_get_data(PurpleStoredImage *img) { + g_return_val_if_fail(img != NULL, NULL); + return img->data; } size_t purple_imgstore_get_size(PurpleStoredImage *img) { + g_return_val_if_fail(img != NULL, 0); + return img->size; } const char *purple_imgstore_get_filename(PurpleStoredImage *img) { + g_return_val_if_fail(img != NULL, NULL); + return img->filename; } const char *purple_imgstore_get_extension(PurpleStoredImage *img) { + g_return_val_if_fail(img != NULL, NULL); + return purple_util_get_image_extension(img->data, img->size); } diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/imgstore.h --- a/libpurple/imgstore.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/imgstore.h Wed Apr 25 21:48:56 2007 +0000 @@ -26,6 +26,8 @@ #ifndef _PURPLE_IMGSTORE_H_ #define _PURPLE_IMGSTORE_H_ +#include + struct _PurpleStoredImage; typedef struct _PurpleStoredImage PurpleStoredImage; diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/jabber/buddy.c Wed Apr 25 21:48:56 2007 +0000 @@ -383,7 +383,6 @@ JabberIq *iq; JabberStream *js = gc->proto_data; xmlnode *vc_node; - char *avatar_file = NULL; struct tag_attr *tag_attr; g_free(js->avatar_hash); @@ -393,7 +392,6 @@ * Send only if there's actually any *information* to send */ vc_node = info ? xmlnode_from_str(info, -1) : NULL; - avatar_file = purple_buddy_icons_get_full_path(purple_account_get_buddy_icon(gc->account)); if(!vc_node) { vc_node = xmlnode_new("vCard"); @@ -403,27 +401,29 @@ if (vc_node->name && !g_ascii_strncasecmp(vc_node->name, "vCard", 5)) { - GError *error = NULL; - gchar *avatar_data_tmp; - guchar *avatar_data; - gsize avatar_len; + PurpleStoredImage *img; - if(avatar_file && g_file_get_contents(avatar_file, &avatar_data_tmp, &avatar_len, &error)) { + if ((img = purple_buddy_icons_find_account_icon(gc->account))) { + gconstpointer avatar_data; + gsize avatar_len; xmlnode *photo, *binval; gchar *enc; int i; unsigned char hashval[20]; char *p, hash[41]; - avatar_data = (guchar *) avatar_data_tmp; + avatar_data = purple_imgstore_get_data(img); + avatar_len = purple_imgstore_get_size(img); photo = xmlnode_new_child(vc_node, "PHOTO"); binval = xmlnode_new_child(photo, "BINVAL"); enc = purple_base64_encode(avatar_data, avatar_len); - purple_cipher_digest_region("sha1", (guchar *)avatar_data, + purple_cipher_digest_region("sha1", avatar_data, avatar_len, sizeof(hashval), hashval, NULL); + purple_imgstore_unref(img); + p = hash; for(i=0; i<20; i++, p+=2) snprintf(p, 3, "%02x", hashval[i]); @@ -431,11 +431,7 @@ xmlnode_insert_data(binval, enc, -1); g_free(enc); - g_free(avatar_data); - } else if (error != NULL) { - g_error_free(error); } - g_free(avatar_file); iq = jabber_iq_new(js, JABBER_IQ_SET); xmlnode_insert_child(iq->node, vc_node); @@ -445,7 +441,7 @@ } } -void jabber_set_buddy_icon(PurpleConnection *gc, const char *iconfile) +void jabber_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) { PurplePresence *gpresence; PurpleStatus *status; diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/jabber/buddy.h --- a/libpurple/protocols/jabber/buddy.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/jabber/buddy.h Wed Apr 25 21:48:56 2007 +0000 @@ -91,7 +91,7 @@ void jabber_set_info(PurpleConnection *gc, const char *info); void jabber_setup_set_info(PurplePluginAction *action); -void jabber_set_buddy_icon(PurpleConnection *gc, const char *iconfile); +void jabber_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img); const char *jabber_buddy_state_get_name(JabberBuddyState state); const char *jabber_buddy_state_get_status_id(JabberBuddyState state); diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/msn/msn.c --- a/libpurple/protocols/msn/msn.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/msn/msn.c Wed Apr 25 21:48:56 2007 +0000 @@ -1290,7 +1290,7 @@ } static void -msn_set_buddy_icon(PurpleConnection *gc, const char *filename) +msn_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) { MsnSession *session; MsnUser *user; @@ -1298,7 +1298,7 @@ session = gc->proto_data; user = session->user; - msn_user_set_buddy_icon(user, filename); + msn_user_set_buddy_icon(user, img); msn_change_status(session); } diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/msn/object.c --- a/libpurple/protocols/msn/object.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/msn/object.c Wed Apr 25 21:48:56 2007 +0000 @@ -111,11 +111,12 @@ g_free(obj->creator); g_free(obj->location); - g_free(obj->real_location); g_free(obj->friendly); g_free(obj->sha1d); g_free(obj->sha1c); + purple_imgstore_unref(obj->img); + if (obj->local) local_objs = g_list_remove(local_objs, obj); @@ -317,21 +318,19 @@ } void -msn_object_set_real_location(MsnObject *obj, const char *real_location) +msn_object_set_image(MsnObject *obj, PurpleStoredImage *img) { g_return_if_fail(obj != NULL); + g_return_if_fail(img != NULL); /* obj->local = TRUE; */ - if (obj->real_location != NULL) - g_free(obj->real_location); - - obj->real_location = - (real_location == NULL ? NULL : g_strdup(real_location)); + purple_imgstore_unref(obj->img); + obj->img = purple_imgstore_ref(img); } -const char * -msn_object_get_real_location(const MsnObject *obj) +PurpleStoredImage * +msn_object_get_image(const MsnObject *obj) { MsnObject *local_obj; @@ -340,7 +339,7 @@ local_obj = msn_object_find_local(msn_object_get_sha1(obj)); if (local_obj != NULL) - return local_obj->real_location; + return local_obj->img; return NULL; } diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/msn/object.h --- a/libpurple/protocols/msn/object.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/msn/object.h Wed Apr 25 21:48:56 2007 +0000 @@ -24,6 +24,8 @@ #ifndef _MSN_OBJECT_H_ #define _MSN_OBJECT_H_ +#include "imgstore.h" + #include "internal.h" typedef enum @@ -44,7 +46,7 @@ char *creator; int size; MsnObjectType type; - char *real_location; + PurpleStoredImage *img; char *location; char *friendly; char *sha1d; @@ -134,6 +136,14 @@ void msn_object_set_sha1c(MsnObject *obj, const char *sha1c); /** + * Associates an image with a MsnObject. + * + * @param obj The object. + * @param img The image to associate. + */ +void msn_object_set_image(MsnObject *obj, PurpleStoredImage *img); + +/** * Returns a MsnObject's creator value. * * @param obj The object. @@ -205,9 +215,15 @@ */ const char *msn_object_get_sha1(const MsnObject *obj); +/** + * Returns the image associated with the MsnObject. + * + * @param obj The object. + * + * @return The associated image. + */ +PurpleStoredImage *msn_object_get_image(const MsnObject *obj); + void msn_object_set_local(MsnObject *obj); -const char *msn_object_get_real_location(const MsnObject *obj); -void msn_object_set_real_location(MsnObject *obj, - const char *real_location); #endif /* _MSN_OBJECT_H_ */ diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/msn/session.c --- a/libpurple/protocols/msn/session.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/msn/session.c Wed Apr 25 21:48:56 2007 +0000 @@ -384,7 +384,7 @@ { PurpleAccount *account; PurpleConnection *gc; - char *icon; + PurpleStoredImage *img; if (session->logged_in) return; @@ -392,9 +392,9 @@ account = session->account; gc = purple_account_get_connection(account); - icon = purple_buddy_icons_get_full_path(purple_account_get_buddy_icon(session->account)); - msn_user_set_buddy_icon(session->user, icon); - g_free(icon); + img = purple_buddy_icons_find_account_icon(session->account); + msn_user_set_buddy_icon(session->user, img); + purple_imgstore_unref(img); session->logged_in = TRUE; diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/msn/slp.c --- a/libpurple/protocols/msn/slp.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/msn/slp.c Wed Apr 25 21:48:56 2007 +0000 @@ -248,14 +248,14 @@ if (!strcmp(euf_guid, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6")) { /* Emoticon or UserDisplay */ + char *content; + gsize len; MsnSlpSession *slpsession; MsnSlpLink *slplink; MsnSlpMessage *slpmsg; MsnObject *obj; char *msnobj_data; - const char *file_name; - char *content; - gsize len; + PurpleStoredImage *img; int type; /* Send Ok */ @@ -281,9 +281,8 @@ g_return_if_reached(); } - file_name = msn_object_get_real_location(obj); - - if (file_name == NULL) + img = msn_object_get_image(obj); + if (img == NULL) { purple_debug_error("msn", "Wrong object.\n"); msn_object_destroy(obj); @@ -314,7 +313,7 @@ #ifdef MSN_DEBUG_SLP slpmsg->info = "SLP DATA"; #endif - msn_slpmsg_open_file(slpmsg, file_name); + msn_slpmsg_set_image(slpmsg, img); msn_slplink_queue_slpmsg(slplink, slpmsg); } else if (!strcmp(euf_guid, "5D3E02AB-6190-11D3-BBBB-00C04F795683")) @@ -1075,8 +1074,8 @@ else { MsnObject *my_obj = NULL; - gchar *data = NULL; - gsize len = 0; + gconstpointer data = NULL; + size_t len = 0; #ifdef MSN_DEBUG_UD purple_debug_info("msn", "Requesting our own user display\n"); @@ -1086,14 +1085,12 @@ if (my_obj != NULL) { - const char *filename = msn_object_get_real_location(my_obj); - - if (filename != NULL) - g_file_get_contents(filename, &data, &len, NULL); + PurpleStoredImage *img = msn_object_get_image(my_obj); + data = purple_imgstore_get_data(img); + len = purple_imgstore_get_size(img); } - purple_buddy_icons_set_for_user(account, user->passport, (void *)data, len, info); - g_free(data); + purple_buddy_icons_set_for_user(account, user->passport, data, len, info); /* Free one window slot */ session->userlist->buddy_icon_window++; diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/msn/slpmsg.c --- a/libpurple/protocols/msn/slpmsg.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/msn/slpmsg.c Wed Apr 25 21:48:56 2007 +0000 @@ -65,7 +65,11 @@ if (slpmsg->fp != NULL) fclose(slpmsg->fp); - if (slpmsg->buffer != NULL) + purple_imgstore_unref(slpmsg->img); + + /* We don't want to free the data of the PurpleStoredImage, + * but to avoid code duplication, it's sharing buffer. */ + if (slpmsg->img == NULL) g_free(slpmsg->buffer); #ifdef MSN_DEBUG_SLP @@ -101,6 +105,11 @@ msn_slpmsg_set_body(MsnSlpMessage *slpmsg, const char *body, long long size) { + /* We can only have one data source at a time. */ + g_return_if_fail(slpmsg->buffer); + g_return_if_fail(slpmsg->img); + g_return_if_fail(slpmsg->fp); + if (body != NULL) slpmsg->buffer = g_memdup(body, size); else @@ -110,10 +119,28 @@ } void +msn_slpmsg_set_image(MsnSlpMessage *slpmsg, PurpleStoredImage *img) +{ + /* We can only have one data source at a time. */ + g_return_if_fail(slpmsg->buffer); + g_return_if_fail(slpmsg->img); + g_return_if_fail(slpmsg->fp); + + slpmsg->img = purple_imgstore_ref(img); + slpmsg->buffer = (guchar *)purple_imgstore_get_data(img); + slpmsg->size = purple_imgstore_get_size(img); +} + +void msn_slpmsg_open_file(MsnSlpMessage *slpmsg, const char *file_name) { struct stat st; + /* We can only have one data source at a time. */ + g_return_if_fail(slpmsg->buffer); + g_return_if_fail(slpmsg->img); + g_return_if_fail(slpmsg->fp); + slpmsg->fp = g_fopen(file_name, "rb"); if (g_stat(file_name, &st) == 0) diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/msn/slpmsg.h --- a/libpurple/protocols/msn/slpmsg.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/msn/slpmsg.h Wed Apr 25 21:48:56 2007 +0000 @@ -26,6 +26,8 @@ typedef struct _MsnSlpMessage MsnSlpMessage; +#include "imgstore.h" + #include "slpsession.h" #include "slpcall.h" #include "slplink.h" @@ -57,6 +59,7 @@ long flags; FILE *fp; + PurpleStoredImage *img; guchar *buffer; long long offset; long long size; @@ -90,6 +93,7 @@ void msn_slpmsg_set_body(MsnSlpMessage *slpmsg, const char *body, long long size); +void msn_slpmsg_set_image(MsnSlpMessage *slpmsg, PurpleStoredImage *img); void msn_slpmsg_open_file(MsnSlpMessage *slpmsg, const char *file_name); MsnSlpMessage * msn_slpmsg_sip_new(MsnSlpCall *slpcall, int cseq, diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/msn/user.c --- a/libpurple/protocols/msn/user.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/msn/user.c Wed Apr 25 21:48:56 2007 +0000 @@ -151,23 +151,20 @@ } void -msn_user_set_buddy_icon(MsnUser *user, const char *filename) +msn_user_set_buddy_icon(MsnUser *user, PurpleStoredImage *img) { - struct stat st; - FILE *fp; MsnObject *msnobj = msn_user_get_object(user); g_return_if_fail(user != NULL); - if (filename == NULL || g_stat(filename, &st) == -1) - { + if (img == NULL) msn_user_set_object(user, NULL); - } - else if ((fp = g_fopen(filename, "rb")) != NULL) + else { PurpleCipherContext *ctx; char *buf; - gsize len; + gconstpointer data = purple_imgstore_get_data(img); + size_t size = purple_imgstore_get_size(img); char *base64; unsigned char digest[20]; @@ -182,26 +179,20 @@ msn_user_set_object(user, msnobj); } - msn_object_set_real_location(msnobj, filename); - - buf = g_malloc(st.st_size); - len = fread(buf, 1, st.st_size, fp); - - fclose(fp); + msn_object_set_image(msnobj, img); /* Compute the SHA1D field. */ memset(digest, 0, sizeof(digest)); ctx = purple_cipher_context_new_by_name("sha1", NULL); - purple_cipher_context_append(ctx, (const guchar *)buf, st.st_size); + purple_cipher_context_append(ctx, data, size); purple_cipher_context_digest(ctx, sizeof(digest), digest, NULL); - g_free(buf); base64 = purple_base64_encode(digest, sizeof(digest)); msn_object_set_sha1d(msnobj, base64); g_free(base64); - msn_object_set_size(msnobj, st.st_size); + msn_object_set_size(msnobj, size); /* Compute the SHA1C field. */ buf = g_strdup_printf( @@ -216,7 +207,7 @@ memset(digest, 0, sizeof(digest)); purple_cipher_context_reset(ctx, NULL); - purple_cipher_context_append(ctx, (const guchar *)buf, strlen(buf)); + purple_cipher_context_append(ctx, data, strlen((char *)data)); purple_cipher_context_digest(ctx, sizeof(digest), digest, NULL); purple_cipher_context_destroy(ctx); g_free(buf); @@ -225,11 +216,6 @@ msn_object_set_sha1c(msnobj, base64); g_free(base64); } - else - { - purple_debug_error("msn", "Unable to open buddy icon %s!\n", filename); - msn_user_set_object(user, NULL); - } } void diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/msn/user.h --- a/libpurple/protocols/msn/user.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/msn/user.h Wed Apr 25 21:48:56 2007 +0000 @@ -138,9 +138,9 @@ * Sets the buddy icon for a local user. * * @param user The user. - * @param filename The path to the buddy icon. + * @param img The buddy icon image */ -void msn_user_set_buddy_icon(MsnUser *user, const char *filename); +void msn_user_set_buddy_icon(MsnUser *user, PurpleStoredImage *img); /** * Sets the group ID list for a user. diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.c Wed Apr 25 21:48:56 2007 +0000 @@ -1895,7 +1895,7 @@ PurpleAccount *account = purple_connection_get_account(gc); PurpleMessageFlags flags = 0; struct buddyinfo *bi; - char *iconfile; + PurpleStoredImage *img; GString *message; gchar *tmp; aim_mpmsg_section_t *curpart; @@ -1932,33 +1932,19 @@ } } - iconfile = purple_buddy_icons_get_full_path(purple_account_get_buddy_icon(account)); - if ((iconfile != NULL) && + img = purple_buddy_icons_find_account_icon(account); + if ((img != NULL) && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ) && !bi->ico_sent && bi->ico_informed) { - FILE *file; - struct stat st; - - if (!g_stat(iconfile, &st)) { - guchar *buf = g_malloc(st.st_size); - file = g_fopen(iconfile, "rb"); - if (file) { - /* XXX - Use g_file_get_contents() */ - /* g_file_get_contents(iconfile, &data, &len, NULL); */ - int len = fread(buf, 1, st.st_size, file); - purple_debug_info("oscar", - "Sending buddy icon to %s (%d bytes, " - "%lu reported)\n", - userinfo->sn, len, st.st_size); - aim_im_sendch2_icon(od, userinfo->sn, buf, st.st_size, - st.st_mtime, aimutil_iconsum(buf, st.st_size)); - fclose(file); - } else - purple_debug_error("oscar", "Can't open buddy icon file!\n"); - g_free(buf); - } else - purple_debug_error("oscar", "Can't stat buddy icon file!\n"); - } - g_free(iconfile); + gconstpointer data = purple_imgstore_get_data(img); + size_t len = purple_imgstore_get_size(img); + purple_debug_info("oscar", + "Sending buddy icon to %s (%d bytes)\n", + userinfo->sn, len); + /* TODO: XXX: FIXME: Does this actually need the mtime of the file? */ + aim_im_sendch2_icon(od, userinfo->sn, data, len, + time(NULL), aimutil_iconsum(data, len)); + } + purple_imgstore_unref(img); message = g_string_new(""); curpart = args->mpmsg.parts; @@ -3295,29 +3281,17 @@ } if (od->set_icon) { - struct stat st; - char *iconfile = purple_buddy_icons_get_full_path(purple_account_get_buddy_icon(purple_connection_get_account(gc))); - if (iconfile == NULL) { + PurpleAccount *account = purple_connection_get_account(gc); + PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account); + if (img == NULL) { aim_ssi_delicon(od); - } else if (!g_stat(iconfile, &st)) { - guchar *buf = g_malloc(st.st_size); - FILE *file = g_fopen(iconfile, "rb"); - if (file) { - /* XXX - Use g_file_get_contents()? */ - fread(buf, 1, st.st_size, file); - fclose(file); - purple_debug_info("oscar", - "Uploading icon to icon server\n"); - aim_bart_upload(od, buf, st.st_size); - } else - purple_debug_error("oscar", - "Can't open buddy icon file!\n"); - g_free(buf); } else { - purple_debug_error("oscar", - "Can't stat buddy icon file!\n"); + purple_debug_info("oscar", + "Uploading icon to icon server\n"); + aim_bart_upload(od, purple_imgstore_get_data(img), + purple_imgstore_get_size(img)); + purple_imgstore_unref(img); } - g_free(iconfile); od->set_icon = FALSE; } @@ -4178,13 +4152,11 @@ PurpleAccount *account; PeerConnection *conn; int ret; - char *iconfile; char *tmp1, *tmp2; od = (OscarData *)gc->proto_data; account = purple_connection_get_account(gc); ret = 0; - iconfile = purple_buddy_icons_get_full_path(purple_account_get_buddy_icon(account)); if (imflags & PURPLE_MESSAGE_AUTO_RESP) tmp1 = purple_str_sub_away_formatters(message, name); @@ -4199,9 +4171,9 @@ } else { struct buddyinfo *bi; struct aim_sendimext_args args; - struct stat st; gsize len; PurpleConversation *conv; + PurpleStoredImage *img; conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, account); @@ -4250,44 +4222,38 @@ bi->ico_need = FALSE; } - if (iconfile && !g_stat(iconfile, &st)) { - FILE *file = g_fopen(iconfile, "rb"); - if (file) { - guchar *buf = g_malloc(st.st_size); - /* TODO: Use g_file_get_contents()? */ - fread(buf, 1, st.st_size, file); - fclose(file); - - args.iconlen = st.st_size; - args.iconsum = aimutil_iconsum(buf, st.st_size); - args.iconstamp = st.st_mtime; - - if ((args.iconlen != bi->ico_me_len) || (args.iconsum != bi->ico_me_csum) || (args.iconstamp != bi->ico_me_time)) { - bi->ico_informed = FALSE; - bi->ico_sent = FALSE; - } - - /* - * TODO: - * For some reason sending our icon to people only works - * when we're the ones who initiated the conversation. If - * the other person sends the first IM then they never get - * the icon. We should fix that. - */ - if (!bi->ico_informed) { - purple_debug_info("oscar", - "Claiming to have a buddy icon\n"); - args.flags |= AIM_IMFLAGS_HASICON; - bi->ico_me_len = args.iconlen; - bi->ico_me_csum = args.iconsum; - bi->ico_me_time = args.iconstamp; - bi->ico_informed = TRUE; - } - - g_free(buf); + img = purple_buddy_icons_find_account_icon(account); + if (img) { + gconstpointer data = purple_imgstore_get_data(img); + args.iconlen = purple_imgstore_get_size(img); + args.iconsum = aimutil_iconsum(data, args.iconlen); + /* TODO: XXX: FIXME: Deal with the timestamp issue. */ + args.iconstamp = time(NULL); + + if ((args.iconlen != bi->ico_me_len) || (args.iconsum != bi->ico_me_csum) || (args.iconstamp != bi->ico_me_time)) { + bi->ico_informed = FALSE; + bi->ico_sent = FALSE; } + + /* + * TODO: + * For some reason sending our icon to people only works + * when we're the ones who initiated the conversation. If + * the other person sends the first IM then they never get + * the icon. We should fix that. + */ + if (!bi->ico_informed) { + purple_debug_info("oscar", + "Claiming to have a buddy icon\n"); + args.flags |= AIM_IMFLAGS_HASICON; + bi->ico_me_len = args.iconlen; + bi->ico_me_csum = args.iconsum; + bi->ico_me_time = args.iconstamp; + bi->ico_informed = TRUE; + } + + purple_imgstore_unref(img); } - g_free(iconfile); args.destsn = name; @@ -4761,8 +4727,7 @@ PurpleBuddy *b; struct aim_ssi_item *curitem; guint32 tmp; - const char *icon_path; - char *cached_icon_path; + PurpleStoredImage *img; va_list ap; guint16 fmtver, numitems; guint32 timestamp; @@ -4995,10 +4960,9 @@ * the event that the local user set a new icon while this * account was offline. */ - icon_path = purple_account_get_buddy_icon(account); - cached_icon_path = purple_buddy_icons_get_full_path(icon_path); - oscar_set_icon(gc, cached_icon_path); - g_free(cached_icon_path); + img = purple_buddy_icons_find_account_icon(account); + oscar_set_icon(gc, img); + purple_imgstore_unref(img); return 1; } @@ -5600,37 +5564,27 @@ od->set_icon = TRUE; aim_srv_requestnew(od, SNAC_FAMILY_BART); } else { - struct stat st; - char *iconfile = purple_buddy_icons_get_full_path(purple_account_get_buddy_icon(purple_connection_get_account(gc))); - if (iconfile == NULL) { + PurpleAccount *account = purple_connection_get_account(gc); + PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account); + if (img == NULL) { aim_ssi_delicon(od); - } else if (!g_stat(iconfile, &st)) { - guchar *buf = g_malloc(st.st_size); - FILE *file = g_fopen(iconfile, "rb"); - if (file) { - /* XXX - Use g_file_get_contents()? */ - fread(buf, 1, st.st_size, file); - fclose(file); - purple_debug_info("oscar", - "Uploading icon to icon server\n"); - aim_bart_upload(od, buf, st.st_size); - } else - purple_debug_error("oscar", - "Can't open buddy icon file!\n"); - g_free(buf); } else { - purple_debug_error("oscar", - "Can't stat buddy icon file!\n"); + + purple_debug_info("oscar", + "Uploading icon to icon server\n"); + aim_bart_upload(od, purple_imgstore_get_data(img), + purple_imgstore_get_size(img)); + purple_imgstore_unref(img); } - g_free(iconfile); } } else if (flags == 0x81) { - char *iconfile = purple_buddy_icons_get_full_path(purple_account_get_buddy_icon(purple_connection_get_account(gc))); - if (iconfile == NULL) + PurpleAccount *account = purple_connection_get_account(gc); + PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account); + if (img == NULL) aim_ssi_delicon(od); else { aim_ssi_seticon(od, md5, length); - g_free(iconfile); + purple_imgstore_unref(img); } } } break; @@ -6212,41 +6166,28 @@ purple_notify_uri(gc, "http://mymobile.aol.com/dbreg/register?action=imf&clientID=1"); } -void oscar_set_icon(PurpleConnection *gc, const char *iconfile) +void oscar_set_icon(PurpleConnection *gc, PurpleStoredImage *img) { OscarData *od = gc->proto_data; - FILE *file; - struct stat st; - - if (iconfile == NULL) { + + if (img == NULL) { aim_ssi_delicon(od); - } else if (!g_stat(iconfile, &st)) { - guchar *buf = g_malloc(st.st_size); - file = g_fopen(iconfile, "rb"); - if (file) - { - PurpleCipher *cipher; - PurpleCipherContext *context; - guchar md5[16]; - int len; - - /* XXX - Use g_file_get_contents()? */ - len = fread(buf, 1, st.st_size, file); - fclose(file); - - cipher = purple_ciphers_find_cipher("md5"); - context = purple_cipher_context_new(cipher, NULL); - purple_cipher_context_append(context, buf, len); - purple_cipher_context_digest(context, 16, md5, NULL); - purple_cipher_context_destroy(context); - - aim_ssi_seticon(od, md5, 16); - } else - purple_debug_error("oscar", - "Can't open buddy icon file!\n"); - g_free(buf); - } else - purple_debug_error("oscar", "Can't stat buddy icon file!\n"); + } else { + PurpleCipher *cipher; + PurpleCipherContext *context; + guchar md5[16]; + gconstpointer data = purple_imgstore_get_data(img); + size_t len = purple_imgstore_get_size(img); + + + cipher = purple_ciphers_find_cipher("md5"); + context = purple_cipher_context_new(cipher, NULL); + purple_cipher_context_append(context, data, len); + purple_cipher_context_digest(context, 16, md5, NULL); + purple_cipher_context_destroy(context); + + aim_ssi_seticon(od, md5, 16); + } } /** diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/oscar/oscarcommon.h --- a/libpurple/protocols/oscar/oscarcommon.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/oscar/oscarcommon.h Wed Apr 25 21:48:56 2007 +0000 @@ -81,7 +81,7 @@ void oscar_rename_group(PurpleConnection *gc, const char *old_name, PurpleGroup *group, GList *moved_buddies); void oscar_convo_closed(PurpleConnection *gc, const char *who); const char *oscar_normalize(const PurpleAccount *account, const char *str); -void oscar_set_icon(PurpleConnection *gc, const char *iconfile); +void oscar_set_icon(PurpleConnection *gc, PurpleStoredImage *img); gboolean oscar_can_receive_file(PurpleConnection *gc, const char *who); void oscar_send_file(PurpleConnection *gc, const char *who, const char *file); PurpleXfer *oscar_new_xfer(PurpleConnection *gc, const char *who); diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/qq/buddy_info.c --- a/libpurple/protocols/qq/buddy_info.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Wed Apr 25 21:48:56 2007 +0000 @@ -546,7 +546,7 @@ } /* TODO: custom faces for QQ members and users with level >= 16 */ -void qq_set_my_buddy_icon(PurpleConnection *gc, const gchar *iconfile) +void qq_set_my_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) { gchar *icon; gint icon_num; diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/qq/buddy_info.h --- a/libpurple/protocols/qq/buddy_info.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/qq/buddy_info.h Wed Apr 25 21:48:56 2007 +0000 @@ -86,7 +86,7 @@ void qq_refresh_buddy_and_myself(contact_info *info, PurpleConnection *gc); void qq_send_packet_get_info(PurpleConnection *gc, guint32 uid, gboolean show_window); -void qq_set_my_buddy_icon(PurpleConnection *gc, const gchar *iconfile); +void qq_set_my_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img); void qq_set_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *icon_num, const gchar *iconfile); void qq_prepare_modify_info(PurpleConnection *gc); void qq_process_modify_info_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/yahoo/yahoo.c --- a/libpurple/protocols/yahoo/yahoo.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Wed Apr 25 21:48:56 2007 +0000 @@ -2682,11 +2682,10 @@ static void yahoo_picture_check(PurpleAccount *account) { PurpleConnection *gc = purple_account_get_connection(account); - char *buddyicon; - - buddyicon = purple_buddy_icons_get_full_path(purple_account_get_buddy_icon(account)); - yahoo_set_buddy_icon(gc, buddyicon); - g_free(buddyicon); + PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account); + + yahoo_set_buddy_icon(gc, img); + purple_imgstore_unref(img); } static int get_yahoo_status_from_purple_status(PurpleStatus *status) diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/yahoo/yahoo_picture.c --- a/libpurple/protocols/yahoo/yahoo_picture.c Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_picture.c Wed Apr 25 21:48:56 2007 +0000 @@ -514,15 +514,12 @@ } } -void yahoo_set_buddy_icon(PurpleConnection *gc, const char *iconfile) +void yahoo_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) { struct yahoo_data *yd = gc->proto_data; PurpleAccount *account = gc->account; - gchar *icondata; - gsize len; - GError *error = NULL; - if (iconfile == NULL) { + if (img == NULL) { g_free(yd->picture_url); yd->picture_url = NULL; @@ -533,14 +530,19 @@ /* Tell everyone we ain't got one no more */ yahoo_send_picture_update(gc, 0); - } else if (g_file_get_contents(iconfile, &icondata, &len, &error)) { - GString *s = g_string_new_len(icondata, len); + } else { + gconstpointer data = purple_imgstore_get_data(img); + size_t len = purple_imgstore_get_size(img); + GString *s = g_string_new_len(data, len); struct yahoo_buddy_icon_upload_data *d; int oldcksum = purple_account_get_int(account, YAHOO_PICCKSUM_SETTING, 0); int expire = purple_account_get_int(account, YAHOO_PICEXPIRE_SETTING, 0); const char *oldurl = purple_account_get_string(account, YAHOO_PICURL_SETTING, NULL); + char *iconfile; - g_free(icondata); + /* TODO: At some point, it'd be nice to fix this for real, or + * TODO: at least change it to be something like: + * TODO: purple_imgstore_get_filename(img); */ yd->picture_checksum = g_string_hash(s); if ((yd->picture_checksum == oldcksum) && @@ -553,11 +555,15 @@ return; } + /* TODO: FIXME: This is completely wrong. The upload code needs to + * TODO: be modified to work with a PurpleStoredImage. */ + iconfile = g_build_filename(purple_buddy_icons_get_cache_dir(), + purple_imgstore_get_filename(img), NULL); d = g_new0(struct yahoo_buddy_icon_upload_data, 1); d->gc = gc; d->str = s; d->fd = -1; - d->filename = g_strdup(iconfile); + d->filename = iconfile; if (!yd->logged_in) { yd->picture_upload_todo = d; @@ -566,10 +572,5 @@ yahoo_buddy_icon_upload(gc, d); - } else { - purple_debug_error("yahoo", - "Could not read buddy icon file '%s': %s\n", - iconfile, error->message); - g_error_free(error); } } diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/protocols/yahoo/yahoo_picture.h --- a/libpurple/protocols/yahoo/yahoo_picture.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_picture.h Wed Apr 25 21:48:56 2007 +0000 @@ -37,7 +37,7 @@ void yahoo_process_avatar_update(PurpleConnection *gc, struct yahoo_packet *pkt); -void yahoo_set_buddy_icon(PurpleConnection *gc, const char *iconfile); +void yahoo_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img); void yahoo_buddy_icon_upload(PurpleConnection *gc, struct yahoo_buddy_icon_upload_data *d); void yahoo_buddy_icon_upload_data_free(struct yahoo_buddy_icon_upload_data *d); diff -r 493ca924c199 -r 4fc51a87ce42 libpurple/prpl.h --- a/libpurple/prpl.h Wed Apr 25 01:19:24 2007 +0000 +++ b/libpurple/prpl.h Wed Apr 25 21:48:56 2007 +0000 @@ -59,6 +59,7 @@ #include "blist.h" #include "conversation.h" #include "ft.h" +#include "imgstore.h" #include "notify.h" #include "proxy.h" #include "plugin.h" @@ -281,7 +282,9 @@ const char *(*normalize)(const PurpleAccount *, const char *); - void (*set_buddy_icon)(PurpleConnection *, const char *cached_path); + /* The prpl does NOT own a reference to img. If it needs one, it + * must purple_imgstore_ref(img) itself. */ + void (*set_buddy_icon)(PurpleConnection *, PurpleStoredImage *img); void (*remove_group)(PurpleConnection *gc, PurpleGroup *group); diff -r 493ca924c199 -r 4fc51a87ce42 pidgin/gtkaccount.c --- a/pidgin/gtkaccount.c Wed Apr 25 01:19:24 2007 +0000 +++ b/pidgin/gtkaccount.c Wed Apr 25 21:48:56 2007 +0000 @@ -122,8 +122,7 @@ GtkWidget *icon_filesel; GtkWidget *icon_preview; GtkWidget *icon_text; - char *cached_icon_path; - char *icon_path; + PurpleStoredImage *icon_img; /* Protocol Options */ GtkWidget *protocol_frame; @@ -195,20 +194,21 @@ } static void -set_dialog_icon(AccountPrefsDialog *dialog, gchar *new_cached_icon_path, gchar *new_icon_path) +set_dialog_icon(AccountPrefsDialog *dialog, gpointer *data, size_t len, gchar *new_icon_path) { - char *filename; GdkPixbuf *pixbuf = NULL; - g_free(dialog->cached_icon_path); - g_free(dialog->icon_path); - dialog->cached_icon_path = new_cached_icon_path; - dialog->icon_path = new_icon_path; - - filename = purple_buddy_icons_get_full_path(dialog->cached_icon_path); - if (filename != NULL) { - pixbuf = gdk_pixbuf_new_from_file(filename, NULL); - g_free(filename); + purple_imgstore_unref(dialog->icon_img); + if (data != NULL && len > 0) + dialog->icon_img = purple_imgstore_add(data, len, new_icon_path); + g_free(data); + + if (dialog->icon_img != NULL) { + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + gdk_pixbuf_loader_write(loader, purple_imgstore_get_data(dialog->icon_img), + purple_imgstore_get_size(dialog->icon_img), NULL); + gdk_pixbuf_loader_close(loader, NULL); + pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); } if (pixbuf && dialog->prpl_info && @@ -298,14 +298,14 @@ static void icon_filesel_choose_cb(const char *filename, gpointer data) { - AccountPrefsDialog *dialog; - - dialog = data; - -#if 0 + AccountPrefsDialog *dialog = data; + if (filename != NULL) - set_dialog_icon(dialog, pidgin_convert_buddy_icon(dialog->plugin, filename), g_strdup(filename)); -#endif + { + size_t len; + gpointer data = pidgin_convert_buddy_icon(dialog->plugin, filename, &len); + set_dialog_icon(dialog, data, len, g_strdup(filename)); + } dialog->icon_filesel = NULL; } @@ -320,7 +320,7 @@ static void icon_reset_cb(GtkWidget *button, AccountPrefsDialog *dialog) { - set_dialog_icon(dialog, NULL, NULL); + set_dialog_icon(dialog, NULL, 0, NULL); } static void @@ -335,6 +335,9 @@ if (!g_ascii_strncasecmp(name, "file://", 7)) { GError *converr = NULL; gchar *tmp, *rtmp; + gpointer data; + size_t len; + /* It looks like we're dealing with a local file. */ if(!(tmp = g_filename_from_uri(name, NULL, &converr))) { purple_debug(PURPLE_DEBUG_ERROR, "buddyicon", "%s\n", @@ -344,10 +347,10 @@ } if ((rtmp = strchr(tmp, '\r')) || (rtmp = strchr(tmp, '\n'))) *rtmp = '\0'; -#if 0 - set_dialog_icon(dialog, pidgin_convert_buddy_icon(dialog->plugin, tmp), g_strdup(tmp)); -#endif - g_free(tmp); + + data = pidgin_convert_buddy_icon(dialog->plugin, tmp, &len); + /* This takes ownership of tmp */ + set_dialog_icon(dialog, data, len, tmp); } gtk_drag_finish(dc, TRUE, FALSE, t); } @@ -595,8 +598,8 @@ gtk_widget_show(dialog->icon_entry); /* TODO: Uh, isn't this next line pretty useless? */ pidgin_set_accessible_label (dialog->icon_entry, label); - dialog->cached_icon_path = NULL; - dialog->icon_path = NULL; + purple_imgstore_unref(dialog->icon_img); + dialog->icon_img = NULL; vbox2 = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0); @@ -621,19 +624,27 @@ } if (dialog->account != NULL) { + PurpleStoredImage *img; + gpointer data = NULL; + size_t len = 0; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->new_mail_check), purple_account_get_check_mail(dialog->account)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->icon_check), !purple_account_get_bool(dialog->account, "use-global-buddyicon", TRUE)); - set_dialog_icon(dialog, - g_strdup(purple_account_get_ui_string(dialog->account, - PIDGIN_UI, "non-global-buddyicon-cached-path", NULL)), - g_strdup(purple_account_get_ui_string(dialog->account, - PIDGIN_UI, "non-global-buddyicon-path", NULL))); + + img = purple_buddy_icons_find_account_icon(dialog->account); + if (img) + { + len = purple_imgstore_get_size(img); + data = g_memdup(purple_imgstore_get_data(img), len); + } + set_dialog_icon(dialog, data, len, + g_strdup(purple_account_get_buddy_icon_path(dialog->account))); } else { - set_dialog_icon(dialog, NULL, NULL); + set_dialog_icon(dialog, NULL, 0, NULL); } if (!dialog->prpl_info || @@ -1076,22 +1087,7 @@ g_list_free(dialog->protocol_opt_entries); g_free(dialog->protocol_id); - if (dialog->cached_icon_path != NULL) - { - const char *icon = purple_account_get_ui_string(dialog->account, PIDGIN_UI, "non-global-buddyicon-cached-path", NULL); - if (dialog->cached_icon_path != NULL && (icon == NULL || strcmp(dialog->cached_icon_path, icon))) - { - /* The user set an icon, which would've been cached by convert_buddy_icon, - * but didn't save the changes. Delete the cache file. */ - char *filename = g_build_filename(purple_buddy_icons_get_cache_dir(), dialog->cached_icon_path, NULL); - g_unlink(filename); - g_free(filename); - } - - g_free(dialog->cached_icon_path); - } - - g_free(dialog->icon_path); + purple_imgstore_unref(dialog->icon_img); if (dialog->icon_filesel) gtk_widget_destroy(dialog->icon_filesel); @@ -1147,28 +1143,37 @@ prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(dialog->plugin); if (prpl_info != NULL && prpl_info->icon_spec.format != NULL) { + const char *filename; + if (new || purple_account_get_bool(account, "use-global-buddyicon", TRUE) == gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check))) { icon_change = TRUE; } purple_account_set_bool(account, "use-global-buddyicon", !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check))); - purple_account_set_ui_string(account, PIDGIN_UI, "non-global-buddyicon-cached-path", dialog->cached_icon_path); - purple_account_set_ui_string(account, PIDGIN_UI, "non-global-buddyicon-path", dialog->icon_path); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check))) { - purple_account_set_buddy_icon_path(account, dialog->icon_path); - purple_account_set_buddy_icon(account, dialog->cached_icon_path); + if (dialog->icon_img) + { + size_t len = purple_imgstore_get_size(dialog->icon_img); + purple_buddy_icons_set_account_icon(account, + g_memdup(purple_imgstore_get_data(dialog->icon_img), len), + len); + purple_account_set_buddy_icon_path(account, purple_imgstore_get_filename(dialog->icon_img)); + } + else + { + purple_buddy_icons_set_account_icon(account, NULL, 0); + purple_account_set_buddy_icon_path(account, NULL); + } } - else if (purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon") && icon_change) + else if ((filename = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon")) && icon_change) { - const char *filename = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon"); -#if 0 - char *icon = pidgin_convert_buddy_icon(dialog->plugin, filename); + size_t len; + gpointer data = pidgin_convert_buddy_icon(dialog->plugin, filename, &len); purple_account_set_buddy_icon_path(account, filename); - purple_account_set_buddy_icon(account, icon); - g_free(icon); -#endif + purple_buddy_icons_set_account_icon(account, data, len); } } @@ -1981,7 +1986,7 @@ set_account(GtkListStore *store, GtkTreeIter *iter, PurpleAccount *account, GdkPixbuf *global_buddyicon) { GdkPixbuf *pixbuf, *buddyicon = NULL; - const char *path = NULL; + PurpleStoredImage *img = NULL; pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM); if ((pixbuf != NULL) && purple_account_is_disconnected(account)) @@ -1992,12 +1997,22 @@ buddyicon = g_object_ref(G_OBJECT(global_buddyicon)); /* This is for when set_account() is called for a single account */ else - path = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon"); - } else - path = purple_account_get_ui_string(account, PIDGIN_UI, "non-global-buddyicon-path", NULL); - - if (path != NULL) { - GdkPixbuf *buddyicon_pixbuf = gdk_pixbuf_new_from_file(path, NULL); + img = purple_buddy_icons_find_account_icon(account); + } else { + img = purple_buddy_icons_find_account_icon(account); + } + + if (img != NULL) { + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + GdkPixbuf *buddyicon_pixbuf; + + gdk_pixbuf_loader_write(loader, purple_imgstore_get_data(img), + purple_imgstore_get_size(img), NULL); + gdk_pixbuf_loader_close(loader, NULL); + buddyicon_pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); + + purple_imgstore_unref(img); + if (buddyicon_pixbuf != NULL) { buddyicon = gdk_pixbuf_scale_simple(buddyicon_pixbuf, 22, 22, GDK_INTERP_HYPER); g_object_unref(G_OBJECT(buddyicon_pixbuf)); diff -r 493ca924c199 -r 4fc51a87ce42 pidgin/gtkstatusbox.c --- a/pidgin/gtkstatusbox.c Wed Apr 25 01:19:24 2007 +0000 +++ b/pidgin/gtkstatusbox.c Wed Apr 25 21:48:56 2007 +0000 @@ -42,8 +42,10 @@ #include #include "account.h" +#include "buddyicon.h" #include "core.h" #include "internal.h" +#include "imgstore.h" #include "network.h" #include "savedstatuses.h" #include "status.h" @@ -383,13 +385,27 @@ if (status_box->account && !purple_account_get_bool(status_box->account, "use-global-buddyicon", TRUE)) { - char *string = purple_buddy_icons_get_full_path(purple_account_get_buddy_icon(status_box->account)); - pidgin_status_box_set_buddy_icon(status_box, string); - g_free(string); + PurpleStoredImage *img = purple_buddy_icons_find_account_icon(status_box->account); + pidgin_status_box_set_buddy_icon(status_box, img); + purple_imgstore_unref(img); } else { - pidgin_status_box_set_buddy_icon(status_box, purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon")); + const char *filename = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon"); + PurpleStoredImage *img = NULL; + + if (filename != NULL) + { + gchar *contents; + gsize size; + if (g_file_get_contents(filename, &contents, &size, NULL)) + { + img = purple_imgstore_add(contents, size, filename); + g_free(contents); + } + } + + pidgin_status_box_set_buddy_icon(status_box, img); } status_box->hand_cursor = gdk_cursor_new (GDK_HAND2); @@ -422,6 +438,8 @@ gdk_cursor_unref(statusbox->hand_cursor); gdk_cursor_unref(statusbox->arrow_cursor); + purple_imgstore_unref(statusbox->buddy_icon_img); + g_object_unref(G_OBJECT(statusbox->buddy_icon)); g_object_unref(G_OBJECT(statusbox->buddy_icon_hover)); @@ -431,12 +449,10 @@ if (statusbox->icon_box_menu) gtk_widget_destroy(statusbox->icon_box_menu); - g_free(statusbox->buddy_icon_path); - statusbox->icon = NULL; statusbox->icon_box = NULL; statusbox->icon_box_menu = NULL; - statusbox->buddy_icon_path = NULL; + statusbox->buddy_icon_img = NULL; statusbox->buddy_icon = NULL; statusbox->buddy_icon_hover = NULL; statusbox->hand_cursor = NULL; @@ -489,14 +505,13 @@ gdk_cursor_unref(statusbox->hand_cursor); gdk_cursor_unref(statusbox->arrow_cursor); + purple_imgstore_unref(statusbox->buddy_icon_img); g_object_unref(G_OBJECT(statusbox->buddy_icon)); g_object_unref(G_OBJECT(statusbox->buddy_icon_hover)); if (statusbox->buddy_icon_sel) gtk_widget_destroy(statusbox->buddy_icon_sel); - g_free(statusbox->buddy_icon_path); - G_OBJECT_CLASS(parent_class)->finalize(obj); } @@ -1432,22 +1447,21 @@ static void buddy_icon_set_cb(const char *filename, PidginStatusBox *box) { + PurpleStoredImage *img = NULL; if (box->account) { PurplePlugin *plug = purple_find_prpl(purple_account_get_protocol_id(box->account)); if (plug) { PurplePluginProtocolInfo *prplinfo = PURPLE_PLUGIN_PROTOCOL_INFO(plug); if (prplinfo && prplinfo->icon_spec.format) { - char *icon = NULL; -#if 0 + gpointer data = NULL; + size_t len = 0; if (filename) - icon = pidgin_convert_buddy_icon(plug, filename); -#endif + data = pidgin_convert_buddy_icon(plug, filename, &len); + img = purple_buddy_icons_set_account_icon(box->account, data, len); + purple_account_set_buddy_icon_path(box->account, filename); + purple_account_set_bool(box->account, "use-global-buddyicon", (filename != NULL)); - purple_account_set_ui_string(box->account, PIDGIN_UI, "non-global-buddyicon-cached-path", icon); - purple_account_set_buddy_icon_path(box->account, filename); - purple_account_set_buddy_icon(box->account, icon); - g_free(icon); } } } else { @@ -1460,19 +1474,20 @@ if (prplinfo != NULL && purple_account_get_bool(account, "use-global-buddyicon", TRUE) && prplinfo->icon_spec.format) { - char *icon = NULL; -#if 0 + gpointer data = NULL; + size_t len = 0; if (filename) - icon = pidgin_convert_buddy_icon(plug, filename); -#endif - purple_account_set_buddy_icon_path(account, filename); - purple_account_set_buddy_icon(account, icon); - g_free(icon); + data = pidgin_convert_buddy_icon(plug, filename, &len); + img = purple_buddy_icons_set_account_icon(box->account, data, len); + purple_account_set_buddy_icon_path(box->account, filename); + + purple_account_set_bool(box->account, "use-global-buddyicon", (filename != NULL)); } } } } - pidgin_status_box_set_buddy_icon(box, filename); + + pidgin_status_box_set_buddy_icon(box, img); } static void @@ -2044,10 +2059,14 @@ status_box->buddy_icon = NULL; status_box->buddy_icon_hover = NULL; - if ((status_box->buddy_icon_path != NULL) && - (*status_box->buddy_icon_path != '\0')) - status_box->buddy_icon = gdk_pixbuf_new_from_file_at_scale(status_box->buddy_icon_path, - status_box->icon_size, status_box->icon_size, FALSE, NULL); + if (status_box->buddy_icon_img != NULL) + { + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + gdk_pixbuf_loader_write(loader, purple_imgstore_get_data(status_box->buddy_icon_img), + purple_imgstore_get_size(status_box->buddy_icon_img), NULL); + gdk_pixbuf_loader_close(loader, NULL); + status_box->buddy_icon = gdk_pixbuf_loader_get_pixbuf(loader); + } if (status_box->buddy_icon == NULL) { @@ -2068,20 +2087,14 @@ } void -pidgin_status_box_set_buddy_icon(PidginStatusBox *status_box, const char *filename) +pidgin_status_box_set_buddy_icon(PidginStatusBox *status_box, PurpleStoredImage *img) { - g_free(status_box->buddy_icon_path); - status_box->buddy_icon_path = g_strdup(filename); + purple_imgstore_unref(status_box->buddy_icon_img); + status_box->buddy_icon_img = purple_imgstore_ref(img); pidgin_status_box_redisplay_buddy_icon(status_box); } -const char* -pidgin_status_box_get_buddy_icon(PidginStatusBox *box) -{ - return box->buddy_icon_path; -} - void pidgin_status_box_pulse_connecting(PidginStatusBox *status_box) { diff -r 493ca924c199 -r 4fc51a87ce42 pidgin/gtkstatusbox.h --- a/pidgin/gtkstatusbox.h Wed Apr 25 01:19:24 2007 +0000 +++ b/pidgin/gtkstatusbox.h Wed Apr 25 21:48:56 2007 +0000 @@ -30,6 +30,7 @@ #include #include "gtkimhtml.h" #include "account.h" +#include "imgstore.h" #include "savedstatuses.h" #include "status.h" #include @@ -89,7 +90,7 @@ GtkWidget *vbox, *sw; GtkWidget *imhtml; - char *buddy_icon_path; + PurpleStoredImage *buddy_icon_img; GdkPixbuf *buddy_icon; GdkPixbuf *buddy_icon_hover; GtkWidget *buddy_icon_sel; @@ -176,10 +177,7 @@ pidgin_status_box_pulse_connecting(PidginStatusBox *status_box); void -pidgin_status_box_set_buddy_icon(PidginStatusBox *status_box, const char *filename); - -const char * -pidgin_status_box_get_buddy_icon(PidginStatusBox *status_box); +pidgin_status_box_set_buddy_icon(PidginStatusBox *status_box, PurpleStoredImage *img); char *pidgin_status_box_get_message(PidginStatusBox *status_box);