changeset 4349:0c68d402f59f

[gaim-migrate @ 4614] XML Blist Gaim stores all the buddy lists in one big happy file now. You can order the buddies however you want, and they'll stay ordered that way. We can also store some per-buddy information now, which will be cool. committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Sun, 19 Jan 2003 22:16:52 +0000
parents 922b66840a51
children 7142f59bec2c
files plugins/ticker/ticker.c src/buddy.c src/buddy_chat.c src/conversation.c src/core.c src/core.h src/dialogs.c src/gaim.h src/gaimrc.c src/list.c src/multi.c src/multi.h src/perl.c src/protocols/gg/gg.c src/protocols/icq/gaim_icq.c src/protocols/irc/irc.c src/protocols/jabber/jabber.c src/protocols/msn/msn.c src/protocols/napster/napster.c src/protocols/oscar/oscar.c src/protocols/toc/toc.c src/protocols/yahoo/yahoo.c src/protocols/zephyr/zephyr.c src/prpl.c src/prpl.h src/server.c src/ui.h src/util.c
diffstat 28 files changed, 1269 insertions(+), 1232 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/ticker/ticker.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/plugins/ticker/ticker.c	Sun Jan 19 22:16:52 2003 +0000
@@ -332,37 +332,33 @@
 {
 	GdkPixmap *pm;
 	GdkBitmap *bm;
-	struct gaim_connection *gc;
 	struct group *g;
 	struct buddy *b;
-	GSList *gcons, *grps, *buds;
+	GSList *grps, *buds;
 	char **xpm;
-	
-	for( gcons = connections; gcons; gcons = gcons->next ) {
-		gc = (struct gaim_connection *)gcons->data;
-		for( grps = gc->groups; grps; grps = grps->next ) {
-			g = (struct group *)grps->data;
-			for( buds = g->members; buds; buds = buds->next ) {
-				b = (struct buddy *)buds->data;
-				if( b->present ) {
-					xpm = NULL;
-					if (gc->prpl->list_icon)
-						xpm = gc->prpl->list_icon(b->uc);
-					if (xpm == NULL)
-						xpm = (char **)no_icon_xpm;
-					pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm);
-					BuddyTickerAddUser( b->name, get_buddy_alias(b), pm, bm );
-					gdk_pixmap_unref(pm);
-					if (bm)
-						gdk_bitmap_unref(bm);
-				}
+
+	for( grps = groups; grps; grps = grps->next ) {
+		g = (struct group *)grps->data;
+		for( buds = g->members; buds; buds = buds->next ) {
+			b = (struct buddy *)buds->data;
+			if( b->present ) {
+				xpm = NULL;
+				if (b->user->gc->prpl->list_icon)
+					xpm = b->user->gc->prpl->list_icon(b->uc);
+				if (xpm == NULL)
+					xpm = (char **)no_icon_xpm;
+				pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm);
+				BuddyTickerAddUser( b->name, get_buddy_alias(b), pm, bm );
+				gdk_pixmap_unref(pm);
+				if (bm)
+					gdk_bitmap_unref(bm);
 			}
 		}
 	}
 }
 
 void signon_cb(struct gaim_connection *gc, char *who) {
-	struct buddy *b  = find_buddy(gc, who);
+	struct buddy *b  = find_buddy(gc->user, who);
 	char **xpm = NULL;
 	
 	GdkPixmap *pm;
@@ -393,7 +389,7 @@
 }
 
 void away_cb(struct gaim_connection *gc, char *who) {
-	struct buddy *b  = find_buddy(gc, who);
+	struct buddy *b  = find_buddy(gc->user, who);
 	char **xpm = NULL;
 	
 	GdkPixmap *pm;
--- a/src/buddy.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/buddy.c	Sun Jan 19 22:16:52 2003 +0000
@@ -118,9 +118,6 @@
 void handle_group_rename(struct group *g, char *prevname)
 {
 	struct group_show *gs, *new_gs;
-	struct buddy_show *bs;
-	struct buddy *b;
-	GSList *m;
 	GtkCTreeNode *c;
 
 	c = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, g);
@@ -134,93 +131,20 @@
 	if (new_gs) {
 		/* transfer everything that was in gs and is in the same gaim_conn as g
 		 * over to new_gs. */
-		m = gs->members;
-		while (m) {
-			bs = (struct buddy_show *)m->data;
-			if (g_slist_index(bs->connlist, g->gc) >= 0) {
-				b = find_buddy(g->gc, bs->name);
-				m = g_slist_next(m);
-				bs->connlist = g_slist_remove(bs->connlist, g->gc);
-				if (!bs->connlist) {
-					gs->members = g_slist_remove(gs->members, bs);
-					if (bs->log_timer > 0)
-						g_source_remove(bs->log_timer);
-					bs->log_timer = 0;
-					remove_buddy_show(gs, bs);
-					g_free(bs->name);
-					g_free(bs);
-				}
-				if ((bs = find_buddy_show(new_gs, b->name)) == NULL) {
-					if (g->gc->prpl->list_icon) {
-						bs = new_buddy_show(new_gs, b,
-								    g->gc->prpl->list_icon(b->uc));
-					} else {
-						bs = new_buddy_show(new_gs, b, (char **)no_icon_xpm);
-					}
-				}
-				bs->connlist = g_slist_append(bs->connlist, g->gc);
-			} else {
-				m = g_slist_next(m);
-			}
+		while (gs->members) {
+			new_gs->members = g_slist_append(new_gs->members, gs->members->data);
+			gs->members = g_slist_remove(gs->members, gs->members->data);
+
 		}
-		if (!gs->members) {
-			/* we just transferred all of the members out of this group_show,
-			 * so this group_show serves no purpose now. */
-			shows = g_slist_remove(shows, gs);
-			gtk_tree_remove_item(GTK_TREE(buddies), gs->item);
-			g_free(gs->name);
-			g_free(gs);
-		} else {
-			update_num_group(gs);
-		}
+		shows = g_slist_remove(shows, gs);
+		gtk_tree_remove_item(GTK_TREE(buddies), gs->item);
+		g_free(gs->name);
+		g_free(gs);
 		update_num_group(new_gs);
 	} else {
-		/* two possible actions: if gs contains things that are only from g,
-		 * just rename gs and fix the label. otherwise, move everything in g
-		 * over to another group_show */
-		for (m = gs->members; m != NULL; m = g_slist_next(m)) {
-			bs = (struct buddy_show *)m->data;
-			if (g_slist_index(bs->connlist, g->gc) < 0 || g_slist_length(bs->connlist) > 1) {
-				break;
-			}
-		}
-		if (m) {
-			/* there's something from a different gaim_connection. */
-			new_gs = new_group_show(g->name);
-			m = gs->members;
-			while (m) {
-				bs = (struct buddy_show *)m->data;
-				if (g_slist_index(bs->connlist, g->gc) >= 0) {
-					b = find_buddy(g->gc, bs->name);
-					m = g_slist_next(m);
-					bs->connlist = g_slist_remove(bs->connlist, g->gc);
-					if (!bs->connlist) {
-						gs->members = g_slist_remove(gs->members, bs);
-						if (bs->log_timer > 0)
-							g_source_remove(bs->log_timer);
-						bs->log_timer = 0;
-						remove_buddy_show(gs, bs);
-						g_free(bs->name);
-						g_free(bs);
-					}
-					if (g->gc->prpl->list_icon) {
-						bs = new_buddy_show(new_gs, b,
-								    g->gc->prpl->list_icon(b->uc));
-					} else {
-						bs = new_buddy_show(new_gs, b, (char **)no_icon_xpm);
-					}
-					bs->connlist = g_slist_append(NULL, g->gc);
-				} else {
-					m = g_slist_next(m);
-				}
-			}
-			update_num_group(gs);
-			update_num_group(new_gs);
-		} else {
-			g_free(gs->name);
-			gs->name = g_strdup(g->name);
-			update_num_group(gs);
-		}
+		g_free(gs->name);
+		gs->name = g_strdup(g->name);
+		update_num_group(gs);
 	}
 }
 
@@ -243,7 +167,7 @@
 	if ((cnv = find_conversation(b->name)) != NULL)
 		set_convo_title(cnv);
 
-	g = find_group_by_buddy(b->gc, b->name);
+	g = find_group_by_buddy(b);
 	if (!g) {
 		/* shouldn't happen */
 		return;
@@ -259,7 +183,7 @@
 	}
 
 	if (g_strcasecmp(b->name, prevname)) {
-		bs->connlist = g_slist_remove(bs->connlist, b->gc);
+		bs->connlist = g_slist_remove(bs->connlist, b->user->gc);
 		if (!bs->connlist) {
 			gs->members = g_slist_remove(gs->members, bs);
 			if (bs->log_timer > 0)
@@ -383,23 +307,14 @@
 
 	} else {
 		/* put back all groups */
-		GSList *c = connections;
-		struct gaim_connection *gc;
-		GSList *m;
-		struct group *g;
-
-		while (c) {
-			gc = (struct gaim_connection *)c->data;
-			m = gc->groups;
-			while (m) {
-				g = (struct group *)m->data;
-				m = g_slist_next(m);
-				if (!find_group_show(g->name))
-					new_group_show(g->name);
-			}
-			c = g_slist_next(c);
+		GSList *m = groups;
+
+		while (m) {
+			struct group *g = (struct group *)m->data;
+			if (!find_group_show(g->name) && gaim_group_on_account(g, NULL))
+				new_group_show(g->name);
+			m = g_slist_next(m);
 		}
-
 	}
 }
 
@@ -428,9 +343,8 @@
 static void update_num_group(struct group_show *gs)
 {
 	GSList *c = connections;
-	struct gaim_connection *gc;
-	struct group *g;
-	struct buddy_show *b;
+	struct group *g = find_group(gs->name);
+	struct buddy *b;
 	int total = 0, on = 0;
 	char buf[256];
 
@@ -438,21 +352,15 @@
 		debug_printf("update_num_group called for unfound group_show %s\n", gs->name);
 		return;
 	}
-
-	while (c) {
-		gc = (struct gaim_connection *)c->data;
-		g = find_group(gc, gs->name);
-		if (g) {
-			total += g_slist_length(g->members);
+	if (g) {
+		for (c = g->members; c; c = c->next) {
+			b = c->data;
+			if(b->user->gc) {
+				if(b->present)
+					on++;
+				total++;
+			}
 		}
-		c = g_slist_next(c);
-	}
-
-	c = gs->members;
-	while (c) {
-		b = (struct buddy_show *)c->data;
-		on += g_slist_length(b->connlist);
-		c = g_slist_next(c);
 	}
 
 	if (blist_options & OPT_BLIST_SHOW_GRPNUM)
@@ -537,7 +445,7 @@
 	} else {
 		c = new_conversation(b->name);
 
-		set_convo_gc(c, b->gc);
+		set_convo_gc(c, b->user->gc);
 	}
 }
 
@@ -568,7 +476,8 @@
 
 void pressed_alias_bs(GtkWidget *widget, struct buddy_show *bs)
 {
-	alias_dialog_bud(find_buddy(bs->connlist->data, bs->name));
+	struct gaim_connection *gc = bs->connlist->data;
+	alias_dialog_bud(find_buddy(gc->user, bs->name));
 }
 
 void pressed_alias_bud(GtkWidget *widget, struct buddy *b)
@@ -740,7 +649,7 @@
 	b->alias[0] = '\0';
 	handle_buddy_rename(b, b->name); /* make me a sammich! */
 	serv_alias_buddy(b);
-	do_export(b->gc);
+	gaim_blist_save();
 }
 
 static gboolean click_edit_tree(GtkWidget *widget, GdkEventButton *event, gpointer data)
@@ -831,8 +740,8 @@
 		/*
 		 * Add protocol-specific edit buddy menu items if they exist
 		 */
-		if (b->gc->prpl->edit_buddy_menu) {
-			GList *mo = mo_top = b->gc->prpl->edit_buddy_menu(b->gc, b->name);
+		if (b->user->gc && b->user->gc->prpl->edit_buddy_menu) {
+			GList *mo = mo_top = b->user->gc->prpl->edit_buddy_menu(b->user->gc, b->name);
 
 			while (mo) {
 				struct proto_buddy_menu *pbm = mo->data;
@@ -872,9 +781,10 @@
 	}
 }
 
-void ui_remove_buddy(struct gaim_connection *gc, struct group *rem_g, struct buddy *rem_b)
+void ui_remove_buddy(struct buddy *rem_b)
 {
 	struct conversation *c;
+	struct group *rem_g = find_group_by_buddy(rem_b);
 	struct group_show *gs;
 	struct buddy_show *bs;
 
@@ -882,8 +792,8 @@
 	if (gs) {
 		bs = find_buddy_show(gs, rem_b->name);
 		if (bs) {
-			if (g_slist_find(bs->connlist, gc)) {
-				bs->connlist = g_slist_remove(bs->connlist, gc);
+			if (g_slist_find(bs->connlist, rem_b->user->gc)) {
+				bs->connlist = g_slist_remove(bs->connlist, rem_b->user->gc);
 				if (!g_slist_length(bs->connlist)) {
 					gs->members = g_slist_remove(gs->members, bs);
 					if (bs->log_timer > 0)
@@ -892,8 +802,9 @@
 					remove_buddy_show(gs, bs);
 					g_free(bs->name);
 					g_free(bs);
-					if (!g_slist_length(gs->members) &&
-					    (blist_options & OPT_BLIST_NO_MT_GRP)) {
+					if ((!g_slist_length(gs->members) &&
+					    (blist_options & OPT_BLIST_NO_MT_GRP)) ||
+							gaim_group_on_account(rem_g, NULL)) {
 						shows = g_slist_remove(shows, gs);
 						gtk_tree_remove_item(GTK_TREE(buddies), gs->item);
 						g_free(gs->name);
@@ -916,9 +827,12 @@
 
 }
 
-void ui_remove_group(struct gaim_connection *gc, struct group *rem_g)
+void ui_remove_group(struct group *rem_g)
 {
 	struct group_show *gs;
+	GtkCTreeNode *gnode = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, rem_g);
+	gtk_ctree_remove_node(GTK_CTREE(edittree), gnode);
+
 
 	if ((gs = find_group_show(rem_g->name)) != NULL) {
 		shows = g_slist_remove(shows, gs);
@@ -935,7 +849,7 @@
 
 	type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), source_node);
 
-	if (*type == EDIT_GC) {
+	if (*type == EDIT_GROUP) {
 		if (!new_parent)
 			return TRUE;
 	} else if (*type == EDIT_BUDDY) {
@@ -944,14 +858,6 @@
 			if (*type == EDIT_GROUP)
 				return TRUE;
 		}
-	} else {		/* group */
-
-		if (g_slist_length(connections) > 1 && new_parent) {
-			type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), new_parent);
-			if (*type == EDIT_GC)
-				return TRUE;
-		} else if (g_slist_length(connections) == 1 && !new_parent)
-			return TRUE;
 	}
 
 	return FALSE;
@@ -976,8 +882,6 @@
 	struct group_show *gs;
 	GSList *m;
 	struct buddy_show *bs;
-	GSList *c = connections;
-	struct gaim_connection *gc;
 	GSList *gr;
 	struct group *g;
 	struct buddy *b;
@@ -1002,35 +906,32 @@
 		g_free(gs);
 	}
 	shows = NULL;
-	while (c) {
-		gc = (struct gaim_connection *)c->data;
-		c = c->next;
-		gr = gc->groups;
-		while (gr) {
-			g = (struct group *)gr->data;
-			gr = gr->next;
-			gs = find_group_show(g->name);
-			if (!gs && !(blist_options & OPT_BLIST_NO_MT_GRP))
-				gs = new_group_show(g->name);
-			m = g->members;
-			while (m) {
-				b = (struct buddy *)m->data;
-				m = m->next;
-				if (b->present) {
-					if (!gs)
-						gs = new_group_show(g->name);
-					bs = find_buddy_show(gs, b->name);
-					if (!bs) {
-						if (gc->prpl->list_icon)
-							bs = new_buddy_show(gs, b,
-									    gc->prpl->list_icon(b->
-												   uc));
-						else
-							bs = new_buddy_show(gs, b, (char **)no_icon_xpm);
-					}
-					bs->connlist = g_slist_append(bs->connlist, gc);
-					update_num_group(gs);
+	gr = groups;
+	while (gr) {
+		g = (struct group *)gr->data;
+		gr = gr->next;
+		gs = find_group_show(g->name);
+		if (!gs && !(blist_options & OPT_BLIST_NO_MT_GRP)
+				&& gaim_group_on_account(g, NULL))
+			gs = new_group_show(g->name);
+		m = g->members;
+		while (m) {
+			b = (struct buddy *)m->data;
+			m = m->next;
+			if (b->present) {
+				if (!gs)
+					gs = new_group_show(g->name);
+				bs = find_buddy_show(gs, b->name);
+				if (!bs) {
+					if (b->user->gc->prpl->list_icon)
+						bs = new_buddy_show(gs, b,
+								b->user->gc->prpl->list_icon(b->
+									uc));
+					else
+						bs = new_buddy_show(gs, b, (char **)no_icon_xpm);
 				}
+				bs->connlist = g_slist_append(bs->connlist, b->user->gc);
+				update_num_group(gs);
 			}
 		}
 	}
@@ -1040,7 +941,6 @@
 static void edit_tree_move(GtkCTree *ctree, GtkCTreeNode *child, GtkCTreeNode *parent,
 			   GtkCTreeNode *sibling, gpointer data)
 {
-	struct gaim_connection *gc, *pc = NULL, *sc = NULL;
 	int *ctype, *ptype = NULL, *stype = NULL;
 
 	ctype = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), child);
@@ -1051,55 +951,18 @@
 	if (sibling)
 		stype = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), sibling);
 
-	if (*ctype == EDIT_GC) {
-		/* not that it particularly matters which order the connections
-		 * are in, but just for debugging sake, i guess.... */
-		gc = (struct gaim_connection *)ctype;
-		connections = g_slist_remove(connections, gc);
-		if (sibling) {
-			int pos;
-			sc = (struct gaim_connection *)stype;
-			pos = g_slist_index(connections, sc);
-			if (pos)
-				connections = g_slist_insert(connections, gc, pos);
-			else
-				connections = g_slist_prepend(connections, gc);
-		} else
-			connections = g_slist_append(connections, gc);
-		redo_convo_menus(); /* this is evil */
-	} else if (*ctype == EDIT_BUDDY) {
+	if (*ctype == EDIT_BUDDY) {
 		/* we moved a buddy. hopefully we just changed groups or positions or something.
 		 * if we changed connections, we copy the buddy to the new connection. if the new
 		 * connection already had the buddy in its buddy list but in a different group,
 		 * we change the group that the buddy is in */
 		struct group *old_g, *new_g = (struct group *)ptype;
 		struct buddy *s = NULL, *buddy = (struct buddy *)ctype;
-		gboolean add = FALSE;
 		int pos;
 
-		if (buddy->gc != new_g->gc) {
-			/* we changed connections */
-			struct buddy *a;
-
-			a = find_buddy(new_g->gc, buddy->name);
-
-			if (a) {
-				/* the buddy is in the new connection, so we'll remove it from
-				 * its current group and add it to the proper group below */
-				struct group *og;
-				og = find_group_by_buddy(new_g->gc, buddy->name);
-				og->members = g_slist_remove(og->members, a);
-			} else {
-				/* we don't have this buddy yet; let's add him */
-				add = TRUE;
-			}
-		}
-
-		old_g = find_group_by_buddy(buddy->gc, buddy->name);
-
-		if (buddy->gc == new_g->gc)
-			/* this is the same connection, so we'll remove it from its old group */
-			old_g->members = g_slist_remove(old_g->members, buddy);
+		old_g = find_group_by_buddy(buddy);
+
+		old_g->members = g_slist_remove(old_g->members, buddy);
 
 		if (sibling) {
 			s = (struct buddy *)stype;
@@ -1111,21 +974,9 @@
 		} else
 			new_g->members = g_slist_append(new_g->members, buddy);
 
-		/*
-		 * we do the add after it's added locally so that prpls can find it if necessary
-		 * JFIXME: Er, shouldn't the buddy be removed from the old server, as well?
-		 */
-		if (add) {
-			serv_add_buddy(new_g->gc, buddy->name);
-		} else {
-			serv_move_buddy(buddy, old_g, new_g);
-		}
-
-		do_export(buddy->gc);
-		if (buddy->gc != new_g->gc) {
-			do_export(new_g->gc);
-			build_edit_tree();
-		}
+		serv_move_buddy(buddy, old_g, new_g);
+
+		gaim_blist_save();
 	} else {		/* group */
 
 		/* move the group. if moving connections, copy the group, and each buddy in the
@@ -1134,57 +985,23 @@
 		struct group *g, *g2, *group;
 		int pos;
 
-		pc = (struct gaim_connection *)ptype;
 		group = (struct group *)ctype;
 
-		if (g_slist_length(connections) > 1) {
-			g = find_group(pc, group->name);
-			if (!g)
-				g = add_group(pc, group->name);
-
-			pc->groups = g_slist_remove(pc->groups, g);
-
-			if (sibling) {
-				g2 = (struct group *)stype;
-				pos = g_slist_index(pc->groups, g2);
-				if (pos)
-					pc->groups = g_slist_insert(pc->groups, g, pos);
-				else
-					pc->groups = g_slist_prepend(pc->groups, g);
-			} else
-				pc->groups = g_slist_append(pc->groups, g);
-
-			if (pc != group->gc) {
-				GSList *mem;
-				struct buddy *b;
-				g2 = group;
-
-				mem = g2->members;
-				while (mem) {
-					b = (struct buddy *)mem->data;
-					if (!find_buddy(pc, b->name))
-						add_buddy(pc, g->name, b->name, b->alias);
-					mem = mem->next;
-				}
-			}
-			do_export(pc);
-		} else {
-			g = group;
-			gc = g->gc;
-
-			gc->groups = g_slist_remove(gc->groups, g);
-
-			if (sibling) {
-				g2 = (struct group *)stype;
-				pos = g_slist_index(gc->groups, g2);
-				if (pos)
-					gc->groups = g_slist_insert(gc->groups, g, pos);
-				else
-					gc->groups = g_slist_prepend(gc->groups, g);
-			} else
-				gc->groups = g_slist_append(gc->groups, g);
-			do_export(gc);
-		}
+		g = group;
+
+		groups = g_slist_remove(groups, g);
+
+		if (sibling) {
+			g2 = (struct group *)stype;
+			pos = g_slist_index(groups, g2);
+			if (pos)
+				groups = g_slist_insert(groups, g, pos);
+			else
+				groups = g_slist_prepend(groups, g);
+		} else
+			groups = g_slist_append(groups, g);
+
+		gaim_blist_save();
 	}
 
 	redo_buddy_list();
@@ -1225,11 +1042,9 @@
 
 void build_edit_tree()
 {
-	GtkCTreeNode *c = NULL, *p = NULL, *n;
-	GSList *con = connections;
+	GtkCTreeNode *p = NULL, *n;
 	GSList *grp;
 	GSList *mem;
-	struct gaim_connection *z;
 	struct group *g;
 	struct buddy *b;
 	char *text[1];
@@ -1241,47 +1056,27 @@
 	gtk_clist_clear(GTK_CLIST(edittree));
 
 
-	while (con) {
-		z = (struct gaim_connection *)con->data;
-
-		if (g_slist_length(connections) > 1) {
-			GdkPixmap *pixmap;
-			GdkBitmap *mask;
-
-			text[0] = z->username;
-
-			create_prpl_icon(blist, z, &pixmap, &mask);
-
-			c = gtk_ctree_insert_node(GTK_CTREE(edittree), NULL,
-						  NULL, text, 3, pixmap, mask, pixmap, mask, 0, 1);
-
-			gdk_pixmap_unref (pixmap);
-			gdk_bitmap_unref (mask);
-
-			gtk_ctree_node_set_row_data(GTK_CTREE(edittree), c, z);
-		} else
-			c = NULL;
-
-		grp = z->groups;
-
-		while (grp) {
-			
-			g = (struct group *)grp->data;
-
-			text[0] = g->name;
-
-			p = gtk_ctree_insert_node(GTK_CTREE(edittree), c,
-						  NULL, text, 5, NULL, NULL, NULL, NULL, 0, 1);
-
-			gtk_ctree_node_set_row_data(GTK_CTREE(edittree), p, g);
-
-			n = NULL;
-
-			mem = g->members;
-
-			while (mem) {
-				char buf[256];
-				b = (struct buddy *)mem->data;
+	grp = groups;
+
+	while (grp) {
+
+		g = (struct group *)grp->data;
+
+		text[0] = g->name;
+
+		p = gtk_ctree_insert_node(GTK_CTREE(edittree), NULL,
+				NULL, text, 5, NULL, NULL, NULL, NULL, 0, 1);
+
+		gtk_ctree_node_set_row_data(GTK_CTREE(edittree), p, g);
+
+		n = NULL;
+
+		mem = g->members;
+
+		while (mem) {
+			char buf[256];
+			b = (struct buddy *)mem->data;
+			if(b->user->gc) {
 				if (get_buddy_alias_only(b)) {
 					g_snprintf(buf, sizeof(buf), "%s (%s)", b->name, get_buddy_alias(b));
 					text[0] = buf;
@@ -1289,17 +1084,15 @@
 					text[0] = b->name;
 
 				n = gtk_ctree_insert_node(GTK_CTREE(edittree),
-							  p, NULL, text, 5,
-							  NULL, NULL, NULL, NULL, 1, 1);
+						p, NULL, text, 5,
+						NULL, NULL, NULL, NULL, 1, 1);
 
 				gtk_ctree_node_set_row_data(GTK_CTREE(edittree), n, b);
-
-				mem = mem->next;
-
 			}
-			grp = g_slist_next(grp);
+
+			mem = mem->next;
 		}
-		con = g_slist_next(con);
+		grp = g_slist_next(grp);
 	}
 
 	gtk_clist_thaw(GTK_CLIST(edittree));
@@ -1321,6 +1114,9 @@
 	if (!blist)
 		return;
 
+	if(!b->user->gc)
+		return;
+
 	p = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, g);
 	if (get_buddy_alias_only(b)) {
 		g_snprintf(buf, sizeof(buf), "%s (%s)", b->name, get_buddy_alias(b));
@@ -1332,9 +1128,9 @@
 	gtk_ctree_node_set_row_data(GTK_CTREE(edittree), n, b);
 }
 
-void ui_add_group(struct gaim_connection *gc, struct group *g)
+void ui_add_group(struct group *g)
 {
-	GtkCTreeNode *c = NULL, *p;
+	GtkCTreeNode *p;
 	char *text[1];
 
 	g->edittype = EDIT_GROUP;
@@ -1342,12 +1138,12 @@
 	if (!blist)
 		return;
 
-	c = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, gc);
 	text[0] = g->name;
-	p = gtk_ctree_insert_node(GTK_CTREE(edittree), c, NULL, text, 5, NULL, NULL, NULL, NULL, 0, 1);
+	p = gtk_ctree_insert_node(GTK_CTREE(edittree), NULL, NULL, text, 5, NULL, NULL, NULL, NULL, 0, 1);
 	gtk_ctree_node_set_row_data(GTK_CTREE(edittree), p, g);
 
-	if (!(blist_options & OPT_BLIST_NO_MT_GRP) && !find_group_show(g->name))
+	if (!(blist_options & OPT_BLIST_NO_MT_GRP) && !find_group_show(g->name)
+			&& gaim_group_on_account(g, NULL))
 		new_group_show(g->name);
 }
 
@@ -1366,18 +1162,14 @@
 		type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node);
 
 		if (*type == EDIT_BUDDY) {
-			struct gaim_connection *gct;
 			b = (struct buddy *)type;
-			g = find_group_by_buddy(b->gc, b->name);
-			gct = b->gc;
-			serv_remove_buddy(b->gc, b->name, g->name);
-			remove_buddy(b->gc, g, b);
-			do_export(gct);
+			g = find_group_by_buddy(b);
+			serv_remove_buddy(b->user->gc, b->name, g->name);
+			remove_buddy(b);
+			gaim_blist_save();
 		} else if (*type == EDIT_GROUP) {
-			struct gaim_connection *gc = ((struct group *)type)->gc;
-			remove_group(gc, (struct group *)type);
-			gtk_ctree_remove_node(GTK_CTREE(edittree), node);
-			do_export(gc);
+			remove_group((struct group *)type);
+			gaim_blist_save();
 		}
 
 	} else {
@@ -1406,13 +1198,16 @@
 
 		if (*type == EDIT_BUDDY) {
 			struct buddy *b = (struct buddy *)type;
-			struct group *g = find_group_by_buddy(b->gc, b->name);
+			struct group *g = find_group_by_buddy(b);
 			grp = g->name;
-			gc = b->gc;
+			gc = b->user->gc;
 		} else if (*type == EDIT_GROUP) {
 			struct group *g = (struct group *)type;
 			grp = g->name;
-			gc = g->gc;
+			if(g->members)
+				gc = ((struct buddy *)g->members->data)->user->gc;
+			else
+				gc = connections->data;
 		} else {
 			gc = (struct gaim_connection *)type;
 		}
@@ -1433,9 +1228,9 @@
 		node = i->data;
 		type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node);
 		if (*type == EDIT_BUDDY)
-			gc = ((struct buddy *)type)->gc;
+			gc = ((struct buddy *)type)->user->gc;
 		else if (*type == EDIT_GROUP)
-			gc = ((struct group *)type)->gc;
+			gc = connections->data;
 		else
 			gc = (struct gaim_connection *)type;
 	}
@@ -1627,7 +1422,7 @@
 static void new_bp_callback(GtkWidget *w, struct buddy *b)
 {
 	if (b)
-		show_new_bp(b->name, b->gc, b->idle, b->uc & UC_UNAVAILABLE, NULL);
+		show_new_bp(b->name, b->user->gc, b->idle, b->uc & UC_UNAVAILABLE, NULL);
 	else
 		show_new_bp(NULL, NULL, 0, 0, NULL);
 }
@@ -1758,24 +1553,18 @@
 
 static int group_number(char *group)
 {
-	GSList *c = connections;
-	struct gaim_connection *g;
 	GSList *m;
 	struct group *p;
 	int pos = 0;
 
-	while (c) {
-		g = (struct gaim_connection *)c->data;
-		m = g->groups;
-		while (m) {
-			p = (struct group *)m->data;
-			if (!strcmp(p->name, group))
-				return pos;
-			if (find_group_show(p->name))
-				pos++;
-			m = m->next;
-		}
-		c = c->next;
+	m = groups;
+	while (m) {
+		p = (struct group *)m->data;
+		if (!strcmp(p->name, group))
+			return pos;
+		if (find_group_show(p->name))
+			pos++;
+		m = m->next;
 	}
 	/* um..... we'll never get here */
 	return -1;
@@ -1783,38 +1572,38 @@
 
 static int buddy_number(char *group, char *buddy)
 {
-	GSList *c = connections;
-	struct gaim_connection *g;
 	struct group *p;
 	GSList *z;
 	struct buddy *b;
 	int pos = 0;
 	char *tmp1 = g_strdup(normalize (buddy));
 	struct group_show *gs = find_group_show(group);
-
-	while (c) {
-		g = (struct gaim_connection *)c->data;
-		p = find_group(g, group);
-		if (!p) {
-			c = c->next;
-			continue;
-		}
+	struct buddy_show *bs;
+	GSList *seen = NULL;
+
+	p = find_group(group);
+	if(p) {
 		z = p->members;
 		while (z) {
 			b = (struct buddy *)z->data;
 			if (!strcmp(tmp1, normalize (b->name))) {
 				g_free(tmp1);
+				g_slist_free(seen);
 				return pos;
 			}
-			if (find_buddy_show(gs, b->name))
-				pos++;
+			if ((bs = find_buddy_show(gs, b->name))) {
+				if(!g_slist_find(seen, bs)) {
+					seen = g_slist_append(seen, bs);
+					pos++;
+				}
+			}
 			z = z->next;
 		}
-		c = c->next;
 	}
 	/* we shouldn't ever get here */
 	debug_printf("got to bad place in buddy_number\n");
 	g_free(tmp1);
+	g_slist_free(seen);
 	return -1;
 }
 
@@ -2123,10 +1912,10 @@
 		GdkPixmap *pm;
 		GdkBitmap *bm;
 		gchar **xpm = NULL;
-		struct buddy *light = find_buddy(b->connlist->data, b->name);
-		if (((struct gaim_connection *)b->connlist->data)->prpl->list_icon)
-			xpm =
-			    (*((struct gaim_connection *)b->connlist->data)->prpl->list_icon)(light->uc);
+		struct gaim_connection *gc = b->connlist->data;
+		struct buddy *light = find_buddy(gc->user, b->name);
+		if (gc->prpl->list_icon)
+			xpm = gc->prpl->list_icon(light->uc);
 		if (xpm == NULL)
 			xpm = (char **)no_icon_xpm;
 		pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm);
@@ -2233,12 +2022,15 @@
 	char serv_alias[512];
 	char *sotime = NULL, *itime;
 
+	struct gaim_connection *gc;
+
 	int i;
 
 	time(&t);
 	if (!bs->connlist)
 		return;
-	b = find_buddy(bs->connlist->data, bs->name);
+	gc = bs->connlist->data;
+	b = find_buddy(gc->user, bs->name);
 	if (!b)
 		return;
 	ihrs = (t - b->idle) / 3600;
@@ -2348,7 +2140,7 @@
 
 void set_buddy(struct gaim_connection *gc, struct buddy *b)
 {
-	struct group *g = find_group_by_buddy(gc, b->name);
+	struct group *g = find_group_by_buddy(b);
 	struct group_show *gs;
 	struct buddy_show *bs;
 	GdkPixmap *pm;
--- a/src/buddy_chat.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/buddy_chat.c	Sun Jan 19 22:16:52 2003 +0000
@@ -354,7 +354,7 @@
 	tmp = g_list_append(tmp, "");
 
 	if (gc) {
-		grp = gc->groups;
+		grp = groups;
 
 		while (grp) {
 			g = (struct group *)grp->data;
@@ -364,7 +364,7 @@
 			while (bl) {
 				buddy = (struct buddy *)bl->data;
 
-				if (buddy->present)
+				if (buddy->user->gc == gc && buddy->present)
 					tmp = g_list_append(tmp, buddy->name);
 
 				bl = g_slist_next(bl);
@@ -806,7 +806,7 @@
 static void chat_press_add(GtkObject *obj, struct conversation *c)
 {
 	char *name = gtk_object_get_user_data(obj);
-	struct buddy *b = find_buddy(c->gc, name);
+	struct buddy *b = find_buddy(c->gc->user, name);
 
 	if (b) {
 		show_confirm_del(c->gc, name);
@@ -896,7 +896,7 @@
 
 		/* Added by Jonas <jonas@birme.se> */
 		if (b->gc) {
-			if (find_buddy(b->gc, who))
+			if (find_buddy(b->gc->user, who))
 				button = gtk_menu_item_new_with_label(_("Remove"));
 			else
 				button = gtk_menu_item_new_with_label(_("Add"));
@@ -1582,7 +1582,7 @@
 		gtk_box_pack_end(GTK_BOX(parent), c->sep2, FALSE, TRUE, 0);
 		gtk_widget_show(c->sep2);
 
-		if (find_buddy(c->gc, c->name) == NULL)
+		if (find_buddy(c->gc->user, c->name) == NULL)
 			c->add = change_text(c->window, _("Add"), c->add, "gtk-add", opt);
 		else
 			c->add = change_text(c->window, _("Remove"), c->add, "gtk-remove", opt);
--- a/src/conversation.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/conversation.c	Sun Jan 19 22:16:52 2003 +0000
@@ -504,7 +504,7 @@
 
 void add_callback(GtkWidget *widget, struct conversation *c)
 {
-	struct buddy *b = find_buddy(c->gc, c->name);
+	struct buddy *b = find_buddy(c->gc->user, c->name);
 	if (b) {
 		show_confirm_del(c->gc, c->name);
 	} else if (c->gc)
@@ -1632,7 +1632,7 @@
 	if (!c->is_chat || !(c->gc->prpl->options & OPT_PROTO_UNIQUE_CHATNAME)) {
 		if (!who) {
 			if (flags & WFLAG_SEND) {
-				b = find_buddy(c->gc, c->gc->username);
+				b = find_buddy(c->gc->user, c->gc->username);
 				if (get_buddy_alias_only(b))
 					 who = get_buddy_alias(b);
 				else if (c->gc->user->alias[0])
@@ -1642,14 +1642,14 @@
 				else
 					who = c->gc->username;
 			} else {
-				b = find_buddy(c->gc, c->name);
+				b = find_buddy(c->gc->user, c->name);
 				if (b)
 					who = get_buddy_alias(b);
 				else
 					who = c->name;
 			}
 		} else {
-			b = find_buddy(c->gc, who);
+			b = find_buddy(c->gc->user, who);
 			if (b)
 				who = get_buddy_alias(b);
 		}
@@ -2179,7 +2179,7 @@
 	GtkWidget *parent = c->add->parent;
 	gboolean rebuild = FALSE;
 
-	if (find_buddy(c->gc, c->name)) {
+	if (find_buddy(c->gc->user, c->name)) {
 		if (!gtk_object_get_user_data(GTK_OBJECT(c->add))) {
 			gtk_widget_destroy(c->add);
 			c->add = gaim_pixbuf_button_from_stock(dispstyle == 0 ? NULL : _("Remove"),
@@ -2780,7 +2780,7 @@
 	
 	/* And put the other buttons on the left */
 
-	if (c->gc && find_buddy(c->gc, c->name) != NULL) {
+	if (c->gc && find_buddy(c->gc->user, c->name) != NULL) {
 		add = gaim_pixbuf_button_from_stock(
 				(dispstyle == 0 ? NULL : _("Remove")),
 				(dispstyle == 1 ? NULL : "gtk-remove"),
@@ -3110,7 +3110,7 @@
 	int index;
 	GtkNotebook *nb;
 
-	if ((im_options & OPT_IM_ALIAS_TAB) && c->gc && ((b = find_buddy(c->gc, c->name)) != NULL))
+	if ((im_options & OPT_IM_ALIAS_TAB) && c->gc && ((b = find_buddy(c->gc->user, c->name)) != NULL))
 		text = get_buddy_alias(b);
 	else
 		text = c->name;
--- a/src/core.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/core.c	Sun Jan 19 22:16:52 2003 +0000
@@ -56,6 +56,7 @@
 #endif
 int gaim_session = 0;
 GSList *uis = NULL;
+GSList *groups = NULL;
 
 static guchar *UI_build(guint32 *len, guchar type, guchar subtype, va_list args)
 {
@@ -490,6 +491,8 @@
 	g_main_run(loop);
 	 */
 
+	gaim_blist_load();
+
 	return 0;
 }
 
--- a/src/core.h	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/core.h	Sun Jan 19 22:16:52 2003 +0000
@@ -66,8 +66,12 @@
 
 	struct gaim_connection *gc;
 	gboolean connecting;
+
+	GSList *permit;
+	GSList *deny;
+	int permdeny;
 };
-	
+
 enum gaim_event {
 	event_signon = 0,
 	event_signoff,
@@ -158,18 +162,19 @@
         int uc;
 	guint caps; /* woohoo! */
 	void *proto_data; /* what a hack */
-	struct gaim_connection *gc; /* the connection it belongs to */
+	struct aim_user *user; /* the connection it belongs to */
+	GHashTable *settings;
 };
 
 struct group {
 	int edittype; /* XXX CUI: this is really a GUI function and we need to put this in ui.h */
 	char name[80];
 	GSList *members;
-	struct gaim_connection *gc; /* the connection it belongs to */
 };
 
 /* Globals in core.c */
 extern GSList *uis;
+extern GSList *groups;
 extern int gaim_session;
 
 /* Globals in plugins.c */
@@ -178,21 +183,30 @@
 extern GList *callbacks;
 
 /* Functions in buddy.c */
-extern struct buddy *find_buddy(struct gaim_connection *, const char *);
-extern struct group *find_group(struct gaim_connection *, const char *);
-extern struct group *find_group_by_buddy(struct gaim_connection *, const char *);
-extern struct buddy *add_buddy(struct gaim_connection *, const char *, const char *, const char *);
-extern void remove_buddy(struct gaim_connection *, struct group *, struct buddy *);
-extern struct group *add_group(struct gaim_connection *, const char *);
-extern void remove_group(struct gaim_connection *, struct group *);
-extern void do_export(struct gaim_connection *);
-extern void do_import(struct gaim_connection *, const char *);
-extern int bud_list_cache_exists(struct gaim_connection *);
-extern void toc_build_config(struct gaim_connection *, char *, int len, gboolean);
-extern void parse_toc_buddy_list(struct gaim_connection *, char *);
+extern struct buddy *find_buddy(struct aim_user *, const char *);
+extern struct group *find_group(const char *);
+extern struct group *find_group_by_buddy(struct buddy *);
+extern struct buddy *add_buddy(struct aim_user *, const char *, const char *, const char *);
+extern void remove_buddy(struct buddy *);
+extern struct group *add_group(const char *);
+extern void remove_group(struct group *);
+extern void toc_build_config(struct aim_user *, char *, int len, gboolean);
+extern void parse_toc_buddy_list(struct aim_user *, char *);
 extern void signoff_blocked(struct gaim_connection *);
 extern char* get_buddy_alias_only(struct buddy *);
 extern char* get_buddy_alias(struct buddy *);
+extern GSList *gaim_group_get_accounts(struct group *);
+extern gboolean gaim_group_on_account(struct group *, struct aim_user *);
+extern void do_import(struct aim_user *, const char *);
+extern void gaim_blist_load();
+extern void gaim_blist_save();
+extern gboolean gaim_privacy_permit_add(struct aim_user *, const char *);
+extern gboolean gaim_privacy_permit_remove(struct aim_user *, const char *);
+extern gboolean gaim_privacy_deny_add(struct aim_user *, const char *);
+extern gboolean gaim_privacy_deny_remove(struct aim_user *, const char *);
+extern void gaim_buddy_set_setting(struct buddy *, const char *, const char *);
+extern char *gaim_buddy_get_setting(struct buddy *, const char *);
+
 
 /* Functions in core.c */
 extern gint UI_write(struct UI *, guchar *, int);
--- a/src/dialogs.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/dialogs.c	Sun Jan 19 22:16:52 2003 +0000
@@ -449,17 +449,16 @@
 
 void do_remove_buddy(struct buddy *b)
 {
-	struct group *g = find_group_by_buddy(b->gc, b->name);
-	struct gaim_connection *gc = b->gc;
+	struct group *g = find_group_by_buddy(b);
 	struct conversation *cv;
 
 	if (!b)
 		return;
 
 	debug_printf(_("Removing '%s' from buddy list.\n"), b->name);
-	serv_remove_buddy(b->gc, b->name, g->name);
-	remove_buddy(gc, g, b);
-	do_export(gc);
+	serv_remove_buddy(b->user->gc, b->name, g->name);
+	remove_buddy(b);
+	gaim_blist_save();
 
 	cv = find_conversation(b->name);
 
@@ -470,7 +469,7 @@
 
 void show_confirm_del(struct gaim_connection *gc, gchar *name)
 {
-	struct buddy *bd = find_buddy(gc, name);
+	struct buddy *bd = find_buddy(gc->user, name);
 	char *text;
 	if (!bd)
 		return;
@@ -884,14 +883,14 @@
 
 		c = find_conversation(who);
 
-		add_buddy(a->gc, grp, who, whoalias);
+		add_buddy(a->gc->user, grp, who, whoalias);
 		serv_add_buddy(a->gc, who);
 
 		if (c != NULL) {
 			update_buttons_by_protocol(c);
 		}
 
-		do_export(a->gc);
+		gaim_blist_save();
 	}
 
 	destroy_dialog(NULL, a->window);
@@ -900,15 +899,15 @@
 void do_add_group(GtkWidget *w, int resp, struct addbuddy *a)
 {
 	const char *grp;
-	
+
 	if (resp == GTK_RESPONSE_OK) {
 		grp = gtk_entry_get_text(GTK_ENTRY(a->entry));
 
 		if (!a->gc)
 			a->gc = connections->data;
 
-		add_group(a->gc, grp);
-		do_export(a->gc);
+		add_group(grp);
+		gaim_blist_save();
 	}
 
 	destroy_dialog(NULL, a->window);
@@ -920,7 +919,7 @@
 	GList *tmp = NULL;
 	char *tmp2;
 	struct group *g;
-	GSList *grp = gc->groups;
+	GSList *grp = groups;
 
 	if (!grp) {
 		tmp2 = g_strdup(_("Buddies"));
@@ -1176,9 +1175,9 @@
 	if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
 		return;
 	debug_printf("setting deny mode %d\n", data);
-	current_deny_gc->permdeny = data;
+	current_deny_gc->user->permdeny = data;
 	serv_set_permit_deny(current_deny_gc);
-	do_export(current_deny_gc);
+	gaim_blist_save();
 }
 
 static GtkWidget *deny_opt(char *label, int which, GtkWidget *set)
@@ -1194,7 +1193,7 @@
 
 	g_signal_connect(GTK_OBJECT(opt), "toggled", G_CALLBACK(set_deny_mode), (void *)which);
 	gtk_widget_show(opt);
-	if (current_deny_gc->permdeny == which)
+	if (current_deny_gc->user->permdeny == which)
 		gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(opt), TRUE);
 
 	return opt;
@@ -1219,7 +1218,7 @@
 {
 	GSList *bg = gtk_radio_button_group(GTK_RADIO_BUTTON(deny_type));
 
-	switch (current_deny_gc->permdeny) {
+	switch (current_deny_gc->user->permdeny) {
 	case 5:
 		bg = bg->next->next;
 		break;
@@ -1248,7 +1247,7 @@
 	if (!current_is_deny)
 		return;
 
-	p = current_deny_gc->permit;
+	p = current_deny_gc->user->permit;
 
 	gtk_list_store_clear(GTK_LIST_STORE(allow_store));
 
@@ -1272,7 +1271,7 @@
 	if (!current_is_deny)
 		return;
 
-	d = current_deny_gc->deny;
+	d = current_deny_gc->user->deny;
 
 	gtk_list_store_clear(GTK_LIST_STORE(block_store));
 
@@ -1390,24 +1389,24 @@
 		return;
 
 	if (permit) {
-		char *name = find_permdeny_by_name(current_deny_gc->permit, who);
+		char *name = find_permdeny_by_name(current_deny_gc->user->permit, who);
 
 		if (name) {
-			current_deny_gc->permit = g_slist_remove(current_deny_gc->permit, name);
+			gaim_privacy_permit_remove(current_deny_gc->user, name);
 			serv_rem_permit(current_deny_gc, who);
 			build_allow_list();
 		}
 	} else {
-		char *name = find_permdeny_by_name(current_deny_gc->deny, who);
+		char *name = find_permdeny_by_name(current_deny_gc->user->deny, who);
 
 		if (name) {
-			current_deny_gc->deny = g_slist_remove(current_deny_gc->deny, name);
+			gaim_privacy_deny_remove(current_deny_gc->user, name);
 			serv_rem_deny(current_deny_gc, who);
 			build_block_list();
 		}
 	}
 
-	do_export(current_deny_gc);
+	gaim_blist_save();
 }
 
 GtkWidget *privacy_win;
@@ -2496,47 +2495,21 @@
 {
 
 	const char *who;
-	char *name;
 
 	who = gtk_entry_get_text(GTK_ENTRY(p->entry));
 
-	name = g_malloc(strlen(who) + 2);
-	g_snprintf(name, strlen(who) + 2, "%s", who);
-
 	if (!p->permit) {
-		GSList *d = p->gc->deny;
-		char *n;
-		n = g_strdup(normalize(name));
-		while (d) {
-			if (!g_strcasecmp(n, normalize(d->data)))
-				break;
-			d = d->next;
+		if (gaim_privacy_deny_add(p->gc->user, who)) {
+			serv_add_deny(p->gc, who);
+			build_block_list();
+			gaim_blist_save();
 		}
-		g_free(n);
-		if (!d) {
-			p->gc->deny = g_slist_append(p->gc->deny, name);
-			serv_add_deny(p->gc, name);
-			build_block_list();
-			do_export(p->gc);
-		} else
-			g_free(name);
 	} else {
-		GSList *d = p->gc->permit;
-		char *n;
-		n = g_strdup(normalize(name));
-		while (d) {
-			if (!g_strcasecmp(n, normalize(d->data)))
-				break;
-			d = d->next;
+		if (gaim_privacy_permit_add(p->gc->user, who)) {
+			serv_add_permit(p->gc, who);
+			build_allow_list();
+			gaim_blist_save();
 		}
-		g_free(n);
-		if (!d) {
-			p->gc->permit = g_slist_append(p->gc->permit, name);
-			serv_add_permit(p->gc, name);
-			build_allow_list();
-			do_export(p->gc);
-		} else
-			g_free(name);
 	}
 
 	destroy_dialog(NULL, p->window);
@@ -3357,8 +3330,8 @@
 		return;
 	}
 	if (g_slist_find(connections, importgc)) {
-		do_import(importgc, file);
-		do_export(importgc);
+		do_import(gc->user, file);
+		gaim_blist_save();
 	}
 	destroy_dialog(NULL, importdialog);
 }
@@ -3777,7 +3750,7 @@
 		b->alias[0] = '\0';
 	handle_buddy_rename(b, b->name);
 	serv_alias_buddy(b);
-	do_export(b->gc);
+	gaim_blist_save();
 	destroy_dialog(aliasdlg, aliasdlg);
 }
 
@@ -4298,7 +4271,7 @@
 	const char *new_name;
 	struct group *g;
 	struct group *orig;
-	struct gaim_connection *gc;
+	GSList *accts;
 
 	if (resp == GTK_RESPONSE_OK) {
 
@@ -4307,27 +4280,35 @@
 
 		if (new_name && (strlen(new_name) != 0) && strcmp(new_name, g->name)) {
 			char *prevname;
-			gc = g->gc;
 	
-			if ((orig = find_group(g->gc, new_name)) != NULL && g_strcasecmp(new_name, g->name)) {
+			if ((orig = find_group(new_name)) != NULL && g_strcasecmp(new_name, g->name)) {
 				orig->members = g_slist_concat(orig->members, g->members);
 				handle_group_rename(orig, g->name);
-				g->gc->groups = g_slist_remove(g->gc->groups, g);
+				groups = g_slist_remove(groups, g);
 				/* FIXME, i don't like calling this. it's sloppy. */ build_edit_tree();
-				serv_rename_group(gc, g, new_name);
+				accts = gaim_group_get_accounts(g);
+				while(accts) {
+					struct aim_user *au = accts->data;
+					serv_rename_group(au->gc, g, new_name);
+					accts = g_slist_remove(accts, accts->data);
+				}
 				g_free(g);
 			} else {
 				prevname = g_strdup(g->name);
-				serv_rename_group(gc, g, new_name);
+				accts = gaim_group_get_accounts(g);
+				while(accts) {
+					struct aim_user *au = accts->data;
+					serv_rename_group(au->gc, g, new_name);
+					accts = g_slist_remove(accts, accts->data);
+				}
 				g_snprintf(g->name, sizeof(g->name), "%s", new_name);
 				handle_group_rename(g, prevname);
 				/* FIXME, i don't like calling this. it's sloppy. */ build_edit_tree();
 				g_free(prevname);
 			}
-			do_export(gc);
+			gaim_blist_save();
 		}
 	}
-
 	destroy_dialog(rename_dialog, rename_dialog);
 }
 
@@ -4403,12 +4384,12 @@
 	new_name = gtk_entry_get_text(GTK_ENTRY(entry));
 	b = gtk_object_get_user_data(obj);
 
-	if (!g_slist_find(connections, b->gc)) {
+	if (!g_slist_find(connections, b->user->gc)) {
 		destroy_dialog(rename_bud_dialog, rename_bud_dialog);
 		return;
 	}
 
-	gr = b->gc->groups;
+	gr = groups;
 	while (gr) {
 		if (g_slist_find(((struct group *)gr->data)->members, b))
 			break;
@@ -4420,14 +4401,14 @@
 	}
 
 	if (new_name && (strlen(new_name) != 0) && strcmp(new_name, b->name)) {
-		struct group *g = find_group_by_buddy(b->gc, b->name);
+		struct group *g = find_group_by_buddy(b);
 		char *prevname = g_strdup(b->name);
 		if (g)
-			serv_remove_buddy(b->gc, b->name, g->name);
+			serv_remove_buddy(b->user->gc, b->name, g->name);
 		g_snprintf(b->name, sizeof(b->name), "%s", new_name);
-		serv_add_buddy(b->gc, b->name);
+		serv_add_buddy(b->user->gc, b->name);
 		handle_buddy_rename(b, prevname);
-		do_export(b->gc);
+		gaim_blist_save();
 		g_free(prevname);
 	}
 
--- a/src/gaim.h	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/gaim.h	Sun Jan 19 22:16:52 2003 +0000
@@ -429,10 +429,10 @@
 extern void serv_add_buddies(struct gaim_connection *, GList *);
 extern void serv_remove_buddy(struct gaim_connection *, char *, char *);
 extern void serv_remove_buddies(struct gaim_connection *, GList *, char *);
-extern void serv_add_permit(struct gaim_connection *, char *);
-extern void serv_add_deny(struct gaim_connection *, char *);
-extern void serv_rem_permit(struct gaim_connection *, char *);
-extern void serv_rem_deny(struct gaim_connection *, char *);
+extern void serv_add_permit(struct gaim_connection *, const char *);
+extern void serv_add_deny(struct gaim_connection *, const char *);
+extern void serv_rem_permit(struct gaim_connection *, const char *);
+extern void serv_rem_deny(struct gaim_connection *, const char *);
 extern void serv_set_permit_deny(struct gaim_connection *);
 extern void serv_warn(struct gaim_connection *, char *, int);
 extern void serv_set_dir(struct gaim_connection *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, int);
--- a/src/gaimrc.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/gaimrc.c	Sun Jan 19 22:16:52 2003 +0000
@@ -504,6 +504,7 @@
 	u->user_info[0] = 0;
 	u->options = OPT_USR_REM_PASS;
 	u->protocol = DEFAULT_PROTO;
+	u->permit = u->deny = NULL;
 
 	if (!fgets(buf, sizeof(buf), f))
 		return u;
--- a/src/list.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/list.c	Sun Jan 19 22:16:52 2003 +0000
@@ -23,6 +23,7 @@
 #include <config.h>
 #endif
 #include <string.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #ifndef _WIN32
@@ -30,6 +31,7 @@
 #else
 #include <direct.h>
 #endif
+#include <ctype.h>
 #include "gaim.h"
 #include "prpl.h"
 
@@ -39,68 +41,72 @@
 
 #define PATHSIZE 1024
 
-void remove_buddy(struct gaim_connection *gc, struct group *rem_g, struct buddy *rem_b)
+void remove_buddy(struct buddy *rem_b)
 {
-	GSList *grp;
-	GSList *mem;
+	if(rem_b->user->gc) {
+		struct group *rem_g = find_group_by_buddy(rem_b);
 
-	struct group *delg;
-	struct buddy *delb;
+		ui_remove_buddy(rem_b);
 
-	/* we assume that gc is not NULL and that the buddy exists somewhere within the
-	 * gc's buddy list, therefore we can safely remove it. we need to ensure this
-	 * via the UI
-	 */
+		rem_g->members = g_slist_remove(rem_g->members, rem_b);
 
-	grp = g_slist_find(gc->groups, rem_g);
-	delg = (struct group *)grp->data;
-	mem = delg->members;
-
-	mem = g_slist_find(mem, rem_b);
-	delb = (struct buddy *)mem->data;
+		g_hash_table_destroy(rem_b->settings);
 
-	delg->members = g_slist_remove(delg->members, delb);
-
-	ui_remove_buddy(gc, rem_g, rem_b);
-
-	g_free(rem_b);
-
-	/* we don't flush buddy list to cache because in the case of remove_group that would
-	 * mean writing to the buddy list file once for each buddy, plus one more time */
+		g_free(rem_b);
+	} else {
+		char *buf = g_strdup_printf(_("%s was not removed from your buddy "
+					"list, because your account (%s) is not logged in."),
+					rem_b->name, rem_b->user->username);
+		do_error_dialog(_("Buddy Not Removed"), buf, GAIM_ERROR);
+		g_free(buf);
+	}
 }
 
-void remove_group(struct gaim_connection *gc, struct group *rem_g)
+void remove_group(struct group *rem_g)
 {
-	GSList *grp;
-	GSList *mem;
-	GList *tmp = NULL;
+	GSList *users;
 
-	struct group *delg;
-	struct buddy *delb;
+	for(users = aim_users; users; users = users->next) {
+		struct aim_user *user = users->data;
+		if(user->gc) {
+			GList *tmp = NULL;
+			GSList *buds = rem_g->members;
+
+			while (buds) {
+				struct buddy *delb = (struct buddy *)buds->data;
+				buds = buds->next;
 
-	/* we assume that the group actually does exist within the gc, and that the gc is not NULL.
-	 * the UI is responsible for this */
+				if(delb->user == user) {
+					tmp = g_list_append(tmp, g_strdup(delb->name));
+					remove_buddy(delb);	/* this should take care of removing
+										   the group_show if necessary */
+				}
+			}
 
-	grp = g_slist_find(gc->groups, rem_g);
-	delg = (struct group *)grp->data;
-	mem = delg->members;
+			if(tmp)
+				serv_remove_buddies(user->gc, tmp, rem_g->name);
 
-	while (delg->members) {
-		delb = (struct buddy *)delg->members->data;
-		tmp = g_list_append(tmp, g_strdup(delb->name));
-		remove_buddy(gc, delg, delb);	/* this should take care of removing
-						   the group_show if necessary */
+			while (tmp) {
+				g_free(tmp->data);
+				tmp = g_list_remove(tmp, tmp->data);
+			}
+		}
 	}
 
-	gc->groups = g_slist_remove(gc->groups, delg);
+	if(rem_g->members) {
+		char *buf = g_strdup_printf(_("%d buddies from group %s were not "
+					"removed because their accounts were not logged in.  These "
+					"buddies, and the group were not removed.\n"),
+				g_slist_length(rem_g->members), rem_g->name);
+		do_error_dialog(_("Group Not Removed"), buf, GAIM_ERROR);
+		g_free(buf);
 
-	serv_remove_buddies(gc, tmp, rem_g->name);
-	while (tmp) {
-		g_free(tmp->data);
-		tmp = g_list_remove(tmp, tmp->data);
+		return;
 	}
 
-	ui_remove_group(gc, rem_g);
+	ui_remove_group(rem_g);
+
+	groups = g_slist_remove(groups, rem_g);
 
 	g_free(rem_g);
 
@@ -108,35 +114,31 @@
 	 * mostly. remove_group is only called from one place, so we'll let it handle it. */
 }
 
-struct buddy *add_buddy(struct gaim_connection *gc, const char *group, const char *buddy, const char *show)
+struct buddy *add_buddy(struct aim_user *user, const char *group, const char *buddy, const char *show)
 {
 	struct buddy *b;
 	struct group *g;
 	const char *good;
 
-	if (!g_slist_find(connections, gc))
-		return NULL;
-
-	if ((b = find_buddy(gc, buddy)) != NULL)
+	if ((b = find_buddy(user, buddy)) != NULL)
 		return b;
 
-	g = find_group(gc, group);
+	g = find_group(group);
 
 	if (g == NULL)
-		g = add_group(gc, group);
+		g = add_group(group);
 
 	b = (struct buddy *)g_new0(struct buddy, 1);
 
 	if (!b)
 		return NULL;
 
-	b->gc = gc;
+	b->user = user;
 	b->present = 0;
 
-	if (gc->prpl->normalize)
-		good = gc->prpl->normalize(buddy);
-	else
-		good = buddy;
+	b->settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+	good = buddy;
 
 	g_snprintf(b->name, sizeof(b->name), "%s", good);
 	if(show && show[0])
@@ -149,220 +151,103 @@
 	b->idle = 0;
 	b->caps = 0;
 
-	ui_add_buddy(gc, g, b);
+	ui_add_buddy(user->gc, g, b);
 
 	return b;
 }
 
-struct group *add_group(struct gaim_connection *gc, const char *group)
+struct group *add_group(const char *group)
 {
-	struct group *g = find_group(gc, group);
+	struct group *g = find_group(group);
 	if (g)
 		return g;
-	if (!g_slist_find(connections, gc))
-		return NULL;
 	g = (struct group *)g_new0(struct group, 1);
 	if (!g)
 		return NULL;
 
-	g->gc = gc;
 	strncpy(g->name, group, sizeof(g->name));
-	gc->groups = g_slist_append(gc->groups, g);
+	groups = g_slist_append(groups, g);
 
 	g->members = NULL;
 
-	ui_add_group(gc, g);
+	ui_add_group(g);
 
 	return g;
 }
 
-struct group *find_group(struct gaim_connection *gc, const char *group)
+struct group *find_group(const char *group)
 {
 	struct group *g;
 	GSList *grp;
-	GSList *c = connections;
-	struct gaim_connection *z;
-	char *grpname = g_malloc(strlen(group) + 1);
-
-	strcpy(grpname, normalize (group));
-	if (gc) {
-		if (!g_slist_find(connections, gc))
-			return NULL;
-		grp = gc->groups;
-		while (grp) {
-			g = (struct group *)grp->data;
-			if (!g_strcasecmp(normalize (g->name), grpname)) {
-				g_free(grpname);
-				return g;
-			}
-			grp = g_slist_next(grp);
-		}
+	char *grpname = g_strdup(normalize(group));
 
-		g_free(grpname);
-		return NULL;
-	} else {
-		while (c) {
-			z = (struct gaim_connection *)c->data;
-			grp = z->groups;
-			while (grp) {
-				g = (struct group *)grp->data;
-				if (!g_strcasecmp(normalize (g->name), grpname)) {
-					g_free(grpname);
-					return g;
-				}
-				grp = g_slist_next(grp);
-			}
-
-			c = c->next;
+	grp = groups;
+	while (grp) {
+		g = (struct group *)grp->data;
+		if (!g_strcasecmp(normalize (g->name), grpname)) {
+			g_free(grpname);
+			return g;
 		}
-		g_free(grpname);
-		return NULL;
+		grp = g_slist_next(grp);
 	}
+	g_free(grpname);
+	return NULL;
 }
 
-struct group *find_group_by_buddy(struct gaim_connection *gc, const char *who)
+struct group *find_group_by_buddy(struct buddy *b)
+{
+	GSList *grp = groups;
+
+	while(grp) {
+		struct group *g = grp->data;
+		if(g_slist_find(g->members, b))
+			return g;
+		grp = grp->next;
+	}
+	return NULL;
+}
+
+struct buddy *find_buddy(struct aim_user *user, const char *who)
 {
 	struct group *g;
 	struct buddy *b;
 	GSList *grp;
 	GSList *mem;
-	char *whoname;
+	char *whoname = NULL;
 	char *(*norm)(const char *);
 
-	if (gc) {
-		if (gc->prpl->normalize)
-			norm = gc->prpl->normalize;
-		else
-			norm = normalize;
-		whoname = g_strdup(norm(who));
-		grp = gc->groups;
-		while (grp) {
-			g = (struct group *)grp->data;
+	grp = groups;
+	while (grp) {
+		g = (struct group *)grp->data;
 
-			mem = g->members;
-			while (mem) {
-				b = (struct buddy *)mem->data;
-				if (!strcmp(norm(b->name), whoname)) {
-					g_free(whoname);
-					return g;
-				}
-				mem = mem->next;
+		mem = g->members;
+		while (mem) {
+			b = (struct buddy *)mem->data;
+			/*
+			norm = (b->user->gc && b->user->gc->prpl->normalize) ? b->user->gc->prpl->normalize : normalize;
+			*/
+			norm = normalize;
+			whoname = g_strdup(norm(who));
+			if ((b->user == user || !user) && !strcmp(norm(b->name), whoname)) {
+				g_free(whoname);
+				return b;
 			}
-			grp = g_slist_next(grp);
+			g_free(whoname);
+			mem = mem->next;
 		}
-		g_free(whoname);
-		return NULL;
-	} else {
-		GSList *c = connections;
-		struct gaim_connection *z;
-		while (c) {
-			z = (struct gaim_connection *)c->data;
-			if (z->prpl->normalize)
-				norm = z->prpl->normalize;
-			else
-				norm = normalize;
-			whoname = g_strdup(norm(who));
-			grp = z->groups;
-			while (grp) {
-				g = (struct group *)grp->data;
-
-				mem = g->members;
-				while (mem) {
-					b = (struct buddy *)mem->data;
-					if (!strcmp(norm(b->name), whoname)) {
-						g_free(whoname);
-						return g;
-					}
-					mem = mem->next;
-				}
-				grp = g_slist_next(grp);
-			}
-			c = c->next;
-			g_free(whoname);
-		}
-		return NULL;
+		grp = g_slist_next(grp);
 	}
+	return NULL;
 }
 
-struct buddy *find_buddy(struct gaim_connection *gc, const char *who)
-{
-	struct group *g;
-	struct buddy *b;
-	GSList *grp;
-	GSList *c;
-	struct gaim_connection *z;
-	GSList *mem;
-	char *whoname;
-	char *(*norm)(const char *);
-
-	if (gc) {
-		if (!g_slist_find(connections, gc))
-			return NULL;
-		if (gc->prpl->normalize)
-			norm = gc->prpl->normalize;
-		else
-			norm = normalize;
-		whoname = g_strdup(norm(who));
-		grp = gc->groups;
-		while (grp) {
-			g = (struct group *)grp->data;
-
-			mem = g->members;
-			while (mem) {
-				b = (struct buddy *)mem->data;
-				if (!strcmp(norm(b->name), whoname)) {
-					g_free(whoname);
-					return b;
-				}
-				mem = mem->next;
-			}
-			grp = g_slist_next(grp);
-		}
-		g_free(whoname);
-		return NULL;
-	} else {
-		c = connections;
-		while (c) {
-			z = (struct gaim_connection *)c->data;
-			if (z->prpl->normalize)
-				norm = z->prpl->normalize;
-			else
-				norm = normalize;
-			whoname = g_strdup(norm(who));
-			grp = z->groups;
-			while (grp) {
-				g = (struct group *)grp->data;
-
-				mem = g->members;
-				while (mem) {
-					b = (struct buddy *)mem->data;
-					if (!strcmp(norm(b->name), whoname)) {
-						g_free(whoname);
-						return b;
-					}
-					mem = mem->next;
-				}
-				grp = g_slist_next(grp);
-			}
-			c = c->next;
-			g_free(whoname);
-		}
-		return NULL;
-	}
-}
-
-void parse_toc_buddy_list(struct gaim_connection *gc, char *config)
+void parse_toc_buddy_list(struct aim_user *user, char *config)
 {
 	char *c;
 	char current[256];
-	char *name;
-	GList *bud;
-	int how_many = 0;
+
 
-	bud = NULL;
-    
 	if (config != NULL) {
-    
+
 		/* skip "CONFIG:" (if it exists) */
 		c = strncmp(config + 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ?
 			strtok(config, "\n") :
@@ -372,116 +257,77 @@
 				break;
 			if (*c == 'g') {
 				strncpy(current, c + 2, sizeof(current));
-				if (!find_group(gc, current)) {
-					add_group(gc, current);
-					how_many++;
+				if (!find_group(current)) {
+					add_group(current);
 				}
-			} else if (*c == 'b' && !find_buddy(gc, c + 2)) {
+			} else if (*c == 'b' && !find_buddy(user, c + 2)) {
 				char nm[80], sw[BUDDY_ALIAS_MAXLEN], *tmp = c + 2;
 				int i = 0;
 				while (*tmp != ':' && *tmp && i < sizeof(nm) - 1)
 					nm[i++] = *tmp++;
-				
+
 				while (*tmp != ':' && *tmp)
 					tmp++;
-				
+
 				if (*tmp == ':')
 					*tmp++ = '\0';
-				
+
 				nm[i] = '\0';
 				i = 0;
 				while (*tmp && i < sizeof(sw) - 1)
 					sw[i++] = *tmp++;
 				sw[i] = '\0';
-				if (!find_buddy(gc, nm)) {
-					add_buddy(gc, current, nm, sw);
-					how_many++;
-					bud = g_list_append(bud, c + 2);
+				if (!find_buddy(user, nm)) {
+					add_buddy(user, current, nm, sw);
 				}
 			} else if (*c == 'p') {
-				GSList *d = gc->permit;
-				char *n;
-				name = g_malloc(strlen(c + 2) + 2);
-				g_snprintf(name, strlen(c + 2) + 1, "%s", c + 2);
-				n = g_strdup(normalize (name));
-				while (d) {
-					if (!g_strcasecmp(n, normalize (d->data)))
-						break;
-					d = d->next;
-				}
-				g_free(n);
-				if (!d) {
-					gc->permit = g_slist_append(gc->permit, name);
-					how_many++;
-				} else
-					g_free(name);
+				gaim_privacy_permit_add(user, c + 2);
 			} else if (*c == 'd') {
-				GSList *d = gc->deny;
-				char *n;
-				name = g_malloc(strlen(c + 2) + 2);
-				g_snprintf(name, strlen(c + 2) + 1, "%s", c + 2);
-				n = g_strdup(normalize (name));
-				while (d) {
-					if (!g_strcasecmp(n, normalize (d->data)))
-					break;
-				d = d->next;
-			}
-			g_free(n);
-			if (!d) {
-				gc->deny = g_slist_append(gc->deny, name);
-				how_many++;
-			} else
-				g_free(name);
+				gaim_privacy_deny_add(user, c + 2);
 			} else if (!strncmp("toc", c, 3)) {
-				sscanf(c + strlen(c) - 1, "%d", &gc->permdeny);
-				debug_printf("permdeny: %d\n", gc->permdeny);
-				if (gc->permdeny == 0)
-					gc->permdeny = 1;
+				sscanf(c + strlen(c) - 1, "%d", &user->permdeny);
+				debug_printf("permdeny: %d\n", user->permdeny);
+				if (user->permdeny == 0)
+					user->permdeny = 1;
 			} else if (*c == 'm') {
-				sscanf(c + 2, "%d", &gc->permdeny);
-				debug_printf("permdeny: %d\n", gc->permdeny);
-				if (gc->permdeny == 0)
-					gc->permdeny = 1;
+				sscanf(c + 2, "%d", &user->permdeny);
+				debug_printf("permdeny: %d\n", user->permdeny);
+				if (user->permdeny == 0)
+					user->permdeny = 1;
 			}
 		} while ((c = strtok(NULL, "\n")));
-		
-		if (bud != NULL) {
-			serv_add_buddies(gc, bud);
-			g_list_free(bud);
-		}
-		serv_set_permit_deny(gc);
 	}
-	
-	if (how_many != 0)
-		do_export(gc);
-	
 }
 
-void toc_build_config(struct gaim_connection *gc, char *s, int len, gboolean show)
+void toc_build_config(struct aim_user *user, char *s, int len, gboolean show)
 {
-	GSList *grp = gc->groups;
+	GSList *grp = groups;
 	GSList *mem;
 	struct group *g;
 	struct buddy *b;
-	GSList *plist = gc->permit;
-	GSList *dlist = gc->deny;
+	GSList *plist = user->permit;
+	GSList *dlist = user->deny;
 
 	int pos = 0;
 
-	if (!gc->permdeny)
-		gc->permdeny = 1;
+	if (!user->permdeny)
+		user->permdeny = 1;
 
-	pos += g_snprintf(&s[pos], len - pos, "m %d\n", gc->permdeny);
+	pos += g_snprintf(&s[pos], len - pos, "m %d\n", user->permdeny);
 	while (len > pos && grp) {
 		g = (struct group *)grp->data;
-		pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name);
-		mem = g->members;
-		while (len > pos && mem) {
-			b = (struct buddy *)mem->data;
-			pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", b->name,
-					  (show && b->alias[0]) ? ":" : "",
-					  (show && b->alias[0]) ? b->alias : "");
-			mem = mem->next;
+		if(gaim_group_on_account(g, user)) {
+			pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name);
+			mem = g->members;
+			while (len > pos && mem) {
+				b = (struct buddy *)mem->data;
+				if(b->user == user) {
+					pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", b->name,
+							(show && b->alias[0]) ? ":" : "",
+							(show && b->alias[0]) ? b->alias : "");
+				}
+				mem = mem->next;
+			}
 		}
 		grp = g_slist_next(grp);
 	}
@@ -665,42 +511,9 @@
 	return good;
 }
 
-/* see if a buddy list cache file for this user exists */
-
-gboolean bud_list_cache_exists(struct gaim_connection *gc)
-{
-	gboolean ret = FALSE;
-	char path[PATHSIZE];
-	char *file;
-	struct stat sbuf;
-	char *g_screenname;
-
-	g_screenname = get_screenname_filename(gc->username);
+static gboolean gaim_blist_read(const char *filename);
 
-	file = gaim_user_dir();
-	if (file != (char *)NULL) {
-		g_snprintf(path, sizeof path, "%s" G_DIR_SEPARATOR_S "%s.%d.blist", file, g_screenname, gc->protocol);
-		if (!stat(path, &sbuf)) {
-			debug_printf("%s exists.\n", path);
-			ret = TRUE;
-		} else {
-			char path2[PATHSIZE];
-			debug_printf("%s does not exist.\n", path);
-			g_snprintf(path2, sizeof path2, "%s" G_DIR_SEPARATOR_S "%s.blist", file, g_screenname);
-			if (!stat(path2, &sbuf)) {
-				debug_printf("%s exists, moving to %s\n", path2, path);
-				if (rename(path2, path))
-					debug_printf("rename didn't work!\n");
-				else
-					ret = TRUE;
-			}
-		}
-	}
-	g_free(g_screenname);
-	return ret;
-}
-
-void do_import(struct gaim_connection *gc, const char *filename)
+void do_import(struct aim_user *user, const char *filename)
 {
 	GString *buf = NULL;
 	char first[64];
@@ -712,11 +525,12 @@
 	if (filename) {
 		g_snprintf(path, sizeof(path), "%s", filename);
 	} else {
-		char *g_screenname = get_screenname_filename(gc->username);
+		char *g_screenname = get_screenname_filename(user->username);
 		char *file = gaim_user_dir();
+		int protocol = (user->protocol == PROTO_OSCAR) ? (isalpha(user->username[0]) ? PROTO_TOC : PROTO_ICQ): user->protocol;
 
 		if (file != (char *)NULL) {
-			sprintf(path, "%s" G_DIR_SEPARATOR_S "%s.%d.blist", file, g_screenname, gc->protocol);
+			sprintf(path, "%s" G_DIR_SEPARATOR_S "%s.%d.blist", file, g_screenname, protocol);
 			g_free(g_screenname);
 		} else {
 			g_free(g_screenname);
@@ -739,7 +553,10 @@
 	if ((first[0] == '\n') || (first[0] == '\r' && first[1] == '\n'))
 		fgets(first, 64, f);
 
-	if (!g_strncasecmp(first, "Config {", strlen("Config {"))) {
+	if (!g_strncasecmp(first, "<xml", strlen("<xml"))) {
+		/* new gaim XML buddy list */
+		gaim_blist_read(path);
+	} else if (!g_strncasecmp(first, "Config {", strlen("Config {"))) {
 		/* AIM 4 buddy list */
 		debug_printf("aim 4\n");
 		rewind(f);
@@ -775,64 +592,28 @@
 	if (buf) {
 		buf = g_string_prepend(buf, "toc_set_config {");
 		buf = g_string_append(buf, "}\n");
-		parse_toc_buddy_list(gc, buf->str);
+		parse_toc_buddy_list(user, buf->str);
 		g_string_free(buf, TRUE);
 	}
 }
 
-void do_export(struct gaim_connection *g)
-{
-	FILE *dir;
-	FILE *f;
-	char buf[32 * 1024];
-	char *file;
-	char path[PATHSIZE];
-	char *g_screenname;
-
-	file = gaim_user_dir();
-	if (!file)
-		return;
-
-	strcpy(buf, file);
-	dir = fopen(buf, "r");
-	if (!dir)
-		mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);
-	else
-		fclose(dir);
-
-	g_screenname = get_screenname_filename(g->username);
-
-	sprintf(path, "%s" G_DIR_SEPARATOR_S "%s.%d.blist", file, g_screenname, g->protocol);
-	if ((f = fopen(path, "w"))) {
-		debug_printf("writing %s\n", path);
-		toc_build_config(g, buf, 8192 - 1, TRUE);
-		fprintf(f, "%s\n", buf);
-		fclose(f);
-		chmod(path, S_IRUSR | S_IWUSR);
-	} else {
-		debug_printf("unable to write %s\n", path);
-	}
-
-	g_free(g_screenname);
-}
-
 static gboolean is_blocked(struct buddy *b)
 {
-	struct gaim_connection *gc = b->gc;
+	struct aim_user *user = b->user;
 
-	if (gc->permdeny == PERMIT_ALL)
+	if (user->permdeny == PERMIT_ALL)
 		return FALSE;
 
-	if (gc->permdeny == PERMIT_NONE) {
-		if (g_strcasecmp(b->name, gc->displayname))
+	if (user->permdeny == PERMIT_NONE) {
+		if (user->gc && g_strcasecmp(b->name, user->gc->username))
 			return TRUE;
 		else
 			return FALSE;
 	}
 
-	if (gc->permdeny == PERMIT_SOME) {
+	if (user->permdeny == PERMIT_SOME) {
 		char *x = g_strdup(normalize(b->name));
-		GSList *s = gc->permit;
+		GSList *s = user->permit;
 		while (s) {
 			if (!g_strcasecmp(x, normalize(s->data)))
 				break;
@@ -844,9 +625,9 @@
 		return TRUE;
 	}
 
-	if (gc->permdeny == DENY_SOME) {
+	if (user->permdeny == DENY_SOME) {
 		char *x = g_strdup(normalize(b->name));
-		GSList *s = gc->deny;
+		GSList *s = user->deny;
 		while (s) {
 			if (!g_strcasecmp(x, normalize(s->data)))
 				break;
@@ -863,7 +644,7 @@
 
 void signoff_blocked(struct gaim_connection *gc)
 {
-	GSList *g = gc->groups;
+	GSList *g = groups;
 	while (g) {
 		GSList *m = ((struct group *)g->data)->members;
 		while (m) {
@@ -894,3 +675,483 @@
 	return ret;
 }
 
+GSList *gaim_group_get_accounts(struct group *g) {
+	GSList *buds = g->members;
+	GSList *ret = NULL;
+	while(buds) {
+		struct buddy *b = buds->data;
+		if(!g_slist_find(ret, b->user))
+			ret = g_slist_append(ret, b->user);
+		buds = buds->next;
+	}
+	return ret;
+}
+
+gboolean gaim_group_on_account(struct group *g, struct aim_user *user) {
+	GSList *buds = g->members;
+	while(buds) {
+		struct buddy *b = buds->data;
+		if((!user && b->user->gc) || b->user == user)
+			return TRUE;
+		buds = buds->next;
+	}
+	return FALSE;
+}
+
+
+static char *blist_parser_group_name = NULL;
+static char *blist_parser_person_name = NULL;
+static char *blist_parser_account_name = NULL;
+static int blist_parser_account_protocol = 0;
+static char *blist_parser_buddy_name = NULL;
+static char *blist_parser_buddy_alias = NULL;
+static char *blist_parser_setting_name = NULL;
+static char *blist_parser_setting_value = NULL;
+static GHashTable *blist_parser_buddy_settings = NULL;
+static int blist_parser_privacy_mode = 0;
+static enum {
+	BLIST_TAG_GAIM,
+	BLIST_TAG_BLIST,
+	BLIST_TAG_GROUP,
+	BLIST_TAG_PERSON,
+	BLIST_TAG_BUDDY,
+	BLIST_TAG_NAME,
+	BLIST_TAG_ALIAS,
+	BLIST_TAG_SETTING,
+	BLIST_TAG_PRIVACY,
+	BLIST_TAG_ACCOUNT,
+	BLIST_TAG_PERMIT,
+	BLIST_TAG_BLOCK,
+	BLIST_TAG_IGNORE
+} blist_parser_current_tag;
+
+static void blist_start_element_handler (GMarkupParseContext *context,
+		const gchar *element_name,
+		const gchar **attribute_names,
+		const gchar **attribute_values,
+		gpointer user_data,
+		GError **error) {
+	int i;
+
+	if(!strcmp(element_name, "gaim")) {
+		blist_parser_current_tag = BLIST_TAG_GAIM;
+	} else if(!strcmp(element_name, "blist")) {
+		blist_parser_current_tag = BLIST_TAG_BLIST;
+	} else if(!strcmp(element_name, "group")) {
+		blist_parser_current_tag = BLIST_TAG_GROUP;
+		for(i=0; attribute_names[i]; i++) {
+			if(!strcmp(attribute_names[i], "name"))
+				blist_parser_group_name = g_strdup(attribute_values[i]);
+		}
+		if(blist_parser_group_name) {
+			add_group(blist_parser_group_name);
+		}
+	} else if(!strcmp(element_name, "person")) {
+		blist_parser_current_tag = BLIST_TAG_PERSON;
+		for(i=0; attribute_names[i]; i++) {
+			if(!strcmp(attribute_names[i], "name"))
+				blist_parser_person_name = g_strdup(attribute_values[i]);
+		}
+	} else if(!strcmp(element_name, "buddy")) {
+		blist_parser_current_tag = BLIST_TAG_BUDDY;
+		for(i=0; attribute_names[i]; i++) {
+			if(!strcmp(attribute_names[i], "account"))
+				blist_parser_account_name = g_strdup(attribute_values[i]);
+			else if(!strcmp(attribute_names[i], "protocol"))
+				blist_parser_account_protocol = atoi(attribute_values[i]);
+		}
+	} else if(!strcmp(element_name, "name")) {
+		blist_parser_current_tag = BLIST_TAG_NAME;
+	} else if(!strcmp(element_name, "alias")) {
+		blist_parser_current_tag = BLIST_TAG_ALIAS;
+	} else if(!strcmp(element_name, "setting")) {
+		blist_parser_current_tag = BLIST_TAG_SETTING;
+		for(i=0; attribute_names[i]; i++) {
+			if(!strcmp(attribute_names[i], "name"))
+				blist_parser_setting_name = g_strdup(attribute_values[i]);
+		}
+	} else if(!strcmp(element_name, "privacy")) {
+		blist_parser_current_tag = BLIST_TAG_PRIVACY;
+	} else if(!strcmp(element_name, "account")) {
+		blist_parser_current_tag = BLIST_TAG_ACCOUNT;
+		for(i=0; attribute_names[i]; i++) {
+			if(!strcmp(attribute_names[i], "protocol"))
+				blist_parser_account_protocol = atoi(attribute_values[i]);
+			else if(!strcmp(attribute_names[i], "mode"))
+				blist_parser_privacy_mode = atoi(attribute_values[i]);
+			else if(!strcmp(attribute_names[i], "name"))
+				blist_parser_account_name = g_strdup(attribute_values[i]);
+		}
+	} else if(!strcmp(element_name, "permit")) {
+		blist_parser_current_tag = BLIST_TAG_PERMIT;
+	} else if(!strcmp(element_name, "block")) {
+		blist_parser_current_tag = BLIST_TAG_BLOCK;
+	} else if(!strcmp(element_name, "ignore")) {
+		blist_parser_current_tag = BLIST_TAG_IGNORE;
+	}
+}
+
+static void blist_end_element_handler(GMarkupParseContext *context,
+		const gchar *element_name, gpointer user_data, GError **error) {
+	if(!strcmp(element_name, "gaim")) {
+	} else if(!strcmp(element_name, "blist")) {
+		blist_parser_current_tag = BLIST_TAG_GAIM;
+	} else if(!strcmp(element_name, "group")) {
+		blist_parser_current_tag = BLIST_TAG_BLIST;
+	} else if(!strcmp(element_name, "person")) {
+		blist_parser_current_tag = BLIST_TAG_GROUP;
+		g_free(blist_parser_person_name);
+		blist_parser_person_name = NULL;
+	} else if(!strcmp(element_name, "buddy")) {
+		struct aim_user *user = find_user(blist_parser_account_name,
+				blist_parser_account_protocol);
+		if(user) {
+			struct buddy *b = add_buddy(user, blist_parser_group_name,
+					blist_parser_buddy_name, blist_parser_buddy_alias);
+			if(blist_parser_buddy_settings) {
+				g_hash_table_destroy(b->settings);
+				b->settings = blist_parser_buddy_settings;
+			}
+		}
+		blist_parser_current_tag = BLIST_TAG_PERSON;
+		g_free(blist_parser_buddy_name);
+		blist_parser_buddy_name = NULL;
+		g_free(blist_parser_buddy_alias);
+		blist_parser_buddy_alias = NULL;
+		g_free(blist_parser_account_name);
+		blist_parser_account_name = NULL;
+		blist_parser_buddy_settings = NULL;
+	} else if(!strcmp(element_name, "name")) {
+		blist_parser_current_tag = BLIST_TAG_BUDDY;
+	} else if(!strcmp(element_name, "alias")) {
+		blist_parser_current_tag = BLIST_TAG_BUDDY;
+	} else if(!strcmp(element_name, "setting")) {
+		if(!blist_parser_buddy_settings)
+			blist_parser_buddy_settings = g_hash_table_new_full(g_str_hash,
+					g_str_equal, g_free, g_free);
+		if(blist_parser_setting_name && blist_parser_setting_value) {
+			g_hash_table_replace(blist_parser_buddy_settings,
+					g_strdup(blist_parser_setting_name),
+					g_strdup(blist_parser_setting_value));
+		}
+		g_free(blist_parser_setting_name);
+		g_free(blist_parser_setting_value);
+		blist_parser_current_tag = BLIST_TAG_BUDDY;
+	} else if(!strcmp(element_name, "privacy")) {
+		blist_parser_current_tag = BLIST_TAG_GAIM;
+	} else if(!strcmp(element_name, "account")) {
+		struct aim_user *user = find_user(blist_parser_account_name,
+				blist_parser_account_protocol);
+		if(user) {
+			user->permdeny = blist_parser_privacy_mode;
+		}
+		blist_parser_current_tag = BLIST_TAG_PRIVACY;
+		g_free(blist_parser_account_name);
+		blist_parser_account_name = NULL;
+	} else if(!strcmp(element_name, "permit")) {
+		struct aim_user *user = find_user(blist_parser_account_name,
+				blist_parser_account_protocol);
+		if(user) {
+			gaim_privacy_permit_add(user, blist_parser_buddy_name);
+		}
+		blist_parser_current_tag = BLIST_TAG_ACCOUNT;
+	} else if(!strcmp(element_name, "block")) {
+		struct aim_user *user = find_user(blist_parser_account_name,
+				blist_parser_account_protocol);
+		if(user) {
+			gaim_privacy_deny_add(user, blist_parser_buddy_name);
+		}
+		blist_parser_current_tag = BLIST_TAG_ACCOUNT;
+	} else if(!strcmp(element_name, "ignore")) {
+		/* we'll apparently do something with this later */
+		blist_parser_current_tag = BLIST_TAG_ACCOUNT;
+	}
+}
+
+static void blist_text_handler(GMarkupParseContext *context, const gchar *text,
+		gsize text_len, gpointer user_data, GError **error) {
+	switch(blist_parser_current_tag) {
+		case BLIST_TAG_NAME:
+			blist_parser_buddy_name = g_strndup(text, text_len);
+			break;
+		case BLIST_TAG_ALIAS:
+			blist_parser_buddy_alias = g_strndup(text, text_len);
+			break;
+		case BLIST_TAG_PERMIT:
+		case BLIST_TAG_BLOCK:
+		case BLIST_TAG_IGNORE:
+			blist_parser_buddy_name = g_strndup(text, text_len);
+			break;
+		case BLIST_TAG_SETTING:
+			blist_parser_setting_value = g_strndup(text, text_len);
+			break;
+		default:
+			break;
+	}
+}
+
+static GMarkupParser blist_parser = {
+	blist_start_element_handler,
+	blist_end_element_handler,
+	blist_text_handler,
+	NULL,
+	NULL
+};
+
+static gboolean gaim_blist_read(const char *filename) {
+	gchar *contents;
+	gsize length;
+	GMarkupParseContext *context;
+	GError *error = NULL;
+	if(!g_file_get_contents(filename, &contents, &length, &error)) {
+		debug_printf("error reading blist: %s\n", error->message);
+		g_error_free(error);
+		return FALSE;
+	}
+
+	context = g_markup_parse_context_new(&blist_parser, 0, NULL, NULL);
+
+	if(!g_markup_parse_context_parse(context, contents, length, NULL)) {
+		g_markup_parse_context_free(context);
+		return FALSE;
+	}
+
+	if(!g_markup_parse_context_end_parse(context, NULL)) {
+		debug_printf("error parsing blist\n");
+		g_markup_parse_context_free(context);
+		return FALSE;
+	}
+
+	g_markup_parse_context_free(context);
+	return TRUE;
+}
+
+void gaim_blist_load() {
+	GSList *accts;
+	char *user_dir = gaim_user_dir();
+	char *filename;
+	char *msg;
+
+	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)) {
+			msg = g_strdup_printf(_("An error was encountered parsing your "
+						"buddy list.  It has not been loaded."));
+			do_error_dialog(_("Buddy List Error"), msg, GAIM_ERROR);
+			g_free(msg);
+		}
+	} else {
+		/* rob wants to inform the user that their buddy lists are
+		 * being converted */
+		msg = g_strdup_printf(_("Gaim is converting your old buddy lists "
+					"to a new format, which will now be located at %s"),
+				filename);
+		do_error_dialog(_("Converting Buddy List"), msg, GAIM_INFO);
+		g_free(msg);
+
+		/* now, let gtk actually display the dialog before we start anything */
+		while(gtk_events_pending())
+			gtk_main_iteration();
+
+		/* read in the old lists, then save to the new format */
+		for(accts = aim_users; accts; accts = accts->next) {
+			do_import(accts->data, NULL);
+		}
+		gaim_blist_save();
+	}
+
+	g_free(filename);
+}
+
+static void blist_print_buddy_settings(gpointer key, gpointer data,
+		gpointer user_data) {
+	char *key_val = g_markup_escape_text(key, -1);
+	char *data_val = g_markup_escape_text(data, -1);
+	FILE *file = user_data;
+	fprintf(file, "\t\t\t\t\t<setting name=\"%s\">%s</setting>\n", key_val,
+			data_val);
+	g_free(key_val);
+	g_free(data_val);
+}
+
+static void gaim_blist_write(FILE *file, struct aim_user *user) {
+	GSList *grps, *buds, *users;
+	fprintf(file, "<?xml version='1.0' encoding='UTF-8' ?>\n");
+	fprintf(file, "<gaim version=\"1\">\n");
+	fprintf(file, "\t<blist>\n");
+
+	for(grps = groups; grps; grps = grps->next) {
+		struct group *g = grps->data;
+		if(!user || gaim_group_on_account(g, user)) {
+			char *group_name = g_markup_escape_text(g->name, -1);
+			fprintf(file, "\t\t<group name=\"%s\">\n", group_name);
+			for(buds = g->members; buds; buds = buds->next) {
+				struct buddy *b = buds->data;
+				if(!user || b->user == user) {
+					char *bud_name = g_markup_escape_text(b->name, -1);
+					char *bud_alias = NULL;
+					char *acct_name = g_markup_escape_text(b->user->username, -1);
+					if(b->alias[0])
+						bud_alias= g_markup_escape_text(b->alias, -1);
+					fprintf(file, "\t\t\t<person name=\"%s\">\n",
+							bud_alias ? bud_alias : bud_name);
+					fprintf(file, "\t\t\t\t<buddy protocol=\"%d\" "
+							"account=\"%s\">\n", b->user->protocol,
+							acct_name);
+					fprintf(file, "\t\t\t\t\t<name>%s</name>\n", bud_name);
+					if(bud_alias) {
+						fprintf(file, "\t\t\t\t\t<alias>%s</alias>\n",
+								bud_alias);
+					}
+					g_hash_table_foreach(b->settings,
+							blist_print_buddy_settings, file);
+					fprintf(file, "\t\t\t\t</buddy>\n");
+					fprintf(file, "\t\t\t</person>\n");
+					g_free(bud_name);
+					g_free(bud_alias);
+					g_free(acct_name);
+				}
+			}
+			fprintf(file, "\t\t</group>\n");
+			g_free(group_name);
+		}
+	}
+
+	fprintf(file, "\t</blist>\n");
+	fprintf(file, "\t<privacy>\n");
+
+	for(users = aim_users; users; users = users->next) {
+		struct aim_user *usr = users->data;
+		char *acct_name = g_markup_escape_text(usr->username, -1);
+		if(!user || usr == user) {
+			fprintf(file, "\t\t<account protocol=\"%d\" name=\"%s\" "
+					"mode=\"%d\">\n", usr->protocol, acct_name, usr->permdeny);
+			for(buds = usr->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 = usr->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);
+			}
+			fprintf(file, "\t\t</account>\n");
+		}
+	}
+
+	fprintf(file, "\t</privacy>\n");
+	fprintf(file, "</gaim>\n");
+}
+
+void gaim_blist_save() {
+	FILE *file;
+	char *user_dir = gaim_user_dir();
+	char *filename;
+
+	if(!user_dir)
+		return;
+
+	file = fopen(user_dir, "r");
+	if(!file)
+		mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR);
+	else
+		fclose(file);
+
+	filename = g_build_filename(user_dir, "blist.xml", NULL);
+
+	if((file = fopen(filename, "w"))) {
+		gaim_blist_write(file, NULL);
+		fclose(file);
+		chmod(filename, S_IRUSR | S_IWUSR);
+	} else {
+		debug_printf("unable to write %s\n", filename);
+	}
+
+	g_free(filename);
+}
+
+gboolean gaim_privacy_permit_add(struct aim_user *user, const char *who) {
+	GSList *d = user->permit;
+	char *n = g_strdup(normalize(who));
+	while(d) {
+		if(!g_strcasecmp(n, normalize(d->data)))
+			break;
+		d = d->next;
+	}
+	g_free(n);
+	if(!d) {
+		user->permit = g_slist_append(user->permit, g_strdup(who));
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+gboolean gaim_privacy_permit_remove(struct aim_user *user, const char *who) {
+	GSList *d = user->permit;
+	char *n = g_strdup(normalize(who));
+	while(d) {
+		if(!g_strcasecmp(n, normalize(d->data)))
+			break;
+		d = d->next;
+	}
+	g_free(n);
+	if(d) {
+		user->permit = g_slist_remove(user->permit, d->data);
+		g_free(d->data);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+gboolean gaim_privacy_deny_add(struct aim_user *user, const char *who) {
+	GSList *d = user->deny;
+	char *n = g_strdup(normalize(who));
+	while(d) {
+		if(!g_strcasecmp(n, normalize(d->data)))
+			break;
+		d = d->next;
+	}
+	g_free(n);
+	if(!d) {
+		user->deny = g_slist_append(user->deny, g_strdup(who));
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+gboolean gaim_privacy_deny_remove(struct aim_user *user, const char *who) {
+	GSList *d = user->deny;
+	char *n = g_strdup(normalize(who));
+	while(d) {
+		if(!g_strcasecmp(n, normalize(d->data)))
+			break;
+		d = d->next;
+	}
+	g_free(n);
+	if(d) {
+		user->deny = g_slist_remove(user->deny, d->data);
+		g_free(d->data);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+void gaim_buddy_set_setting(struct buddy *b, const char *key,
+		const char *value) {
+	if(!b)
+		return;
+	g_hash_table_replace(b->settings, g_strdup(key), g_strdup(value));
+}
+
+char *gaim_buddy_get_setting(struct buddy *b, const char *key) {
+	if(!b)
+		return NULL;
+	return g_strdup(g_hash_table_lookup(b->settings, key));
+}
--- a/src/multi.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/multi.c	Sun Jan 19 22:16:52 2003 +0000
@@ -86,9 +86,6 @@
 	gc->keepalive = 0;
 	gc->inpa = 0;
 	gc->buddy_chats = NULL;
-	gc->groups = NULL;
-	gc->permit = NULL;
-	gc->deny = NULL;
 	gc->away = NULL;
 	gc->away_state = NULL;
 
@@ -109,32 +106,21 @@
 
 void destroy_gaim_conn(struct gaim_connection *gc)
 {
-	GSList *g = gc->groups;
+	GSList *g = groups;
 	GSList *h;
 	struct group *m;
 	struct buddy *n;
 	while (g) {
 		m = (struct group *)g->data;
-		g = g_slist_remove(g, m);
+		g = g_slist_next(g);
 		h = m->members;
 		while (h) {
 			n = (struct buddy *)h->data;
-			if (gc->prpl->buddy_free)
-				gc->prpl->buddy_free(n);
-			h = g_slist_remove(h, n);
-			g_free(n);
+			h = g_slist_next(h);
+			if(n->user == gc->user) {
+				n->present = 0;
+			}
 		}
-		g_free(m);
-	}
-	g = gc->permit;
-	while (g) {
-		g_free(g->data);
-		g = g_slist_remove(g, g->data);
-	}
-	g = gc->deny;
-	while (g) {
-		g_free(g->data);
-		g = g_slist_remove(g, g->data);
 	}
 	g_free(gc->away);
 	g_free(gc->away_state);
@@ -1112,6 +1098,7 @@
 static void do_del_acct(struct aim_user *u)
 {
 	GtkTreeIter iter;
+	GSList *grps = groups, *buds;
 
 	if (u->gc) {
 		u->gc->wants_to_die = TRUE;
@@ -1122,7 +1109,33 @@
 		gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
 	}
 
+
+	/* remove the buddies for the account we just destroyed */
+	while(grps) {
+		struct group *g = grps->data;
+		grps = grps->next;
+		buds = g->members;
+		while(buds) {
+			struct buddy *b = buds->data;
+			buds = buds->next;
+			if(b->user == u) {
+				/* sigh, someday we'll get a central gaim_buddy_free() */
+				g->members = g_slist_remove(g->members, b);
+				g_hash_table_destroy(b->settings);
+				g_free(b);
+			}
+		}
+		if(!g->members) {
+			ui_remove_group(g);
+			groups = g_slist_remove(groups, g);
+			g_free(g);
+		}
+	}
+
 	aim_users = g_slist_remove(aim_users, u);
+
+	gaim_blist_save();
+
 	save_prefs();
 }
 
@@ -1320,6 +1333,8 @@
 {
 	struct signon_meter *meter = find_signon_meter(gc);
 	GtkTreeIter iter;
+	GSList *grps, *buds;
+	GList *add_buds=NULL;
 
 	/* Set the time the account came online */
 	time(&gc->login_time);
@@ -1341,6 +1356,7 @@
 	do_away_menu();
 	do_proto_menu();
 	redo_convo_menus();
+	redo_buddy_list();
 	gaim_setup(gc);
 
 	gc->user->connecting = FALSE;
@@ -1363,6 +1379,25 @@
 		opt_away_arg = NULL;
 	}
 
+	/* let the prpl know what buddies we pulled out of the local list */
+
+	for(grps = groups; grps; grps = grps->next) {
+		struct group *g = grps->data;
+		for(buds = g->members; buds; buds = buds->next) {
+			struct buddy *b = buds->data;
+			if(b->user->gc == gc) {
+				add_buds = g_list_append(add_buds, b->name);
+			}
+		}
+	}
+
+	if(add_buds) {
+		serv_add_buddies(gc, add_buds);
+		g_list_free(add_buds);
+	}
+
+	serv_set_permit_deny(gc);
+
 	/* everything for the account editor */
 	if (!acctedit)
 		return;
@@ -1658,7 +1693,6 @@
 
 	/* more UI stuff */
 	redo_buddy_list();
-	build_edit_tree();
 	do_away_menu();
 	do_proto_menu();
 	redo_convo_menus();
@@ -1681,6 +1715,8 @@
 	g_snprintf(u->user_info, sizeof(u->user_info), "%s", DEFAULT_INFO);
 	u->protocol = proto;
 	u->options = opts;
+	u->permit = NULL;
+	u->deny = NULL;
 	aim_users = g_slist_append(aim_users, u);
 
 	if (treeview) {
--- a/src/multi.h	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/multi.h	Sun Jan 19 22:16:52 2003 +0000
@@ -40,13 +40,6 @@
 	/* all connections need an input watcher */
 	int inpa;
 
-	/* buddy list stuff. there is still a global groups for the buddy list, but
-	 * we need to maintain our own set of buddies, and our own permit/deny lists */
-	GSList *groups;
-	GSList *permit;
-	GSList *deny;
-	int permdeny;
-
 	/* all connections need a list of chats, even if they don't have chat */
 	GSList *buddy_chats;
 
--- a/src/perl.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/perl.c	Sun Jan 19 22:16:52 2003 +0000
@@ -635,22 +635,21 @@
 	struct gaim_connection *gc;
 	struct buddy *buddy;
 	struct group *g;
-	GSList *list = NULL;
+	GSList *list = groups;
 	GSList *mem;
 	int i = 0;
 	dXSARGS;
 	items = 0;
 
 	gc = (struct gaim_connection *)SvIV(ST(0));
-	if (g_slist_find(connections, gc))
-		list = gc->groups;
 
 	while (list) {
 		g = (struct group *)list->data;
 		mem = g->members;
 		while (mem) {
 			buddy = (struct buddy *)mem->data;
-			XST_mPV(i++, buddy->name);
+			if(buddy->user->gc == gc)
+				XST_mPV(i++, buddy->name);
 			mem = mem->next;
 		}
 		list = g_slist_next(list);
@@ -663,22 +662,20 @@
 	struct gaim_connection *gc;
 	struct buddy *b;
 	struct group *g;
-	GSList *list = NULL;
+	GSList *list = groups;
 	GSList *mem;
 	int i = 0;
 	dXSARGS;
 	items = 0;
 
 	gc = (struct gaim_connection *)SvIV(ST(0));
-	if (g_slist_find(connections, gc))
-		list = gc->groups;
 
 	while (list) {
 		g = (struct group *)list->data;
 		mem = g->members;
 		while (mem) {
 			b = (struct buddy *)mem->data;
-			if (b->present) XST_mPV(i++, b->name);
+			if (b->user->gc == gc && b->present) XST_mPV(i++, b->name);
 			mem = mem->next;
 		}
 		list = g_slist_next(list);
@@ -747,7 +744,7 @@
 
 	gc = (struct gaim_connection *)SvIV(ST(0));
 	if (g_slist_find(connections, gc))
-		buddy = find_buddy(gc, SvPV(ST(1), junk));
+		buddy = find_buddy(gc->user, SvPV(ST(1), junk));
 
 	if (!buddy)
 		XSRETURN(0);
--- a/src/protocols/gg/gg.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/protocols/gg/gg.c	Sun Jan 19 22:16:52 2003 +0000
@@ -1,6 +1,6 @@
 /*
  * gaim - Gadu-Gadu Protocol Plugin
- * $Id: gg.c 4597 2003-01-18 01:58:00Z thekingant $
+ * $Id: gg.c 4614 2003-01-19 22:16:52Z faceprint $
  *
  * Copyright (C) 2001 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
  * 
@@ -129,7 +129,7 @@
 
 static gboolean allowed_uin(struct gaim_connection *gc, char *uin)
 {
-	switch (gc->permdeny) {
+	switch (gc->user->permdeny) {
 	case 1:
 		/* permit all, deny none */
 		return TRUE;
@@ -140,13 +140,13 @@
 		break;
 	case 3:
 		/* permit some. */
-		if (g_slist_find_custom(gc->permit, uin, args_compare))
+		if (g_slist_find_custom(gc->user->permit, uin, args_compare))
 			return TRUE;
 		return FALSE;
 		break;
 	case 4:
 		/* deny some. */
-		if (g_slist_find_custom(gc->deny, uin, args_compare))
+		if (g_slist_find_custom(gc->user->deny, uin, args_compare))
 			return FALSE;
 		return TRUE;
 		break;
@@ -277,7 +277,7 @@
 {
 	GList *m = NULL;
 	struct proto_buddy_menu *pbm;
-	struct buddy *b = find_buddy(gc, who);
+	struct buddy *b = find_buddy(gc->user, who);
 	static char buf[AGG_BUF_LEN];
 
 	if (!b) {
@@ -507,8 +507,6 @@
 		account_online(gc);
 		serv_finish_login(gc);
 
-		if (bud_list_cache_exists(gc))
-			do_import(gc, NULL);
 		break;
 	case GG_EVENT_CONN_FAILED:
 		gaim_input_remove(gc->inpa);
@@ -797,7 +795,7 @@
 		}
 
 		debug_printf("import_buddies_server_results: uin: %s\n", name);
-		if (!find_buddy(gc, name)) {
+		if (!find_buddy(gc->user, name)) {
 			/* Default group if none specified on server */
 			gchar *group = g_strdup("Gadu-Gadu");
 			if (strlen(data_tbl[5])) {
@@ -809,8 +807,8 @@
 				g_strfreev(group_tbl);
 			}
 			/* Add Buddy to our userlist */
-			add_buddy(gc, group, name, strlen(show) ? show : name);
-			do_export(gc);
+			add_buddy(gc->user, group, name, strlen(show) ? show : name);
+			gaim_blist_save();
 			g_free(group);
 		}
 		g_strfreev(data_tbl);
@@ -1003,7 +1001,7 @@
 	gchar *u = gg_urlencode(gc->username);
 	gchar *p = gg_urlencode(gc->password);
 
-	GSList *gr = gc->groups;
+	GSList *gr = groups;
 
 	he->gc = gc;
 	he->type = AGG_HTTP_USERLIST_EXPORT;
@@ -1019,26 +1017,28 @@
 		GSList *m = g->members;
 		while (m) {
 			struct buddy *b = m->data;
-			gchar *newdata;
-			/* GG Number */
-			gchar *name = gg_urlencode(b->name);
-			/* GG Pseudo */
-			gchar *show = gg_urlencode(b->alias[0] ? b->alias : b->name);
-			/* Group Name */
-			gchar *gname = gg_urlencode(g->name);
+
+			if(b->user->gc == gc) {
+				gchar *newdata;
+				/* GG Number */
+				gchar *name = gg_urlencode(b->name);
+				/* GG Pseudo */
+				gchar *show = gg_urlencode(b->alias[0] ? b->alias : b->name);
+				/* Group Name */
+				gchar *gname = gg_urlencode(g->name);
 
-			ptr = he->request;
-			newdata = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s\r\n",
-						  show, show, show, show, "", gname, name);
-			he->request = g_strconcat(ptr, newdata, NULL);
+				ptr = he->request;
+				newdata = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s\r\n",
+						show, show, show, show, "", gname, name);
+				he->request = g_strconcat(ptr, newdata, NULL);
 
-			g_free(newdata);
-			g_free(ptr);
+				g_free(newdata);
+				g_free(ptr);
 
-			g_free(gname);
-			g_free(show);
-			g_free(name);
-
+				g_free(gname);
+				g_free(show);
+				g_free(name);
+			}
 			m = g_slist_next(m);
 		}
 		gr = g_slist_next(gr);
@@ -1254,7 +1254,7 @@
 	/* It's implemented on client side because GG server doesn't support this */
 }
 
-static void agg_permit_deny_dummy(struct gaim_connection *gc, char *who)
+static void agg_permit_deny_dummy(struct gaim_connection *gc, const char *who)
 {
 	/* It's implemented on client side because GG server doesn't support this */
 }
--- a/src/protocols/icq/gaim_icq.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/protocols/icq/gaim_icq.c	Sun Jan 19 22:16:52 2003 +0000
@@ -274,7 +274,7 @@
 		icq_SendAuthMsg(iq->link, iq->uin);
 
 		g_snprintf(uin, sizeof(uin), "%ld", iq->uin);
-		if (find_buddy(iq->gc, uin))
+		if (find_buddy(iq->gc->user, uin))
 			return;
 
 		iqnew = g_memdup(iq, sizeof(struct icq_auth));
@@ -342,8 +342,6 @@
 		icq_SetProxy(link, proxyhost, proxyport, proxyuser[0], proxyuser, proxypass);
 
 	icq_ContactClear(id->link);
-	if (bud_list_cache_exists(gc))
-		do_import(gc, NULL);
 
 	if (icq_Connect(link, "icq.mirabilis.com", 4000) < 1) {
 		hide_login_progress(gc, "Unable to connect");
--- a/src/protocols/irc/irc.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/protocols/irc/irc.c	Sun Jan 19 22:16:52 2003 +0000
@@ -610,23 +610,25 @@
 		return;
 
 	g_strdown(id->str->str);
-	gr = gc->groups;
+	gr = groups;
 	while (gr) {
 		GSList *m = ((struct group *)gr->data)->members;
 		while (m) {
 			struct buddy *b = m->data;
-			char *tmp = g_strdup(b->name);
-			char *x, *l;
-			g_strdown(tmp);
-			x = strstr(id->str->str, tmp);
-			l = x + strlen(b->name);
-			if (x && (*l != ' ' && *l != 0))
-				x = 0;
-			if (!b->present && x)
-				serv_got_update(gc, b->name, 1, 0, 0, 0, 0, 0);
-			else if (b->present && !x)
-				serv_got_update(gc, b->name, 0, 0, 0, 0, 0, 0);
-			g_free(tmp);
+			if(b->user->gc == gc) {
+				char *tmp = g_strdup(b->name);
+				char *x, *l;
+				g_strdown(tmp);
+				x = strstr(id->str->str, tmp);
+				l = x + strlen(b->name);
+				if (x && (*l != ' ' && *l != 0))
+					x = 0;
+				if (!b->present && x)
+					serv_got_update(gc, b->name, 1, 0, 0, 0, 0, 0);
+				else if (b->present && !x)
+					serv_got_update(gc, b->name, 0, 0, 0, 0, 0, 0);
+				g_free(tmp);
+			}
 			m = m->next;
 		}
 		gr = gr->next;
@@ -643,7 +645,7 @@
 	char buf[500];
 	int n = g_snprintf(buf, sizeof(buf), "ISON");
 
-	GSList *gr = gc->groups;
+	GSList *gr = groups;
 	if (!gr || id->bc)
 		return TRUE;
 
@@ -652,13 +654,15 @@
 		GSList *m = g->members;
 		while (m) {
 			struct buddy *b = m->data;
-			if (n + strlen(b->name) + 2 > sizeof(buf)) {
-				g_snprintf(buf + n, sizeof(buf) - n, "\r\n");
-				irc_write(id->fd, buf, n);
-				id->bc++;
-				n = g_snprintf(buf, sizeof(buf), "ISON");
+			if(b->user->gc == gc) {
+				if (n + strlen(b->name) + 2 > sizeof(buf)) {
+					g_snprintf(buf + n, sizeof(buf) - n, "\r\n");
+					irc_write(id->fd, buf, n);
+					id->bc++;
+					n = g_snprintf(buf, sizeof(buf), "ISON");
+				}
+				n += g_snprintf(buf + n, sizeof(buf) - n, " %s", b->name);
 			}
-			n += g_snprintf(buf + n, sizeof(buf) - n, " %s", b->name);
 			m = m->next;
 		}
 		gr = gr->next;
@@ -1321,9 +1325,6 @@
 		account_online(gc);
 		serv_finish_login(gc);
 
-		if (bud_list_cache_exists(gc))
-			do_import(gc, NULL);
-
 		/* we don't call this now because otherwise some IRC servers might not like us */
 		idata->timer = g_timeout_add(20000, irc_request_buddy_update, gc);
 		idata->online = TRUE;
--- a/src/protocols/jabber/jabber.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/protocols/jabber/jabber.c	Sun Jan 19 22:16:52 2003 +0000
@@ -957,13 +957,10 @@
 {
 	struct buddy *b;
 
-	if ((b = find_buddy(gc, buddyname)) != NULL) {
-		struct group *group;
-
-		group = find_group_by_buddy(gc, buddyname);
-		debug_printf("removing buddy [1]: %s, from group: %s\n", buddyname, group->name);
-		remove_buddy(gc, group, b);
-		do_export(gc);
+	if ((b = find_buddy(gc->user, buddyname)) != NULL) {
+		debug_printf("removing buddy [1]: %s\n", buddyname);
+		remove_buddy(b);
+		gaim_blist_save();
 	}
 }
 
@@ -1511,7 +1508,7 @@
 			jc->b = cnv = serv_got_joined_chat(GJ_GC(gjc), i++, gjid->user);
 			jc->id = jc->b->id;
 			jc->state = JCS_ACTIVE;
-		} else if ((b = find_buddy(GJ_GC(gjc), buddy)) == NULL) {
+		} else if ((b = find_buddy(GJ_GC(gjc)->user, buddy)) == NULL) {
 			g_free(buddy);
 			gaim_jid_free(gjid);
 			return;
@@ -1615,7 +1612,7 @@
 		 * If we don't already have the buddy on *our* buddylist,
 		 * ask if we want him or her added.
 		 */
-		if(find_buddy(jap->gc, jap->user) == NULL) {
+		if(find_buddy(jap->gc->user, jap->user) == NULL) {
 			show_got_added(jap->gc, NULL, jap->user, NULL, NULL);
 		}
 	}
@@ -1762,13 +1759,13 @@
 	 * Add or remove a buddy?  Change buddy's alias or group?
 	 */
 	if (BUD_SUB_TO_PEND(sub, ask) || BUD_SUBD_TO(sub, ask)) {
-		if ((b = find_buddy(GJ_GC(gjc), buddyname)) == NULL) {
+		if ((b = find_buddy(GJ_GC(gjc)->user, buddyname)) == NULL) {
 			debug_printf("adding buddy [4]: %s\n", buddyname);
-			b = add_buddy(GJ_GC(gjc), groupname ? groupname : _("Buddies"), buddyname,
+			b = add_buddy(GJ_GC(gjc)->user, groupname ? groupname : _("Buddies"), buddyname,
 				name ? name : buddyname);
-			do_export(GJ_GC(gjc));
+			gaim_blist_save();
 		} else {
-			struct group *c_grp = find_group_by_buddy(GJ_GC(gjc), buddyname);
+			struct group *c_grp = find_group_by_buddy(b);
 
 			/*
 			 * If the buddy's in a new group or his/her alias is changed...
@@ -1782,10 +1779,10 @@
 				/*
 				 * seems rude, but it seems to be the only way...
 				 */
-				remove_buddy(GJ_GC(gjc), c_grp, b);
-				b = add_buddy(GJ_GC(gjc), groupname, buddyname,
+				remove_buddy(b);
+				b = add_buddy(GJ_GC(gjc)->user, groupname, buddyname,
 					name ? name : buddyname);
-				do_export(GJ_GC(gjc));
+				gaim_blist_save();
 				if(present) {
 					serv_got_update(GJ_GC(gjc), buddyname, 1, 0, signon, idle,
 							uc, 0);
@@ -1793,7 +1790,7 @@
 			} else if(name != NULL && strcmp(b->alias, name)) {
 				g_snprintf(b->alias, sizeof(b->alias), "%s", name);
 				handle_buddy_rename(b, buddyname);
-				do_export(GJ_GC(gjc));
+				gaim_blist_save();
 			}
 		}
 	}  else if (BUD_USUB_TO_PEND(sub, ask) || BUD_USUBD_TO(sub, ask) || !strcasecmp(sub, "remove")) {
@@ -1836,9 +1833,6 @@
 			account_online(GJ_GC(gjc));
 			serv_finish_login(GJ_GC(gjc));
 
-			if (bud_list_cache_exists(GJ_GC(gjc)))
-				do_import(GJ_GC(gjc), NULL);
-
 			((struct jabber_data *)GJ_GC(gjc)->proto_data)->did_import = TRUE;
 
 			gjab_reqroster(gjc);
@@ -2528,13 +2522,15 @@
 		y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item");
 		xmlnode_put_attrib(y, "jid", realwho);
 
+		buddy = find_buddy(gc->user, realwho);
+
 		/*
 		 * See if there's an explict (new?) alias for the buddy or we can pull
 		 * one out of current Gaim buddylist data for him.
 		 */
 		if(alias && alias[0] != '\0') {
 			my_alias = alias;
-		} else if((buddy = find_buddy(gc, realwho)) != NULL && buddy->alias[0]) {
+		} else if(buddy && buddy->alias[0]) {
 			my_alias = buddy->alias;
 		}
 
@@ -2552,7 +2548,7 @@
 		 */
 		if(group && group[0] != '\0') {
 			my_group = group;
-		} else if((buddy_group = find_group_by_buddy(gc, realwho)) != NULL) {
+		} else if((buddy_group = find_group_by_buddy(buddy)) != NULL) {
 			my_group = buddy_group->name;
 		}
 
@@ -2929,7 +2925,7 @@
 		jc->gjid = gjid;
 		jc->gc = gc;
 		((struct jabber_data *)gc->proto_data)->chats = g_slist_append(jcs, jc);
-		add_buddy(gc, _("Chats"), realwho, realwho);
+		add_buddy(gc->user, _("Chats"), realwho, realwho);
 	}
 
 	jc->state = JCS_PENDING;
@@ -3231,7 +3227,7 @@
 static GList *jabber_buddy_menu(struct gaim_connection *gc, char *who) {
 	GList *m = NULL;
 	struct proto_buddy_menu *pbm;
-	struct buddy *b = find_buddy(gc, who);
+	struct buddy *b = find_buddy(gc->user, who);
 
 	if(b->uc == UC_ERROR)
 	{
--- a/src/protocols/msn/msn.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/protocols/msn/msn.c	Sun Jan 19 22:16:52 2003 +0000
@@ -488,7 +488,7 @@
 			struct conversation *cnv;
 			struct buddy *b;
 
-			if ((b = find_buddy(gc, user)) != NULL)
+			if ((b = find_buddy(gc->user, user)) != NULL)
 				username = get_buddy_alias(b);
 			else
 				username = user;
@@ -1083,7 +1083,7 @@
 			signoff(map->gc);
 			return;
 		}
-		map->gc->permit = g_slist_append(map->gc->permit, map->user);
+		gaim_privacy_permit_add(map->gc->user, map->user);
 		build_allow_list(); /* er. right. we'll need to have a thing for this in CUI too */
 		show_got_added(map->gc, NULL, map->user, map->friend, NULL);
 	}
@@ -1105,7 +1105,7 @@
 			signoff(map->gc);
 			return;
 		}
-		map->gc->deny = g_slist_append(map->gc->deny, map->user);
+		gaim_privacy_deny_add(map->gc->user, map->user);
 		build_block_list();
 	}
 
@@ -1122,7 +1122,7 @@
 	if (!g_strncasecmp(buf, "ADD", 3)) {
 		char *list, *user, *friend, *tmp = buf;
 		struct msn_add_permit *ap;
-		GSList *perm = gc->permit;
+		GSList *perm = gc->user->permit;
 		char msg[MSN_BUF_LEN];
 
 		GET_NEXT(tmp);
@@ -1167,14 +1167,14 @@
 			 * from users who are not in BL will be delivered
 			 *
 			 * In other words, deny some */
-			gc->permdeny = DENY_SOME;
+			gc->user->permdeny = DENY_SOME;
 		} else {
 			/* If the current
 			 * setting is BL, only messages from people who are in the AL will be
 			 * delivered.
-			 * 
+			 *
 			 * In other words, permit some */
-			gc->permdeny = PERMIT_SOME;
+			gc->user->permdeny = PERMIT_SOME;
 		}
 	} else if (!g_strncasecmp(buf, "BPR", 3)) {
 	} else if (!g_strncasecmp(buf, "CHG", 3)) {
@@ -1247,8 +1247,8 @@
 	} else if (!g_strncasecmp(buf, "LST", 3)) {
 		char *which, *who, *friend, *tmp = buf;
 		struct msn_add_permit *ap; /* for any as yet undealt with buddies who've added you to their buddy list when you were off-line.  How dare they! */
-		GSList *perm = gc->permit; /* current permit list */
-		GSList *denyl = gc->deny;
+		GSList *perm = gc->user->permit; /* current permit list */
+		GSList *denyl = gc->user->deny;
 		char msg[MSN_BUF_LEN];
 		int new = 1;
 		int pos, tot;
@@ -1274,15 +1274,14 @@
 			b->friend = g_strdup(friend);
 			md->fl = g_slist_append(md->fl, b);
 		} else if (!g_strcasecmp(which, "AL") && pos) {
-			char *dupl;
-			if ((dupl = (char *)g_slist_find_custom(gc->deny, who, 
-							(GCompareFunc)strcmp))) {
+			if (g_slist_find_custom(gc->user->deny, who,
+							(GCompareFunc)strcmp)) {
 				debug_printf("moving from deny to permit: %s", who);
-				gc->deny = g_slist_remove(gc->deny, dupl);
+				gaim_privacy_deny_remove(gc->user, who);
 			}
-			gc->permit = g_slist_append(gc->permit, g_strdup(who));
+			gaim_privacy_permit_add(gc->user, who);
 		} else if (!g_strcasecmp(which, "BL") && pos) {
-			gc->deny = g_slist_append(gc->deny, g_strdup(who));
+			gaim_privacy_deny_remove(gc->user, who);
 		} else if (!g_strcasecmp(which, "RL")) {
 		    if (pos) {
 			while(perm) {
@@ -1320,25 +1319,15 @@
 			account_online(gc);
 			serv_finish_login(gc);
 
-			md->permit = g_slist_copy(gc->permit);
-			md->deny = g_slist_copy(gc->deny);
-
-			if (bud_list_cache_exists(gc))
-				do_import(gc, NULL);
-			else {
-				g_snprintf(sendbuf, sizeof(sendbuf), "BLP %u AL\r\n", ++md->trId);
-				if (msn_write(md->fd, sendbuf, strlen(sendbuf)) < 0) {
-					hide_login_progress(gc, _("Unable to write"));
-					signoff(gc);
-					return 0;
-				}
-			}
+			md->permit = g_slist_copy(gc->user->permit);
+			md->deny = g_slist_copy(gc->user->deny);
+
 			while (md->fl) {
 				struct msn_buddy *mb = md->fl->data;
-				struct buddy *b = find_buddy(gc, mb->user);
+				struct buddy *b = find_buddy(gc->user, mb->user);
 				md->fl = g_slist_remove(md->fl, mb);
 				if(!b)
-					b = add_buddy(gc, _("Buddies"), mb->user, NULL);
+					b = add_buddy(gc->user, _("Buddies"), mb->user, NULL);
 				serv_got_alias(gc, mb->user, mb->friend);
 				g_free(mb->user);
 				g_free(mb->friend);
@@ -2458,7 +2447,7 @@
 {
 	GList *m = NULL;
 	struct proto_buddy_menu *pbm;
-	struct buddy *b = find_buddy(gc, who);
+	struct buddy *b = find_buddy(gc->user, who);
 	static char buf[MSN_BUF_LEN];
 
 	pbm = g_new0(struct proto_buddy_menu, 1);
@@ -2604,7 +2593,7 @@
 	char buf[MSN_BUF_LEN];
 	GSList *s, *t = NULL;
 
-	if (gc->permdeny == PERMIT_ALL || gc->permdeny == DENY_SOME)
+	if (gc->user->permdeny == PERMIT_ALL || gc->user->permdeny == DENY_SOME)
 		g_snprintf(buf, sizeof(buf), "BLP %u AL\r\n", ++md->trId);
 	else
 		g_snprintf(buf, sizeof(buf), "BLP %u BL\r\n", ++md->trId);
@@ -2618,11 +2607,11 @@
 	/* this is safe because we'll always come here after we've gotten the list off the server,
 	 * and data is never removed. So if the lengths are equal we don't know about anyone locally
 	 * and so there's no sense in going through them all. */
-	if (g_slist_length(gc->permit) == g_slist_length(md->permit)) {
+	if (g_slist_length(gc->user->permit) == g_slist_length(md->permit)) {
 		g_slist_free(md->permit);
 		md->permit = NULL;
 	}
-	if (g_slist_length(gc->deny) == g_slist_length(md->deny)) {
+	if (g_slist_length(gc->user->deny) == g_slist_length(md->deny)) {
 		g_slist_free(md->deny);
 		md->deny = NULL;
 	}
@@ -2630,16 +2619,15 @@
 		return;
 
 	if (md->permit) {
-		s = g_slist_nth(gc->permit, g_slist_length(md->permit));
+		s = g_slist_nth(gc->user->permit, g_slist_length(md->permit));
 		while (s) {
 			char *who = s->data;
-			char *dupl;
 			s = s->next;
 			if (!strchr(who, '@')) {
 				t = g_slist_append(t, who);
 				continue;
 			}
-			if ((dupl = (char *)g_slist_find(md->deny, who))) {
+			if (g_slist_find(md->deny, who)) {
 				t = g_slist_append(t, who);
 				continue;
 			}
@@ -2651,9 +2639,7 @@
 			}
 		}
 		while (t) {
-			char *who = t->data;
-			gc->permit = g_slist_remove(gc->permit, who);
-			g_free(who);
+			gaim_privacy_permit_remove(gc->user, t->data);
 			t = t->next;
 		}
 		if (t)
@@ -2664,16 +2650,15 @@
 	}
 	
 	if (md->deny) {
-		s = g_slist_nth(gc->deny, g_slist_length(md->deny));
+		s = g_slist_nth(gc->user->deny, g_slist_length(md->deny));
 		while (s) {
 			char *who = s->data;
-			char *dupl;
 			s = s->next;
 			if (!strchr(who, '@')) {
 				t = g_slist_append(t, who);
 				continue;
 			}
-			if ((dupl = (char *)g_slist_find(md->deny, who))) {
+			if (g_slist_find(md->deny, who)) {
 				t = g_slist_append(t, who);
 				continue;
 			}
@@ -2685,9 +2670,7 @@
 			}
 		}
 		while (t) {
-			char *who = t->data;
-			gc->deny = g_slist_remove(gc->deny, who);
-			g_free(who);
+			gaim_privacy_deny_remove(gc->user, t->data);
 			t = t->next;
 		}
 		if (t)
@@ -2697,11 +2680,10 @@
 	}
 }
 
-static void msn_add_permit(struct gaim_connection *gc, char *who)
+static void msn_add_permit(struct gaim_connection *gc, const char *who)
 {
 	struct msn_data *md = gc->proto_data;
 	char buf[MSN_BUF_LEN];
-	char *dupl;
 
 	if (!strchr(who, '@')) {
 		g_snprintf(buf, sizeof(buf), 
@@ -2709,15 +2691,13 @@
 			     "Perhaps you meant %s@hotmail.com.  No changes were made to your "
 			     "allow list."), who);
 		do_error_dialog(_("Invalid MSN screenname"), buf, GAIM_ERROR);
-		gc->permit = g_slist_remove(gc->permit, who);
-		g_free(who);
+		gaim_privacy_permit_remove(gc->user, who);
 		return;
 	}
 
-	if ((dupl = (char *)g_slist_find_custom(gc->deny, who, 
-					(GCompareFunc)strcmp))) {
+	if (g_slist_find_custom(gc->user->deny, who, (GCompareFunc)strcmp)) {
 		debug_printf("MSN: Moving %s from BL to AL\n", who);
-		gc->deny = g_slist_remove(gc->deny, dupl);
+		gaim_privacy_deny_remove(gc->user, who);
 		g_snprintf(buf, sizeof(buf), "REM %u BL %s\r\n", ++md->trId, who);
 			if (msn_write(md->fd, buf, strlen(buf)) < 0) {
 				hide_login_progress(gc, _("Write error"));
@@ -2733,7 +2713,7 @@
 	}
 }
 
-static void msn_rem_permit(struct gaim_connection *gc, char *who)
+static void msn_rem_permit(struct gaim_connection *gc, const char *who)
 {
 	struct msn_data *md = gc->proto_data;
 	char buf[MSN_BUF_LEN];
@@ -2744,8 +2724,8 @@
 		signoff(gc);
 		return;
 	}
-	
-	g_slist_append(gc->deny, who);
+
+	gaim_privacy_deny_add(gc->user, who);
 	g_snprintf(buf, sizeof(buf), "ADD %u BL %s %s\r\n", ++md->trId, who, who);
 	if (msn_write(md->fd, buf, strlen(buf)) < 0) {
 		hide_login_progress(gc, _("Write error"));
@@ -2754,27 +2734,24 @@
 	}
 }
 
-static void msn_add_deny(struct gaim_connection *gc, char *who)
+static void msn_add_deny(struct gaim_connection *gc, const char *who)
 {
 	struct msn_data *md = gc->proto_data;
 	char buf[MSN_BUF_LEN];
-	char *dupl;
-	
+
 	if (!strchr(who, '@')) {
 		g_snprintf(buf, sizeof(buf), 
 			   _("An MSN screenname must be in the form \"user@server.com\".  "
 			     "Perhaps you meant %s@hotmail.com.  No changes were made to your "
 			     "block list."), who);
 		do_error_dialog(_("Invalid MSN screenname"), buf, GAIM_ERROR);
-		gc->deny = g_slist_remove(gc->deny, who);
-		g_free(who);
+		gaim_privacy_deny_remove(gc->user, who);
 		return;
 	}
 
-	if ((dupl = (char *)g_slist_find_custom(gc->permit, who, 
-					(GCompareFunc)strcmp))) {
+	if (g_slist_find_custom(gc->user->permit, who, (GCompareFunc)strcmp)) {
 		debug_printf("MSN: Moving %s from AL to BL\n", who);
-		gc->permit = g_slist_remove(gc->permit, dupl);
+		gaim_privacy_permit_remove(gc->user, who);
 		g_snprintf(buf, sizeof(buf), "REM %u AL %s\r\n", ++md->trId, who);
 		if (msn_write(md->fd, buf, strlen(buf)) < 0) {
 			hide_login_progress(gc, _("Write error"));
@@ -2782,7 +2759,7 @@
 			return;
 		}
 	}
-		
+
 
 	g_snprintf(buf, sizeof(buf), "ADD %u BL %s %s\r\n", ++md->trId, who, who);
 	if (msn_write(md->fd, buf, strlen(buf)) < 0) {
@@ -2792,7 +2769,7 @@
 	}
 }
 
-static void msn_rem_deny(struct gaim_connection *gc, char *who)
+static void msn_rem_deny(struct gaim_connection *gc, const char *who)
 {
 	struct msn_data *md = gc->proto_data;
 	char buf[MSN_BUF_LEN];
@@ -2803,8 +2780,8 @@
 		signoff(gc);
 		return;
 	}
-	
-	g_slist_append(gc->permit, who);
+
+	gaim_privacy_permit_add(gc->user, who);
 	g_snprintf(buf, sizeof(buf), "ADD %u AL %s %s\r\n", ++md->trId, who, who);
 	if (msn_write(md->fd, buf, strlen(buf)) < 0) {
 		hide_login_progress(gc, _("Write error"));
--- a/src/protocols/napster/napster.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/protocols/napster/napster.c	Sun Jan 19 22:16:52 2003 +0000
@@ -403,9 +403,6 @@
 		account_online(gc);
 		serv_finish_login(gc);
 
-		if (bud_list_cache_exists(gc))
-			do_import(gc, NULL);
-
 		return;
 	}
 }
--- a/src/protocols/oscar/oscar.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/protocols/oscar/oscar.c	Sun Jan 19 22:16:52 2003 +0000
@@ -642,10 +642,8 @@
 	if (isdigit(*user->username)) {
 		odata->icq = TRUE;
 		/* this is odd but it's necessary for a proper do_import and do_export */
-		gc->protocol = PROTO_ICQ;
 		gc->password[8] = 0;
 	} else {
-		gc->protocol = PROTO_TOC;
 		gc->flags |= OPT_CONN_HTML;
 		gc->flags |= OPT_CONN_AUTO_RESP;
 	}
@@ -2063,8 +2061,8 @@
 
 	if (g_slist_find(connections, gc)) {
 		struct oscar_data *od = gc->proto_data;
-		struct buddy *buddy = find_buddy(gc, data->name);
-		struct group *group = find_group_by_buddy(gc, data->name);
+		struct buddy *buddy = find_buddy(gc->user, data->name);
+		struct group *group = find_group_by_buddy(buddy);
 		if (buddy && group) {
 			debug_printf("ssi: adding buddy %s to group %s\n", buddy->name, group->name);
 			aim_ssi_sendauthrequest(od->sess, od->conn, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list."));
@@ -2094,7 +2092,7 @@
 	struct buddy *buddy;
 	gchar *dialog_msg, *nombre;
 
-	buddy = find_buddy(gc, name);
+	buddy = find_buddy(gc->user, name);
 	if (buddy && (get_buddy_alias_only(buddy)))
 		nombre = g_strdup_printf("%s (%s)", name, get_buddy_alias_only(buddy));
 	else
@@ -2120,7 +2118,7 @@
 		struct buddy *buddy;
 		gchar message;
 		message = 0;
-		buddy = find_buddy(gc, data->name);
+		buddy = find_buddy(gc->user, data->name);
 		aim_send_im_ch4(od->sess, data->name, AIM_ICQMSG_AUTHGRANTED, &message);
 		show_got_added(gc, NULL, data->name, (buddy ? get_buddy_alias_only(buddy) : NULL), NULL);
 #else
@@ -3321,9 +3319,6 @@
 	account_online(gc);
 	serv_finish_login(gc);
 
-	if (bud_list_cache_exists(gc))
-		do_import(gc, NULL);
-
 	debug_printf("buddy list loaded\n");
 
 	aim_clientready(sess, fr->conn);
@@ -3410,7 +3405,7 @@
 	 * parse-icq-status-message function knows if it is putting it's message in 
 	 * an info window because the name will _not_ be in od->evilhack.  For getting 
 	 * only the away message the contact's UIN is put in od->evilhack. */
-	if ((budlight = find_buddy(gc, who))) {
+	if ((budlight = find_buddy(gc->user, who))) {
 		if ((budlight->uc >> 16) & (AIM_ICQ_STATE_AWAY || AIM_ICQ_STATE_DND || AIM_ICQ_STATE_OUT || AIM_ICQ_STATE_BUSY || AIM_ICQ_STATE_CHAT)) {
 			if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
 				g_show_info_text(gc, who, 0, buf, NULL);
@@ -3776,7 +3771,7 @@
 static void oscar_get_away(struct gaim_connection *g, char *who) {
 	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
 	if (odata->icq) {
-		struct buddy *budlight = find_buddy(g, who);
+		struct buddy *budlight = find_buddy(g->user, who);
 		if (budlight)
 			if ((budlight->uc & 0xffff0000) >> 16)
 				if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
@@ -3909,13 +3904,14 @@
 	}
 
 	if (strcmp(state, _("Invisible"))) {
-		if (aim_ssi_getpermdeny(od->sess->ssi.local) != gc->permdeny)
-			aim_ssi_setpermdeny(od->sess, od->conn, gc->permdeny, 0xffffffff);
-		gc->permdeny = 4;
+		if (aim_ssi_getpermdeny(od->sess->ssi.local) != gc->user->permdeny)
+			aim_ssi_setpermdeny(od->sess, od->conn, gc->user->permdeny,
+					0xffffffff);
+		gc->user->permdeny = 4;
 	} else {
 		if (aim_ssi_getpermdeny(od->sess->ssi.local) != 0x03)
 			aim_ssi_setpermdeny(od->sess, od->conn, 0x03, 0xffffffff);
-		gc->permdeny = 3;
+		gc->user->permdeny = 3;
 	}
 
 	if (!strcmp(state, _("Online")))
@@ -3980,8 +3976,8 @@
 	aim_add_buddy(od->sess, od->conn, name);
 #else
 	if ((od->sess->ssi.received_data) && !(aim_ssi_itemlist_exists(od->sess->ssi.local, name))) {
-		struct buddy *buddy = find_buddy(gc, name);
-		struct group *group = find_group_by_buddy(gc, name);
+		struct buddy *buddy = find_buddy(gc->user, name);
+		struct group *group = find_group_by_buddy(buddy);
 		if (buddy && group) {
 			debug_printf("ssi: adding buddy %s to group %s\n", name, group->name);
 			aim_ssi_addbuddy(od->sess, od->conn, buddy->name, group->name, get_buddy_alias_only(buddy), NULL, NULL, 0);
@@ -4007,8 +4003,8 @@
 #else
 	if (od->sess->ssi.received_data) {
 		while (buddies) {
-			struct buddy *buddy = find_buddy(gc, (const char *)buddies->data);
-			struct group *group = find_group_by_buddy(gc, (const char *)buddies->data);
+			struct buddy *buddy = find_buddy(gc->user, (const char *)buddies->data);
+			struct group *group = find_group_by_buddy(buddy);
 			if (buddy && group) {
 				debug_printf("ssi: adding buddy %s to group %s\n", (const char *)buddies->data, group->name);
 				aim_ssi_addbuddy(od->sess, od->conn, buddy->name, group->name, get_buddy_alias_only(buddy), NULL, NULL, 0);
@@ -4140,14 +4136,14 @@
 				if (curitem->name) {
 					char *gname = aim_ssi_itemlist_findparentname(sess->ssi.local, curitem->name);
 					char *alias = aim_ssi_getalias(sess->ssi.local, gname, curitem->name);
-					struct buddy *buddy = find_buddy(gc, curitem->name);
+					struct buddy *buddy = find_buddy(gc->user, curitem->name);
 					if (buddy) {
 						/* Get server stored alias */
 						if (alias)
 							strcpy(buddy->alias, alias);
 					} else {
 						debug_printf("ssi: adding buddy %s to group %s to local list\n", curitem->name, gname);
-						add_buddy(gc, (gname ? gname : "orphans"), curitem->name, alias);
+						add_buddy(gc->user, (gname ? gname : "orphans"), curitem->name, alias);
 						tmp++;
 					}
 					free(alias);
@@ -4162,12 +4158,10 @@
 				if (curitem->name) {
 					/* if (!find_permdeny_by_name(gc->permit, curitem->name)) { AAA */
 					GSList *list;
-					for (list=gc->permit; (list && aim_sncmp(curitem->name, list->data)); list=list->next);
+					for (list=gc->user->permit; (list && aim_sncmp(curitem->name, list->data)); list=list->next);
 					if (!list) {
-						char *name;
 						debug_printf("ssi: adding permit buddy %s to local list\n", curitem->name);
-						name = g_strdup(normalize(curitem->name));
-						gc->permit = g_slist_append(gc->permit, name);
+						gaim_privacy_permit_add(gc->user, curitem->name);
 						build_allow_list();
 						tmp++;
 					}
@@ -4177,12 +4171,10 @@
 			case 0x0003: { /* Deny buddy */
 				if (curitem->name) {
 					GSList *list;
-					for (list=gc->deny; (list && aim_sncmp(curitem->name, list->data)); list=list->next);
+					for (list=gc->user->deny; (list && aim_sncmp(curitem->name, list->data)); list=list->next);
 					if (!list) {
-						char *name;
 						debug_printf("ssi: adding deny buddy %s to local list\n", curitem->name);
-						name = g_strdup(normalize(curitem->name));
-						gc->deny = g_slist_append(gc->deny, name);
+						gaim_privacy_deny_add(gc->user, curitem->name);
 						build_block_list();
 						tmp++;
 					}
@@ -4192,10 +4184,10 @@
 			case 0x0004: { /* Permit/deny setting */
 				if (curitem->data) {
 					fu8_t permdeny;
-					if ((permdeny = aim_ssi_getpermdeny(sess->ssi.local)) && (permdeny != gc->permdeny)) {
-						debug_printf("ssi: changing permdeny from %d to %hhu\n", gc->permdeny, permdeny);
-						gc->permdeny = permdeny;
-						if (od->icq && gc->permdeny == 0x03) {
+					if ((permdeny = aim_ssi_getpermdeny(sess->ssi.local)) && (permdeny != gc->user->permdeny)) {
+						debug_printf("ssi: changing permdeny from %d to %hhu\n", gc->user->permdeny, permdeny);
+						gc->user->permdeny = permdeny;
+						if (od->icq && gc->user->permdeny == 0x03) {
 							serv_set_away(gc, "Invisible", "");
 						}
 						tmp++;
@@ -4211,34 +4203,36 @@
 
 	/* If changes were made, then flush buddy list to file */
 	if (tmp)
-		do_export(gc);
+		gaim_blist_save();
 
 	/* Add from local list to server list */
 	if (gc) {
 		GSList *cur;
 
 		/* Buddies */
-		for (cur=gc->groups; cur; cur=g_slist_next(cur)) {
+		for (cur=groups; cur; cur=g_slist_next(cur)) {
 			GSList *curb;
 			struct group *group = cur->data;
 			for (curb=group->members; curb; curb=curb->next) {
 				struct buddy *buddy = curb->data;
-				if (aim_ssi_itemlist_exists(sess->ssi.local, buddy->name)) {
-					/* Store local alias on server */
-					char *alias = aim_ssi_getalias(sess->ssi.local, group->name, buddy->name);
-					if (!alias && buddy->alias[0])
-						aim_ssi_aliasbuddy(sess, od->conn, group->name, buddy->name, buddy->alias);
-					free(alias);
-				} else {
-					debug_printf("ssi: adding buddy %s from local list to server list\n", buddy->name);
-					aim_ssi_addbuddy(sess, od->conn, buddy->name, group->name, get_buddy_alias_only(buddy), NULL, NULL, 0);
+				if(buddy->user == gc->user) {
+					if (aim_ssi_itemlist_exists(sess->ssi.local, buddy->name)) {
+						/* Store local alias on server */
+						char *alias = aim_ssi_getalias(sess->ssi.local, group->name, buddy->name);
+						if (!alias && buddy->alias[0])
+							aim_ssi_aliasbuddy(sess, od->conn, group->name, buddy->name, buddy->alias);
+						free(alias);
+					} else {
+						debug_printf("ssi: adding buddy %s from local list to server list\n", buddy->name);
+						aim_ssi_addbuddy(sess, od->conn, buddy->name, group->name, get_buddy_alias_only(buddy), NULL, NULL, 0);
+					}
 				}
 			}
 		}
 
 		/* Permit list */
-		if (gc->permit) {
-			for (cur=gc->permit; cur; cur=cur->next)
+		if (gc->user->permit) {
+			for (cur=gc->user->permit; cur; cur=cur->next)
 				if (!aim_ssi_itemlist_finditem(sess->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
 					debug_printf("ssi: adding permit %s from local list to server list\n", (char *)cur->data);
 					aim_ssi_addpermit(sess, od->conn, cur->data);
@@ -4246,8 +4240,8 @@
 		}
 
 		/* Deny list */
-		if (gc->deny) {
-			for (cur=gc->deny; cur; cur=cur->next)
+		if (gc->user->deny) {
+			for (cur=gc->user->deny; cur; cur=cur->next)
 				if (!aim_ssi_itemlist_finditem(sess->ssi.local, NULL, cur->data, AIM_SSI_TYPE_DENY)) {
 					debug_printf("ssi: adding deny %s from local list to server list\n", (char *)cur->data);
 					aim_ssi_adddeny(sess, od->conn, cur->data);
@@ -4260,9 +4254,15 @@
 				aim_ssi_setpresence(sess, fr->conn, tmp | 0x400);
 
 		/* Check for maximum number of buddies */
-		for (cur=gc->groups, tmp=0; cur; cur=g_slist_next(cur)) {
+		for (cur=groups, tmp=0; cur; cur=g_slist_next(cur)) {
 			struct group* gr = (struct group*)cur->data;
-			tmp = tmp + g_slist_length(gr->members);
+			GSList *buds = gr->members;
+			while(buds) {
+				struct buddy *b = buds->data;
+				if(b->user == gc->user)
+					tmp++;
+				buds = buds->next;
+			}
 		}
 		if (tmp > od->rights.maxbuddies) {
 			char *dialog_msg = g_strdup_printf(_("The maximum number of buddies allowed in your buddy list is %d, and you have %d."
@@ -4332,7 +4332,7 @@
 
 	debug_printf("ssi: %s has given you permission to add him to your buddy list\n", sn);
 
-	buddy = find_buddy(gc, sn);
+	buddy = find_buddy(gc->user, sn);
 	if (buddy && (get_buddy_alias_only(buddy)))
 		nombre = g_strdup_printf("%s (%s)", sn, get_buddy_alias_only(buddy));
 	else
@@ -4366,7 +4366,7 @@
 
 	debug_printf("ssi: received authorization request from %s\n", sn);
 
-	buddy = find_buddy(gc, sn);
+	buddy = find_buddy(gc->user, sn);
 	if (buddy && (get_buddy_alias_only(buddy)))
 		nombre = g_strdup_printf("%s (%s)", sn, get_buddy_alias_only(buddy));
 	else
@@ -4401,7 +4401,7 @@
 
 	debug_printf("ssi: received authorization reply from %s.  Reply is 0x%04hhx\n", sn, reply);
 
-	buddy = find_buddy(gc, sn);
+	buddy = find_buddy(gc->user, sn);
 	if (buddy && (get_buddy_alias_only(buddy)))
 		nombre = g_strdup_printf("%s (%s)", sn, get_buddy_alias_only(buddy));
 	else
@@ -4432,7 +4432,7 @@
 	sn = va_arg(ap, char *);
 	va_end(ap);
 
-	buddy = find_buddy(gc, sn);
+	buddy = find_buddy(gc->user, sn);
 	debug_printf("ssi: %s added you to their buddy list\n", sn);
 	show_got_added(gc, NULL, sn, (buddy ? get_buddy_alias_only(buddy) : NULL), NULL);
 
@@ -4898,7 +4898,7 @@
 	struct oscar_data *od = gc->proto_data;
 	od->evilhack = g_slist_append(od->evilhack, g_strdup(normalize(who)));
 	if (od->icq) {
-		struct buddy *budlight = find_buddy(gc, who);
+		struct buddy *budlight = find_buddy(gc->user, who);
 		if (budlight)
 			if ((budlight->uc >> 16) & (AIM_ICQ_STATE_AWAY || AIM_ICQ_STATE_DND || AIM_ICQ_STATE_OUT || AIM_ICQ_STATE_BUSY || AIM_ICQ_STATE_CHAT))
 				if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
@@ -4930,7 +4930,7 @@
 	char buf[MAXMSGLEN];
 	int at;
 
-	switch(gc->permdeny) {
+	switch(gc->user->permdeny) {
 	case 1:
 		aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_DENYADD, gc->username);
 		break;
@@ -4956,16 +4956,18 @@
 		aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_DENYADD, buf);
 		break;
 	case 5:
-		g = gc->groups;
+		g = groups;
 		at = 0;
 		while (g) {
-		        list = ((struct group *)g->data)->members;
+			list = ((struct group *)g->data)->members;
 			while (list) {
-				at += g_snprintf(buf + at, sizeof(buf) - at, "%s&", ((struct buddy *)list->data)->name);
+				struct buddy *b = list->data;
+				if(b->user == gc->user)
+					at += g_snprintf(buf + at, sizeof(buf) - at, "%s&", b->name);
 				list = list->next;
 			}
 			g = g->next;
-		}			
+		}
 		aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_PERMITADD, buf);
 		break;
 	default:
@@ -4974,13 +4976,13 @@
 	signoff_blocked(gc);
 #else
 	if (od->sess->ssi.received_data)
-		aim_ssi_setpermdeny(od->sess, od->conn, gc->permdeny, 0xffffffff);
+		aim_ssi_setpermdeny(od->sess, od->conn, gc->user->permdeny, 0xffffffff);
 #endif
 }
 
-static void oscar_add_permit(struct gaim_connection *gc, char *who) {
+static void oscar_add_permit(struct gaim_connection *gc, const char *who) {
 #ifdef NOSSI
-	if (gc->permdeny == 3)
+	if (gc->user->permdeny == 3)
 		oscar_set_permit_deny(gc);
 #else
 	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
@@ -4990,9 +4992,9 @@
 #endif
 }
 
-static void oscar_add_deny(struct gaim_connection *gc, char *who) {
+static void oscar_add_deny(struct gaim_connection *gc, const char *who) {
 #ifdef NOSSI
-	if (gc->permdeny == 4)
+	if (gc->user->permdeny == 4)
 		oscar_set_permit_deny(gc);
 #else
 	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
@@ -5002,9 +5004,9 @@
 #endif
 }
 
-static void oscar_rem_permit(struct gaim_connection *gc, char *who) {
+static void oscar_rem_permit(struct gaim_connection *gc, const char *who) {
 #ifdef NOSSI
-	if (gc->permdeny == 3)
+	if (gc->user->permdeny == 3)
 		oscar_set_permit_deny(gc);
 #else
 	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
@@ -5014,9 +5016,9 @@
 #endif
 }
 
-static void oscar_rem_deny(struct gaim_connection *gc, char *who) {
+static void oscar_rem_deny(struct gaim_connection *gc, const char *who) {
 #ifdef NOSSI
-	if (gc->permdeny == 4)
+	if (gc->user->permdeny == 4)
 		oscar_set_permit_deny(gc);
 #else
 	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
@@ -5196,11 +5198,11 @@
 
 	text = g_strdup(_("You are awaiting authorization from the following buddies:<BR>"));
 
-	for (curg=gc->groups; curg; curg=g_slist_next(curg)) {
+	for (curg=groups; curg; curg=g_slist_next(curg)) {
 		struct group *group = curg->data;
 		for (curb=group->members; curb; curb=g_slist_next(curb)) {
 			struct buddy *buddy = curb->data;
-			if (aim_ssi_waitingforauth(od->sess->ssi.local, group->name, buddy->name)) {
+			if (buddy->user == gc->user && aim_ssi_waitingforauth(od->sess->ssi.local, group->name, buddy->name)) {
 				if (get_buddy_alias_only(buddy))
 					nombre = g_strdup_printf(" %s (%s)", buddy->name, get_buddy_alias_only(buddy));
 				else
--- a/src/protocols/toc/toc.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/protocols/toc/toc.c	Sun Jan 19 22:16:52 2003 +0000
@@ -513,7 +513,6 @@
         case 983:
                 g_snprintf(buf, sizeof(buf), _("You have been connecting and disconnecting too frequently.  Wait ten minutes and try again.  If you continue to try, you will need to wait even longer."));
                 break;
-        case 989:
                 g_snprintf(buf, sizeof(buf), _("An unknown signon error has occurred: %s."), w);
                 break;
         default:
@@ -601,9 +600,6 @@
 		account_online(gc);
 		serv_finish_login(gc);
 
-		if (bud_list_cache_exists(gc))
-			do_import(gc, NULL);
-
 		/* Client sends TOC toc_init_done message */
 		debug_printf("* Client sends TOC toc_init_done message\n");
 		g_snprintf(snd, sizeof snd, "toc_init_done");
@@ -637,8 +633,6 @@
 				signoff(gc);
 				return;
 			}
-			if (bud_list_cache_exists(gc))
-				do_import(gc, NULL);
 			g_snprintf(snd, sizeof snd, "toc_init_done");
 			sflap_send(gc, snd, -1, TYPE_DATA);
 			do_error_dialog(_("TOC has come back from its pause. You may now send"
@@ -646,7 +640,7 @@
 		}
 	} else if (!strcasecmp(c, "CONFIG")) {
 		c = strtok(NULL, ":");
-		parse_toc_buddy_list(gc, c);
+		parse_toc_buddy_list(gc->user, c);
 	} else if (!strcasecmp(c, "NICK")) {
 		/* ignore NICK so that things get imported/exported properly
 		c = strtok(NULL, ":");
@@ -995,7 +989,7 @@
 static void toc_set_config(struct gaim_connection *gc)
 {
 	char *buf = g_malloc(MSG_LEN), snd[BUF_LEN * 2];
-	toc_build_config(gc, buf, MSG_LEN - strlen("toc_set_config \\{\\}"), FALSE);
+	toc_build_config(gc->user, buf, MSG_LEN - strlen("toc_set_config \\{\\}"), FALSE);
 	g_snprintf(snd, MSG_LEN, "toc_set_config {%s}", buf);
 	sflap_send(gc, snd, -1, TYPE_DATA);
 	g_free(buf);
@@ -1272,10 +1266,10 @@
 	return m;
 }
 
-static void toc_add_permit(struct gaim_connection *gc, char *who)
+static void toc_add_permit(struct gaim_connection *gc, const char *who)
 {
 	char buf2[BUF_LEN * 2];
-	if (gc->permdeny != 3)
+	if (gc->user->permdeny != 3)
 		return;
 	g_snprintf(buf2, sizeof(buf2), "toc_add_permit %s", normalize(who));
 	sflap_send(gc, buf2, -1, TYPE_DATA);
@@ -1283,10 +1277,10 @@
 	signoff_blocked(gc);
 }
 
-static void toc_add_deny(struct gaim_connection *gc, char *who)
+static void toc_add_deny(struct gaim_connection *gc, const char *who)
 {
 	char buf2[BUF_LEN * 2];
-	if (gc->permdeny != 4)
+	if (gc->user->permdeny != 4)
 		return;
 	g_snprintf(buf2, sizeof(buf2), "toc_add_deny %s", normalize(who));
 	sflap_send(gc, buf2, -1, TYPE_DATA);
@@ -1300,7 +1294,7 @@
 	GSList *list;
 	int at;
 
-	switch (gc->permdeny) {
+	switch (gc->user->permdeny) {
 	case 1:
 		/* permit all, deny none. to get here reliably we need to have been in permit
 		 * mode, and send an empty toc_add_deny message, which will switch us to deny none */
@@ -1324,7 +1318,7 @@
 		sflap_send(gc, buf2, -1, TYPE_DATA);
 
 		at = g_snprintf(buf2, sizeof(buf2), "toc_add_permit ");
-		list = gc->permit;
+		list = gc->user->permit;
 		while (list) {
 			at += g_snprintf(buf2 + at, sizeof(buf2) - at, "%s ", normalize(list->data));
 			if (at > MSG_LEN + 32) {	/* from out my ass comes greatness */
@@ -1342,7 +1336,7 @@
 		sflap_send(gc, buf2, -1, TYPE_DATA);
 
 		at = g_snprintf(buf2, sizeof(buf2), "toc_add_deny ");
-		list = gc->deny;
+		list = gc->user->deny;
 		while (list) {
 			at += g_snprintf(buf2 + at, sizeof(buf2) - at, "%s ", normalize(list->data));
 			if (at > MSG_LEN + 32) {	/* from out my ass comes greatness */
@@ -1360,16 +1354,16 @@
 	signoff_blocked(gc);
 }
 
-static void toc_rem_permit(struct gaim_connection *gc, char *who)
+static void toc_rem_permit(struct gaim_connection *gc, const char *who)
 {
-	if (gc->permdeny != 3)
+	if (gc->user->permdeny != 3)
 		return;
 	toc_set_permit_deny(gc);
 }
 
-static void toc_rem_deny(struct gaim_connection *gc, char *who)
+static void toc_rem_deny(struct gaim_connection *gc, const char *who)
 {
-	if (gc->permdeny != 4)
+	if (gc->user->permdeny != 4)
 		return;
 	toc_set_permit_deny(gc);
 }
--- a/src/protocols/yahoo/yahoo.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/protocols/yahoo/yahoo.c	Sun Jan 19 22:16:52 2003 +0000
@@ -464,7 +464,6 @@
 		if (pair->key != 87)
 			continue;
 
-		do_import(gc, NULL);
 		lines = g_strsplit(pair->value, "\n", -1);
 		for (tmp = lines; *tmp; tmp++) {
 			split = g_strsplit(*tmp, ":", 2);
@@ -476,8 +475,8 @@
 			}
 			buddies = g_strsplit(split[1], ",", -1);
 			for (bud = buddies; bud && *bud; bud++)
-				if (!find_buddy(gc, *bud)) {
-					add_buddy(gc, split[0], *bud, *bud);
+				if (!find_buddy(gc->user, *bud)) {
+					add_buddy(gc->user, split[0], *bud, *bud);
 					export = TRUE;
 				}
 			g_strfreev(buddies);
@@ -487,7 +486,7 @@
 	}
 
 	if (export)
-		do_export(gc);
+		gaim_blist_save();
 }
 
 static void yahoo_process_notify(struct gaim_connection *gc, struct yahoo_packet *pkt)
@@ -520,7 +519,7 @@
 		else
 			serv_got_typing_stopped(gc, from);
 	} else if (!g_strncasecmp(msg, "GAME", strlen("GAME"))) {
-		struct buddy *bud = find_buddy(gc, from);
+		struct buddy *bud = find_buddy(gc->user, from);
 		void *free1=NULL, *free2=NULL;
 		if (!bud)
 			debug_printf("%s is playing a game, and doesn't want you to know.\n", from);
@@ -1070,7 +1069,7 @@
 	GList *m = NULL;
 	struct proto_buddy_menu *pbm;
 	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
-	struct buddy *b = find_buddy(gc, who); /* this should never be null. if it is,
+	struct buddy *b = find_buddy(gc->user, who); /* this should never be null. if it is,
 						  segfault and get the bug report. */
 	static char buf[1024];
 	static char buf2[1024];
@@ -1312,7 +1311,7 @@
 	if (!yd->logged_in)
 		return;
 
-	g = find_group_by_buddy(gc, who);
+	g = find_group_by_buddy(find_buddy(gc->user, who));
 	if (g)
 		group = g->name;
 	else
--- a/src/protocols/zephyr/zephyr.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/protocols/zephyr/zephyr.c	Sun Jan 19 22:16:52 2003 +0000
@@ -320,10 +320,10 @@
 
 			if (ZParseLocations(&notice, NULL, &nlocs, &user) != ZERR_NONE)
 				return;
-			if ((b = find_buddy(zgc, user)) == NULL) {
+			if ((b = find_buddy(zgc->user, user)) == NULL) {
 				char *e = strchr(user, '@');
 				if (e) *e = '\0';
-				b = find_buddy(zgc, user);
+				b = find_buddy(zgc->user, user);
 			}
 			if (!b) {
 				free(user);
@@ -445,18 +445,20 @@
 	memset(&(ald.uid), 0, sizeof(ZUnique_Id_t));
 	ald.version = NULL;
 
-	gr = zgc->groups;
+	gr = groups;
 	while (gr) {
 		struct group *g = gr->data;
 		m = g->members;
 		while (m) {
 			struct buddy *b = m->data;
-			char *chk;
-			chk = zephyr_normalize(b->name);
-			/* doesn't matter if this fails or not; we'll just move on to the next one */
-			ZRequestLocations(chk, &ald, UNACKED, ZAUTH);
-			free(ald.user);
-			free(ald.version);
+			if(b->user->gc == zgc) {
+				char *chk;
+				chk = zephyr_normalize(b->name);
+				/* doesn't matter if this fails or not; we'll just move on to the next one */
+				ZRequestLocations(chk, &ald, UNACKED, ZAUTH);
+				free(ald.user);
+				free(ald.version);
+			}
 			m = m->next;
 		}
 		gr = gr->next;
@@ -571,7 +573,7 @@
 		while (fgets(buff, BUFSIZ, fd)) {
 			strip_comments(buff);
 			if (buff[0])
-				add_buddy(zgc, "Anyone", buff, buff);
+				add_buddy(zgc->user, "Anyone", buff, buff);
 		}
 		fclose(fd);
 	}
@@ -606,8 +608,6 @@
 	account_online(zgc);
 	serv_finish_login(zgc);
 
-	if (bud_list_cache_exists(zgc))
-		do_import(zgc, NULL);
 	process_anyone();
 	process_zsubs();
 
@@ -667,24 +667,26 @@
 		return;
 	}
 
-	gr = zgc->groups;
+	gr = groups;
 	while (gr) {
 		g = gr->data;
 		m = g->members;
 		while (m) {
 			b = m->data;
-			if ((ptr = strchr(b->name, '@')) != NULL) {
-				ptr2 = ptr + 1;
-				/* We should only strip the realm name if the principal
-				   is in the user's realm
-				*/
-				if (!g_strcasecmp(ptr2,ZGetRealm())) {
-					*ptr = '\0';
+			if(b->user->gc == zgc) {
+				if ((ptr = strchr(b->name, '@')) != NULL) {
+					ptr2 = ptr + 1;
+					/* We should only strip the realm name if the principal
+					   is in the user's realm
+					   */
+					if (!g_strcasecmp(ptr2,ZGetRealm())) {
+						*ptr = '\0';
+					}
 				}
+				fprintf(fd, "%s\n", b->name);
+				if (ptr)
+					*ptr = '@';
 			}
-			fprintf(fd, "%s\n", b->name);
-			if (ptr)
-				*ptr = '@';
 			m = m->next;
 		}
 		gr = gr->next;
--- a/src/prpl.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/prpl.c	Sun Jan 19 22:16:52 2003 +0000
@@ -646,11 +646,13 @@
 {
 	char buf[BUF_LONG];
 	struct got_add *ga = g_new0(struct got_add, 1);
+	struct buddy *b = find_buddy(gc->user, who);
 
 	ga->gc = gc;
 	ga->who = g_strdup(who);
 	ga->alias = alias ? g_strdup(alias) : NULL;
 
+
 	g_snprintf(buf, sizeof(buf), _("%s%s%s%s has made %s his or her buddy%s%s%s"),
 		   who,
 		   alias ? " (" : "",
@@ -659,8 +661,8 @@
 		   id ? id : gc->displayname[0] ? gc->displayname : gc->username,
 		   msg ? ": " : ".",
 		   msg ? msg : "",
-		   find_buddy(gc, ga->who) ? "" : _("\n\nDo you wish to add him or her to your buddy list?"));
-	if (find_buddy(gc, ga->who))
+		   b ? "" : _("\n\nDo you wish to add him or her to your buddy list?"));
+	if (b)
 		do_error_dialog(_("Gaim - Information"), buf, GAIM_INFO);
 	else
 		do_ask_dialog(_("Gaim - Confirm"), buf, ga, _("Add"), do_add, _("Cancel"), dont_add, NULL, FALSE);
--- a/src/prpl.h	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/prpl.h	Sun Jan 19 22:16:52 2003 +0000
@@ -144,10 +144,10 @@
 	void (* add_buddies)	(struct gaim_connection *, GList *buddies);
 	void (* remove_buddy)	(struct gaim_connection *, char *name, char *group);
 	void (* remove_buddies)	(struct gaim_connection *, GList *buddies, const char *group);
-	void (* add_permit)	(struct gaim_connection *, char *name);
-	void (* add_deny)	(struct gaim_connection *, char *name);
-	void (* rem_permit)	(struct gaim_connection *, char *name);
-	void (* rem_deny)	(struct gaim_connection *, char *name);
+	void (* add_permit)	(struct gaim_connection *, const char *name);
+	void (* add_deny)	(struct gaim_connection *, const char *name);
+	void (* rem_permit)	(struct gaim_connection *, const char *name);
+	void (* rem_deny)	(struct gaim_connection *, const char *name);
 	void (* set_permit_deny)(struct gaim_connection *);
 	void (* warn)		(struct gaim_connection *, char *who, int anonymous);
 	void (* join_chat)	(struct gaim_connection *, GList *data);
--- a/src/server.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/server.c	Sun Jan 19 22:16:52 2003 +0000
@@ -333,13 +333,13 @@
  */
 void serv_alias_buddy(struct buddy *b)
 {
-	if(b && b->gc && b->gc->prpl && b->gc->prpl->alias_buddy) {
-		b->gc->prpl->alias_buddy(b->gc, b->name, b->alias);
+	if(b && b->user->gc && b->user->gc->prpl && b->user->gc->prpl->alias_buddy) {
+		b->user->gc->prpl->alias_buddy(b->user->gc, b->name, b->alias);
 	}
 }
 
 void serv_got_alias(struct gaim_connection *gc, char *who, char *alias) {
-	struct buddy *b = find_buddy(gc, who);
+	struct buddy *b = find_buddy(gc->user, who);
 	if(!b)
 		return;
 
@@ -359,14 +359,9 @@
  */
 void serv_move_buddy(struct buddy *b, struct group *og, struct group *ng)
 {
-	if(b && b->gc && og && og->gc && ng && ng->gc) {
-		/*
-		 * If there are no connection changes...
-		 */
-		if(b->gc == og->gc && b->gc == ng->gc && ng->gc == og->gc) {
-			if(b->gc->prpl && b->gc->prpl->group_buddy) {
-				b->gc->prpl->group_buddy(b->gc, b->name, og->name, ng->name);
-			}
+	if(b && b->user->gc && og && ng) {
+		if(b->user->gc->prpl && b->user->gc->prpl->group_buddy) {
+			b->user->gc->prpl->group_buddy(b->user->gc, b->name, og->name, ng->name);
 		}
 	}
 }
@@ -396,25 +391,25 @@
 	}
 }
 
-void serv_add_permit(struct gaim_connection *g, char *name)
+void serv_add_permit(struct gaim_connection *g, const char *name)
 {
 	if (g && g_slist_find(connections, g) && g->prpl && g->prpl->add_permit)
 		g->prpl->add_permit(g, name);
 }
 
-void serv_add_deny(struct gaim_connection *g, char *name)
+void serv_add_deny(struct gaim_connection *g, const char *name)
 {
 	if (g && g_slist_find(connections, g) && g->prpl && g->prpl->add_deny)
 		g->prpl->add_deny(g, name);
 }
 
-void serv_rem_permit(struct gaim_connection *g, char *name)
+void serv_rem_permit(struct gaim_connection *g, const char *name)
 {
 	if (g && g_slist_find(connections, g) && g->prpl && g->prpl->rem_permit)
 		g->prpl->rem_permit(g, name);
 }
 
-void serv_rem_deny(struct gaim_connection *g, char *name)
+void serv_rem_deny(struct gaim_connection *g, const char *name)
 {
 	if (g && g_slist_find(connections, g) && g->prpl && g->prpl->rem_deny)
 		g->prpl->rem_deny(g, name);
@@ -622,7 +617,7 @@
 	if (gc->away) {
 		time_t t;
 		char *tmpmsg;
-		struct buddy *b = find_buddy(gc, name);
+		struct buddy *b = find_buddy(gc->user, name);
 		char *alias = b ? get_buddy_alias(b) : name;
 		int row;
 		struct queued_away_response *qar;
@@ -787,7 +782,7 @@
 void serv_got_update(struct gaim_connection *gc, char *name, int loggedin, int evil, time_t signon,
 		     time_t idle, int type, guint caps)
 {
-	struct buddy *b = find_buddy(gc, name);
+	struct buddy *b = find_buddy(gc->user, name);
 
 	if (signon && (gc->prpl->options & OPT_PROTO_CORRECT_TIME)) {
 		char *tmp = g_strdup(normalize(name));
@@ -811,7 +806,7 @@
 		char *who = g_strdup(b->name);
 		g_snprintf(b->name, sizeof(b->name), "%s", name);
 		handle_buddy_rename(b, who);
-		do_export(b->gc);
+		gaim_blist_save();
 		g_free(who);
 	}
 
--- a/src/ui.h	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/ui.h	Sun Jan 19 22:16:52 2003 +0000
@@ -372,9 +372,9 @@
 extern void build_edit_tree();
 extern void do_bp_menu();
 extern void ui_add_buddy(struct gaim_connection *, struct group *, struct buddy *);
-extern void ui_remove_buddy(struct gaim_connection *, struct group *, struct buddy *);
-extern void ui_add_group(struct gaim_connection *, struct group *);
-extern void ui_remove_group(struct gaim_connection *, struct group *);
+extern void ui_remove_buddy(struct buddy *);
+extern void ui_add_group(struct group *);
+extern void ui_remove_group(struct group *);
 extern void toggle_buddy_pixmaps();
 extern void gaim_separator(GtkWidget *);
 extern void redo_buddy_list(); /* you really shouldn't call this function */
--- a/src/util.c	Sun Jan 19 22:03:57 2003 +0000
+++ b/src/util.c	Sun Jan 19 22:16:52 2003 +0000
@@ -960,7 +960,7 @@
 	   AIM account connected. */
 	while (conn) {
 		gc = conn->data;
-		if (gc->protocol == PROTO_TOC) {
+		if (gc->protocol == PROTO_OSCAR && isalpha(gc->username[0])) {
 			break;
 		}
 		conn = conn->next;