changeset 9285:7a8aa87164ae

[gaim-migrate @ 10088] Ok I'm done. This started out as shx's patch to make add/remove buddy/buddies take GaimBuddy and GaimGroup's in various places. I think his diff was like 2000 lines and mine is like 5000. I tried to clean up blist.c a bit and make it more uniform. There are some more g_return_if_fail() checks. Removed some code that was deprecated--it's probably been long enough. Removed some #include <multi.h>'s. Make blist.xml saving happen on a timer, like prefs.xml and accounts.xml. Sorry if this doesn't merge cleanly with whatever you're doing. People should really test this a lot. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Tue, 15 Jun 2004 02:37:27 +0000
parents fe0291162312
children 46cfbd17ce3e
files plugins/perl/common/BuddyList_Buddy.xs plugins/perl/common/BuddyList_Chat.xs plugins/perl/common/BuddyList_Group.xs src/account.c src/blist.c src/blist.h src/buddyicon.c src/connection.c src/dialogs.c src/gtkblist.c src/gtkconv.c src/gtkprefs.c src/gtkprivacy.c src/idle.c src/privacy.c src/protocols/gg/gg.c src/protocols/icq/gaim_icq.c src/protocols/irc/irc.c src/protocols/jabber/buddy.c src/protocols/jabber/roster.c src/protocols/jabber/roster.h src/protocols/msn/msn.c src/protocols/msn/slp.c src/protocols/napster/napster.c src/protocols/novell/novell.c src/protocols/oscar/oscar.c src/protocols/oscar/ssi.c src/protocols/silc/buddy.c src/protocols/silc/silc.c src/protocols/toc/toc.c src/protocols/trepia/trepia.c src/protocols/yahoo/yahoo.c src/prpl.c src/prpl.h src/server.c src/server.h
diffstat 36 files changed, 1221 insertions(+), 1454 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/perl/common/BuddyList_Buddy.xs	Tue Jun 15 01:17:16 2004 +0000
+++ b/plugins/perl/common/BuddyList_Buddy.xs	Tue Jun 15 02:37:27 2004 +0000
@@ -94,14 +94,3 @@
 	RETVAL = gaim_find_buddys_group(buddy);
 OUTPUT:
 	RETVAL
-
-void
-gaim_buddy_set_setting(buddy, key, value)
-	Gaim::BuddyList::Buddy buddy
-	const char *key
-	const char *value
-
-const char *
-gaim_buddy_get_setting(buddy, key)
-	Gaim::BuddyList::Buddy buddy
-	const char *key
--- a/plugins/perl/common/BuddyList_Chat.xs	Tue Jun 15 01:17:16 2004 +0000
+++ b/plugins/perl/common/BuddyList_Chat.xs	Tue Jun 15 02:37:27 2004 +0000
@@ -26,21 +26,6 @@
 OUTPUT:
 	RETVAL
 
-void
-gaim_chat_set_setting(chat, key, value)
-	Gaim::BuddyList::Chat chat
-	const char *key
-	const char *value
-
-const char *
-gaim_chat_get_setting(chat, key)
-	Gaim::BuddyList::Chat chat
-	const char *key
-CODE:
-	RETVAL = gaim_chat_get_setting(chat, key);
-OUTPUT:
-	RETVAL
-
 Gaim::Account
 get_account(chat)
 	Gaim::BuddyList::Chat chat
--- a/plugins/perl/common/BuddyList_Group.xs	Tue Jun 15 01:17:16 2004 +0000
+++ b/plugins/perl/common/BuddyList_Group.xs	Tue Jun 15 02:37:27 2004 +0000
@@ -53,17 +53,6 @@
 	RETVAL
 
 void
-gaim_group_set_setting(group, key, value)
-	Gaim::BuddyList::Group group
-	const char *key
-	const char *value
-
-const char *
-gaim_group_get_setting(group, key)
-	Gaim::BuddyList::Group group
-	const char *key
-
-void
 buddies(group)
 	Gaim::BuddyList::Group group
 PREINIT:
--- a/src/account.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/account.c	Tue Jun 15 02:37:27 2004 +0000
@@ -1482,7 +1482,6 @@
 			}
 		}
 	}
-	gaim_blist_save();
 
 	/* Remove this account's pounces */
 	gaim_pounce_destroy_all_by_account(account);
--- a/src/blist.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/blist.c	Tue Jun 15 02:37:27 2004 +0000
@@ -38,6 +38,7 @@
 
 GaimBuddyList *gaimbuddylist = NULL;
 static GaimBlistUiOps *blist_ui_ops = NULL;
+static guint blist_save_timer = 0;
 
 struct gaim_blist_node_setting {
 	enum {
@@ -80,12 +81,12 @@
 	GaimBlistNode *group;
 };
 
-static guint _gaim_blist_hbuddy_hash (struct _gaim_hbuddy *hb)
+static guint _gaim_blist_hbuddy_hash(struct _gaim_hbuddy *hb)
 {
 	return g_str_hash(hb->name);
 }
 
-static guint _gaim_blist_hbuddy_equal (struct _gaim_hbuddy *hb1, struct _gaim_hbuddy *hb2)
+static guint _gaim_blist_hbuddy_equal(struct _gaim_hbuddy *hb1, struct _gaim_hbuddy *hb2)
 {
 	return ((!strcmp(hb1->name, hb2->name)) && hb1->account == hb2->account && hb1->group == hb2->group);
 }
@@ -96,49 +97,47 @@
 	g_free(hb);
 }
 
-static void blist_pref_cb(const char *name, GaimPrefType typ, gpointer value, gpointer data)
+static void blist_pref_cb(const char *name, GaimPrefType type, gpointer value, gpointer data)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimBlistNode *gnode, *cnode, *bnode;
 
-	if (!ops)
+	if (!ops || !ops->update)
 		return;
 
-	for(gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
-		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
+	for (gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
+		if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
-			if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
-				for(bnode = cnode->child; bnode; bnode = bnode->next) {
-					if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
+		for (cnode = gnode->child; cnode; cnode = cnode->next) {
+			if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+				for (bnode = cnode->child; bnode; bnode = bnode->next) {
+					if (!GAIM_BLIST_NODE_IS_BUDDY(bnode))
 						continue;
 					ops->update(gaimbuddylist, bnode);
 				}
-			} else if(GAIM_BLIST_NODE_IS_CHAT(cnode)) {
+			} else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) {
 				ops->update(gaimbuddylist, cnode);
 			}
 		}
 	}
 }
 
-GaimContact *gaim_buddy_get_contact(GaimBuddy *buddy)
+static void gaim_contact_compute_priority_buddy(GaimContact *contact)
 {
-	return (GaimContact*)((GaimBlistNode*)buddy)->parent;
-}
-
-static void gaim_contact_compute_priority_buddy(GaimContact *contact) {
 	GaimBlistNode *bnode;
 	int contact_score = INT_MAX;
+
+	g_return_if_fail(contact != NULL);
+
 	contact->priority = NULL;
-
-	for(bnode = ((GaimBlistNode*)contact)->child; bnode; bnode = bnode->next) {
+	for (bnode = ((GaimBlistNode*)contact)->child; bnode; bnode = bnode->next) {
 		GaimBuddy *buddy;
 		int score = 0;
 
-		if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
+		if (!GAIM_BLIST_NODE_IS_BUDDY(bnode))
 			continue;
 		buddy = (GaimBuddy*)bnode;
-		if(!gaim_account_is_connected(buddy->account))
+		if (!gaim_account_is_connected(buddy->account))
 			continue;
 
 		if (!GAIM_BUDDY_IS_ONLINE(buddy))
@@ -160,6 +159,20 @@
 	}
 }
 
+static gboolean blist_save_callback(gpointer data)
+{
+	gaim_blist_sync();
+	blist_save_timer = 0;
+	return FALSE;
+}
+
+static void schedule_blist_save()
+{
+	if (blist_save_timer != 0)
+		gaim_timeout_remove(blist_save_timer);
+	blist_save_timer = gaim_timeout_add(1000, blist_save_callback, NULL);
+}
+
 
 /*****************************************************************************
  * Public API functions                                                      *
@@ -181,7 +194,6 @@
 	gaim_prefs_connect_callback("/core/buddies/use_server_alias",
 								blist_pref_cb, NULL);
 
-
 	return gbl;
 }
 
@@ -192,41 +204,45 @@
 }
 
 GaimBuddyList *
-gaim_get_blist(void)
+gaim_get_blist()
 {
 	return gaimbuddylist;
 }
 
-void  gaim_blist_show ()
+void gaim_blist_show()
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	if (ops)
+
+	if (ops && ops->show)
 		ops->show(gaimbuddylist);
 }
 
 void gaim_blist_destroy()
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
+
 	gaim_debug(GAIM_DEBUG_INFO, "blist", "Destroying\n");
-	if (ops)
+
+	if (ops && ops->destroy)
 		ops->destroy(gaimbuddylist);
 }
 
-void  gaim_blist_set_visible (gboolean show)
+void gaim_blist_set_visible(gboolean show)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	if (ops)
+
+	if (ops && ops->set_visible)
 		ops->set_visible(gaimbuddylist, show);
 }
 
-void  gaim_blist_update_buddy_status (GaimBuddy *buddy, int status)
+void gaim_blist_update_buddy_status(GaimBuddy *buddy, int status)
 {
-	GaimBlistUiOps *ops;
-	int old_status = buddy->uc;
-
-
-	ops = gaimbuddylist->ui_ops;
-
+	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
+	int old_status;
+
+	g_return_if_fail(buddy != NULL);
+
+	old_status = buddy->uc;
 	if (old_status != status) {
 		buddy->uc = status;
 		gaim_contact_compute_priority_buddy(gaim_buddy_get_contact(buddy));
@@ -239,30 +255,32 @@
 		}
 	}
 
-	if (ops)
+	if (ops && ops->update)
 		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
 }
 
-static gboolean presence_update_timeout_cb(GaimBuddy *buddy) {
+static gboolean presence_update_timeout_cb(GaimBuddy *buddy)
+{
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimConversation *conv;
 
-	conv = gaim_find_conversation_with_account(buddy->name, buddy->account);
-
-	if(buddy->present == GAIM_BUDDY_SIGNING_ON) {
+	g_return_val_if_fail(buddy != NULL, FALSE);
+
+	if (buddy->present == GAIM_BUDDY_SIGNING_ON) {
 		buddy->present = GAIM_BUDDY_ONLINE;
-	} else if(buddy->present == GAIM_BUDDY_SIGNING_OFF) {
+	} else if (buddy->present == GAIM_BUDDY_SIGNING_OFF) {
 		buddy->present = GAIM_BUDDY_OFFLINE;
 		((GaimContact*)((GaimBlistNode*)buddy)->parent)->online--;
-		if(((GaimContact*)((GaimBlistNode*)buddy)->parent)->online == 0)
+		if (((GaimContact*)((GaimBlistNode*)buddy)->parent)->online == 0)
 			((GaimGroup *)((GaimBlistNode *)buddy)->parent->parent)->online--;
 	}
 
 	buddy->timer = 0;
 
-	if (ops)
+	if (ops && ops->update)
 		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
 
+	conv = gaim_find_conversation_with_account(buddy->name, buddy->account);
 	if (conv) {
 		if (buddy->present == GAIM_BUDDY_ONLINE)
 			gaim_conversation_update(conv, GAIM_CONV_ACCOUNT_ONLINE);
@@ -273,83 +291,109 @@
 	return FALSE;
 }
 
-void gaim_blist_update_buddy_presence(GaimBuddy *buddy, int presence) {
+void gaim_blist_update_buddy_presence(GaimBuddy *buddy, int presence)
+{
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	gboolean do_something = FALSE;
+	gboolean did_something = FALSE;
+
+	g_return_if_fail(buddy != NULL);
 
 	if (!GAIM_BUDDY_IS_ONLINE(buddy) && presence) {
 		int old_present = buddy->present;
 		buddy->present = GAIM_BUDDY_SIGNING_ON;
 		gaim_signal_emit(gaim_blist_get_handle(), "buddy-signed-on", buddy);
-		do_something = TRUE;
-
-		if(old_present != GAIM_BUDDY_SIGNING_OFF) {
+		did_something = TRUE;
+
+		if (old_present != GAIM_BUDDY_SIGNING_OFF) {
 			((GaimContact*)((GaimBlistNode*)buddy)->parent)->online++;
-			if(((GaimContact*)((GaimBlistNode*)buddy)->parent)->online == 1)
+			if (((GaimContact*)((GaimBlistNode*)buddy)->parent)->online == 1)
 				((GaimGroup *)((GaimBlistNode *)buddy)->parent->parent)->online++;
 		}
-	} else if(GAIM_BUDDY_IS_ONLINE(buddy) && !presence) {
+	} else if (GAIM_BUDDY_IS_ONLINE(buddy) && !presence) {
 		buddy->present = GAIM_BUDDY_SIGNING_OFF;
 		gaim_signal_emit(gaim_blist_get_handle(), "buddy-signed-off", buddy);
-		do_something = TRUE;
+		did_something = TRUE;
 	}
 
-	if(do_something) {
-		if(buddy->timer > 0)
+	if (did_something) {
+		if (buddy->timer > 0)
 			gaim_timeout_remove(buddy->timer);
 		buddy->timer = gaim_timeout_add(10000, (GSourceFunc)presence_update_timeout_cb, buddy);
 
 		gaim_contact_compute_priority_buddy(gaim_buddy_get_contact(buddy));
-		if (ops)
-			ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+		if (ops && ops->update)
+			ops->update(gaimbuddylist, (GaimBlistNode *)buddy);
 	}
 }
 
-void  gaim_blist_update_buddy_signon (GaimBuddy *buddy, time_t signon)
+void gaim_blist_update_buddy_signon(GaimBuddy *buddy, time_t signon)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	if(buddy->signon == signon)
+
+	g_return_if_fail(buddy != NULL);
+
+	if (buddy->signon == signon)
 		return;
 
 	buddy->signon = signon;
-	if (ops)
-		ops->update(gaimbuddylist,(GaimBlistNode*)buddy);
+
+	if (ops && ops->update)
+		ops->update(gaimbuddylist, (GaimBlistNode *)buddy);
 }
 
-void  gaim_blist_update_buddy_idle (GaimBuddy *buddy, int idle)
+void gaim_blist_update_buddy_idle(GaimBuddy *buddy, int idle)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	if(buddy->idle == idle)
+
+	g_return_if_fail(buddy != NULL);
+
+	if (buddy->idle == idle)
 		return;
 
 	buddy->idle = idle;
 	gaim_contact_compute_priority_buddy(gaim_buddy_get_contact(buddy));
-	if (ops)
-		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+
+	if (ops && ops->update)
+		ops->update(gaimbuddylist, (GaimBlistNode *)buddy);
 }
 
-void  gaim_blist_update_buddy_evil (GaimBuddy *buddy, int warning)
+void gaim_blist_update_buddy_evil(GaimBuddy *buddy, int warning)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	if(buddy->evil == warning)
+
+	g_return_if_fail(buddy != NULL);
+
+	if (buddy->evil == warning)
 		return;
 
 	buddy->evil = warning;
-	if (ops)
-		ops->update(gaimbuddylist,(GaimBlistNode*)buddy);
+
+	if (ops && ops->update)
+		ops->update(gaimbuddylist, (GaimBlistNode *)buddy);
 }
 
-void gaim_blist_update_buddy_icon(GaimBuddy *buddy) {
-	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	if(ops)
-		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
-}
-
-void  gaim_blist_rename_buddy (GaimBuddy *buddy, const char *name)
+void gaim_blist_update_buddy_icon(GaimBuddy *buddy)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	struct _gaim_hbuddy *hb = g_new(struct _gaim_hbuddy, 1);
-
+
+	g_return_if_fail(buddy != NULL);
+
+	if (ops && ops->update)
+		ops->update(gaimbuddylist, (GaimBlistNode *)buddy);
+}
+
+/*
+ * XXX - Maybe remove the call to this from server.c and call it
+ * from oscar.c and toc.c instead?
+ */
+void gaim_blist_rename_buddy(GaimBuddy *buddy, const char *name)
+{
+	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
+	struct _gaim_hbuddy *hb;
+
+	g_return_if_fail(buddy != NULL);
+
+	hb = g_new(struct _gaim_hbuddy, 1);
 	hb->name = g_strdup(gaim_normalize(buddy->account, buddy->name));
 	hb->account = buddy->account;
 	hb->group = ((GaimBlistNode *)buddy)->parent->parent;
@@ -361,139 +405,182 @@
 
 	g_free(buddy->name);
 	buddy->name = g_strdup(name);
-	if (ops)
-		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+
+	schedule_blist_save();
+
+	if (ops && ops->update)
+		ops->update(gaimbuddylist, (GaimBlistNode *)buddy);
 }
 
 void gaim_blist_alias_chat(GaimChat *chat, const char *alias)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 
+	g_return_if_fail(chat != NULL);
+
 	g_free(chat->alias);
-
-	if(alias && strlen(alias))
+	if ((alias != NULL) && (*alias != '\0'))
 		chat->alias = g_strdup(alias);
 	else
 		chat->alias = NULL;
 
-	if(ops)
-		ops->update(gaimbuddylist, (GaimBlistNode*)chat);
+	schedule_blist_save();
+
+	if (ops && ops->update)
+		ops->update(gaimbuddylist, (GaimBlistNode *)chat);
 }
 
-void  gaim_blist_alias_buddy (GaimBuddy *buddy, const char *alias)
+void gaim_blist_alias_buddy(GaimBuddy *buddy, const char *alias)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimConversation *conv;
 
+	g_return_if_fail(buddy != NULL);
+
 	g_free(buddy->alias);
-
-	if(alias && strlen(alias))
+	if ((alias != NULL) && (*alias != '\0'))
 		buddy->alias = g_strdup(alias);
 	else
 		buddy->alias = NULL;
 
-	if (ops)
-		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+	schedule_blist_save();
+
+	if (ops && ops->update)
+		ops->update(gaimbuddylist, (GaimBlistNode *)buddy);
 
 	conv = gaim_find_conversation_with_account(buddy->name, buddy->account);
-
 	if (conv)
 		gaim_conversation_autoset_title(conv);
 }
 
-void  gaim_blist_server_alias_buddy (GaimBuddy *buddy, const char *alias)
+void gaim_blist_server_alias_buddy(GaimBuddy *buddy, const char *alias)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimConversation *conv;
 
+	g_return_if_fail(buddy != NULL);
+
 	g_free(buddy->server_alias);
-
-	if(alias && strlen(alias) && g_utf8_validate(alias, -1, NULL))
+	if ((alias != NULL) && (*alias != '\0') && g_utf8_validate(alias, -1, NULL))
 		buddy->server_alias = g_strdup(alias);
 	else
 		buddy->server_alias = NULL;
 
-	if (ops)
-		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+	schedule_blist_save();
+
+	if (ops && ops->update)
+		ops->update(gaimbuddylist, (GaimBlistNode *)buddy);
 
 	conv = gaim_find_conversation_with_account(buddy->name, buddy->account);
-
 	if (conv)
 		gaim_conversation_autoset_title(conv);
 }
 
-void gaim_blist_rename_group(GaimGroup *group, const char *name)
+/*
+ * XXX - If merging, prompt the user if they want to merge.
+ */
+void gaim_blist_rename_group(GaimGroup *source, const char *new_name)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	GaimGroup *dest_group;
-	GaimBlistNode *prev, *child, *next;
+	GaimGroup *dest;
+	gchar *old_name;
+	GList *moved_buddies = NULL;
 	GSList *accts;
 
-	if(!name || !strlen(name) || !strcmp(name, group->name)) {
-		/* nothing to do here */
+	g_return_if_fail(source != NULL);
+	g_return_if_fail(new_name != NULL);
+
+	if (*new_name == '\0' || !strcmp(new_name, source->name))
 		return;
-	} else if((dest_group = gaim_find_group(name))) {
-		/* here we're merging two groups */
-		prev = gaim_blist_get_last_child((GaimBlistNode*)dest_group);
-		child = ((GaimBlistNode*)group)->child;
-
-		while(child)
+
+	dest = gaim_find_group(new_name);
+	if (dest != NULL) {
+		/* We're merging two groups */
+		GaimBlistNode *prev, *child, *next;
+
+		prev = gaim_blist_get_last_child((GaimBlistNode*)dest);
+		child = ((GaimBlistNode*)source)->child;
+
+		/*
+		 * XXX - This seems like a dumb way to do this... why not just
+		 * append all children from the old group to the end of the new
+		 * one?  PRPLs might be expecting to receive an add_buddy() for
+		 * each moved buddy...
+		 */
+		while (child)
 		{
 			next = child->next;
-			if(GAIM_BLIST_NODE_IS_CONTACT(child)) {
+			if (GAIM_BLIST_NODE_IS_CONTACT(child)) {
 				GaimBlistNode *bnode;
-				gaim_blist_add_contact((GaimContact *)child, dest_group, prev);
-				for(bnode = child->child; bnode; bnode = bnode->next)
-					gaim_blist_add_buddy((GaimBuddy*)bnode, (GaimContact*)child,
+				gaim_blist_add_contact((GaimContact *)child, dest, prev);
+				for (bnode = child->child; bnode != NULL; bnode = bnode->next) {
+					gaim_blist_add_buddy((GaimBuddy *)bnode, (GaimContact *)child,
 							NULL, bnode->prev);
+					moved_buddies = g_list_append(moved_buddies, bnode);
+				}
 				prev = child;
-			} else if(GAIM_BLIST_NODE_IS_CHAT(child)) {
-				gaim_blist_add_chat((GaimChat *)child, dest_group, prev);
+			} else if (GAIM_BLIST_NODE_IS_CHAT(child)) {
+				gaim_blist_add_chat((GaimChat *)child, dest, prev);
 				prev = child;
 			} else {
 				gaim_debug(GAIM_DEBUG_ERROR, "blist",
-						"Unknown child type in group %s\n", group->name);
+						"Unknown child type in group %s\n", source->name);
 			}
 			child = next;
 		}
-		for (accts = gaim_group_get_accounts(group); accts; accts = g_slist_remove(accts, accts->data)) {
-			GaimAccount *account = accts->data;
-			serv_rename_group(account->gc, group, name);
-		}
-		gaim_blist_remove_group(group);
+
+		/* Make a copy of the old group name and then delete the old group */
+		old_name = g_strdup(source->name);
+		gaim_blist_remove_group(source);
 	} else {
-		/* a simple rename */
-		for (accts = gaim_group_get_accounts(group); accts; accts = g_slist_remove(accts, accts->data)) {
-			GaimAccount *account = accts->data;
-			serv_rename_group(account->gc, group, name);
+		/* A simple rename */
+		GaimBlistNode *cnode, *bnode;
+
+		/* Build a GList of all buddies in this group */
+		for (cnode = ((GaimBlistNode *)source)->child; cnode != NULL; cnode = cnode->next) {
+			if (GAIM_BLIST_NODE_IS_CONTACT(cnode))
+				for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
+					moved_buddies = g_list_append(moved_buddies, bnode);
 		}
-		g_free(group->name);
-		group->name = g_strdup(name);
-		if (ops)
-			ops->update(gaimbuddylist, (GaimBlistNode*)group);
+
+		old_name = source->name;
+		source->name = g_strdup(new_name);
+
 	}
+
+	/* Save our changes */
+	schedule_blist_save();
+
+	/* Update the UI */
+	if (ops && ops->update)
+		ops->update(gaimbuddylist, (GaimBlistNode*)source);
+
+	/* Notify all PRPLs */
+	for (accts = gaim_group_get_accounts(source); accts; accts = g_slist_remove(accts, accts->data)) {
+		GaimAccount *account = accts->data;
+		serv_rename_group(account->gc, old_name, source, moved_buddies);
+	}
+	g_list_free(moved_buddies);
+	g_free(old_name);
 }
 
-static void gaim_blist_node_initialize_settings(GaimBlistNode* node);
+static void gaim_blist_node_initialize_settings(GaimBlistNode *node);
 
 GaimChat *gaim_chat_new(GaimAccount *account, const char *alias, GHashTable *components)
 {
+	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimChat *chat;
-	GaimBlistUiOps *ops;
-
-	if(!components)
-		return NULL;
+
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(components != NULL, FALSE);
 
 	chat = g_new0(GaimChat, 1);
 	chat->account = account;
-	if(alias && strlen(alias))
+	if ((alias != NULL) && (*alias != '\0'))
 		chat->alias = g_strdup(alias);
 	chat->components = components;
-	gaim_blist_node_initialize_settings((GaimBlistNode*)chat);
-
-	((GaimBlistNode*)chat)->type = GAIM_BLIST_CHAT_NODE;
-
-	ops = gaim_blist_get_ui_ops();
+	gaim_blist_node_initialize_settings((GaimBlistNode *)chat);
+	((GaimBlistNode *)chat)->type = GAIM_BLIST_CHAT_NODE;
 
 	if (ops != NULL && ops->new_node != NULL)
 		ops->new_node((GaimBlistNode *)chat);
@@ -505,10 +592,11 @@
 {
 	char *name;
 
-	if(chat->alias){
+	g_return_val_if_fail(chat != NULL, FALSE);
+
+	if (chat->alias != NULL) {
 		 name = g_strdup(chat->alias);
-	}
-	else{
+	} else {
 		 GList *parts;
 		 GaimPlugin *prpl;
 		 GaimPluginProtocolInfo *prpl_info;
@@ -530,22 +618,23 @@
 
 GaimBuddy *gaim_buddy_new(GaimAccount *account, const char *screenname, const char *alias)
 {
-	GaimBuddy *b;
-	GaimBlistUiOps *ops;
-
-	b = g_new0(GaimBuddy, 1);
-	b->account = account;
-	b->name  = g_strdup(screenname);
-	b->alias = g_strdup(alias);
-	gaim_blist_node_initialize_settings((GaimBlistNode*)b);
-	((GaimBlistNode*)b)->type = GAIM_BLIST_BUDDY_NODE;
-
-	ops = gaim_blist_get_ui_ops();
-
-	if (ops != NULL && ops->new_node != NULL)
-		ops->new_node((GaimBlistNode *)b);
-
-	return b;
+	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
+	GaimBuddy *buddy;
+
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(screenname != NULL, FALSE);
+
+	buddy = g_new0(GaimBuddy, 1);
+	buddy->account = account;
+	buddy->name  = g_strdup(screenname);
+	buddy->alias = g_strdup(alias);
+	gaim_blist_node_initialize_settings((GaimBlistNode *)buddy);
+	((GaimBlistNode *)buddy)->type = GAIM_BLIST_BUDDY_NODE;
+
+	if (ops && ops->new_node)
+		ops->new_node((GaimBlistNode *)buddy);
+
+	return buddy;
 }
 
 void
@@ -561,6 +650,8 @@
 		buddy->icon = (icon == NULL ? NULL : gaim_buddy_icon_ref(icon));
 
 		gaim_buddy_icon_cache(icon, buddy);
+
+		schedule_blist_save();
 	}
 
 	gaim_blist_update_buddy_icon(buddy);
@@ -576,27 +667,24 @@
 
 void gaim_blist_add_chat(GaimChat *chat, GaimGroup *group, GaimBlistNode *node)
 {
-	GaimBlistNode *n = node, *cnode = (GaimBlistNode*)chat;
-	GaimGroup *g = group;
+	GaimBlistNode *cnode = (GaimBlistNode*)chat;
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	gboolean save = FALSE;
-
 
 	g_return_if_fail(chat != NULL);
-	g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT((GaimBlistNode*)chat));
-
-	if (!n) {
-		if (!g) {
-			g = gaim_group_new(_("Chats"));
-			gaim_blist_add_group(g,
+	g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT((GaimBlistNode *)chat));
+
+	if (node == NULL) {
+		if (group == NULL) {
+			group = gaim_group_new(_("Chats"));
+			gaim_blist_add_group(group,
 					gaim_blist_get_last_sibling(gaimbuddylist->root));
 		}
 	} else {
-		g = (GaimGroup*)n->parent;
+		group = (GaimGroup*)node->parent;
 	}
 
 	/* if we're moving to overtop of ourselves, do nothing */
-	if(cnode == n)
+	if (cnode == node)
 		return;
 
 	if (cnode->parent) {
@@ -608,48 +696,48 @@
 			((GaimGroup *)cnode->parent)->online--;
 			((GaimGroup *)cnode->parent)->currentsize--;
 		}
-		if(cnode->next)
+		if (cnode->next)
 			cnode->next->prev = cnode->prev;
-		if(cnode->prev)
+		if (cnode->prev)
 			cnode->prev->next = cnode->next;
-		if(cnode->parent->child == cnode)
+		if (cnode->parent->child == cnode)
 			cnode->parent->child = cnode->next;
 
 		ops->remove(gaimbuddylist, cnode);
 
-		save = TRUE;
+		schedule_blist_save();
 	}
 
-	if (n) {
-		if(n->next)
-			n->next->prev = cnode;
-		cnode->next = n->next;
-		cnode->prev = n;
-		cnode->parent = n->parent;
-		n->next = cnode;
-		((GaimGroup *)n->parent)->totalsize++;
+	if (node != NULL) {
+		if (node->next)
+			node->next->prev = cnode;
+		cnode->next = node->next;
+		cnode->prev = node;
+		cnode->parent = node->parent;
+		node->next = cnode;
+		((GaimGroup *)node->parent)->totalsize++;
 		if (gaim_account_is_connected(chat->account)) {
-			((GaimGroup *)n->parent)->online++;
-			((GaimGroup *)n->parent)->currentsize++;
+			((GaimGroup *)node->parent)->online++;
+			((GaimGroup *)node->parent)->currentsize++;
 		}
 	} else {
-		if(((GaimBlistNode*)g)->child)
-			((GaimBlistNode*)g)->child->prev = cnode;
-		cnode->next = ((GaimBlistNode*)g)->child;
+		if (((GaimBlistNode *)group)->child)
+			((GaimBlistNode *)group)->child->prev = cnode;
+		cnode->next = ((GaimBlistNode *)group)->child;
 		cnode->prev = NULL;
-		((GaimBlistNode*)g)->child = cnode;
-		cnode->parent = (GaimBlistNode*)g;
-		g->totalsize++;
+		((GaimBlistNode *)group)->child = cnode;
+		cnode->parent = (GaimBlistNode *)group;
+		group->totalsize++;
 		if (gaim_account_is_connected(chat->account)) {
-			g->online++;
-			g->currentsize++;
+			group->online++;
+			group->currentsize++;
 		}
 	}
 
-	if (ops)
-		ops->update(gaimbuddylist, (GaimBlistNode*)cnode);
-	if (save)
-		gaim_blist_save();
+	schedule_blist_save();
+
+	if (ops && ops->update)
+		ops->update(gaimbuddylist, (GaimBlistNode *)cnode);
 }
 
 void gaim_blist_add_buddy(GaimBuddy *buddy, GaimContact *contact, GaimGroup *group, GaimBlistNode *node)
@@ -658,7 +746,6 @@
 	GaimGroup *g;
 	GaimContact *c;
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	gboolean save = FALSE;
 	struct _gaim_hbuddy *hb;
 
 	g_return_if_fail(buddy != NULL);
@@ -667,19 +754,19 @@
 	bnode = (GaimBlistNode *)buddy;
 
 	/* if we're moving to overtop of ourselves, do nothing */
-	if(bnode == node || (!node && bnode->parent &&
+	if (bnode == node || (!node && bnode->parent &&
 				contact && bnode->parent == (GaimBlistNode*)contact
 				&& bnode == bnode->parent->child))
 		return;
 
-	if(node && GAIM_BLIST_NODE_IS_BUDDY(node)) {
+	if (node && GAIM_BLIST_NODE_IS_BUDDY(node)) {
 		c = (GaimContact*)node->parent;
 		g = (GaimGroup*)node->parent->parent;
-	} else if(contact) {
+	} else if (contact) {
 		c = contact;
-		g = (GaimGroup*)((GaimBlistNode*)c)->parent;
-	} else  {
-		if(group) {
+		g = (GaimGroup *)((GaimBlistNode *)c)->parent;
+	} else {
+		if (group) {
 			g = group;
 		} else {
 			g = gaim_group_new(_("Buddies"));
@@ -693,35 +780,35 @@
 
 	cnode = (GaimBlistNode *)c;
 
-	if(bnode->parent) {
-		if(GAIM_BUDDY_IS_ONLINE(buddy)) {
+	if (bnode->parent) {
+		if (GAIM_BUDDY_IS_ONLINE(buddy)) {
 			((GaimContact*)bnode->parent)->online--;
-			if(((GaimContact*)bnode->parent)->online == 0)
+			if (((GaimContact*)bnode->parent)->online == 0)
 				((GaimGroup*)bnode->parent->parent)->online--;
 		}
-		if(gaim_account_is_connected(buddy->account)) {
+		if (gaim_account_is_connected(buddy->account)) {
 			((GaimContact*)bnode->parent)->currentsize--;
-			if(((GaimContact*)bnode->parent)->currentsize == 0)
+			if (((GaimContact*)bnode->parent)->currentsize == 0)
 				((GaimGroup*)bnode->parent->parent)->currentsize--;
 		}
 		((GaimContact*)bnode->parent)->totalsize--;
 		/* the group totalsize will be taken care of by remove_contact below */
 
-		if(bnode->parent->parent != (GaimBlistNode*)g)
+		if (bnode->parent->parent != (GaimBlistNode*)g)
 			serv_move_buddy(buddy, (GaimGroup *)bnode->parent->parent, g);
 
-		if(bnode->next)
+		if (bnode->next)
 			bnode->next->prev = bnode->prev;
-		if(bnode->prev)
+		if (bnode->prev)
 			bnode->prev->next = bnode->next;
-		if(bnode->parent->child == bnode)
+		if (bnode->parent->child == bnode)
 			bnode->parent->child = bnode->next;
 
 		ops->remove(gaimbuddylist, bnode);
 
-		save = TRUE;
-
-		if(bnode->parent->parent != (GaimBlistNode*)g) {
+		schedule_blist_save();
+
+		if (bnode->parent->parent != (GaimBlistNode*)g) {
 			hb = g_new(struct _gaim_hbuddy, 1);
 			hb->name = g_strdup(gaim_normalize(buddy->account, buddy->name));
 			hb->account = buddy->account;
@@ -731,7 +818,7 @@
 			g_free(hb);
 		}
 
-		if(!bnode->parent->child) {
+		if (!bnode->parent->child) {
 			gaim_blist_remove_contact((GaimContact*)bnode->parent);
 		} else {
 			gaim_contact_compute_priority_buddy((GaimContact*)bnode->parent);
@@ -739,15 +826,15 @@
 		}
 	}
 
-	if(node && GAIM_BLIST_NODE_IS_BUDDY(node)) {
-		if(node->next)
+	if (node && GAIM_BLIST_NODE_IS_BUDDY(node)) {
+		if (node->next)
 			node->next->prev = bnode;
 		bnode->next = node->next;
 		bnode->prev = node;
 		bnode->parent = node->parent;
 		node->next = bnode;
 	} else {
-		if(cnode->child)
+		if (cnode->child)
 			cnode->child->prev = bnode;
 		bnode->prev = NULL;
 		bnode->next = cnode->child;
@@ -755,19 +842,18 @@
 		bnode->parent = cnode;
 	}
 
-	if(GAIM_BUDDY_IS_ONLINE(buddy)) {
+	if (GAIM_BUDDY_IS_ONLINE(buddy)) {
 		((GaimContact*)bnode->parent)->online++;
-		if(((GaimContact*)bnode->parent)->online == 1)
+		if (((GaimContact*)bnode->parent)->online == 1)
 			((GaimGroup*)bnode->parent->parent)->online++;
 	}
-	if(gaim_account_is_connected(buddy->account)) {
+	if (gaim_account_is_connected(buddy->account)) {
 		((GaimContact*)bnode->parent)->currentsize++;
-		if(((GaimContact*)bnode->parent)->currentsize == 1)
+		if (((GaimContact*)bnode->parent)->currentsize == 1)
 			((GaimGroup*)bnode->parent->parent)->currentsize++;
 	}
 	((GaimContact*)bnode->parent)->totalsize++;
 
-
 	hb = g_new(struct _gaim_hbuddy, 1);
 	hb->name = g_strdup(gaim_normalize(buddy->account, buddy->name));
 	hb->account = buddy->account;
@@ -776,52 +862,55 @@
 	g_hash_table_replace(gaimbuddylist->buddies, hb, buddy);
 
 	gaim_contact_compute_priority_buddy(gaim_buddy_get_contact(buddy));
-	if (ops)
+
+	schedule_blist_save();
+
+	if (ops && ops->update)
 		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
-	if (save)
-		gaim_blist_save();
 }
 
 GaimContact *gaim_contact_new()
 {
-	GaimBlistUiOps *ops;
-	GaimContact *c = g_new0(GaimContact, 1);
-	((GaimBlistNode*)c)->type = GAIM_BLIST_CONTACT_NODE;
-
-	c->totalsize = c->currentsize = c->online = 0;
-	gaim_blist_node_initialize_settings((GaimBlistNode*)c);
-
-	ops = gaim_blist_get_ui_ops();
-	if (ops != NULL && ops->new_node != NULL)
-		ops->new_node((GaimBlistNode *)c);
-
-	return c;
+	GaimBlistUiOps *ops = gaim_blist_get_ui_ops();
+
+	GaimContact *contact = g_new0(GaimContact, 1);
+	contact->totalsize = 0;
+	contact->currentsize = 0;
+	contact->online = 0;
+	gaim_blist_node_initialize_settings((GaimBlistNode *)contact);
+	((GaimBlistNode *)contact)->type = GAIM_BLIST_CONTACT_NODE;
+
+	if (ops && ops->new_node)
+		ops->new_node((GaimBlistNode *)contact);
+
+	return contact;
 }
 
-void gaim_contact_set_alias(GaimContact* contact, const char *alias)
+void gaim_contact_set_alias(GaimContact *contact, const char *alias)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 
 	g_return_if_fail(contact != NULL);
 
-	if(contact->alias)
+	if (contact->alias != NULL)
 		g_free(contact->alias);
 
-	if(alias && *alias)
+	if ((alias != NULL) && (*alias != '\0'))
 		contact->alias = g_strdup(alias);
 	else
 		contact->alias = NULL;
 
-	if (ops)
+	schedule_blist_save();
+
+	if (ops && ops->update)
 		ops->update(gaimbuddylist, (GaimBlistNode*)contact);
 }
 
 const char *gaim_contact_get_alias(GaimContact* contact)
 {
-	if(!contact)
-		return NULL;
-
-	if(contact->alias)
+	g_return_val_if_fail(contact != NULL, NULL);
+
+	if (contact->alias)
 		return contact->alias;
 
 	return gaim_get_buddy_alias(contact->priority);
@@ -829,25 +918,24 @@
 
 GaimGroup *gaim_group_new(const char *name)
 {
-	GaimGroup *g = gaim_find_group(name);
-
-	if (!g) {
-		GaimBlistUiOps *ops;
-		g= g_new0(GaimGroup, 1);
-		g->name = g_strdup(name);
-		g->totalsize = 0;
-		g->currentsize = 0;
-		g->online = 0;
-		gaim_blist_node_initialize_settings((GaimBlistNode*)g);
-		((GaimBlistNode*)g)->type = GAIM_BLIST_GROUP_NODE;
-
-		ops = gaim_blist_get_ui_ops();
-
-		if (ops != NULL && ops->new_node != NULL)
-			ops->new_node((GaimBlistNode *)g);
-
-	}
-	return g;
+	GaimBlistUiOps *ops = gaim_blist_get_ui_ops();
+	GaimGroup *group = gaim_find_group(name);
+
+	if (group != NULL)
+		return group;
+
+	group = g_new0(GaimGroup, 1);
+	group->name = g_strdup(name);
+	group->totalsize = 0;
+	group->currentsize = 0;
+	group->online = 0;
+	gaim_blist_node_initialize_settings((GaimBlistNode *)group);
+	((GaimBlistNode *)group)->type = GAIM_BLIST_GROUP_NODE;
+
+	if (ops && ops->new_node)
+		ops->new_node((GaimBlistNode *)group);
+
+	return group;
 }
 
 void gaim_blist_add_contact(GaimContact *contact, GaimGroup *group, GaimBlistNode *node)
@@ -855,18 +943,18 @@
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimGroup *g;
 	GaimBlistNode *gnode, *cnode, *bnode;
-	gboolean save = FALSE, empty_contact = FALSE;
+	gboolean empty_contact = FALSE;
 
 	g_return_if_fail(contact != NULL);
 	g_return_if_fail(GAIM_BLIST_NODE_IS_CONTACT((GaimBlistNode*)contact));
 
-	if((GaimBlistNode*)contact == node)
+	if ((GaimBlistNode*)contact == node)
 		return;
 
-	if(node && (GAIM_BLIST_NODE_IS_CONTACT(node) ||
+	if (node && (GAIM_BLIST_NODE_IS_CONTACT(node) ||
 				GAIM_BLIST_NODE_IS_CHAT(node)))
 		g = (GaimGroup*)node->parent;
-	else if(group)
+	else if (group)
 		g = group;
 	else {
 		g = gaim_group_new(_("Buddies"));
@@ -877,27 +965,27 @@
 	gnode = (GaimBlistNode*)g;
 	cnode = (GaimBlistNode*)contact;
 
-	if(cnode->parent) {
-		if(cnode->parent->child == cnode)
+	if (cnode->parent) {
+		if (cnode->parent->child == cnode)
 			cnode->parent->child = cnode->next;
-		if(cnode->prev)
+		if (cnode->prev)
 			cnode->prev->next = cnode->next;
-		if(cnode->next)
+		if (cnode->next)
 			cnode->next->prev = cnode->prev;
 
 
-		if(contact->online > 0)
+		if (contact->online > 0)
 			((GaimGroup*)cnode->parent)->online--;
-		if(contact->currentsize > 0)
+		if (contact->currentsize > 0)
 			((GaimGroup*)cnode->parent)->currentsize--;
 		((GaimGroup*)cnode->parent)->totalsize--;
 
 		ops->remove(gaimbuddylist, cnode);
 
-		save = TRUE;
-
-		if(cnode->parent != gnode) {
-			for(bnode = cnode->child; bnode; bnode = bnode->next) {
+		schedule_blist_save();
+
+		if (cnode->parent != gnode) {
+			for (bnode = cnode->child; bnode; bnode = bnode->next) {
 				GaimBuddy *b = (GaimBuddy*)bnode;
 
 				struct _gaim_hbuddy *hb = g_new(struct _gaim_hbuddy, 1);
@@ -907,21 +995,21 @@
 
 				g_hash_table_remove(gaimbuddylist->buddies, hb);
 
-				if(!gaim_find_buddy_in_group(b->account, b->name, g)) {
+				if (!gaim_find_buddy_in_group(b->account, b->name, g)) {
 					hb->group = gnode;
 					g_hash_table_replace(gaimbuddylist->buddies, hb, b);
 
-					if(b->account->gc)
-						serv_move_buddy(b, (GaimGroup*)cnode->parent, g);
+					if (b->account->gc)
+						serv_move_buddy(b, (GaimGroup *)cnode->parent, g);
 				} else {
 					/* this buddy already exists in the group, so we're
 					 * gonna delete it instead */
 					g_free(hb->name);
 					g_free(hb);
-					if(b->account->gc)
-						serv_remove_buddy(b->account->gc, b->name, ((GaimGroup*)cnode->parent)->name);
-
-					if(!cnode->child->next)
+					if (b->account->gc)
+						serv_remove_buddy(b->account->gc, b, (GaimGroup *)cnode->parent);
+
+					if (!cnode->child->next)
 						empty_contact = TRUE;
 					gaim_blist_remove_buddy(b);
 				}
@@ -929,20 +1017,20 @@
 		}
 	}
 
-	if(empty_contact)
+	if (empty_contact)
 		return;
 
 
-	if(node && (GAIM_BLIST_NODE_IS_CONTACT(node) ||
+	if (node && (GAIM_BLIST_NODE_IS_CONTACT(node) ||
 				GAIM_BLIST_NODE_IS_CHAT(node))) {
-		if(node->next)
+		if (node->next)
 			node->next->prev = cnode;
 		cnode->next = node->next;
 		cnode->prev = node;
 		cnode->parent = node->parent;
 		node->next = cnode;
 	} else {
-		if(gnode->child)
+		if (gnode->child)
 			gnode->child->prev = cnode;
 		cnode->prev = NULL;
 		cnode->next = gnode->child;
@@ -950,20 +1038,19 @@
 		cnode->parent = gnode;
 	}
 
-	if(contact->online > 0)
+	if (contact->online > 0)
 		g->online++;
-	if(contact->currentsize > 0)
+	if (contact->currentsize > 0)
 		g->currentsize++;
 	g->totalsize++;
 
-	if(ops && cnode->child)
+	schedule_blist_save();
+
+	if (ops && cnode->child)
 		ops->update(gaimbuddylist, cnode);
 
-	for(bnode = cnode->child; bnode; bnode = bnode->next)
+	for (bnode = cnode->child; bnode; bnode = bnode->next)
 		ops->update(gaimbuddylist, bnode);
-
-	if (save)
-		gaim_blist_save();
 }
 
 void gaim_blist_merge_contact(GaimContact *source, GaimBlistNode *node)
@@ -973,43 +1060,46 @@
 	GaimBlistNode *prev, *cur, *next;
 	GaimContact *target;
 
-	if(GAIM_BLIST_NODE_IS_CONTACT(node)) {
-		target = (GaimContact*)node;
+	g_return_if_fail(source != NULL);
+	g_return_if_fail(node != NULL);
+
+	if (GAIM_BLIST_NODE_IS_CONTACT(node)) {
+		target = (GaimContact *)node;
 		prev = gaim_blist_get_last_child(node);
-	} else if(GAIM_BLIST_NODE_IS_BUDDY(node)) {
-		target = (GaimContact*)node->parent;
+	} else if (GAIM_BLIST_NODE_IS_BUDDY(node)) {
+		target = (GaimContact *)node->parent;
 		prev = node;
 	} else {
 		return;
 	}
 
-	if(source == target || !target)
+	if (source == target || !target)
 		return;
 
-	targetnode = (GaimBlistNode*)target;
+	targetnode = (GaimBlistNode *)target;
 	next = sourcenode->child;
 
-	while(next) {
+	while (next) {
 		cur = next;
 		next = cur->next;
-		if(GAIM_BLIST_NODE_IS_BUDDY(cur)) {
-			gaim_blist_add_buddy((GaimBuddy*)cur, target, NULL, prev);
+		if (GAIM_BLIST_NODE_IS_BUDDY(cur)) {
+			gaim_blist_add_buddy((GaimBuddy *)cur, target, NULL, prev);
 			prev = cur;
 		}
 	}
 }
 
-void  gaim_blist_add_group (GaimGroup *group, GaimBlistNode *node)
+void gaim_blist_add_group(GaimGroup *group, GaimBlistNode *node)
 {
 	GaimBlistUiOps *ops;
 	GaimBlistNode *gnode = (GaimBlistNode*)group;
-	gboolean save = FALSE;
 
 	g_return_if_fail(group != NULL);
-	g_return_if_fail(GAIM_BLIST_NODE_IS_GROUP((GaimBlistNode*)group));
-
-	if (!gaimbuddylist)
-		gaimbuddylist = gaim_blist_new();
+	g_return_if_fail(GAIM_BLIST_NODE_IS_GROUP((GaimBlistNode *)group));
+
+	/* XXX - Wha?  Why does this exist here? */
+	//if (!gaimbuddylist)
+		//gaimbuddylist = gaim_blist_new();
 	ops = gaimbuddylist->ui_ops;
 
 	if (!gaimbuddylist->root) {
@@ -1018,176 +1108,212 @@
 	}
 
 	/* if we're moving to overtop of ourselves, do nothing */
-	if(gnode == node)
+	if (gnode == node)
 		return;
 
 	if (gaim_find_group(group->name)) {
 		/* This is just being moved */
 
-		ops->remove(gaimbuddylist, (GaimBlistNode*)group);
-
-		if(gnode == gaimbuddylist->root)
+		ops->remove(gaimbuddylist, (GaimBlistNode *)group);
+
+		if (gnode == gaimbuddylist->root)
 			gaimbuddylist->root = gnode->next;
-		if(gnode->prev)
+		if (gnode->prev)
 			gnode->prev->next = gnode->next;
-		if(gnode->next)
+		if (gnode->next)
 			gnode->next->prev = gnode->prev;
-
-		save = TRUE;
 	}
 
 	if (node && GAIM_BLIST_NODE_IS_GROUP(node)) {
 		gnode->next = node->next;
 		gnode->prev = node;
-		if(node->next)
+		if (node->next)
 			node->next->prev = gnode;
 		node->next = gnode;
 	} else {
-		if(gaimbuddylist->root)
+		if (gaimbuddylist->root)
 			gaimbuddylist->root->prev = gnode;
 		gnode->next = gaimbuddylist->root;
 		gnode->prev = NULL;
 		gaimbuddylist->root = gnode;
 	}
 
-
-	if (ops) {
+	schedule_blist_save();
+
+	if (ops && ops->update) {
 		ops->update(gaimbuddylist, gnode);
-		for(node = gnode->child; node; node = node->next)
+		for (node = gnode->child; node; node = node->next)
 			ops->update(gaimbuddylist, node);
 	}
-	if (save)
-		gaim_blist_save();
 }
 
-void gaim_blist_remove_contact(GaimContact* contact)
+void gaim_blist_remove_contact(GaimContact *contact)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-
-	GaimBlistNode *gnode, *cnode = (GaimBlistNode*)contact;
-
-	gnode = cnode->parent;
-
-	if(cnode->child) {
-		while(cnode->child) {
-			gaim_blist_remove_buddy((GaimBuddy*)cnode->child);
+	GaimBlistNode *node, *gnode;
+
+	g_return_if_fail(contact != NULL);
+
+	node = (GaimBlistNode *)contact;
+	gnode = node->parent;
+
+	if (node->child) {
+		/*
+		 * If this contact has children then remove them.  When the last
+		 * buddy is removed from the contact, the contact is deleted.
+		 */
+		while (node->child) {
+			gaim_blist_remove_buddy((GaimBuddy*)node->child);
 		}
 	} else {
-		if(ops)
-			ops->remove(gaimbuddylist, cnode);
-
-		if(gnode->child == cnode)
-			gnode->child = cnode->next;
-		if(cnode->prev)
-			cnode->prev->next = cnode->next;
-		if(cnode->next)
-			cnode->next->prev = cnode->prev;
-
+		/* Remove the node from its parent */
+		if (gnode->child == node)
+			gnode->child = node->next;
+		if (node->prev)
+			node->prev->next = node->next;
+		if (node->next)
+			node->next->prev = node->prev;
+
+		schedule_blist_save();
+
+		/* Update the UI */
+		if (ops && ops->remove)
+			ops->remove(gaimbuddylist, node);
+
+		/* Delete the node */
 		g_free(contact);
 	}
 }
 
-void gaim_blist_remove_buddy (GaimBuddy *buddy)
+void gaim_blist_remove_buddy(GaimBuddy *buddy)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-
-	GaimBlistNode *cnode, *node = (GaimBlistNode*)buddy;
+	GaimBlistNode *node, *cnode, *gnode;
+	GaimContact *contact;
 	GaimGroup *group;
 	struct _gaim_hbuddy hb;
 
+	g_return_if_fail(buddy != NULL);
+
+	node = (GaimBlistNode *)buddy;
 	cnode = node->parent;
-	group = (GaimGroup *)cnode->parent;
-
-	if(GAIM_BUDDY_IS_ONLINE(buddy)) {
-		((GaimContact*)cnode)->online--;
-		if(((GaimContact*)cnode)->online == 0)
-			group->online--;
-	}
-	if(gaim_account_is_connected(buddy->account)) {
-		((GaimContact*)cnode)->currentsize--;
-		if(((GaimContact*)cnode)->currentsize == 0)
-			group->currentsize--;
-	}
-	((GaimContact*)cnode)->totalsize--;
-
+	gnode = cnode->parent;
+	contact = (GaimContact *)cnode;
+	group = (GaimGroup *)gnode;
+
+	/* Remove the node from its parent */
 	if (node->prev)
 		node->prev->next = node->next;
 	if (node->next)
 		node->next->prev = node->prev;
-	if(cnode->child == node) {
+	if (cnode->child == node)
 		cnode->child = node->next;
+
+	/* Adjust size counts */
+	if (GAIM_BUDDY_IS_ONLINE(buddy)) {
+		contact->online--;
+		if (contact->online == 0)
+			group->online--;
 	}
-
-	if(((GaimContact*)cnode)->priority == buddy) {
-		gaim_contact_compute_priority_buddy((GaimContact*)cnode);
-		ops->update(gaimbuddylist, cnode);
+	if (gaim_account_is_connected(buddy->account)) {
+		contact->currentsize--;
+		if (contact->currentsize == 0)
+			group->currentsize--;
 	}
-
+	contact->totalsize--;
+
+	schedule_blist_save();
+
+	/* Re-sort the contact */
+	if (contact->priority == buddy) {
+		gaim_contact_compute_priority_buddy(contact);
+		if (ops && ops->update)
+			ops->update(gaimbuddylist, cnode);
+	}
+
+	/* Remove this buddy from the buddies hash table */
 	hb.name = g_strdup(gaim_normalize(buddy->account, buddy->name));
 	hb.account = buddy->account;
 	hb.group = ((GaimBlistNode*)buddy)->parent->parent;
 	g_hash_table_remove(gaimbuddylist->buddies, &hb);
 	g_free(hb.name);
 
-	if(buddy->timer > 0)
+	/* Update the UI */
+	if (ops && ops->remove)
+		ops->remove(gaimbuddylist, node);
+
+	/* Delete the node */
+	if (buddy->timer > 0)
 		gaim_timeout_remove(buddy->timer);
-
 	if (buddy->icon != NULL)
 		gaim_buddy_icon_unref(buddy->icon);
-
-	ops->remove(gaimbuddylist, node);
 	g_hash_table_destroy(buddy->node.settings);
 	g_free(buddy->name);
 	g_free(buddy->alias);
 	g_free(buddy);
 
-	if(!cnode->child)
-		gaim_blist_remove_contact((GaimContact*)cnode);
+	/* If the contact is empty then remove it */
+	if (!cnode->child)
+		gaim_blist_remove_contact(contact);
 }
 
-void  gaim_blist_remove_chat (GaimChat *chat)
+void gaim_blist_remove_chat(GaimChat *chat)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-
-	GaimBlistNode *gnode, *node = (GaimBlistNode*)chat;
+	GaimBlistNode *node, *gnode;
 	GaimGroup *group;
 
+	g_return_if_fail(chat != NULL);
+
+	node = (GaimBlistNode *)chat;
 	gnode = node->parent;
 	group = (GaimGroup *)gnode;
 
-	if(gnode->child == node)
+	/* Remove the node from its parent */
+	if (gnode->child == node)
 		gnode->child = node->next;
 	if (node->prev)
 		node->prev->next = node->next;
 	if (node->next)
 		node->next->prev = node->prev;
-	group->totalsize--;
+
+	/* Adjust size counts */
 	if (gaim_account_is_connected(chat->account)) {
-		group->currentsize--;
 		group->online--;
+		group->currentsize--;
 	}
-
-	ops->remove(gaimbuddylist, node);
+	group->totalsize--;
+
+	schedule_blist_save();
+
+	/* Update the UI */
+	if (ops && ops->remove)
+		ops->remove(gaimbuddylist, node);
+
+	/* Delete the node */
 	g_hash_table_destroy(chat->components);
 	g_free(chat->alias);
 	g_free(chat);
 }
 
-void  gaim_blist_remove_group (GaimGroup *group)
+void gaim_blist_remove_group(GaimGroup *group)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
-	GaimBlistNode *node = (GaimBlistNode*)group;
+	GaimBlistNode *node;
 	GList *l;
 
-	if(node->child) {
+	g_return_if_fail(group != NULL);
+
+	node = (GaimBlistNode *)group;
+
+	/* Make sure the group is empty */
+	if (node->child) {
 		char *buf;
 		int count = 0;
-		GaimBlistNode *child = node->child;
-
-		while(child) {
+		GaimBlistNode *child;
+
+		for (child = node->child; child != NULL; child = child->next)
 			count++;
-			child = child->next;
-		}
 
 		buf = g_strdup_printf(ngettext("%d buddy from group %s was not removed "
 									   "because its account was not logged in."
@@ -1203,76 +1329,90 @@
 		return;
 	}
 
-	if(gaimbuddylist->root == node)
+	/* Remove the node from its parent */
+	if (gaimbuddylist->root == node)
 		gaimbuddylist->root = node->next;
 	if (node->prev)
 		node->prev->next = node->next;
 	if (node->next)
 		node->next->prev = node->prev;
 
+	schedule_blist_save();
+
+	/* Update the UI */
+	if (ops && ops->remove)
+		ops->remove(gaimbuddylist, node);
+
+	/* Remove the group from all accounts that are online */
 	for (l = gaim_connections_get_all(); l != NULL; l = l->next)
 	{
 		GaimConnection *gc = (GaimConnection *)l->data;
 
 		if (gaim_connection_get_state(gc) == GAIM_CONNECTED)
-			serv_remove_group(gc, group->name);
+			serv_remove_group(gc, group);
 	}
 
-	ops->remove(gaimbuddylist, node);
+	/* Delete the node */
 	g_free(group->name);
 	g_free(group);
 }
 
-GaimBuddy *gaim_contact_get_priority_buddy(GaimContact *contact) {
+GaimBuddy *gaim_contact_get_priority_buddy(GaimContact *contact)
+{
+	g_return_val_if_fail(contact != NULL, NULL);
+
 	return contact->priority;
 }
 
-const char *gaim_get_buddy_alias_only(GaimBuddy *b) {
-	if(!b)
-		return NULL;
-
-	if(b->alias && b->alias[0]) {
-		return b->alias;
-	}
-	else if (b->server_alias != NULL &&
-			 gaim_prefs_get_bool("/core/buddies/use_server_alias")) {
-
-		return b->server_alias;
+const char *gaim_get_buddy_alias_only(GaimBuddy *buddy)
+{
+	g_return_val_if_fail(buddy != NULL, NULL);
+
+	if ((buddy->alias != NULL) && (*buddy->alias != '\0')) {
+		return buddy->alias;
+	} else if ((buddy->server_alias != NULL) &&
+			   (*buddy->server_alias != '\0') &&
+			   (gaim_prefs_get_bool("/core/buddies/use_server_alias"))) {
+
+		return buddy->server_alias;
 	}
 
 	return NULL;
 }
 
-const char *  gaim_get_buddy_alias (GaimBuddy *buddy)
+const char *gaim_get_buddy_alias(GaimBuddy *buddy)
 {
 	const char *ret;
 
-	if(!buddy)
+	/* Are there ever times when we WANT to return "Unknown"? */
+	/* g_return_val_if_fail(buddy != NULL, NULL); */
+	if (!buddy)
 		return _("Unknown");
 
-	ret= gaim_get_buddy_alias_only(buddy);
+	ret = gaim_get_buddy_alias_only(buddy);
 
 	return ret ? ret : buddy->name;
 }
 
 const char *gaim_chat_get_name(GaimChat *chat)
 {
-	if(chat->alias && *chat->alias) {
+	struct proto_chat_entry *pce;
+	GList *parts, *tmp;
+	char *ret;
+
+	g_return_val_if_fail(chat != NULL, NULL);
+
+	if ((chat->alias != NULL) && (*chat->alias != '\0'))
 		return chat->alias;
-	} else {
-		struct proto_chat_entry *pce;
-		GList *parts, *tmp;
-		char *ret;
-
-		parts = GAIM_PLUGIN_PROTOCOL_INFO(chat->account->gc->prpl)->chat_info(chat->account->gc);
-		pce = parts->data;
-		ret = g_hash_table_lookup(chat->components, pce->identifier);
-		for(tmp = parts; tmp; tmp = tmp->next)
-			g_free(tmp->data);
-		g_list_free(parts);
-
-		return ret;
-	}
+
+	parts = GAIM_PLUGIN_PROTOCOL_INFO(chat->account->gc->prpl)->chat_info(chat->account->gc);
+	pce = parts->data;
+	ret = g_hash_table_lookup(chat->components, pce->identifier);
+	for (tmp = parts; tmp; tmp = tmp->next)
+		g_free(tmp->data);
+	g_list_free(parts);
+
+	return ret;
 }
 
 GaimBuddy *gaim_find_buddy(GaimAccount *account, const char *name)
@@ -1281,24 +1421,22 @@
 	struct _gaim_hbuddy hb;
 	GaimBlistNode *group;
 
-	if (!gaimbuddylist)
-		return NULL;
-
-	if ((name == NULL) || (*name == '\0'))
-		return 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.account = account;
 	hb.name = g_strdup(gaim_normalize(account, name));
 
-	for(group = gaimbuddylist->root; group; group = group->next) {
+	for (group = gaimbuddylist->root; group; group = group->next) {
 		hb.group = group;
 		if ((buddy = g_hash_table_lookup(gaimbuddylist->buddies, &hb))) {
 			g_free(hb.name);
 			return buddy;
 		}
 	}
-
 	g_free(hb.name);
+
 	return NULL;
 }
 
@@ -1308,11 +1446,9 @@
 	struct _gaim_hbuddy hb;
 	GaimBuddy *ret;
 
-	if (!gaimbuddylist)
-		return NULL;
-
-	if (!name)
-		return 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;
@@ -1320,6 +1456,7 @@
 
 	ret = g_hash_table_lookup(gaimbuddylist->buddies, &hb);
 	g_free(hb.name);
+
 	return ret;
 }
 
@@ -1327,39 +1464,38 @@
 {
 	struct buddy *buddy;
 	struct _gaim_hbuddy hb;
-	GaimBlistNode *group;
+	GaimBlistNode *node;
 	GSList *ret = NULL;
 
-	if (!gaimbuddylist)
-		return NULL;
-
-	if (!name)
-		return 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(group = gaimbuddylist->root; group; group = group->next) {
-		hb.group = group;
+	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);
 	}
-
 	g_free(hb.name);
+
 	return ret;
 }
 
 GaimGroup *gaim_find_group(const char *name)
 {
 	GaimBlistNode *node;
-	if (!gaimbuddylist)
-		return NULL;
-	node = gaimbuddylist->root;
-	while(node) {
+
+	g_return_val_if_fail(gaimbuddylist != NULL, NULL);
+	g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
+
+	for (node = gaimbuddylist->root; node != NULL; node = node->next) {
 		if (!strcmp(((GaimGroup *)node)->name, name))
 			return (GaimGroup *)node;
-		node = node->next;
 	}
+
 	return NULL;
 }
 
@@ -1374,16 +1510,16 @@
 	GaimBlistNode *node, *group;
 	GList *parts;
 
-	g_return_val_if_fail(gaim_get_blist() != NULL, NULL);
-	g_return_val_if_fail(name != NULL, NULL);
-
-	if(!gaim_account_is_connected(account))
+	g_return_val_if_fail(gaimbuddylist != NULL, NULL);
+	g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
+
+	if (!gaim_account_is_connected(account))
 		return NULL;
 
 	prpl = gaim_find_prpl(gaim_account_get_protocol_id(account));
 	prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl);
 
-	if(prpl_info->find_blist_chat != NULL)
+	if (prpl_info->find_blist_chat != NULL)
 		return prpl_info->find_blist_chat(account, name);
 
 	for (group = gaimbuddylist->root; group != NULL; group = group->next) {
@@ -1392,7 +1528,7 @@
 
 				chat = (GaimChat*)node;
 
-				if(account != chat->account)
+				if (account != chat->account)
 					continue;
 
 				parts = prpl_info->chat_info(
@@ -1422,10 +1558,16 @@
 	return (GaimGroup *)(((GaimBlistNode *)chat)->parent);
 }
 
+GaimContact *gaim_buddy_get_contact(GaimBuddy *buddy)
+{
+	g_return_val_if_fail(buddy != NULL, NULL);
+
+	return (GaimContact*)((GaimBlistNode*)buddy)->parent;
+}
+
 GaimGroup *gaim_find_buddys_group(GaimBuddy *buddy)
 {
-	if (!buddy)
-		return NULL;
+	g_return_val_if_fail(buddy != NULL, NULL);
 
 	if (((GaimBlistNode *)buddy)->parent == NULL)
 		return NULL;
@@ -1433,21 +1575,21 @@
 	return (GaimGroup *)(((GaimBlistNode*)buddy)->parent->parent);
 }
 
-GSList *gaim_group_get_accounts(GaimGroup *g)
+GSList *gaim_group_get_accounts(GaimGroup *group)
 {
 	GSList *l = NULL;
 	GaimBlistNode *gnode, *cnode, *bnode;
 
-	gnode = (GaimBlistNode *)g;
-
-	for(cnode = gnode->child;  cnode; cnode = cnode->next) {
+	gnode = (GaimBlistNode *)group;
+
+	for (cnode = gnode->child;  cnode; cnode = cnode->next) {
 		if (GAIM_BLIST_NODE_IS_CHAT(cnode)) {
-			if(!g_slist_find(l, ((GaimChat *)cnode)->account))
+			if (!g_slist_find(l, ((GaimChat *)cnode)->account))
 				l = g_slist_append(l, ((GaimChat *)cnode)->account);
-		} else if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
-			for(bnode = cnode->child; bnode; bnode = bnode->next) {
-				if(GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
-					if(!g_slist_find(l, ((GaimBuddy *)bnode)->account))
+		} else if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+			for (bnode = cnode->child; bnode; bnode = bnode->next) {
+				if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
+					if (!g_slist_find(l, ((GaimBuddy *)bnode)->account))
 						l = g_slist_append(l, ((GaimBuddy *)bnode)->account);
 				}
 			}
@@ -1462,34 +1604,33 @@
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimBlistNode *gnode, *cnode, *bnode;
 
-	if(!gaimbuddylist)
-		return;
-
-	if(!ops)
+	g_return_if_fail(gaimbuddylist != NULL);
+
+	if (!ops || !ops->update)
 		return;
 
-	for(gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
-		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
+	for (gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
+		if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
-			if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+		for (cnode = gnode->child; cnode; cnode = cnode->next) {
+			if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
 				gboolean recompute = FALSE;
-					for(bnode = cnode->child; bnode; bnode = bnode->next) {
-						if(GAIM_BLIST_NODE_IS_BUDDY(bnode) &&
+					for (bnode = cnode->child; bnode; bnode = bnode->next) {
+						if (GAIM_BLIST_NODE_IS_BUDDY(bnode) &&
 								((GaimBuddy*)bnode)->account == account) {
 							recompute = TRUE;
 							((GaimContact*)cnode)->currentsize++;
-							if(((GaimContact*)cnode)->currentsize == 1)
+							if (((GaimContact*)cnode)->currentsize == 1)
 								((GaimGroup*)gnode)->currentsize++;
 							ops->update(gaimbuddylist, bnode);
 						}
 					}
-					if(recompute ||
+					if (recompute ||
 							gaim_blist_node_get_bool(cnode, "show_offline")) {
 						gaim_contact_compute_priority_buddy((GaimContact*)cnode);
 						ops->update(gaimbuddylist, cnode);
 					}
-			} else if(GAIM_BLIST_NODE_IS_CHAT(cnode) &&
+			} else if (GAIM_BLIST_NODE_IS_CHAT(cnode) &&
 					((GaimChat*)cnode)->account == account) {
 				((GaimGroup *)gnode)->online++;
 				((GaimGroup *)gnode)->currentsize++;
@@ -1505,28 +1646,27 @@
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimBlistNode *gnode, *cnode, *bnode;
 
-	if (!gaimbuddylist)
-		return;
-
-	for(gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
-		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
+	g_return_if_fail(gaimbuddylist != NULL);
+
+	for (gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
+		if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
-			if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+		for (cnode = gnode->child; cnode; cnode = cnode->next) {
+			if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
 				gboolean recompute = FALSE;
-				for(bnode = cnode->child; bnode; bnode = bnode->next) {
-					if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
+				for (bnode = cnode->child; bnode; bnode = bnode->next) {
+					if (!GAIM_BLIST_NODE_IS_BUDDY(bnode))
 						continue;
-					if(account == ((GaimBuddy *)bnode)->account) {
+					if (account == ((GaimBuddy *)bnode)->account) {
 						recompute = TRUE;
-						if(((GaimBuddy*)bnode)->present == GAIM_BUDDY_ONLINE ||
+						if (((GaimBuddy*)bnode)->present == GAIM_BUDDY_ONLINE ||
 								((GaimBuddy*)bnode)->present == GAIM_BUDDY_SIGNING_ON) {
 							((GaimContact*)cnode)->online--;
-							if(((GaimContact*)cnode)->online == 0)
+							if (((GaimContact*)cnode)->online == 0)
 								((GaimGroup*)gnode)->online--;
 						}
 						((GaimContact*)cnode)->currentsize--;
-						if(((GaimContact*)cnode)->currentsize == 0)
+						if (((GaimContact*)cnode)->currentsize == 0)
 							((GaimGroup*)gnode)->currentsize--;
 
 						((GaimBuddy*)bnode)->present = GAIM_BUDDY_OFFLINE;
@@ -1536,20 +1676,20 @@
 						((GaimBuddy*)bnode)->evil = 0;
 
 
-						if(ops)
+						if (ops && ops->remove)
 							ops->remove(gaimbuddylist, bnode);
 					}
 				}
-				if(recompute) {
+				if (recompute) {
 					gaim_contact_compute_priority_buddy((GaimContact*)cnode);
-					if(ops)
+					if (ops && ops->update)
 						ops->update(gaimbuddylist, cnode);
 				}
-			} else if(GAIM_BLIST_NODE_IS_CHAT(cnode) &&
+			} else if (GAIM_BLIST_NODE_IS_CHAT(cnode) &&
 					((GaimChat*)cnode)->account == account) {
 				((GaimGroup*)gnode)->currentsize--;
 				((GaimGroup*)gnode)->online--;
-				if(ops)
+				if (ops && ops->remove)
 					ops->remove(gaimbuddylist, cnode);
 			}
 		}
@@ -1560,8 +1700,7 @@
 {
 	char *c;
 	char current[256];
-	GList *bud = NULL;
-
+	GList *buddies = NULL;
 
 	if (config != NULL) {
 
@@ -1616,7 +1755,7 @@
 					GaimGroup *g = gaim_find_group(current);
 					gaim_blist_add_buddy(b, NULL, g,
 							gaim_blist_get_last_child((GaimBlistNode*)g));
-					bud = g_list_append(bud, g_strdup(nm));
+					buddies = g_list_append(buddies, b);
 				}
 			} else if (*c == 'p') {
 				gaim_privacy_permit_add(account, c + 2, TRUE);
@@ -1637,178 +1776,17 @@
 			}
 		} while ((c = strtok(NULL, "\n")));
 
-		if(account->gc) {
-			if(bud) {
-				GList *node = bud;
-				serv_add_buddies(account->gc, bud);
-				while(node) {
-					g_free(node->data);
-					node = node->next;
-				}
+		if (account->gc) {
+			if (buddies != NULL) {
+				serv_add_buddies(account->gc, buddies);
+				g_list_free(buddies);
 			}
 			serv_set_permit_deny(account->gc);
 		}
-		g_list_free(bud);
+		g_list_free(buddies);
 	}
 }
 
-#if 0
-/* translate an AIM 3 buddylist (*.lst) to a Gaim buddylist */
-static GString *translate_lst(FILE *src_fp)
-{
-	char line[BUF_LEN], *line2;
-	char *name;
-	int i;
-
-	GString *dest = g_string_new("m 1\n");
-
-	while (fgets(line, BUF_LEN, src_fp)) {
-		line2 = g_strchug(line);
-		if (strstr(line2, "group") == line2) {
-			name = strpbrk(line2, " \t\n\r\f") + 1;
-			dest = g_string_append(dest, "g ");
-			for (i = 0; i < strcspn(name, "\n\r"); i++)
-				if (name[i] != '\"')
-					dest = g_string_append_c(dest, name[i]);
-			dest = g_string_append_c(dest, '\n');
-		}
-		if (strstr(line2, "buddy") == line2) {
-			name = strpbrk(line2, " \t\n\r\f") + 1;
-			dest = g_string_append(dest, "b ");
-			for (i = 0; i < strcspn(name, "\n\r"); i++)
-				if (name[i] != '\"')
-					dest = g_string_append_c(dest, name[i]);
-			dest = g_string_append_c(dest, '\n');
-		}
-	}
-
-	return dest;
-}
-
-
-/* translate an AIM 4 buddylist (*.blt) to Gaim format */
-static GString *translate_blt(FILE *src_fp)
-{
-	int i;
-	char line[BUF_LEN];
-	char *buddy;
-
-	GString *dest = g_string_new("m 1\n");
-
-	while (strstr(fgets(line, BUF_LEN, src_fp), "Buddy") == NULL);
-	while (strstr(fgets(line, BUF_LEN, src_fp), "list") == NULL);
-
-	while (1) {
-		fgets(line, BUF_LEN, src_fp); g_strchomp(line);
-		if (strchr(line, '}') != NULL)
-			break;
-
-		if (strchr(line, '{') != NULL) {
-			/* Syntax starting with "<group> {" */
-
-			dest = g_string_append(dest, "g ");
-			buddy = g_strchug(strtok(line, "{"));
-			for (i = 0; i < strlen(buddy); i++)
-				if (buddy[i] != '\"')
-					dest = g_string_append_c(dest, buddy[i]);
-			dest = g_string_append_c(dest, '\n');
-			while (strchr(fgets(line, BUF_LEN, src_fp), '}') == NULL) {
-				gboolean pounce = FALSE;
-				char *e;
-				g_strchomp(line);
-				buddy = g_strchug(line);
-				gaim_debug(GAIM_DEBUG_MISC, "AIM 4 blt import",
-						   "buddy: \"%s\"\n", buddy);
-				dest = g_string_append(dest, "b ");
-				if (strchr(buddy, '{') != NULL) {
-					/* buddy pounce, etc */
-					char *pos = strchr(buddy, '{') - 1;
-					*pos = 0;
-					pounce = TRUE;
-				}
-				if ((e = strchr(buddy, '\"')) != NULL) {
-					*e = '\0';
-					buddy++;
-				}
-				dest = g_string_append(dest, buddy);
-				dest = g_string_append_c(dest, '\n');
-				if (pounce)
-					do
-						fgets(line, BUF_LEN, src_fp);
-					while (!strchr(line, '}'));
-			}
-		} else {
-
-			/* Syntax "group buddy buddy ..." */
-			buddy = g_strchug(strtok(line, " \n"));
-			dest = g_string_append(dest, "g ");
-			if (strchr(buddy, '\"') != NULL) {
-				dest = g_string_append(dest, &buddy[1]);
-				dest = g_string_append_c(dest, ' ');
-				buddy = g_strchug(strtok(NULL, " \n"));
-				while (strchr(buddy, '\"') == NULL) {
-					dest = g_string_append(dest, buddy);
-					dest = g_string_append_c(dest, ' ');
-					buddy = g_strchug(strtok(NULL, " \n"));
-				}
-				buddy[strlen(buddy) - 1] = '\0';
-				dest = g_string_append(dest, buddy);
-			} else {
-				dest = g_string_append(dest, buddy);
-			}
-			dest = g_string_append_c(dest, '\n');
-			while ((buddy = g_strchug(strtok(NULL, " \n"))) != NULL) {
-				dest = g_string_append(dest, "b ");
-				if (strchr(buddy, '\"') != NULL) {
-					dest = g_string_append(dest, &buddy[1]);
-					dest = g_string_append_c(dest, ' ');
-					buddy = g_strchug(strtok(NULL, " \n"));
-					while (strchr(buddy, '\"') == NULL) {
-						dest = g_string_append(dest, buddy);
-						dest = g_string_append_c(dest, ' ');
-						buddy = g_strchug(strtok(NULL, " \n"));
-					}
-					buddy[strlen(buddy) - 1] = '\0';
-					dest = g_string_append(dest, buddy);
-				} else {
-					dest = g_string_append(dest, buddy);
-				}
-				dest = g_string_append_c(dest, '\n');
-			}
-		}
-	}
-
-	return dest;
-}
-
-static GString *translate_gnomeicu(FILE *src_fp)
-{
-	char line[BUF_LEN];
-	GString *dest = g_string_new("m 1\ng Buddies\n");
-
-	while (strstr(fgets(line, BUF_LEN, src_fp), "NewContacts") == NULL);
-
-	while (fgets(line, BUF_LEN, src_fp)) {
-		char *eq;
-		g_strchomp(line);
-		if (line[0] == '\n' || line[0] == '[')
-			break;
-		eq = strchr(line, '=');
-		if (!eq)
-			break;
-		*eq = ':';
-		eq = strchr(eq, ',');
-		if (eq)
-			*eq = '\0';
-		dest = g_string_append(dest, "b ");
-		dest = g_string_append(dest, line);
-		dest = g_string_append_c(dest, '\n');
-	}
-
-	return dest;
-}
-#endif
-
 static gchar *get_screenname_filename(const char *name)
 {
 	gchar **split;
@@ -1826,9 +1804,6 @@
 	return ret;
 }
 
-static gboolean gaim_blist_read(const char *filename);
-
-
 static void do_import(GaimAccount *account, const char *filename)
 {
 	GString *buf = NULL;
@@ -1851,7 +1826,7 @@
 
 		protocol = prpl_num;
 
-		/* TODO Somehow move this checking into prpls */
+		/* XXX - Somehow move this checking into the PRPLs */
 		if (prpl_num == GAIM_PROTO_OSCAR) {
 			if ((username = gaim_account_get_username(account)) != NULL) {
 				protocol = (isalpha(*username)
@@ -1885,47 +1860,22 @@
 	if ((first[0] == '\n') || (first[0] == '\r' && first[1] == '\n'))
 		fgets(first, 64, f);
 
-#if 0
-	if (!g_ascii_strncasecmp(first, "<xml", strlen("<xml"))) {
-		/* new gaim XML buddy list */
-		gaim_blist_read(path);
-		
-		/* We really don't need to bother doing stuf like translating AIM 3 buddy lists anymore */
-		
-	} else if (!g_ascii_strncasecmp(first, "Config {", strlen("Config {"))) {
-		/* AIM 4 buddy list */
-		gaim_debug(GAIM_DEBUG_MISC, "blist import", "aim 4\n");
-		rewind(f);
-		buf = translate_blt(f);
-	} else if (strstr(first, "group") != NULL) {
-		/* AIM 3 buddy list */
-		gaim_debug(GAIM_DEBUG_MISC, "blist import", "aim 3\n");
-		rewind(f);
-		buf = translate_lst(f);
-	} else if (!g_ascii_strncasecmp(first, "[User]", strlen("[User]"))) {
-		/* GnomeICU (hopefully) */
-		gaim_debug(GAIM_DEBUG_MISC, "blist import", "gnomeicu\n");
+	/* We're going to parse an old-style Gaim buddy list */
+	if (first[0] == 'm') {
+		char buf2[BUF_LONG * 2];
+		buf = g_string_new("");
 		rewind(f);
-		buf = translate_gnomeicu(f);
-
-	} else 
-#endif
-		if (first[0] == 'm') {
-			/* Gaim buddy list - no translation */
-			char buf2[BUF_LONG * 2];
-			buf = g_string_new("");
-			rewind(f);
-			while (1) {
-				len = fread(buf2, 1, BUF_LONG * 2 - 1, f);
-				if (len <= 0)
-					break;
-			buf2[len] = '\0';
-			buf = g_string_append(buf, buf2);
-			if (len != BUF_LONG * 2 - 1)
+		while (1) {
+			len = fread(buf2, 1, BUF_LONG * 2 - 1, f);
+			if (len <= 0)
 				break;
-			}
+		buf2[len] = '\0';
+		buf = g_string_append(buf, buf2);
+		if (len != BUF_LONG * 2 - 1)
+			break;
 		}
-	
+	}
+
 	fclose(f);
 
 	if (buf) {
@@ -1936,21 +1886,22 @@
 	}
 }
 
-gboolean gaim_group_on_account(GaimGroup *g, GaimAccount *account) {
+gboolean gaim_group_on_account(GaimGroup *g, GaimAccount *account)
+{
 	GaimBlistNode *cnode, *bnode;
-	for(cnode = ((GaimBlistNode *)g)->child; cnode; cnode = cnode->next) {
-		if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
-			for(bnode = cnode->child; bnode; bnode = bnode->next) {
-				if(GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
+	for (cnode = ((GaimBlistNode *)g)->child; cnode; cnode = cnode->next) {
+		if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+			for (bnode = cnode->child; bnode; bnode = bnode->next) {
+				if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
 					GaimBuddy *buddy = (GaimBuddy *)bnode;
-					if((!account && gaim_account_is_connected(buddy->account))
+					if ((!account && gaim_account_is_connected(buddy->account))
 							|| buddy->account == account)
 						return TRUE;
 				}
 			}
-		} else if(GAIM_BLIST_NODE_IS_CHAT(cnode)) {
+		} else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) {
 			GaimChat *chat = (GaimChat *)cnode;
-			if((!account && gaim_account_is_connected(chat->account))
+			if ((!account && gaim_account_is_connected(chat->account))
 					|| chat->account == account)
 				return TRUE;
 		}
@@ -1966,14 +1917,14 @@
 	const char *type = xmlnode_get_attrib(setting, "type");
 	char *value = xmlnode_get_data(setting);
 
-	if(!value)
+	if (!value)
 		return;
 
-	if(!type || !strcmp(type, "string"))
+	if (!type || !strcmp(type, "string"))
 		gaim_blist_node_set_string(node, name, value);
-	else if(!strcmp(type, "bool"))
+	else if (!strcmp(type, "bool"))
 		gaim_blist_node_set_bool(node, name, atoi(value));
-	else if(!strcmp(type, "int"))
+	else if (!strcmp(type, "int"))
 		gaim_blist_node_set_int(node, name, atoi(value));
 
 	g_free(value);
@@ -1991,33 +1942,33 @@
 	protocol = xmlnode_get_attrib(bnode, "protocol");
 	proto = xmlnode_get_attrib(bnode, "proto");
 
-	if(!acct_name || (!proto && !protocol))
+	if (!acct_name || (!proto && !protocol))
 		return;
 
 	account = gaim_accounts_find(acct_name, proto ? proto : protocol);
 
-	if(!account)
+	if (!account)
 		return;
 
-	if((x = xmlnode_get_child(bnode, "name")))
+	if ((x = xmlnode_get_child(bnode, "name")))
 		name = xmlnode_get_data(x);
 
-	if(!name)
+	if (!name)
 		return;
 
-	if((x = xmlnode_get_child(bnode, "alias")))
+	if ((x = xmlnode_get_child(bnode, "alias")))
 		alias = xmlnode_get_data(x);
 
 	buddy = gaim_buddy_new(account, name, alias);
 	gaim_blist_add_buddy(buddy, contact, group,
 			gaim_blist_get_last_child((GaimBlistNode*)contact));
 
-	for(x = xmlnode_get_child(bnode, "setting"); x; x = xmlnode_get_next_twin(x)) {
+	for (x = xmlnode_get_child(bnode, "setting"); x; x = xmlnode_get_next_twin(x)) {
 		parse_setting((GaimBlistNode*)buddy, x);
 	}
 
 	g_free(name);
-	if(alias)
+	if (alias)
 		g_free(alias);
 }
 
@@ -2030,21 +1981,21 @@
 	gaim_blist_add_contact(contact, group,
 			gaim_blist_get_last_child((GaimBlistNode*)group));
 
-	if((alias = xmlnode_get_attrib(cnode, "alias"))) {
+	if ((alias = xmlnode_get_attrib(cnode, "alias"))) {
 		gaim_contact_set_alias(contact, alias);
 	}
 
-	for(x = cnode->child; x; x = x->next) {
-		if(x->type != XMLNODE_TYPE_TAG)
+	for (x = cnode->child; x; x = x->next) {
+		if (x->type != XMLNODE_TYPE_TAG)
 			continue;
-		if(!strcmp(x->name, "buddy"))
+		if (!strcmp(x->name, "buddy"))
 			parse_buddy(group, contact, x);
-		else if(!strcmp(x->name, "setting"))
+		else if (!strcmp(x->name, "setting"))
 			parse_setting((GaimBlistNode*)contact, x);
 	}
 
 	/* if the contact is empty, don't keep it around.  it causes problems */
-	if(!((GaimBlistNode*)contact)->child)
+	if (!((GaimBlistNode*)contact)->child)
 		gaim_blist_remove_contact(contact);
 }
 
@@ -2061,20 +2012,20 @@
 	protocol = xmlnode_get_attrib(cnode, "protocol");
 	proto = xmlnode_get_attrib(cnode, "proto");
 
-	if(!acct_name || (!proto && !protocol))
+	if (!acct_name || (!proto && !protocol))
 		return;
 
 	account = gaim_accounts_find(acct_name, proto ? proto : protocol);
 
-	if(!account)
+	if (!account)
 		return;
 
-	if((x = xmlnode_get_child(cnode, "alias")))
+	if ((x = xmlnode_get_child(cnode, "alias")))
 		alias = xmlnode_get_data(x);
 
 	components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 
-	for(x = xmlnode_get_child(cnode, "component"); x; x = xmlnode_get_next_twin(x)) {
+	for (x = xmlnode_get_child(cnode, "component"); x; x = xmlnode_get_next_twin(x)) {
 		const char *name;
 		char *value;
 
@@ -2087,11 +2038,11 @@
 	gaim_blist_add_chat(chat, group,
 			gaim_blist_get_last_child((GaimBlistNode*)group));
 
-	for(x = xmlnode_get_child(cnode, "setting"); x; x = xmlnode_get_next_twin(x)) {
+	for (x = xmlnode_get_child(cnode, "setting"); x; x = xmlnode_get_next_twin(x)) {
 		parse_setting((GaimBlistNode*)chat, x);
 	}
 
-	if(alias)
+	if (alias)
 		g_free(alias);
 }
 
@@ -2102,27 +2053,28 @@
 	GaimGroup *group;
 	xmlnode *cnode;
 
-	if(!name)
+	if (!name)
 		name = _("Buddies");
 
 	group = gaim_group_new(name);
 	gaim_blist_add_group(group,
 			gaim_blist_get_last_sibling(gaimbuddylist->root));
 
-	for(cnode = groupnode->child; cnode; cnode = cnode->next) {
-		if(cnode->type != XMLNODE_TYPE_TAG)
+	for (cnode = groupnode->child; cnode; cnode = cnode->next) {
+		if (cnode->type != XMLNODE_TYPE_TAG)
 			continue;
-		if(!strcmp(cnode->name, "setting"))
+		if (!strcmp(cnode->name, "setting"))
 			parse_setting((GaimBlistNode*)group, cnode);
-		else if(!strcmp(cnode->name, "contact") ||
+		else if (!strcmp(cnode->name, "contact") ||
 				!strcmp(cnode->name, "person"))
 			parse_contact(group, cnode);
-		else if(!strcmp(cnode->name, "chat"))
+		else if (!strcmp(cnode->name, "chat"))
 			parse_chat(group, cnode);
 	}
 }
 
-static gboolean gaim_blist_read(const char *filename) {
+static gboolean gaim_blist_read(const char *filename)
+{
 	GError *error;
 	gchar *contents = NULL;
 	gsize length;
@@ -2130,7 +2082,7 @@
 
 	gaim_debug(GAIM_DEBUG_INFO, "blist import",
 			   "Reading %s\n", filename);
-	if(!g_file_get_contents(filename, &contents, &length, &error)) {
+	if (!g_file_get_contents(filename, &contents, &length, &error)) {
 		gaim_debug(GAIM_DEBUG_ERROR, "blist import",
 				   "Error reading blist: %s\n", error->message);
 		g_error_free(error);
@@ -2139,14 +2091,14 @@
 
 	gaim = xmlnode_from_str(contents, length);
 	
-	if(!gaim) {
+	if (!gaim) {
 		FILE *backup;
 		char *name;
 		gaim_debug(GAIM_DEBUG_ERROR, "blist import", "Error parsing %s\n",
 				filename);
 		name = g_build_filename(gaim_user_dir(), "blist.xml~", NULL);
 
-		if((backup = fopen(name, "w"))) {
+		if ((backup = fopen(name, "w"))) {
 			fwrite(contents, length, 1, backup);
 			fclose(backup);
 			chmod(name, S_IRUSR | S_IWUSR);
@@ -2162,18 +2114,18 @@
 	g_free(contents);
 	
 	blist = xmlnode_get_child(gaim, "blist");
-	if(blist) {
+	if (blist) {
 		xmlnode *groupnode;
-		for(groupnode = xmlnode_get_child(blist, "group"); groupnode;
+		for (groupnode = xmlnode_get_child(blist, "group"); groupnode;
 				groupnode = xmlnode_get_next_twin(groupnode)) {
 			parse_group(groupnode);
 		}
 	}
 
 	privacy = xmlnode_get_child(gaim, "privacy");
-	if(privacy) {
+	if (privacy) {
 		xmlnode *anode;
-		for(anode = privacy->child; anode; anode = anode->next) {
+		for (anode = privacy->child; anode; anode = anode->next) {
 			xmlnode *x;
 			GaimAccount *account;
 			const char *acct_name, *proto, *mode, *protocol;
@@ -2183,26 +2135,26 @@
 			proto = xmlnode_get_attrib(anode, "proto");
 			mode = xmlnode_get_attrib(anode, "mode");
 
-			if(!acct_name || (!proto && !protocol) || !mode)
+			if (!acct_name || (!proto && !protocol) || !mode)
 				continue;
 
 			account = gaim_accounts_find(acct_name, proto ? proto : protocol);
 
-			if(!account)
+			if (!account)
 				continue;
 
 			account->perm_deny = atoi(mode);
 
-			for(x = anode->child; x; x = x->next) {
+			for (x = anode->child; x; x = x->next) {
 				char *name;
-				if(x->type != XMLNODE_TYPE_TAG)
+				if (x->type != XMLNODE_TYPE_TAG)
 					continue;
 
-				if(!strcmp(x->name, "permit")) {
+				if (!strcmp(x->name, "permit")) {
 					name = xmlnode_get_data(x);
 					gaim_privacy_permit_add(account, name, TRUE);
 					g_free(name);
-				} else if(!strcmp(x->name, "block")) {
+				} else if (!strcmp(x->name, "block")) {
 					name = xmlnode_get_data(x);
 					gaim_privacy_deny_add(account, name, TRUE);
 					g_free(name);
@@ -2218,7 +2170,8 @@
 	return TRUE;
 }
 
-void gaim_blist_load() {
+void gaim_blist_load()
+{
 	GList *accts;
 	char *user_dir = gaim_user_dir();
 	char *filename;
@@ -2226,25 +2179,25 @@
 
 	blist_safe_to_write = TRUE;
 
-	if(!user_dir)
+	if (!user_dir)
 		return;
 
 	filename = g_build_filename(user_dir, "blist.xml", NULL);
 
-	if(g_file_test(filename, G_FILE_TEST_EXISTS)) {
-		if(!gaim_blist_read(filename)) {
+	if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
+		if (!gaim_blist_read(filename)) {
 			msg = g_strdup_printf(_("An error was encountered parsing your "
 						"buddy list.  It has not been loaded, "
 						"and the old file has moved to blist.xml~."));
 			gaim_notify_error(NULL, NULL, _("Buddy List Error"), msg);
 			g_free(msg);
 		}
-	} else if(g_list_length(gaim_accounts_get_all())) {
+	} else if (g_list_length(gaim_accounts_get_all())) {
 		/* read in the old lists, then save to the new format */
-		for(accts = gaim_accounts_get_all(); accts; accts = accts->next) {
+		for (accts = gaim_accounts_get_all(); accts; accts = accts->next) {
 			do_import(accts->data, NULL);
 		}
-		gaim_blist_save();
+		schedule_blist_save();
 	}
 
 	g_free(filename);
@@ -2291,7 +2244,7 @@
 	const char *type = NULL;
 	int i;
 
-	if(!key)
+	if (!key)
 		return;
 
 	switch(setting->type) {
@@ -2304,7 +2257,7 @@
 			data_val = g_strdup_printf("%d", setting->value.integer);
 			break;
 		case GAIM_BLIST_NODE_SETTING_STRING:
-			if(!setting->value.string)
+			if (!setting->value.string)
 				return;
 
 			type = "string";
@@ -2313,10 +2266,10 @@
 	}
 
 	/* this can't happen */
-	if(!type || !data_val)
+	if (!type || !data_val)
 		return;
 
-	for(i=0; i<indent; i++) fprintf(file, "\t");
+	for (i=0; i<indent; i++) fprintf(file, "\t");
 
 	key_val = g_markup_escape_text(key, -1);
 	fprintf(file, "<setting name=\"%s\" type=\"%s\">%s</setting>\n", key_val, type,
@@ -2327,17 +2280,20 @@
 }
 
 static void blist_print_group_settings(gpointer key, gpointer data,
-		gpointer user_data) {
+		gpointer user_data)
+{
 	blist_print_setting(key, data, user_data, 3);
 }
 
 static void blist_print_buddy_settings(gpointer key, gpointer data,
-		gpointer user_data) {
+		gpointer user_data)
+{
 	blist_print_setting(key, data, user_data, 5);
 }
 
 static void blist_print_cnode_settings(gpointer key, gpointer data,
-		gpointer user_data) {
+		gpointer user_data)
+{
 	blist_print_setting(key, data, user_data, 4);
 }
 
@@ -2347,7 +2303,7 @@
 	char *data_val;
 	FILE *file = user_data;
 
-	if(!key || !data)
+	if (!key || !data)
 		return;
 
 	key_val = g_markup_escape_text(key, -1);
@@ -2359,21 +2315,22 @@
 	g_free(data_val);
 }
 
-static void print_buddy(FILE *file, GaimBuddy *buddy) {
+static void print_buddy(FILE *file, GaimBuddy *buddy)
+{
 	char *bud_name = g_markup_escape_text(buddy->name, -1);
 	char *bud_alias = NULL;
 	char *acct_name = g_markup_escape_text(buddy->account->username, -1);
 	int proto_num = gaim_account_get_protocol(buddy->account);
-	if(buddy->alias)
+	if (buddy->alias)
 		bud_alias= g_markup_escape_text(buddy->alias, -1);
 	fprintf(file, "\t\t\t\t<buddy account=\"%s\" proto=\"%s\"", acct_name,
 			gaim_account_get_protocol_id(buddy->account));
-	if(proto_num != -1)
+	if (proto_num != -1)
 		fprintf(file, " protocol=\"%d\"", proto_num);
 	fprintf(file, ">\n");
 
 	fprintf(file, "\t\t\t\t\t<name>%s</name>\n", bud_name);
-	if(bud_alias) {
+	if (bud_alias) {
 		fprintf(file, "\t\t\t\t\t<alias>%s</alias>\n", bud_alias);
 	}
 	g_hash_table_foreach(buddy->node.settings, blist_print_buddy_settings, file);
@@ -2383,7 +2340,8 @@
 	g_free(acct_name);
 }
 
-static void gaim_blist_write(FILE *file, GaimAccount *exp_acct) {
+static void gaim_blist_write(FILE *file, GaimAccount *exp_acct)
+{
 	GList *accounts;
 	GSList *buds;
 	GaimBlistNode *gnode, *cnode, *bnode;
@@ -2391,33 +2349,33 @@
 	fprintf(file, "<gaim version=\"1\">\n");
 	fprintf(file, "\t<blist>\n");
 
-	for(gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
+	for (gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
 		GaimGroup *group;
 
-		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
+		if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
 			continue;
 
 		group = (GaimGroup *)gnode;
-		if(!exp_acct || gaim_group_on_account(group, exp_acct)) {
+		if (!exp_acct || gaim_group_on_account(group, exp_acct)) {
 			char *group_name = g_markup_escape_text(group->name, -1);
 			fprintf(file, "\t\t<group name=\"%s\">\n", group_name);
 			g_hash_table_foreach(group->node.settings,
 					blist_print_group_settings, file);
-			for(cnode = gnode->child; cnode; cnode = cnode->next) {
-				if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+			for (cnode = gnode->child; cnode; cnode = cnode->next) {
+				if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
 					GaimContact *contact = (GaimContact*)cnode;
 					fprintf(file, "\t\t\t<contact");
-					if(contact->alias) {
+					if (contact->alias) {
 						char *alias = g_markup_escape_text(contact->alias, -1);
 						fprintf(file, " alias=\"%s\"", alias);
 						g_free(alias);
 					}
 					fprintf(file, ">\n");
 
-					for(bnode = cnode->child; bnode; bnode = bnode->next) {
-						if(GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
+					for (bnode = cnode->child; bnode; bnode = bnode->next) {
+						if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
 							GaimBuddy *buddy = (GaimBuddy *)bnode;
-							if(!exp_acct || buddy->account == exp_acct) {
+							if (!exp_acct || buddy->account == exp_acct) {
 								print_buddy(file, buddy);
 							}
 						}
@@ -2427,19 +2385,19 @@
 							blist_print_cnode_settings, file);
 
 					fprintf(file, "\t\t\t</contact>\n");
-				} else if(GAIM_BLIST_NODE_IS_CHAT(cnode)) {
+				} else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) {
 					GaimChat *chat = (GaimChat *)cnode;
-					if(!exp_acct || chat->account == exp_acct) {
+					if (!exp_acct || chat->account == exp_acct) {
 						char *acct_name = g_markup_escape_text(chat->account->username, -1);
 						int proto_num = gaim_account_get_protocol(chat->account);
 						fprintf(file, "\t\t\t<chat proto=\"%s\" account=\"%s\"",
 								gaim_account_get_protocol_id(chat->account),
 								acct_name);
-						if(proto_num != -1)
+						if (proto_num != -1)
 							fprintf(file, " protocol=\"%d\"", proto_num);
 						fprintf(file, ">\n");
 
-						if(chat->alias) {
+						if (chat->alias) {
 							char *chat_alias = g_markup_escape_text(chat->alias, -1);
 							fprintf(file, "\t\t\t\t<alias>%s</alias>\n", chat_alias);
 							g_free(chat_alias);
@@ -2461,27 +2419,27 @@
 	fprintf(file, "\t</blist>\n");
 	fprintf(file, "\t<privacy>\n");
 
-	for(accounts = gaim_accounts_get_all();
+	for (accounts = gaim_accounts_get_all();
 		accounts != NULL;
 		accounts = accounts->next) {
 
 		GaimAccount *account = accounts->data;
 		char *acct_name = g_markup_escape_text(account->username, -1);
 		int proto_num = gaim_account_get_protocol(account);
-		if(!exp_acct || account == exp_acct) {
+		if (!exp_acct || account == exp_acct) {
 			fprintf(file, "\t\t<account proto=\"%s\" name=\"%s\" "
 					"mode=\"%d\"", gaim_account_get_protocol_id(account),
 					acct_name, account->perm_deny);
-			if(proto_num != -1)
+			if (proto_num != -1)
 				fprintf(file, " protocol=\"%d\"", proto_num);
 			fprintf(file, ">\n");
 
-			for(buds = account->permit; buds; buds = buds->next) {
+			for (buds = account->permit; buds; buds = buds->next) {
 				char *bud_name = g_markup_escape_text(buds->data, -1);
 				fprintf(file, "\t\t\t<permit>%s</permit>\n", bud_name);
 				g_free(bud_name);
 			}
-			for(buds = account->deny; buds; buds = buds->next) {
+			for (buds = account->deny; buds; buds = buds->next) {
 				char *bud_name = g_markup_escape_text(buds->data, -1);
 				fprintf(file, "\t\t\t<block>%s</block>\n", bud_name);
 				g_free(bud_name);
@@ -2495,29 +2453,31 @@
 	fprintf(file, "</gaim>\n");
 }
 
-void gaim_blist_save() {
+void gaim_blist_sync()
+{
 	FILE *file;
 	char *user_dir = gaim_user_dir();
 	char *filename;
 	char *filename_real;
 
-	if(!user_dir)
+	if (!user_dir)
 		return;
-	if(!blist_safe_to_write) {
+
+	if (!blist_safe_to_write) {
 		gaim_debug(GAIM_DEBUG_WARNING, "blist save",
 				   "AHH!! Tried to write the blist before we read it!\n");
 		return;
 	}
 
 	file = fopen(user_dir, "r");
-	if(!file)
+	if (!file)
 		mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR);
 	else
 		fclose(file);
 
 	filename = g_build_filename(user_dir, "blist.xml.save", NULL);
 
-	if((file = fopen(filename, "w"))) {
+	if ((file = fopen(filename, "w"))) {
 		gaim_blist_write(file, NULL);
 		fclose(file);
 		chmod(filename, S_IRUSR | S_IWUSR);
@@ -2530,7 +2490,7 @@
 
 	filename_real = g_build_filename(user_dir, "blist.xml", NULL);
 
-	if(rename(filename, filename_real) < 0)
+	if (rename(filename, filename_real) < 0)
 		gaim_debug(GAIM_DEBUG_ERROR, "blist save",
 				   "Error renaming %s to %s\n", filename, filename_real);
 
@@ -2553,9 +2513,9 @@
 	g_free(setting);
 }
 
-static void gaim_blist_node_initialize_settings(GaimBlistNode* node)
+static void gaim_blist_node_initialize_settings(GaimBlistNode *node)
 {
-	if(node->settings)
+	if (node->settings)
 		return;
 
 	node->settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
@@ -2569,6 +2529,8 @@
 	g_return_if_fail(key != NULL);
 
 	g_hash_table_remove(node->settings, key);
+
+	schedule_blist_save();
 }
 
 
@@ -2585,6 +2547,8 @@
 	setting->value.boolean = value;
 
 	g_hash_table_replace(node->settings, g_strdup(key), setting);
+
+	schedule_blist_save();
 }
 
 gboolean gaim_blist_node_get_bool(GaimBlistNode* node, const char *key)
@@ -2597,7 +2561,7 @@
 
 	setting = g_hash_table_lookup(node->settings, key);
 
-	if(!setting)
+	if (!setting)
 		return FALSE;
 
 	g_return_val_if_fail(setting->type == GAIM_BLIST_NODE_SETTING_BOOL, FALSE);
@@ -2618,6 +2582,8 @@
 	setting->value.integer = value;
 
 	g_hash_table_replace(node->settings, g_strdup(key), setting);
+
+	schedule_blist_save();
 }
 
 int gaim_blist_node_get_int(GaimBlistNode* node, const char *key)
@@ -2630,7 +2596,7 @@
 
 	setting = g_hash_table_lookup(node->settings, key);
 
-	if(!setting)
+	if (!setting)
 		return 0;
 
 	g_return_val_if_fail(setting->type == GAIM_BLIST_NODE_SETTING_INT, 0);
@@ -2652,6 +2618,8 @@
 	setting->value.string = g_strdup(value);
 
 	g_hash_table_replace(node->settings, g_strdup(key), setting);
+
+	schedule_blist_save();
 }
 
 const char *gaim_blist_node_get_string(GaimBlistNode* node, const char *key)
@@ -2664,7 +2632,7 @@
 
 	setting = g_hash_table_lookup(node->settings, key);
 
-	if(!setting)
+	if (!setting)
 		return NULL;
 
 	g_return_val_if_fail(setting->type == GAIM_BLIST_NODE_SETTING_STRING, NULL);
@@ -2672,55 +2640,8 @@
 	return setting->value.string;
 }
 
-
-/* XXX: this is compatibility stuff.  Remove after.... oh, I dunno... 0.77 or so */
-
-void gaim_group_set_setting(GaimGroup *g, const char *key, const char *value)
-{
-	gaim_debug_warning("blist", "gaim_group_set_setting() is deprecated\n");
-
-	gaim_blist_node_set_string((GaimBlistNode*)g, key, value);
-}
-
-const char *gaim_group_get_setting(GaimGroup *g, const char *key)
-{
-	gaim_debug_warning("blist", "gaim_group_get_setting() is deprecated\n");
-
-	return gaim_blist_node_get_string((GaimBlistNode*)g, key);
-}
-
-void gaim_chat_set_setting(GaimChat *c, const char *key, const char *value)
+GList *gaim_blist_node_get_extended_menu(GaimBlistNode *n)
 {
-	gaim_debug_warning("blist", "gaim_chat_set_setting() is deprecated\n");
-
-	gaim_blist_node_set_string((GaimBlistNode*)c, key, value);
-}
-
-const char *gaim_chat_get_setting(GaimChat *c, const char *key)
-{
-	gaim_debug_warning("blist", "gaim_chat_get_setting() is deprecated\n");
-
-	return gaim_blist_node_get_string((GaimBlistNode*)c, key);
-}
-
-void gaim_buddy_set_setting(GaimBuddy *b, const char *key, const char *value)
-{
-	gaim_debug_warning("blist", "gaim_buddy_set_setting() is deprecated\n");
-
-	gaim_blist_node_set_string((GaimBlistNode*)b, key, value);
-}
-
-const char *gaim_buddy_get_setting(GaimBuddy *b, const char *key)
-{
-	gaim_debug_warning("blist", "gaim_buddy_get_setting() is deprecated\n");
-
-	return gaim_blist_node_get_string((GaimBlistNode*)b, key);
-}
-
-/* XXX: end compat crap */
-
-
-GList *gaim_blist_node_get_extended_menu(GaimBlistNode *n) {
 	GList *menu = NULL;
 
 	g_return_val_if_fail(n, NULL);
@@ -2745,15 +2666,17 @@
 }
 
 
-int gaim_blist_get_group_size(GaimGroup *group, gboolean offline) {
-	if(!group)
+int gaim_blist_get_group_size(GaimGroup *group, gboolean offline)
+{
+	if (!group)
 		return 0;
 
 	return offline ? group->totalsize : group->currentsize;
 }
 
-int gaim_blist_get_group_online_count(GaimGroup *group) {
-	if(!group)
+int gaim_blist_get_group_online_count(GaimGroup *group)
+{
+	if (!group)
 		return 0;
 
 	return group->online;
@@ -2830,6 +2753,11 @@
 void
 gaim_blist_uninit(void)
 {
+	if (blist_save_timer != 0) {
+		gaim_timeout_remove(blist_save_timer);
+		blist_save_timer = 0;
+		gaim_blist_sync();
+	}
+
 	gaim_signals_unregister_by_instance(gaim_blist_get_handle());
 }
-
--- a/src/blist.h	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/blist.h	Tue Jun 15 02:37:27 2004 +0000
@@ -569,7 +569,7 @@
 		GaimGroup *group);
 
 /**
- * Finds all buddies struct given a screenname and an account
+ * Finds all GaimBuddy structs given a screenname and an account
  *
  * @param name    The buddy's screenname
  * @param account The account this buddy belongs to
@@ -677,9 +677,10 @@
 
 /*@{*/
 /**
- * Saves the buddy list to file
+ * Force an immediate write of the buddy list.  Normally the buddy list is
+ * saved automatically a few seconds after a change is made.
  */
-void gaim_blist_save();
+void gaim_blist_sync();
 
 /**
  * Parses the toc-style buddy list used in older versions of Gaim and for SSI in toc.c
@@ -790,79 +791,6 @@
  */
 void gaim_blist_node_remove_setting(GaimBlistNode *node, const char *key);
 
-/**
- * Associates some data with the group in the xml buddy list
- *
- * @param g      The group the data is associated with
- * @param key    The key used to retrieve the data
- * @param value  The data to set
- * @deprecated   Replaced by gaim_blist_node_set_bool(), gaim_blist_node_set_int()
- * 		 and gaim_blist_node_set_string() to enable types and consolidate functionality.
- * 		 This function is scheduled to be removed in the near future.
- */
-void gaim_group_set_setting(GaimGroup *g, const char *key, const char *value);
-
-/**
- * Retrieves data from the XML buddy list set by gaim_group_set_setting())
- *
- * @param g      The group to retrieve data from
- * @param key    The key to retrieve the data with
- * @return       The associated data or NULL if no data is associated
- * @deprecated   Replaced by gaim_blist_node_get_bool(), gaim_blist_node_get_int()
- * 		 and gaim_blist_node_get_string() to enable types and consolidate functionality.
- * 		 This function is scheduled to be removed in the near future.
- */
-const char *gaim_group_get_setting(GaimGroup *g, const char *key);
-
-/**
- * Associates some data with the chat in the xml buddy list
- *
- * @param c      The chat the data is associated with
- * @param key    The key used to retrieve the data
- * @param value  The data to set
- * @deprecated   Replaced by gaim_blist_node_set_bool(), gaim_blist_node_set_int()
- * 		 and gaim_blist_node_set_string() to enable types and consolidate functionality.
- * 		 This function is scheduled to be removed in the near future.
- */
-void gaim_chat_set_setting(GaimChat *c, const char *key, const char *value);
-
-/**
- * Retrieves data from the XML buddy list set by gaim_chat_set_setting())
- *
- * @param c      The chat to retrieve data from
- * @param key    The key to retrieve the data with
- *
- * @return       The associated data or NULL if no data is associated
- * @deprecated   Replaced by gaim_blist_node_get_bool(), gaim_blist_node_get_int()
- * 		 and gaim_blist_node_get_string() to enable types and consolidate functionality.
- * 		 This function is scheduled to be removed in the near future.
- */
-const char *gaim_chat_get_setting(GaimChat *c, const char *key);
-
-/**
- * Associates some data with the buddy in the xml buddy list
- *
- * @param b      The buddy the data is associated with
- * @param key    The key used to retrieve the data
- * @param value  The data to set
- * @deprecated   Replaced by gaim_blist_node_set_bool(), gaim_blist_node_set_int()
- * 		 and gaim_blist_node_set_string() to enable types and consolidate functionality.
- * 		 This function is scheduled to be removed in the near future.
- */
-void gaim_buddy_set_setting(GaimBuddy *b, const char *key, const char *value);
-
-/**
- * Retrieves data from the XML buddy list set by gaim_buddy_set_setting())
- *
- * @param b      The buddy to retrieve data from
- * @param key    The key to retrieve the data with
- * @return       The associated data or NULL if no data is associated
- * @deprecated   Replaced by gaim_blist_node_get_bool(), gaim_blist_node_get_int()
- * 		 and gaim_blist_node_get_string() to enable types and consolidate functionality.
- * 		 This function is scheduled to be removed in the near future.
- */
-const char *gaim_buddy_get_setting(GaimBuddy *b, const char *key);
-
 /*@}*/
 
 
--- a/src/buddyicon.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/buddyicon.c	Tue Jun 15 02:37:27 2004 +0000
@@ -220,8 +220,7 @@
 	if (old_icon != NULL)
 		unlink(old_icon);
 
-	gaim_blist_node_set_string((GaimBlistNode*)buddy, "buddy_icon", filename);
-	gaim_blist_save();
+	gaim_blist_node_set_string((GaimBlistNode *)buddy, "buddy_icon", filename);
 
 	g_free(filename);
 }
--- a/src/connection.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/connection.c	Tue Jun 15 02:37:27 2004 +0000
@@ -311,7 +311,7 @@
 	if (gc->state == GAIM_CONNECTED) {
 		GaimBlistNode *gnode,*cnode,*bnode;
 		GList *wins;
-		GList *add_buds=NULL;
+		GList *add_buds = NULL;
 		GaimAccount *account = gaim_connection_get_account(gc);
 
 		/* Set the time the account came online */
@@ -377,7 +377,7 @@
 
 					b = (GaimBuddy *)bnode;
 					if(b->account == gc->account) {
-						add_buds = g_list_append(add_buds, b->name);
+						add_buds = g_list_append(add_buds, b);
 					}
 				}
 			}
--- a/src/dialogs.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/dialogs.c	Tue Jun 15 02:37:27 2004 +0000
@@ -22,8 +22,6 @@
 #include "gtkinternal.h"
 
 #include "debug.h"
-#include "log.h"
-#include "multi.h"
 #include "notify.h"
 #include "prefs.h"
 #include "prpl.h"
@@ -31,13 +29,10 @@
 #include "status.h"
 #include "util.h"
 
-#include "gtkblist.h"
-#include "gtkconv.h"
 #include "gtkimhtml.h"
 #include "gtkimhtmltoolbar.h"
-#include "gtkprefs.h"
+#include "gtklog.h"
 #include "gtkutils.h"
-#include "gtklog.h"
 #include "stock.h"
 
 #include "ui.h"
@@ -200,107 +195,106 @@
 do_remove_chat(GaimChat *chat)
 {
 	gaim_blist_remove_chat(chat);
-	gaim_blist_save();
 }
 
 static void
-do_remove_buddy(GaimBuddy *b)
+do_remove_buddy(GaimBuddy *buddy)
 {
-	GaimGroup *g;
-	GaimConversation *c;
+	GaimGroup *group;
+	GaimConversation *conv;
 	gchar *name;
 	GaimAccount *account;
 
-	if (!b)
+	if (!buddy)
 		return;
 
-	g = gaim_find_buddys_group(b);
-	name = g_strdup(b->name); /* b->name is a crasher after remove_buddy */
-	account = b->account;
+	group = gaim_find_buddys_group(buddy);
+	name = g_strdup(buddy->name); /* b->name is a crasher after remove_buddy */
+	account = buddy->account;
 
 	gaim_debug(GAIM_DEBUG_INFO, "blist",
-			   "Removing '%s' from buddy list.\n", b->name);
-	serv_remove_buddy(b->account->gc, name, g->name);
-	gaim_blist_remove_buddy(b);
-	gaim_blist_save();
+			   "Removing '%s' from buddy list.\n", buddy->name);
+	/* XXX - Should remove from blist first... then call serv_remove_buddy()? */
+	serv_remove_buddy(buddy->account->gc, buddy, group);
+	gaim_blist_remove_buddy(buddy);
 
-	c = gaim_find_conversation_with_account(name, account);
+	conv = gaim_find_conversation_with_account(name, account);
 
-	if (c != NULL)
-		gaim_conversation_update(c, GAIM_CONV_UPDATE_REMOVE);
+	if (conv != NULL)
+		gaim_conversation_update(conv, GAIM_CONV_UPDATE_REMOVE);
 
 	g_free(name);
 }
 
-static void do_remove_contact(GaimContact *c)
+static void do_remove_contact(GaimContact *contact)
 {
 	GaimBlistNode *bnode, *cnode;
-	GaimGroup *g;
+	GaimGroup *group;
 
-	if(!c)
+	if (!contact)
 		return;
 
-	cnode = (GaimBlistNode *)c;
-	g = (GaimGroup*)cnode->parent;
-	for(bnode = cnode->child; bnode; bnode = bnode->next) {
-		GaimBuddy *b = (GaimBuddy*)bnode;
-		if(b->account->gc)
-			serv_remove_buddy(b->account->gc, b->name, g->name);
+	cnode = (GaimBlistNode *)contact;
+	group = (GaimGroup*)cnode->parent;
+	for (bnode = cnode->child; bnode; bnode = bnode->next) {
+		GaimBuddy *buddy = (GaimBuddy*)bnode;
+		if (gaim_account_is_connected(buddy->account))
+			serv_remove_buddy(buddy->account->gc, buddy, group);
 	}
-	gaim_blist_remove_contact(c);
+	gaim_blist_remove_contact(contact);
 }
 
-void do_remove_group(GaimGroup *g)
+void do_remove_group(GaimGroup *group)
 {
 	GaimBlistNode *cnode, *bnode;
 
-	cnode = ((GaimBlistNode*)g)->child;
+	cnode = ((GaimBlistNode*)group)->child;
 
-	while(cnode) {
-		if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+	while (cnode) {
+		if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
 			bnode = cnode->child;
 			cnode = cnode->next;
-			while(bnode) {
-				GaimBuddy *b;
-				if(GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
-					GaimConversation *c;
-                                        b = (GaimBuddy*)bnode;
+			while (bnode) {
+				GaimBuddy *buddy;
+				if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
+					GaimConversation *conv;
+					buddy = (GaimBuddy*)bnode;
 					bnode = bnode->next;
-					c = gaim_find_conversation_with_account(b->name, b->account);
-					if(gaim_account_is_connected(b->account)) {
-						serv_remove_buddy(b->account->gc, b->name, g->name);
-						gaim_blist_remove_buddy(b);
-						if(c)
-							gaim_conversation_update(c,
+					conv = gaim_find_conversation_with_account(buddy->name, buddy->account);
+					if (gaim_account_is_connected(buddy->account)) {
+						serv_remove_buddy(buddy->account->gc, buddy, group);
+						gaim_blist_remove_buddy(buddy);
+						if (conv)
+							gaim_conversation_update(conv,
 									GAIM_CONV_UPDATE_REMOVE);
 					}
 				} else {
 					bnode = bnode->next;
 				}
 			}
-		} else if(GAIM_BLIST_NODE_IS_CHAT(cnode)) {
+		} else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) {
 			GaimChat *chat = (GaimChat *)cnode;
 			cnode = cnode->next;
-			if(gaim_account_is_connected(chat->account))
+			if (gaim_account_is_connected(chat->account))
 				gaim_blist_remove_chat(chat);
 		} else {
 			cnode = cnode->next;
 		}
 	}
 
-	gaim_blist_remove_group(g);
-	gaim_blist_save();
+	gaim_blist_remove_group(group);
 }
 
-void show_confirm_del(GaimBuddy *b)
+void show_confirm_del(GaimBuddy *buddy)
 {
 	char *text;
-	if (!b)
+
+	if (!buddy)
 		return;
 
-	text = g_strdup_printf(_("You are about to remove %s from your buddy list.  Do you want to continue?"), b->name);
+	text = g_strdup_printf(_("You are about to remove %s from your buddy list.  Do you want to continue?"), buddy->name);
 
-	gaim_request_action(NULL, NULL, _("Remove Buddy"), text, -1, b, 2,
+	gaim_request_action(NULL, NULL, _("Remove Buddy"), text, -1, buddy, 2,
 						_("Remove Buddy"), G_CALLBACK(do_remove_buddy),
 						_("Cancel"), NULL);
 
@@ -320,33 +314,33 @@
 	g_free(text);
 }
 
-void show_confirm_del_group(GaimGroup *g)
+void show_confirm_del_group(GaimGroup *group)
 {
 	char *text = g_strdup_printf(_("You are about to remove the group %s and all its members from your buddy list.  Do you want to continue?"),
-			       g->name);
+			       group->name);
 
-	gaim_request_action(NULL, NULL, _("Remove Group"), text, -1, g, 2,
+	gaim_request_action(NULL, NULL, _("Remove Group"), text, -1, group, 2,
 						_("Remove Group"), G_CALLBACK(do_remove_group),
 						_("Cancel"), NULL);
 
 	g_free(text);
 }
 
-void show_confirm_del_contact(GaimContact *c)
+void show_confirm_del_contact(GaimContact *contact)
 {
-	GaimBuddy *b = gaim_contact_get_priority_buddy(c);
+	GaimBuddy *buddy = gaim_contact_get_priority_buddy(contact);
 
-	if(!b)
+	if (!buddy)
 		return;
 
-	if(((GaimBlistNode*)c)->child == (GaimBlistNode*)b &&
-			!((GaimBlistNode*)b)->next) {
-		show_confirm_del(b);
+	if (((GaimBlistNode*)contact)->child == (GaimBlistNode*)buddy &&
+			!((GaimBlistNode*)buddy)->next) {
+		show_confirm_del(buddy);
 	} else {
 		char *text = g_strdup_printf(_("You are about to remove the contact containing %s and %d other buddies from your buddy list.  Do you want to continue?"),
-			       b->name, c->totalsize - 1);
+			       buddy->name, contact->totalsize - 1);
 
-		gaim_request_action(NULL, NULL, _("Remove Contact"), text, -1, c, 2,
+		gaim_request_action(NULL, NULL, _("Remove Contact"), text, -1, contact, 2,
 				_("Remove Contact"), G_CALLBACK(do_remove_contact),
 				_("Cancel"), NULL);
 
@@ -359,12 +353,9 @@
 	GtkWidget *window;
 	GtkWidget *hbox;
 	GtkWidget *label;
-	GaimGtkBuddyList *gtkblist;
 	GtkWidget *img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_COOL, GTK_ICON_SIZE_DIALOG);
 	gchar *norm = gaim_strreplace(ee, "rocksmyworld", "");
 
-	gtkblist = GAIM_GTK_BLIST(gaim_get_blist());
-
 	label = gtk_label_new(NULL);
 	if (!strcmp(norm, "zilding"))
 		gtk_label_set_markup(GTK_LABEL(label),
@@ -398,7 +389,7 @@
 	if (strlen(gtk_label_get_label(GTK_LABEL(label))) <= 0)
 		return FALSE;
 
-	window = gtk_dialog_new_with_buttons(GAIM_ALERT_TITLE, GTK_WINDOW(gtkblist->window), 0, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+	window = gtk_dialog_new_with_buttons(GAIM_ALERT_TITLE, NULL, 0, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
 	gtk_dialog_set_default_response (GTK_DIALOG(window), GTK_RESPONSE_OK);
 	g_signal_connect(G_OBJECT(window), "response", G_CALLBACK(gtk_widget_destroy), NULL);
 
@@ -805,7 +796,6 @@
 alias_chat_cb(GaimChat *chat, const char *new_alias)
 {
 	gaim_blist_alias_chat(chat, new_alias);
-	gaim_blist_save();
 }
 
 void
@@ -822,7 +812,6 @@
 alias_contact_cb(GaimContact *contact, const char *new_alias)
 {
 	gaim_contact_set_alias(contact, new_alias);
-	gaim_blist_save();
 }
 
 void
@@ -840,7 +829,6 @@
 {
 	gaim_blist_alias_buddy(buddy, (alias != NULL && *alias != '\0') ? alias : NULL);
 	serv_alias_buddy(buddy);
-	gaim_blist_save();
 }
 
 void
--- a/src/gtkblist.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/gtkblist.c	Tue Jun 15 02:37:27 2004 +0000
@@ -532,8 +532,6 @@
 {
 	gaim_blist_node_set_bool((GaimBlistNode*)chat, "gtk-autojoin",
 			gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)));
-
-	gaim_blist_save();
 }
 
 static void gtk_blist_menu_join_cb(GtkWidget *w, GaimChat *chat)
@@ -903,7 +901,6 @@
 
 	if (GAIM_BLIST_NODE_IS_GROUP(node)) {
 		gaim_blist_node_set_bool(node, "collapsed", FALSE);
-		gaim_blist_save();
 	}
 }
 
@@ -917,7 +914,6 @@
 
 	if (GAIM_BLIST_NODE_IS_GROUP(node)) {
 		gaim_blist_node_set_bool(node, "collapsed", TRUE);
-		gaim_blist_save();
 	} else if(GAIM_BLIST_NODE_IS_CONTACT(node)) {
 		gaim_gtk_blist_collapse_contact_cb(NULL, node);
 	}
@@ -1889,8 +1885,6 @@
 
 			gtk_tree_path_free(path);
 			gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t);
-
-			gaim_blist_save();
 		}
 	}
 	else if (sd->target == gdk_atom_intern("application/x-im-contact",
@@ -2333,9 +2327,11 @@
 rename_group_cb(GaimGroup *g, const char *new_name)
 {
 	gaim_blist_rename_group(g, new_name);
-	gaim_blist_save();
 }
 
+/*
+ * Should disallow empty group names.
+ */
 static void
 show_rename_group(GtkWidget *unused, GaimGroup *g)
 {
@@ -3864,22 +3860,25 @@
 
 		b = gaim_buddy_new(data->account, who, whoalias);
 		gaim_blist_add_buddy(b, NULL, g, NULL);
-		serv_add_buddy(gaim_account_get_connection(data->account), who, g);
+		serv_add_buddy(gaim_account_get_connection(data->account), b);
 
 		/*
+		 * XXX
 		 * It really seems like it would be better if the call to serv_add_buddy()
 		 * and gaim_conversation_update() were done in blist.c, possibly in the
 		 * gaim_blist_add_buddy() function.  Maybe serv_add_buddy() should be
 		 * renamed to gaim_blist_add_new_buddy() or something, and have it call
 		 * gaim_blist_add_buddy() after it creates it.  --Mark
+		 *
+		 * No that's not good.  blist.c should only deal with adding nodes to the
+		 * local list.  We need a new, non-gtk file that calls both serv_add_buddy
+		 * and gaim_blist_add_buddy().  Or something.  --Mark
 		 */
 
 		if (c != NULL) {
 			gaim_buddy_icon_update(gaim_conv_im_get_icon(GAIM_CONV_IM(c)));
 			gaim_conversation_update(c, GAIM_CONV_UPDATE_ADD);
 		}
-
-		gaim_blist_save();
 	}
 
 	gtk_widget_destroy(data->window);
@@ -4056,7 +4055,6 @@
 	if (chat != NULL)
 	{
 		gaim_blist_add_chat(chat, group, NULL);
-		gaim_blist_save();
 	}
 
 	gtk_widget_destroy(data->window);
@@ -4335,11 +4333,10 @@
 static void
 add_group_cb(GaimConnection *gc, const char *group_name)
 {
-	GaimGroup *g;
-
-	g = gaim_group_new(group_name);
-	gaim_blist_add_group(g, NULL);
-	gaim_blist_save();
+	GaimGroup *group;
+
+	group = gaim_group_new(group_name);
+	gaim_blist_add_group(group, NULL);
 }
 
 void
--- a/src/gtkconv.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/gtkconv.c	Tue Jun 15 02:37:27 2004 +0000
@@ -40,7 +40,6 @@
 #include "debug.h"
 #include "imgstore.h"
 #include "log.h"
-#include "multi.h"
 #include "notify.h"
 #include "prefs.h"
 #include "prpl.h"
--- a/src/gtkprefs.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/gtkprefs.c	Tue Jun 15 02:37:27 2004 +0000
@@ -32,7 +32,6 @@
 #include "prpl.h"
 #include "sound.h"
 #include "util.h"
-#include "multi.h"
 #include "network.h"
 
 #include "gtkblist.h"
--- a/src/gtkprivacy.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/gtkprivacy.c	Tue Jun 15 02:37:27 2004 +0000
@@ -244,7 +244,6 @@
 
 	dialog->account->perm_deny = new_type;
 	serv_set_permit_deny(gaim_account_get_connection(dialog->account));
-	gaim_blist_save();
 
 	gtk_widget_hide(dialog->allow_widget);
 	gtk_widget_hide(dialog->block_widget);
--- a/src/idle.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/idle.c	Tue Jun 15 02:37:27 2004 +0000
@@ -36,7 +36,6 @@
 #include "connection.h"
 #include "debug.h"
 #include "log.h"
-#include "multi.h"
 #include "prefs.h"
 #include "prpl.h"
 #include "signals.h"
--- a/src/privacy.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/privacy.c	Tue Jun 15 02:37:27 2004 +0000
@@ -55,8 +55,6 @@
 	if (!local_only && gaim_account_is_connected(account))
 		serv_add_permit(gaim_account_get_connection(account), who);
 
-	gaim_blist_save();
-
 	if (privacy_ops != NULL && privacy_ops->permit_added != NULL)
 		privacy_ops->permit_added(account, who);
 
@@ -91,8 +89,6 @@
 	if (!local_only && gaim_account_is_connected(account))
 		serv_rem_permit(gaim_account_get_connection(account), who);
 
-	gaim_blist_save();
-
 	if (privacy_ops != NULL && privacy_ops->permit_removed != NULL)
 		privacy_ops->permit_removed(account, who);
 
@@ -126,8 +122,6 @@
 	if (!local_only && gaim_account_is_connected(account))
 		serv_add_deny(gaim_account_get_connection(account), who);
 
-	gaim_blist_save();
-
 	if (privacy_ops != NULL && privacy_ops->deny_added != NULL)
 		privacy_ops->deny_added(account, who);
 
@@ -162,8 +156,6 @@
 	if (!local_only && gaim_account_is_connected(account))
 		serv_rem_deny(gaim_account_get_connection(account), who);
 
-	gaim_blist_save();
-
 	if (privacy_ops != NULL && privacy_ops->deny_removed != NULL)
 		privacy_ops->deny_removed(account, who);
 
--- a/src/protocols/gg/gg.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/gg/gg.c	Tue Jun 15 02:37:27 2004 +0000
@@ -1,6 +1,6 @@
 /*
  * gaim - Gadu-Gadu Protocol Plugin
- * $Id: gg.c 9806 2004-05-23 17:27:45Z thekingant $
+ * $Id: gg.c 10088 2004-06-15 02:37:27Z thekingant $
  *
  * Copyright (C) 2001 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
  *
@@ -326,7 +326,6 @@
 			}
 			b = gaim_buddy_new(gc->account, name, strlen(show) ? show : NULL);
 			gaim_blist_add_buddy(b,NULL,g,NULL);
-			gaim_blist_save();
 
 			userlist_size++;
 			userlist = g_renew(uin_t, userlist, userlist_size);
@@ -346,12 +345,12 @@
 	}
 }
 
-static void agg_save_buddy_list (GaimConnection *gc, char *existlist)
+static void agg_save_buddy_list(GaimConnection *gc, char *existlist)
 {
+    struct agg_data *gd = (struct agg_data *)gc->proto_data;
     GaimBlistNode *gnode, *cnode, *bnode;
     char *buddylist = g_strdup(existlist ? existlist : "");
     char *ptr;
-    struct agg_data *gd = (struct agg_data *)gc->proto_data;
 
     for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) {
 		GaimGroup *g = (GaimGroup *)gnode;
@@ -781,38 +780,39 @@
 	return 1;
 }
 
-static void agg_add_buddy(GaimConnection *gc, const char *who, GaimGroup *group)
+static void agg_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	struct agg_data *gd = (struct agg_data *)gc->proto_data;
-	if (invalid_uin(who))
+	if (invalid_uin(buddy->name))
 		return;
-	gg_add_notify(gd->sess, strtol(who, (char **)NULL, 10));
+	gg_add_notify(gd->sess, strtol(buddy->name, (char **)NULL, 10));
 	agg_save_buddy_list(gc, NULL);
 }
 
-static void agg_rem_buddy(GaimConnection *gc, const char *who, const char *group)
+static void agg_rem_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	struct agg_data *gd = (struct agg_data *)gc->proto_data;
-	if (invalid_uin(who))
+	if (invalid_uin(buddy->name))
 		return;
-	gg_remove_notify(gd->sess, strtol(who, (char **)NULL, 10));
+	gg_remove_notify(gd->sess, strtol(buddy->name, (char **)NULL, 10));
 	agg_save_buddy_list(gc, NULL);
 }
 
-static void agg_add_buddies(GaimConnection *gc, GList *whos)
+static void agg_add_buddies(GaimConnection *gc, GList *buddies, GList *groups)
 {
 	struct agg_data *gd = (struct agg_data *)gc->proto_data;
 	uin_t *userlist = NULL;
 	int userlist_size = 0;
 
-	while (whos) {
-		if (!invalid_uin(whos->data)) {
+	while (buddies) {
+		GaimBuddy *buddy = buddies->data;
+		if (!invalid_uin(buddy->name)) {
 			userlist_size++;
 			userlist = g_renew(uin_t, userlist, userlist_size);
 			userlist[userlist_size - 1] =
-			    (uin_t) strtol((char *)whos->data, (char **)NULL, 10);
+			    (uin_t) strtol(buddy->name, (char **)NULL, 10);
 		}
-		whos = g_list_next(whos);
+		buddies = g_list_next(buddies);
 	}
 
 	if (userlist) {
@@ -844,6 +844,7 @@
 	j = 0;
 
 	/* Parse array */
+	/* XXX - Make this use a GString */
 	for (i = 0; webdata_tbl[i] != NULL; i++) {
 		gchar *p, *oldibuf;
 		static gchar *ibuf;
@@ -1519,8 +1520,8 @@
     g_free(newdata);
 }
 
-static void agg_rename_group (GaimConnection *gc, const char *old_group,
-		     const char *new_group, GList *members)
+static void agg_rename_group (GaimConnection *gc, const char *old_name,
+		     GaimGroup *group, GList *moved_buddies)
 {
     agg_save_buddy_list(gc, NULL);
 }
--- a/src/protocols/icq/gaim_icq.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/icq/gaim_icq.c	Tue Jun 15 02:37:27 2004 +0000
@@ -376,18 +376,19 @@
 	icq_KeepAlive(id->link);
 }
 
-static void icq_add_buddy(struct gaim_connection *gc, const char *who) {
+static void icq_add_buddy(struct gaim_connection *gc, GaimBuddy *buddy) {
 	struct icq_data *id = (struct icq_data *)gc->proto_data;
-	icq_ContactAdd(id->link, atol(who));
-	icq_ContactSetVis(id->link, atol(who), TRUE);
+	icq_ContactAdd(id->link, atol(buddy->name));
+	icq_ContactSetVis(id->link, atol(buddy->name), TRUE);
 }
 
-static void icq_add_buddies(struct gaim_connection *gc, GList *whos) {
+static void icq_add_buddies(struct gaim_connection *gc, GList *buddies) {
 	struct icq_data *id = (struct icq_data *)gc->proto_data;
-	while (whos) {
-		icq_ContactAdd(id->link, atol(whos->data));
-		icq_ContactSetVis(id->link, atol(whos->data), TRUE);
-		whos = whos->next;
+	while (buddies) {
+		Gaimbuddy *buddy = buddies->data;
+		icq_ContactAdd(id->link, atol(buddy->name));
+		icq_ContactSetVis(id->link, atol(buddy->name), TRUE);
+		buddies = buddies->next;
 	}
 }
 
--- a/src/protocols/irc/irc.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/irc/irc.c	Tue Jun 15 02:37:27 2004 +0000
@@ -355,23 +355,22 @@
 	irc_cmd_away(irc, "away", NULL, args);
 }
 
-static void irc_add_buddy(GaimConnection *gc, const char *who, GaimGroup *group)
+static void irc_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	struct irc_conn *irc = (struct irc_conn *)gc->proto_data;
 	struct irc_buddy *ib = g_new0(struct irc_buddy, 1);
-	ib->name = g_strdup(who);
+	ib->name = g_strdup(buddy->name);
 	g_hash_table_insert(irc->buddies, ib->name, ib);
 
 	irc_blist_timeout(irc);
 }
 
-static void irc_remove_buddy(GaimConnection *gc, const char *who, const char *group)
+static void irc_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	struct irc_conn *irc = (struct irc_conn *)gc->proto_data;
-	g_hash_table_remove(irc->buddies, who);
+	g_hash_table_remove(irc->buddies, buddy->name);
 }
 
-
 static void irc_input_cb(gpointer data, gint source, GaimInputCondition cond)
 {
 	GaimConnection *gc = data;
--- a/src/protocols/jabber/buddy.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/jabber/buddy.c	Tue Jun 15 02:37:27 2004 +0000
@@ -630,7 +630,6 @@
 				serv_got_alias(js->gc, from, text);
 				if(b) {
 					gaim_blist_node_set_string((GaimBlistNode*)b, "servernick", text);
-					gaim_blist_save();
 				}
 				g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
 						_("Nickname"), text);
--- a/src/protocols/jabber/roster.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/jabber/roster.c	Tue Jun 15 02:37:27 2004 +0000
@@ -195,8 +195,6 @@
 			add_gaim_buddies_in_groups(js, jid, name, groups);
 		}
 	}
-
-	gaim_blist_save();
 }
 
 static void jabber_roster_update(JabberStream *js, const char *name,
@@ -246,8 +244,8 @@
 	jabber_iq_send(iq);
 }
 
-void jabber_roster_add_buddy(GaimConnection *gc, const char *name,
-		GaimGroup *grp)
+void jabber_roster_add_buddy(GaimConnection *gc, GaimBuddy *buddy,
+		GaimGroup *group)
 {
 	JabberStream *js = gc->proto_data;
 	char *who;
@@ -259,13 +257,13 @@
 	if(!js->roster_parsed)
 		return;
 
-	if(!(who = jabber_get_bare_jid(name)))
+	if(!(who = jabber_get_bare_jid(buddy->name)))
 		return;
 
-	jb = jabber_buddy_find(js, name, FALSE);
+	jb = jabber_buddy_find(js, buddy->name, FALSE);
 
 	if(!jb || !(jb->subscription & JABBER_SUB_TO)) {
-		groups = g_slist_append(groups, grp->name);
+		groups = g_slist_append(groups, group->name);
 	}
 
 	jabber_roster_update(js, who, groups);
@@ -318,39 +316,41 @@
 	g_slist_free(groups);
 }
 
-void jabber_roster_group_rename(GaimConnection *gc, const char *old_group,
-		const char *new_group, GList *members)
+void jabber_roster_group_rename(GaimConnection *gc, const char *old_name,
+		GaimGroup *group, GList *moved_buddies)
 {
 	GList *l;
-	if(old_group && new_group && strcmp(old_group, new_group)) {
-		for(l = members; l; l = l->next) {
-			jabber_roster_group_change(gc, l->data, old_group, new_group);
-		}
+	for(l = moved_buddies; l; l = l->next) {
+		GaimBuddy *buddy = l->data;
+		jabber_roster_group_change(gc, buddy->name, old_name, group->name);
 	}
 }
 
-void jabber_roster_remove_buddy(GaimConnection *gc, const char *name, const char *group) {
-	GSList *buddies = gaim_find_buddies(gc->account, name);
+void jabber_roster_remove_buddy(GaimConnection *gc, GaimBuddy *buddy,
+		GaimGroup *group) {
+	GSList *buddies = gaim_find_buddies(gc->account, buddy->name);
 	GSList *groups = NULL;
-	GaimGroup *g = gaim_find_group(group);
-	GaimBuddy *b = gaim_find_buddy_in_group(gc->account, name, g);
 
-	buddies = g_slist_remove(buddies, b);
+	buddies = g_slist_remove(buddies, buddy);
 	if(g_slist_length(buddies)) {
+		GaimBuddy *tmpbuddy;
+		GaimGroup *tmpgroup;
+
 		while(buddies) {
-			b = buddies->data;
-			g = gaim_find_buddys_group(b);
-			groups = g_slist_append(groups, g->name);
-			buddies = g_slist_remove(buddies, b);
+			tmpbuddy = buddies->data;
+			tmpgroup = gaim_find_buddys_group(tmpbuddy);
+			groups = g_slist_append(groups, tmpgroup->name);
+			buddies = g_slist_remove(buddies, tmpbuddy);
 		}
-		jabber_roster_update(gc->proto_data, name, groups);
+
+		jabber_roster_update(gc->proto_data, buddy->name, groups);
 	} else {
 		JabberIq *iq = jabber_iq_new_query(gc->proto_data, JABBER_IQ_SET,
 				"jabber:iq:roster");
 		xmlnode *query = xmlnode_get_child(iq->node, "query");
 		xmlnode *item = xmlnode_new_child(query, "item");
 
-		xmlnode_set_attrib(item, "jid", name);
+		xmlnode_set_attrib(item, "jid", buddy->name);
 		xmlnode_set_attrib(item, "subscription", "remove");
 
 		jabber_iq_send(iq);
--- a/src/protocols/jabber/roster.h	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/jabber/roster.h	Tue Jun 15 02:37:27 2004 +0000
@@ -28,15 +28,15 @@
 
 void jabber_roster_parse(JabberStream *js, xmlnode *packet);
 
-void jabber_roster_add_buddy(GaimConnection *gc, const char *name,
-		GaimGroup *grp);
+void jabber_roster_add_buddy(GaimConnection *gc, GaimBuddy *buddy,
+		GaimGroup *group);
 void jabber_roster_alias_change(GaimConnection *gc, const char *name,
 		const char *alias);
 void jabber_roster_group_change(GaimConnection *gc, const char *name,
 		const char *old_group, const char *new_group);
-void jabber_roster_group_rename(GaimConnection *gc, const char *old_group,
-		const char *new_group, GList *members);
-void jabber_roster_remove_buddy(GaimConnection *gc, const char *name,
-		const char *group);
+void jabber_roster_group_rename(GaimConnection *gc, const char *old_name,
+		GaimGroup *group, GList *moved_buddies);
+void jabber_roster_remove_buddy(GaimConnection *gc, GaimBuddy *buddy,
+		GaimGroup *group);
 
 #endif /* _GAIM_JABBER_ROSTER_H_ */
--- a/src/protocols/msn/msn.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/msn/msn.c	Tue Jun 15 02:37:27 2004 +0000
@@ -802,7 +802,7 @@
 }
 
 static void
-msn_add_buddy(GaimConnection *gc, const char *name, GaimGroup *group)
+msn_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	MsnSession *session;
 	MsnUserList *userlist;
@@ -810,7 +810,7 @@
 
 	session = gc->proto_data;
 	userlist = session->userlist;
-	who = msn_normalize(gc->account, name);
+	who = msn_normalize(gc->account, buddy->name);
 
 	if (group != NULL)
 		gaim_debug_info("msn", "msn_add_buddy: %s, %s\n", who, group->name);
@@ -823,17 +823,18 @@
 	{
 		gaim_debug_info("msn", "Too many buddies\n");
 		/* Buddy list full */
-		/* TODO: gaim should be notifyied of this */
+		/* TODO: gaim should be notified of this */
 		return;
 	}
 #endif
 
+	/* XXX - Would group ever be NULL here?  I don't think so... */
 	msn_userlist_add_buddy(userlist, who, MSN_LIST_FL,
 						   group ? group->name : NULL);
 }
 
 static void
-msn_rem_buddy(GaimConnection *gc, const char *who, const char *group_name)
+msn_rem_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	MsnSession *session;
 	MsnUserList *userlist;
@@ -841,7 +842,8 @@
 	session = gc->proto_data;
 	userlist = session->userlist;
 
-	msn_userlist_rem_buddy(userlist, who, MSN_LIST_FL, group_name);
+	/* XXX - Does buddy->name need to be msn_normalize'd here?  --KingAnt */
+	msn_userlist_rem_buddy(userlist, buddy->name, MSN_LIST_FL, group->name);
 }
 
 static void
@@ -1037,8 +1039,8 @@
 }
 
 static void
-msn_rename_group(GaimConnection *gc, const char *old_group_name,
-				 const char *new_group_name, GList *members)
+msn_rename_group(GaimConnection *gc, const char *old_name,
+				 GaimGroup *group, GList *moved_buddies)
 {
 	MsnSession *session;
 	MsnCmdProc *cmdproc;
@@ -1047,9 +1049,9 @@
 
 	session = gc->proto_data;
 	cmdproc = session->notification->cmdproc;
-	enc_new_group_name = gaim_url_encode(new_group_name);
+	enc_new_group_name = gaim_url_encode(group->name);
 
-	old_gid = msn_userlist_find_group_id(session->userlist, old_group_name);
+	old_gid = msn_userlist_find_group_id(session->userlist, old_name);
 
 	if (old_gid >= 0)
 	{
@@ -1112,7 +1114,7 @@
 }
 
 static void
-msn_remove_group(GaimConnection *gc, const char *name)
+msn_remove_group(GaimConnection *gc, GaimGroup *group)
 {
 	MsnSession *session;
 	MsnCmdProc *cmdproc;
@@ -1121,7 +1123,7 @@
 	session = gc->proto_data;
 	cmdproc = session->notification->cmdproc;
 
-	if ((group_id = msn_userlist_find_group_id(session->userlist, name)) >= 0)
+	if ((group_id = msn_userlist_find_group_id(session->userlist, group->name)) >= 0)
 	{
 		msn_cmdproc_send(cmdproc, "RMG", "%d", group_id);
 	}
--- a/src/protocols/msn/slp.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/msn/slp.c	Tue Jun 15 02:37:27 2004 +0000
@@ -763,7 +763,6 @@
 	{
 		GaimBuddy *buddy = (GaimBuddy *)sl->data;
 		gaim_blist_node_set_string((GaimBlistNode*)buddy, "icon_checksum", info);
-		gaim_blist_save();
 	}
 }
 
--- a/src/protocols/napster/napster.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/napster/napster.c	Tue Jun 15 02:37:27 2004 +0000
@@ -141,24 +141,25 @@
 }
 
 /* 207 - MSG_CLIENT_ADD_HOTLIST */
-static void nap_add_buddy(GaimConnection *gc, const char *name, GaimGroup *group)
+static void nap_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
-	nap_write_packet(gc, 207, "%s", name);
+	nap_write_packet(gc, 207, "%s", buddy->name);
 }
 
 /* 208 - MSG_CLIENT_ADD_HOTLIST_SEQ */
-static void nap_add_buddies(GaimConnection *gc, GList *buddies)
+static void nap_add_buddies(GaimConnection *gc, GList *buddies, GList *groups)
 {
 	while (buddies) {
-		nap_write_packet(gc, 208, "%s", (char *)buddies->data);
-		buddies = buddies -> next;
+		GaimBuddy *buddy = buddies->data;
+		nap_write_packet(gc, 208, "%s", buddy->name);
+		buddies = buddies->next;
 	}
 }
 
 /* 303 - MSG_CLIENT_REMOVE_HOTLIST */
-static void nap_remove_buddy(GaimConnection *gc, const char *name, const char *group)
+static void nap_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
-	nap_write_packet(gc, 303, "%s", name);
+	nap_write_packet(gc, 303, "%s", buddy->name);
 }
 
 /* 400 - MSG_CLIENT_JOIN */
--- a/src/protocols/novell/novell.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/novell/novell.c	Tue Jun 15 02:37:27 2004 +0000
@@ -2430,15 +2430,15 @@
 }
 
 static void
-novell_add_buddy(GaimConnection * gc, const char *name, GaimGroup * group)
+novell_add_buddy(GaimConnection * gc, GaimBuddy *buddy, GaimGroup * group)
 {
-	GaimBuddy *buddy;
 	NMFolder *folder = NULL;
 	NMContact *contact;
 	NMUser *user;
 	NMERR_T rc = NM_OK;
-
-	if (gc == NULL || name == NULL || group == NULL)
+	const char *alias;
+
+	if (gc == NULL || buddy == NULL || group == NULL)
 		return;
 
 	user = (NMUser *) gc->proto_data;
@@ -2446,21 +2446,17 @@
 		return;
 
 	contact = nm_create_contact();
-	nm_contact_set_dn(contact, name);
+	nm_contact_set_dn(contact, buddy->name);
 
 	/* Remove the GaimBuddy (we will add it back after adding it
 	 * to the server side list). Save the alias if there is one.
 	 */
-	buddy = gaim_find_buddy_in_group(user->client_data, name, group);
-	if (buddy) {
-		const char *alias = gaim_get_buddy_alias(buddy);
-
-		if (alias && strcmp(alias, name))
-			nm_contact_set_display_name(contact, gaim_get_buddy_alias(buddy));
-		gaim_blist_remove_buddy(buddy);
-		buddy = NULL;
-	}
-
+	alias = gaim_get_buddy_alias(buddy);
+	if (alias && strcmp(alias, buddy->name))
+		nm_contact_set_display_name(contact, alias);
+
+	gaim_blist_remove_buddy(buddy);
+	buddy = NULL;
 
 	folder = nm_find_folder(user, group->name);
 	if (folder) {
@@ -2481,7 +2477,7 @@
 }
 
 static void
-novell_remove_buddy(GaimConnection * gc, const char *name, const char *group_name)
+novell_remove_buddy(GaimConnection * gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	NMContact *contact;
 	NMFolder *folder;
@@ -2489,13 +2485,13 @@
 	const char *dn;
 	NMERR_T rc = NM_OK;
 
-	if (gc == NULL || name == NULL || group_name == NULL)
+	if (gc == NULL || buddy == NULL || group == NULL)
 		return;
 
 	user = (NMUser *) gc->proto_data;
-	if (user && (dn = nm_lookup_dn(user, name))) {
-
-		folder = nm_find_folder(user, group_name);
+	if (user && (dn = nm_lookup_dn(user, buddy->name))) {
+
+		folder = nm_find_folder(user, group->name);
 		if (folder) {
 			contact = nm_folder_find_contact(folder, dn);
 			if (contact) {
@@ -2513,17 +2509,17 @@
 }
 
 static void
-novell_remove_group(GaimConnection * gc, const char *name)
+novell_remove_group(GaimConnection * gc, GaimGroup *group)
 {
 	NMUser *user;
 	NMERR_T rc = NM_OK;
 
-	if (gc == NULL || name == NULL)
+	if (gc == NULL || group == NULL)
 		return;
 
 	user = (NMUser *) gc->proto_data;
 	if (user) {
-		NMFolder *folder = nm_find_folder(user, name);
+		NMFolder *folder = nm_find_folder(user, group->name);
 
 		if (folder) {
 			rc = nm_send_remove_folder(user, folder,
@@ -2632,21 +2628,21 @@
 
 static void
 novell_rename_group(GaimConnection * gc, const char *old_name,
-					const char *new_name, GList * tobemoved)
+					GaimGroup *group, GList *moved_buddies)
 {
 	NMERR_T rc = NM_OK;
 	NMFolder *folder;
 	NMUser *user;
 
-	if (gc == NULL || old_name == NULL || new_name == NULL || tobemoved == NULL) {
+	if (gc == NULL || old_name == NULL || group == NULL || moved_buddies == NULL) {
 		return;
 	}
 
 	user = gc->proto_data;
 	if (user) {
 		/* Does new folder exist already? */
-		if (nm_find_folder(user, new_name)) {
-			/* Gaim currently calls novell_group_buddy() for
+		if (nm_find_folder(user, group->name)) {
+			/* Gaim currently calls novell_group_buddy()
 			 * for all buddies in the group, so we don't
 			 * need to worry about this situation.
 			 */
@@ -2656,7 +2652,7 @@
 		folder = nm_find_folder(user, old_name);
 
 		if (folder) {
-			rc = nm_send_rename_folder(user, folder, new_name,
+			rc = nm_send_rename_folder(user, folder, group->name,
 									   _rename_folder_resp_cb, NULL);
 			_check_for_disconnect(user, rc);
 		}
--- a/src/protocols/oscar/oscar.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/oscar/oscar.c	Tue Jun 15 02:37:27 2004 +0000
@@ -4332,7 +4332,6 @@
 		b16 = gaim_base16_encode(iconcsum, iconcsumlen);
 		if (b16) {
 			gaim_blist_node_set_string((GaimBlistNode*)b, "icon_checksum", b16);
-			gaim_blist_save();
 			g_free(b16);
 		}
 	}
@@ -4931,7 +4930,6 @@
 		serv_got_alias(gc, who, utf8);
 		if ((b = gaim_find_buddy(gc->account, who))) {
 			gaim_blist_node_set_string((GaimBlistNode*)b, "servernick", utf8);
-			gaim_blist_save();
 		}
 		g_free(utf8);
 	}
@@ -5510,50 +5508,43 @@
 	aim_im_warn(od->sess, od->conn, name, anon ? AIM_WARN_ANON : 0);
 }
 
-static void oscar_add_buddy(GaimConnection *gc, const char *name, GaimGroup *g) {
+static void oscar_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) {
 	OscarData *od = (OscarData *)gc->proto_data;
-	GaimBuddy *b;
-
-	if (g == NULL) {
-		/* If we were called from oscar_add_buddies... */
-		b = gaim_find_buddy(gaim_connection_get_account(gc), name);
-		g = gaim_find_buddys_group(b);
-	} else
-		b = gaim_find_buddy_in_group(gaim_connection_get_account(gc), name, g);
-
-	if (!aim_snvalid(name)) {
+
+	if (!aim_snvalid(buddy->name)) {
 		gchar *buf;
-		buf = g_strdup_printf(_("Could not add the buddy %s because the screen name is invalid.  Screen names must either start with a letter and contain only letters, numbers and spaces, or contain only numbers."), name);
+		buf = g_strdup_printf(_("Could not add the buddy %s because the screen name is invalid.  Screen names must either start with a letter and contain only letters, numbers and spaces, or contain only numbers."), buddy->name);
 		gaim_notify_error(gc, NULL, _("Unable To Add"), buf);
 		g_free(buf);
 
 		/* Remove from local list */
-		gaim_blist_remove_buddy(b);
+		gaim_blist_remove_buddy(buddy);
 
 		return;
 	}
 
 #ifdef NOSSI
-	aim_buddylist_addbuddy(od->sess, od->conn, name);
+	aim_buddylist_addbuddy(od->sess, od->conn, buddy->name);
 #else
-	if ((od->sess->ssi.received_data) && !(aim_ssi_itemlist_exists(od->sess->ssi.local, name))) {
-		if (b && g) {
+	if ((od->sess->ssi.received_data) && !(aim_ssi_itemlist_finditem(od->sess->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY))) {
+		if (buddy && group) {
 			gaim_debug_info("oscar",
-					   "ssi: adding buddy %s to group %s\n", name, g->name);
-			aim_ssi_addbuddy(od->sess, b->name, g->name, gaim_get_buddy_alias_only(b), NULL, NULL, 0);
+					   "ssi: adding buddy %s to group %s\n", buddy->name, group->name);
+			aim_ssi_addbuddy(od->sess, buddy->name, group->name, gaim_get_buddy_alias_only(buddy), NULL, NULL, 0);
 		}
 	}
 #endif
 
 	if (od->icq)
-		aim_icq_getalias(od->sess, name);
-}
-
-static void oscar_add_buddies(GaimConnection *gc, GList *buddies) {
+		aim_icq_getalias(od->sess, buddy->name);
+}
+
+static void oscar_add_buddies(GaimConnection *gc, GList *buddies, GList *groups) {
 	OscarData *od = (OscarData *)gc->proto_data;
 #ifdef NOSSI
 	char buf[MSG_LEN];
 	int n=0;
+
 	while (buddies) {
 		if (n > MSG_LEN - 18) {
 			aim_buddylist_set(od->sess, od->conn, buf);
@@ -5564,39 +5555,53 @@
 	}
 	aim_buddylist_set(od->sess, od->conn, buf);
 #else
+
 	if (od->sess->ssi.received_data) {
-		while (buddies) {
-			oscar_add_buddy(gc, buddies->data, NULL);
-			buddies = buddies->next;
+		GList *curb = buddies;
+		GList *curg = groups;
+		while ((curb != NULL) && (curg != NULL)) {
+			GaimBuddy *buddy = curb->data;
+			GaimGroup *group = curg->data;
+			oscar_add_buddy(gc, buddy, group);
+			curb = curb->next;
+			curg = curg->next;
 		}
 	}
 #endif
 }
 
-static void oscar_remove_buddy(GaimConnection *gc, const char *name, const char *group) {
+static void oscar_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) {
 	OscarData *od = (OscarData *)gc->proto_data;
+
 #ifdef NOSSI
-	aim_buddylist_removebuddy(od->sess, od->conn, name);
+	aim_buddylist_removebuddy(od->sess, od->conn, buddy->name);
 #else
 	if (od->sess->ssi.received_data) {
 		gaim_debug_info("oscar",
-				   "ssi: deleting buddy %s from group %s\n", name, group);
-		aim_ssi_delbuddy(od->sess, name, group);
+				   "ssi: deleting buddy %s from group %s\n", buddy->name, group->name);
+		aim_ssi_delbuddy(od->sess, buddy->name, group->name);
 	}
 #endif
 }
 
-static void oscar_remove_buddies(GaimConnection *gc, GList *buddies, const char *group) {
+static void oscar_remove_buddies(GaimConnection *gc, GList *buddies, GList *groups) {
 	OscarData *od = (OscarData *)gc->proto_data;
+
 #ifdef NOSSI
-	GList *cur;
-	for (cur=buddies; cur; cur=cur->next)
-		aim_buddylist_removebuddy(od->sess, od->conn, cur->data);
+	for (cur = buddies; cur != NULL; cur = cur->next) {
+		GaimBuddy *buddy = cur->data;
+		aim_buddylist_removebuddy(od->sess, od->conn, buddy->name);
+	}
 #else
 	if (od->sess->ssi.received_data) {
-		while (buddies) {
-			oscar_remove_buddy(gc, buddies->data, group);
-			buddies = buddies->next;
+		GList *curb = buddies;
+		GList *curg = groups;
+		while ((curb != NULL) && (curg != NULL)) {
+			GaimBuddy *buddy = curb->data;
+			GaimGroup *group = curg->data;
+			oscar_remove_buddy(gc, buddy, group);
+			curb = curb->next;
+			curg = curg->next;
 		}
 	}
 #endif
@@ -5624,19 +5629,28 @@
 	}
 }
 
-static void oscar_rename_group(GaimConnection *gc, const char *old_group, const char *new_group, GList *members) {
+static void oscar_rename_group(GaimConnection *gc, const char *old_name, GaimGroup *group, GList *moved_buddies) {
 	OscarData *od = (OscarData *)gc->proto_data;
 
 	if (od->sess->ssi.received_data) {
-		if (aim_ssi_itemlist_finditem(od->sess->ssi.local, new_group, NULL, AIM_SSI_TYPE_GROUP)) {
-			oscar_remove_buddies(gc, members, old_group);
-			oscar_add_buddies(gc, members);
+		if (aim_ssi_itemlist_finditem(od->sess->ssi.local, group->name, NULL, AIM_SSI_TYPE_GROUP)) {
+			GList *cur, *groups = NULL;
+
+			/* Make a list of what the groups each buddy is in */
+			for (cur = moved_buddies; cur != NULL; cur = cur->next) {
+				GaimBlistNode *node = cur->data;
+				groups = g_list_append(groups, node->parent);
+			}
+
+			oscar_remove_buddies(gc, moved_buddies, groups);
+			oscar_add_buddies(gc, moved_buddies, groups);
+			g_list_free(groups);
 			gaim_debug_info("oscar",
-					   "ssi: moved all buddies from group %s to %s\n", old_group, new_group);
+					   "ssi: moved all buddies from group %s to %s\n", old_name, group->name);
 		} else {
-			aim_ssi_rename_group(od->sess, old_group, new_group);
+			aim_ssi_rename_group(od->sess, old_name, group->name);
 			gaim_debug_info("oscar",
-					   "ssi: renamed group %s to %s\n", old_group, new_group);
+					   "ssi: renamed group %s to %s\n", old_name, group->name);
 		}
 	}
 }
@@ -5843,7 +5857,7 @@
 						}
 
 						gaim_debug_info("oscar",
-								   "ssi: adding b %s to group %s to local list\n", curitem->name, gname_utf8 ? gname_utf8 : _("Orphans"));
+								   "ssi: adding buddy %s to group %s to local list\n", curitem->name, gname_utf8 ? gname_utf8 : _("Orphans"));
 						gaim_blist_add_buddy(b, NULL, g, NULL);
 					}
 					if (!aim_sncmp(curitem->name, account->username)) {
@@ -6004,7 +6018,7 @@
 		}
 
 		gaim_debug_info("oscar",
-				   "ssi: adding b %s to group %s to local list\n", name, gname_utf8 ? gname_utf8 : _("Orphans"));
+				   "ssi: adding buddy %s to group %s to local list\n", name, gname_utf8 ? gname_utf8 : _("Orphans"));
 		gaim_blist_add_buddy(b, NULL, g, NULL);
 	}
 	g_free(gname_utf8);
--- a/src/protocols/oscar/ssi.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/oscar/ssi.c	Tue Jun 15 02:37:27 2004 +0000
@@ -266,7 +266,7 @@
  * @param gn The group name of the desired item.
  * @param bn The buddy name of the desired item.
  * @param type The type of the desired item.
- * @return Return a pointer to the item if found, else return NULL;
+ * @return Return a pointer to the item if found, else return NULL.
  */
 faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, fu16_t type)
 {
--- a/src/protocols/silc/buddy.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/silc/buddy.c	Tue Jun 15 02:37:27 2004 +0000
@@ -1322,41 +1322,15 @@
 	silc_buffer_free(attrs);
 }
 
-void silcgaim_add_buddy(GaimConnection *gc, const char *name, GaimGroup *grp)
+void silcgaim_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
-	GaimBuddy *b;
-
-	b = gaim_find_buddy_in_group(gc->account, name, grp);
-	if (!b)
-	  return;
-
-	silcgaim_add_buddy_i(gc, b, FALSE);
+	silcgaim_add_buddy_i(gc, buddy, FALSE);
 }
 
-void silcgaim_add_buddies(GaimConnection *gc, GList *buddies)
+void silcgaim_remove_buddy(GaimConnection *gc, GaimBuddy *buddy,
+			   GaimGroup *group)
 {
-	while (buddies) {
-		GaimBuddy *b;
-		b = gaim_find_buddy(gc->account, buddies->data);
-		if (!b)
-			continue;
-		silcgaim_add_buddy_i(gc, b, TRUE);
-		buddies = buddies->next;
-	}
-}
-
-void silcgaim_remove_buddy(GaimConnection *gc, const char *name,
-			   const char *group)
-{
-	GaimBuddy *b;
-	GaimGroup *g;
-
-	g = gaim_find_group(group);
-	b = gaim_find_buddy_in_group(gc->account, name, g);
-	if (!b)
-		return;
-
-	silc_free(b->proto_data);
+	silc_free(buddy->proto_data);
 }
 
 void silcgaim_idle_set(GaimConnection *gc, int idle)
--- a/src/protocols/silc/silc.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/silc/silc.c	Tue Jun 15 02:37:27 2004 +0000
@@ -1282,7 +1282,7 @@
 	silcgaim_idle_set,
 	silcgaim_change_passwd,
 	silcgaim_add_buddy,
-	silcgaim_add_buddies,
+	NULL,
 	silcgaim_remove_buddy,
 	NULL,
 	NULL,
--- a/src/protocols/toc/toc.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/toc/toc.c	Tue Jun 15 02:37:27 2004 +0000
@@ -567,9 +567,9 @@
 	struct signon so;
 	char buf[8 * 1024], *c;
 	char snd[BUF_LEN * 2];
-
 	const char *username = gaim_account_get_username(account);
 	char *password;
+	GaimBuddy *buddy;
 
 	/* there's data waiting to be read, so read it. */
 	if (wait_reply(gc, buf, 8 * 1024) <= 0) {
@@ -647,7 +647,10 @@
 		 * Add me to my buddy list so that we know the time when
 		 * the server thinks I signed on.
 		 */
-		serv_add_buddy(gc, username, NULL);
+		buddy = gaim_buddy_new(account, username, NULL);
+		/* XXX - Pick a group to add to */
+		/* gaim_blist_add(buddy, NULL, g, NULL); */
+		serv_add_buddy(gc, buddy);
 
 		/* Client sends TOC toc_init_done message */
 		gaim_debug(GAIM_DEBUG_INFO, "toc",
@@ -1185,52 +1188,56 @@
 }
 
 static void
-toc_add_buddy(GaimConnection *gc, const char *name, GaimGroup *group)
+toc_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	char buf[BUF_LEN * 2];
-	g_snprintf(buf, sizeof(buf), "toc_add_buddy %s", gaim_normalize(gc->account, name));
+	g_snprintf(buf, sizeof(buf), "toc_add_buddy %s", gaim_normalize(gc->account, buddy->name));
 	sflap_send(gc, buf, -1, TYPE_DATA);
 	toc_set_config(gc);
 }
 
-static void toc_add_buddies(GaimConnection *gc, GList *buddies)
+static void toc_add_buddies(GaimConnection *gc, GList *buddies, GList *groups)
 {
 	char buf[BUF_LEN * 2];
 	int n;
+	GList *cur;
 
 	n = g_snprintf(buf, sizeof(buf), "toc_add_buddy");
-	while (buddies) {
-		if (strlen(gaim_normalize(gc->account, buddies->data)) + n + 32 > MSG_LEN) {
+	for (cur = buddies; cur != NULL; cur = cur->next) {
+		GaimBuddy *buddy = cur->data;
+
+		if (strlen(gaim_normalize(gc->account, buddy->name)) + n + 32 > MSG_LEN) {
 			sflap_send(gc, buf, -1, TYPE_DATA);
 			n = g_snprintf(buf, sizeof(buf), "toc_add_buddy");
 		}
-		n += g_snprintf(buf + n, sizeof(buf) - n, " %s", gaim_normalize(gc->account, buddies->data));
-		buddies = buddies->next;
+		n += g_snprintf(buf + n, sizeof(buf) - n, " %s", gaim_normalize(gc->account, buddy->name));
 	}
 	sflap_send(gc, buf, -1, TYPE_DATA);
 }
 
-static void toc_remove_buddy(GaimConnection *gc, const char *name, const char *group)
+static void toc_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	char buf[BUF_LEN * 2];
-	g_snprintf(buf, sizeof(buf), "toc_remove_buddy %s", gaim_normalize(gc->account, name));
+	g_snprintf(buf, sizeof(buf), "toc_remove_buddy %s", gaim_normalize(gc->account, buddy->name));
 	sflap_send(gc, buf, -1, TYPE_DATA);
 	toc_set_config(gc);
 }
 
-static void toc_remove_buddies(GaimConnection *gc, GList *buddies, const char *group)
+static void toc_remove_buddies(GaimConnection *gc, GList *buddies, GList *groups)
 {
 	char buf[BUF_LEN * 2];
 	int n;
+	GList *cur;
 
 	n = g_snprintf(buf, sizeof(buf), "toc_remove_buddy");
-	while (buddies) {
-		if (strlen(gaim_normalize(gc->account, buddies->data)) + n + 32 > MSG_LEN) {
+	for (cur = buddies; cur != NULL; cur = cur->next) {
+		GaimBuddy *buddy = cur->data;
+
+		if (strlen(gaim_normalize(gc->account, buddy->name)) + n + 32 > MSG_LEN) {
 			sflap_send(gc, buf, -1, TYPE_DATA);
 			n = g_snprintf(buf, sizeof(buf), "toc_remove_buddy");
 		}
-		n += g_snprintf(buf + n, sizeof(buf) - n, " %s", gaim_normalize(gc->account, buddies->data));
-		buddies = buddies->next;
+		n += g_snprintf(buf + n, sizeof(buf) - n, " %s", gaim_normalize(gc->account, buddy->name));
 	}
 	sflap_send(gc, buf, -1, TYPE_DATA);
 	toc_set_config(gc);
--- a/src/protocols/trepia/trepia.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/trepia/trepia.c	Tue Jun 15 02:37:27 2004 +0000
@@ -1136,16 +1136,6 @@
 }
 
 static void
-trepia_add_buddy(GaimConnection *gc, const char *name, GaimGroup *group)
-{
-}
-
-static void
-trepia_rem_buddy(GaimConnection *gc, const char *who, const char *group)
-{
-}
-
-static void
 trepia_buddy_free(GaimBuddy *b)
 {
 	if (b->proto_data != NULL) {
@@ -1226,9 +1216,9 @@
 	NULL,	/* set_away */
 	NULL,	/* set_idle */
 	NULL,	/* change_passwd */
-	trepia_add_buddy,
+	NULL,	/* add_buddy */
 	NULL,	/* add_buddies */
-	trepia_rem_buddy,
+	NULL,	/* rem_buddy */
 	NULL,	/* remove_buddies */
 	NULL,	/* add_permit */
 	NULL,	/* add_deny */
--- a/src/protocols/yahoo/yahoo.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/protocols/yahoo/yahoo.c	Tue Jun 15 02:37:27 2004 +0000
@@ -46,7 +46,7 @@
 
 /* #define YAHOO_DEBUG */
 
-static void yahoo_add_buddy(GaimConnection *gc, const char *who, GaimGroup *);
+static void yahoo_add_buddy(GaimConnection *gc, GaimBuddy *, GaimGroup *);
 static void yahoo_send_buddy_icon_request(GaimConnection *gc, const char *who);
 
 struct yahoo_packet *yahoo_packet_new(enum yahoo_service service, enum yahoo_status status, int id)
@@ -417,8 +417,7 @@
 	}
 }
 
-static void yahoo_do_group_check(GaimAccount *account, GHashTable *ht, const char *name, const char *group,
-				 gboolean *export)
+static void yahoo_do_group_check(GaimAccount *account, GHashTable *ht, const char *name, const char *group)
 {
 	GaimBuddy *b;
 	GaimGroup *g;
@@ -455,7 +454,6 @@
 		}
 		b = gaim_buddy_new(account, name, NULL);
 		gaim_blist_add_buddy(b, NULL, g, NULL);
-		*export = TRUE;
 	}
 
 	if (list) {
@@ -472,10 +470,6 @@
 	GSList *list = value, *i;
 	GaimBuddy *b;
 	GaimGroup *g;
-	gboolean *export = user_data;
-
-	if (list)
-		*export = TRUE;
 
 	for (i = list; i; i = i->next) {
 		b = i->data;
@@ -593,7 +587,7 @@
 					export = TRUE;
 				}
 
-				yahoo_do_group_check(account, ht, norm_bud, grp, &export);
+				yahoo_do_group_check(account, ht, norm_bud, grp);
 				g_free(norm_bud);
 			}
 			g_strfreev(buddies);
@@ -604,7 +598,7 @@
 
 		g_string_free(yd->tmp_serv_blist, TRUE);
 		yd->tmp_serv_blist = NULL;
-		g_hash_table_foreach(ht, yahoo_do_group_cleanup, &export);
+		g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL);
 		g_hash_table_destroy(ht);
 	}
 
@@ -626,8 +620,6 @@
 		gc->account->perm_deny = 4;
 		serv_set_permit_deny(gc);
 	}
-	if (export)
-		gaim_blist_save();
 }
 
 static void yahoo_process_notify(GaimConnection *gc, struct yahoo_packet *pkt)
@@ -1620,31 +1612,30 @@
 	}
 }
 
-static void ignore_buddy(GaimBuddy *b) {
-	GaimGroup *g;
-	GaimConversation *c;
+static void ignore_buddy(GaimBuddy *buddy) {
+	GaimGroup *group;
+	GaimConversation *conv;
 	GaimAccount *account;
 	gchar *name;
 
-	if (!b)
+	if (!buddy)
 		return;
 
-	g = gaim_find_buddys_group(b);
-	name = g_strdup(b->name);
-	account = b->account;
+	group = gaim_find_buddys_group(buddy);
+	name = g_strdup(buddy->name);
+	account = buddy->account;
 
 	gaim_debug(GAIM_DEBUG_INFO, "blist",
-		"Removing '%s' from buddy list.\n", b->name);
-	serv_remove_buddy(account->gc, name, g->name);
-	gaim_blist_remove_buddy(b);
+		"Removing '%s' from buddy list.\n", buddy->name);
+	serv_remove_buddy(account->gc, buddy, group);
+	gaim_blist_remove_buddy(buddy);
 
 	serv_add_deny(account->gc, name);
-	gaim_blist_save();
-
-	c = gaim_find_conversation_with_account(name, account);
-
-	if (c != NULL)
-		gaim_conversation_update(c, GAIM_CONV_UPDATE_REMOVE);
+
+	conv = gaim_find_conversation_with_account(name, account);
+
+	if (conv != NULL)
+		gaim_conversation_update(conv, GAIM_CONV_UPDATE_REMOVE);
 
 	g_free(name);
 }
@@ -2598,7 +2589,7 @@
 	buddy = (GaimBuddy *) node;
 	gc = gaim_account_get_connection(buddy->account);
 
-	yahoo_add_buddy(gc, buddy->name, NULL);
+	yahoo_add_buddy(gc, buddy, NULL);
 }
 
 
@@ -2958,7 +2949,8 @@
 	yahoo_packet_free(pkt);
 }
 
-static void yahoo_add_buddy(GaimConnection *gc, const char *who, GaimGroup *foo)
+/* XXX - What's the deal with GaimGroup *foo? */
+static void yahoo_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *foo)
 {
 	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
 	struct yahoo_packet *pkt;
@@ -2972,7 +2964,7 @@
 	if (foo)
 		group = foo->name;
 	if (!group) {
-		g = gaim_find_buddys_group(gaim_find_buddy(gc->account, who));
+		g = gaim_find_buddys_group(gaim_find_buddy(gc->account, buddy->name));
 		if (g)
 			group = g->name;
 		else
@@ -2982,7 +2974,7 @@
 	group2 = yahoo_string_encode(gc, group, NULL);
 	pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0);
 	yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc));
-	yahoo_packet_hash(pkt, 7, who);
+	yahoo_packet_hash(pkt, 7, buddy->name);
 	yahoo_packet_hash(pkt, 65, group2);
 	yahoo_packet_hash(pkt, 14, "");
 	yahoo_send_packet(yd, pkt);
@@ -2990,7 +2982,7 @@
 	g_free(group2);
 }
 
-static void yahoo_remove_buddy(GaimConnection *gc, const char *who, const char *group)
+static void yahoo_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
 	YahooFriend *f;
@@ -3000,13 +2992,13 @@
 	gboolean remove = TRUE;
 	char *cg;
 
-	if (!(f = yahoo_friend_find(gc, who)))
+	if (!(f = yahoo_friend_find(gc, buddy->name)))
 		return;
 
-	buddies = gaim_find_buddies(gaim_connection_get_account(gc), who);
+	buddies = gaim_find_buddies(gaim_connection_get_account(gc), buddy->name);
 	for (l = buddies; l; l = l->next) {
 		g = gaim_find_buddys_group(l->data);
-		if (gaim_utf8_strcasecmp(group, g->name)) {
+		if (gaim_utf8_strcasecmp(group->name, g->name)) {
 			remove = FALSE;
 			break;
 		}
@@ -3015,12 +3007,12 @@
 	g_slist_free(buddies);
 
 	if (remove)
-		g_hash_table_remove(yd->friends, who);
-
-	cg = yahoo_string_encode(gc, group, NULL);
+		g_hash_table_remove(yd->friends, buddy->name);
+
+	cg = yahoo_string_encode(gc, group->name, NULL);
 	pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0);
 	yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc));
-	yahoo_packet_hash(pkt, 7, who);
+	yahoo_packet_hash(pkt, 7, buddy->name);
 	yahoo_packet_hash(pkt, 65, cg);
 	yahoo_send_packet(yd, pkt);
 	yahoo_packet_free(pkt);
@@ -3141,15 +3133,15 @@
 	g_free(gpo);
 }
 
-static void yahoo_rename_group(GaimConnection *gc, const char *old_group,
-                                                 const char *new_group, GList *whocares)
+static void yahoo_rename_group(GaimConnection *gc, const char *old_name,
+							   GaimGroup *group, GList *moved_buddies)
 {
 	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
 	char *gpn, *gpo;
 
-	gpn = yahoo_string_encode(gc, new_group, NULL);
-	gpo = yahoo_string_encode(gc, old_group, NULL);
+	gpn = yahoo_string_encode(gc, group->name, NULL);
+	gpo = yahoo_string_encode(gc, old_name, NULL);
 	if (!strcmp(gpn, gpo)) {
 		g_free(gpn);
 		g_free(gpo);
--- a/src/prpl.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/prpl.c	Tue Jun 15 02:37:27 2004 +0000
@@ -23,7 +23,6 @@
 #include "internal.h"
 #include "conversation.h"
 #include "debug.h"
-#include "multi.h"
 #include "notify.h"
 #include "prpl.h"
 #include "request.h"
--- a/src/prpl.h	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/prpl.h	Tue Jun 15 02:37:27 2004 +0000
@@ -237,12 +237,10 @@
 	void (*set_idle)(GaimConnection *, int idletime);
 	void (*change_passwd)(GaimConnection *, const char *old_pass,
 						  const char *new_pass);
-	void (*add_buddy)(GaimConnection *, const char *name, GaimGroup *group);
-	void (*add_buddies)(GaimConnection *, GList *buddies);
-	void (*remove_buddy)(GaimConnection *, const char *name,
-						const char *group);
-	void (*remove_buddies)(GaimConnection *, GList *buddies,
-						   const char *group);
+	void (*add_buddy)(GaimConnection *, GaimBuddy *buddy, GaimGroup *group);
+	void (*add_buddies)(GaimConnection *, GList *buddies, GList *groups);
+	void (*remove_buddy)(GaimConnection *, GaimBuddy *buddy, GaimGroup *group);
+	void (*remove_buddies)(GaimConnection *, GList *buddies, GList *groups);
 	void (*add_permit)(GaimConnection *, const char *name);
 	void (*add_deny)(GaimConnection *, const char *name);
 	void (*rem_permit)(GaimConnection *, const char *name);
@@ -275,8 +273,8 @@
 						const char *old_group, const char *new_group);
 
 	/* rename a group on a server list/roster */
-	void (*rename_group)(GaimConnection *, const char *old_group,
-						 const char *new_group, GList *members);
+	void (*rename_group)(GaimConnection *, const char *old_name,
+						 GaimGroup *group, GList *moved_buddies);
 
 	void (*buddy_free)(GaimBuddy *);
 
@@ -286,7 +284,7 @@
 
 	void (*set_buddy_icon)(GaimConnection *, const char *filename);
 
-	void (*remove_group)(GaimConnection *gc, const char *group);
+	void (*remove_group)(GaimConnection *gc, GaimGroup *group);
 
 	char *(*get_cb_real_name)(GaimConnection *gc, int id, const char *who);
 
--- a/src/server.c	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/server.c	Tue Jun 15 02:37:27 2004 +0000
@@ -24,7 +24,6 @@
 #include "conversation.h"
 #include "debug.h"
 #include "log.h"
-#include "multi.h"
 #include "notify.h"
 #include "prefs.h"
 #include "prpl.h"
@@ -41,6 +40,7 @@
 #include "ui.h"
 
 #define SECS_BEFORE_RESENDING_AUTORESPONSE 600
+#define SEX_BEFORE_RESENDING_AUTORESPONSE "Only after you're married"
 
 static void add_idle_buddy(GaimBuddy *buddy);
 static void remove_idle_buddy(GaimBuddy *buddy);
@@ -286,15 +286,15 @@
 	return val;
 }
 
-void serv_get_info(GaimConnection *g, const char *name)
+void serv_get_info(GaimConnection *gc, const char *name)
 {
 	GaimPluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if (gc != NULL && gc->prpl != NULL)
+		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
 
-	if (g && prpl_info && prpl_info->get_info)
-		prpl_info->get_info(g, name);
+	if (gc && prpl_info && prpl_info->get_info)
+		prpl_info->get_info(gc, name);
 }
 
 void serv_set_away(GaimConnection *gc, const char *state, const char *message)
@@ -354,50 +354,50 @@
 	}
 }
 
-void serv_set_info(GaimConnection *g, const char *info)
+void serv_set_info(GaimConnection *gc, const char *info)
 {
 	GaimPluginProtocolInfo *prpl_info = NULL;
 	GaimAccount *account;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if (gc != NULL && gc->prpl != NULL)
+		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
 
-	if (prpl_info && g_list_find(gaim_connections_get_all(), g) &&
+	if (prpl_info && g_list_find(gaim_connections_get_all(), gc) &&
 		prpl_info->set_info) {
 
-		account = gaim_connection_get_account(g);
+		account = gaim_connection_get_account(gc);
 
 		if (gaim_signal_emit_return_1(gaim_accounts_get_handle(),
 									  "account-setting-info", account, info))
 			return;
 
-		prpl_info->set_info(g, info);
+		prpl_info->set_info(gc, info);
 
 		gaim_signal_emit(gaim_accounts_get_handle(),
 						 "account-set-info", account, info);
 	}
 }
 
-void serv_change_passwd(GaimConnection *g, const char *orig, const char *new)
+void serv_change_passwd(GaimConnection *gc, const char *orig, const char *new)
 {
 	GaimPluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if (gc != NULL && gc->prpl != NULL)
+		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
 
-	if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->change_passwd)
-		prpl_info->change_passwd(g, orig, new);
+	if (prpl_info && g_list_find(gaim_connections_get_all(), gc) && prpl_info->change_passwd)
+		prpl_info->change_passwd(gc, orig, new);
 }
 
-void serv_add_buddy(GaimConnection *g, const char *name, GaimGroup *group)
+void serv_add_buddy(GaimConnection *gc, GaimBuddy *buddy)
 {
 	GaimPluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if (gc != NULL && gc->prpl != NULL)
+		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
 
-	if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->add_buddy)
-		prpl_info->add_buddy(g, name, group);
+	if (prpl_info && g_list_find(gaim_connections_get_all(), gc) && prpl_info->add_buddy)
+		prpl_info->add_buddy(gc, buddy, gaim_find_buddys_group(buddy));
 }
 
 void serv_add_buddies(GaimConnection *gc, GList *buddies)
@@ -408,37 +408,77 @@
 		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
 
 	if (prpl_info && g_list_find(gaim_connections_get_all(), gc)) {
+		GList *cur, *groups = NULL;
+
+		/* Make a list of what the groups each buddy is in */
+		for (cur = buddies; cur != NULL; cur = cur->next) {
+			GaimBlistNode *node = cur->data;
+			groups = g_list_append(groups, node->parent);
+		}
+
 		if (prpl_info->add_buddies)
-			prpl_info->add_buddies(gc, buddies);
+			prpl_info->add_buddies(gc, buddies, groups);
 		else if (prpl_info->add_buddy) {
-			while (buddies) {
-				prpl_info->add_buddy(gc, buddies->data, NULL);
-				buddies = buddies->next;
+			GList *curb = buddies;
+			GList *curg = groups;
+			while ((curb != NULL) && (curg != NULL)) {
+				prpl_info->add_buddy(gc, curb->data, curg->data);
+				curb = curb->next;
+				curg = curg->next;
+			}
+		}
+
+		g_list_free(groups);
+	}
+}
+
+
+void serv_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
+{
+	GaimPluginProtocolInfo *prpl_info = NULL;
+
+	if (buddy->idle > 0)
+		remove_idle_buddy(buddy);
+
+	if (gc != NULL && gc->prpl != NULL)
+		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
+
+	if (prpl_info && g_list_find(gaim_connections_get_all(), gc) && prpl_info->remove_buddy)
+		prpl_info->remove_buddy(gc, buddy, group);
+}
+
+void serv_remove_buddies(GaimConnection *gc, GList *buddies, GList *groups)
+{
+	GaimPluginProtocolInfo *prpl_info = NULL;
+
+	if (!g_list_find(gaim_connections_get_all(), gc))
+		return;
+
+	if (gc != NULL && gc->prpl != NULL)
+		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
+
+	if (prpl_info && g_list_find(gaim_connections_get_all(), gc)) {
+		if (prpl_info->remove_buddies) {
+			GList *curb;
+			for (curb = buddies; curb != NULL; curb = curb->next) {
+				GaimBuddy *buddy = curb->data;
+				if (buddy->idle > 0)
+					remove_idle_buddy(buddy);
+			}
+			prpl_info->remove_buddies(gc, buddies, groups);
+		} else {
+			GList *curb = buddies;
+			GList *curg = groups;
+			while ((curb != NULL) && (curg != NULL)) {
+				serv_remove_buddy(gc, curb->data, curg->data);
+				curb = curb->next;
+				curg = curg->next;
 			}
 		}
 	}
 }
 
-
-void serv_remove_buddy(GaimConnection *g, const char *name, const char *group)
-{
-	GaimPluginProtocolInfo *prpl_info = NULL;
-	GaimBuddy *buddy;
-
-	buddy = gaim_find_buddy(gaim_connection_get_account(g), name);
-
-	if (buddy->idle > 0)
-		remove_idle_buddy(buddy);
-
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl);
-
-	if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->remove_buddy)
-		prpl_info->remove_buddy(g, name, group);
-}
-
-void
-serv_remove_group(GaimConnection *gc, const char *name)
+void serv_remove_group(GaimConnection *gc, GaimGroup *group)
 {
 	GaimPluginProtocolInfo *prpl_info = NULL;
 
@@ -448,30 +488,7 @@
 	if (prpl_info && g_list_find(gaim_connections_get_all(), gc) &&
 		prpl_info->remove_group)
 	{
-		prpl_info->remove_group(gc, name);
-	}
-}
-
-void serv_remove_buddies(GaimConnection *gc, GList *g, const char *group)
-{
-	GaimPluginProtocolInfo *prpl_info = NULL;
-
-	if (!g_list_find(gaim_connections_get_all(), gc))
-		return;
-
-	if (!gc->prpl)
-		return;		/* how the hell did that happen? */
-
-	if (gc != NULL && gc->prpl != NULL)
-		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
-
-	if (prpl_info->remove_buddies)
-		prpl_info->remove_buddies(gc, g, group);
-	else {
-		while (g) {
-			serv_remove_buddy(gc, g->data, group);
-			g = g->next;
-		}
+		prpl_info->remove_group(gc, group);
 	}
 }
 
@@ -524,7 +541,8 @@
  * Move a buddy from one group to another on server.
  *
  * Note: For now we'll not deal with changing gc's at the same time, but
- * it should be possible.  Probably needs to be done, someday.
+ * it should be possible.  Probably needs to be done, someday.  Although,
+ * the UI for that would be difficult, because groups are Gaim-wide.
  */
 void serv_move_buddy(GaimBuddy *b, GaimGroup *og, GaimGroup *ng)
 {
@@ -543,44 +561,32 @@
 /*
  * Rename a group on server roster/list.
  */
-void serv_rename_group(GaimConnection *g, GaimGroup *old_group,
-					   const char *new_name)
+void serv_rename_group(GaimConnection *gc, const char *old_name,
+					   GaimGroup *group, GList *moved_buddies)
 {
 	GaimPluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl);
-
-	if (prpl_info && old_group && new_name) {
-		GList *tobemoved = NULL;
-		GaimBlistNode *cnode, *bnode;
+	if (gc != NULL && gc->prpl != NULL)
+		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
 
-		for(cnode = ((GaimBlistNode*)old_group)->child; cnode; cnode = cnode->next) {
-			if(!GAIM_BLIST_NODE_IS_CONTACT(cnode))
-				continue;
-			for(bnode = cnode->child; bnode; bnode = bnode->next) {
-				GaimBuddy *b;
-				if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
-					continue;
-				b = (GaimBuddy*)bnode;
-
-				if(b->account == g->account)
-					tobemoved = g_list_append(tobemoved, b->name);
-
-			}
-
-		}
-
+	if (prpl_info && old_name && group && strcmp(old_name, group->name)) {
 		if (prpl_info->rename_group) {
 			/* prpl's might need to check if the group already
 			 * exists or not, and handle that differently */
-			prpl_info->rename_group(g, old_group->name, new_name, tobemoved);
+			prpl_info->rename_group(gc, old_name, group, moved_buddies);
 		} else {
-			serv_remove_buddies(g, tobemoved, old_group->name);
-			serv_add_buddies(g, tobemoved);
+			GList *cur, *groups = NULL;
+
+			/* Make a list of what the groups each buddy is in */
+			for (cur = moved_buddies; cur != NULL; cur = cur->next) {
+				GaimBlistNode *node = cur->data;
+				groups = g_list_append(groups, node->parent);
+			}
+
+			serv_remove_buddies(gc, moved_buddies, groups);
+			g_list_free(groups);
+			serv_add_buddies(gc, moved_buddies);
 		}
-
-		g_list_free(tobemoved);
 	}
 }
 
@@ -1148,7 +1154,6 @@
 	/* store things how THEY want it... */
 	if (strcmp(name, b->name)) {
 		gaim_blist_rename_buddy(b, name);
-		gaim_blist_save();
 	}
 
 	old_idle = b->idle;
--- a/src/server.h	Tue Jun 15 01:17:16 2004 +0000
+++ b/src/server.h	Tue Jun 15 02:37:27 2004 +0000
@@ -50,11 +50,13 @@
 void serv_set_away_all(const char *);
 int  serv_send_typing(GaimConnection *, const char *, int);
 void serv_change_passwd(GaimConnection *, const char *, const char *);
-void serv_add_buddy(GaimConnection *, const char *, GaimGroup *);
+void serv_add_buddy(GaimConnection *, GaimBuddy *);
 void serv_add_buddies(GaimConnection *, GList *);
-void serv_remove_buddy(GaimConnection *, const char *, const char *);
-void serv_remove_buddies(GaimConnection *, GList *, const char *);
-void serv_remove_group(GaimConnection *, const char *);
+void serv_remove_buddy(GaimConnection *, GaimBuddy *, GaimGroup *);
+void serv_remove_buddies(GaimConnection *, GList *, GList *);
+void serv_remove_group(GaimConnection *, GaimGroup *);
+void serv_move_buddy(GaimBuddy *, GaimGroup *, GaimGroup *);
+void serv_rename_group(GaimConnection *, const char *, GaimGroup *, GList *);
 void serv_add_permit(GaimConnection *, const char *);
 void serv_add_deny(GaimConnection *, const char *);
 void serv_rem_permit(GaimConnection *, const char *);
@@ -75,8 +77,6 @@
 int  serv_chat_send(GaimConnection *, int, const char *);
 void serv_alias_buddy(GaimBuddy *);
 void serv_got_alias(GaimConnection *gc, const char *who, const char *alias);
-void serv_move_buddy(GaimBuddy *, GaimGroup *, GaimGroup *);
-void serv_rename_group(GaimConnection *, GaimGroup *, const char *);
 void serv_got_eviled(GaimConnection *gc, const char *name, int lev);
 void serv_got_typing(GaimConnection *gc, const char *name, int timeout,
 					 GaimTypingState state);