changeset 14752:4124030c3f3a

[gaim-migrate @ 17509] Fix the situation (I think it will only happen while shutting down) where GaimBuddy->proto_data could be accessed after it is freed. Specifically, it happened when gtkblist was requesting the emblems from the msn prpl. Big thanks to henningn for noticing the funkiness in valgrind. I discovered that there is no function to retrieve all the buddies for an account (shock, horror) - so I modified gaim_find_buddies() to return all the account buddies if "name" is NULL. committer: Tailor Script <tailor@pidgin.im>
author Daniel Atallah <daniel.atallah@gmail.com>
date Wed, 18 Oct 2006 03:32:14 +0000
parents 510da3975938
children 2993aae00c9c
files libgaim/blist.c libgaim/blist.h libgaim/connection.c
diffstat 3 files changed, 47 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/libgaim/blist.c	Wed Oct 18 03:27:43 2006 +0000
+++ b/libgaim/blist.c	Wed Oct 18 03:32:14 2006 +0000
@@ -65,6 +65,11 @@
 	return gaim_blist_get_last_sibling(node->child);
 }
 
+struct _list_account_buddies {
+	GSList *list;
+	GaimAccount *account;
+};
+
 struct _gaim_hbuddy {
 	char *name;
 	GaimAccount *account;
@@ -2119,26 +2124,46 @@
 	return ret;
 }
 
+static void find_acct_buddies(gpointer key, gpointer value, gpointer data)
+{
+	struct _gaim_hbuddy *hb = key;
+	GaimBuddy *buddy = value;
+	struct _list_account_buddies *ab = data;
+
+	if (hb->account == ab->account) {
+		ab->list = g_slist_prepend(ab->list, buddy);
+	}
+}
+
 GSList *gaim_find_buddies(GaimAccount *account, const char *name)
 {
-	struct buddy *buddy;
-	struct _gaim_hbuddy hb;
+	GaimBuddy *buddy;
 	GaimBlistNode *node;
 	GSList *ret = NULL;
 
 	g_return_val_if_fail(gaimbuddylist != NULL, NULL);
 	g_return_val_if_fail(account != NULL, NULL);
-	g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
-
-	hb.name = g_strdup(gaim_normalize(account, name));
-	hb.account = account;
-
-	for (node = gaimbuddylist->root; node != NULL; node = node->next) {
-		hb.group = node;
-		if ((buddy = g_hash_table_lookup(gaimbuddylist->buddies, &hb)) != NULL)
-			ret = g_slist_append(ret, buddy);
+
+
+	if ((name != NULL) && (*name != '\0')) {
+		struct _gaim_hbuddy hb;
+
+		hb.name = g_strdup(gaim_normalize(account, name));
+		hb.account = account;
+
+		for (node = gaimbuddylist->root; node != NULL; node = node->next) {
+			hb.group = node;
+			if ((buddy = g_hash_table_lookup(gaimbuddylist->buddies, &hb)) != NULL)
+				ret = g_slist_prepend(ret, buddy);
+		}
+		g_free(hb.name);
+	} else {
+		struct _list_account_buddies *ab = g_new0(struct _list_account_buddies, 1);
+		ab->account = account;
+		g_hash_table_foreach(gaimbuddylist->buddies, find_acct_buddies, ab);
+		ret = ab->list;
+		g_free(ab);
 	}
-	g_free(hb.name);
 
 	return ret;
 }
--- a/libgaim/blist.h	Wed Oct 18 03:27:43 2006 +0000
+++ b/libgaim/blist.h	Wed Oct 18 03:32:14 2006 +0000
@@ -616,7 +616,7 @@
  * Finds all GaimBuddy structs given a screenname and an account
  *
  * @param account The account this buddy belongs to
- * @param name    The buddy's screenname
+ * @param name    The buddy's screenname (or NULL to return all buddies in the account)
  *
  * @return        A GSList of buddies (which must be freed), or NULL if the buddy doesn't exist
  */
--- a/libgaim/connection.c	Wed Oct 18 03:27:43 2006 +0000
+++ b/libgaim/connection.c	Wed Oct 18 03:32:14 2006 +0000
@@ -160,6 +160,7 @@
 gaim_connection_destroy(GaimConnection *gc)
 {
 	GaimAccount *account;
+	GSList *buddies, *tmp;
 #if 0
 	GList *wins;
 #endif
@@ -195,6 +196,14 @@
 			(prpl_info->close)(gc);
 	}
 
+	/* Clear out the proto data that was freed in the prpl close method*/
+	buddies = gaim_find_buddies(account, NULL);
+	for (tmp = buddies; tmp; tmp = tmp->next) {
+		GaimBuddy *buddy = tmp->data;
+		buddy->proto_data = NULL;
+	}
+	g_slist_free(buddies);
+
 	connections = g_list_remove(connections, gc);
 
 	gaim_connection_set_state(gc, GAIM_DISCONNECTED);