Updates for the account buddy icon stuff. This doesn't yet work fully (and maybe not even partly), but it compiles. rlaager.gaim_migration

Wed, 25 Apr 2007 21:48:56 +0000

author
Richard Laager <rlaager@pidgin.im>
date
Wed, 25 Apr 2007 21:48:56 +0000
branch
rlaager.gaim_migration
changeset 16538
c7e61e2917c9
parent 16537
763d885ff7a2
child 16539
75a20ae3a527
child 16541
5a3a58753409

Updates for the account buddy icon stuff. This doesn't yet work fully (and maybe not even partly), but it compiles.

libpurple/account.c file | annotate | diff | comparison | revisions
libpurple/account.h file | annotate | diff | comparison | revisions
libpurple/buddyicon.c file | annotate | diff | comparison | revisions
libpurple/buddyicon.h file | annotate | diff | comparison | revisions
libpurple/imgstore.c file | annotate | diff | comparison | revisions
libpurple/imgstore.h file | annotate | diff | comparison | revisions
libpurple/protocols/jabber/buddy.c file | annotate | diff | comparison | revisions
libpurple/protocols/jabber/buddy.h file | annotate | diff | comparison | revisions
libpurple/protocols/msn/msn.c file | annotate | diff | comparison | revisions
libpurple/protocols/msn/object.c file | annotate | diff | comparison | revisions
libpurple/protocols/msn/object.h file | annotate | diff | comparison | revisions
libpurple/protocols/msn/session.c file | annotate | diff | comparison | revisions
libpurple/protocols/msn/slp.c file | annotate | diff | comparison | revisions
libpurple/protocols/msn/slpmsg.c file | annotate | diff | comparison | revisions
libpurple/protocols/msn/slpmsg.h file | annotate | diff | comparison | revisions
libpurple/protocols/msn/user.c file | annotate | diff | comparison | revisions
libpurple/protocols/msn/user.h file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/oscar.c file | annotate | diff | comparison | revisions
libpurple/protocols/oscar/oscarcommon.h file | annotate | diff | comparison | revisions
libpurple/protocols/qq/buddy_info.c file | annotate | diff | comparison | revisions
libpurple/protocols/qq/buddy_info.h file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/yahoo.c file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/yahoo_picture.c file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/yahoo_picture.h file | annotate | diff | comparison | revisions
libpurple/prpl.h file | annotate | diff | comparison | revisions
pidgin/gtkaccount.c file | annotate | diff | comparison | revisions
pidgin/gtkstatusbox.c file | annotate | diff | comparison | revisions
pidgin/gtkstatusbox.h file | annotate | diff | comparison | revisions
--- 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);
 }
--- 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.
--- 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);
 }
 
--- 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);
 
--- 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);
 }
 
--- 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 <glib.h>
+
 struct _PurpleStoredImage;
 typedef struct _PurpleStoredImage PurpleStoredImage;
 
--- 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;
--- 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);
--- 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);
 }
--- 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;
 }
--- 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_ */
--- 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;
 
--- 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++;
--- 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)
--- 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,
--- 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
--- 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.
--- 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);
+	}
 }
 
 /**
--- 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);
--- 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;
--- 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);
--- 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)
--- 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);
 	}
 }
--- 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);
 
--- 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);
 
--- 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));
--- 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 <gdk/gdkkeysyms.h>
 
 #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)
 {
--- 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 <gtk/gtk.h>
 #include "gtkimhtml.h"
 #include "account.h"
+#include "imgstore.h"
 #include "savedstatuses.h"
 #include "status.h"
 #include <gtk/gtktreemodel.h>
@@ -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);
 

mercurial