# HG changeset patch # User Daniel Atallah # Date 1161142334 0 # Node ID 4124030c3f3a8f14c4adde8a699828df57742873 # Parent 510da3975938d39869988626cc9bc158cb61a6c8 [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 diff -r 510da3975938 -r 4124030c3f3a libgaim/blist.c --- 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; } diff -r 510da3975938 -r 4124030c3f3a libgaim/blist.h --- 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 */ diff -r 510da3975938 -r 4124030c3f3a libgaim/connection.c --- 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);