changeset 16386:e0c9a46b459f

Move the prpl icon checksum code into the core, so we can delete the checksum if the cache file disappears. See ticket #223
author Richard Laager <rlaager@wiktel.com>
date Wed, 25 Apr 2007 00:56:13 +0000
parents a0df0eb75e1b
children 414b9c9405fd
files libpurple/buddyicon.c libpurple/buddyicon.h libpurple/protocols/jabber/buddy.c libpurple/protocols/jabber/presence.c libpurple/protocols/msn/slp.c libpurple/protocols/oscar/oscar.c libpurple/protocols/qq/buddy_info.c libpurple/protocols/qq/buddy_info.h libpurple/protocols/yahoo/yahoo.c libpurple/protocols/yahoo/yahoo.h libpurple/protocols/yahoo/yahoo_picture.c
diffstat 11 files changed, 182 insertions(+), 149 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/buddyicon.c	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/buddyicon.c	Wed Apr 25 00:56:13 2007 +0000
@@ -38,9 +38,10 @@
 struct _PurpleBuddyIcon
 {
 	PurpleAccount *account;    /**< The account the user is on.          */
-	char *username;            /**< The username the icon belongs to.    */
 	PurpleStoredImage *img;    /**< The id of the stored image with the
 	                                the icon data.                       */
+	char *username;            /**< The username the icon belongs to.    */
+	char *checksum;            /**< The protocol checksum.               */
 	int ref_count;             /**< The buddy icon reference count.      */
 };
 
@@ -196,7 +197,7 @@
 	g_free(path);
 }
 
-gboolean
+static gboolean
 value_equals(gpointer key, gpointer value, gpointer user_data)
 {
 	return (value == user_data);
@@ -265,6 +266,7 @@
 
 	icon->account = account;
 	icon->username = g_strdup(username);
+	icon->checksum = NULL;
 
 	icon_cache = g_hash_table_lookup(account_cache, account);
 
@@ -282,7 +284,8 @@
 
 PurpleBuddyIcon *
 purple_buddy_icon_new(PurpleAccount *account, const char *username,
-                      void *icon_data, size_t icon_len)
+                      void *icon_data, size_t icon_len,
+                      const char *checksum)
 {
 	PurpleBuddyIcon *icon;
 
@@ -305,7 +308,7 @@
 	/* purple_buddy_icon_set_data() sets img, but it
 	 * references img first, so we need to initialize it */
 	icon->img = NULL;
-	purple_buddy_icon_set_data(icon, icon_data, icon_len);
+	purple_buddy_icon_set_data(icon, icon_data, icon_len, checksum);
 
 	return icon;
 }
@@ -338,6 +341,7 @@
 			g_hash_table_remove(icon_cache, purple_buddy_icon_get_username(icon));
 
 		g_free(icon->username);
+		g_free(icon->checksum);
 		purple_imgstore_unref(icon->img);
 
 		PURPLE_DBUS_UNREGISTER_POINTER(icon);
@@ -388,11 +392,24 @@
 			purple_blist_node_set_string((PurpleBlistNode *)buddy,
 			                             "buddy_icon",
 			                             filename);
+
+			if (icon->checksum && *icon->checksum)
+			{
+				purple_blist_node_set_string((PurpleBlistNode *)buddy,
+				                             "icon_checksum",
+				                             icon->checksum);
+			}
+			else
+			{
+				purple_blist_node_remove_setting((PurpleBlistNode *)buddy,
+				                                 "icon_checksum");
+			}
 			ref_filename(filename);
 		}
 		else
 		{
 			purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon");
+			purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "icon_checksum");
 		}
 		unref_filename(old_icon);
 		g_free(old_icon);
@@ -407,7 +424,8 @@
 }
 
 void
-purple_buddy_icon_set_data(PurpleBuddyIcon *icon, guchar *data, size_t len)
+purple_buddy_icon_set_data(PurpleBuddyIcon *icon, guchar *data,
+                           size_t len, const char *checksum)
 {
 	PurpleStoredImage *old_img;
 
@@ -419,6 +437,8 @@
 	if (data != NULL && len > 0)
 		icon->img = purple_buddy_icon_data_new(data, len, NULL);
 
+	icon->checksum = g_strdup(checksum);
+
 	purple_buddy_icon_update(icon);
 
 	purple_imgstore_unref(old_img);
@@ -440,6 +460,14 @@
 	return icon->username;
 }
 
+const char *
+purple_buddy_icon_get_checksum(const PurpleBuddyIcon *icon)
+{
+	g_return_val_if_fail(icon != NULL, NULL);
+
+	return icon->checksum;
+}
+
 gconstpointer
 purple_buddy_icon_get_data(const PurpleBuddyIcon *icon, size_t *len)
 {
@@ -467,7 +495,8 @@
 
 void
 purple_buddy_icons_set_for_user(PurpleAccount *account, const char *username,
-                                void *icon_data, size_t icon_len)
+                                void *icon_data, size_t icon_len,
+                                const char *checksum)
 {
 	g_return_if_fail(account  != NULL);
 	g_return_if_fail(username != NULL);
@@ -479,21 +508,28 @@
 		icon = purple_buddy_icons_find(account, username);
 
 		if (icon != NULL)
-			purple_buddy_icon_set_data(icon, icon_data, icon_len);
+			purple_buddy_icon_set_data(icon, icon_data, icon_len, checksum);
 	}
 	else
 	{
-		PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len);
+		PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len, checksum);
 		purple_buddy_icon_unref(icon);
 	}
 }
 
+const char *
+purple_buddy_icons_get_checksum_for_user(PurpleBuddy *buddy)
+{
+	return purple_blist_node_get_string((PurpleBlistNode*)buddy,
+	                                    "icon_checksum");
+}
+
 static gboolean
 read_icon_file(const char *path, guchar **data, size_t *len)
 {
 	GError *err = NULL;
 
-	if (!g_file_get_contents(path, data, len, &err))
+	if (!g_file_get_contents(path, (gchar **)data, len, &err))
 	{
 		purple_debug_error("buddyicon", "Error reading %s: %s\n",
 		                   path, err->message);
@@ -546,11 +582,14 @@
 			char *path = g_build_filename(dirname, protocol_icon_file, NULL);
 			if (read_icon_file(path, &data, &len))
 			{
+				const char *checksum;
+
 				if (icon == NULL)
 					icon = purple_buddy_icon_create(account, username);
 				icon->ref_count = 0;
 				icon->img = NULL;
-				purple_buddy_icon_set_data(icon, data, len);
+				checksum = g_strdup(purple_blist_node_get_string((PurpleBlistNode*)b, "icon_checksum"));
+				purple_buddy_icon_set_data(icon, data, len, checksum);
 				g_free(data);
 			}
 			g_free(path);
@@ -749,12 +788,43 @@
 		ref_filename(new_filename);
 
 		g_free(new_filename);
+
+		if (!strcmp(setting_name, "buddy_icon"))
+		{
+			const char *hash;
+
+			hash = purple_blist_node_get_string(node, "avatar_hash");
+			if (hash != NULL)
+			{
+				purple_blist_node_set_string(node, "icon_checksum", hash);
+				purple_blist_node_remove_setting(node, "avatar_hash");
+			}
+			else
+			{
+				int checksum = purple_blist_node_get_int(node, "icon_checksum");
+				if (checksum != 0)
+				{
+					char *checksum_str = g_strdup_printf("%i", checksum);
+					purple_blist_node_remove_setting(node, "icon_checksum");
+					purple_blist_node_set_string(node, "icon_checksum", checksum_str);
+					g_free(checksum_str);
+				}
+			}
+		}
 	}
 	else
 	{
 		/* If the icon is gone, drop the setting... */
 		purple_blist_node_remove_setting(node,
 		                                 setting_name);
+
+		if (!strcmp(setting_name, "buddy_icon"))
+		{
+			purple_blist_node_remove_setting(node,
+			                                 "avatar_hash");
+			purple_blist_node_remove_setting(node,
+			                                 "icon_checksum");
+		}
 		g_free(path);
 	}
 }
@@ -806,6 +876,8 @@
 					{
 						purple_blist_node_remove_setting(node,
 						                                 "buddy_icon");
+						purple_blist_node_remove_setting(node,
+						                                 "icon_checksum");
 					}
 					else
 						ref_filename(filename);
--- a/libpurple/buddyicon.h	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/buddyicon.h	Wed Apr 25 00:56:13 2007 +0000
@@ -54,11 +54,13 @@
  * @param username  The username the icon belongs to.
  * @param icon_data The buddy icon data.
  * @param icon_len  The buddy icon length.
+ * @param checksum  A protocol checksum from the prpl or @c NULL.
  *
  * @return The buddy icon structure.
  */
 PurpleBuddyIcon *purple_buddy_icon_new(PurpleAccount *account, const char *username,
-								void *icon_data, size_t icon_len);
+                                       void *icon_data, size_t icon_len,
+                                       const char *checksum);
 
 /**
  * Increments the reference count on a buddy icon.
@@ -93,8 +95,11 @@
  * @param icon The buddy icon.
  * @param data The buddy icon data received over the wire.
  * @param len  The length of the data in @a data.
+ * @param checksum  A protocol checksum from the prpl or @c NULL.
  */
-void purple_buddy_icon_set_data(PurpleBuddyIcon *icon, guchar *data, size_t len);
+void
+purple_buddy_icon_set_data(PurpleBuddyIcon *icon, guchar *data,
+                           size_t len, const char *checksum);
 
 /**
  * Returns the buddy icon's account.
@@ -115,6 +120,17 @@
 const char *purple_buddy_icon_get_username(const PurpleBuddyIcon *icon);
 
 /**
+ * Returns the buddy icon's checksum.
+ *
+ * This function is really only for prpl use.
+ *
+ * @param icon The buddy icon.
+ *
+ * @return The checksum.
+ */
+const char *purple_buddy_icon_get_checksum(const PurpleBuddyIcon *icon);
+
+/**
  * Returns the buddy icon's data.
  *
  * @param icon The buddy icon.
@@ -149,12 +165,27 @@
  * @param username  The username of the user.
  * @param icon_data The icon data.
  * @param icon_len  The length of the icon data.
+ * @param checksum  A protocol checksum from the prpl or @c NULL.
  *
  * @return The buddy icon set, or NULL if no icon was set.
  */
 void
 purple_buddy_icons_set_for_user(PurpleAccount *account, const char *username,
-                                void *icon_data, size_t icon_len);
+                                void *icon_data, size_t icon_len,
+                                const char *checksum);
+
+/**
+ * Returns the checksum for the buddy icon of a specified buddy.
+ *
+ * This avoids loading the icon image data from the cache if it's
+ * not already loaded for some other reason.
+ *
+ * @param buddy The buddy
+ *
+ * @return The checksum.
+ */
+const char *
+purple_buddy_icons_get_checksum_for_user(PurpleBuddy *buddy);
 
 /**
  * Returns the buddy icon information for a user.
--- a/libpurple/protocols/jabber/buddy.c	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Wed Apr 25 00:56:13 2007 +0000
@@ -965,15 +965,14 @@
 							photo ? _("Photo") : _("Logo"),
 							GPOINTER_TO_INT(jbi->vcard_imgids->data));
 
-					purple_buddy_icons_set_for_user(js->gc->account, bare_jid,
-							data, size);
-
 					purple_cipher_digest_region("sha1", (guchar *)data, size,
 							sizeof(hashval), hashval, NULL);
 					p = hash;
 					for(i=0; i<20; i++, p+=2)
 						snprintf(p, 3, "%02x", hashval[i]);
-					purple_blist_node_set_string((PurpleBlistNode*)b, "avatar_hash", hash);
+
+					purple_buddy_icons_set_for_user(js->gc->account, bare_jid,
+							data, size, hash);
 
 					g_free(data);
 					g_free(bintext);
--- a/libpurple/protocols/jabber/presence.c	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/protocols/jabber/presence.c	Wed Apr 25 00:56:13 2007 +0000
@@ -201,7 +201,6 @@
 static void jabber_vcard_parse_avatar(JabberStream *js, xmlnode *packet, gpointer blah)
 {
 	JabberBuddy *jb = NULL;
-	PurpleBuddy *b = NULL;
 	xmlnode *vcard, *photo, *binval;
 	char *text;
 	guchar *data;
@@ -221,21 +220,20 @@
 				(( (binval = xmlnode_get_child(photo, "BINVAL")) &&
 				(text = xmlnode_get_data(binval))) ||
 				(text = xmlnode_get_data(photo)))) {
+			unsigned char hashval[20];
+			char hash[41], *p;
+			int i;
+
 			data = purple_base64_decode(text, &size);
 
-			purple_buddy_icons_set_for_user(js->gc->account, from, data, size);
-			if((b = purple_find_buddy(js->gc->account, from))) {
-				unsigned char hashval[20];
-				char hash[41], *p;
-				int i;
+			purple_cipher_digest_region("sha1", data, size,
+					sizeof(hashval), hashval, NULL);
+			p = hash;
+			for(i=0; i<20; i++, p+=2)
+				snprintf(p, 3, "%02x", hashval[i]);
 
-				purple_cipher_digest_region("sha1", data, size,
-						sizeof(hashval), hashval, NULL);
-				p = hash;
-				for(i=0; i<20; i++, p+=2)
-					snprintf(p, 3, "%02x", hashval[i]);
-				purple_blist_node_set_string((PurpleBlistNode*)b, "avatar_hash", hash);
-			}
+			purple_buddy_icons_set_for_user(js->gc->account, from, data, size, hash);
+
 			g_free(data);
 			g_free(text);
 		}
@@ -520,7 +518,7 @@
 		}
 
 		if(avatar_hash) {
-			const char *avatar_hash2 = purple_blist_node_get_string((PurpleBlistNode*)b, "avatar_hash");
+			const char *avatar_hash2 = purple_buddy_icons_get_checksum_for_user(b);
 			if(!avatar_hash2 || strcmp(avatar_hash, avatar_hash2)) {
 				JabberIq *iq;
 				xmlnode *vcard;
--- a/libpurple/protocols/msn/slp.c	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/protocols/msn/slp.c	Wed Apr 25 00:56:13 2007 +0000
@@ -870,7 +870,7 @@
 	if (buddy == NULL)
 		return FALSE;
 
-	old = purple_blist_node_get_string((PurpleBlistNode *)buddy, "icon_checksum");
+	old = purple_buddy_icons_get_checksum_for_user(buddy);
 	new = msn_object_get_sha1(obj);
 
 	if (new == NULL)
@@ -956,22 +956,7 @@
 
 	if (obj == NULL)
 	{
-		/* It seems the user has not set a msnobject */
-		GSList *sl, *list;
-
-		list = purple_find_buddies(account, user->passport);
-
-		for (sl = list; sl != NULL; sl = sl->next)
-		{
-			PurpleBuddy *buddy = (PurpleBuddy *)sl->data;
-			if (buddy->icon)
-				purple_blist_node_remove_setting((PurpleBlistNode*)buddy, "icon_checksum");
-		}
-		g_slist_free(list);
-
-		/* TODO: I think we need better buddy icon core functions. */
-		purple_buddy_icons_set_for_user(account, user->passport, NULL, 0);
-
+		purple_buddy_icons_set_for_user(account, user->passport, NULL, 0, NULL);
 		return;
 	}
 
@@ -1001,7 +986,6 @@
 	MsnUserList *userlist;
 	const char *info;
 	PurpleAccount *account;
-	GSList *sl, *list;
 
 	g_return_if_fail(slpcall != NULL);
 
@@ -1013,18 +997,8 @@
 	userlist = slpcall->slplink->session->userlist;
 	account = slpcall->slplink->session->account;
 
-	/* TODO: I think we need better buddy icon core functions. */
 	purple_buddy_icons_set_for_user(account, slpcall->slplink->remote_user,
-								  (void *)data, size);
-
-	list = purple_find_buddies(account, slpcall->slplink->remote_user);
-
-	for (sl = list; sl != NULL; sl = sl->next)
-	{
-		PurpleBuddy *buddy = (PurpleBuddy *)sl->data;
-		purple_blist_node_set_string((PurpleBlistNode*)buddy, "icon_checksum", info);
-	}
-	g_slist_free(list);
+								  (void *)data, size, info);
 
 #if 0
 	/* Free one window slot */
@@ -1103,7 +1077,6 @@
 		MsnObject *my_obj = NULL;
 		gchar *data = NULL;
 		gsize len = 0;
-		GSList *sl, *list;
 
 #ifdef MSN_DEBUG_UD
 		purple_debug_info("msn", "Requesting our own user display\n");
@@ -1120,18 +1093,9 @@
 		}
 
 		/* TODO: I think we need better buddy icon core functions. */
-		purple_buddy_icons_set_for_user(account, user->passport, (void *)data, len);
+		purple_buddy_icons_set_for_user(account, user->passport, (void *)data, len, info);
 		g_free(data);
 
-		list = purple_find_buddies(account, user->passport);
-
-		for (sl = list; sl != NULL; sl = sl->next)
-		{
-			PurpleBuddy *buddy = (PurpleBuddy *)sl->data;
-			purple_blist_node_set_string((PurpleBlistNode*)buddy, "icon_checksum", info);
-		}
-		g_slist_free(list);
-
 		/* Free one window slot */
 		session->userlist->buddy_icon_window++;
 
--- a/libpurple/protocols/oscar/oscar.c	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Wed Apr 25 00:56:13 2007 +0000
@@ -1841,34 +1841,14 @@
 	bi->ipaddr = info->icqinfo.ipaddr;
 
 	if (info->iconcsumlen) {
-		const char *filename, *saved_b16 = NULL;
-		char *b16 = NULL, *filepath = NULL;
+		const char *saved_b16 = NULL;
+		char *b16 = NULL;
 		PurpleBuddy *b = NULL;
 
 		b16 = purple_base16_encode(info->iconcsum, info->iconcsumlen);
 		b = purple_find_buddy(account, info->sn);
-		/*
-		 * If for some reason the checksum is valid, but cached file is not..
-		 * we want to know.
-		 */
 		if (b != NULL)
-			filename = purple_blist_node_get_string((PurpleBlistNode*)b, "buddy_icon");
-		else
-			filename = NULL;
-		if (filename != NULL) {
-			if (g_file_test(filename, G_FILE_TEST_EXISTS))
-				saved_b16 = purple_blist_node_get_string((PurpleBlistNode*)b,
-						"icon_checksum");
-			else {
-				filepath = g_build_filename(purple_buddy_icons_get_cache_dir(),
-											filename, NULL);
-				if (g_file_test(filepath, G_FILE_TEST_EXISTS))
-					saved_b16 = purple_blist_node_get_string((PurpleBlistNode*)b,
-															"icon_checksum");
-				g_free(filepath);
-			}
-		} else
-			saved_b16 = NULL;
+			saved_b16 = purple_buddy_icons_get_checksum_for_user(b);
 
 		if (!b16 || !saved_b16 || strcmp(b16, saved_b16)) {
 			GSList *cur = od->requesticon;
@@ -2177,7 +2157,8 @@
 	{
 		purple_buddy_icons_set_for_user(account, userinfo->sn,
 									  args->info.icon.icon,
-									  args->info.icon.length);
+									  args->info.icon.length,
+									  NULL);
 	}
 
 	else if (args->type & OSCAR_CAPABILITY_ICQSERVERRELAY)
@@ -3273,16 +3254,10 @@
 	 * no icon is set.  Ignore these.
 	 */
 	if ((iconlen > 0) && (iconlen != 90)) {
-		char *b16;
-		PurpleBuddy *b;
+		char *b16 = purple_base16_encode(iconcsum, iconcsumlen);
 		purple_buddy_icons_set_for_user(purple_connection_get_account(gc),
-									  sn, icon, iconlen);
-		b16 = purple_base16_encode(iconcsum, iconcsumlen);
-		b = purple_find_buddy(gc->account, sn);
-		if ((b16 != NULL) && (b != NULL)) {
-			purple_blist_node_set_string((PurpleBlistNode*)b, "icon_checksum", b16);
-			g_free(b16);
-		}
+									  sn, icon, iconlen, b16);
+		g_free(b16);
 	}
 
 	cur = od->requesticon;
--- a/libpurple/protocols/qq/buddy_info.c	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/protocols/qq/buddy_info.c	Wed Apr 25 00:56:13 2007 +0000
@@ -531,21 +531,17 @@
 	qq_send_packet_get_info(gc, qd->uid, FALSE);
 }
 
-void qq_set_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *iconfile)
+void qq_set_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *icon_num, const gchar *iconfile)
 {
-	FILE *file;
-	struct stat st;
+	gchar *data;
+	gsize len;
 
-	g_return_if_fail(g_stat(iconfile, &st) == 0);
-	file = g_fopen(iconfile, "rb");
-	if (file) {
-		PurpleBuddyIcon *icon;
-		size_t data_len;
-		gchar *data = g_new(gchar, st.st_size + 1);
-		data_len = fread(data, 1, st.st_size, file);
-		fclose(file);
-		purple_buddy_icons_set_for_user(account, who, data, data_len);
-		// TODO: Set a blist setting or something
+	if (!g_file_get_contents(iconfile, &data, &len, NULL))
+		g_return_if_reached();
+	else
+	{
+		purple_buddy_icons_set_for_user(account, who, data, len, icon_num);
+		g_free(data);
 	}
 }
 
@@ -599,26 +595,29 @@
 	/* tell server my icon changed */
 	_qq_send_packet_modify_face(gc, icon_num);
 	/* display in blist */
-	qq_set_buddy_icon_for_user(account, account->username, icon_path);
+	qq_set_buddy_icon_for_user(account, account->username, icon, icon_path);
 }
 
 
 static void _qq_update_buddy_icon(PurpleAccount *account, const gchar *name, gint face)
 {
-	gchar *icon_path;
 	PurpleBuddyIcon *icon = purple_buddy_icons_find(account, name);
 	gchar *icon_num_str = face_to_icon_str(face);
-	// TODO: This needs to use a blist setting or something.
-	const gchar *old_path = NULL;
-	const gchar *buddy_icon_dir = qq_buddy_icon_dir();
+	const gchar *old_icon_num = purple_buddy_icon_get_checksum(icon);
+
+	if (icon == NULL || old_icon_num == NULL ||
+	    strcmp(icon_num_str, old_icon_num))
+	{
+		gchar *icon_path;
 
-	icon_path = g_strconcat(buddy_icon_dir, G_DIR_SEPARATOR_S, QQ_ICON_PREFIX, 
-			icon_num_str, QQ_ICON_SUFFIX, NULL);
-	if (icon == NULL || old_path == NULL 
-		|| g_ascii_strcasecmp(icon_path, old_path) != 0)
-		qq_set_buddy_icon_for_user(account, name, icon_path);
+		icon_path = g_strconcat(qq_buddy_icon_dir(), G_DIR_SEPARATOR_S,
+		                        QQ_ICON_PREFIX, icon_num_str,
+		                        QQ_ICON_SUFFIX, NULL);
+
+		qq_set_buddy_icon_for_user(account, name, icon_num_str, icon_path);
+		g_free(icon_path);
+	}
 	g_free(icon_num_str);
-	g_free(icon_path);
 }
 
 /* after getting info or modify myself, refresh the buddy list accordingly */
--- a/libpurple/protocols/qq/buddy_info.h	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/protocols/qq/buddy_info.h	Wed Apr 25 00:56:13 2007 +0000
@@ -87,7 +87,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_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *iconfile);
+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);
 void qq_process_get_info_reply(guint8 *buf, gint buf_len, PurpleConnection *gc);
--- a/libpurple/protocols/yahoo/yahoo.c	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Wed Apr 25 00:56:13 2007 +0000
@@ -342,6 +342,8 @@
 		}
 		case 192: /* Pictures, aka Buddy Icons, checksum */
 		{
+			/* FIXME: Please, if you know this protocol,
+			 * FIXME: fix up the strtol() stuff if possible. */
 			int cksum = strtol(pair->value, NULL, 10);
 			PurpleBuddy *b;
 
@@ -353,9 +355,7 @@
 			if (!cksum || (cksum == -1)) {
 				if (f)
 					yahoo_friend_set_buddy_icon_need_request(f, TRUE);
-				purple_buddy_icons_set_for_user(gc->account, name, NULL, 0);
-				if (b)
-					purple_blist_node_remove_setting((PurpleBlistNode *)b, YAHOO_ICON_CHECKSUM_KEY);
+				purple_buddy_icons_set_for_user(gc->account, name, NULL, 0, NULL);
 				break;
 			}
 
@@ -363,7 +363,7 @@
 				break;
 
 			yahoo_friend_set_buddy_icon_need_request(f, FALSE);
-			if (b && cksum != purple_blist_node_get_int((PurpleBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY))
+			if (b && cksum != strtol(purple_buddy_icons_get_checksum_for_user(b), NULL, 10))
 				yahoo_send_picture_request(gc, name);
 
 			break;
--- a/libpurple/protocols/yahoo/yahoo.h	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo.h	Wed Apr 25 00:56:13 2007 +0000
@@ -48,7 +48,6 @@
 
 #define WEBMESSENGER_URL "http://login.yahoo.com/config/login?.src=pg"
 
-#define YAHOO_ICON_CHECKSUM_KEY "icon_checksum"
 #define YAHOO_PICURL_SETTING "picture_url"
 #define YAHOO_PICCKSUM_SETTING "picture_checksum"
 #define YAHOO_PICEXPIRE_SETTING "picture_expire"
--- a/libpurple/protocols/yahoo/yahoo_picture.c	Tue Apr 24 20:23:50 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo_picture.c	Wed Apr 25 00:56:13 2007 +0000
@@ -49,7 +49,6 @@
 {
 	struct yahoo_fetch_picture_data *d;
 	struct yahoo_data *yd;
-	PurpleBuddy *b;
 
 	d = user_data;
 	yd = d->gc->proto_data;
@@ -60,10 +59,9 @@
 	} else if (len == 0) {
 		purple_debug_error("yahoo", "Fetched an icon with length 0.  Strange.\n");
 	} else {
-		purple_buddy_icons_set_for_user(purple_connection_get_account(d->gc), d->who, (void *)pic_data, len);
-		b = purple_find_buddy(purple_connection_get_account(d->gc), d->who);
-		if (b)
-			purple_blist_node_set_int((PurpleBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY, d->checksum);
+		char *checksum = g_strdup_printf("%i", d->checksum);
+		purple_buddy_icons_set_for_user(purple_connection_get_account(d->gc), d->who, (void *)pic_data, len, checksum);
+		g_free(checksum);
 	}
 
 	g_free(d->who);
@@ -117,7 +115,9 @@
 		PurpleUtilFetchUrlData *url_data;
 		struct yahoo_fetch_picture_data *data;
 		PurpleBuddy *b = purple_find_buddy(gc->account, who);
-		if (b && (checksum == purple_blist_node_get_int((PurpleBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY)))
+
+		/* FIXME: Cleanup this strtol() stuff if possible. */
+		if (b && (checksum == strtol(purple_buddy_icons_get_checksum_for_user(b), NULL, 10)))
 			return;
 
 		data = g_new0(struct yahoo_fetch_picture_data, 1);
@@ -166,11 +166,8 @@
 		if (icon == 2)
 			yahoo_send_picture_request(gc, who);
 		else if ((icon == 0) || (icon == 1)) {
-			PurpleBuddy *b = purple_find_buddy(gc->account, who);
 			YahooFriend *f;
-			purple_buddy_icons_set_for_user(gc->account, who, NULL, 0);
-			if (b)
-				purple_blist_node_remove_setting((PurpleBlistNode *)b, YAHOO_ICON_CHECKSUM_KEY);
+			purple_buddy_icons_set_for_user(gc->account, who, NULL, 0, NULL);
 			if ((f = yahoo_friend_find(gc, who)))
 				yahoo_friend_set_buddy_icon_need_request(f, TRUE);
 			purple_debug_misc("yahoo", "Setting user %s's icon to NULL.\n", who);
@@ -203,7 +200,9 @@
 
 	if (who) {
 		PurpleBuddy *b = purple_find_buddy(gc->account, who);
-		if (b && (checksum != purple_blist_node_get_int((PurpleBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY)))
+
+		/* FIXME: Cleanup this strtol() stuff if possible. */
+		if (b && (checksum != strtol(purple_buddy_icons_get_checksum_for_user(b), NULL, 10)))
 			yahoo_send_picture_request(gc, who);
 	}
 }
@@ -276,11 +275,8 @@
 		if (avatar == 2)
 			yahoo_send_picture_request(gc, who);
 		else if ((avatar == 0) || (avatar == 1)) {
-			PurpleBuddy *b = purple_find_buddy(gc->account, who);
 			YahooFriend *f;
-			purple_buddy_icons_set_for_user(gc->account, who, NULL, 0);
-			if (b)
-				purple_blist_node_remove_setting((PurpleBlistNode *)b, YAHOO_ICON_CHECKSUM_KEY);
+			purple_buddy_icons_set_for_user(gc->account, who, NULL, 0, NULL);
 			if ((f = yahoo_friend_find(gc, who)))
 				yahoo_friend_set_buddy_icon_need_request(f, TRUE);
 			purple_debug_misc("yahoo", "Setting user %s's icon to NULL.\n", who);