changeset 1030:38452403563b

[gaim-migrate @ 1040] updating the buddy list to work better with multiple connections. there are still a bunch of things fucked up with this but i wanted more people to start working on it than just me, especially since i won't be here this weekend. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Fri, 27 Oct 2000 07:53:32 +0000
parents 740c6f933fe0
children 6df117f1674d
files FIXME PRPL STATUS configure.in plugins/autorecon.c src/Makefile.am src/aim.c src/buddy.c src/buddy_chat.c src/conversation.c src/dialogs.c src/gaim.h src/gnome_applet_mgr.h src/idle.c src/multi.c src/multi.h src/oscar.c src/perl.c src/prefs.c src/prpl.h src/server.c src/toc.c src/util.c
diffstat 23 files changed, 914 insertions(+), 1417 deletions(-) [+]
line wrap: on
line diff
--- a/FIXME	Thu Oct 26 18:05:29 2000 +0000
+++ b/FIXME	Fri Oct 27 07:53:32 2000 +0000
@@ -1,19 +1,25 @@
 GAIM: Items to be fixed
 ------------------------
-Holy crap.
+This is just for the buddy list window now. Everything else is nearing completion.
 
-Take a deep breath.
+1. Enforce order. E.g. a buddy list looks like:
+	|-Buddies
+	|   |--EWarmenhoven
+	|   `--RobFlynn
+	`-Friends
+	    `--Zilding
 
-Holy Crap.
+   Need to enforce that Buddies comes before Friends, and EWarmenhoven comes before RobFlynn.
+   See appropriate FIXME comments in buddy.c.
 
-1. We need to modify the conversation window to state who you're sending messages as. The current way,
-   with the drop-down menu, is pretty crappy, though effective. (Perhaps just repositioning the menu?)
-2. We need to modify the buddy list to indicate which buddies belong to which connections. We also
-   need to modify the buddy list to vary the right-click menus on a per-conversation basis. (I.e. create
-   the menu based on which options the protocol supports.)
-3. We need to modify nearly every function in server.c to determine which connection to do things on.
-   The ones that still need to be modified have a FIXME comment in them.
-   3.1. We need to modify the UI to let the user indicate which account to do things on.
-4. We need to completely modify the plugin/perl system to account for multiple connections. SOMEWHAT DONE
+2. Need to make it so that when the buddy list is edited the main window properly reflects that.
+
+3. Need to modify the right-click menu for buddies, to include status for the buddy from each
+   connection that has it registered, and also to get available actions from each connection
+   that has it registered.
 
-And that's just the large things. There are countless trivial issues that need to be addressed.
+4. Need to get Aliases working again.
+
+5. Need to set number of buddies in group (as an option)
+
+6. Need to not hide empty groups (as an option)
--- a/PRPL	Thu Oct 26 18:05:29 2000 +0000
+++ b/PRPL	Fri Oct 27 07:53:32 2000 +0000
@@ -68,3 +68,33 @@
 Simply load the oscar.so file from the normal plugin window. This will set up everything necessary.
 You may unload the plugin at any time, but the protocol will still be loaded. This may or may not
 be a problem and may or may not be fixed at a later point in time.
+
+======
+
+I guess I should document how to write a PRPL.
+
+The first thing to do is to write your init function. It should be delcared
+
+void my_proto_init(struct prpl *p);
+
+You then fill in the members of the struct. See prpl.h for what they are.
+
+If you're going to load your protocol dynamically, put the function gaim_plugin_init(void *) in the
+file, and have it call
+
+	load_protocol(my_proto_init);
+
+and return a non-negative int. Then compile as a plugin, load the .so file, and you're set. If you're
+going to load it dynamically, extern the my_proto_init function, and in prpl.c, call load_protocol.
+
+Your PRPL needs to have a login function, which ideally should set up a gdk_input watcher. When you
+want to indicate that the account is online, simply call account_online(struct gaim_connection *).
+When there is information from the server, you should call the appropriate serv_got function (see
+gaim.h for a (partial?) list).
+
+When the UI wants to send something via the server, it will call the appropriate function that you set
+in your PRPL, if it's non-NULL.
+
+There's currently no way to unload a PRPL, even if compiled dynamically and the plugin is removed. If
+you do remove a dynamic PRPL and try to load a new version of it, you will still be using the old
+version. Hopefully I can figure out how to fix this. Maybe it's not that important.
--- a/STATUS	Thu Oct 26 18:05:29 2000 +0000
+++ b/STATUS	Fri Oct 27 07:53:32 2000 +0000
@@ -1,4 +1,4 @@
-STATUS of GAIM CVS tree. Last modified $Date: 2000-10-16 16:14:18 -0400 (Mon, 16 Oct 2000) $ by $Author: warmenhoven $.
+STATUS of GAIM CVS tree. Last modified $Date: 2000-10-27 03:53:32 -0400 (Fri, 27 Oct 2000) $ by $Author: warmenhoven $.
 
 This file is meant to provide gaim users who use the CVS version to see whether
 they actually want to compile what they just checked out. Gaim CVS is usually
@@ -34,13 +34,9 @@
 ==========
 
 The buddy list is completely fucked up. It needs to be heavily modified to be
-able to support The Change. But logging in as only one user makes it work as
-it always did.
-
-This may be changed, but here's how the buddy list cache currently works. When
-you sign on it imports the list from the name you sign on as. When the list is
-saved, it is saved to all of the signed on users. This means that when you sign
-on two or more names at once their lists will be merged.
+able to support The Change. It is currently in the process of being changed,
+and so will probably act very bizarrely. It should still be mostly usable, but
+don't try to edit your buddy list.
 
 
 TOC
--- a/configure.in	Thu Oct 26 18:05:29 2000 +0000
+++ b/configure.in	Fri Oct 27 07:53:32 2000 +0000
@@ -49,7 +49,7 @@
 AC_ARG_ENABLE(plugins, [  --disable-plugins       compile with out plugin support],,enable_plugins=yes)
 AC_ARG_ENABLE(perl,    [  --disable-perl          compile without perl scripting],,enable_perl=yes)
 AC_ARG_ENABLE(debug,   [  --enable-debug          compile with debugging support],,enable_debug=no)
-AC_ARG_ENABLE(screensaver,   [  --disable-screensaver     compile without  X screensaver extension],enable_xss=no,enable_xss=yes)
+AC_ARG_ENABLE(screensaver,   [  --disable-screensaver     compile without  X screensaver extension],,enable_xss=yes)
 AM_CONDITIONAL(PLUGINS, test "x$enable_plugins" = "xyes")
 AC_ARG_ENABLE(,,,)
 
--- a/plugins/autorecon.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/plugins/autorecon.c	Fri Oct 27 07:53:32 2000 +0000
@@ -18,7 +18,7 @@
 }
 
 void do_signon(char *name) {
-	struct aim_user *u = find_user(name);
+	struct aim_user *u = find_user(name, -1);
 	g_free(name);
 	serv_login(u);
 	gtk_timeout_remove(recon);
--- a/src/Makefile.am	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/Makefile.am	Fri Oct 27 07:53:32 2000 +0000
@@ -65,7 +65,7 @@
 endif
 
 CFLAGS += -DLOCALEDIR=\"$(datadir)/locale\" $(DEBUG_CFLAGS)
-LDFLAGS += $(DEBUG_LDFLAGS)
+LIBS += $(DEBUG_LIBS)
 
 EXTRA_DIST =	convo.h \
 		gaim.h \
--- a/src/aim.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/aim.c	Fri Oct 27 07:53:32 2000 +0000
@@ -60,12 +60,9 @@
 static GtkWidget *name;
 static GtkWidget *pass;
 
-GList *permit = NULL;
-GList *deny = NULL;
 GList *log_conversations = NULL;
 GList *buddy_pounces = NULL;
 GSList *away_messages = NULL;
-GSList *groups = NULL;
 GList *conversations = NULL;
 GList *chat_rooms = NULL;
 
@@ -160,11 +157,12 @@
 		return;
 	}
 
-	u = find_user(username);
+	/* if there is more than one user of the same name, then fuck them, they just have
+	 * to use the account editor to sign in the second one */
+	u = find_user(username, -1);
 	if (!u) {
 		u = g_new0(struct aim_user, 1);
 		g_snprintf(u->username, sizeof(u->username), "%s", username);
-		g_snprintf(u->password, sizeof(u->password), "%s", password);
 		u->protocol = PROTO_TOC;
 		u->options = OPT_USR_REM_PASS;
 		aim_users = g_list_append(aim_users, u);
@@ -193,7 +191,7 @@
 	char *txt = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
 	struct aim_user *u;
 
-	u = find_user(txt);
+	u = find_user(txt, -1);
 
 	if (u && u->options & OPT_USR_REM_PASS) {
 		gtk_entry_set_text(GTK_ENTRY(pass), u->password);
@@ -438,7 +436,8 @@
 
 int main(int argc, char *argv[])
 {
-	char opt, i;
+	char opt;
+	int i;
 	int opt_acct = 0, opt_help = 0, opt_version = 0,
 	    opt_user = 0, opt_login = 0, do_login_ret = -1;
 	char *opt_user_arg = NULL, *opt_login_arg = NULL;
--- a/src/buddy.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/buddy.c	Fri Oct 27 07:53:32 2000 +0000
@@ -38,17 +38,13 @@
 
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
+#include "prpl.h"
 #include "gaim.h"
 #include <aim.h>
-#include "pixmaps/admin_icon.xpm"
-#include "pixmaps/aol_icon.xpm"
-#include "pixmaps/free_icon.xpm"
-#include "pixmaps/dt_icon.xpm"
-#include "pixmaps/no_icon.xpm"
 #include "pixmaps/login_icon.xpm"
 #include "pixmaps/logout_icon.xpm"
+#include "pixmaps/no_icon.xpm"
 
-#include "pixmaps/away_icon.xpm"
 #include "pixmaps/away_small.xpm"
 
 #include "pixmaps/add_small.xpm"
@@ -86,7 +82,6 @@
 GtkWidget *blist = NULL;
 GtkWidget *bpmenu;
 GtkWidget *buddies;
-int permdeny;
 
 void BuddyTickerLogonTimeout( gpointer data );
 void BuddyTickerLogoutTimeout( gpointer data );
@@ -95,6 +90,24 @@
 static void new_bp_callback(GtkWidget *w, char *name);
 static void log_callback(GtkWidget *w, char *name);
 
+/* stuff for actual display of buddy list */
+struct buddy_show {
+	GtkWidget *item;
+	GtkWidget *pix;
+	GtkWidget *label;
+	char *name;
+	GSList *connlist;
+	guint log_timer;
+};
+struct group_show {
+	GtkWidget *item;
+	GtkWidget *label;
+	GtkWidget *tree;
+	GSList *members;
+	char *name;
+};
+static GSList *shows = NULL;
+
 
 void destroy_buddy()
 {
@@ -104,117 +117,6 @@
 	imchatbox = NULL;
 }
 
-void update_num_groups()
-{
-	GSList *grp = groups;
-	GList *mem;
-        struct buddy *b;
-	struct group *g;
-	int pres, total;
-        char buf[BUF_LONG];
-
-#ifndef USE_APPLET
-        if (!(display_options & OPT_DISP_SHOW_GRPNUM))
-                return;
-#else
-	int onl = 0;
-	int all = 0;
-#endif
-
-        while(grp) {
-		g = (struct group *)grp->data;
-                mem = g->members;
-                pres = 0;
-                total = 0;
-                while(mem) {
-			b = (struct buddy *)mem->data;
-                        if (b->present)
-                                pres++;
-                        total++;
-
-
-                        mem = mem->next;
-                }
-
-                g_snprintf(buf, sizeof(buf), "%s  (%d/%d)", g->name, pres, total);
-
-#ifdef USE_APPLET
-		onl += pres;
-		all += total;
-		if (display_options & OPT_DISP_SHOW_GRPNUM)
-#endif
-                gtk_label_set(GTK_LABEL(g->label), buf);
-                grp = g_slist_next(grp);
-        }
-#ifdef USE_APPLET
-	g_snprintf(buf, sizeof(buf), _("%d/%d Buddies Online"), onl, all);
-	applet_set_tooltips(buf);
-#endif
-}
-
-void update_show_idlepix()
-{
-	GSList *grp = groups;
-	GList *mem;
-	struct group *g;
-        struct buddy *b;
-
-	while (grp) {
-                g = (struct group *)grp->data;
-                mem = g->members;
-
-                while(mem) {
-			b = (struct buddy *)mem->data;
-
-                        if (display_options & OPT_DISP_SHOW_IDLETIME)
-                                gtk_widget_show(b->idletime);
-                        else
-                                gtk_widget_hide(b->idletime);
-						
-                        if (display_options & OPT_DISP_SHOW_PIXMAPS)
-                                gtk_widget_show(b->pix);
-                        else
-                                gtk_widget_hide(b->pix);
-                        mem = mem->next;
-                }
-                grp = g_slist_next(grp);
-        }
-}
-
-void update_all_buddies()
-{
-	GSList *grp = groups;
-	GList *mem;
-        struct buddy *b;
-	struct group *g;
-	int count;
-
-        while(grp) {
-		g = (struct group *)grp->data;
-		count = 0;
-                mem = g->members;
-                while(mem) {
-			b = (struct buddy *)mem->data;
-
-                        if (b->present || !GTK_WIDGET_VISIBLE(b->item))
-				set_buddy(b);
-
-			if (b->present || GTK_WIDGET_VISIBLE(b->item))
-				count++;
-
-                        mem = mem->next;
-                }
-		/* this is a fall-back in case we missed any */
-		if (!count && (display_options & OPT_DISP_NO_MT_GRP))
-			gtk_widget_hide(g->item);
-		else gtk_widget_show(g->item);
-
-                grp = g_slist_next(grp);
-        }
-
-
-}
-
 static void adjust_pic(GtkWidget *button, const char *c, gchar **xpm)
 {
         GdkPixmap *pm;
@@ -289,21 +191,10 @@
 
 void signoff(struct gaim_connection *gc)
 {
-	GList *mem;
-
 	plugin_event(event_signoff, gc, 0, 0, 0);
 	serv_close(gc);
 
 	if (connections) return;
-        while(groups) {
-		mem = ((struct group *)groups->data)->members;
-		while(mem) {
-			g_free(mem->data);
-                        mem = g_list_remove(mem, mem->data);
-		}
-		g_free(groups->data);
-                groups = g_slist_remove(groups, groups->data);
-	}
 
 	sprintf(debug_buff, "date: %s\n", full_date());
 	debug_print(debug_buff);
@@ -333,7 +224,7 @@
 	}
 }
 
-void pressed_im(GtkWidget *widget, struct buddy *b)
+void pressed_im(GtkWidget *widget, struct buddy_show *b)
 {
 	struct conversation *c;
 
@@ -359,29 +250,30 @@
 	}
 }
 
-void pressed_info(GtkWidget *widget, struct buddy *b)
+void pressed_info(GtkWidget *widget, struct buddy_show *b)
 {
         serv_get_info(b->name);
 }
 
-void pressed_alias(GtkWidget *widget, struct buddy *b)
+void pressed_alias(GtkWidget *widget, struct buddy_show *b)
 {
-	alias_dialog(b);
+	struct buddy *m = find_buddy(connections->data, b->name);
+	alias_dialog(m);
 }
 
-void pressed_dir_info(GtkWidget *widget, struct buddy *b)
+void pressed_dir_info(GtkWidget *widget, struct buddy_show *b)
 {
         serv_get_dir(b->name);
 
 }
 
-void pressed_away_msg(GtkWidget *widget, struct buddy *b)
+void pressed_away_msg(GtkWidget *widget, struct buddy_show *b)
 {
         serv_get_away_msg(b->name);
 
 }
 
-void handle_click_buddy(GtkWidget *widget, GdkEventButton *event, struct buddy *b)
+void handle_click_buddy(GtkWidget *widget, GdkEventButton *event, struct buddy_show *b)
 {
         if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
                 struct conversation *c;
@@ -467,73 +359,71 @@
 
 
 
-void remove_buddy(struct group *rem_g, struct buddy *rem_b)
+void remove_buddy(struct gaim_connection *gc, struct group *rem_g, struct buddy *rem_b)
 {
 	GSList *grp;
-	GList *mem;
-	struct buddy *b;
-	int count = 0;
+	GSList *mem;
+	struct conversation *c;
 	
 	struct group *delg;
 	struct buddy *delb;
 
-	grp = g_slist_find(groups, rem_g);
+	/* 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
+	 */
+
+	grp = g_slist_find(gc->groups, rem_g);
         delg = (struct group *)grp->data;
         mem = delg->members;
 	
-        mem = g_list_find(mem, rem_b);
+        mem = g_slist_find(mem, rem_b);
         delb = (struct buddy *)mem->data;
 	
-	gtk_tree_remove_items(GTK_TREE(delg->tree), g_list_append(NULL, delb->item));
-        delg->members = g_list_remove(delg->members, delb);
-        serv_remove_buddy(delb->name);
+        delg->members = g_slist_remove(delg->members, delb);
+        serv_remove_buddy(gc, delb->name);
+	c = find_conversation(delb->name);
         g_free(delb);
 	mem = delg->members;
-	while (mem && !count) {
-		b = (struct buddy *)mem->data;
-		if (b->present || GTK_WIDGET_VISIBLE(b->item)) count++;
-		mem = mem->next;
-	}
-	if (!count && (display_options & OPT_DISP_NO_MT_GRP))
-		gtk_widget_hide(delg->item);
-	
 
-        serv_save_config();
+	if (c)
+		update_convo_add_button(c);
 
 	// flush buddy list to cache
 
 	do_export( (GtkWidget *) NULL, 0 );
-        
-	update_num_groups();
 }
 
-void remove_group(struct group *rem_g)
+void remove_group(struct gaim_connection *gc, struct group *rem_g)
 {
 	GSList *grp;
-	GList *mem;
+	GSList *mem;
 	
 	struct group *delg;
 	struct buddy *delb;
 
-	grp = g_slist_find(groups, rem_g);
+	struct conversation *c;
+
+	/* we assume that the group actually does exist within the gc, and that the gc is not NULL.
+	 * the UI is responsible for this */
+
+	grp = g_slist_find(gc->groups, rem_g);
         delg = (struct group *)grp->data;
         mem = delg->members;
 
 	while(delg->members) {
 		delb = (struct buddy *)delg->members->data;
-		gtk_tree_remove_items(GTK_TREE(delg->tree), g_list_append(NULL, delb->item));
-                delg->members = g_list_remove(delg->members, delb);
-                serv_remove_buddy(delb->name);
+                delg->members = g_slist_remove(delg->members, delb);
+		c = find_conversation(delb->name);
+		if (c)
+			update_convo_add_button(c);
+                serv_remove_buddy(gc, delb->name);
                 g_free(delb);
 	}
 
-
-	gtk_tree_remove_items(GTK_TREE(buddies), g_list_append(NULL, delg->item));
-	groups = g_slist_remove(groups, delg);
+	gc->groups = g_slist_remove(gc->groups, delg);
 	g_free(delg);
 
-        serv_save_config();
-
         // flush buddy list to cache
 
         do_export( (GtkWidget *) NULL, 0 );
@@ -547,22 +437,40 @@
 				 GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling)
 {
         gboolean leaf;
+	struct gaim_connection *gc, *pc;
+	char *source;
+	char *parent;
 
-	gtk_ctree_get_node_info (ctree, source_node, NULL,
+	gtk_ctree_get_node_info (ctree, source_node, &source,
 				 NULL, NULL, NULL, NULL, NULL, &leaf, NULL);
 
+	gc = (struct gaim_connection *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), source_node);
 	
-	if (leaf) {
+	if (!strcmp(gc->username, source)) {
 		if (!new_parent)
-			return FALSE;
-	} else {
-		
-		if (new_parent)
-			return FALSE;
-		
+			return TRUE;
+	} else if (leaf) {
+		if (new_parent) {
+			gtk_ctree_get_node_info (ctree, new_parent, &parent,
+						 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+			pc = (struct gaim_connection *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree),
+					new_parent);
+			if (strcmp(parent, pc->username))
+				return TRUE;
+		}
+	} else /* group */ {
+		if (g_slist_length(connections) > 1 && new_parent) {
+			gtk_ctree_get_node_info (ctree, new_parent, &parent,
+						 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+			pc = (struct gaim_connection *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree),
+					new_parent);
+			if (!strcmp(parent, pc->username))
+				return TRUE;
+		} else if (g_slist_length(connections) == 1 && !new_parent)
+			return TRUE;
 	}
 
-	return TRUE;
+	return FALSE;
 }
 
 
@@ -570,201 +478,154 @@
 static void edit_tree_move (GtkCTree *ctree, GtkCTreeNode *child, GtkCTreeNode *parent,
                  GtkCTreeNode *sibling, gpointer data)
 {
-	char *source;
-	char *target1;
-        char *target2;
+	gboolean leaf;
+	char *source = "";
+	char *target1 = "";
+        char *target2 = "";
+	struct gaim_connection *gc, *pc = NULL, *sc = NULL;
+	
+	gc = (struct gaim_connection *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), child);
 	
 	gtk_ctree_get_node_info (ctree, child, &source,
-				 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-	if (parent)
+				 NULL, NULL, NULL, NULL, NULL, &leaf, NULL);
+	if (parent) {
 		gtk_ctree_get_node_info (ctree, parent, &target1,
 					 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-	if (sibling)
+		pc = (struct gaim_connection *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), parent);
+	}
+
+	if (sibling) {
 		gtk_ctree_get_node_info (ctree, sibling, &target2,
 					 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-
-	
-	if (!parent) {
-		GSList *grps;
-		GList *buds;
-		struct group *g, *g2;
-		GList *tmp, *mem;
-		int pos, count;
-		struct buddy *b;
-		/* Okay we've moved group order... */
-
-		g = find_group(source);
-
-                gtk_widget_ref(g->tree);
-
-		buds = g->members;
-		while(buds) {
-			b = (struct buddy *)buds->data;
-			gtk_widget_ref(b->item);
-			gtk_widget_ref(b->label);
-			gtk_widget_ref(b->idletime);
-			gtk_widget_ref(b->pix);
-			buds = buds->next;
-		}
-
-		
-
-		
-		pos = g_list_index(GTK_TREE(buddies)->children, g->item);
-
-                tmp = g_list_append(NULL, g->item);
-		gtk_tree_remove_items(GTK_TREE(buddies), tmp);
-		g_list_free(tmp);
-
-                groups = g_slist_remove(groups, g);
+		sc = (struct gaim_connection *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), sibling);
+	}
 
-                g->item = gtk_tree_item_new_with_label(g->name);
-		mem = g->members; count = 0;
-		while (mem && !count) {
-			b = (struct buddy *)mem->data;
-			if (b->present) count++;
-			mem = mem->next;
-		}
-		if (!count) gtk_widget_show(g->item);
+	if (!strcmp(source, gc->username)) {
+		/* not that it particularly matters which order the connections
+		 * are in, but just for debugging sake, i guess.... */
+		connections = g_slist_remove(connections, gc);
+		if (sibling) {
+			int 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);
+	} else if (leaf) {
+		/* 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 *new_g, *old_g;
+		struct buddy *b, *s = NULL;
+		int pos;
 
-		if (sibling) {
-			g2 = find_group(target2);
-                        pos = g_slist_index(groups, g2);
-                        if (pos == 0) {
-				groups = g_slist_prepend(groups, g);
-				gtk_tree_prepend(GTK_TREE(buddies), g->item);
+		if (gc != pc) {
+			/* we changed connections */
+			struct buddy *a;
+
+			a = find_buddy(pc, source);
+
+			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(pc, source);
+				og->members = g_slist_remove(og->members, a);
 			} else {
-				groups = g_slist_insert(groups, g, pos);
-				gtk_tree_insert(GTK_TREE(buddies), g->item, pos);
+				/* we don't have this buddy yet; let's add him */
+				serv_add_buddy(pc, source);
 			}
-         
-		} else {
-			groups = g_slist_append(groups, g);
-			gtk_tree_append(GTK_TREE(buddies), g->item);
-
-		}
-
-		gtk_tree_item_set_subtree (GTK_TREE_ITEM(g->item), g->tree);
-                gtk_tree_item_expand (GTK_TREE_ITEM(g->item));
-                gtk_signal_connect(GTK_OBJECT(g->item), "button_press_event",
-                                   GTK_SIGNAL_FUNC(handle_click_group),
-                                   NULL);
-                gtk_object_set_user_data(GTK_OBJECT(g->item), NULL);
-
-                gtk_widget_unref(g->tree);
-
-                update_num_groups();
-
-		buds = g->members;
-
-		while(buds) {
-			b = (struct buddy *)buds->data;
-			set_buddy(b);
-			buds = buds->next;
 		}
 
-		grps = groups;
-		while(grps) {
-			g = (struct group *)grps->data;
-			grps = g_slist_next(grps);
-		}
+		b = find_buddy(gc, source);
+		new_g = find_group(pc, target1);
+		old_g = find_group_by_buddy(gc, source);
 
-        } else {
-                struct group *new_g, *old_g;
-                struct buddy *b, *s;
-                GtkWidget *gtree;
-                GtkWidget *owner;
-                GList *temp;
-                int pos;
+		if (gc == pc) /* this is the same connection, so we'll remove it from its old group */
+			old_g->members = g_slist_remove(old_g->members, b);
 
-                b = find_buddy(source);
-                new_g = find_group(target1);
-                old_g = find_group_by_buddy(source);
-                gtree = old_g->tree;
-                if (sibling)
-                        s = find_buddy(target2);
-                else
-                        s = NULL;
-
-                old_g->members = g_list_remove(old_g->members, b);
+		if (sibling) {
+			s = find_buddy(sc, target2);
+			pos = g_slist_index(new_g->members, s);
+			if (pos)
+				new_g->members = g_slist_insert(new_g->members, b, pos);
+			else
+				new_g->members = g_slist_prepend(new_g->members, b);
+		} else
+			new_g->members = g_slist_append(new_g->members, b);
 
-                gtk_widget_ref(b->item);
-                gtk_widget_ref(b->label);
-                gtk_widget_ref(b->pix);
-                gtk_widget_ref(b->idletime);
-                gtk_widget_ref(gtree);
+		if (pc != gc)
+			build_edit_tree();
+	} else /* group */ {
+		/* move the group. if moving connections, copy the group, and each buddy in the
+		 * group. if the buddy exists in the new connection, leave it where it is. */
 
-                owner = GTK_TREE(gtree)->tree_owner;
-                
-                temp = g_list_append(NULL, b->item);
-                gtk_tree_remove_items(GTK_TREE(old_g->tree), temp);
-                g_list_free(temp);
+		struct group *g, *g2;
+		int pos;
+
+		if (g_slist_length(connections) > 1) {
+			g = find_group(pc, source);
+			if (!g)
+				g = add_group(pc, source);
+
+			pc->groups = g_slist_remove(pc->groups, g);
 
-                if (gtree->parent == NULL){
-                        gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), gtree);
-                        gtk_tree_item_expand (GTK_TREE_ITEM(owner));
-                }
-                
-                if (!sibling) {
-                        gtk_tree_append(GTK_TREE(new_g->tree), b->item);
-                        new_g->members = g_list_append(new_g->members, b);
-                } else {
-                        pos = g_list_index(new_g->members, s);
-                        if (pos != 0) {
-                                new_g->members = g_list_insert(new_g->members, b, pos);
-                                gtk_tree_insert(GTK_TREE(new_g->tree), b->item, pos);
-                        } else {
-                                new_g->members = g_list_prepend(new_g->members, b);
-                                gtk_tree_prepend(GTK_TREE(new_g->tree), b->item);
+			if (sibling) {
+				g2 = find_group(pc, target2);
+				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);
 
-                        }
-                }
-
-                gtk_widget_unref(b->item);
-                gtk_widget_unref(b->label);
-                gtk_widget_unref(b->pix);
-                gtk_widget_unref(b->idletime);
-                gtk_widget_unref(gtree);
+			if (pc != gc) {
+				GSList *mem;
+				struct buddy *b;
+				g2 = find_group(gc, source);
 
-                gtk_ctree_expand(ctree, parent);
-                
-                update_num_groups();
-                update_show_idlepix();
-		if (b->present) {
-			GList *mem = old_g->members;
-			struct buddy *bt;
-			int count = 0;
-			while (mem && !count) {
-				bt = (struct buddy *)mem->data;
-				if (bt->present || GTK_WIDGET_VISIBLE(b->item)) count++;
-				mem = mem->next;
+				mem = g2->members;
+				while (mem) {
+					b = (struct buddy *)mem->data;
+					if (!find_buddy(pc, b->name))
+						add_buddy(pc, g->name, b->name, b->show);
+					mem = mem->next;
+				}
+				
+				build_edit_tree();
 			}
-			if (!count && (display_options & OPT_DISP_NO_MT_GRP))
-				gtk_widget_hide(old_g->item);
-			gtk_widget_show(new_g->item);
-		}
-                set_buddy(b);
-                
+		} else {
+			g = find_group(gc, source);
 
-
+			gc->groups = g_slist_remove(gc->groups, g);
 
-
-        }
+			if (sibling) {
+				g2 = find_group(gc, target2);
+				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);
+		}
+	}
 
-        serv_save_config();
-
-        // flush buddy list to cache
-
-        do_export( (GtkWidget *) NULL, 0 );
+	do_export( (GtkWidget *) NULL, 0 );
 }
 
 
 
 void build_edit_tree()
 {
-        GtkCTreeNode *p = NULL, *n;
-	GSList *grp = groups;
-	GList *mem;
+        GtkCTreeNode *c = NULL, *p = NULL, *n;
+	GSList *con = connections;
+	GSList *grp;
+	GSList *mem;
+	struct gaim_connection *z;
 	struct group *g;
 	struct buddy *b;
 	char *text[1];
@@ -773,55 +634,73 @@
 	gtk_clist_clear(GTK_CLIST(edittree));
 	
         
-	while(grp) {
-		g = (struct group *)grp->data;
+	while (con) {
+		z = (struct gaim_connection *)con->data;
+
+		if (g_slist_length(connections) > 1) {
+			text[0] = z->username;
+
+			c = gtk_ctree_insert_node(GTK_CTREE(edittree), NULL,
+							NULL, text, 5, NULL, NULL,
+							NULL, NULL, 0, 1);
 
-                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), c, z);
+		} else
+			c = NULL;
+
+		grp = z->groups;
 
-		n = NULL;
-		
-		mem = g->members;
+		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);
 
-                while(mem) {
-			b = (struct buddy *)mem->data;
+			gtk_ctree_node_set_row_data(GTK_CTREE(edittree), p, z);
 
-			text[0] = b->name;
+			n = NULL;
+			
+			mem = g->members;
+
+			while(mem) {
+				b = (struct buddy *)mem->data;
+
+				text[0] = b->name;
 
-			n = gtk_ctree_insert_node(GTK_CTREE(edittree),
-						  p, NULL, text, 5,
-						  NULL, NULL,
-						  NULL, NULL, 1, 1);
+				n = gtk_ctree_insert_node(GTK_CTREE(edittree),
+							  p, NULL, text, 5,
+							  NULL, NULL,
+							  NULL, NULL, 1, 1);
+
+				gtk_ctree_node_set_row_data(GTK_CTREE(edittree), n, z);
 
-			mem = mem->next;
-                        
- 		}
-		grp = g_slist_next(grp);
+				mem = mem->next;
+				
+			}
+			grp = g_slist_next(grp);
+		}
+		con = g_slist_next(con);
 	}
 
 	gtk_clist_thaw(GTK_CLIST(edittree));
 	
 }
 
-struct buddy *add_buddy(char *group, char *buddy, char *show)
+struct buddy *add_buddy(struct gaim_connection *gc, char *group, char *buddy, char *show)
 {
 	struct buddy *b;
 	struct group *g;
-	GdkPixmap *pm;
-	GdkBitmap *bm;
-	GtkWidget *box;
 
-
-	if ((b = find_buddy(buddy)) != NULL)
+	if ((b = find_buddy(gc, buddy)) != NULL)
                 return b;
 
-	g = find_group(group);
+	g = find_group(gc, group);
 
 	if (g == NULL)
-		g = add_group(group);
+		g = add_group(gc, group);
 	
         b = (struct buddy *)g_new0(struct buddy, 1);
         
@@ -829,56 +708,22 @@
 		return NULL;
 
 	b->present = 0;
-        b->item = gtk_tree_item_new();
 
 	g_snprintf(b->name, sizeof(b->name), "%s", buddy);
 	g_snprintf(b->show, sizeof(b->show), "%s", show ? (show[0] ? show : buddy) : buddy);
 		
-        g->members = g_list_append(g->members, b);
-
-
-        if (blist == NULL)
-                return b;
-        
-	box = gtk_hbox_new(FALSE, 1);
-	pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-					  NULL, (gchar **)login_icon_xpm);
-        b->pix = gtk_pixmap_new(pm, bm);
+        g->members = g_slist_append(g->members, b);
 
         b->idle = 0;
 	b->caps = 0;
 			
-	gtk_widget_show(b->pix);
-	gdk_pixmap_unref(pm);
-	gdk_bitmap_unref(bm);
-
-	b->label = gtk_label_new(buddy);
-	gtk_misc_set_alignment(GTK_MISC(b->label), 0.0, 0.5);
-
-	b->idletime = gtk_label_new("");
-
-	gtk_tree_append(GTK_TREE(g->tree),b->item);
-	gtk_container_add(GTK_CONTAINER(b->item), box);
-
-	gtk_box_pack_start(GTK_BOX(box), b->pix, FALSE, FALSE, 1);
-	gtk_box_pack_start(GTK_BOX(box), b->label, TRUE, TRUE, 1);
-	gtk_box_pack_start(GTK_BOX(box), b->idletime, FALSE, FALSE, 1);
-
-	gtk_widget_show(b->label);
-	gtk_widget_show(box);
-
-	gtk_object_set_user_data(GTK_OBJECT(b->item), b);
-
-	gtk_signal_connect(GTK_OBJECT(b->item), "button_press_event",
-			   GTK_SIGNAL_FUNC(handle_click_buddy), b);
-
 	return b;
 }
 
 
-struct group *add_group(char *group)
+struct group *add_group(struct gaim_connection *gc, char *group)
 {
-	struct group *g = find_group(group);
+	struct group *g = find_group(gc, group);
 	if (g)
 		return g;
 	g = (struct group *)g_new0(struct group, 1);
@@ -886,35 +731,13 @@
 		return NULL;
 
 	strncpy(g->name, group, sizeof(g->name));
-        groups = g_slist_append(groups, g);
+        gc->groups = g_slist_append(gc->groups, g);
 
-        if (blist == NULL)
-                return g;
-        
-        g->item = gtk_tree_item_new();
-        g->label = gtk_label_new(g->name);
-        gtk_misc_set_alignment(GTK_MISC(g->label), 0.0, 0.5);
-        gtk_widget_show(g->label);
-        gtk_container_add(GTK_CONTAINER(g->item), g->label);
-	g->tree = gtk_tree_new();
-	gtk_widget_show(g->item);
-	gtk_widget_show(g->tree);
-	gtk_tree_append(GTK_TREE(buddies), g->item);
-	gtk_tree_item_set_subtree(GTK_TREE_ITEM(g->item), g->tree);
-	gtk_tree_item_expand(GTK_TREE_ITEM(g->item));
-	gtk_signal_connect(GTK_OBJECT(g->item), "button_press_event",
-			   GTK_SIGNAL_FUNC(handle_click_group),
-			   NULL);
-        gtk_object_set_user_data(GTK_OBJECT(g->item), NULL);
 	g->members = NULL;
-	if (display_options & OPT_DISP_NO_MT_GRP)
-		gtk_widget_hide(g->item);
 	
- 
 	build_edit_tree();
 	
 	return g;
-	
 }
 
 
@@ -924,28 +747,31 @@
         char *bud, *grp;
 	struct buddy *b;
 	struct group *g;
+	struct gaim_connection *gc;
 	GList *i;
 	
 	i = GTK_CLIST(edittree)->selection;
 	if (i) {
 		node = i->data;
+		gc = (struct gaim_connection *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node);
 
 		if (GTK_CTREE_ROW(node)->is_leaf) {
                         gtk_ctree_get_node_info (GTK_CTREE(edittree), node, &bud,
 						 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
-			b = find_buddy(bud);
-			g = find_group_by_buddy(bud);
-			remove_buddy(g, b);
+			b = find_buddy(gc, bud);
+			g = find_group_by_buddy(gc, bud);
+			remove_buddy(gc, g, b);
 		} else {
 			gtk_ctree_get_node_info (ctree, node, &grp,
-						 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-			g = find_group(grp);
-                        remove_group(g);
+						NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+			if (strcmp(gc->username, grp)) {
+				g = find_group(gc, grp);
+				remove_group(gc, g);
+			}
                 }
                 
                 build_edit_tree();
-                serv_save_config();
 
         	// flush buddy list to cache
 
@@ -954,7 +780,6 @@
         } else {
                 /* Nothing selected. */
         }
-        update_num_groups();
 }
 
 
@@ -990,7 +815,6 @@
 			(*gaim_plugin_remove)();
 		/* we don't need to worry about removing callbacks since
 		 * there won't be any more chance to call them back :) */
-		dlclose(p->handle);
 		g_free(p->filename); /* why do i bother? */
 		g_free(p);
 		c = c->next;
@@ -1008,19 +832,21 @@
 	char *grp = NULL;
 	GtkCTreeNode *node;
 	GList *i;
+	struct gaim_connection *gc = NULL;
 
 	i = GTK_CLIST(edittree)->selection;
 	if (i) {
 		node = i->data;
+		gc = (struct gaim_connection *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node);
 
 		if (GTK_CTREE_ROW(node)->is_leaf) {
 			node = GTK_CTREE_ROW(node)->parent;
+		} else if (gc) {
+			gtk_ctree_get_node_info (GTK_CTREE(edittree), node, &grp,
+						 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 		}
-
-		gtk_ctree_get_node_info (GTK_CTREE(edittree), node, &grp,
-					 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 	}
-	show_add_buddy(NULL, grp);
+	show_add_buddy(gc, NULL, grp);
 
 }
 
@@ -1075,83 +901,158 @@
 	join_chat();
 }
 
-struct group *find_group(char *group)
+struct group *find_group(struct gaim_connection *gc, char *group)
 {
 	struct group *g;
-        GSList *grp = groups;
+        GSList *grp;
+	GSList *c = connections;
+	struct gaim_connection *z;
 	char *grpname = g_malloc(strlen(group) + 1);
 
 	strcpy(grpname, normalize(group));
-	while (grp) {
-		g = (struct group *)grp->data;
-		if (!strcasecmp(normalize(g->name), grpname)) {
-				g_free(grpname);
-				return g;
+	if (gc) {
+		grp = gc->groups;
+		while (grp) {
+			g = (struct group *)grp->data;
+			if (!strcasecmp(normalize(g->name), grpname)) {
+					g_free(grpname);
+					return g;
+			}
+			grp = g_slist_next(grp);
 		}
-		grp = g_slist_next(grp);
-	}
 
-	g_free(grpname);
-	return NULL;	
-	
+		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 (!strcasecmp(normalize(g->name), grpname)) {
+						g_free(grpname);
+						return g;
+				}
+				grp = g_slist_next(grp);
+			}
+
+			c = c->next;
+		}
+		g_free(grpname);
+		return NULL;
+	}
 }
 
 
-struct group *find_group_by_buddy(char *who)
+struct group *find_group_by_buddy(struct gaim_connection *gc, char *who)
 {
 	struct group *g;
 	struct buddy *b;
-	GSList *grp = groups;
-	GList *mem;
+	GSList *grp;
+	GSList *mem;
         char *whoname = g_malloc(strlen(who) + 1);
 
 	strcpy(whoname, normalize(who));
 	
-	while(grp) {
-		g = (struct group *)grp->data;
+	if (gc) {
+		grp = gc->groups;
+		while(grp) {
+			g = (struct group *)grp->data;
 
-		mem = g->members;
-		while(mem) {
-			b = (struct buddy *)mem->data;
-			if (!strcasecmp(normalize(b->name), whoname)) {
-				g_free(whoname);
-				return g;
+			mem = g->members;
+			while(mem) {
+				b = (struct buddy *)mem->data;
+				if (!strcasecmp(normalize(b->name), whoname)) {
+					g_free(whoname);
+					return g;
+				}
+				mem = mem->next;
 			}
-			mem = mem->next;
+			grp = g_slist_next(grp);
 		}
-		grp = g_slist_next(grp);
+		g_free(whoname);
+		return NULL;
+	} else {
+		GSList *c = connections;
+		struct gaim_connection *z;
+		while (c) {
+			z = (struct gaim_connection *)c->data;
+			grp = z->groups;
+			while(grp) {
+				g = (struct group *)grp->data;
+
+				mem = g->members;
+				while(mem) {
+					b = (struct buddy *)mem->data;
+					if (!strcasecmp(normalize(b->name), whoname)) {
+						g_free(whoname);
+						return g;
+					}
+					mem = mem->next;
+				}
+				grp = g_slist_next(grp);
+			}
+			c = c->next;
+		}
+		g_free(whoname);
+		return NULL;
 	}
-	g_free(whoname);
-	return NULL;
 }
 
 
-struct buddy *find_buddy(char *who)
+struct buddy *find_buddy(struct gaim_connection *gc, char *who)
 {
 	struct group *g;
 	struct buddy *b;
-	GSList *grp = groups;
-	GList *mem;
+	GSList *grp;
+	GSList *c;
+	struct gaim_connection *z;
+	GSList *mem;
         char *whoname = g_malloc(strlen(who) + 1);
 
 	strcpy(whoname, normalize(who));
-	
-	while(grp) {
-		g = (struct group *)grp->data;
+	if (gc) {
+		grp = gc->groups;
+		while(grp) {
+			g = (struct group *)grp->data;
 
-		mem = g->members;
-		while(mem) {
-			b = (struct buddy *)mem->data;
-			if (!strcasecmp(normalize(b->name), whoname)) {
-				g_free(whoname);
-				return b;
+			mem = g->members;
+			while(mem) {
+				b = (struct buddy *)mem->data;
+				if (!strcasecmp(normalize(b->name), whoname)) {
+					g_free(whoname);
+					return b;
+				}
+				mem = mem->next;
 			}
-			mem = mem->next;
+			grp = g_slist_next(grp);
 		}
-		grp = g_slist_next(grp);
+		g_free(whoname);
+		return NULL;
+	} else {
+		c = connections;
+		while (c) {
+			z = (struct gaim_connection *)c->data;
+			grp = z->groups;
+			while(grp) {
+				g = (struct group *)grp->data;
+
+				mem = g->members;
+				while(mem) {
+					b = (struct buddy *)mem->data;
+					if (!strcasecmp(normalize(b->name), whoname)) {
+						g_free(whoname);
+						return b;
+					}
+					mem = mem->next;
+				}
+				grp = g_slist_next(grp);
+			}
+			c = c->next;
+		}
+		g_free(whoname);
+		return NULL;
 	}
-	g_free(whoname);
-	return NULL;
 }
 
 
@@ -1309,32 +1210,6 @@
 }
 
 
-gint log_timeout(char *name)
-{
-	struct buddy *b;
-	struct group *g;
-	
-	b = find_buddy(name);
-
-	if(!b)
-                return FALSE;
-
-        b->log_timer = 0;
-			
-	if (!b->present) {
-		gtk_widget_hide(b->item);
-		g = find_group_by_buddy(name);
-		if (GTK_TREE_ITEM(g->item)->expanded) {
-			gtk_tree_item_collapse(GTK_TREE_ITEM(g->item));
-			gtk_tree_item_expand(GTK_TREE_ITEM(g->item));
-		}
-	} else
-		set_buddy(b);
-	
-	return FALSE;
-}
-
-
 static char *caps_string(u_short caps)
 {
 	static char buf[BUF_LEN];
@@ -1370,265 +1245,211 @@
 }
 
 
-void set_buddy(struct buddy *b)
-{
-	char infotip[256];
-        char idlet[16];
-        char warn[256];
-	char caps[256];
-	char *who;
-        int i;
-        int ihrs, imin;
-        time_t t;
-	GdkPixmap *pm;
-        GdkBitmap *bm;
-        char *itime, *sotime;
-	
-        if (b->present) {
-                time(&t);
+static struct group_show *find_group_show(char *group) {
+	GSList *m = shows;
+	struct group_show *g = NULL;
+
+	while (m) {
+		g = (struct group_show *)m->data;
+		if (!strcmp(g->name, group))
+			break;
+		g = NULL;
+		m = m->next;
+	}
+
+	return g;
+}
+
+static struct buddy_show *find_buddy_show(struct group_show *gs, char *name) {
+	GSList *m = gs->members;
+	struct buddy_show *b = NULL;
+
+	while (m) {
+		b = (struct buddy_show *)m->data;
+		if (!strcmp(b->name, name))
+			break;
+		b = NULL;
+		m = m->next;
+	}
+
+	return b;
+}
+
+static struct group_show *new_group_show(char *group) {
+	struct group_show *g = g_new0(struct group_show, 1);
+
+	g->name = g_strdup(group);
+
+	g->item = gtk_tree_item_new();
+	/* FIXME */
+	gtk_tree_append(GTK_TREE(buddies), g->item);
+	gtk_signal_connect(GTK_OBJECT(g->item), "button_press_event",
+			   GTK_SIGNAL_FUNC(handle_click_group), NULL);
+	gtk_widget_show(g->item);
 
-                ihrs = (t - b->idle) / 3600;
-                imin = ((t - b->idle) / 60) % 60;
+	g->label = gtk_label_new(group);
+	gtk_misc_set_alignment(GTK_MISC(g->label), 0.0, 0.5);
+	gtk_container_add(GTK_CONTAINER(g->item), g->label);
+	gtk_widget_show(g->label);
+
+	g->tree = gtk_tree_new();
+	gtk_tree_item_set_subtree(GTK_TREE_ITEM(g->item), g->tree);
+	gtk_tree_item_expand(GTK_TREE_ITEM(g->item));
+	gtk_widget_show(g->tree);
+
+	/* FIXME */
+	shows = g_slist_append(shows, g);
+	return g;
+}
+
+static struct buddy_show *new_buddy_show(struct group_show *gs, char *buddy) {
+	struct buddy_show *b = g_new0(struct buddy_show, 1);
+	GtkWidget *box;
+	GdkPixmap *pm;
+	GdkBitmap *bm;
 
-                if (ihrs)
-                        g_snprintf(idlet, sizeof(idlet), "(%d:%02d)", ihrs, imin);
-                else
-                        g_snprintf(idlet, sizeof(idlet), "(%02d)", imin);
-                
-                gtk_widget_hide(b->idletime);
-                
-		if (b->idle)
-			gtk_label_set(GTK_LABEL(b->idletime), idlet);
-		else
-			gtk_label_set(GTK_LABEL(b->idletime), "");
-                if (display_options & OPT_DISP_SHOW_IDLETIME)
-                        gtk_widget_show(b->idletime);
+	b->name = g_strdup(buddy);
+
+	b->item = gtk_tree_item_new();
+	/* FIXME */
+	gtk_tree_append(GTK_TREE(gs->tree), b->item);
+	gtk_object_set_user_data(GTK_OBJECT(b->item), b);
+	gtk_signal_connect(GTK_OBJECT(b->item), "button_press_event",
+			   GTK_SIGNAL_FUNC(handle_click_buddy), b);
+	gtk_widget_show(b->item);
+
+	box = gtk_hbox_new(FALSE, 1);
+	gtk_container_add(GTK_CONTAINER(b->item), box);
+	gtk_widget_show(box);
+
+	pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, (char **)login_icon_xpm);
+	b->pix = gtk_pixmap_new(pm, bm);
+	gtk_box_pack_start(GTK_BOX(box), b->pix, FALSE, FALSE, 1);
+	gtk_widget_show(b->pix);
+	gdk_pixmap_unref(pm);
+	gdk_bitmap_unref(bm);
 
+	b->label = gtk_label_new(buddy);
+	gtk_misc_set_alignment(GTK_MISC(b->label), 0.0, 0.5);
+	gtk_box_pack_start(GTK_BOX(box), b->label, TRUE, TRUE, 1);
+	gtk_widget_show(b->label);
 
-                sotime = sec_to_text(t - b->signon + correction_time);
-                if (b->idle) {
-                        itime = sec_to_text(t - b->idle);
-                } else {
-                        itime = g_malloc(1);
-                        itime[0] = 0;
-                }
-		
-		if (b->evil) {
-			g_snprintf(warn, sizeof(warn), _("Warnings: %d%%\n"), b->evil);
+	/* FIXME */
+	gs->members = g_slist_append(gs->members, b);
+	return b;
+}
+
+static struct group_show *find_gs_by_bs(struct buddy_show *b) {
+	GSList *m, *n;
+	struct group_show *g = NULL;
+	struct buddy_show *h;
+
+	m = shows;
+	while (m) {
+		g = (struct group_show *)m->data;
+		n = g->members;
+		while (n) {
+			h = (struct buddy_show *)n->data;
+			if (h == b)
+				return g;
+			n = n->next;
+		}
+		g = NULL;
+		m = m->next;
+	}
+
+	return g;
+}
 
-		} else
-			warn[0] = '\0';
-		
-		if (b->caps) {
-			g_snprintf(caps, sizeof(caps), _("Capabilities: %s\n"), caps_string(b->caps));
-		} else
-			caps[0] = '\0';
-		
-                i = g_snprintf(infotip, sizeof(infotip), _("Alias: %s               \nScreen Name: %s\nLogged in: %s\n%s%s%s%s%s"), b->show, b->name, sotime, warn, ((b->idle) ? _("Idle: ") : ""),  itime, ((b->idle) ? "\n" : ""), caps);
+static int log_timeout(struct buddy_show *b) {
+	if (!b->connlist) {
+		struct group_show *g = find_gs_by_bs(b);
+		g->members = g_slist_remove(g->members, b);
+		gtk_widget_destroy(b->item);
+		if (g->members == NULL && (display_options & OPT_DISP_NO_MT_GRP)) {
+			shows = g_slist_remove(shows, g);
+			gtk_widget_destroy(g->item);
+			g_free(g->name);
+			g_free(g);
+		}
+		g_free(b->name);
+		g_free(b);
+	} else {
+		/* um.... what do we have to do here? just update the pixmap? */
+		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);
+		if (xpm == NULL)
+			xpm = (char **)no_icon_xpm;
+		pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm);
+		gtk_widget_hide(b->pix);
+		gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm);
+		gtk_widget_show(b->pix);
+		if (ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER)
+			BuddyTickerSetPixmap(b->name, pm, bm);
+		gdk_pixmap_unref(pm);
+		gdk_bitmap_unref(bm);
+	}
+	b->log_timer = -1;
+	return FALSE;
+}
 
-		gtk_tooltips_set_tip(tips, GTK_WIDGET(b->item), infotip, "");
-
-                g_free(sotime);
-                g_free(itime);
-
-                
-
-		/* this check should also depend on whether they left,
-		 * and signed on again before they got erased */
-                if (!GTK_WIDGET_VISIBLE(b->item) || b->present == 1) {
-			plugin_event(event_buddy_signon, b->name, 0, 0, 0);
-			
+void set_buddy(struct gaim_connection *gc, struct buddy *b)
+{
+	time_t t;
+	struct group *g = find_group_by_buddy(gc, b->name);
+	struct group_show *gs;
+	struct buddy_show *bs;
+	GdkPixmap *pm;
+	GdkBitmap *bm;
+	char **xpm = NULL;
+	if (b->present) {
+		if ((gs = find_group_show(g->name)) == NULL)
+			gs = new_group_show(g->name);
+		if ((bs = find_buddy_show(gs, b->name)) == NULL)
+			bs = new_buddy_show(gs, b->name);
+		if (b->present == 1) {
 			play_sound(BUDDY_ARRIVE);
 			b->present = 2;
-
-			who = g_malloc(sizeof(b->show) + 10);
-			strcpy(who, b->show);
-			gtk_label_set(GTK_LABEL(b->label), who);
-			g_free(who);
-
-			pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-				NULL, (gchar **)login_icon_xpm);
-			gtk_widget_hide(b->pix);
-			gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm);
-                        if (display_options & OPT_DISP_SHOW_PIXMAPS)
-				gtk_widget_show(b->pix);
-			gdk_pixmap_unref(pm);
-			gdk_bitmap_unref(bm);
-
-			pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-				NULL, (gchar **)login_icon_xpm);
-
-        		if ( ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER )
-				BuddyTickerAddUser( b->name, pm, bm );	
+			if (b->log_timer > 0)
+				gtk_timeout_remove(b->log_timer);
+			if (!g_slist_find(bs->connlist, gc))
+				bs->connlist = g_slist_append(bs->connlist, gc);
+			b->log_timer = gtk_timeout_add(10000, (GtkFunction)log_timeout, bs);
+		} else {
+			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);
+			gtk_widget_hide(bs->pix);
+			gtk_pixmap_set(GTK_PIXMAP(bs->pix), pm, bm);
+			gtk_widget_show(bs->pix);
+			if (ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER)
+				BuddyTickerSetPixmap(b->name, pm, bm);
 			gdk_pixmap_unref(pm);
 			gdk_bitmap_unref(bm);
-
-			if (display_options & OPT_DISP_SHOW_LOGON) {
-				struct conversation *c = find_conversation(b->name);
-				if (c) {
-					char tmp[1024];
-
-					
-					g_snprintf(tmp, sizeof(tmp), _("<HR><B>%s logged in%s%s.</B><BR><HR>"), b->name,
-                                                   ((display_options & OPT_DISP_SHOW_TIME) ? " @ " : ""),
-                                                   ((display_options & OPT_DISP_SHOW_TIME) ? date() : ""));
-
-
-					write_to_conv(c, tmp, WFLAG_SYSTEM, NULL);
-
-				}
-			}
-
-			
-			{ struct group *g = find_group_by_buddy(b->name);
-			  gtk_widget_show(g->item); }
-			gtk_widget_show(b->item);
-			gtk_widget_show(b->label);
-                        b->log_timer = gtk_timeout_add(10000, (GtkFunction) log_timeout, b->name);
-        		if ( ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER )
-                        	gtk_timeout_add(10000, (GtkFunction) BuddyTickerLogonTimeout, b->name);
-                        update_num_groups();
-                        update_show_idlepix();
-                        setup_buddy_chats();
-			return;
-                }
-
-
-                
-                if (!b->log_timer) {
-                        gtk_widget_hide(b->pix);
-                        if (b->uc & UC_UNAVAILABLE) {
-                                pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)away_icon_xpm);
-                                gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm);
-				gdk_pixmap_unref(pm);
-				gdk_bitmap_unref(bm);
-        			if ( ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER )
-				{
-					pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)away_icon_xpm);
-					BuddyTickerSetPixmap(b->name, pm, bm);
-					gdk_pixmap_unref(pm);
-					gdk_bitmap_unref(bm);
-				}
-                        } else if (b->uc & UC_AOL) {
-                                pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)aol_icon_xpm);
-                                gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm);
-				gdk_pixmap_unref(pm);
-				gdk_bitmap_unref(bm);
-        			if ( ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER )
-				{
-					pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)aol_icon_xpm);
-					BuddyTickerSetPixmap(b->name, pm, bm);
-					gdk_pixmap_unref(pm);
-					gdk_bitmap_unref(bm);
-				}
-                        } else if (b->uc & UC_NORMAL) {
-                                pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)free_icon_xpm);
-                                gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm);
-				gdk_pixmap_unref(pm);
-				gdk_bitmap_unref(bm);
-        			if ( ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER )
-				{
-					pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)free_icon_xpm);
-					BuddyTickerSetPixmap(b->name, pm, bm);
-					gdk_pixmap_unref(pm);
-					gdk_bitmap_unref(bm);
-				}
-                        } else if (b->uc & UC_ADMIN) {
-                                pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)admin_icon_xpm);
-                                gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm);
-				gdk_pixmap_unref(pm);
-				gdk_bitmap_unref(bm);
-        			if ( ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER )
-				{
-					pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)admin_icon_xpm);
-					BuddyTickerSetPixmap(b->name, pm, bm);
-					gdk_pixmap_unref(pm);
-					gdk_bitmap_unref(bm);
-				}
-                        } else if (b->uc & UC_UNCONFIRMED) {
-                                pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)dt_icon_xpm);
-                                gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm);
-				gdk_pixmap_unref(pm);
-				gdk_bitmap_unref(bm);
-        			if ( ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER )
-				{
-					pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)dt_icon_xpm);
-					BuddyTickerSetPixmap(b->name, pm, bm);
-					gdk_pixmap_unref(pm);
-					gdk_bitmap_unref(bm);
-				}
-                        } else {
-                                pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)no_icon_xpm);
-                                gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm);
-				gdk_pixmap_unref(pm);
-				gdk_bitmap_unref(bm);
-        			if ( ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER )
-				{
-					pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-                                                                  NULL, (gchar **)no_icon_xpm);
-					BuddyTickerSetPixmap(b->name, pm, bm);
-					gdk_pixmap_unref(pm);
-					gdk_bitmap_unref(bm);
-				}
-                        }
-                        if (display_options & OPT_DISP_SHOW_PIXMAPS)
-                                gtk_widget_show(b->pix);
-                }
-	
-
-
+		}
 	} else {
-		if (GTK_WIDGET_VISIBLE(b->item)) {
-			plugin_event(event_buddy_signoff, b->name, 0, 0, 0);
-			play_sound(BUDDY_LEAVE);
-			pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-				NULL, (gchar **)logout_icon_xpm);
-			gtk_widget_hide(b->pix);
-			gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm);
-                        if (display_options & OPT_DISP_SHOW_PIXMAPS)
-				gtk_widget_show(b->pix);
-			gdk_pixmap_unref(pm);
-			gdk_bitmap_unref(bm);
-			pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-				NULL, (gchar **)logout_icon_xpm);
-        		if ( ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER )
-				BuddyTickerSetPixmap( b->name, pm, bm );
-			gdk_pixmap_unref(pm);
-			gdk_bitmap_unref(bm);
-			if (display_options & OPT_DISP_SHOW_LOGON) {
-				struct conversation *c = find_conversation(b->name);
-				if (c) {
-					char tmp[1024];
-
-					
-					g_snprintf(tmp, sizeof(tmp), _("<HR><B>%s logged out%s%s.</B><BR><HR>"), b->name,
-                                                   ((display_options & OPT_DISP_SHOW_TIME) ? " @ " : ""),
-                                                   ((display_options & OPT_DISP_SHOW_TIME) ? date() : ""));
-
-
-					write_to_conv(c, tmp, WFLAG_SYSTEM, NULL);
-
-				}
-			}
-                        b->log_timer = gtk_timeout_add(10000, (GtkFunction)log_timeout, b->name);
-        		if ( ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER )
-                        	gtk_timeout_add(10000, (GtkFunction)BuddyTickerLogoutTimeout, b->name);
-                        update_num_groups();
-                        update_show_idlepix();
-		}
-        }
-        setup_buddy_chats();
+		play_sound(BUDDY_LEAVE);
+		gs = find_group_show(g->name);
+		bs = find_buddy_show(gs, b->name);
+		bs->connlist = g_slist_remove(bs->connlist, gc);
+		if (b->log_timer > 0)
+			gtk_timeout_remove(b->log_timer);
+		b->log_timer = gtk_timeout_add(10000, (GtkFunction)log_timeout, bs);
+		pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, logout_icon_xpm);
+		gtk_widget_hide(bs->pix);
+		gtk_pixmap_set(GTK_PIXMAP(bs->pix), pm, bm);
+		gtk_widget_show(bs->pix);
+		if (ticker_prefs & OPT_DISP_SHOW_BUDDYTICKER)
+			BuddyTickerSetPixmap(b->name, pm, bm);
+		gdk_pixmap_unref(pm);
+		gdk_bitmap_unref(bm);
+	}
 }
 
 
@@ -2086,7 +1907,6 @@
 void refresh_buddy_window()
 {
         build_edit_tree();
-	build_permit_tree();
         
         update_button_pix();
         gtk_widget_show(blist);
--- a/src/buddy_chat.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/buddy_chat.c	Fri Oct 27 07:53:32 2000 +0000
@@ -158,6 +158,7 @@
 		gtk_window_set_focus(GTK_WINDOW(joinchat), entry);
 		gtk_widget_show(entry);
 
+#ifndef NO_MULTI
 		hbox = gtk_hbox_new(TRUE, 10);
 		gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 5);
 		gtk_widget_show(hbox);
@@ -167,6 +168,9 @@
 		gtk_widget_show(label);
 
 		create_joinchat_menu(hbox);
+#else
+		joinchatgc = connections->data;
+#endif
 
 		hbox = gtk_hbox_new(TRUE, 10);
 		gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 5);
@@ -843,7 +847,7 @@
 		c->close = change_text(c->window, _("Close"), c->close, cancel_xpm, opt);
 		gtk_box_reorder_child(GTK_BOX(parent), c->close, 0);
 		gtk_box_set_child_packing(GTK_BOX(parent), c->sep1, dispstyle, dispstyle, 0, GTK_PACK_END);
-		if (find_buddy(c->name) == NULL)
+		if (find_buddy(c->gc, c->name) == NULL)
 			c->add = change_text(c->window, _("Add"), c->add, gnome_add_xpm, opt);
 		else
 			c->add = change_text(c->window, _("Remove"), c->add, gnome_remove_xpm, opt);
--- a/src/conversation.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/conversation.c	Fri Oct 27 07:53:32 2000 +0000
@@ -135,9 +135,9 @@
 		fclose(fd);
 	}
 
-        show_conv(c);
 	if (connections)
 		c->gc = (struct gaim_connection *)connections->data;
+        show_conv(c);
         conversations = g_list_append(conversations, c);
 	plugin_event(event_new_conversation, name, 0, 0, 0);
         return c;
@@ -406,26 +406,16 @@
 
 void add_callback(GtkWidget *widget, struct conversation *c)
 {
-	if (find_buddy(c->name) != NULL) {
-		int dispstyle;
-		GtkWidget *parent = c->add->parent;
-
-		dispstyle = set_dispstyle(0);
-
+	if (c->gc && find_buddy(c->gc, c->name) != NULL) {
 		sprintf(debug_buff,_("Removing '%s' from buddylist.\n"), c->name);
 		debug_print(debug_buff);
-		remove_buddy(find_group_by_buddy(c->name), find_buddy(c->name));
+		remove_buddy(c->gc, find_group_by_buddy(c->gc, c->name), find_buddy(c->gc, c->name));
 		build_edit_tree();
-		gtk_widget_destroy(c->add);
-		c->add = picture_button2(c->window, _("Add"), gnome_add_xpm, dispstyle);
-		gtk_signal_connect(GTK_OBJECT(c->add), "clicked", GTK_SIGNAL_FUNC(add_callback), c);
-		gtk_box_pack_end(GTK_BOX(parent), c->add, dispstyle, dispstyle, 0);
-		gtk_box_reorder_child(GTK_BOX(parent), c->add, 2);
-		gtk_widget_show(c->add);
+		update_convo_add_button(c);
 	}
 	else
 	{
-        	show_add_buddy(c->name, NULL);
+        	show_add_buddy(c->gc, c->name, NULL);
 	}
 
 	gtk_widget_grab_focus(c->entry);
@@ -1181,20 +1171,20 @@
 
 	if (!who) {
 		if (flags & WFLAG_SEND) {
-			b = find_buddy(c->gc->username);
+			b = find_buddy(c->gc, c->gc->username);
 			if (b)
 				who = b->show;
 			else
 				who = c->gc->username;
 		} else {
-			b = find_buddy(c->name);
+			b = find_buddy(c->gc, c->name);
 			if (b)
 				who = b->show;
 			else
 				who = c->name;
 		}
 	} else {
-		b = find_buddy(who);
+		b = find_buddy(c->gc, who);
 		if (b)
 			who = b->show;
 	}
@@ -1598,6 +1588,24 @@
 	cnv->gc = c;
 }
 
+void update_convo_add_button(struct conversation *c)
+{
+	int dispstyle = set_dispstyle(0);
+	GtkWidget *parent = c->add->parent;
+	gtk_widget_destroy(c->add);
+	
+	if (c->gc && find_buddy(c->gc, c->name)) {
+		/* remove */
+		c->add = picture_button2(c->window, _("Remove"), gnome_remove_xpm, dispstyle);
+	} else {
+		c->add = picture_button2(c->window, _("Add"), gnome_remove_xpm, dispstyle);
+	}
+	gtk_signal_connect(GTK_OBJECT(c->add), "clicked", GTK_SIGNAL_FUNC(add_callback), c);
+	gtk_box_pack_end(GTK_BOX(parent), c->add, dispstyle, dispstyle, 0);
+	gtk_box_reorder_child(GTK_BOX(parent), c->add, 2);
+	gtk_widget_show(c->add);
+}
+
 static void create_convo_menu(struct conversation *cnv)
 {
 	GtkWidget *menu, *opt;
@@ -1643,6 +1651,8 @@
 		else
 			C->gc = NULL;
 
+		update_convo_add_button(C);
+
 		c = c->next;
 	}
 }
@@ -1684,7 +1694,7 @@
 	info = picture_button2(win, _("Info"), tb_search_xpm, dispstyle);
 	warn = picture_button2(win, _("Warn"), warn_xpm, dispstyle);
 	close = picture_button2(win, _("Close"), cancel_xpm, dispstyle);
-	if (find_buddy(c->name) != NULL)
+	if (c->gc && find_buddy(c->gc, c->name) != NULL)
 		add = picture_button2(win, _("Remove"), gnome_remove_xpm, dispstyle);
 	else
 		add = picture_button2(win, _("Add"), gnome_add_xpm, dispstyle);
--- a/src/dialogs.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/dialogs.c	Fri Oct 27 07:53:32 2000 +0000
@@ -777,35 +777,31 @@
 {
 	char *grp, *who;
         struct conversation *c;
+	GSList *n = connections;
+	struct gaim_connection *g;
         
 	who = gtk_entry_get_text(GTK_ENTRY(a->entry));
         grp = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(a->combo)->entry));
 
         c = find_conversation(who);
 
-        add_buddy(grp, who, NULL);
+	/* FIXME */
+        add_buddy(connections->data, grp, who, NULL);
 
         if (c != NULL) {
-		int dispstyle = set_dispstyle(0);
-		GtkWidget *parent = c->add->parent;
-		gtk_widget_destroy(c->add);
-		c->add = picture_button2(c->window, _("Remove"), gnome_remove_xpm, dispstyle);
-		gtk_signal_connect(GTK_OBJECT(c->add), "clicked", GTK_SIGNAL_FUNC(add_callback), c);
-		gtk_box_pack_end(GTK_BOX(parent), c->add, dispstyle, dispstyle, 0);
-		gtk_box_reorder_child(GTK_BOX(parent), c->add, 2);
-		gtk_widget_show(c->add);
+		update_convo_add_button(c);
 	}
         
         build_edit_tree();
 
-        serv_save_config();
-
-        serv_add_buddy(who);
+	while (n) {
+		g = (struct gaim_connection *)n->data;
+		serv_add_buddy(g, who);
+		n = n->next;
+	}
 
 	do_export( (GtkWidget *) NULL, 0 );
 
-        update_num_groups();
-
         destroy_dialog(NULL, a->window);
 }
 
@@ -815,26 +811,23 @@
 
 	grp = gtk_entry_get_text(GTK_ENTRY(a->entry));
 
-	add_group(grp);
+	/* FIXME */
+	add_group(connections->data, grp);
 
 	build_edit_tree();
 
-	serv_save_config();
-
 	do_export( (GtkWidget *) NULL, 0 );
 
-	update_num_groups();
-
 	destroy_dialog(NULL, a->window);
 }
 
 
-static GList *groups_tree()
+static GList *groups_tree(struct gaim_connection *gc)
 {
 	GList *tmp=NULL;
         char *tmp2;
 	struct group *g;
-        GSList *grp = groups;
+        GSList *grp = gc->groups;
         
 	if (!grp) {
                 tmp2 = g_strdup(_("Buddies"));
@@ -930,7 +923,7 @@
 	gtk_widget_show(a->window);
 }
 
-void show_add_buddy(char *buddy, char *group)
+void show_add_buddy(struct gaim_connection *gc, char *buddy, char *group)
 {
 	GtkWidget *cancel;
 	GtkWidget *add;
@@ -956,7 +949,7 @@
         a->entry = gtk_entry_new();
         a->combo = gtk_combo_new();
         /* Fix the combo box */
-        gtk_combo_set_popdown_strings(GTK_COMBO(a->combo), groups_tree());
+        gtk_combo_set_popdown_strings(GTK_COMBO(a->combo), groups_tree(gc ? gc : connections->data));
         /* Put the buttons in the box */
 
 	add = picture_button(a->window, _("Add"), add_xpm);
@@ -1457,7 +1450,11 @@
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
 	gtk_widget_show(vbox);
 
+#ifndef NO_MULTI
 	passwd_multi_menu(vbox, b);
+#else
+	b->gc = connections->data;
+#endif
 
 	/* First Line */
 	hbox = gtk_hbox_new(FALSE, 5);
@@ -1733,38 +1730,13 @@
         }
 
         if (d) {
-		GList *d = deny;
-		char *n = g_strdup(normalize(name));
-		while (d) {
-			if (!strcmp(n, normalize(d->data)))
-				break;
-			d = d->next;
-		}
-		g_free(n);
-		if (!d) {
-	                deny = g_list_append(deny, name);
-        	        serv_add_deny(name);
-		}
+		/* FIXME */
+		serv_add_deny(connections->data, name);
         } else {
-		GList *d = permit;
-		char *n = g_strdup(normalize(name));
-		while (d) {
-			if (!strcmp(n, normalize(d->data)))
-				break;
-			d = d->next;
-		}
-		g_free(n);
-		if (!d) {
-			permit = g_list_append(permit, name);
-			serv_add_permit(name);
-		}
+		/* FIXME */
+		serv_add_permit(connections->data, name);
         }
 
-
-
-        build_permit_tree();
-
-        serv_save_config();
 	do_export(0, 0);
 
         destroy_dialog(NULL, p->window);
@@ -2697,7 +2669,7 @@
 		file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(exportdialog));
 		strncpy( path, file, PATHSIZE - 1 );
 		if ((f = fopen(path,"w"))) {
-			serv_build_config(buf, 8192 - 1, TRUE);
+			toc_build_config(connections->data, buf, 8192 - 1, TRUE);
 			fprintf(f, "%s\n", buf);
 			fclose(f);
 			chmod(buf, S_IRUSR | S_IWUSR);
@@ -2733,7 +2705,7 @@
 				if ((f = fopen(path,"w"))) {
 					sprintf(debug_buff, "writing %s\n", path);
 					debug_print(debug_buff);
-					serv_build_config(buf, 8192 - 1, TRUE);
+					toc_build_config(g, buf, 8192 - 1, TRUE);
 					fprintf(f, "%s\n", buf);
 					fclose(f);
 					chmod(buf, S_IRUSR | S_IWUSR);
@@ -2871,10 +2843,7 @@
 
         parse_toc_buddy_list(gc, buf, 1);
 
-        serv_save_config();
-
         build_edit_tree();
-        build_permit_tree();
 
 	fclose( f );
 
@@ -3233,7 +3202,8 @@
 	char *name, *who;
 	struct buddy *b;
 	name = g_strdup(gtk_entry_get_text(GTK_ENTRY(aliasentry)));
-	if ((b = find_buddy(name)) == NULL) {
+	/* FIXME */
+	if ((b = find_buddy(connections->data, name)) == NULL) {
 		g_free(name);
 		destroy_dialog(aliasdlg, aliasdlg);
 		return;
@@ -3242,9 +3212,10 @@
 	do_export(0, 0);
 	who = g_malloc(sizeof(b->show) + 10);
 	strcpy(who, b->show);
-	gtk_label_set(GTK_LABEL(b->label), who);
+	/* FIXME */
+	/* gtk_label_set(GTK_LABEL(b->label), who); */
 	g_free(who);
-	set_buddy(b);
+	/* set_buddy(b); */
 	g_free(name);
 	destroy_dialog(aliasdlg, aliasdlg);
 }
--- a/src/gaim.h	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/gaim.h	Fri Oct 27 07:53:32 2000 +0000
@@ -74,8 +74,7 @@
 
 #define IDLE_NONE        0
 #define IDLE_GAIM        1
-#define IDLE_SYSTEM      2
-#define IDLE_SCREENSAVER 3
+#define IDLE_SCREENSAVER 2
 
 #define WFLAG_SEND 1
 #define WFLAG_RECV 2
@@ -134,6 +133,8 @@
 	int options;
 	int protocol;
 
+	struct gaim_connection *gc;
+
 	/* stuff for modify window */
 	GtkWidget *mod;
 	GtkWidget *name;
@@ -218,10 +219,6 @@
 struct buddy {
 	char name[80];
 	char show[80];
-	GtkWidget *item;
-	GtkWidget *label;
-	GtkWidget *pix;
-        GtkWidget *idletime;
         int present;
         int log_timer;
 	int evil;
@@ -250,11 +247,8 @@
 };
 
 struct group {
-	GtkWidget *item;
-        GtkWidget *label;
-        GtkWidget *tree;
 	char name[80];
-	GList *members;
+	GSList *members;
 };
 
 struct chat_room {
@@ -467,12 +461,9 @@
 /* Globals in toc.c */
 
 /* Globals in aim.c */
-extern GList *permit;  /* The list of people permitted */
-extern GList *deny;    /* The list of people denied */
 extern GList *log_conversations;
 extern GList *buddy_pounces;
 extern GSList *away_messages;
-extern GSList *groups;
 extern GList *conversations;
 extern GList *chat_rooms;
 extern GtkWidget *mainwindow;
@@ -484,7 +475,6 @@
 extern GtkWidget *awaymenu;
 
 /* Globals in buddy.c */
-extern int permdeny;
 extern GtkWidget *buddies;
 extern GtkWidget *bpmenu;
 extern GtkWidget *blist;
@@ -616,7 +606,7 @@
 extern void aol_icon(GdkWindow *);
 extern FILE *open_log_file (char *);
 extern char *sec_to_text(int);
-extern struct aim_user *find_user(const char *);
+extern struct aim_user *find_user(const char *, int);
 extern char *full_date();
 extern void check_gaim_versions();
 extern void spell_checker(GtkWidget *);
@@ -645,14 +635,14 @@
 extern void serv_set_info(struct gaim_connection *, char *);
 extern void serv_set_away(char *);
 extern void serv_change_passwd(struct gaim_connection *, char *, char *);
-extern void serv_add_buddy(char *);
-extern void serv_add_buddies(GList *);
-extern void serv_remove_buddy(char *);
-extern void serv_add_permit(char *);
-extern void serv_add_deny(char *);
-extern void serv_set_permit_deny();
-extern void serv_build_config(char *, int, gboolean);
-extern void serv_save_config();
+extern void serv_add_buddy(struct gaim_connection *, char *);
+extern void serv_add_buddies(struct gaim_connection *, GList *);
+extern void serv_remove_buddy(struct gaim_connection *, 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_set_permit_deny(struct gaim_connection *);
 extern void serv_warn(struct gaim_connection *, char *, int);
 extern void serv_set_dir(char *, char *, char *, char *, char *, char *, char *, int);
 extern void serv_dir_search(char *, char *, char *, char *, char *, char *, char *, char *);
@@ -664,7 +654,7 @@
 extern void serv_chat_send(struct gaim_connection *, int, char *);
 
 /* output from serv */
-extern void serv_got_update(char *, int, int, time_t, time_t, int, u_short);
+extern void serv_got_update(struct gaim_connection *, char *, int, int, time_t, time_t, int, u_short);
 extern void serv_got_im(struct gaim_connection *, char *, char *, int);
 extern void serv_got_eviled(char *, int);
 extern void serv_got_chat_invite(struct gaim_connection *, char *, int, char *, char *);
@@ -675,6 +665,7 @@
 extern void serv_rvous_cancel(struct gaim_connection *, char *, char *, char *);
 
 /* Functions in conversation.c */
+extern void update_convo_add_button(struct conversation *);
 extern void write_html_with_smileys(GtkWidget *, GtkWidget *, char *);
 extern void write_to_conv(struct conversation *, char *, int, char *);
 extern void show_conv(struct conversation *);
@@ -722,32 +713,28 @@
 
 /* Functions in buddy.c */
 extern void destroy_buddy();
-extern void update_num_groups();
-extern void update_show_idlepix();
 extern void update_button_pix();
 extern void update_all_buddies();
 extern void show_buddy_list();
 extern void refresh_buddy_window();
-extern void toc_build_config(char *, int len, gboolean);
+extern void toc_build_config(struct gaim_connection *, char *, int len, gboolean);
 extern void signoff(struct gaim_connection *);
 extern void signoff_all(GtkWidget *, gpointer);
 extern void do_im_back();
-extern void set_buddy(struct buddy *);
-extern struct person *add_person(char *, char *);
-extern struct group *add_group(char *);
+extern void set_buddy(struct gaim_connection *, struct buddy *);
+extern struct group *add_group(struct gaim_connection *, char *);
 extern void add_category(char *);
 extern void build_edit_tree();
 extern void remove_person(struct group *, struct buddy *);
 extern void remove_category(struct group *);
 extern void do_pounce(char *);
 extern void do_bp_menu();
-extern struct buddy *find_buddy(char *);
-extern struct group *find_group(char *);
-extern struct group *find_group_by_buddy(char *);
-extern void remove_buddy(struct group *, struct buddy *);
-extern struct buddy *add_buddy(char *, char *, char *);
-extern void remove_group(struct group *);
-extern void update_lagometer(int);
+extern struct buddy *find_buddy(struct gaim_connection *, char *);
+extern struct group *find_group(struct gaim_connection *, char *);
+extern struct group *find_group_by_buddy(struct gaim_connection *, char *);
+extern void remove_buddy(struct gaim_connection *, struct group *, struct buddy *);
+extern struct buddy *add_buddy(struct gaim_connection *, char *, char *, char *);
+extern void remove_group(struct gaim_connection *, struct group *);
 
 /* Functions in away.c */
 extern void rem_away_mess(GtkWidget *, struct away_message *);
@@ -799,7 +786,6 @@
 extern void set_option(GtkWidget *, int *);
 extern void show_prefs();
 extern void show_debug(GtkObject *);
-extern void build_permit_tree();
 extern void update_color(GtkWidget *, GtkWidget *);
 extern GtkWidget *prefs_away_list;
 extern GtkWidget *pref_fg_picture;
@@ -820,7 +806,7 @@
 extern void show_error_dialog(char *);
 extern void show_im_dialog();
 extern void show_info_dialog();
-extern void show_add_buddy(char *, char *);
+extern void show_add_buddy(struct gaim_connection *, char *, char *);
 extern void show_add_group();
 extern void show_add_perm();
 extern void destroy_all_dialogs();
--- a/src/gnome_applet_mgr.h	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/gnome_applet_mgr.h	Fri Oct 27 07:53:32 2000 +0000
@@ -78,7 +78,6 @@
 
 extern void update_pixmaps();
 extern void applet_set_tooltips(char *);
-extern void dologin(GtkWidget *, GtkWidget *);
 
 extern gboolean applet_buddy_show;
 
--- a/src/idle.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/idle.c	Fri Oct 27 07:53:32 2000 +0000
@@ -47,7 +47,6 @@
 #endif
 
         /* Not idle, really...  :) */
-	update_all_buddies();
 
 	plugin_event(event_blist_update, 0, 0, 0, 0);
         
--- a/src/multi.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/multi.c	Fri Oct 27 07:53:32 2000 +0000
@@ -56,6 +56,9 @@
 	gc->keepalive = -1;
 	gc->inpa = -1;
 	gc->buddy_chats = NULL;
+	gc->groups = NULL;
+	gc->permit = NULL;
+	gc->deny = NULL;
 
 	connections = g_slist_append(connections, gc);
 
@@ -206,8 +209,7 @@
 	} else {
 		char *titles[4];
 		txt = gtk_entry_get_text(GTK_ENTRY(tmpusr.name));
-		if (find_user(txt)) {
-			/* PRPL: also need to check protocol. remember TOC and Oscar are both AIM */
+		if (find_user(txt, tmpusr.protocol)) {
 			gtk_widget_destroy(newmod);
 			return;
 		}
@@ -406,13 +408,11 @@
 static void mod_acct(GtkWidget *w, gpointer d)
 {
 	int row = -1;
-	char *name;
 	struct aim_user *u;
 	if (GTK_CLIST(list)->selection)
 		row = (int)GTK_CLIST(list)->selection->data;
 	if (row != -1) {
-		gtk_clist_get_text(GTK_CLIST(list), row, 0, &name);
-		u = find_user(name);
+		u = g_list_nth_data(aim_users, row);
 		if (u)
 			show_acct_mod(u);
 	}
@@ -502,16 +502,12 @@
 static void acct_signin(GtkWidget *w, gpointer d)
 {
 	int row = -1;
-	char *name;
 	struct aim_user *u;
-	struct gaim_connection *gc;
 	if (GTK_CLIST(list)->selection)
 		row = (int)GTK_CLIST(list)->selection->data;
 	if (row != -1) {
-		gtk_clist_get_text(GTK_CLIST(list), row, 0, &name);
-		u = find_user(name);
-		gc = find_gaim_conn_by_name(name);
-		if (!gc) {
+		u = g_list_nth_data(aim_users, row);
+		if (!u->gc) {
 			if (!u->password[0]) {
 				do_pass_dlg(u);
 			} else {
@@ -521,7 +517,7 @@
 				serv_login(u);
 			}
 		} else {
-			signoff(gc);
+			signoff(u->gc);
 		}
 	}
 }
@@ -529,13 +525,11 @@
 static void del_acct(GtkWidget *w, gpointer d)
 {
 	int row = -1;
-	char *name;
 	struct aim_user *u;
 	if (GTK_CLIST(list)->selection)
 		row = (int)GTK_CLIST(list)->selection->data;
 	if (row != -1) {
-		gtk_clist_get_text(GTK_CLIST(list), row, 0, &name);
-		u = find_user(name);
+		u = g_list_nth_data(aim_users, row);
 		if (u) {
 			aim_users = g_list_remove(aim_users, u);
 			save_prefs();
@@ -603,11 +597,13 @@
 	gtk_widget_show(acctedit);
 }
 
-void account_online(struct gaim_connection *gc)
+void account_online(struct aim_user *u, struct gaim_connection *gc)
 {
-	struct aim_user *u;
 	int i;
 
+	gc->user = u;
+	u->gc = gc;
+
 	/* first we hide the login progress meter */
 	if (gc->meter)
 		gtk_widget_destroy(gc->meter);
@@ -640,8 +636,7 @@
 
 	/* everything for the account editor */
 	if (!acctedit) return;
-	u = find_user(gc->username);
-	i = gtk_clist_find_row_from_data(GTK_CLIST(list), u);
+	i = gtk_clist_find_row_from_data(GTK_CLIST(list), gc->user);
 	gtk_clist_set_text(GTK_CLIST(list), i, 1, "Yes");
 	gtk_clist_set_text(GTK_CLIST(list), i, 3, proto_name(gc->protocol));
 
@@ -650,11 +645,10 @@
 
 void account_offline(struct gaim_connection *gc)
 {
-	struct aim_user *u;
 	int i;
+	gc->user->gc = NULL; /* wasn't that awkward? */
 	if (!acctedit) return;
-	u = find_user(gc->username);
-	i = gtk_clist_find_row_from_data(GTK_CLIST(list), u);
+	i = gtk_clist_find_row_from_data(GTK_CLIST(list), gc->user);
 	gtk_clist_set_text(GTK_CLIST(list), i, 1, "No");
 	redo_convo_menus();
 }
--- a/src/multi.h	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/multi.h	Fri Oct 27 07:53:32 2000 +0000
@@ -36,12 +36,21 @@
 	/* 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;
 
 	/* each connection then can have its own protocol-specific data */
 	void *proto_data;
 
+	struct aim_user *user;
+
 	char username[64];
 	char password[32];
 	char user_info[2048];
@@ -70,7 +79,7 @@
 
 void account_editor(GtkWidget *, GtkWidget *);
 
-void account_online(struct gaim_connection *);
+void account_online(struct aim_user *, struct gaim_connection *);
 void account_offline(struct gaim_connection *);
 
 void auto_login();
--- a/src/oscar.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/oscar.c	Fri Oct 27 07:53:32 2000 +0000
@@ -45,8 +45,11 @@
 #include "aim.h"
 #include "gnome_applet_mgr.h"
 
-#include "pixmaps/cancel.xpm"
-#include "pixmaps/ok.xpm"
+#include "pixmaps/admin_icon.xpm"
+#include "pixmaps/aol_icon.xpm"
+#include "pixmaps/away_icon.xpm"
+#include "pixmaps/dt_icon.xpm"
+#include "pixmaps/free_icon.xpm"
 
 int gaim_caps = AIM_CAPS_CHAT | AIM_CAPS_SENDFILE | AIM_CAPS_GETFILE |
 		AIM_CAPS_VOICE | AIM_CAPS_IMIMAGE | AIM_CAPS_BUDDYICON;
@@ -258,6 +261,7 @@
 	char buf[256];
 	struct gaim_connection *gc = new_gaim_conn(PROTO_OSCAR, user->username, user->password);
 	struct oscar_data *odata = gc->proto_data = g_new0(struct oscar_data, 1);
+	gc->user = user;
 
 	sprintf(debug_buff, _("Logging in %s\n"), user->username);
 	debug_print(debug_buff);
@@ -579,6 +583,7 @@
 	struct aim_userinfo_s *info;
 	time_t time_idle;
 	int type = 0;
+	struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
 
 	va_list ap;
 	va_start(ap, command);
@@ -602,7 +607,7 @@
 	} else
 		time_idle = 0;
 
-	serv_got_update(info->sn, 1, info->warnlevel/10, info->onlinesince,
+	serv_got_update(gc, info->sn, 1, info->warnlevel/10, info->onlinesince,
 			time_idle, type, info->capabilities);
 
 	return 1;
@@ -612,12 +617,13 @@
 			struct command_rx_struct *command, ...) {
 	char *sn;
 	va_list ap;
+	struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
 
 	va_start(ap, command);
 	sn = va_arg(ap, char *);
 	va_end(ap);
 
-	serv_got_update(sn, 0, 0, 0, 0, 0, 0);
+	serv_got_update(gc, sn, 0, 0, 0, 0, 0, 0);
 
 	return 1;
 }
@@ -1063,7 +1069,7 @@
 		aim_bos_setprofile(sess, command->conn, gc->user_info, NULL, gaim_caps);
 		aim_bos_reqbuddyrights(sess, command->conn);
 
-		account_online(gc);
+		account_online(gc->user, gc); /* this is an awkward hack */
 		serv_finish_login(gc);
 
 		if (bud_list_cache_exists(gc))
@@ -1144,7 +1150,6 @@
 
 static void oscar_send_im(struct gaim_connection *gc, char *name, char *message, int away) {
 	struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
-	struct conversation *cnv = find_conversation(name);
 	if (away)
 		aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_AWAY, message);
 	else
@@ -1326,9 +1331,24 @@
 	aim_chat_send_im(odata->sess, cn, message);
 }
 
+static char **oscar_list_icon(int uc) {
+	if (uc & UC_UNAVAILABLE)
+		return (char **)away_icon_xpm;
+	if (uc & UC_AOL)
+		return (char **)aol_icon_xpm;
+	if (uc & UC_NORMAL)
+		return (char **)free_icon_xpm;
+	if (uc & UC_ADMIN)
+		return (char **)admin_icon_xpm;
+	if (uc & UC_UNCONFIRMED)
+		return (char **)dt_icon_xpm;
+	return NULL;
+}
+
 void oscar_init(struct prpl *ret) {
 	ret->protocol = PROTO_OSCAR;
 	ret->name = oscar_name;
+	ret->list_icon = oscar_list_icon;
 	ret->login = oscar_login;
 	ret->close = oscar_close;
 	ret->send_im = oscar_send_im;
--- a/src/perl.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/perl.c	Fri Oct 27 07:53:32 2000 +0000
@@ -335,6 +335,7 @@
 
 XS (XS_AIM_buddy_list)
 {
+	/* FIXME
 	struct buddy *buddy;
 	struct group *g;
 	GSList *list = groups;
@@ -354,10 +355,12 @@
 		list = g_slist_next(list);
 	}
 	XSRETURN(i);
+	*/
 }
 
 XS (XS_AIM_online_list)
 {
+	/* FIXME
 	struct buddy *b;
 	struct group *g;
 	GSList *list = groups;
@@ -377,10 +380,12 @@
 		list = g_slist_next(list);
 	}
 	XSRETURN(i);
+	*/
 }
 
 XS (XS_AIM_deny_list)
 {
+	/* FIXME, yet again. perl is so fucked
 	char *name;
 	GList *list = deny;
 	int i = 0;
@@ -393,6 +398,7 @@
 		list = list->next;
 	}
 	XSRETURN(i);
+	*/
 }
 
 XS (XS_AIM_command)
@@ -437,6 +443,7 @@
 
 XS (XS_AIM_user_info)
 {
+	/* FIXME
 	int junk;
 	struct buddy *buddy;
 	char *nick;
@@ -457,6 +464,7 @@
 	XST_mIV(5, buddy->uc);
 	XST_mIV(6, buddy->caps);
 	XSRETURN(7);
+	*/
 }
 
 XS (XS_AIM_print_to_conv)
--- a/src/prefs.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/prefs.c	Fri Oct 27 07:53:32 2000 +0000
@@ -406,251 +406,6 @@
 	gtk_widget_show(prefdialog);
 }
 
-static GtkWidget *permtree = NULL;
-
-static void build_deny_tree()
-{
-	GtkWidget *ti;
-        GtkWidget *sub;
-        GList *plist = permit;
-        GList *dlist = deny;
-
-	if (!permtree) return;
-
-        gtk_tree_clear_items(GTK_TREE(permtree), 0, -1);
-
-        ti = gtk_tree_item_new_with_label(_("Permit"));
-        sub = gtk_tree_new();
-        gtk_widget_show(ti);
-        gtk_widget_show(sub);
-        gtk_tree_prepend(GTK_TREE(permtree), ti);
-        gtk_tree_item_set_subtree(GTK_TREE_ITEM(ti), sub);
-        gtk_tree_item_expand(GTK_TREE_ITEM(ti));
-        
-        while(plist) {
-                ti = gtk_tree_item_new_with_label((char *)plist->data);
-                gtk_widget_show(ti);
-                gtk_tree_prepend(GTK_TREE(sub), ti);
-                plist = plist->next;
-        }
-
-
-        ti = gtk_tree_item_new_with_label(_("Deny"));
-        sub = gtk_tree_new();
-        gtk_widget_show(ti);
-        gtk_widget_show(sub);
-        gtk_tree_prepend(GTK_TREE(permtree), ti);
-        gtk_tree_item_set_subtree(GTK_TREE_ITEM(ti), sub);
-        gtk_tree_item_expand(GTK_TREE_ITEM(ti));
-        
-        while(dlist) {
-                ti = gtk_tree_item_new_with_label((char *)dlist->data);
-                gtk_widget_show(ti);
-                gtk_tree_prepend(GTK_TREE(sub), ti);
-                dlist = dlist->next;
-        }
-}
-
-static void do_del_perm(GtkWidget *w, GtkTree *ptree)
-{
-	GtkLabel *label, *plabel;
-	GtkWidget *item, *pitem;
-	char *c, *d;
-	GList *i;
-	
-        GList *plist;
-        GList *dlist;
-	int level;
-
-        plist = permit;
-        dlist = deny;
-        
-	i = GTK_TREE_SELECTION(ptree);
-	if (i) {
-		item = GTK_WIDGET(i->data);
-		gtk_tree_unselect_child(GTK_TREE(ptree), item);
-		label = GTK_LABEL(GTK_BIN(item)->child);
-		gtk_label_get(label, &c);
-		level = GTK_TREE(item->parent)->level;
-		if (level > 0) {
-			pitem = GTK_WIDGET(GTK_TREE(item->parent)->tree_owner);
-			plabel = GTK_LABEL(GTK_BIN(pitem)->child);
-			gtk_label_get(plabel, &d);
-                        if (!strcasecmp(d, _("Permit"))) {
-                                while(plist) {
-                                        if (!strcasecmp((char *)(plist->data), c)) {
-                                                permit = g_list_remove(permit, plist->data);
-                                                break;
-                                        }
-
-                                        plist = plist->next;
-                                }
-
-                        } else {
-                                while(dlist) {
-                                        if (!strcasecmp((char *)(dlist->data), c)) {
-                                                deny = g_list_remove(deny, dlist->data);
-                                                
-                                                break;
-                                        }
-                                        dlist = dlist->next;
-                                }
-
-                        }
-
-                        
-                } else {
-                        /* Can't delete groups here! :) */
-                        return;
-                }
-                serv_set_permit_deny();
-		gtk_tree_clear_items(GTK_TREE(ptree), 0, -1);
-                build_permit_tree();
-                serv_save_config();
-		do_export(0, 0);
-	}
-}
-
-
-static void set_permit(GtkWidget *w, int *data)
-{
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
-		permdeny = (int)data;
-	        if (blist) {
-			do_export(0, 0);
-			serv_save_config();
-			/* we do this here because we can :) */
-			serv_set_permit_deny();
-		}
-	}
-}
-
-static GtkWidget *deny_radio(char *label, int which, GtkWidget *box, GtkWidget *set)
-{
-	GtkWidget *opt;
-
-	if (!set)
-		opt = gtk_radio_button_new_with_label(NULL, label);
-	else
-		opt = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(set)), label);
-	gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0);
-	gtk_signal_connect(GTK_OBJECT(opt), "clicked", GTK_SIGNAL_FUNC(set_permit), (void *)which);
-	gtk_widget_show(opt);
-	if (permdeny == which)
-		gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(opt), TRUE);
-
-	return opt;
-}
-
-static void permdest(GtkWidget *m, gpointer n)
-{
-	do_export(0, 0);
-	serv_save_config();
-	gtk_widget_destroy(permtree);
-	permtree = NULL;
-}
-
-static void add_perm_callback(GtkWidget *widget, void *dummy)
-{
-	if (!blist)
-		do_error_dialog(_("Please sign on before editing the permit/deny lists."),
-				_("Please sign on"));
-	else
-	        show_add_perm(NULL);
-}
-
-static void deny_page()
-{
-	GtkWidget *parent;
-	GtkWidget *box;
-	GtkWidget *label;
-	GtkWidget *sep;
-	GtkWidget *hbox;
-	GtkWidget *vbox;
-	GtkWidget *xbox;
-	GtkWidget *opt;
-	GtkWidget *button;
-
-	parent = prefdialog->parent;
-	gtk_widget_destroy(prefdialog);
-
-	prefdialog = gtk_frame_new(_("Permit/Deny List Options"));
-	gtk_container_add(GTK_CONTAINER(parent), prefdialog);
-
-	box = gtk_vbox_new(FALSE, 5);
-	gtk_container_add(GTK_CONTAINER(prefdialog), box);
-	gtk_widget_show(box);
-
-	label = gtk_label_new(_("All options take effect immediately unless otherwise noted."));
-	gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5);
-	gtk_widget_show(label);
-
-	sep = gtk_hseparator_new();
-	gtk_box_pack_start(GTK_BOX(box), sep, FALSE, FALSE, 5);
-	gtk_widget_show(sep);
-
-	label = gtk_label_new(_("The permit/deny configuration will change between users,\n"
-				"and changes while you are signed off will not be saved."));
-	gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5);
-	gtk_widget_show(label);
-
-	hbox = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 5);
-	gtk_widget_show(hbox);
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 5);
-	gtk_widget_show(vbox);
-
-	opt = deny_radio(_("Allow Anyone"), PERMIT_ALL, vbox, NULL);
-#if 0
-	/* This doesn't work because TOC doesn't have a PERMIT_BUDDY setting
-	 * and merging the two would be very difficult at best, most likely
-	 * impossible. If we can guarantee only Oscar than this is easy */
-	opt = deny_radio(_("Allow only users on Buddy List"), PERMIT_BUDDY, vbox, opt);
-#endif
-	opt = deny_radio(_("Allow only the users in \"Permit\""), PERMIT_SOME, vbox, opt);
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 5);
-	gtk_widget_show(vbox);
-
-	opt = deny_radio(_("Block all users"), PERMIT_NONE, vbox, opt);
-	opt = deny_radio(_("Block the users in \"Deny\""), DENY_SOME, vbox, opt);
-
-	xbox = gtk_scrolled_window_new(NULL, NULL);
-	gtk_box_pack_start(GTK_BOX(box), xbox, TRUE, TRUE, 5);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(xbox),
-					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	gtk_widget_show(xbox);
-
-	permtree = gtk_tree_new();
-	build_deny_tree();
-	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(xbox), permtree);
-	gtk_signal_connect(GTK_OBJECT(permtree), "destroy", GTK_SIGNAL_FUNC(permdest), 0);
-	gtk_widget_show(permtree);
-
-	hbox = gtk_hbox_new(TRUE, 10);
-	gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 5);
-	gtk_widget_show(hbox);
-
-	button = picture_button(prefs, _("Add"), gnome_add_xpm);
-	gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 10);
-	gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(add_perm_callback), NULL);
-
-	button = picture_button(prefs, _("Remove"), gnome_remove_xpm);
-	gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 10);
-	gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_del_perm), permtree);
-
-	gtk_widget_show(prefdialog);
-}
-
-void build_permit_tree()
-{
-	if (permtree)
-		deny_page();
-}
-
 static void convo_page()
 {
 	GtkWidget *parent;
@@ -2039,19 +1794,13 @@
 
 void prefs_build_buddy(GtkWidget *preftree)
 {
-	GtkCTreeNode *parent, *node;
+	GtkCTreeNode *parent;
 	char *text[1];
 
 	text[0] = _("Buddy List");
 	parent = gtk_ctree_insert_node(GTK_CTREE(preftree), NULL, NULL,
 					text, 5, NULL, NULL, NULL, NULL, 0, 1);
 	gtk_ctree_node_set_row_data(GTK_CTREE(preftree), parent, buddy_page);
-
-	/* FIXME ! We should move this to a per-user configuration */
-	text[0] = _("Permit/Deny");
-	node = gtk_ctree_insert_node(GTK_CTREE(preftree), parent, NULL,
-					text, 5, NULL, NULL, NULL, NULL, 0, 1);
-	gtk_ctree_node_set_row_data(GTK_CTREE(preftree), node, deny_page);
 }
 
 void prefs_build_convo(GtkWidget *preftree)
--- a/src/prpl.h	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/prpl.h	Fri Oct 27 07:53:32 2000 +0000
@@ -39,6 +39,8 @@
 	int protocol;
 	char *(* name)();
 
+	char **(* list_icon)(int);
+
 	void (* login)		(struct aim_user *);
 	void (* close)		(struct gaim_connection *);
 	void (* send_im)	(struct gaim_connection *, char *who, char *message, int away);
--- a/src/server.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/server.c	Fri Oct 27 07:53:32 2000 +0000
@@ -57,17 +57,16 @@
 
 void serv_close(struct gaim_connection *gc)
 {
+	if (gc->idle_timer > 0)
+		gtk_timeout_remove(gc->idle_timer);
+        gc->idle_timer = -1;
+
 	if (gc->prpl && gc->prpl->close)
 		(*gc->prpl->close)(gc);
 
 	account_offline(gc);
 	destroy_gaim_conn(gc);
-
-	if (connections) return;
-
-	if (gc->idle_timer > 0)
-		gtk_timeout_remove(gc->idle_timer);
-        gc->idle_timer = -1;
+	build_edit_tree();
 }
 
 void serv_touch_idle(struct gaim_connection *gc)
@@ -99,7 +98,7 @@
 
         time(&gc->login_time);
 
-        serv_add_buddy(gc->username);
+        serv_add_buddy(gc, gc->username);
 }
 
 
@@ -132,7 +131,7 @@
 	if (!connections) return;
 	g = connections->data;
 
-	if (g && g->prpl && g->prpl->get_info)
+	if (g && g->prpl && g->prpl->get_away_msg)
 		(*g->prpl->get_away_msg)(g, name);
 }
 
@@ -196,165 +195,51 @@
 		(*g->prpl->change_passwd)(g, orig, new);
 }
 
-void serv_add_buddy(char *name)
+void serv_add_buddy(struct gaim_connection *g, char *name)
 {
-	/* FIXME: this will need to be changed. for now all buddies will be added to
-	 * all connections :-P */
-	GSList *c = connections;
-	struct gaim_connection *g;
-
-	while (c) {
-		g = (struct gaim_connection *)c->data;
-		if (g->prpl && g->prpl->add_buddy)
-			(*g->prpl->add_buddy)(g, name);
-		c = c->next;
-	}
-}
-
-void serv_add_buddies(GList *buddies)
-{
-	/* FIXME: see the comment above for adding one buddy :-P */
-	GSList *c = connections;
-	struct gaim_connection *g;
-
-	while (c) {
-		g = (struct gaim_connection *)c->data;
-		if (g->prpl && g->prpl->add_buddies)
-			(*g->prpl->add_buddies)(g, buddies);
-		c = c->next;
-	}
+	if (g->prpl && g->prpl->add_buddy)
+		(*g->prpl->add_buddy)(g, name);
 }
 
-
-void serv_remove_buddy(char *name)
+void serv_add_buddies(struct gaim_connection *g, GList *buddies)
 {
-	/* FIXME: since we added them to all conns, we need to remove them from all conns */
-	GSList *c = connections;
-	struct gaim_connection *g;
-
-	while (c) {
-		g = (struct gaim_connection *)c->data;
-		if (g->prpl && g->prpl->remove_buddy)
-			(*g->prpl->remove_buddy)(g, name);
-		c = c->next;
-	}
-}
-
-void serv_add_permit(char *name)
-{
-	permdeny = 3;
-	build_permit_tree();
-	serv_set_permit_deny();
-}
-
-
-
-void serv_add_deny(char *name)
-{
-	permdeny = 4;
-	build_permit_tree();
-	serv_set_permit_deny();
+	if (g->prpl && g->prpl->add_buddies)
+		(*g->prpl->add_buddies)(g, buddies);
 }
 
 
+void serv_remove_buddy(struct gaim_connection *g, char *name)
+{
+	if (g->prpl && g->prpl->remove_buddy)
+		(*g->prpl->remove_buddy)(g, name);
+}
 
-void serv_set_permit_deny()
+void serv_add_permit(struct gaim_connection *gc, char *name)
+{
+	/* FIXME */
+}
+
+void serv_add_deny(struct gaim_connection *gc, char *name)
 {
 	/* FIXME */
-	struct gaim_connection *g;
-	if (!connections) return;
-	g = connections->data;
-	if (g && g->protocol == PROTO_TOC) {
-		char buf[MSG_LEN];
-		int at;
-		GList *list;
+}
+
+void serv_rem_permit(struct gaim_connection *gc, char *name)
+{
+	/* FIXME */
+}
 
-		switch (permdeny) {
-		case PERMIT_ALL:
-			sprintf(buf, "toc_add_permit %s", g->username);
-			sflap_send(g, buf, -1, TYPE_DATA);
-			sprintf(buf, "toc_add_deny");
-			sflap_send(g, buf, -1, TYPE_DATA);
-			break;
-		case PERMIT_NONE:
-			sprintf(buf, "toc_add_deny %s", g->username);
-			sflap_send(g, buf, -1, TYPE_DATA);
-			sprintf(buf, "toc_add_permit");
-			sflap_send(g, buf, -1, TYPE_DATA);
-			break;
-		case PERMIT_SOME:
-			at = g_snprintf(buf, sizeof(buf), "toc_add_permit");
-			list = permit;
-			while (list) {
-				at += g_snprintf(&buf[at], sizeof(buf) - at, " %s", normalize(list->data));
-				list = list->next;
-			}
-			buf[at] = 0; /* is this necessary? */
-			sflap_send(g, buf, -1, TYPE_DATA);
-			break;
-		case DENY_SOME:
-			/* you'll still see people as being online, but they won't see you, and you
-			 * won't get updates for them. that's why i thought this was broken. */
-			at = g_snprintf(buf, sizeof(buf), "toc_add_deny");
-			list = deny;
-			while (list) {
-				at += g_snprintf(&buf[at], sizeof(buf) - at, " %s", normalize(list->data));
-				list = list->next;
-			}
-			buf[at] = 0; /* is this necessary? */
-			sflap_send(g, buf, -1, TYPE_DATA);
-			break;
-		}
-	} else if (g->protocol == PROTO_OSCAR) {
-/*
-		int at;
-		GList *list;
-		char buf[MSG_LEN];
+void serv_rem_deny(struct gaim_connection *gc, char *name)
+{
+	/* FIXME */
+}
 
-		switch (permdeny) {
-		case PERMIT_ALL:
-			aim_bos_changevisibility(gaim_sess, gaim_conn,
-			   AIM_VISIBILITYCHANGE_DENYADD, current_user->username);
-			break;
-		case PERMIT_NONE:
-			aim_bos_changevisibility(gaim_sess, gaim_conn,
-			   AIM_VISIBILITYCHANGE_PERMITADD, current_user->username);
-			break;
-		case PERMIT_SOME:
-			at = g_snprintf(buf, sizeof(buf), "%s", current_user->username);
-			list = permit;
-			while (list) {
-				at += g_snprintf(&buf[at], sizeof(buf) - at, "&");
-				at += g_snprintf(&buf[at], sizeof(buf) - at, "%s", list->data);
-				list = list->next;
-			}
-			aim_bos_changevisibility(gaim_sess, gaim_conn,
-			   AIM_VISIBILITYCHANGE_PERMITADD, buf);
-			break;
-		case DENY_SOME:
-			if (deny) {
-				at = 0;
-				list = deny;
-				while (list) {
-					at += g_snprintf(&buf[at], sizeof(buf) - at, "%s", list->data);
-					list = list->next;
-					if (list)
-						at += g_snprintf(&buf[at], sizeof(buf) - at, "&");
-				}
-				sprintf(debug_buff, "denying %s\n", buf);
-				debug_print(debug_buff);
-				aim_bos_changevisibility(gaim_sess, gaim_conn,
-				   AIM_VISIBILITYCHANGE_DENYADD, buf);
-			} else {
-				aim_bos_changevisibility(gaim_sess, gaim_conn,
-				   AIM_VISIBILITYCHANGE_DENYADD, current_user->username);
-			}
-			break;
-		}
-*/
-	}
-	do_export(0, 0);
-	serv_save_config();
+void serv_set_permit_deny(struct gaim_connection *gc)
+{
+	/* FIXME */
+	/* this is called when some other function has modified the permit/deny list and
+	 * now wants to register that change with the server. if you're just adding/removing
+	 * one name, use the add/remove functions above */
 }
 
 
@@ -370,29 +255,6 @@
 		(*g->prpl->warn)(g, name, anon);
 }
 
-void serv_build_config(char *buf, int len, gboolean show) {
-	toc_build_config(buf, len, show);
-}
-
-
-void serv_save_config()
-{
-	/* FIXME */
-	struct gaim_connection *g;
-	if (!connections) return;
-	g = connections->data;
-	if (g && g->protocol == PROTO_TOC) {
-		char *buf = g_malloc(BUF_LONG);
-		char *buf2 = g_malloc(MSG_LEN);
-		serv_build_config(buf, BUF_LONG / 2, FALSE);
-		g_snprintf(buf2, MSG_LEN, "toc_set_config {%s}", buf);
-	        sflap_send(g, buf2, -1, TYPE_DATA);
-		g_free(buf2);
-		g_free(buf);
-	}
-}
-
-
 void serv_accept_chat(struct gaim_connection *g, int i)
 {
 	if (g->prpl && g->prpl->accept_chat)
@@ -505,7 +367,7 @@
 	if (awaymessage != NULL) {
 		time_t t;
 		char *tmpmsg;
-		struct buddy *b = find_buddy(name);
+		struct buddy *b = find_buddy(gc, name);
 		char *alias = b ? b->show : name;
 
 		time(&t);
@@ -542,14 +404,13 @@
 
 
 
-void serv_got_update(char *name, int loggedin, int evil, time_t signon, time_t idle, int type, u_short caps)
+void serv_got_update(struct gaim_connection *gc, char *name, int loggedin, int evil, time_t signon, time_t idle, int type, u_short caps)
 {
-        struct buddy *b = find_buddy(name);
-	struct gaim_connection *gc = find_gaim_conn_by_name(name);
+        struct buddy *b = find_buddy(gc, name);
+	struct gaim_connection *g = find_gaim_conn_by_name(name);
                      
-        if (gc) {
-                correction_time = (int)(signon - gc->login_time);
-                update_all_buddies();
+        if (g) {
+                correction_time = (int)(signon - g->login_time);
                 if (!b) {
                         return;
 		}
@@ -561,6 +422,8 @@
                 return;
         }
 
+	debug_printf("got update for %s\n", b->name);
+
         /* This code will 'align' the name from the TOC */
         /* server with what's in our record.  We want to */
         /* store things how THEY want it... */
@@ -616,11 +479,15 @@
                 if (!b->present) {
                         b->present = 1;
                         do_pounce(b->name);
+			plugin_event(event_buddy_signon, b->name, 0, 0, 0);
                 }
-        } else
+        } else {
+		if (b->present)
+			plugin_event(event_buddy_signoff, b->name, 0, 0, 0);
                 b->present = 0;
+	}
 
-        set_buddy(b);
+        set_buddy(gc, b);
 }
 
 static
--- a/src/toc.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/toc.c	Fri Oct 27 07:53:32 2000 +0000
@@ -40,7 +40,13 @@
 #include "gaim.h"
 #include "gnome_applet_mgr.h"
 
-#define REVISION "gaim:$Revision: 1030 $"
+#include "pixmaps/admin_icon.xpm"
+#include "pixmaps/aol_icon.xpm"
+#include "pixmaps/away_icon.xpm"
+#include "pixmaps/dt_icon.xpm"
+#include "pixmaps/free_icon.xpm"
+
+#define REVISION "gaim:$Revision: 1040 $"
 
 struct toc_data {
 	int toc_fd;
@@ -136,7 +142,7 @@
 	while (gtk_events_pending())
 		gtk_main_iteration();
 
-	account_online(gc);
+	account_online(user, gc);
 	serv_finish_login(gc);
 
 	config = toc_wait_config(gc);
@@ -414,7 +420,7 @@
                 } else
                         time_idle = 0;
 		
-                serv_got_update(c, logged, evil, signon, time_idle, type, 0);
+                serv_got_update(gc, c, logged, evil, signon, time_idle, type, 0);
 
 	} else if (!strcasecmp(c, "CONFIG")) {
 		/* do we want to load the buddy list again here? */
@@ -804,21 +810,21 @@
 		return NULL;
 }
 
-void toc_build_config(char *s, int len, gboolean show)
+void toc_build_config(struct gaim_connection *gc, char *s, int len, gboolean show)
 {
-	GSList *grp = groups;
-	GList *mem;
+	GSList *grp = gc->groups;
+	GSList *mem;
 	struct group *g;
 	struct buddy *b;
-	GList *plist = permit;
-	GList *dlist = deny;
+	GSList *plist = gc->permit;
+	GSList *dlist = gc->deny;
 
 	int pos=0;
 
-	if (!permdeny)
-		permdeny = 1;
+	if (!gc->permdeny)
+		gc->permdeny = 1;
 
-	pos += g_snprintf(&s[pos], len - pos, "m %d\n", permdeny);
+	pos += g_snprintf(&s[pos], len - pos, "m %d\n", gc->permdeny);
 	while(grp) {
 		g = (struct group *)grp->data;
 		pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name);
@@ -864,9 +870,9 @@
 				break;
 			if (*c == 'g') {
 				strncpy(current,c+2, sizeof(current));
-				add_group(current);
+				add_group(gc, current);
 				how_many++;
-			} else if (*c == 'b' && !find_buddy(c+2)) {
+			} else if (*c == 'b' && !find_buddy(gc, c+2)) {
 				char nm[80], sw[80], *tmp = c+2;
 				int i = 0;
 				while (*tmp != ':' && *tmp)
@@ -876,13 +882,13 @@
 				i = 0;
 				while (*tmp) sw[i++] = *tmp++;
 				sw[i] = '\0';
-				if (!find_buddy(nm))
-					add_buddy(current, nm, sw);
+				if (!find_buddy(gc, nm))
+					add_buddy(gc, current, nm, sw);
 				how_many++;
 				
 				bud = g_list_append(bud, c+2);
 			} else if (*c == 'p') {
-				GList *d = permit;
+				GSList *d = gc->permit;
 				char *n;
 				name = g_malloc(strlen(c+2) + 2);
 				g_snprintf(name, strlen(c+2) + 1, "%s", c+2);
@@ -894,9 +900,9 @@
 				}
 				g_free(n);
 				if (!d)
-					permit = g_list_append(permit, name);
+					gc->permit = g_slist_append(gc->permit, name);
 			} else if (*c == 'd') {
-				GList *d = deny;
+				GSList *d = gc->deny;
 				char *n;
 				name = g_malloc(strlen(c+2) + 2);
 				g_snprintf(name, strlen(c+2) + 1, "%s", c+2);
@@ -908,30 +914,29 @@
 				}
 				g_free(n);
 				if (!d)
-					deny = g_list_append(deny, name);
+					gc->deny = g_slist_append(gc->deny, name);
 			} else if (!strncmp("toc", c, 3)) {
-				sscanf(c + strlen(c) - 1, "%d", &permdeny);
-				sprintf(debug_buff, "permdeny: %d\n", permdeny);
+				sscanf(c + strlen(c) - 1, "%d", &gc->permdeny);
+				sprintf(debug_buff, "permdeny: %d\n", gc->permdeny);
 				debug_print(debug_buff);
-				if (permdeny == 0)
-					permdeny = 1;
+				if (gc->permdeny == 0)
+					gc->permdeny = 1;
 			} else if (*c == 'm') {
-				sscanf(c + 2, "%d", &permdeny);
-				sprintf(debug_buff, "permdeny: %d\n", permdeny);
+				sscanf(c + 2, "%d", &gc->permdeny);
+				sprintf(debug_buff, "permdeny: %d\n", gc->permdeny);
 				debug_print(debug_buff);
-				if (permdeny == 0)
-					permdeny = 1;
+				if (gc->permdeny == 0)
+					gc->permdeny = 1;
 			}
 		} while((c=strtok(NULL,"\n"))); 
 #if 0
 		fprintf(stdout, "Sending message '%s'\n",buf);
 #endif
 				      
-		if (bud != NULL) serv_add_buddies(bud);
-		serv_set_permit_deny();
+		if (bud != NULL) serv_add_buddies(gc, bud);
+		serv_set_permit_deny(gc);
 		if (blist) {
 			build_edit_tree();
-			build_permit_tree();
 		}
 	}
 
@@ -1096,9 +1101,24 @@
 	sflap_send(gc, "", 0, TYPE_KEEPALIVE);
 }
 
+static char **toc_list_icon(int uc) {
+	if (uc & UC_UNAVAILABLE)
+		return (char **)away_icon_xpm;
+	if (uc & UC_AOL)
+		return (char **)aol_icon_xpm;
+	if (uc & UC_NORMAL)
+		return (char **)free_icon_xpm;
+	if (uc & UC_ADMIN)
+		return (char **)admin_icon_xpm;
+	if (uc & UC_UNCONFIRMED)
+		return (char **)dt_icon_xpm;
+	return NULL;
+}
+
 void toc_init(struct prpl *ret) {
         ret->protocol = PROTO_TOC;
         ret->name = toc_name;
+	ret->list_icon = toc_list_icon;
         ret->login = toc_login;
         ret->close = toc_close;
         ret->send_im = toc_send_im;
--- a/src/util.c	Thu Oct 26 18:05:29 2000 +0000
+++ b/src/util.c	Fri Oct 27 07:53:32 2000 +0000
@@ -704,7 +704,7 @@
 #endif
 }
 
-struct aim_user *find_user(const char *name)
+struct aim_user *find_user(const char *name, int protocol)
 {
         char *who = g_strdup(normalize(name));
         GList *usr = aim_users;
@@ -713,8 +713,16 @@
         while(usr) {
                 u = (struct aim_user *)usr->data;
                 if (!strcmp(normalize(u->username), who)) {
-                        g_free(who);
-                        return u;
+			if (protocol != -1) {
+				if (u->protocol == protocol) {
+					g_free(who);
+					return u;
+				}
+			} else {
+				g_free(who);
+				return u;
+			}
+				
                 }
                 usr = usr->next;
         }
@@ -1205,7 +1213,7 @@
 {
 	struct aim_user *u;
 
-	u = find_user (name);
+	u = find_user (name, -1);
 
 	if (!u) { /* new user */
 		u = g_new0(struct aim_user, 1);
@@ -1237,7 +1245,7 @@
 		names = g_strsplit (name, ",", 32);
 		for (n = names; *n != NULL; n++) {
 			printf ("user %s...\n", *n);
-			u = find_user(*n);
+			u = find_user(*n, -1);
 			if (u) { /* found a user */
 				if (first == NULL)
 					first = g_strdup (*n);