changeset 4687:283fb289c510

[gaim-migrate @ 4998] This is a new buddy list. Lots of things about it just Don't Work. I probably already know about those things, and you'd just be wasting my time in submitting a bug report about it. I decided that instead of getting it to all work perfectly before committing, that I'd get it in cvs, and slowly fix it with regular commits. That way, it's easier to keep track of things, and other developers can help. Plus, I'm getting pissed off at the buddy list and want it to die. It's kinda boring, and doing nothing but the buddy list for such a long time has just gotten me very bitter. After 0.60 is released later this week, Gaim will resume being fun. This week is going to be very stressful, though, I'm sure. Things you ought to know about this buddy list: - It crashes - It leaks - There's no way to edit the buddy list, or access offline buddies - Most of the menus and buttons and whatnot just plain ol' don't work. - Status icons are only implemented for AIM. That's mostly just because I'm lazy. As such, you may want to be wary of updating this. If you do decide to update this, you may want to learn "cvs update -D yesterday" as well :) All the art there is just placeholder art. You probably won't really have as many problems as it sounds like you will from reading this. This message is extra-negative to stress that I don't want to be bothered with complaints about something not working about it :). I'll repeat: If something doesn't work, I probably already know about it. If you want to actually help with something, I'd be delighted to have it. IM me. -s. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Mon, 10 Mar 2003 05:30:31 +0000
parents a1de8a9c99ba
children 0a35ec3585ef
files configure.ac pixmaps/Makefile.am pixmaps/status/Makefile.am pixmaps/status/default/Makefile.am pixmaps/status/default/activebuddy.png pixmaps/status/default/admin.png pixmaps/status/default/aim.png pixmaps/status/default/aol.png pixmaps/status/default/away.png pixmaps/status/default/gadu-gadu.png pixmaps/status/default/icq.png pixmaps/status/default/irc.png pixmaps/status/default/jabber.png pixmaps/status/default/msn.png pixmaps/status/default/napster.png pixmaps/status/default/wireless.png pixmaps/status/default/yahoo.png plugins/Makefile.am plugins/PERL-HOWTO plugins/ticker/Makefile.am plugins/ticker/ticker.c src/Makefile.am src/away.c src/buddy.c src/conversation.c src/core.h src/dialogs.c src/gaim.h src/gtkconv.c src/gtkft.c src/gtklist.h src/gtkutils.c src/gtkutils.h src/idle.c src/list.c src/log.c src/main.c src/multi.c src/perl.c src/pounce.c src/pounce.h src/prefs.c src/privacy.h src/protocols/gg/gg.c src/protocols/icq/gaim_icq.c src/protocols/irc/irc.c src/protocols/jabber/jabber.c src/protocols/msn/msn.c src/protocols/msn/switchboard.c src/protocols/napster/napster.c src/protocols/oscar/oscar.c src/protocols/toc/toc.c src/protocols/yahoo/yahoo.c src/protocols/zephyr/zephyr.c src/prpl.c src/prpl.h src/server.c src/stock.c src/stock.h src/ui.h src/util.c
diffstat 61 files changed, 2174 insertions(+), 3782 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Mon Mar 10 04:51:10 2003 +0000
+++ b/configure.ac	Mon Mar 10 05:30:31 2003 +0000
@@ -393,6 +393,8 @@
 	   pixmaps/protocols/gg/Makefile
 	   pixmaps/smileys/Makefile
 	   pixmaps/smileys/default/Makefile
+	   pixmaps/status/Makefile
+	   pixmaps/status/default/Makefile
 	   plugins/Makefile
 	   plugins/docklet/Makefile
 	   plugins/gestures/Makefile
--- a/pixmaps/Makefile.am	Mon Mar 10 04:51:10 2003 +0000
+++ b/pixmaps/Makefile.am	Mon Mar 10 05:30:31 2003 +0000
@@ -1,4 +1,4 @@
-SUBDIRS = protocols smileys
+SUBDIRS = protocols smileys status
 EXTRA_DIST =	about_menu.png \
 		accounts.png \
 		accounts-menu.png \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pixmaps/status/Makefile.am	Mon Mar 10 05:30:31 2003 +0000
@@ -0,0 +1,2 @@
+SUBDIRS = default 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pixmaps/status/default/Makefile.am	Mon Mar 10 05:30:31 2003 +0000
@@ -0,0 +1,7 @@
+EXTRA_DIST = aim.png icq.png msn.png jabber.png yahoo.png gadu-gadu.png napster.png irc.png \ 
+	     activebuddy.png admin.png aol.png away.png wireless.png
+
+gaimstatuspixdir = $(datadir)/pixmaps/gaim/status/default
+
+gaimstatuspix_DATA = aim.png icq.png msn.png jabber.png yahoo.png gadu-gadu.png napster.png irc.png \
+	   	     activebuddy.png admin.png aol.png away.png wireless.png
Binary file pixmaps/status/default/activebuddy.png has changed
Binary file pixmaps/status/default/admin.png has changed
Binary file pixmaps/status/default/aim.png has changed
Binary file pixmaps/status/default/aol.png has changed
Binary file pixmaps/status/default/away.png has changed
Binary file pixmaps/status/default/gadu-gadu.png has changed
Binary file pixmaps/status/default/icq.png has changed
Binary file pixmaps/status/default/irc.png has changed
Binary file pixmaps/status/default/jabber.png has changed
Binary file pixmaps/status/default/msn.png has changed
Binary file pixmaps/status/default/napster.png has changed
Binary file pixmaps/status/default/wireless.png has changed
Binary file pixmaps/status/default/yahoo.png has changed
--- a/plugins/Makefile.am	Mon Mar 10 04:51:10 2003 +0000
+++ b/plugins/Makefile.am	Mon Mar 10 05:30:31 2003 +0000
@@ -6,7 +6,6 @@
 
 
 autorecon_la_LDFLAGS = -module -avoid-version
-chatlist_la_LDFLAGS  = -module -avoid-version
 iconaway_la_LDFLAGS  = -module -avoid-version
 notify_la_LDFLAGS    = -module -avoid-version
 spellchk_la_LDFLAGS  = -module -avoid-version
@@ -18,7 +17,6 @@
 
 plugin_LTLIBRARIES = \
 	autorecon.la   \
-	chatlist.la    \
 	iconaway.la    \
 	notify.la      \
 	spellchk.la    \
@@ -27,7 +25,6 @@
 	idle.la
 
 autorecon_la_SOURCES = autorecon.c
-chatlist_la_SOURCES  = chatlist.c
 iconaway_la_SOURCES  = iconaway.c
 notify_la_SOURCES    = notify.c
 spellchk_la_SOURCES  = spellchk.c
--- a/plugins/PERL-HOWTO	Mon Mar 10 04:51:10 2003 +0000
+++ b/plugins/PERL-HOWTO	Mon Mar 10 05:30:31 2003 +0000
@@ -101,19 +101,6 @@
 		their warning level
 		signon time, in seconds since the epoch
 		idle time, in seconds (?)
-		user class, an integer with bit values
-			AOL		1
-			ADMIN		2
-			UNCONFIRMED	4
-			NORMAL		8
-			AWAY		16
-		their capabilites, an integer with bit values
-			BUDDYICON	1
-			VOICE		2
-			IMIMAGE		4
-			CHAT		8
-			GETFILE		16
-			SENDFILE	32
 	Since buddy lists are per-connection this goes through the connections
 	until it finds a matching buddy name.
 
--- a/plugins/ticker/Makefile.am	Mon Mar 10 04:51:10 2003 +0000
+++ b/plugins/ticker/Makefile.am	Mon Mar 10 05:30:31 2003 +0000
@@ -13,7 +13,8 @@
 
 endif
 
-CFLAGS += $(DEBUG_CFLAGS)
+CFLAGS += $(DEBUG_CFLAGS) -DDATADIR=\"$(datadir)\"
+
 
 INCLUDES = \
 	-I$(top_srcdir) \
--- a/plugins/ticker/ticker.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/plugins/ticker/ticker.c	Mon Mar 10 05:30:31 2003 +0000
@@ -61,9 +61,9 @@
 
 void BuddyTickerDestroyWindow( GtkWidget *window );
 void BuddyTickerCreateWindow( void );
-void BuddyTickerAddUser( char *name, char *alias, GdkPixmap *pm, GdkBitmap *bm );
+void BuddyTickerAddUser( char *name, char *alias, const char *pb);
 void BuddyTickerRemoveUser( char *name );
-void BuddyTickerSetPixmap( char *name, GdkPixmap *pm, GdkBitmap *bm );
+void BuddyTickerSetPixmap( char *name, const char *pb);
 void BuddyTickerClearList( void );
 void BuddyTickerSignOff( void );
 GList * BuddyTickerFindUser( char *name );
@@ -127,7 +127,7 @@
 }
 
 void
-BuddyTickerAddUser( char *name, char *alias, GdkPixmap *pm, GdkBitmap *bm )
+BuddyTickerAddUser( char *name, char *alias, const char *pb)
 {
 	TickerData *p;
 	GList *q;
@@ -157,7 +157,7 @@
 	gtk_ticker_add( GTK_TICKER( ticker ), p->hbox );
 	gtk_widget_show_all( p->hbox );
 
-	BuddyTickerSetPixmap( name, pm, bm );
+	BuddyTickerSetPixmap(name, pb);
 
 	p->ebox = gtk_event_box_new();
 
@@ -202,11 +202,12 @@
 }
 
 void
-BuddyTickerSetPixmap( char *name, GdkPixmap *pm, GdkBitmap *bm )
+BuddyTickerSetPixmap( char *name, const char *pb)
 {
 	GList *p;
 	TickerData *data;
-
+	char *file = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", pb, NULL);
+	
 	if ( userclose == TRUE )
 		return;
 	p = (GList *) BuddyTickerFindUser( name );
@@ -215,11 +216,11 @@
 	else
 		return;
 	if ( data->pix == (GtkWidget *) NULL ) {
-		data->pix = gtk_image_new_from_pixmap( pm, bm );
+		data->pix = gtk_image_new_from_file(file);
 		gtk_box_pack_start_defaults( GTK_BOX( data->hbox ), data->pix );
 	} else {
 		gtk_widget_hide( data->pix );
-		gtk_image_set_from_pixmap(GTK_IMAGE(data->pix), pm, bm);
+		gtk_image_set_from_file(GTK_IMAGE(data->pix), file);
 	}
 	gtk_widget_show( data->pix );
 }
@@ -330,12 +331,10 @@
 
 void BuddyTickerShow()
 {
-	GdkPixmap *pm;
-	GdkBitmap *bm;
 	struct group *g;
 	struct buddy *b;
 	GSList *grps, *buds;
-	char **xpm;
+	const char *xpm;
 
 	for( grps = groups; grps; grps = grps->next ) {
 		g = (struct group *)grps->data;
@@ -344,36 +343,21 @@
 			if( b->present ) {
 				xpm = NULL;
 				if (b->account->gc->prpl->list_icon)
-					xpm = b->account->gc->prpl->list_icon(b->uc);
-				if (xpm == NULL)
-					xpm = (char **)no_icon_xpm;
-				pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm);
-				BuddyTickerAddUser( b->name, get_buddy_alias(b), pm, bm );
-				gdk_pixmap_unref(pm);
-				if (bm)
-					gdk_bitmap_unref(bm);
+					xpm = b->account->gc->prpl->list_icon(b->account, b);
+				BuddyTickerAddUser( b->name, gaim_get_buddy_alias(b), xpm);
 			}
 		}
 	}
 }
 
 void signon_cb(struct gaim_connection *gc, char *who) {
-	struct buddy *b  = find_buddy(gc->account, who);
-	char **xpm = NULL;
-	
-	GdkPixmap *pm;
-	GdkBitmap *bm;
-	
+	struct buddy *b  = gaim_find_buddy(gc->account, who);
+	const char *xpm = NULL;
+       
 	if (gc->prpl->list_icon)
-		xpm = gc->prpl->list_icon(b->uc);
-	if (xpm == NULL)
-		xpm = (char **)no_icon_xpm;
-	pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm);
-		
-	BuddyTickerAddUser(who, get_buddy_alias(b), pm, bm);
-	gdk_pixmap_unref(pm);
-	if (bm)
-		gdk_bitmap_unref(bm);
+		xpm = gc->prpl->list_icon(b->account, b);
+	
+	BuddyTickerAddUser(who, gaim_get_buddy_alias(b), xpm);
 }
 
 void signoff_cb(struct gaim_connection *gc) {
@@ -389,21 +373,12 @@
 }
 
 void away_cb(struct gaim_connection *gc, char *who) {
-	struct buddy *b  = find_buddy(gc->account, who);
-	char **xpm = NULL;
-	
-	GdkPixmap *pm;
-	GdkBitmap *bm;
+	struct buddy *b  = gaim_find_buddy(gc->account, who);
+	const char *xpm = NULL;
 	
 	if (gc->prpl->list_icon)
-		xpm = gc->prpl->list_icon(b->uc);
-	if (xpm == NULL)
-		xpm = (char **)no_icon_xpm;
-	pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm);
-	BuddyTickerSetPixmap(who, pm, bm);
-	gdk_pixmap_unref(pm);
-	if (bm)
-		gdk_bitmap_unref(bm);
+		xpm = gc->prpl->list_icon(b->account, b);
+	BuddyTickerSetPixmap(who, xpm);
 }
 
 /*
--- a/src/Makefile.am	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/Makefile.am	Mon Mar 10 05:30:31 2003 +0000
@@ -46,6 +46,8 @@
 		multi.c \
 		multi.h \
 		perl.c \
+		pounce.c \
+		pounce.h \
 		prefs.c \
 		proxy.c \
 		proxy.h \
--- a/src/away.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/away.c	Mon Mar 10 05:30:31 2003 +0000
@@ -32,6 +32,7 @@
 #include "prpl.h"
 #include "gtkimhtml.h"
 #include "pixmaps/join.xpm"
+#include "gtklist.h"
 
 GtkWidget *imaway = NULL;
 
@@ -207,9 +208,6 @@
 	char *buf2;
 	char *buf;
 
-	if (!blist)
-		return;
-
 	if (!a)
 		return;
 
--- a/src/buddy.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/buddy.c	Mon Mar 10 05:30:31 2003 +0000
@@ -19,12 +19,6 @@
  *
  */
 
-#ifdef GTK_DISABLE_DEPRECATED
-#undef GTK_DISABLE_DEPRECATED
-#endif
-
-#define GTK_ENABLE_BROKEN
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
@@ -41,6 +35,8 @@
 #include <time.h>
 #include <ctype.h>
 
+#include "pixmaps/no_icon.xpm"
+
 #ifdef _WIN32
 #include <gdk/gdkwin32.h>
 #else
@@ -53,2645 +49,675 @@
 #include "prpl.h"
 #include "sound.h"
 #include "gaim.h"
+#include "gtklist.h"
+#include "gtkft.h"
 
 #ifdef _WIN32
 #include "win32dep.h"
 #endif
 
-#include "pixmaps/login_icon.xpm"
-#include "pixmaps/logout_icon.xpm"
-#include "pixmaps/no_icon.xpm"
-
-#include "pixmaps/away_big.xpm"
-
-#include "pixmaps/group.xpm"
-
-#include "pixmaps/arrow_down.xpm"
-#include "pixmaps/arrow_right.xpm"
-
-static GtkTooltips *tips;
-static GtkAccelGroup *accel;
-static GtkWidget *editpane;
-static GtkWidget *buddypane;
-static GtkWidget *imchatbox;
-static GtkWidget *edittree;
-static GtkWidget *imbutton, *infobutton, *chatbutton, *awaybutton;
-static GtkWidget *addbutton, *groupbutton, *rembutton;
-
-GtkWidget *blist = NULL;
-GtkWidget *bpmenu;
-GtkWidget *buddies;
-
-typedef struct _GtkTreePixmaps GtkTreePixmaps;
-
-struct buddy_show {
-	GtkWidget *item;
-	GtkWidget *pix;
-	GtkWidget *label;
-	GtkWidget *warn;
-	GtkWidget *idle;
-	char *name;
-	GSList *connlist;
-	guint log_timer;
-	gint sound;
-};
-
-/* stuff for actual display of buddy list */
-struct group_show {
-	GtkWidget *item;
-	GtkWidget *label;
-	GtkWidget *tree;
-	GSList *members;
-	char *name;
-};
-static GSList *shows = NULL;
-
-int docklet_count = 0;
 static gboolean obscured = FALSE;
 
-/* Predefine some functions */
-static void new_bp_callback(GtkWidget *w, struct buddy *bs);
-static struct group_show *find_group_show(char *group);
-static struct buddy_show *find_buddy_show(struct group_show *gs, char *name);
-static int group_number(char *group);
-static int buddy_number(char *group, char *buddy);
-static struct group_show *new_group_show(char *group);
-static struct buddy_show *new_buddy_show(struct group_show *gs, struct buddy *buddy, char **xpm);
-static void remove_buddy_show(struct group_show *gs, struct buddy_show *bs);
-static struct group_show *find_gs_by_bs(struct buddy_show *b);
-static void update_num_group(struct group_show *gs);
-static void update_idle_time(struct buddy_show *bs);
-
-void handle_group_rename(struct group *g, char *prevname)
-{
-	struct group_show *gs, *new_gs;
-	GtkCTreeNode *c;
-
-	c = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, g);
-	gtk_ctree_node_set_text(GTK_CTREE(edittree), c, 0, g->name);
-
-	gs = find_group_show(prevname);
-	if (!gs) {
-		return;
-	}
-	new_gs = find_group_show(g->name);
-	if (new_gs) {
-		/* transfer everything that was in gs and is in the same gaim_conn as g
-		 * over to new_gs. */
-		while (gs->members) {
-			new_gs->members = g_slist_append(new_gs->members, gs->members->data);
-			gs->members = g_slist_remove(gs->members, gs->members->data);
-
-		}
-		shows = g_slist_remove(shows, gs);
-		gtk_tree_remove_item(GTK_TREE(buddies), gs->item);
-		g_free(gs->name);
-		g_free(gs);
-		update_num_group(new_gs);
-	} else {
-		g_free(gs->name);
-		gs->name = g_strdup(g->name);
-		update_num_group(gs);
-	}
-}
-
-void handle_buddy_rename(struct buddy *b, char *prevname)
-{
-	struct gaim_conversation *cnv;
-	struct buddy_show *bs;
-	struct group_show *gs;
-	struct group *g;
-	GtkCTreeNode *c;
-	char buf[256];
-
-	c = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, b);
-	if (get_buddy_alias_only(b))
-		g_snprintf(buf, sizeof(buf), "%s (%s)", b->name, get_buddy_alias(b));
-	else
-		g_snprintf(buf, sizeof(buf), "%s", b->name);
-	gtk_ctree_node_set_text(GTK_CTREE(edittree), c, 0, buf);
-
-	if ((cnv = gaim_find_conversation(b->name)) != NULL)
-		gaim_conversation_autoset_title(cnv);
-
-	g = find_group_by_buddy(b);
-	if (!g) {
-		/* shouldn't happen */
-		return;
-	}
-	gs = find_group_show(g->name);
-	if (!gs) {
-		return;
-	}
-	bs = find_buddy_show(gs, prevname);
-	if (!bs) {
-		/* buddy's offline */
-		return;
-	}
+static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node);
 
-	if (g_strcasecmp(b->name, prevname)) {
-		bs->connlist = g_slist_remove(bs->connlist, b->account->gc);
-		if (!bs->connlist) {
-			gs->members = g_slist_remove(gs->members, bs);
-			if (bs->log_timer > 0)
-				g_source_remove(bs->log_timer);
-			bs->log_timer = 0;
-			remove_buddy_show(gs, bs);
-			g_free(bs->name);
-			g_free(bs);
-		}
-		update_num_group(gs);
-	} else {
-		gtk_label_set_text(GTK_LABEL(bs->label), get_buddy_alias(b));
-		update_idle_time(bs);
-	}
-}
-
-void destroy_buddy()
-{
-	GSList *s = shows;
-	struct group_show *g;
-	GSList *m;
-	struct buddy_show *b;
-	while (s) {
-		g = (struct group_show *)s->data;
-		debug_printf("group_show still exists: %s\n", g->name);
-		m = g->members;
-		while (m) {
-			b = (struct buddy_show *)m->data;
-			debug_printf("buddy_show still exists: %s\n", b->name);
-			m = g_slist_remove(m, b);
-			if (b->log_timer > 0)
-				g_source_remove(b->log_timer);
-			b->log_timer = 0;
-			gtk_tree_remove_item(GTK_TREE(g->tree), b->item);
-			g_free(b->name);
-			g_free(b);
-		}
-		gtk_tree_remove_item(GTK_TREE(buddies), g->item);
-		s = g_slist_remove(s, g);
-		g_free(g->name);
-		g_free(g);
-	}
-	shows = NULL;
-
-	if (blist)
-		gtk_widget_destroy(blist);
-	blist = NULL;
-	imchatbox = NULL;
-	awaymenu = NULL;
-	protomenu = NULL;
-}
-
-static void adjust_pic(GtkWidget *button, const char *c, gchar **xpm)
-{
-	GdkPixmap *pm;
-	GdkBitmap *bm;
-	GtkWidget *pic;
-	GtkWidget *label;
-
-	/*if the user had opted to put pictures on the buttons */
-	if (blist_options & OPT_BLIST_SHOW_BUTTON_XPM && xpm) {
-		pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm);
-		pic = gtk_pixmap_new(pm, bm);
-		gtk_widget_show(pic);
-		gdk_pixmap_unref(pm);
-		gdk_bitmap_unref(bm);
-		label = GTK_BIN(button)->child;
-		gtk_container_remove(GTK_CONTAINER(button), label);
-		gtk_container_add(GTK_CONTAINER(button), pic);
-	} else {
-		label = gtk_label_new(c);
-		gtk_widget_show(label);
-		pic = GTK_BIN(button)->child;
-		gtk_container_remove(GTK_CONTAINER(button), pic);
-		gtk_container_add(GTK_CONTAINER(button), label);
-	}
-
-}
-
-/* This will remain here until we phase out the others */
-static void adjust_pic2(GtkWidget *button, const char *c, gchar *icon)
-{
-	GtkWidget *pic;
-	GtkWidget *label;
+/***************************************************
+ *              Callbacks                          *
+ ***************************************************/
 
-	/*if the user had opted to put pictures on the buttons */
-	if (blist_options & OPT_BLIST_SHOW_BUTTON_XPM && icon) {
-		label = GTK_BIN(button)->child;
-		gtk_container_remove(GTK_CONTAINER(button), label);
-		gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_stock(icon, GTK_ICON_SIZE_BUTTON));
-		gtk_widget_show_all(button);
-	} else {
-		label = gtk_label_new(c);
-		gtk_widget_show(label);
-		pic = GTK_BIN(button)->child;
-		gtk_container_remove(GTK_CONTAINER(button), pic);
-		gtk_container_add(GTK_CONTAINER(button), label);
-	}
-
-}
-
-
-void toggle_show_empty_groups()
-{
-	if (blist_options & OPT_BLIST_NO_MT_GRP) {
-		/* remove any group_shows with empty members */
-		GSList *s = shows;
-		struct group_show *g;
-
-		while (s) {
-			g = (struct group_show *)s->data;
-			if (!g_slist_length(g->members)) {
-				shows = g_slist_remove(shows, g);
-				s = shows;
-				gtk_tree_remove_item(GTK_TREE(buddies), g->item);
-				g_free(g->name);
-				g_free(g);
-			} else
-				s = g_slist_next(s);
-		}
-
-	} else {
-		/* put back all groups */
-		GSList *m = groups;
-
-		while (m) {
-			struct group *g = (struct group *)m->data;
-			if (!find_group_show(g->name) && gaim_group_on_account(g, NULL))
-				new_group_show(g->name);
-			m = g_slist_next(m);
-		}
-	}
-}
-
-void toggle_buddy_pixmaps()
-{
-	GSList *s = shows;
-	struct group_show *g;
-	GSList *m;
-	struct buddy_show *b;
-
-	while (s) {
-		g = s->data;
-		m = g->members;
-		while (m) {
-			b = m->data;
-			if (blist_options & OPT_BLIST_SHOW_PIXMAPS)
-				gtk_widget_show(b->pix);
-			else
-				gtk_widget_hide(b->pix);
-			m = m->next;
-		}
-		s = s->next;
-	}
-}
-
-static void update_num_group(struct group_show *gs)
-{
-	GSList *c = connections;
-	struct group *g = find_group(gs->name);
-	struct buddy *b;
-	int total = 0, on = 0;
-	char buf[256];
-
-	if (!g_slist_find(shows, gs)) {
-		debug_printf("update_num_group called for unfound group_show %s\n", gs->name);
-		return;
-	}
-	if (g) {
-		for (c = g->members; c; c = c->next) {
-			b = c->data;
-			if(b->account->gc) {
-				if(b->present)
-					on++;
-				total++;
-			}
-		}
-	}
-
-	if (blist_options & OPT_BLIST_SHOW_GRPNUM)
-		g_snprintf(buf, sizeof buf, "%s (%d/%d)", gs->name, on, total);
-	else
-		g_snprintf(buf, sizeof buf, "%s", gs->name);
-
-	gtk_label_set_text(GTK_LABEL(gs->label), buf);
-}
-
-void update_num_groups(void)
-{
-	GSList *s = shows;
-	struct group_show *g;
-
-	while (s) {
-		g = (struct group_show *)s->data;
-		update_num_group(g);
-		s = g_slist_next(s);
-	}
-}
-
-void update_button_pix()
-{
-
-	adjust_pic2(addbutton, _("Add"), GTK_STOCK_ADD); 
-	adjust_pic(groupbutton, _("Group"), (gchar **)group_xpm);
-	adjust_pic2(rembutton, _("Remove"), GTK_STOCK_REMOVE);
-
-	if (!(blist_options & OPT_BLIST_NO_BUTTONS)) {
-		adjust_pic(awaybutton, _("Away"), (gchar **)away_big_xpm);
-		adjust_pic2(chatbutton, _("Chat"), GTK_STOCK_JUMP_TO);
-		adjust_pic2(imbutton, _("IM"), GTK_STOCK_CONVERT);
-		adjust_pic2(infobutton, _("Info"), GTK_STOCK_FIND);
-	}
-	gtk_widget_hide(addbutton->parent);
-	gtk_widget_show(addbutton->parent);
-	if (!(blist_options & OPT_BLIST_NO_BUTTONS)) {
-		gtk_widget_hide(chatbutton->parent);
-		gtk_widget_show(chatbutton->parent);
-	}
-}
-
-void set_blist_tab()
-{
-	GtkWidget *blist_notebook;
-	if (!buddypane)
-		return;
+static void gtk_blist_row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data) {
+	GaimBlistNode *node;
+	GtkTreeIter iter;
+	GValue val = { 0, };
 	
-	blist_notebook = buddypane->parent;  /* The "Online" Page */
-
-	debug_printf("blist_options = %d\n", blist_options);
-	if((blist_options & OPT_BLIST_BOTTOM_TAB))
-		gtk_notebook_set_tab_pos(GTK_NOTEBOOK(blist_notebook), GTK_POS_BOTTOM);
-	else
-		gtk_notebook_set_tab_pos(GTK_NOTEBOOK(blist_notebook), GTK_POS_TOP);
-
-}
-
-
-static int handle_click_group(GtkWidget *widget, GdkEventButton *event, struct group *g)
-{
-	if (event->type == GDK_2BUTTON_PRESS) {
-		if (GTK_TREE_ITEM(widget)->expanded)
-			gtk_tree_item_collapse(GTK_TREE_ITEM(widget));
-		else
-			gtk_tree_item_expand(GTK_TREE_ITEM(widget));
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-void pressed_im_bud(GtkWidget *widget, struct buddy *b)
-{
-	struct gaim_conversation *c;
-
-	c = gaim_find_conversation(b->name);
-
-	if (c != NULL)
-		gaim_window_show(gaim_conversation_get_window(c));
-	else
-		c = gaim_conversation_new(GAIM_CONV_IM, b->account, b->name);
-}
-
-void pressed_im(GtkWidget *widget, struct buddy_show *b)
-{
-	struct gaim_conversation *c;
-
-	c = gaim_find_conversation(b->name);
-
-	if (c != NULL) {
-		gaim_window_show(gaim_conversation_get_window(c));
-	} else {
-		struct gaim_account *account;
-
-		account = ((struct gaim_connection *)b->connlist->data)->account;
-		c    = gaim_conversation_new(GAIM_CONV_IM, account, b->name);
+	gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path);
+	
+	gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val);
+	node = g_value_get_pointer(&val);
+	
+	if (GAIM_BLIST_NODE_IS_BUDDY(node)) {
+		gaim_conversation_new(GAIM_CONV_IM, ((struct buddy*)node)->account, ((struct buddy*)node)->name);
 	}
 }
 
-void pressed_log(GtkWidget *widget, char *name)
-{
-	show_log(name);
-}
-
-void show_syslog()
-{
-	show_log(NULL);
-}
-
-void pressed_alias_bs(GtkWidget *widget, struct buddy_show *bs)
-{
-	struct gaim_connection *gc = bs->connlist->data;
-	alias_dialog_bud(find_buddy(gc->account, bs->name));
-}
-
-void pressed_alias_bud(GtkWidget *widget, struct buddy *b)
-{
-	alias_dialog_bud(b);
-}
-
-static void menu_click(GtkObject *obj, char *who)
-{
-	GList *list = gtk_object_get_user_data(obj);
-	struct proto_buddy_menu *pbm = list->data;
-	if (pbm->callback)
-		pbm->callback(pbm->gc, who);
-}
-
-static int handle_click_buddy(GtkWidget *widget, GdkEventButton *event, struct buddy_show *b)
+static void gaim_proto_menu_cb(GtkMenuItem *item, struct buddy *b)
 {
-	if (!b->connlist)
-		return FALSE;
-
-	if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
-		struct gaim_conversation *c;
-		struct gaim_account *account;
-
-		account = ((struct gaim_connection *)b->connlist->data)->account;
-
-		c = gaim_find_conversation(b->name);
-
-		if (c != NULL) {
-			struct gaim_window *win = gaim_conversation_get_window(c);
-			size_t index = gaim_conversation_get_index(c);
-
-			gaim_window_switch_conversation(win, index);
-			gaim_window_show(win);
-
-			gaim_conversation_set_account(c, account);
-		}
-		else
-			c = gaim_conversation_new(GAIM_CONV_IM, account, b->name);
-
-		gaim_window_switch_conversation(gaim_conversation_get_window(c),
-										gaim_conversation_get_index(c));
-
-		gaim_window_raise(gaim_conversation_get_window(c));
-
-		/* XXX-GTK gtk_widget_grab_focus(c->entry); */
-	} else if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
-		static GtkWidget *menu = NULL;
-		static GList *mo_top = NULL;
-		GtkWidget *button;
-		GtkWidget *menuitem;
-		GtkWidget *conmenu;
-		GSList *cn = b->connlist;
-		struct gaim_connection *g;
-		/* We're gonna make us a menu right here */
-
-		/*
-		 * If a menu already exists, destroy it before creating a new one,
-		 * thus freeing-up the memory it occupied.  Same for its associated
-		 * (prpl menu items) GList.
-		 */
-		if(menu) {
-			gtk_widget_destroy(menu);
-			if(mo_top) {
-				g_list_foreach(mo_top, (GFunc)g_free, NULL);
-				g_list_free(mo_top);
-				mo_top = NULL;
-			}
-		}
-
-		menu = gtk_menu_new();
-
-		button = gtk_menu_item_new_with_label(_("IM"));
-		g_signal_connect(GTK_OBJECT(button), "activate", G_CALLBACK(pressed_im), b);
-		gtk_menu_append(GTK_MENU(menu), button);
-		gtk_widget_show(button);
-
-		button = gtk_menu_item_new_with_label(_("Alias"));
-		g_signal_connect(GTK_OBJECT(button), "activate", G_CALLBACK(pressed_alias_bs), b);
-		gtk_menu_append(GTK_MENU(menu), button);
-		gtk_widget_show(button);
-
-		button = gtk_menu_item_new_with_label(_("Add Buddy Pounce"));
-		g_signal_connect(GTK_OBJECT(button), "activate",
-				   G_CALLBACK(new_bp_callback),
-				   cn ? find_buddy(((struct gaim_connection *)cn->data)->account, b->name) : NULL);
-		gtk_menu_append(GTK_MENU(menu), button);
-		gtk_widget_show(button);
-
-		button = gtk_menu_item_new_with_label(_("View Log"));
-		g_signal_connect(GTK_OBJECT(button), "activate",
-				   G_CALLBACK(pressed_log), b->name);
-		gtk_menu_append(GTK_MENU(menu), button);
-		gtk_widget_show(button);
-
-		if (g_slist_length(cn) > 1) {
-			while (cn) {
-				g = (struct gaim_connection *)cn->data;
-				if (g->prpl->buddy_menu) {
-					GList *mo = mo_top = g->prpl->buddy_menu(g, b->name);
-
-					menuitem = gtk_menu_item_new_with_label(g->username);
-					gtk_menu_append(GTK_MENU(menu), menuitem);
-					gtk_widget_show(menuitem);
-
-					conmenu = gtk_menu_new();
-					gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), conmenu);
-					gtk_widget_show(conmenu);
-
-					while (mo) {
-						struct proto_buddy_menu *pbm = mo->data;
-						GtkWidget *button;
-
-						button = gtk_menu_item_new_with_label(pbm->label);
-						g_signal_connect(GTK_OBJECT(button), "activate",
-								   G_CALLBACK(menu_click), b->name);
-						gtk_object_set_user_data(GTK_OBJECT(button), mo);
-						gtk_menu_append(GTK_MENU(conmenu), button);
-						gtk_widget_show(button);
-
-						mo = mo->next;
-					}
-				}
-				cn = g_slist_next(cn);
-			}
-		} else {
-			g = (struct gaim_connection *)cn->data;
-			if (g->prpl->buddy_menu) {
-				GList *mo = mo_top = g->prpl->buddy_menu(g, b->name);
-
-				while (mo) {
-					struct proto_buddy_menu *pbm = mo->data;
-					GtkWidget *button;
-
-					button = gtk_menu_item_new_with_label(pbm->label);
-					g_signal_connect(GTK_OBJECT(button), "activate",
-							   G_CALLBACK(menu_click), b->name);
-					gtk_object_set_user_data(GTK_OBJECT(button), mo);
-					gtk_menu_append(GTK_MENU(menu), button);
-					gtk_widget_show(button);
-
-					mo = mo->next;
-				}
-			}
-		}
-
-		/* we send the menu widget so we can add menuitems within a plugin */
-		plugin_event(event_draw_menu, menu, b->name);
-
-		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
-
-	} else if (event->type == GDK_3BUTTON_PRESS && event->button == 2) {
-		if (!g_strcasecmp("zilding", normalize (b->name)))
-			 show_ee_dialog(0);
-		else if (!g_strcasecmp("robflynn", normalize (b->name)))
-			 show_ee_dialog(1);
-		else if (!g_strcasecmp("flynorange", normalize (b->name)))
-			 show_ee_dialog(2);
-		else if (!g_strcasecmp("ewarmenhoven", normalize (b->name)))
-			 show_ee_dialog(3);
-		else if (!g_strcasecmp("markster97", normalize (b->name)))
-			 show_ee_dialog(4);
-		else if (!g_strcasecmp("seanegn", normalize (b->name)))
-			show_ee_dialog(5);
-		else if (!g_strcasecmp("chipx86", normalize (b->name)))
-			show_ee_dialog(6);
-		else if (!g_strcasecmp("kingant", normalize (b->name)))
-			show_ee_dialog(7);
-		else if (!g_strcasecmp("lschiere", normalize (b->name)))
-			show_ee_dialog(8);
-
-	} else {
-
-		/* Anything for other buttons? :) */
-	}
-
-	return FALSE;
-}
-
-static void un_alias(GtkWidget *a, struct buddy *b)
-{
-	b->alias[0] = '\0';
-	handle_buddy_rename(b, b->name); /* make me a sammich! */
-	serv_alias_buddy(b);
-	gaim_blist_save();
+	struct proto_buddy_menu *pbm = g_object_get_data(G_OBJECT(item), "gaimcallback");
+	if (pbm->callback)
+		pbm->callback(pbm->gc, b->name);
 }
 
-static gboolean click_edit_tree(GtkWidget *widget, GdkEventButton *event, gpointer data)
+static gboolean gtk_blist_button_press_cb(GtkWidget *tv, GdkEventButton *event, gpointer null)
 {
-	GtkCTreeNode *node;
-	int *type;
-	int row, column;
-	static GtkWidget *menu = NULL;
-	GtkWidget *button;
-	static GList *mo_top = NULL;
-
-	if (event->button != 3 || event->type != GDK_BUTTON_PRESS)
-		return FALSE;
-
-	if (!gtk_clist_get_selection_info(GTK_CLIST(edittree), event->x, event->y, &row, &column))
-		return FALSE;
+	GtkTreePath *path;
+	GaimBlistNode *node;
+	GValue val = { 0, };
+	GtkTreeIter iter;
+	GtkWidget *menu, *menuitem;
+	GtkWidget *image;
+	GList *list;
+	struct prpl *prpl;
 
-	node = gtk_ctree_node_nth(GTK_CTREE(edittree), row);
-	type = gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node);
+	if (event->button != 3)
+		return FALSE;
+	
+	/* Here we figure out which node was clicked */
+	if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL))
+		return FALSE;
+	gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path);
+	gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val);
+	node = g_value_get_pointer(&val);
+	
+	if (!GAIM_BLIST_NODE_IS_BUDDY(node)) 
+		return FALSE;
+		
+	menu = gtk_menu_new();
 
-	/*
-	 * If a menu already exists, destroy it before creating a new one,
-	 * thus freeing-up the memory it occupied.
-	 */
-	if(menu) {
-		gtk_widget_destroy(menu);
-		menu = NULL;	/* safety measure */
-		if(mo_top) {
-			g_list_foreach(mo_top, (GFunc)g_free, NULL);
-			g_list_free(mo_top);
-			mo_top = NULL;
+	/* Protocol specific options */
+	prpl = find_prpl(((struct buddy*)node)->account->protocol);
+	if (prpl) {
+		list = prpl->buddy_menu(((struct buddy*)node)->account->gc, ((struct buddy*)node)->name);
+		while (list) {
+			struct proto_buddy_menu *pbm = list->data;
+			menuitem = gtk_menu_item_new_with_mnemonic(pbm->label);
+			g_object_set_data(G_OBJECT(menuitem), "gaimcallback", pbm);
+			g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gaim_proto_menu_cb), node);
+			gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+			list = list->next;
 		}
 	}
-
-	if (*type == EDIT_GROUP) {
-		struct group *group = (struct group *)type;
-		menu = gtk_menu_new();
-
-		button = gtk_menu_item_new_with_label(_("Rename"));
-		g_signal_connect(GTK_OBJECT(button), "activate",
-				   G_CALLBACK(show_rename_group), group);
-		gtk_menu_append(GTK_MENU(menu), button);
-		gtk_widget_show(button);
-
-		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
-
-		return TRUE;
-	} else if (*type == EDIT_BUDDY) {
-		struct buddy *b = (struct buddy *)type;
-		menu = gtk_menu_new();
-
-		button = gtk_menu_item_new_with_label(_("IM"));
-		g_signal_connect(GTK_OBJECT(button), "activate", G_CALLBACK(pressed_im_bud), b);
-		gtk_menu_append(GTK_MENU(menu), button);
-		gtk_widget_show(button);
-
-		button = gtk_menu_item_new_with_label(_("Alias"));
-		g_signal_connect(GTK_OBJECT(button), "activate",
-				   G_CALLBACK(pressed_alias_bud), b);
-		gtk_menu_append(GTK_MENU(menu), button);
-		gtk_widget_show(button);
-
-		if (b->alias[0]) {
-			button = gtk_menu_item_new_with_label(_("Un-Alias"));
-			g_signal_connect(GTK_OBJECT(button), "activate", G_CALLBACK(un_alias), b);
-			gtk_menu_append(GTK_MENU(menu), button);
-			gtk_widget_show(button);
-		}
-
-		button = gtk_menu_item_new_with_label(_("Rename"));
-		g_signal_connect(GTK_OBJECT(button), "activate",
-				   G_CALLBACK(show_rename_buddy), b);
-		gtk_menu_append(GTK_MENU(menu), button);
-		gtk_widget_show(button);
-
-		button = gtk_menu_item_new_with_label(_("Add Buddy Pounce"));
-		g_signal_connect(GTK_OBJECT(button), "activate",
-				   G_CALLBACK(new_bp_callback), b);
-		gtk_menu_append(GTK_MENU(menu), button);
-		gtk_widget_show(button);
-
-		button = gtk_menu_item_new_with_label(_("View Log"));
-		g_signal_connect(GTK_OBJECT(button), "activate",
-				   G_CALLBACK(pressed_log), b->name);
-		gtk_menu_append(GTK_MENU(menu), button);
-		gtk_widget_show(button);
-
-		/*
-		 * Add protocol-specific edit buddy menu items if they exist
-		 */
-		if (b->account->gc && b->account->gc->prpl->edit_buddy_menu) {
-			GList *mo = mo_top = b->account->gc->prpl->edit_buddy_menu(b->account->gc, b->name);
-
-			while (mo) {
-				struct proto_buddy_menu *pbm = mo->data;
-				GtkWidget *button;
-
-				button = gtk_menu_item_new_with_label(pbm->label);
-				g_signal_connect(GTK_OBJECT(button), "activate",
-						   G_CALLBACK(menu_click), b->name);
-				gtk_object_set_user_data(GTK_OBJECT(button), mo);
-				gtk_menu_append(GTK_MENU(menu), button);
-				gtk_widget_show(button);
-
-				mo = mo->next;
-			}
-		}
-
-		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
-
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
+	
+	menuitem = gtk_image_menu_item_new_with_mnemonic("_IM");
+ 	image = gtk_image_new_from_stock(GAIM_STOCK_IM, GTK_ICON_SIZE_MENU);
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);	
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+	
+	menuitem = gtk_image_menu_item_new_with_mnemonic("_Alias");
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+	
+	menuitem = gtk_image_menu_item_new_with_mnemonic("Add Buddy _Pounce");
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+	
+	menuitem = gtk_image_menu_item_new_with_mnemonic("View _Log");
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
 
-/*
- * Find and remove CTree node associated with buddylist entry
- */
-static void ui_remove_buddy_node(struct group *rem_g, struct buddy *rem_b)
-{
-	GtkCTreeNode *gnode = NULL, *bnode;
-
-	if((gnode = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, rem_g)) != NULL &&
-		(bnode = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), gnode, rem_b)) != NULL)
-	{
-		gtk_ctree_remove_node(GTK_CTREE(edittree), bnode);
-	}
-}
-
-void ui_remove_buddy(struct buddy *rem_b)
-{
-	struct gaim_conversation *c;
-	struct group *rem_g = find_group_by_buddy(rem_b);
-	struct group_show *gs;
-	struct buddy_show *bs;
-
-	gs = find_group_show(rem_g->name);
-	if (gs) {
-		bs = find_buddy_show(gs, rem_b->name);
-		if (bs) {
-			if (g_slist_find(bs->connlist, rem_b->account->gc)) {
-				bs->connlist = g_slist_remove(bs->connlist, rem_b->account->gc);
-				if (!g_slist_length(bs->connlist)) {
-					gs->members = g_slist_remove(gs->members, bs);
-					if (bs->log_timer > 0)
-						g_source_remove(bs->log_timer);
-					bs->log_timer = 0;
-					remove_buddy_show(gs, bs);
-					g_free(bs->name);
-					g_free(bs);
-					if (!g_slist_length(gs->members) &&
-					    (blist_options & OPT_BLIST_NO_MT_GRP)) {
-						shows = g_slist_remove(shows, gs);
-						gtk_tree_remove_item(GTK_TREE(buddies), gs->item);
-						g_free(gs->name);
-						g_free(gs);
-						gs = NULL;
-					}
-				}
-			}
-		}
-		if (gs)
-			update_num_group(gs);
-	}
-
-	c = gaim_find_conversation(rem_b->name);
-
-	if (c)
-		gaim_conversation_update(c, GAIM_CONV_UPDATE_REMOVE);
-
-		/* CONVXXX update_buttons_by_protocol(c); */
-
-	/* Remove CTree node for buddy */
-	ui_remove_buddy_node(rem_g, rem_b);
-
-}
-
-void ui_remove_group(struct group *rem_g)
-{
-	struct group_show *gs;
-	GtkCTreeNode *gnode = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, rem_g);
-	gtk_ctree_remove_node(GTK_CTREE(edittree), gnode);
-
-
-	if ((gs = find_group_show(rem_g->name)) != NULL) {
-		shows = g_slist_remove(shows, gs);
-		gtk_tree_remove_item(GTK_TREE(buddies), gs->item);
-		g_free(gs->name);
-		g_free(gs);
-	}
-}
-
-gboolean edit_drag_compare_func(GtkCTree *ctree, GtkCTreeNode *source_node,
-				GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling)
-{
-	int *type;
-
-	type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), source_node);
-
-	if (*type == EDIT_GROUP) {
-		if (!new_parent)
-			return TRUE;
-	} else if (*type == EDIT_BUDDY) {
-		if (new_parent) {
-			type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), new_parent);
-			if (*type == EDIT_GROUP)
-				return TRUE;
-		}
-	}
+	gtk_widget_show_all(menu);
+	
+	gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time);
 
 	return FALSE;
 }
 
-
-/* you really shouldn't call this function */
-void redo_buddy_list()
-{
-	/* so here we can safely assume that we don't have to add or delete anything, we
-	 * just have to go through and reorder everything. remember, nothing is going to
-	 * change connections, so we can assume that we don't have to change any user
-	 * data or anything. this is just a simple reordering. so calm down. */
-	/* note: we only have to do this if we want to strongly enforce order; however,
-	 * order doesn't particularly matter to the stability of the program. but, it's
-	 * kind of nice to have */
-	/* the easy way to implement this is just to go through shows and destroy all the
-	 * group_shows, then go through the connections and put everything back. though,
-	 * there are slight complications with that; most of them deal with timeouts and
-	 * people not seeing the login icon for the full 10 seconds. butt fuck them. */
-	GSList *s = shows;
-	struct group_show *gs;
-	GSList *m;
-	struct buddy_show *bs;
-	GSList *gr;
-	struct group *g;
-	struct buddy *b;
-
-	if (!blist)
-		return;
-
-	while (s) {
-		gs = (struct group_show *)s->data;
-		s = g_slist_remove(s, gs);
-		m = gs->members;
-		gtk_tree_remove_item(GTK_TREE(buddies), gs->item);
-		while (m) {
-			bs = (struct buddy_show *)m->data;
-			m = g_slist_remove(m, bs);
-			if (bs->log_timer > 0)
-				g_source_remove(bs->log_timer);
-			g_free(bs->name);
-			g_free(bs);
-		}
-		g_free(gs->name);
-		g_free(gs);
-	}
-	shows = NULL;
-	gr = groups;
-	while (gr) {
-		g = (struct group *)gr->data;
-		gr = gr->next;
-		gs = find_group_show(g->name);
-		if (!gs && !(blist_options & OPT_BLIST_NO_MT_GRP)
-				&& gaim_group_on_account(g, NULL))
-			gs = new_group_show(g->name);
-		m = g->members;
-		while (m) {
-			b = (struct buddy *)m->data;
-			m = m->next;
-			if (b->present) {
-				if (!gs)
-					gs = new_group_show(g->name);
-				bs = find_buddy_show(gs, b->name);
-				if (!bs) {
-					if (b->account->gc->prpl->list_icon)
-						bs = new_buddy_show(gs, b,
-								b->account->gc->prpl->list_icon(b->
-									uc));
-					else
-						bs = new_buddy_show(gs, b, (char **)no_icon_xpm);
-				}
-				bs->connlist = g_slist_append(bs->connlist, b->account->gc);
-				update_num_group(gs);
-			}
-		}
-	}
-	update_idle_times();
-}
-
-static void edit_tree_move(GtkCTree *ctree, GtkCTreeNode *child,
-						   GtkCTreeNode *parent, GtkCTreeNode *sibling,
-						   gpointer data)
-{
-	int *ctype, *ptype = NULL, *stype = NULL;
-
-	ctype = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), child);
-
-	if (parent)
-		ptype = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), parent);
-
-	if (sibling)
-		stype = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree), sibling);
-
-	if (*ctype == EDIT_BUDDY) {
-		/* we moved a buddy. hopefully we just changed groups or positions or something.
-		 * if we changed connections, we copy the buddy to the new connection. if the new
-		 * connection already had the buddy in its buddy list but in a different group,
-		 * we change the group that the buddy is in */
-		struct group *old_g, *new_g = (struct group *)ptype;
-		struct buddy *s = NULL, *buddy = (struct buddy *)ctype;
-		int pos;
-
-		old_g = find_group_by_buddy(buddy);
-
-		old_g->members = g_slist_remove(old_g->members, buddy);
-
-		if (sibling) {
-			s = (struct buddy *)stype;
-			pos = g_slist_index(new_g->members, s);
-			if (pos)
-				new_g->members = g_slist_insert(new_g->members, buddy, pos);
-			else
-				new_g->members = g_slist_prepend(new_g->members, buddy);
-		} else
-			new_g->members = g_slist_append(new_g->members, buddy);
-
-		serv_move_buddy(buddy, old_g, new_g);
-
-		gaim_blist_save();
-	} else {		/* group */
-
-		/* move the group. if moving connections, copy the group, and each buddy in the
-		 * group. if the buddy exists in the new connection, leave it where it is. */
-
-		struct group *g, *g2, *group;
-		int pos;
-
-		group = (struct group *)ctype;
-
-		g = group;
-
-		groups = g_slist_remove(groups, g);
-
-		if (sibling) {
-			g2 = (struct group *)stype;
-			pos = g_slist_index(groups, g2);
-			if (pos)
-				groups = g_slist_insert(groups, g, pos);
-			else
-				groups = g_slist_prepend(groups, g);
-		} else
-			groups = g_slist_append(groups, g);
-
-		gaim_blist_save();
-	}
-
-	redo_buddy_list();
-	update_num_groups();
-}
-
-void
-create_prpl_icon(GtkWidget *widget, struct gaim_connection *gc,
-				 GdkPixmap **pixmap, GdkBitmap **mask)
+static void gaim_gtk_blist_reordered_cb(GtkTreeModel *model,
+					GtkTreePath *path,
+					GtkTreeIter *iter,
+					gint        *neworder,
+					gpointer    null)
 {
-    /* This whole thing is a hack--but it looks nice.
-     * Probably should have a prpl->icon(struct gaim_connection *) to
-     * do this. */
-	GtkStyle *style;
-	char **xpm = NULL; 
-
-	if (widget == NULL || gc == NULL || pixmap == NULL || mask == NULL)
-		return;
-	
-	style = gtk_widget_get_style( widget );
-	
-	if (gc->prpl->list_icon) {
-		if (gc->prpl->protocol ==  PROTO_OSCAR) { 
-			if (isdigit(*gc->username)) {
-				xpm = gc->prpl->list_icon(0);
-			} else {
-				xpm = gc->prpl->list_icon(0x10);
-			}
-		} else { 
-			xpm = gc->prpl->list_icon (0);
-		}
-	}
-	if (xpm == NULL)
-		xpm = (char **)no_icon_xpm;
-	
-	*pixmap = gdk_pixmap_create_from_xpm_d(widget->window, mask, &style->bg[GTK_STATE_NORMAL], xpm);
-}
-
-void build_edit_tree()
-{
-	GtkCTreeNode *p = NULL, *n;
-	GSList *grp;
-	GSList *mem;
-	struct group *g;
-	struct buddy *b;
-	char *text[1];
-
-	if (!blist)
-		return;
-
-	gtk_clist_freeze(GTK_CLIST(edittree));
-	gtk_clist_clear(GTK_CLIST(edittree));
-
-
-	grp = groups;
-
-	while (grp) {
-
-		g = (struct group *)grp->data;
-
-		text[0] = g->name;
-
-		p = gtk_ctree_insert_node(GTK_CTREE(edittree), NULL,
-				NULL, text, 5, NULL, NULL, NULL, NULL, 0, 1);
-
-		gtk_ctree_node_set_row_data(GTK_CTREE(edittree), p, g);
-
-		n = NULL;
-
-		mem = g->members;
-
-		while (mem) {
-			char buf[256];
-			b = (struct buddy *)mem->data;
-			if(b->account->gc) {
-				if (get_buddy_alias_only(b)) {
-					g_snprintf(buf, sizeof(buf), "%s (%s)", b->name, get_buddy_alias(b));
-					text[0] = buf;
-				} else
-					text[0] = b->name;
-
-				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, b);
-			}
-
-			mem = mem->next;
-		}
-		grp = g_slist_next(grp);
-	}
-
-	gtk_clist_thaw(GTK_CLIST(edittree));
-
-}
-
-void ui_add_buddy(struct gaim_connection *gc, struct group *g, struct buddy *b)
-{
-	GtkCTreeNode *p = NULL, *n;
-	char *text[1];
-	char buf[256];
-	struct group_show *gs = find_group_show(g->name);
-
-	b->edittype = EDIT_BUDDY;
-
-	if (gs)
-		update_num_group(gs);
-
-	if (!blist)
-		return;
-
-	if(!b->account->gc)
-		return;
-
-	p = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, g);
-	if (get_buddy_alias_only(b)) {
-		g_snprintf(buf, sizeof(buf), "%s (%s)", b->name, get_buddy_alias(b));
-		text[0] = buf;
-	} else
-		text[0] = b->name;
-
-	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, b);
-}
-
-void ui_add_group(struct group *g)
-{
-	GtkCTreeNode *p;
-	char *text[1];
-
-	g->edittype = EDIT_GROUP;
-
-	if (!blist)
-		return;
-
-	text[0] = g->name;
-	p = gtk_ctree_insert_node(GTK_CTREE(edittree), NULL, NULL, text, 5, NULL, NULL, NULL, NULL, 0, 1);
-	gtk_ctree_node_set_row_data(GTK_CTREE(edittree), p, g);
-
-	if (!(blist_options & OPT_BLIST_NO_MT_GRP) && !find_group_show(g->name)
-			&& gaim_group_on_account(g, NULL))
-		new_group_show(g->name);
-}
-
-
-static void do_del_buddy(GtkWidget *w, GtkCTree *ctree)
-{
-	GtkCTreeNode *node;
-	struct buddy *b;
-	struct group *g;
-	int *type;
-	GList *i;
-
-	i = GTK_CLIST(edittree)->selection;
-	if (i) {
-		node = i->data;
-		type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node);
-
-		if (*type == EDIT_BUDDY) {
-			b = (struct buddy *)type;
-			g = find_group_by_buddy(b);
-			serv_remove_buddy(b->account->gc, b->name, g->name);
-			remove_buddy(b);
-			gaim_blist_save();
-		} else if (*type == EDIT_GROUP) {
-			remove_group((struct group *)type);
-			gaim_blist_save();
-		}
-
-	} else {
-		/* Nothing selected. */
-	}
-}
-
-
-void import_callback(GtkWidget *widget, void *null)
-{
-	show_import_dialog();
-}
-
-void add_buddy_callback(GtkWidget *widget, void *dummy)
-{
-	char *grp = NULL;
-	GtkCTreeNode *node;
-	GList *i;
-	struct gaim_connection *gc = NULL;
-	int *type;
-
-	i = GTK_CLIST(edittree)->selection;
-	if (i) {
-		node = i->data;
-		type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node);
-
-		if (*type == EDIT_BUDDY) {
-			struct buddy *b = (struct buddy *)type;
-			struct group *g = find_group_by_buddy(b);
-			grp = g->name;
-			gc = b->account->gc;
-		} else if (*type == EDIT_GROUP) {
-			struct group *g = (struct group *)type;
-			grp = g->name;
-			if(g->members)
-				gc = ((struct buddy *)g->members->data)->account->gc;
-			else
-				gc = connections->data;
-		} else {
-			gc = (struct gaim_connection *)type;
-		}
-	}
-	show_add_buddy(gc, NULL, grp, NULL);
+	debug_printf("This doesn't work because GTK is broken\n");
 
 }
 
-void add_group_callback(GtkWidget *widget, void *dummy)
-{
-	GtkCTreeNode *node;
-	GList *i;
-	struct gaim_connection *gc = NULL;
-	int *type;
+/* This is called 10 seconds after the buddy logs in.  It removes the "logged in" icon and replaces it with
+ * the normal status icon */
 
-	i = GTK_CLIST(edittree)->selection;
-	if (i) {
-		node = i->data;
-		type = (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree), node);
-		if (*type == EDIT_BUDDY)
-			gc = ((struct buddy *)type)->account->gc;
-		else if (*type == EDIT_GROUP)
-			gc = connections->data;
-		else
-			gc = (struct gaim_connection *)type;
-	}
-	show_add_group(gc);
+static gboolean gaim_reset_present_icon(GaimBlistNode *b)
+{
+	((struct buddy*)b)->present = 1;
+	gaim_gtk_blist_update(NULL, b);
+	return FALSE;
 }
 
-static void im_callback(GtkWidget *widget, GtkTree *tree)
+static void gaim_gtk_blist_add_buddy_cb()
 {
-	GList *i;
-	struct buddy_show *b = NULL;
-	struct gaim_conversation *c;
-	struct gaim_account *account;
-
-	i = GTK_TREE_SELECTION_OLD(tree);
-	if (i) {
-		b = gtk_object_get_user_data(GTK_OBJECT(i->data));
-	}
-	if (!i || !b) {
-		show_im_dialog();
-		return;
-	}
-	if (!b->name)
-		return;
-
-	account = ((struct gaim_connection *)b->connlist->data)->account;
-
-	c = gaim_find_conversation(b->name);
+	GtkTreeSelection *sel = gtk_tree_view_get_selection(gtkblist->treeview);
+	GtkTreeIter iter;
+	GaimBlistNode *node;
+	GValue val;
 
-	if (c == NULL)
-		c = gaim_conversation_new(GAIM_CONV_IM, account, b->name);
-	else {
-		gaim_conversation_set_account(c, account);
-		gaim_window_raise(gaim_conversation_get_window(c));
-	}
-}
-
-static void info_callback(GtkWidget *widget, GtkTree *tree)
-{
-	GList *i;
-	struct buddy_show *b = NULL;
-	i = GTK_TREE_SELECTION_OLD(tree);
-	if (i) {
-		b = gtk_object_get_user_data(GTK_OBJECT(i->data));
-	}
-	if (!i || !b) {
-		show_info_dialog();
-		return;
-	}
-	if (!b->name)
-		return;
-	if (b->connlist)
-		serv_get_info(b->connlist->data, b->name);
+	gtk_tree_selection_get_selected(sel, NULL, &iter);
+	gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val);
+	node = g_value_get_pointer(&val);
+	
+	if (GAIM_BLIST_NODE_IS_BUDDY(node)) 
+		show_add_buddy(NULL, NULL, ((struct group*)node->parent)->name, NULL);
+	else if (GAIM_BLIST_NODE_IS_GROUP(node))
+		show_add_buddy(NULL, NULL, ((struct group*)node)->name, NULL);
+	
 }
 
 
-void chat_callback(GtkWidget *widget, GtkTree *tree)
-{
-	join_chat();
-}
-
-static void away_callback(GtkWidget *widget, GtkTree *tree)
+/***************************************************
+ *            Crap                                 *
+ ***************************************************/
+static GtkItemFactoryEntry blist_menu[] =
 {
-	GSList *awy = away_messages;
-	static GtkWidget *menu = NULL;
-	GtkWidget *menuitem;
-
-	if (!awy)
-		return;
+	/* Buddies menu */
+	{ N_("/_Buddies"), NULL, NULL, 0, "<Branch>" },
+	{ N_("/Buddies/_Add A Buddy..."), "<CTL>B", gaim_gtk_blist_add_buddy_cb, 0,
+	  "<StockItem>", GTK_STOCK_ADD },
+	{ N_("/Buddies/New _Instant Message..."), "<CTL>I", show_im_dialog, 0,
+	  "<StockItem>", GAIM_STOCK_IM },
+	{ N_("/Buddies/Join a _Chat..."), "<CTL>C", join_chat, 0, 
+	  "<StockItem>", GAIM_STOCK_CHAT },
+	{ N_("/Buddies/sep1"), NULL, NULL, 0, "<Separator>" },
+	{ N_("/Buddies/Get _User Info..."), "<CTL>J", show_info_dialog, 0,
+	  "<StockItem>", GAIM_STOCK_INFO },
+	{ N_("/Buddies/sep2"), NULL, NULL, 0, "<Separator>" },
+	{ N_("/Buddies/_Signoff"), "<CTL>D", signoff_all, 0, NULL },
+	{ N_("/Buddies/_Quit"), "<CTL>Q", do_quit, 0,
+	  "<StockItem>", GTK_STOCK_QUIT },
 
-	/*
-	 * If a menu already exists, destroy it before creating a new one,
-	 * thus freeing-up the memory it occupied.
-	 */
-	if(menu)
-		gtk_widget_destroy(menu);
+	/* Tools */ 
+	{ N_("/_Tools"), NULL, NULL, 0, "<Branch>" },
+	{ N_("/Tools/_Away"), NULL, NULL, 0, "<Branch>" },
+	{ N_("/Tools/Buddy _Pounce"), NULL, NULL, 0, "<Branch>" },
+	{ N_("/Tools/sep1"), NULL, NULL, 0, "<Separator>" },
+	{ N_("/Tools/A_ccounts"), "<CTL>A", account_editor, 0, NULL },
+	{ N_("/Tools/Preferences"), "<CTL>P", show_prefs, 0, 
+	  "<StockItem>", GTK_STOCK_PREFERENCES },
+	{ N_("/Tools/_File Transfers"), NULL, NULL, 0,
+	  "<StockItem>", GTK_STOCK_REVERT_TO_SAVED },
+	{ N_("/Tools/sep2"), NULL, NULL, 0, "<Separator>" },
+	{ N_("/Tools/P_rotocol Actions"), NULL, NULL, 0, "<Branch>" },
+	{ N_("/Tools/Pr_ivacy"), NULL, show_privacy_options, 0, NULL },
+	{ N_("/Tools/View System _Log"), NULL, NULL, 0, NULL },
 
-	menu = gtk_menu_new();
+	/* Help */
+	{ N_("/_Help"), NULL, NULL, 0, "<Branch>" },
+	{ N_("/Help/Online _Help"), "F1", NULL, 0,
+	  "<StockItem>", GTK_STOCK_HELP },
+	{ N_("/Help/_Debug Window"), NULL, NULL, 0, NULL },
+	{ N_("/Help/_About"), NULL, show_about, 0, NULL },
+
+};
 
-	while (awy) {
-		struct away_message *a = awy->data;
+/*********************************************************
+ * Private Utility functions                             *
+ *********************************************************/
+
+static GdkPixbuf *gaim_gtk_blist_get_status_icon(struct buddy *b) 
+{
+	GdkPixbuf *status = NULL;
+	GdkPixbuf *scale = NULL;
+	GdkPixbuf *emblem = NULL;
+	gchar *filename = NULL;	
+	const char *protoname = NULL;
 
-		menuitem = gtk_menu_item_new_with_label(a->name);
-		gtk_menu_append(GTK_MENU(menu), menuitem);
-		g_signal_connect(GTK_OBJECT(menuitem), "activate",
-				   G_CALLBACK(do_away_message), a);
-		gtk_widget_show(menuitem);
-		awy = awy->next;
+	char *se,*sw,*nw,*ne;
+	
+	int scalesize = 30;
+
+	struct prpl* prpl = find_prpl(b->account->protocol);
+	if (prpl->list_icon)
+		protoname = prpl->list_icon(b->account, b);
+	if (prpl->list_emblems)
+		prpl->list_emblems(b, &se, &sw, &nw, &ne);
+	
+	if (!(blist_options & OPT_BLIST_SHOW_ICONS)) {
+		scalesize = 15;
+		sw = nw = ne = NULL; /* So that only the se icon will composite */
 	}
 
-	gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME );
-}
+		
+	if (b->present == 2) {
+		/* If b->present is 2, that means this buddy has just signed on.  We use the "login" icon for the
+		 * status, and we set a timeout to change it to a normal icon after 10 seconds. */
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "login.png", NULL);
+		status = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+		g_timeout_add(10000, (GSourceFunc)gaim_reset_present_icon, b);
+		
+		/* "Hey, what's all this crap?" you ask.  Status icons will be themeable too, and 
+		   then it will look up protoname from the theme */
+	} else {
+		char *image = g_strdup_printf("%s.png", protoname);
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL);
+		status = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(image);
+		g_free(filename);
 
-void rem_bp(GtkWidget *w, struct buddy_pounce *b)
-{
-	buddy_pounces = g_list_remove(buddy_pounces, b);
-	do_bp_menu();
-	save_prefs();
+	}
+	
+	if (!status)
+		return NULL;
+	
+	scale =  gdk_pixbuf_scale_simple(status, scalesize, scalesize, GDK_INTERP_BILINEAR);
+	
+	/* Emblems */
+	
+	/* Each protocol can specify up to four "emblems" to composite over the base icon.  "away", "busy", "mobile user"
+	 * are all examples of states represented by emblems.  I'm not even really sure I like this yet. */
+	
+	/* XXX Clean this crap up, yo. */
+	if (se) {
+		char *image = g_strdup_printf("%s.png", se);
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL);
+		g_free(image);
+		emblem = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+		if (emblem) {
+			if (blist_options & OPT_BLIST_SHOW_ICONS)
+				gdk_pixbuf_composite (emblem,
+						      scale, 15, 15,
+						      15, 15,
+						      15, 15,
+						      1, 1,
+						      GDK_INTERP_BILINEAR,
+						      255);
+			else
+					gdk_pixbuf_composite (emblem,
+						      scale, 0, 0,
+						      15, 15,
+						      0, 0,
+						      1, 1,
+						      GDK_INTERP_BILINEAR,
+						      255);
+		}
+	}
+	if (sw) {
+		char *image = g_strdup_printf("%s.png", sw);
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL);
+		g_free(image);
+		emblem = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+		if (emblem) {
+				gdk_pixbuf_composite (emblem,
+						      scale, 0, 15,
+						      15, 15,
+						      0, 15,
+						      1, 1,
+						      GDK_INTERP_BILINEAR,
+						      255);
+		}
+	}
+	if (nw) {
+		char *image = g_strdup_printf("%s.png", nw);
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL);
+		g_free(image);
+		emblem = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+		if (emblem) {
+			gdk_pixbuf_composite (emblem,
+					      scale, 0, 0,
+					      15, 15,
+					      0, 0,
+					      1, 1,
+					      GDK_INTERP_BILINEAR,
+					      255);
+		}
+	}
+	if (ne) {
+		char *image = g_strdup_printf("%s.png", ne);
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image, NULL);
+		g_free(image);
+		emblem = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+		if (emblem) {
+			gdk_pixbuf_composite (emblem,
+					      scale, 15, 0,
+					      15, 15,
+					      15, 0,
+					      1, 1,
+					      GDK_INTERP_BILINEAR,
+					      255);
+		}
+	}		
+
+	
+	/* Idle gray buddies affects the whole row.  This converts the status icon to greyscale. */
+	if (b->idle) 
+		gdk_pixbuf_saturate_and_pixelate(scale, scale, 0, FALSE);
+	return scale;
 }
 
-void do_pounce(struct gaim_connection *gc, char *name, int when)
+static GdkPixbuf *gaim_gtk_blist_get_buddy_icon(struct buddy *b) 
 {
-	char *who;
-
-	struct buddy_pounce *b;
-	struct gaim_conversation *c;
-	struct gaim_account *account;
-
-	GList *bp = buddy_pounces;
-
-	who = g_strdup(normalize (name));
-
-	while (bp) {
-		b = (struct buddy_pounce *)bp->data;
-		bp = bp->next;	/* increment the list here because rem_bp can make our handle bad */
-
-		if (!(b->options & when))
-			continue;
-
-		account = gaim_account_find(b->pouncer, b->protocol);	/* find our user */
-		if (account == NULL)
-			continue;
-
-		/* check and see if we're signed on as the pouncer */
-		if (account->gc != gc)
-			continue;
-
-		if (!g_strcasecmp(who, normalize (b->name))) {	/* find someone to pounce */
-			if (b->options & OPT_POUNCE_POPUP) {
-				c = gaim_find_conversation(name);
-
-				if (c == NULL)
-					c = gaim_conversation_new(GAIM_CONV_IM, account, name);
-				else
-					gaim_conversation_set_account(c, account);
-			}
-			if (b->options & OPT_POUNCE_NOTIFY) {
-				char tmp[1024];
-
-				/* I know the line below is really ugly. I only did it this way
-				 * because I thought it'd be funny :-) */
-
-				g_snprintf(tmp, sizeof(tmp), 
-					   (when & OPT_POUNCE_TYPING) ? _("%s has started typing to you") :
-					   (when & OPT_POUNCE_SIGNON) ? _("%s has signed on") : 
-					   (when & OPT_POUNCE_UNIDLE) ? _("%s has returned from being idle") : 
-					   _("%s has returned from being away"), name);
-				
-				do_error_dialog(tmp, NULL, GAIM_INFO);
-			}
-			if (b->options & OPT_POUNCE_SEND_IM) {
-				if (strlen(b->message) > 0) {
-					c = gaim_find_conversation(name);
-
-					if (c == NULL)
-						c = gaim_conversation_new(GAIM_CONV_IM, account, name);
-					else
-						gaim_conversation_set_account(c, account);
-
-					gaim_conversation_write(c, NULL, b->message, -1,
-											WFLAG_SEND, time(NULL));
-
-					serv_send_im(account->gc, name, b->message, -1, 0);
-				}
-			}
-			if (b->options & OPT_POUNCE_COMMAND) {
-#ifndef _WIN32
-				int pid = fork();
-
-				if (pid == 0) {
-					char *args[4];
-					args[0] = "sh";
-					args[1] = "-c";
-					args[2] = b->command;
-					args[3] = NULL;
-					execvp(args[0], args);
-					_exit(0);
-				}
-#else
-				STARTUPINFO si;
-				PROCESS_INFORMATION pi;
-
-				ZeroMemory( &si, sizeof(si) );
-				si.cb = sizeof(si);
-				ZeroMemory( &pi, sizeof(pi) );
-
-				CreateProcess( NULL, b->command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
-				CloseHandle( pi.hProcess );
-				CloseHandle( pi.hThread );
-#endif /*_WIN32*/
-			}
-			if (b->options & OPT_POUNCE_SOUND) {
-				if (strlen(b->sound))
-					gaim_sound_play_file(b->sound);
-				else
-					gaim_sound_play_event(GAIM_SOUND_POUNCE_DEFAULT);
-			}
-
-			if (!(b->options & OPT_POUNCE_SAVE))
-				rem_bp(NULL, b);
-
+	/* This just opens a file from ~/.gaim/icons/screenname.  This needs to change to be more gooder. */
+	char *file = g_build_filename(gaim_user_dir(), "icons", normalize(b->name), NULL);
+	GdkPixbuf *buf = gdk_pixbuf_new_from_file(file, NULL);
+	
+	if (!(blist_options & OPT_BLIST_SHOW_ICONS))
+		return NULL;
+	
+	if (buf) {
+		if (b->idle) {
+			gdk_pixbuf_saturate_and_pixelate(buf, buf, 0, FALSE);
 		}
+		return gdk_pixbuf_scale_simple(buf,30,30, GDK_INTERP_BILINEAR);
 	}
-	g_free(who);
-}
-
-static void new_bp_callback(GtkWidget *w, struct buddy *b)
-{
-	if (b)
-		show_new_bp(b->name, b->account->gc, b->idle, b->uc & UC_UNAVAILABLE, NULL);
-	else
-		show_new_bp(NULL, NULL, 0, 0, NULL);
-}
-
-static void edit_bp_callback(GtkWidget *w, struct buddy_pounce *b)
-{
-  show_new_bp(NULL, NULL, 0, 0, b);
+	return NULL;
 }
 
-static GtkTooltips *bp_tooltip = NULL;
-void do_bp_menu()
+static gchar *gaim_gtk_blist_get_name_markup(struct buddy *b) 
 {
-	GtkWidget *menuitem, *mess, *messmenu;
-	static GtkWidget *remmenu;
-	GtkWidget *remitem;
-	GtkWidget *sep;
-	GList *l;
-	struct buddy_pounce *b;
-	GList *bp = buddy_pounces;
+	char *name = gaim_get_buddy_alias(b);
+	char *esc = g_markup_escape_text(name, strlen(name)), *text = NULL;
+	/* XXX Clean up this crap */
+	
+	int ihrs, imin;
+	char *idletime = "";
+	char *warning = idletime;
+       	time_t t;
 
-	/* Tooltip for editing bp's */
-	if(!bp_tooltip)
-		bp_tooltip = gtk_tooltips_new();
-
-	l = gtk_container_children(GTK_CONTAINER(bpmenu));
-
-	while (l) {
-		gtk_widget_destroy(GTK_WIDGET(l->data));
-		l = l->next;
+	if (!(blist_options & OPT_BLIST_SHOW_ICONS)) {
+		if (b->idle > 0) {
+			text =  g_strdup_printf("<span color='gray'>%s</span>",
+						esc);	
+			g_free(esc);
+			return text;
+		} else {
+			return esc;
+		}
 	}
 
-	remmenu = gtk_menu_new();
+	time(&t);
+	ihrs = (t - b->idle) / 3600;
+	imin = ((t - b->idle) / 60) % 60;
+	
+	if (b->idle) {
+		if (ihrs)
+			idletime = g_strdup_printf(_("Idle (%dh%02dm)"), ihrs, imin);
+		else
+			idletime = g_strdup_printf(_("Idle (%dm)"), imin);
+	}
+	
+	if (b->evil > 0)
+		warning = g_strdup_printf(_("Warned (%d%%)"), b->evil);
+	
+	if (b->idle) 
+		text =  g_strdup_printf("<span color='grey'>%s</span>\n<span color='gray' size='smaller'>%s %s</span>",
+					esc,
+					idletime, warning);
+	else
+		text = g_strdup_printf("%s\n<span color='gray' size='smaller'>%s</span>", esc, warning);
+
+	if (idletime[0])
+		g_free(idletime);
+	if (warning[0])
+		g_free(warning);
+	
+	return text;
+}
 
-	menuitem = gtk_menu_item_new_with_label(_("New Buddy Pounce"));
-	gtk_menu_append(GTK_MENU(bpmenu), menuitem);
-	gtk_widget_show(menuitem);
-	g_signal_connect(GTK_OBJECT(menuitem), "activate", G_CALLBACK(new_bp_callback), NULL);
+/**********************************************************************************
+ * Public API Functions                                                           *
+ **********************************************************************************/
+static void gaim_gtk_blist_show(struct gaim_buddy_list *list)
+{
+	GtkItemFactory *ift;
+	GtkCellRenderer *rend;
+	GtkTreeViewColumn *column;
+	GtkWidget *sw;
+	GtkWidget *button;
+	GValue *val;
+	GtkTreeIter iter;
+	
+	if (gtkblist) {
+		gtk_widget_show(gtkblist->window);
+		return;
+	}
+		
+	gtkblist = g_new0(struct gaim_gtk_buddy_list , 1);
+	gtkblist->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_title(GTK_WINDOW(gtkblist->window), _("Buddy List"));
+	
+	gtkblist->vbox = gtk_vbox_new(FALSE, 6);
+	gtk_container_add(GTK_CONTAINER(gtkblist->window), gtkblist->vbox);
 
-
-	while (bp) {
+	/******************************* Menu bar *************************************/
+	ift = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<GaimMain>", NULL);
+	gtk_item_factory_create_items(ift, sizeof(blist_menu) / sizeof(*blist_menu),
+				      blist_menu, NULL);
+	gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtk_item_factory_get_widget(ift, "<GaimMain>"), FALSE, FALSE, 0);
 
-		b = (struct buddy_pounce *)bp->data;
-		remitem = gtk_menu_item_new_with_label(b->name);
-		gtk_menu_append(GTK_MENU(remmenu), remitem);
-		gtk_widget_show(remitem);
-		g_signal_connect(GTK_OBJECT(remitem), "activate", G_CALLBACK(rem_bp), b);
+	/****************************** GtkTreeView **********************************/
+	sw = gtk_scrolled_window_new(NULL,NULL);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_widget_set_usize(sw, 200, 200);
+
+	gtkblist->treemodel = gtk_tree_store_new(BLIST_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, 
+						 G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_POINTER);
+	/* This is broken because GTK is broken
+ 	g_signal_connect(G_OBJECT(gtkblist->treemodel), "row-reordered", gaim_gtk_blist_reordered_cb, NULL); */
+ 
+	gtkblist->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(gtkblist->treemodel));
+
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE);
 
-		bp = bp->next;
+	rend = gtk_cell_renderer_pixbuf_new();
+	column = gtk_tree_view_column_new_with_attributes("Status", rend, "pixbuf", STATUS_ICON_COLUMN, NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column);
+	
+	rend = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes("Name", rend, "markup", NAME_COLUMN, NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column);
+	
+	rend = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes("Warning", rend, "text", WARNING_COLUMN, NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column);
+
+	rend = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes("Idle", rend, "text", IDLE_COLUMN, NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column);
 
-	}
+	rend = gtk_cell_renderer_pixbuf_new();
+	column = gtk_tree_view_column_new_with_attributes("Buddy Icon", rend, "pixbuf", BUDDY_ICON_COLUMN, NULL);
+	g_object_set(rend, "xalign", 1.0, NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column);
+	
+	g_signal_connect(G_OBJECT(gtkblist->treeview), "row-activated", G_CALLBACK(gtk_blist_row_activated_cb), NULL);
+	g_signal_connect(G_OBJECT(gtkblist->treeview), "button-press-event", G_CALLBACK(gtk_blist_button_press_cb), NULL);
 
-	menuitem = gtk_menu_item_new_with_label(_("Remove Buddy Pounce"));
-	gtk_menu_append(GTK_MENU(bpmenu), menuitem);
-	gtk_widget_show(menuitem);
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), remmenu);
-	gtk_widget_show(remmenu);
+	gtk_box_pack_start(GTK_BOX(gtkblist->vbox), sw, TRUE, TRUE, 0);
+	gtk_container_add(GTK_CONTAINER(sw), gtkblist->treeview);
+	
+	/**************************** Button Box **************************************/
+	gtkblist->bbox = gtk_hbox_new(TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->bbox, FALSE, FALSE, 0);
+	button = gaim_pixbuf_button_from_stock(_("IM"), GAIM_STOCK_IM, GAIM_BUTTON_VERTICAL);
+	gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0);
+	gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
+	button = gaim_pixbuf_button_from_stock(_("Get Info"), GAIM_STOCK_INFO, GAIM_BUTTON_VERTICAL);
+	gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0);
+	gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
+	button = gaim_pixbuf_button_from_stock(_("Chat"), GAIM_STOCK_CHAT, GAIM_BUTTON_VERTICAL);
+	gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0);
+	gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
+	button = gaim_pixbuf_button_from_stock(_("Away"), GAIM_STOCK_AWAY, GAIM_BUTTON_VERTICAL);
+	gtk_box_pack_start(GTK_BOX(gtkblist->bbox), button, FALSE, FALSE, 0);
+	gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
+
+	/* OK... let's show this bad boy. */
+	gaim_gtk_blist_refresh(list);
+	gtk_widget_show_all(gtkblist->window);
+}
 
-	sep = gtk_hseparator_new();
-	menuitem = gtk_menu_item_new();
-	gtk_menu_append(GTK_MENU(bpmenu), menuitem);
-	gtk_container_add(GTK_CONTAINER(menuitem), sep);
-	gtk_widget_set_sensitive(menuitem, FALSE);
-	gtk_widget_show(menuitem);
-	gtk_widget_show(sep);
+void gaim_gtk_blist_refresh(struct gaim_buddy_list *list)
+{
+	GaimBlistNode *group = list->root;
+	GaimBlistNode *buddy;
+	
+	while (group) {
+		gaim_gtk_blist_update(list, group);
+		buddy = group->child;
+		while (buddy) {
+			gaim_gtk_blist_update(list, buddy);		
+			buddy = buddy->next;
+		}
+		group = group->next;
+	}
+}
 
-	bp = buddy_pounces;
+static void gaim_gtk_blist_update(struct gaim_buddy_list *list, GaimBlistNode *node)
+{
+	GtkTreeIter *iter = node->ui_data;
+	GtkTreePath *path;
+	GdkPixbuf *buf = NULL;
+	gboolean expand = FALSE;
 
-	while (bp) {
-
-		b = (struct buddy_pounce *)bp->data;
+	if (!gtkblist)
+		return;
+				
+	if (!iter) { /* This is a newly added node */
+		if (GAIM_BLIST_NODE_IS_BUDDY(node)) {
+			if (((struct buddy*)node)->present) {
+				if(node->parent && node->parent && !node->parent->ui_data) {
+					
+					/* This buddy's group has not yet been added.  We do that here */
+					
+					char *mark = g_strdup_printf("<span weight='bold'>%s</span>",  ((struct group*)node->parent)->name);
+					GtkTreeIter *iter2 = g_new0(GtkTreeIter, 1);
+					GaimBlistNode *insertat = node->parent->prev;
+					GtkTreeIter *insertatiter = NULL;
 
-		menuitem = gtk_menu_item_new_with_label(b->name);
-		gtk_menu_append(GTK_MENU(bpmenu), menuitem);
-		messmenu = gtk_menu_new();
-		gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), messmenu);
-		gtk_widget_show(menuitem);
+					/* We traverse backwards through the buddy list to find the node in the tree to insert it after */
+					while (insertat && !insertat->ui_data)
+						insertat = insertat->prev;
+					if (insertat)
+						insertatiter = insertat->ui_data;
+					
+					/* This is where we create the node and add it. */
+					gtk_tree_store_insert_after(gtkblist->treemodel, iter2, 
+								    node->parent->parent ? node->parent->parent->ui_data : NULL, insertatiter);
+					gtk_tree_store_set(gtkblist->treemodel, iter2, 
+							   STATUS_ICON_COLUMN, gtk_widget_render_icon
+							   (gtkblist->treeview,GTK_STOCK_OPEN,GTK_ICON_SIZE_LARGE_TOOLBAR,NULL),
+							   NAME_COLUMN, mark,
+							   NODE_COLUMN, node->parent,
+							   -1);
+					node->parent->ui_data = iter2;
+					expand = TRUE;
+				}
+				iter = g_new0(GtkTreeIter, 1);
+				node->ui_data = iter;
+				
+				gtk_tree_store_insert_after (gtkblist->treemodel, iter, node->parent  ? node->parent->ui_data : NULL,
+							     node->prev ? node->prev->ui_data : NULL);
+			
+							   
+				if (expand) {       /* expand was set to true if this is the first element added to a group.  In such case
+						     * we expand the group node */
+					GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), node->parent->ui_data);
+					gtk_tree_view_expand_row(GTK_TREE_VIEW(gtkblist->treeview), path, TRUE);	
+				}
+				node->ui_data = iter;
+			}
+		} 
+	}
+	
+	if (GAIM_BLIST_NODE_IS_BUDDY(node) && ((struct buddy*)node)->present) {
+		GdkPixbuf *status, *avatar;
+		char *mark;
+		
+		status = gaim_gtk_blist_get_status_icon((struct buddy*)node);
+		avatar = gaim_gtk_blist_get_buddy_icon((struct buddy*)node);
+		mark   = gaim_gtk_blist_get_name_markup((struct buddy*)node);
+		
+		gtk_tree_store_set(gtkblist->treemodel, iter, 
+				   STATUS_ICON_COLUMN, status,
+				   NAME_COLUMN, mark,
+				   WARNING_COLUMN, "",
+				   IDLE_COLUMN, "",
+				   BUDDY_ICON_COLUMN, avatar, 
+				   NODE_COLUMN, node,
+				   -1);
+			
+		g_free(mark);
+		g_object_unref(status);
+		if (avatar) {
+				g_object_unref(avatar);
+		}
+	} else if (GAIM_BLIST_NODE_IS_BUDDY(node) && node->ui_data){
+		gtk_tree_store_remove(GTK_TREE_STORE(gtkblist->treemodel), (GtkTreeIter*)(node->ui_data));
+		g_free(node->ui_data);
+		node->ui_data = NULL;
+	}
+	
+}
 
-		if (strlen(b->message))
-			mess = gtk_menu_item_new_with_label(b->message);
-		else
-			mess = gtk_menu_item_new_with_label(_("[no message]"));
-		gtk_menu_append(GTK_MENU(messmenu), mess);
-		gtk_tooltips_set_tip(bp_tooltip, GTK_WIDGET(mess), _("[Click to edit]"), NULL);
-		gtk_widget_show(mess);
-		g_signal_connect(GTK_OBJECT(mess), "activate", G_CALLBACK(edit_bp_callback), b);
-		bp = bp->next;
+static void gaim_gtk_blist_remove(struct gaim_buddy_list *list, GaimBlistNode *node)
+{
+	if (!node->ui_data)
+		return;
+	gtk_tree_store_remove(gtkblist->treemodel, (GtkTreeIter*)(node->ui_data));
+}
+
+static void gaim_gtk_blist_destroy(struct gaim_buddy_list *list)
+{
+	gtk_widget_destroy(gtkblist->window);
+}
 
-	}
+static void gaim_gtk_blist_set_visible(struct gaim_buddy_list *list, gboolean show)
+{
+	if (show)
+		gtk_widget_show(gtkblist->window);
+	else
+		gtk_widget_hide(gtkblist->window);
+}
 
-}
+static struct gaim_blist_ui_ops blist_ui_ops =
+{
+	gaim_gtk_blist_show,
+	gaim_gtk_blist_update,
+	gaim_gtk_blist_remove,
+	gaim_gtk_blist_destroy,
+	gaim_gtk_blist_set_visible
+};
 
 
-static struct group_show *find_group_show(char *group)
-{
-	GSList *m = shows;
-	struct group_show *g = NULL;
-	char *who = g_strdup(normalize (group));
-
-	while (m) {
-		g = (struct group_show *)m->data;
-		if (!g_strcasecmp(normalize (g->name), who))
-			 break;
-		g = NULL;
-		m = m->next;
-	}
-	g_free(who);
-
-	return g;
-}
-
-static struct buddy_show *find_buddy_show(struct group_show *gs, char *name)
-{
-	GSList *m = gs->members;
-	struct buddy_show *b = NULL;
-	char *who = g_strdup(normalize (name));
-
-	while (m) {
-		b = (struct buddy_show *)m->data;
-		if (!g_strcasecmp(normalize (b->name), who))
-			 break;
-		b = NULL;
-		m = m->next;
-	}
-	g_free(who);
-
-	return b;
-}
-
-static int group_number(char *group)
+struct gaim_blist_ui_ops *gaim_get_gtk_blist_ui_ops()
 {
-	GSList *m;
-	struct group *p;
-	int pos = 0;
-
-	m = groups;
-	while (m) {
-		p = (struct group *)m->data;
-		if (!strcmp(p->name, group))
-			return pos;
-		if (find_group_show(p->name))
-			pos++;
-		m = m->next;
-	}
-	/* um..... we'll never get here */
-	return -1;
-}
-
-static int buddy_number(char *group, char *buddy)
-{
-	struct group *p;
-	GSList *z;
-	struct buddy *b;
-	int pos = 0;
-	char *tmp1 = g_strdup(normalize (buddy));
-	struct group_show *gs = find_group_show(group);
-	struct buddy_show *bs;
-	GSList *seen = NULL;
-
-	p = find_group(group);
-	if(p) {
-		z = p->members;
-		while (z) {
-			b = (struct buddy *)z->data;
-			if (!strcmp(tmp1, normalize (b->name))) {
-				g_free(tmp1);
-				g_slist_free(seen);
-				return pos;
-			}
-			if ((bs = find_buddy_show(gs, b->name))) {
-				if(!g_slist_find(seen, bs)) {
-					seen = g_slist_append(seen, bs);
-					pos++;
-				}
-			}
-			z = z->next;
-		}
-	}
-	/* we shouldn't ever get here */
-	debug_printf("got to bad place in buddy_number\n");
-	g_free(tmp1);
-	g_slist_free(seen);
-	return -1;
+	return &blist_ui_ops;
 }
 
 
 
-static struct group_show *new_group_show(char *group)
-{
-	struct group_show *g = g_new0(struct group_show, 1);
-	int pos = group_number(group);
-	GdkPixmap *pm;
-	GdkBitmap *bm;
-	GtkStyle *style;
-	GtkStyle *style2;
-
-	g->name = g_strdup(group);
-
-	g->item = gtk_tree_item_new();
-
-	g_signal_connect(GTK_OBJECT(g->item), "button_press_event",
-			   G_CALLBACK(handle_click_group), g);
-
-	gtk_tree_insert(GTK_TREE(buddies), g->item, pos);
-
-	gtk_widget_show(g->item);
-
-	g->label = gtk_label_new(group);
-	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);
-
-	shows = g_slist_insert(shows, g, pos);
-
-	/* Rob does drugs - this is still evil, damn you becausse I SAID SO! */
-
-	pm = gdk_pixmap_create_from_xpm_d(g->item->window, 
-		&bm, NULL, arrow_down_xpm);
-
-	gtk_pixmap_set(GTK_PIXMAP(GTK_TREE_ITEM(g->item)->minus_pix_widget), 
-		pm, bm);
-
-	gdk_pixmap_unref(pm);
-	gdk_bitmap_unref(bm);
-
-	pm = gdk_pixmap_create_from_xpm_d(buddies->window, 
-		&bm, NULL, arrow_right_xpm);
-
-	gtk_pixmap_set(GTK_PIXMAP(GTK_TREE_ITEM(g->item)->plus_pix_widget), 
-		pm, bm);
-
-	gdk_pixmap_unref(pm);
-	gdk_bitmap_unref(bm);
-
-//	style = gtk_widget_get_style(GTK_TREE_ITEM(g->item)->pixmaps_box);
-	style2 = gtk_style_copy(gtk_widget_get_style(g->item));
-	style = gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(g->label)));
-
-	style->bg[0] = style2->base[0];
-	gtk_widget_set_style(GTK_TREE_ITEM(g->item)->pixmaps_box, style);
-
-	gtk_style_unref(style);
-	gtk_style_unref(style2);
-
-	/* bad drugs */
-
-	update_num_group(g);
-	
-	return g;
-}
-
-static struct buddy_show *new_buddy_show(struct group_show *gs, struct buddy *buddy, char **xpm)
-{
-	struct buddy_show *b = g_new0(struct buddy_show, 1);
-	GtkWidget *box;
-	GdkPixmap *pm;
-	GdkBitmap *bm;
-	int pos = buddy_number(gs->name, buddy->name);
-	b->sound = 0;
-
-	if (gs->members == NULL) {
-		gs->tree = gtk_tree_new();
-		gtk_tree_item_set_subtree(GTK_TREE_ITEM(gs->item), gs->tree);
-		gtk_tree_item_expand(GTK_TREE_ITEM(gs->item));
-		gtk_widget_show(gs->tree);
-	}
-
-	b->name = g_strdup(buddy->name);
-
-	b->item = gtk_tree_item_new();
-	gtk_tree_insert(GTK_TREE(gs->tree), b->item, pos);
-	gtk_object_set_user_data(GTK_OBJECT(b->item), b);
-	g_signal_connect(GTK_OBJECT(b->item), "button_press_event",
-			   G_CALLBACK(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, xpm ? xpm : no_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);
-	if (!(blist_options & OPT_BLIST_SHOW_PIXMAPS))
-		gtk_widget_hide(b->pix);
-	gdk_pixmap_unref(pm);
-	gdk_bitmap_unref(bm);
-
-	b->label = gtk_label_new(get_buddy_alias(buddy));
-	gtk_misc_set_alignment(GTK_MISC(b->label), 0.0, 0.5);
-	gtk_box_pack_start(GTK_BOX(box), b->label, FALSE, FALSE, 1);
-	gtk_widget_show(b->label);
-
-	b->warn = gtk_label_new("");
-	gtk_box_pack_start(GTK_BOX(box), b->warn, FALSE, FALSE, 1);
-	gtk_widget_show(b->warn);
-
-	b->idle = gtk_label_new("");
-	gtk_box_pack_end(GTK_BOX(box), b->idle, FALSE, FALSE, 1);
-	gtk_widget_show(b->idle);
-
-	gs->members = g_slist_insert(gs->members, b, pos);
-	update_num_group(gs);
-	return b;
-}
-
-static void remove_buddy_show(struct group_show *gs, struct buddy_show *bs)
-{
-	/* the name of this function may be misleading, but don't let it fool you. the point
-	 * of this is to remove bs->item from gs->tree, and make sure gs->tree still exists
-	 * and is a valid tree afterwards. Otherwise, Bad Things will happen. */
-	gtk_tree_remove_item(GTK_TREE(gs->tree), bs->item);
-	bs->item = NULL;
-}
-
-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;
-}
-
-/* used by this file, and by iconaway.so */
-void hide_buddy_list() {
-	if (blist) {
-		if (!connections || docklet_count) {
-#ifdef _WIN32
-			/* minimize to systray with effects */
-			wgaim_systray_minimize(blist);
-#endif
-			gtk_widget_hide(blist);
-		} else {
-			gtk_window_iconify(GTK_WINDOW(blist));
-		}
-	}
-}
-
-/* mostly used by code in this file */
-void unhide_buddy_list() {
-	if (blist) {
-		if (!GTK_WIDGET_VISIBLE(blist) && blist_options & OPT_BLIST_SAVED_WINDOWS &&
-		      blist_pos.width != 0) {
-			/* don't move it off screen */
-			if (blist_pos.x >= gdk_screen_width()) {
-				blist_pos.x = gdk_screen_width() - 100;
-			} else if (blist_pos.x < 0) {
-				blist_pos.x = 100;
-			}
-
-			if (blist_pos.y >= gdk_screen_height()) {
-				blist_pos.y = gdk_screen_height() - 100;
-			} else if (blist_pos.y < 0) {
-				blist_pos.y = 100;
-			}
-
-			gtk_window_move(GTK_WINDOW(blist), blist_pos.x, blist_pos.y);
-			gtk_window_resize(GTK_WINDOW(blist), blist_pos.width, blist_pos.height);
-		}
-
-		gtk_window_present(GTK_WINDOW(blist));
-	}
-}
-
-/* for the delete_event handler */
-static void close_buddy_list() {
-	if (docklet_count) {
-		hide_buddy_list();
-	} else {
-		do_quit();
-	}
-}
-
-void docklet_add() {
-	docklet_count++;
-	debug_printf("docklet_count: %d\n",docklet_count);
-}
-
-void docklet_remove() {
-	docklet_count--;
-	debug_printf("docklet_count: %d\n",docklet_count);
-	if (!docklet_count) {
-		if (connections) {
-			unhide_buddy_list();
-		} else {
-			gtk_window_present(GTK_WINDOW(mainwindow));
-		}
-	}
-}
-
-void docklet_toggle() {
-	/* Useful for the docklet plugin and also for the win32 tray icon*/
-	/* This is called when one of those is clicked--it will show/hide the 
-	   buddy list/login window--depending on which is active */
-	if (connections && blist) {
-		if (GTK_WIDGET_VISIBLE(blist)) {
-			if (GAIM_WINDOW_ICONIFIED(blist) || obscured) {
-				unhide_buddy_list();
-			} else {
-				hide_buddy_list();
-			}
-		} else {
-#if _WIN32
-			wgaim_systray_maximize(blist);
-#endif
-			unhide_buddy_list();
-		}
-	} else if (connections) {
-		/* we're logging in or something... do nothing */
-		debug_printf("docklet_toggle called with connections but no blist!\n");
-	} else {
-		if (GTK_WIDGET_VISIBLE(mainwindow)) {
-			if (GAIM_WINDOW_ICONIFIED(mainwindow)) {
-				gtk_window_present(GTK_WINDOW(mainwindow));
-			} else {
-#if _WIN32
-				wgaim_systray_minimize(mainwindow);
-#endif
-				gtk_widget_hide(mainwindow);
-			}
-		} else {
-#if _WIN32
-			wgaim_systray_maximize(mainwindow);
-#endif
-			gtk_window_present(GTK_WINDOW(mainwindow));
-		}
-	}
-}
-
-static gboolean log_timeout(gpointer data)
-{
-	struct buddy_show *b = data;
-	/* this part is really just a bad hack because of a bug I can't find */
-	GSList *s = shows;
-	while (s) {
-		struct group_show *gs = s->data;
-		GSList *m = gs->members;
-		while (m) {
-			if (b == m->data)
-				break;
-			m = m->next;
-		}
-		if (m != NULL)
-			break;
-		s = s->next;
-	}
-	if (!s)
-		return FALSE;
-
-	/* this is the real part. */
-	if (!b->connlist) {
-		struct group_show *g = find_gs_by_bs(b);
-		g->members = g_slist_remove(g->members, b);
-		if (blist)
-			remove_buddy_show(g, b);
-		else
-			debug_printf("log_timeout but buddy list not available\n");
-		if ((g->members == NULL) && (blist_options & OPT_BLIST_NO_MT_GRP)) {
-			shows = g_slist_remove(shows, g);
-			if (blist)
-				gtk_tree_remove_item(GTK_TREE(buddies), g->item);
-			g_free(g->name);
-			g_free(g);
-		}
-		g_source_remove(b->log_timer);
-		b->log_timer = 0;
-		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 gaim_connection *gc = b->connlist->data;
-		struct buddy *light = find_buddy(gc->account, b->name);
-		if (gc->prpl->list_icon)
-			xpm = gc->prpl->list_icon(light->uc);
-		if (xpm == NULL)
-			xpm = (char **)no_icon_xpm;
-		pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, xpm);
-		gtk_widget_hide(b->pix);
-		gtk_pixmap_set(GTK_PIXMAP(b->pix), pm, bm);
-		gtk_widget_show(b->pix);
-		if (!(blist_options & OPT_BLIST_SHOW_PIXMAPS))
-			gtk_widget_hide(b->pix);
-		gdk_pixmap_unref(pm);
-		gdk_bitmap_unref(bm);
-		g_source_remove(b->log_timer);
-		b->log_timer = 0;
-		b->sound = 0;
-	}
-	return FALSE;
-}
-
-static char *caps_string(guint caps)
-{
-	static char buf[256], *tmp;
-	int count = 0, i = 0;
-	guint bit = 1;
-	while (bit <= 0x10000) {
-		if (bit & caps) {
-			switch (bit) {
-			case 0x1:
-				tmp = _("Buddy Icon");
-				break;
-			case 0x2:
-				tmp = _("Voice");
-				break;
-			case 0x4:
-				tmp = _("IM Image");
-				break;
-			case 0x8:
-				tmp = _("Chat");
-				break;
-			case 0x10:
-				tmp = _("Get File");
-				break;
-			case 0x20:
-				tmp = _("Send File");
-				break;
-			case 0x40:
-			case 0x200:
-				tmp = _("Games");
-				break;
-			case 0x80:
-				tmp = _("Stocks");
-				break;
-			case 0x100:
-				tmp = _("Send Buddy List");
-				break;
-			case 0x400:
-				tmp = _("EveryBuddy Bug");
-				break;
-			case 0x800:
-				tmp = _("AP User");
-				break;
-			case 0x1000:
-				tmp = _("ICQ RTF");
-				break;
-			case 0x2000:
-				tmp = _("Nihilist");
-				break;
-			case 0x4000:
-				tmp = _("ICQ Server Relay");
-				break;
-			case 0x8000:
-				tmp = _("ICQ Unknown");
-				break;
-			case 0x10000:
-				tmp = _("Trillian Encryption");
-				break;
-			default:
-				tmp = NULL;
-				break;
-			}
-			if (tmp)
-				i += g_snprintf(buf + i, sizeof(buf) - i, "%s%s", (count ? ", " : ""),
-						tmp);
-			count++;
-		}
-		bit <<= 1;
-	}
-	return buf;
-}
-
-/* for this we're just going to assume the first connection that registered the buddy.
- * if it's not the one you were hoping for then you're shit out of luck */
-static void update_idle_time(struct buddy_show *bs)
-{
-	/* this also updates the tooltip since that has idle time in it */
-	char idlet[16], warnl[16];
-	time_t t;
-	int ihrs, imin;
-	struct buddy *b;
-	GtkStyle *style;
-
-	char infotip[2048];
-	char warn[256];
-	char caps[256];
-	char alias[512];
-	char serv_alias[512];
-	char *sotime = NULL, *itime;
-
-	struct gaim_connection *gc;
-
-	int i;
-
-	time(&t);
-	if (!bs->connlist)
-		return;
-	gc = bs->connlist->data;
-	b = find_buddy(gc->account, bs->name);
-	if (!b)
-		return;
-	ihrs = (t - b->idle) / 3600;
-	imin = ((t - b->idle) / 60) % 60;
-
-	if (ihrs)
-		g_snprintf(idlet, sizeof idlet, "(%d:%02d)", ihrs, imin);
-	else
-		g_snprintf(idlet, sizeof idlet, "(%d)", imin);
-
-	gtk_widget_hide(bs->idle);
-	if (b->idle)
-		gtk_label_set(GTK_LABEL(bs->idle), idlet);
-	else
-		gtk_label_set(GTK_LABEL(bs->idle), "");
-	if (blist_options & OPT_BLIST_SHOW_IDLETIME)
-		gtk_widget_show(bs->idle);
-
-	style = gtk_style_new();
-	gtk_style_set_font(style, gdk_font_ref(gtk_style_get_font(bs->label->style)));
-	for (i = 0; i < 5; i++)
-		style->fg[i] = bs->idle->style->fg[i];
-	if ((blist_options & OPT_BLIST_GREY_IDLERS) && (b->idle)) {
-		style->fg[GTK_STATE_NORMAL].red =
-		  (style->fg[GTK_STATE_NORMAL].red / 2) + (style->base[GTK_STATE_NORMAL].red / 2);
-		style->fg[GTK_STATE_NORMAL].green = 
-		  (style->fg[GTK_STATE_NORMAL].green / 2) + (style->base[GTK_STATE_NORMAL].green / 2);
-		style->fg[GTK_STATE_NORMAL].blue = 
-		  (style->fg[GTK_STATE_NORMAL].blue / 2) + (style->base[GTK_STATE_NORMAL].blue / 2);
-	}
-	gtk_widget_set_style(bs->label, style);
-	gtk_style_unref(style);
-
-	/* now we do the tooltip */
-	if (b->signon) {
-		char *stime = sec_to_text(t - b->signon +
-					  ((struct gaim_connection *)bs->connlist->data)->
-					  correction_time);
-		sotime = g_strdup_printf(_("Logged in: %s\n"), stime);
-		g_free(stime);
-	}
-
-	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);
-		g_snprintf(warnl, sizeof warnl, "(%d%%)", b->evil);
-	} else {
-		warn[0] = '\0';
-		warnl[0] = '\0';
-	}
-	gtk_widget_hide(bs->warn);
-	gtk_label_set(GTK_LABEL(bs->warn), warnl);
-	if (blist_options & OPT_BLIST_SHOW_WARN)
-		gtk_widget_show(bs->warn);
-
-	if (b->caps)
-		g_snprintf(caps, sizeof caps, _("Capabilities: %s\n"), caps_string(b->caps));
-	else
-		caps[0] = '\0';
-
-	if (b->alias[0])
-		g_snprintf(alias, sizeof alias, _("Alias: %s\n"), b->alias);
-	else
-		alias[0] = '\0';
-
-	if (b->server_alias[0])
-		g_snprintf(serv_alias, sizeof serv_alias, _("Nickname: %s\n"),
-				b->server_alias);
-	else
-		serv_alias[0] = '\0';
-
-	g_snprintf(infotip, sizeof infotip, _("%s%sScreen Name: %s\n%s%s%s%s%s%s"),
-		   alias, serv_alias, b->name, (b->signon ? sotime : ""), warn,
-		   (b->idle ? _("Idle: ") : ""), itime, (b->idle ? "\n" : ""), caps);
-
-	gtk_tooltips_set_tip(tips, GTK_WIDGET(bs->item), infotip, "");
-
-	if (b->signon)
-		g_free(sotime);
-	g_free(itime);
-}
-
-void update_idle_times()
-{
-	GSList *grp = shows;
-	GSList *mem;
-	struct buddy_show *b;
-	struct group_show *g;
+/*********************************************************************
+ * Public utility functions                                          *
+ *********************************************************************/
 
-	while (grp) {
-		g = (struct group_show *)grp->data;
-		mem = g->members;
-		while (mem) {
-			b = (struct buddy_show *)mem->data;
-			update_idle_time(b);
-			mem = mem->next;
-		}
-		grp = grp->next;
-	}
-}
-
-void set_buddy(struct gaim_connection *gc, struct buddy *b)
-{
-	struct group *g = find_group_by_buddy(b);
-	struct group_show *gs;
-	struct buddy_show *bs;
-	GdkPixmap *pm;
-	GdkBitmap *bm;
-	char **xpm = NULL;
-
-	if (!blist)
-		return;
-
-	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, (char **)login_icon_xpm);
-		if (!g_slist_find(bs->connlist, gc)) {
-			bs->connlist = g_slist_append(bs->connlist, gc);
-			update_num_group(gs);
-		}
-		if (b->present == 1) {
-			if (bs->sound != 2)
-				gaim_sound_play_event(GAIM_SOUND_BUDDY_ARRIVE);
-			if (blist_options & OPT_BLIST_POPUP)
-				gdk_window_show(blist->window);
-			pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
-							  NULL, (char **)login_icon_xpm);
-			gtk_widget_hide(bs->pix);
-			gtk_pixmap_set(GTK_PIXMAP(bs->pix), pm, bm);
-			gtk_widget_show(bs->pix);
-			gdk_pixmap_unref(pm);
-			gdk_bitmap_unref(bm);
-			b->present = 2;
-			if (bs->log_timer > 0)
-				g_source_remove(bs->log_timer);
-			bs->log_timer = g_timeout_add(10000, log_timeout, bs);
-			if ((bs->sound != 2) && (im_options & OPT_IM_LOGON)) {
-				struct gaim_conversation *c = gaim_find_conversation(b->name);
-				if (c) {
-					char tmp[1024];
-					g_snprintf(tmp, sizeof(tmp), _("%s logged in."),
-							   get_buddy_alias(b));
-					gaim_conversation_write(c, NULL, tmp, -1,
-											WFLAG_SYSTEM, time(NULL));
-				} else if (awayqueue && find_queue_total_by_name(b->name)) {
-					struct queued_message *qm = g_new0(struct queued_message, 1);
-					g_snprintf(qm->name, sizeof(qm->name), "%s", b->name);
-					qm->message = g_strdup_printf(_("%s logged in."),
-							get_buddy_alias(b));
-					qm->account = gc->account;
-					qm->tm = time(NULL);
-					qm->flags = WFLAG_SYSTEM;
-					qm->len = -1;
-					message_queue = g_slist_append(message_queue, qm);
-				}
-			}
-			bs->sound = 2;
-		} else if (bs->log_timer == 0) {
-			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 (!(blist_options & OPT_BLIST_SHOW_PIXMAPS))
-				gtk_widget_hide(bs->pix);
-			gdk_pixmap_unref(pm);
-			gdk_bitmap_unref(bm);
-		}
-		update_idle_time(bs);
-	} else {
-		gs = find_group_show(g->name);
-		if (!gs)
-			return;
-		bs = find_buddy_show(gs, b->name);
-		if (!bs)
-			return;
-		if (!bs->connlist)
-			return;	/* we won't do signoff updates for
-				   buddies that have already signed
-				   off */
-		if (bs->sound != 1)
-			gaim_sound_play_event(GAIM_SOUND_BUDDY_LEAVE);
-		if (blist_options & OPT_BLIST_POPUP)
-			gdk_window_show(blist->window);
-		bs->connlist = g_slist_remove(bs->connlist, gc);
-		update_num_group(gs);
-		if (bs->log_timer > 0)
-			g_source_remove(bs->log_timer);
-		bs->log_timer = g_timeout_add(10000, 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);
-		gdk_pixmap_unref(pm);
-		gdk_bitmap_unref(bm);
-		if ((bs->sound != 1) && (im_options & OPT_IM_LOGON)) {
-			struct gaim_conversation *c = gaim_find_conversation(b->name);
-			if (c) {
-				char tmp[1024];
-				g_snprintf(tmp, sizeof(tmp), _("%s logged out."),
-						   get_buddy_alias(b));
-				gaim_conversation_write(c, NULL, tmp, -1,
-										WFLAG_SYSTEM, time(NULL));
-			} else if (awayqueue && find_queue_total_by_name(b->name)) {
-				struct queued_message *qm = g_new0(struct queued_message, 1);
-				g_snprintf(qm->name, sizeof(qm->name), "%s",
-						get_buddy_alias(b));
-				qm->message = g_strdup_printf(_("%s logged out."),
-						get_buddy_alias(b));
-				qm->account = gc->account;
-				qm->tm = time(NULL);
-				qm->flags = WFLAG_SYSTEM;
-				qm->len = -1;
-				message_queue = g_slist_append(message_queue, qm);
-			}
-		}
-
-		bs->sound = 1;
-	}
-}
-
-static gboolean delayed_save_prefs(gpointer data) {
-	save_prefs();
-	return FALSE;
-}
-
-static gboolean configure_blist_window(GtkWidget *w, GdkEventConfigure *event, gpointer data) {
-	/* unfortunately GdkEventConfigure ignores the window gravity, but  *
-	 * the only way we have of setting the position doesn't. we have to *
-	 * call get_position and get_size because they do pay attention to  *
-	 * the gravity. this is inefficient and I agree it sucks, but it's  *
-	 * more likely to work correctly.                        - Robot101 */
-	gint x, y;
-
-	/* check for visibility because when we aren't visible, this will   *
-	 *  give us bogus (0,0) coordinates.                     - xOr      */
-	if (GTK_WIDGET_VISIBLE(blist)) {
-	  gtk_window_get_position(GTK_WINDOW(blist), &x, &y);
-
-	  if (x != blist_pos.x ||
-	      y != blist_pos.y ||
-	      event->width != blist_pos.width ||
-	      event->height != blist_pos.height) {
-	    blist_pos.x = x;
-	    blist_pos.y = y;
-	    blist_pos.width = event->width;
-	    blist_pos.height = event->height;
-
-	    if (!g_main_context_find_source_by_user_data(NULL, &delayed_save_prefs)) {
-	      debug_printf("queueing save of blist prefs\n");
-	      g_timeout_add(5000, delayed_save_prefs, &delayed_save_prefs);
-	    }
-	  }
-	}
-
-	return FALSE;
-}
-
-static void visibility_blist_window(GtkWidget *w, GdkEventVisibility *event, void *data) {
-	if (event->state == GDK_VISIBILITY_FULLY_OBSCURED) {
-		obscured = TRUE;
-	} else {
-		obscured = FALSE;
-	}
-}
-
-/*******************************************************************
- *
- * Helper funs for making the menu
- *
- *******************************************************************/
-
-void gaim_separator(GtkWidget *menu)
-{
-	GtkWidget *menuitem;
-
-	menuitem = gtk_separator_menu_item_new();
-	gtk_widget_show(menuitem);
-	gtk_menu_append(GTK_MENU(menu), menuitem);
-}
-
-
-void build_imchat_box(gboolean on)
-{
-	if (on) {
-		if (imchatbox)
-			return;
-
-		imbutton = gtk_button_new_with_label(_("IM"));
-		infobutton = gtk_button_new_with_label(_("Info"));
-		chatbutton = gtk_button_new_with_label(_("Chat"));
-		awaybutton = gtk_button_new_with_label(_("Away"));
-
-		imchatbox = gtk_hbox_new(TRUE, 10);
-
-		gtk_button_set_relief(GTK_BUTTON(imbutton), GTK_RELIEF_NONE);
-		gtk_button_set_relief(GTK_BUTTON(infobutton), GTK_RELIEF_NONE);
-		gtk_button_set_relief(GTK_BUTTON(chatbutton), GTK_RELIEF_NONE);
-		gtk_button_set_relief(GTK_BUTTON(awaybutton), GTK_RELIEF_NONE);
-
-		/* Put the buttons in the hbox */
-		gtk_widget_show(imbutton);
-		gtk_widget_show(infobutton);
-		gtk_widget_show(chatbutton);
-		gtk_widget_show(awaybutton);
-
-		gtk_box_pack_start(GTK_BOX(imchatbox), imbutton, TRUE, TRUE, 0);
-		gtk_box_pack_start(GTK_BOX(imchatbox), infobutton, TRUE, TRUE, 0);
-		gtk_box_pack_start(GTK_BOX(imchatbox), chatbutton, TRUE, TRUE, 0);
-		gtk_box_pack_start(GTK_BOX(imchatbox), awaybutton, TRUE, TRUE, 0);
-		gtk_container_border_width(GTK_CONTAINER(imchatbox), 5);
-
-		g_signal_connect(GTK_OBJECT(imbutton), "clicked", G_CALLBACK(im_callback),
-				   buddies);
-		g_signal_connect(GTK_OBJECT(infobutton), "clicked", G_CALLBACK(info_callback),
-				   buddies);
-		g_signal_connect(GTK_OBJECT(chatbutton), "clicked", G_CALLBACK(chat_callback),
-				   buddies);
-		g_signal_connect(GTK_OBJECT(awaybutton), "clicked", G_CALLBACK(away_callback),
-				   buddies);
-
-		gtk_tooltips_set_tip(tips, infobutton, _("Information on selected Buddy"), "Penguin");
-		gtk_tooltips_set_tip(tips, imbutton, _("Send Instant Message"), "Penguin");
-		gtk_tooltips_set_tip(tips, chatbutton, _("Start/join a Buddy Chat"), "Penguin");
-		gtk_tooltips_set_tip(tips, awaybutton, _("Activate Away Message"), "Penguin");
-
-		gtk_box_pack_start(GTK_BOX(buddypane), imchatbox, FALSE, FALSE, 0);
-
-		gtk_widget_show(imchatbox);
-	} else {
-		if (imchatbox)
-			gtk_widget_destroy(imchatbox);
-		imchatbox = NULL;
-	}
-}
-
-extern GtkWidget *debugbutton;
-void clicked_debug (GtkWidget *widg, gpointer pntr)
-{	
-	if (debugbutton)
-		gtk_button_clicked(GTK_BUTTON(debugbutton));
-	else {
-		misc_options ^= OPT_MISC_DEBUG;
-		show_debug();
-	}
-}
-
-void
-show_xfer_dialog(GtkMenuItem *item, gpointer user_data)
+GdkPixbuf *
+create_prpl_icon(struct gaim_account *account)
 {
-	struct gaim_gtkxfer_dialog *dialog;
-
-	dialog = gaim_get_gtkxfer_dialog();
-
-	if (dialog == NULL) {
-		dialog = gaim_gtkxfer_dialog_new();
-
-		gaim_set_gtkxfer_dialog(dialog);
-	}
-
-	gaim_gtkxfer_dialog_show(dialog);
-}
-
-void make_buddy_list()
-{
-
-	/* Build the buddy list, based on *config */
-
-	GtkWidget *sw;
-	GtkWidget *menu;
-#ifdef NO_MULTI
-	GtkWidget *setmenu;
-	GtkWidget *findmenu;
-#endif
-	GtkWidget *menubar;
-	GtkWidget *vbox;
-	GtkWidget *menuitem;
-	GtkWidget *notebook;
-	GtkWidget *label;
-	GtkWidget *bbox;
-	GtkWidget *tbox;
-
-	if (blist) {
-		return;
+	struct prpl *prpl = find_prpl(account->protocol);
+	GdkPixbuf *status = NULL;
+	char *filename = NULL;
+	const char *protoname = prpl->list_icon(account, NULL);
+	/* "Hey, what's all this crap?" you ask.  Status icons will be themeable too, and 
+	   then it will look up protoname from the theme */
+	if (!strcmp(protoname, "aim")) {
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "aim.png", NULL);
+		status = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+	} else if (!strcmp(protoname, "yahoo")) {
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "yahoo.png", NULL);
+		status = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+	} else if (!strcmp(protoname, "msn")) {
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "msn.png", NULL);
+		status = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+	} else if (!strcmp(protoname, "jabber")) {
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "jabber.png", NULL);
+		status = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+	} else if (!strcmp(protoname, "icq")) {
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "icq.png", NULL);
+		status = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+	} else if (!strcmp(protoname, "gadu-gadu")) {
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "gadugadu.png", NULL);
+		status = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+	} else if (!strcmp(protoname, "napster")) {
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "napster.png", NULL);
+		status = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
+	} else if (!strcmp(protoname, "irc")) {
+		filename = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", "irc.png", NULL);
+		status = gdk_pixbuf_new_from_file(filename,NULL);
+		g_free(filename);
 	}
-
-	blist = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
-	gtk_window_set_gravity(GTK_WINDOW(blist), GDK_GRAVITY_NORTH_WEST);
-	gtk_window_set_policy(GTK_WINDOW(blist), TRUE, TRUE, TRUE);
-	gtk_window_set_title(GTK_WINDOW(blist), _("Gaim - Buddy List"));
-	gtk_window_set_role(GTK_WINDOW(blist), "buddy_list");
-
-	gtk_widget_realize(blist);
-
-	accel = gtk_accel_group_new();
-	gtk_window_add_accel_group(GTK_WINDOW(blist), accel);
-
-	menubar = gtk_menu_bar_new();
-
-	menu = gtk_menu_new();
-	gtk_menu_set_accel_group(GTK_MENU(menu), accel);
-
-	menuitem = gaim_new_item(NULL, _("File"));
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
-	gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuitem);
-
-	gaim_new_item_from_stock(menu, _("_Add A Buddy"), GTK_STOCK_ADD,
-				  G_CALLBACK(add_buddy_callback), NULL,  'b', GDK_CONTROL_MASK, "Ctl+B");
-	gaim_new_item_from_stock(menu, _("_Join A Chat"), GTK_STOCK_JUMP_TO,
-				  G_CALLBACK(chat_callback), NULL, 'c', GDK_CONTROL_MASK, "Ctl+C");
-	gaim_new_item_from_stock(menu, _("_New Message"), GTK_STOCK_CONVERT,
-				  G_CALLBACK(show_im_dialog), NULL, 'i', GDK_CONTROL_MASK, "Ctl+I");
-	gaim_new_item_from_stock(menu, _("_Get User Info"), GTK_STOCK_FIND,
-				  G_CALLBACK(show_info_dialog), NULL, 'j', GDK_CONTROL_MASK, "Ctl+J");
-
-	gaim_separator(menu);
-
-	gaim_new_item_from_pixbuf(menu, _("Import Buddy List"), "import-menu.png",
-				  G_CALLBACK(import_callback), NULL, 0, 0, 0);
-
-	gaim_separator(menu);
-
-	gaim_new_item_from_stock(menu, _("Signoff"), NULL,
-				  G_CALLBACK(signoff_all), (void*)1, 'd', GDK_CONTROL_MASK, "Ctl+D");
-	gaim_new_item_from_stock(menu, _("Hide"), NULL,
-				  G_CALLBACK(hide_buddy_list), NULL, 'h', GDK_CONTROL_MASK, "Ctl+H");
-	gaim_new_item_from_stock(menu, _("Quit"), GTK_STOCK_QUIT,
-				  G_CALLBACK(do_quit), NULL, 'q', GDK_CONTROL_MASK, "Ctl+Q");
-
-	menu = gtk_menu_new();
-
-	menuitem = gaim_new_item(NULL, _("Tools"));
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
-	gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuitem);
-
-	awaymenu = gtk_menu_new();
-	menuitem = gaim_new_item_from_stock(menu, _("Away"), NULL, NULL, NULL, 0, 0, 0);
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), awaymenu);
-	do_away_menu();
-
-	bpmenu = gtk_menu_new();
-	menuitem = gaim_new_item_from_stock(menu, _("Buddy Pounce"), NULL, NULL, NULL, 0, 0, 0);
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), bpmenu);
-	do_bp_menu();
-
-	gaim_separator(menu);
-
-#ifndef NO_MULTI
-	gaim_new_item_from_pixbuf(menu, _("_Accounts..."), "accounts-menu.png",
-				  G_CALLBACK(account_editor), NULL, 'a', GDK_CONTROL_MASK, "Ctl+A");
-#endif
-	gaim_new_item_from_stock(menu, _("_Preferences..."), GTK_STOCK_PREFERENCES,
-				  G_CALLBACK(show_prefs), NULL, 'p', GDK_CONTROL_MASK, "Ctl+P");
-
-	gaim_new_item_from_stock(menu, _("_File Transfers..."), GTK_STOCK_REVERT_TO_SAVED,
-				G_CALLBACK(show_xfer_dialog), NULL, 0, 0, NULL);
-
-	gaim_separator(menu);
-
-	protomenu = gtk_menu_new();
-	menuitem = gaim_new_item_from_stock(menu, _("Protocol Actions"), NULL, NULL, NULL, 0, 0, 0);
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), protomenu);
-	do_proto_menu();
-
-	gaim_new_item_from_stock(menu, _("Pr_ivacy..."), NULL,
-				  G_CALLBACK(show_privacy_options), NULL, 0, 0, 0);
-
-	gaim_new_item_from_stock(menu, _("_View System Log..."), NULL,
-				  G_CALLBACK(show_syslog), NULL, 0, 0, 0);
-
-	menu = gtk_menu_new();
-
-	menuitem = gaim_new_item(NULL, _("Help"));
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
-	gtk_menu_bar_append(GTK_MENU_BAR(menubar), menuitem);
-
-	gaim_new_item_from_stock(menu, _("Online Help"), GTK_STOCK_HELP, G_CALLBACK(open_url), WEBSITE"documentation.php", GDK_F1, 0, NULL);
-	gaim_new_item_from_stock(menu, _("Debug Window"), NULL, G_CALLBACK(clicked_debug), NULL, 0, 0, NULL);
-	
-	gaim_separator(menu);
-
-	gaim_new_item_from_pixbuf(menu, _("About Gaim"), "about_menu.png", G_CALLBACK(show_about), NULL, GDK_F1, GDK_CONTROL_MASK, NULL);
-	
-	gtk_widget_show(menubar);
-
-	vbox = gtk_vbox_new(FALSE, 0);
-
-	notebook = gtk_notebook_new();
-
-	/* Do buddy list stuff */
-	/* FIXME: spacing on both panes is ad hoc */
-	buddypane = gtk_vbox_new(FALSE, 1);
-
-	buddies = gtk_tree_new();
-	gtk_tree_set_view_lines(GTK_TREE(buddies), FALSE);
-	sw = gtk_scrolled_window_new(NULL, NULL);
-
-	tips = gtk_tooltips_new();
-	gtk_object_set_data(GTK_OBJECT(blist), _("Buddy List"), tips);
-
-	/* Now the buddy list */
-	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), buddies);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-				       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	gtk_widget_set_usize(sw, 200, 200);
-	gtk_widget_show(buddies);
-	gtk_widget_show(sw);
-
-	gtk_box_pack_start(GTK_BOX(buddypane), sw, TRUE, TRUE, 0);
-	gtk_widget_show(buddypane);
-
-	if (!(blist_options & OPT_BLIST_NO_BUTTONS))
-		build_imchat_box(TRUE);
-
-	/* Swing the edit buddy */
-	editpane = gtk_vbox_new(FALSE, 1);
-
-	edittree = gtk_ctree_new(1, 0);
-	gtk_ctree_set_line_style(GTK_CTREE(edittree), GTK_CTREE_LINES_SOLID);;
-	gtk_ctree_set_expander_style(GTK_CTREE(edittree), GTK_CTREE_EXPANDER_SQUARE);
-	gtk_clist_set_reorderable(GTK_CLIST(edittree), TRUE);
-	g_signal_connect(GTK_OBJECT(edittree), "button_press_event",
-			   G_CALLBACK(click_edit_tree), NULL);
-
-	gtk_ctree_set_drag_compare_func(GTK_CTREE(edittree),
-					(GtkCTreeCompareDragFunc) edit_drag_compare_func);
-
-
-	g_signal_connect_after(GTK_OBJECT(edittree), "tree_move",
-				 G_CALLBACK(edit_tree_move), NULL);
-
-
-	bbox = gtk_hbox_new(TRUE, 5);
-	gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
-	tbox = gtk_scrolled_window_new(NULL, NULL);
-
-	/* buttons */
-	addbutton = gtk_button_new_with_label(_("Add"));
-	groupbutton = gtk_button_new_with_label(_("Group"));
-	rembutton = gtk_button_new_with_label(_("Remove"));
-
-	gtk_button_set_relief(GTK_BUTTON(addbutton), GTK_RELIEF_NONE);
-	gtk_button_set_relief(GTK_BUTTON(groupbutton), GTK_RELIEF_NONE);
-	gtk_button_set_relief(GTK_BUTTON(rembutton), GTK_RELIEF_NONE);
-
-	gtk_box_pack_start(GTK_BOX(bbox), addbutton, TRUE, TRUE, 0);
-	gtk_box_pack_start(GTK_BOX(bbox), groupbutton, TRUE, TRUE, 0);
-	gtk_box_pack_start(GTK_BOX(bbox), rembutton, TRUE, TRUE, 0);
-
-	gtk_tooltips_set_tip(tips, addbutton, _("Add a new Buddy"), "Penguin");
-	gtk_tooltips_set_tip(tips, groupbutton, _("Add a new Group"), "Penguin");
-	gtk_tooltips_set_tip(tips, rembutton, _("Remove selected Buddy/Group"), "Penguin");
-
-	g_signal_connect(G_OBJECT(rembutton), "clicked", G_CALLBACK(do_del_buddy), edittree);
-	g_signal_connect(G_OBJECT(addbutton), "clicked", G_CALLBACK(add_buddy_callback), NULL);
-	g_signal_connect(G_OBJECT(groupbutton), "clicked", G_CALLBACK(add_group_callback), NULL);
-
-	/* And the boxes in the box */
-	gtk_box_pack_start(GTK_BOX(editpane), tbox, TRUE, TRUE, 0);
-	gtk_box_pack_start(GTK_BOX(editpane), bbox, FALSE, FALSE, 0);
-
-	/* Finish up */
-	gtk_widget_show(addbutton);
-	gtk_widget_show(groupbutton);
-	gtk_widget_show(rembutton);
-	gtk_widget_show(edittree);
-	gtk_widget_show(tbox);
-	gtk_widget_show(bbox);
-	gtk_widget_show(editpane);
-
-	update_button_pix();
-
-	label = gtk_label_new(_("Online"));
-	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), buddypane, label);
-	label = gtk_label_new(_("Edit Buddies"));
-	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), editpane, label);
-
-	if(blist_options & OPT_BLIST_BOTTOM_TAB)
-		gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
-	
-	gtk_widget_show_all(notebook);
-
-	/* Pack things in the vbox */
-	gtk_widget_show(vbox);
-	gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
-	gtk_container_add(GTK_CONTAINER(blist), vbox);
-
-	g_signal_connect(G_OBJECT(blist), "delete_event", G_CALLBACK(close_buddy_list), NULL);
-	g_signal_connect(G_OBJECT(blist), "configure_event", G_CALLBACK(configure_blist_window), NULL);
-	g_signal_connect(G_OBJECT(blist), "visibility_notify_event", G_CALLBACK(visibility_blist_window), NULL);
-
-	gtk_widget_add_events(blist, GDK_VISIBILITY_NOTIFY_MASK);
-
-	/* The edit tree */
-	gtk_container_add(GTK_CONTAINER(tbox), edittree);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tbox),
-				       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
-#ifdef _WIN32
-	/* Register newly created window with systray module */
-	wgaim_created_blistwin(GTK_WIDGET(blist));
-#endif
-
-	/* Houston, we are go for launch. */
-	unhide_buddy_list();
+	return status;
 }
-
-void show_buddy_list()
-{
-	make_buddy_list();
-	build_edit_tree();
-	update_button_pix();
-}
--- a/src/conversation.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/conversation.c	Mon Mar 10 05:30:31 2003 +0000
@@ -1163,9 +1163,9 @@
 	name = gaim_conversation_get_name(conv);
 
 	if (((im_options & OPT_IM_ALIAS_TAB) == OPT_IM_ALIAS_TAB) &&
-		account != NULL && ((b = find_buddy(account, name)) != NULL)) {
-
-		text = get_buddy_alias(b);
+		account != NULL && ((b = gaim_find_buddy(account, name)) != NULL)) {
+
+		text = gaim_get_buddy_alias(b);
 	}
 	else
 		text = name;
@@ -1416,11 +1416,10 @@
 		!(account->gc->prpl->options & OPT_PROTO_UNIQUE_CHATNAME)) {
 
 		if (who == NULL) {
-			if ((flags & WFLAG_SEND)) {
-				b = find_buddy(account, account->gc->username);
-
-				if (b != NULL && strcmp(b->name, get_buddy_alias(b)))
-					who = get_buddy_alias(b);
+			if (flags & WFLAG_SEND) {
+				b = gaim_find_buddy(account, account->gc->username);
+				if (b != NULL && strcmp(b->name, gaim_get_buddy_alias(b)))
+					who = gaim_get_buddy_alias(b);
 				else if (*account->alias)
 					who = account->alias;
 				else if (*account->gc->displayname)
@@ -1429,19 +1428,19 @@
 					who = account->gc->username;
 			}
 			else {
-				b = find_buddy(account, gaim_conversation_get_name(conv));
+				b = gaim_find_buddy(account, gaim_conversation_get_name(conv));
 
 				if (b != NULL)
-					who = get_buddy_alias(b);
+					who = gaim_get_buddy_alias(b);
 				else
 					who = gaim_conversation_get_name(conv);
 			}
 		}
 		else {
-			b = find_buddy(account, who);
+			b = gaim_find_buddy(account, who);
 
 			if (b != NULL)
-				who = get_buddy_alias(b);
+				who = gaim_get_buddy_alias(b);
 		}
 	}
 
@@ -2116,11 +2115,11 @@
 		struct group *grp = NULL;
 		GList *wins, *convs;
 
-		b = find_buddy(gaim_conversation_get_account(conv),
+		b = gaim_find_buddy(gaim_conversation_get_account(conv),
 					   gaim_conversation_get_name(conv));
 
 		if (b != NULL)
-			grp = find_group_by_buddy(b);
+			grp = gaim_find_buddys_group(b);
 
 		/* Go through the list of IMs and find one with this group. */
 		for (wins = gaim_get_windows(); wins != NULL; wins = wins->next) {
@@ -2137,11 +2136,11 @@
 
 				conv2 = (struct gaim_conversation *)convs->data;
 
-				b2 = find_buddy(gaim_conversation_get_account(conv2),
+				b2 = gaim_find_buddy(gaim_conversation_get_account(conv2),
 								gaim_conversation_get_name(conv2));
 
 				if (b2 != NULL)
-					g2 = find_group_by_buddy(b2);
+					g2 = gaim_find_buddys_group(b2);
 
 				if (grp == g2) {
 					gaim_window_add_conversation(win2, conv);
--- a/src/core.h	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/core.h	Mon Mar 10 05:30:31 2003 +0000
@@ -50,6 +50,7 @@
 #include "multi.h"
 #include "conversation.h"
 #include "ft.h"
+#include "privacy.h"
 
 /* Really user states are controlled by the PRPLs now. We just use this for event_away */
 #define UC_UNAVAILABLE  1
@@ -157,30 +158,6 @@
 };
 #endif
 
-#define BUDDY_ALIAS_MAXLEN 388	/* because MSN names can be 387 characters */
-
-struct buddy {
-	int edittype; /* XXX CUI: this is really a GUI function and we need to put this in ui.h */
-	char name[80];
-	char alias[BUDDY_ALIAS_MAXLEN];
-	char server_alias[BUDDY_ALIAS_MAXLEN];
-	int present;
-	int evil;
-	time_t signon;
-	time_t idle;
-        int uc;
-	guint caps; /* woohoo! */
-	void *proto_data; /* what a hack */
-	struct gaim_account *account; /* the connection it belongs to */
-	GHashTable *settings;
-};
-
-struct group {
-	int edittype; /* XXX CUI: this is really a GUI function and we need to put this in ui.h */
-	char name[80];
-	GSList *members;
-};
-
 /* Globals in core.c */
 extern GSList *uis;
 extern GSList *groups;
@@ -191,32 +168,6 @@
 extern GList *probed_plugins;
 extern GList *callbacks;
 
-/* Functions in buddy.c */
-extern struct buddy *find_buddy(struct gaim_account *, const char *);
-extern struct group *find_group(const char *);
-extern struct group *find_group_by_buddy(struct buddy *);
-extern struct buddy *add_buddy(struct gaim_account *, const char *, const char *, const char *);
-extern void remove_buddy(struct buddy *);
-extern struct group *add_group(const char *);
-extern void remove_group(struct group *);
-extern void toc_build_config(struct gaim_account *, char *, int len, gboolean);
-extern void parse_toc_buddy_list(struct gaim_account *, char *);
-extern void signoff_blocked(struct gaim_connection *);
-extern char* get_buddy_alias_only(struct buddy *);
-extern char* get_buddy_alias(struct buddy *);
-extern GSList *gaim_group_get_accounts(struct group *);
-extern gboolean gaim_group_on_account(struct group *, struct gaim_account *);
-extern void do_import(struct gaim_account *, const char *);
-extern void gaim_blist_load();
-extern void gaim_blist_save();
-extern gboolean gaim_privacy_permit_add(struct gaim_account *, const char *);
-extern gboolean gaim_privacy_permit_remove(struct gaim_account *, const char *);
-extern gboolean gaim_privacy_deny_add(struct gaim_account *, const char *);
-extern gboolean gaim_privacy_deny_remove(struct gaim_account *, const char *);
-extern void gaim_buddy_set_setting(struct buddy *, const char *, const char *);
-extern char *gaim_buddy_get_setting(struct buddy *, const char *);
-
-
 /* Functions in core.c */
 extern gint UI_write(struct UI *, guchar *, int);
 extern void UI_build_write(struct UI *, guchar, guchar, ...);
--- a/src/dialogs.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/dialogs.c	Mon Mar 10 05:30:31 2003 +0000
@@ -48,6 +48,7 @@
 #include "gaim.h"
 #include "gtkimhtml.h"
 #include "prpl.h"
+#include "gtklist.h"
 
 #ifdef _WIN32
 #include "win32dep.h"
@@ -116,28 +117,6 @@
 	gboolean permit;
 };
 
-struct addbp {
-	GtkWidget *window;
-	GtkWidget *nameentry;
-	GtkWidget *messentry;
-	GtkWidget *commentry;
-	GtkWidget *command;
-	GtkWidget *sendim;
-	GtkWidget *openwindow;
-	GtkWidget *popupnotify;
-	GtkWidget *p_signon;
-	GtkWidget *p_unaway;
-	GtkWidget *p_unidle;
-	GtkWidget *p_typing;
-	GtkWidget *save;
-	GtkWidget *menu;
-	GtkWidget *sound;
-	GtkWidget *soundentry;
-
-	struct gaim_account *account;
-	struct buddy_pounce *buddy_pounce;
-};
-
 struct findbyemail {
 	GtkWidget *window;
 	GtkWidget *emailentry;
@@ -440,18 +419,18 @@
 
 void do_remove_buddy(struct buddy *b)
 {
-	struct group *g = find_group_by_buddy(b);
+	struct group *g = gaim_find_buddys_group(b);
 	struct gaim_conversation *c;
 	gchar *name = g_strdup(b->name); /* b->name is null after remove_buddy */
 
 	if (!b)
 		return;
 
-	g = find_group_by_buddy(b);
+	g = gaim_find_buddys_group(b);
 
 	debug_printf(_("Removing '%s' from buddy list.\n"), b->name);
 	serv_remove_buddy(b->account->gc, name, g->name);
-	remove_buddy(b);
+	gaim_blist_remove_buddy(b);
 	gaim_blist_save();
 
 	c = gaim_find_conversation(name);
@@ -464,7 +443,7 @@
 
 void show_confirm_del(struct gaim_connection *gc, gchar *name)
 {
-	struct buddy *bd = find_buddy(gc->account, name);
+	struct buddy *bd = gaim_find_buddy(gc->account, name);
 	char *text;
 	if (!bd)
 		return;
@@ -639,7 +618,7 @@
 		gtk_label_set_markup(GTK_LABEL(label), 
 				     "<span weight=\"bold\" size=\"large\" foreground=\"gray\">I'm not anything.</span>");
 	
-	window = gtk_dialog_new_with_buttons("", GTK_WINDOW(blist), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+	window = gtk_dialog_new_with_buttons("", GTK_WINDOW(gtkblist->window), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
 	gtk_dialog_set_default_response (GTK_DIALOG(window), GTK_RESPONSE_OK);
 	g_signal_connect(G_OBJECT(window), "response", G_CALLBACK(gtk_widget_destroy), NULL);
 	
@@ -689,7 +668,7 @@
 	if (!imdialog) {
 		info = g_new0(struct getuserinfo, 1);
 		info->gc = connections->data;
-		imdialog = gtk_dialog_new_with_buttons(_("Gaim - New Message"), blist ? GTK_WINDOW(blist) : NULL, GTK_DIALOG_MODAL,
+		imdialog = gtk_dialog_new_with_buttons(_("New Message"), gtkblist ? GTK_WINDOW(gtkblist->window) : NULL, GTK_DIALOG_MODAL,
 						       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
 		gtk_dialog_set_default_response (GTK_DIALOG(imdialog), GTK_RESPONSE_OK);
 		gtk_container_set_border_width (GTK_CONTAINER(imdialog), 6);
@@ -790,7 +769,7 @@
 	g_free(filename);
 	info->gc = connections->data;
 
-	window = gtk_dialog_new_with_buttons(_("Gaim - Get User Info"), blist ? GTK_WINDOW(blist) : NULL, GTK_DIALOG_MODAL, 
+	window = gtk_dialog_new_with_buttons(_("Gaim - Get User Info"), gtkblist->window ? GTK_WINDOW(gtkblist->window) : NULL, GTK_DIALOG_MODAL, 
 					     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
 	gtk_dialog_set_default_response (GTK_DIALOG(window), GTK_RESPONSE_OK);
 	gtk_container_set_border_width (GTK_CONTAINER(window), 6);
@@ -885,6 +864,8 @@
 {
 	const char *grp, *who, *whoalias;
 	struct gaim_conversation *c;
+	struct buddy *b;
+	struct group *g;
 
 	if (resp == GTK_RESPONSE_OK) {
 
@@ -893,8 +874,10 @@
 		whoalias = gtk_entry_get_text(GTK_ENTRY(a->entry_for_alias));
 
 		c = gaim_find_conversation(who);
-
-		add_buddy(a->gc->account, grp, who, whoalias);
+		if (!(g = gaim_find_group(grp)))
+			g = gaim_group_new(grp);
+		b = gaim_buddy_new(a->gc->account, who, whoalias);
+		gaim_blist_add_buddy(b, g, NULL);
 		serv_add_buddy(a->gc, who);
 
 		if (c != NULL)
@@ -909,6 +892,7 @@
 void do_add_group(GtkWidget *w, int resp, struct addbuddy *a)
 {
 	const char *grp;
+	struct group *g;
 
 	if (resp == GTK_RESPONSE_OK) {
 		grp = gtk_entry_get_text(GTK_ENTRY(a->entry));
@@ -916,7 +900,8 @@
 		if (!a->gc)
 			a->gc = connections->data;
 
-		add_group(grp);
+		g = gaim_group_new(grp);
+		gaim_blist_add_group (g, NULL);
 		gaim_blist_save();
 	}
 
@@ -963,7 +948,7 @@
 	g_free(filename);
 	a->gc = gc;
 
-	a->window =  gtk_dialog_new_with_buttons(_("Gaim - Add Group"), GTK_WINDOW(blist), GTK_DIALOG_MODAL, 
+	a->window =  gtk_dialog_new_with_buttons(_("Gaim - Add Group"), GTK_WINDOW(gtkblist->window), GTK_DIALOG_MODAL, 
 						 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_ADD, GTK_RESPONSE_OK, NULL);
 	gtk_dialog_set_default_response (GTK_DIALOG(a->window), GTK_RESPONSE_OK);
 	gtk_container_set_border_width (GTK_CONTAINER(a->window), 6);
@@ -1076,7 +1061,7 @@
 	g_free(filename);
 
 	GAIM_DIALOG(a->window);
-	a->window = gtk_dialog_new_with_buttons(_("Gaim - Add Buddy"), blist ? GTK_WINDOW(blist) : NULL, GTK_DIALOG_MODAL,
+	a->window = gtk_dialog_new_with_buttons(_("Gaim - Add Buddy"), gtkblist->window ? GTK_WINDOW(gtkblist->window) : NULL, GTK_DIALOG_MODAL,
 					GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_ADD, GTK_RESPONSE_OK, NULL);
 
 	gtk_dialog_set_default_response(GTK_DIALOG(a->window), GTK_RESPONSE_OK);
@@ -1618,383 +1603,6 @@
 	
 }
 
-/*------------------------------------------------------------------------*/
-/*  The dialog for new buddy pounces                                      */
-/*------------------------------------------------------------------------*/
-
-
-void do_new_bp(GtkWidget *w, struct addbp *b)
-{
-	struct buddy_pounce *bp;
-	
-	if (strlen(gtk_entry_get_text(GTK_ENTRY(b->nameentry))) == 0) {
-		do_error_dialog(_("Please enter a buddy to pounce."), NULL, GAIM_ERROR);
-		return;
-	}
-
-        if(!b->buddy_pounce)
-		bp = g_new0(struct buddy_pounce, 1);
-	else
-		bp = b->buddy_pounce;
-
-	
-	g_snprintf(bp->name, 80, "%s", gtk_entry_get_text(GTK_ENTRY(b->nameentry)));
-	g_snprintf(bp->message, 2048, "%s", gtk_entry_get_text(GTK_ENTRY(b->messentry)));
-	g_snprintf(bp->command, 2048, "%s", gtk_entry_get_text(GTK_ENTRY(b->commentry)));
-	g_snprintf(bp->sound, 2048, "%s", gtk_entry_get_text(GTK_ENTRY(b->soundentry)));
-	g_snprintf(bp->pouncer, 80, "%s", b->account->username);
-
-	bp->protocol = b->account->protocol;
-
-	bp->options = 0;
-
-	if (GTK_TOGGLE_BUTTON(b->popupnotify)->active)
-		bp->options |= OPT_POUNCE_NOTIFY;
-
-	if (GTK_TOGGLE_BUTTON(b->openwindow)->active)
-		bp->options |= OPT_POUNCE_POPUP;
-
-	if (GTK_TOGGLE_BUTTON(b->sendim)->active)
-		bp->options |= OPT_POUNCE_SEND_IM;
-
-	if (GTK_TOGGLE_BUTTON(b->command)->active)
-		bp->options |= OPT_POUNCE_COMMAND;
-
-	if (GTK_TOGGLE_BUTTON(b->sound)->active)
-		bp->options |= OPT_POUNCE_SOUND;
-
-	if (GTK_TOGGLE_BUTTON(b->p_signon)->active)
-		bp->options |= OPT_POUNCE_SIGNON;
-
-	if (GTK_TOGGLE_BUTTON(b->p_unaway)->active)
-		bp->options |= OPT_POUNCE_UNAWAY;
-
-	if (GTK_TOGGLE_BUTTON(b->p_unidle)->active)
-		bp->options |= OPT_POUNCE_UNIDLE;
-	
-	if (GTK_TOGGLE_BUTTON(b->p_typing)->active)
-		bp->options |= OPT_POUNCE_TYPING;
-
-	if (GTK_TOGGLE_BUTTON(b->save)->active)
-		bp->options |= OPT_POUNCE_SAVE;
-
-	if(!b->buddy_pounce)
-		buddy_pounces = g_list_append(buddy_pounces, bp);
-
-	do_bp_menu();
-
-	destroy_dialog(NULL, b->window);
-
-	save_prefs();
-	g_free(b);
-}
-
-static void pounce_choose(GtkWidget *opt, struct addbp *b)
-{
-	struct gaim_account *account = g_object_get_data(G_OBJECT(opt), "gaim_account");
-	b->account = account;
-}
-
-static GtkWidget *pounce_user_menu(struct addbp *b, struct gaim_connection *gc)
-{
-	GtkWidget *optmenu;
-	GtkWidget *menu;
-	GtkWidget *opt;
-	GSList *u = gaim_accounts;
-	struct gaim_account *account;
-	struct prpl *p;
-	int count = 0;
-	int place = 0;
-	char buf[2048];
-
-
-	optmenu = gtk_option_menu_new();
-
-	menu = gtk_menu_new();
-
-	while (u) {
-		account = (struct gaim_account *)u->data;
-		p = (struct prpl *)find_prpl(account->protocol);
-		g_snprintf(buf, sizeof buf, "%s (%s)", account->username, (p && p->name)?p->name:_("Unknown"));
-		opt = gtk_menu_item_new_with_label(buf);
-		g_object_set_data(G_OBJECT(opt), "gaim_account", account);
-		g_signal_connect(GTK_OBJECT(opt), "activate", G_CALLBACK(pounce_choose), b);
-		gtk_menu_shell_append(GTK_MENU_SHELL(menu), opt);
-		gtk_widget_show(opt);
-
-		if (b->account == account) {
-			gtk_menu_item_activate(GTK_MENU_ITEM(opt));
-			place = count;
-		}
-
-		count++;
-
-		u = u->next;
-	}
-
-	gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu);
-	gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), place);
-
-	b->menu = optmenu;
-
-	return optmenu;
-}
-
-
-void show_new_bp(char *name, struct gaim_connection *gc, int idle, int away, struct buddy_pounce *edit_bp)
-{
-	GtkWidget *label;
-	GtkWidget *bbox;
-	GtkWidget *vbox;
-	GtkWidget *button;
-	GtkWidget *frame;
-	GtkWidget *table;
-	GtkWidget *optmenu;
-	GtkWidget *sep;
-	GtkSizeGroup *sg;
-
-	struct addbp *b = g_new0(struct addbp, 1);
-	
-	if(edit_bp) {
-		b->buddy_pounce = edit_bp;
-		b->account = gaim_account_find(edit_bp->pouncer, edit_bp->protocol);
-	} else {
-		b->account = gc ? gc->account : gaim_accounts->data;
-		b->buddy_pounce = NULL;
-	}
-
-	GAIM_DIALOG(b->window);
-	dialogwindows = g_list_prepend(dialogwindows, b->window);
-	gtk_window_set_resizable(GTK_WINDOW(b->window), TRUE);
-	gtk_window_set_role(GTK_WINDOW(b->window), "new_bp");
-	gtk_window_set_title(GTK_WINDOW(b->window), _("Gaim - New Buddy Pounce"));
-	g_signal_connect(GTK_OBJECT(b->window), "destroy", G_CALLBACK(destroy_dialog), b->window);
-	gtk_widget_realize(b->window);
-
-	vbox = gtk_vbox_new(FALSE, 5);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
-	gtk_container_add(GTK_CONTAINER(b->window), vbox);
-	gtk_widget_show(vbox);
-
-	/* <pounce type="who"> */
-	frame = gtk_frame_new(_("Pounce Who"));
-	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
-	gtk_widget_show(GTK_WIDGET(frame));
-
-	table = gtk_table_new(2, 2, FALSE);
-	gtk_container_add(GTK_CONTAINER(frame), table);
-	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
-	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
-	gtk_table_set_row_spacings(GTK_TABLE(table), 5);
-	gtk_widget_show(table);
-
-	label = gtk_label_new(_("Account"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-	gtk_widget_show(label);
-
-	optmenu = pounce_user_menu(b, gc);
-	gtk_table_attach(GTK_TABLE(table), optmenu, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-	gtk_widget_show(optmenu);
-
-	label = gtk_label_new(_("Buddy"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
-	gtk_widget_show(label);
-
-	b->nameentry = gtk_entry_new();
-	gtk_table_attach(GTK_TABLE(table), b->nameentry, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-	if (name !=NULL)
-		gtk_entry_set_text(GTK_ENTRY(b->nameentry), name);
-	else if(edit_bp)
-		gtk_entry_set_text(GTK_ENTRY(b->nameentry), edit_bp->name);
-	gtk_window_set_focus(GTK_WINDOW(b->window), b->nameentry);
-	gtk_widget_show(b->nameentry);
-	/* </pounce type="who"> */
-
-
-	/* <pounce type="when"> */
-	frame = gtk_frame_new(_("Pounce When"));
-	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
-	gtk_widget_show(GTK_WIDGET(frame));
-
-	table = gtk_table_new(2, 2, FALSE);
-	gtk_container_add(GTK_CONTAINER(frame), table);
-	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
-	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
-	gtk_widget_show(table);
-
-	b->p_signon = gtk_check_button_new_with_label(_("Pounce on sign on"));
-	if(edit_bp)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_signon),
-		                           (edit_bp->options & OPT_POUNCE_SIGNON) ? TRUE : FALSE);
-	else
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_signon), TRUE);
-	gtk_table_attach(GTK_TABLE(table), b->p_signon, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-	gtk_widget_show(b->p_signon);
-
-	b->p_unaway = gtk_check_button_new_with_label(_("Pounce on return from away"));
-	if (away)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unaway), TRUE);
-	else if(edit_bp)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unaway),
-					   (edit_bp->options & OPT_POUNCE_UNAWAY) ? TRUE : FALSE);
-	gtk_table_attach(GTK_TABLE(table), b->p_unaway, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-	gtk_widget_show(b->p_unaway);
-
-	b->p_unidle = gtk_check_button_new_with_label(_("Pounce on return from idle"));
-	if (idle)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unidle), TRUE);
-	else if(edit_bp)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unidle),
-				           (edit_bp->options & OPT_POUNCE_UNIDLE) ? TRUE : FALSE);
-	gtk_table_attach(GTK_TABLE(table), b->p_unidle, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
-	gtk_widget_show(b->p_unidle);
-
-	b->p_typing = gtk_check_button_new_with_label(_("Pounce when buddy is typing to you"));
-	if (edit_bp)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_typing),
-					   (edit_bp->options & OPT_POUNCE_TYPING) ? TRUE : FALSE);
-	gtk_table_attach(GTK_TABLE(table), b->p_typing,1,2,1,2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-	gtk_widget_show(b->p_typing);
-
-	/* </pounce type="when"> */
-
-	/* <pounce type="action"> */
-	frame = gtk_frame_new(_("Pounce Action"));
-	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
-	gtk_widget_show(GTK_WIDGET(frame));
-
-	table = gtk_table_new(4, 2, FALSE);
-	gtk_container_add(GTK_CONTAINER(frame), table);
-	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
-	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
-	gtk_table_set_row_spacings(GTK_TABLE(table), 5);
-	gtk_widget_show(table);
-
-	b->openwindow = gtk_check_button_new_with_label(_("Open IM Window"));
-	if(edit_bp)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->openwindow),
-			                   (edit_bp->options & OPT_POUNCE_POPUP) ? TRUE : FALSE);
-	else
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->openwindow), FALSE);
-	gtk_table_attach(GTK_TABLE(table), b->openwindow, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-	gtk_widget_show(b->openwindow);
-
-	b->popupnotify = gtk_check_button_new_with_label(_("Popup Notification"));
-	if(edit_bp)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->popupnotify),
-					   (edit_bp->options & OPT_POUNCE_NOTIFY) ? TRUE : FALSE);
-	else
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->popupnotify), FALSE);
-	gtk_table_attach(GTK_TABLE(table), b->popupnotify, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
-	gtk_widget_show(b->popupnotify);
-
-	b->sendim = gtk_check_button_new_with_label(_("Send Message"));
-	if(edit_bp)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sendim),
-					   (edit_bp->options & OPT_POUNCE_SEND_IM) ? TRUE : FALSE);
-	else
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sendim), TRUE);
-	gtk_table_attach(GTK_TABLE(table), b->sendim, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
-	gtk_widget_show(b->sendim);
-
-	b->messentry = gtk_entry_new();
-	gtk_table_attach(GTK_TABLE(table), b->messentry, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-	g_signal_connect(GTK_OBJECT(b->messentry), "activate", G_CALLBACK(do_new_bp), b);
-	if(edit_bp) {
-		gtk_widget_set_sensitive(GTK_WIDGET(b->messentry),
-					(edit_bp->options & OPT_POUNCE_SEND_IM) ? TRUE : FALSE);
-		gtk_entry_set_text(GTK_ENTRY(b->messentry), edit_bp->message);
-	}
-	gtk_widget_show(b->messentry);
-
-	g_signal_connect(GTK_OBJECT(b->sendim), "clicked",
-					 G_CALLBACK(gaim_gtk_toggle_sensitive), b->messentry);
-
-	b->command = gtk_check_button_new_with_label(_("Execute command on pounce"));
-	gtk_table_attach(GTK_TABLE(table), b->command, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
-	if(edit_bp)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->command),
-					   (edit_bp->options & OPT_POUNCE_COMMAND) ? TRUE : FALSE);
-	else
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->command), FALSE);
-	gtk_widget_show(b->command);
-
-	b->commentry = gtk_entry_new();
-	gtk_table_attach(GTK_TABLE(table), b->commentry, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-	g_signal_connect(GTK_OBJECT(b->commentry), "activate", G_CALLBACK(do_new_bp), b);
-	if(edit_bp) {
-		gtk_widget_set_sensitive(GTK_WIDGET(b->commentry), 
-					(edit_bp->options & OPT_POUNCE_COMMAND) ? TRUE : FALSE);
-		gtk_entry_set_text(GTK_ENTRY(b->commentry), edit_bp->command);
-	}
-	else
-		gtk_widget_set_sensitive(GTK_WIDGET(b->commentry), FALSE);
-	gtk_widget_show(b->commentry);
-	g_signal_connect(GTK_OBJECT(b->command), "clicked",
-					 G_CALLBACK(gaim_gtk_toggle_sensitive), b->commentry);
-
-	b->sound = gtk_check_button_new_with_label(_("Play sound on pounce"));
-	if(edit_bp)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sound),
-					   (edit_bp->options & OPT_POUNCE_SOUND) ? TRUE : FALSE);
-	else
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sound), FALSE);
-	gtk_table_attach(GTK_TABLE(table), b->sound, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
-	gtk_widget_show(b->sound);
-
-	b->soundentry = gtk_entry_new();
-	gtk_table_attach(GTK_TABLE(table), b->soundentry, 1, 2, 3, 4, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-	g_signal_connect(GTK_OBJECT(b->soundentry), "activate", G_CALLBACK(do_new_bp), b);
-	if(edit_bp) {
-		gtk_widget_set_sensitive(GTK_WIDGET(b->soundentry), 
-					(edit_bp->options & OPT_POUNCE_SOUND) ? TRUE : FALSE);
-		gtk_entry_set_text(GTK_ENTRY(b->soundentry), edit_bp->sound);
-	} else 
-		gtk_widget_set_sensitive(GTK_WIDGET(b->soundentry), FALSE);
-	gtk_widget_show(b->soundentry);
-	g_signal_connect(GTK_OBJECT(b->sound), "clicked",
-					 G_CALLBACK(gaim_gtk_toggle_sensitive), b->soundentry);
-	/* </pounce type="action"> */
-
-	b->save = gtk_check_button_new_with_label(_("Save this pounce after activation"));
-	gtk_container_set_border_width(GTK_CONTAINER(b->save), 7);
-	if(edit_bp)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->save),
-					   (edit_bp->options & OPT_POUNCE_SAVE) ? TRUE : FALSE);
-	else
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->save), FALSE);
-	gtk_box_pack_start(GTK_BOX(vbox), b->save, FALSE, FALSE, 0);
-	gtk_widget_show(b->save);
-
-	sep = gtk_hseparator_new();
-	gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
-	gtk_widget_show(sep);
-	
-	bbox = gtk_hbox_new(FALSE, 5);
-	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
-	gtk_widget_show(bbox);
-
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-
-	button = gaim_pixbuf_button_from_stock(_("_Save"), "gtk-execute", GAIM_BUTTON_HORIZONTAL);
-	gtk_size_group_add_widget(sg, button);
-	g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(do_new_bp), b);
-	gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, FALSE, 0);
-	gtk_widget_show(button);
-
-	button = gaim_pixbuf_button_from_stock(_("C_ancel"), "gtk-cancel", GAIM_BUTTON_HORIZONTAL);
-	gtk_size_group_add_widget(sg, button);
-	g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(destroy_dialog), b->window);
-	gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, FALSE, 0);
-	gtk_widget_show(button);
-
-
-	gtk_widget_show(b->window);
-}
-
-
 
 /*------------------------------------------------------------------------*/
 /*  The dialog for SET INFO / SET DIR INFO                                */
@@ -3379,100 +2987,6 @@
 }
 
 /*------------------------------------------------------------------------*/
-/*  The dialog for import/export                                          */
-/*------------------------------------------------------------------------*/
-
-static void do_import_dialog(GtkWidget *w, gpointer data)
-{
-	const char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(importdialog));
-	if (file_is_dir(file, importdialog)) {
-		return;
-	}
-	if (g_slist_find(connections, importgc)) {
-		do_import(importgc->account, file);
-		gaim_blist_save();
-	}
-	destroy_dialog(NULL, importdialog);
-}
-
-static void set_import_gc(gpointer data, struct gaim_connection *gc)
-{
-	importgc = gc;
-}
-
-static void create_import_dropdown(GtkFileSelection *fs)
-{
-	GtkWidget *hbox;
-	GtkWidget *label;
-	GSList *g = connections;
-	struct gaim_connection *c;
-	GtkWidget *optmenu;
-	GtkWidget *menu;
-	char buf[256];
-	GtkWidget *opt;
-
-	if (!connections)
-		return;
-	importgc = connections->data;
-	if (!connections->next)
-		return;
-
-	hbox = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_end(GTK_BOX(fs->action_area), hbox, FALSE, FALSE, 0);
-	gtk_widget_show(hbox);
-
-	optmenu = gtk_option_menu_new();
-	gtk_box_pack_end(GTK_BOX(hbox), optmenu, FALSE, FALSE, 5);
-	gtk_widget_show(optmenu);
-
-	label = gtk_label_new(_("Import to:"));
-	gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 5);
-	gtk_widget_show(label);
-
-	menu = gtk_menu_new();
-
-	while (g) {
-		c = (struct gaim_connection *)g->data;
-		g_snprintf(buf, sizeof buf, "%s (%s)", c->username, c->prpl->name);
-		opt = gtk_menu_item_new_with_label(buf);
-		g_signal_connect(GTK_OBJECT(opt), "activate", G_CALLBACK(set_import_gc), c);
-		gtk_widget_show(opt);
-		gtk_menu_shell_append(GTK_MENU_SHELL(menu), opt);
-		g = g->next;
-	}
-
-	gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu);
-	gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), 0);
-}
-
-void show_import_dialog()
-{
-	char *buf = g_malloc(BUF_LEN);
-	if (!importdialog) {
-		importdialog = gtk_file_selection_new(_("Gaim - Import Buddy List"));
-
-		gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(importdialog));
-
-		g_snprintf(buf, BUF_LEN - 1, "%s" G_DIR_SEPARATOR_S, gaim_home_dir());
-
-		gtk_file_selection_set_filename(GTK_FILE_SELECTION(importdialog), buf);
-		g_signal_connect(GTK_OBJECT(importdialog), "destroy",
-				   G_CALLBACK(destroy_dialog), importdialog);
-
-		g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(importdialog)->ok_button),
-				   "clicked", G_CALLBACK(do_import_dialog), NULL);
-		g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(importdialog)->cancel_button),
-				   "clicked", G_CALLBACK(destroy_dialog), importdialog);
-
-		create_import_dropdown(GTK_FILE_SELECTION(importdialog));
-	}
-
-	g_free(buf);
-	gtk_widget_show(importdialog);
-	gdk_window_raise(importdialog->window);
-}
-
-/*------------------------------------------------------------------------*/
 /*  The dialog for new away messages                                      */
 /*------------------------------------------------------------------------*/
 
@@ -3811,7 +3325,7 @@
 		g_snprintf(b->alias, sizeof(b->alias), "%s", al);
 	else
 		b->alias[0] = '\0';
-	handle_buddy_rename(b, b->name);
+	gaim_blist_alias_buddy (b, al);
 	serv_alias_buddy(b);
 	gaim_blist_save();
 	destroy_dialog(aliasdlg, aliasdlg);
@@ -4363,11 +3877,10 @@
 		if (new_name && (strlen(new_name) != 0) && strcmp(new_name, g->name)) {
 			char *prevname;
 	
-			if ((orig = find_group(new_name)) != NULL && g_strcasecmp(new_name, g->name)) {
+			if ((orig = gaim_find_group(new_name)) != NULL && g_strcasecmp(new_name, g->name)) {
 				orig->members = g_slist_concat(orig->members, g->members);
-				handle_group_rename(orig, g->name);
+				gaim_blist_rename_group(orig, g->name);
 				groups = g_slist_remove(groups, g);
-				/* FIXME, i don't like calling this. it's sloppy. */ build_edit_tree();
 				accts = gaim_group_get_accounts(g);
 				while(accts) {
 					struct gaim_account *account = accts->data;
@@ -4384,8 +3897,7 @@
 					accts = g_slist_remove(accts, accts->data);
 				}
 				g_snprintf(g->name, sizeof(g->name), "%s", new_name);
-				handle_group_rename(g, prevname);
-				/* FIXME, i don't like calling this. it's sloppy. */ build_edit_tree();
+				gaim_blist_rename_group(g, prevname);
 				g_free(prevname);
 			}
 			gaim_blist_save();
@@ -4406,7 +3918,7 @@
 	g_free(filename);
 
 	if (!rename_dialog) {
-		rename_dialog =  gtk_dialog_new_with_buttons(_("Gaim - Rename Group"), GTK_WINDOW(blist), GTK_DIALOG_MODAL,
+		rename_dialog =  gtk_dialog_new_with_buttons(_("Rename Group"), GTK_WINDOW(gtkblist->window), GTK_DIALOG_MODAL, 
 						 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
 		gtk_dialog_set_default_response (GTK_DIALOG(rename_dialog), GTK_RESPONSE_OK);
 		gtk_container_set_border_width (GTK_CONTAINER(rename_dialog), 6);
@@ -4483,13 +3995,13 @@
 	}
 
 	if (new_name && (strlen(new_name) != 0) && strcmp(new_name, b->name)) {
-		struct group *g = find_group_by_buddy(b);
+		struct group *g = gaim_find_buddys_group(b);
 		char *prevname = g_strdup(b->name);
 		if (g)
 			serv_remove_buddy(b->account->gc, b->name, g->name);
 		g_snprintf(b->name, sizeof(b->name), "%s", new_name);
 		serv_add_buddy(b->account->gc, b->name);
-		handle_buddy_rename(b, prevname);
+		gaim_blist_rename_buddy(b, prevname);
 		gaim_blist_save();
 		g_free(prevname);
 	}
--- a/src/gaim.h	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/gaim.h	Mon Mar 10 05:30:31 2003 +0000
@@ -28,6 +28,7 @@
 
 #include "core.h"
 #include "ui.h"
+#include "list.h"
 
 #define XPATCH BAD /* Because Kalla Said So */
 
@@ -236,6 +237,7 @@
 #define OPT_BLIST_GREY_IDLERS		0x00000400
 #define OPT_BLIST_BOTTOM_TAB		0X00000800
 #define OPT_BLIST_POPUP                 0x00001000
+#define OPT_BLIST_SHOW_ICONS            0x00002000 
 
 extern guint convo_options;
 #define OPT_CONVO_ENTER_SENDS		0x00000001
@@ -340,9 +342,6 @@
 
 /* Functions in buddy.c */
 extern void signoff(struct gaim_connection *);
-extern void do_pounce(struct gaim_connection *, char *, int);
-void create_prpl_icon(GtkWidget *widget, struct gaim_connection *gc,
-					  GdkPixmap **pixmap, GdkBitmap **mask);
 
 /* Functions in buddy_chat.c */
 #if 0
--- a/src/gtkconv.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/gtkconv.c	Mon Mar 10 05:30:31 2003 +0000
@@ -447,7 +447,7 @@
 
 	gc   = gaim_conversation_get_gc(conv);
 	name = gaim_conversation_get_name(conv);
-	b    = find_buddy(gc->account, name);
+	b    = gaim_find_buddy(gc->account, name);
 
 	if (b != NULL)
 		show_confirm_del(gc, (char *)name);
@@ -656,7 +656,7 @@
 
 	gc   = gaim_conversation_get_gc(conv);
 	name = g_object_get_data(G_OBJECT(w), "user_data");
-	b    = find_buddy(gc->account, name);
+	b    = gaim_find_buddy(gc->account, name);
 
 	if (b != NULL)
 		show_confirm_del(gc, name);
@@ -764,7 +764,7 @@
 
 		/* Added by Jonas <jonas@birme.se> */
 		if (gc) {
-			if (find_buddy(gc->account, who))
+			if (gaim_find_buddy(gc->account, who))
 				button = gtk_menu_item_new_with_label(_("Remove"));
 			else
 				button = gtk_menu_item_new_with_label(_("Add"));
@@ -2530,7 +2530,7 @@
 	/* Now, um, just kind of all over the place. Huh? */
 
 	/* Add button */
-	if (find_buddy(gaim_conversation_get_account(conv),
+	if (gaim_find_buddy(gaim_conversation_get_gc(conv),
 				   gaim_conversation_get_name(conv)) == NULL) {
 		gtkim->add = gaim_gtk_change_text(_("Add"), gtkim->add,
 										  GTK_STOCK_ADD, type);
@@ -3566,7 +3566,7 @@
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	parent  = gtk_widget_get_parent(gtkconv->u.im->add);
 
-	if (find_buddy(gc->account, gaim_conversation_get_name(conv))) {
+	if (gaim_find_buddy(gc->account, gaim_conversation_get_name(conv))) {
 		gtkconv->u.im->add =
 			gaim_gtk_change_text(_("Remove"), gtkconv->u.im->add,
 								 GTK_STOCK_REMOVE, type);
--- a/src/gtkft.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/gtkft.c	Mon Mar 10 05:30:31 2003 +0000
@@ -567,7 +567,7 @@
 	gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE);
 	gtk_window_set_default_size(GTK_WINDOW(window), 390, 400);
 #endif
-	gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
+	//gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
 	gtk_container_set_border_width(GTK_CONTAINER(window), 12);
 	gtk_widget_realize(window);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gtklist.h	Mon Mar 10 05:30:31 2003 +0000
@@ -0,0 +1,79 @@
+/**
+ * @file gtklist.h GTK+ Buddy List API
+ *
+ * gaim
+ *
+ * Copyright (C) 2002-2003, Sean Egan <sean.egan@binghamton.edu>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _GAIM_GTK_LIST_H_
+#define _GAIM_GTK_LIST_H_
+extern GtkWidget *blist;
+
+enum {
+	STATUS_ICON_COLUMN,
+	NAME_COLUMN,
+	WARNING_COLUMN,
+	IDLE_COLUMN,
+	BUDDY_ICON_COLUMN,
+	NODE_COLUMN,
+	BLIST_COLUMNS
+	};
+
+/**************************************************************************
+ * @name Structures
+ **************************************************************************/
+/**
+ * Like, everything you need to know about the gtk buddy list
+ */
+struct gaim_gtk_buddy_list {
+	GtkWidget *window;
+	GtkWidget *vbox;                /**< This is the vbox that everything gets packed into.  Your plugin might
+					   want to pack something in it itself.  Go, plugins! */
+
+	GtkWidget *treeview;            /**< It's a treeview... d'uh. */
+	GtkTreeStore *treemodel;        /**< This is the treemodel.  */
+			
+	GtkWidget *bbox;                /**< A Button Box. */
+};
+struct gaim_gtk_buddy_list *gtkblist;
+
+
+/**************************************************************************
+ * @name GTK+ Conversation API
+ **************************************************************************/
+/**
+ * Returns the UI operations structure for the buddy list.
+ *
+ * @return The GTK list operations structure.
+ */
+struct gaim_blist_ui_ops *gaim_get_gtk_blist_ui_ops(void);
+
+/**
+ * Returns the base image to represent the account, based on the currently selected theme
+ *
+ * @param account  The account.
+ * 
+ * @return         The icon
+ */
+GdkPixbuf *create_prpl_icon(struct gaim_account *account);
+
+
+void gaim_gtk_blist_refresh(struct gaim_buddy_list *list);
+
+#endif /* _GAIM_GTK_LIST_H_ */
--- a/src/gtkutils.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/gtkutils.c	Mon Mar 10 05:30:31 2003 +0000
@@ -390,3 +390,11 @@
 	gtk_widget_set_sensitive(to_toggle, !sensitivity);
 }
 
+void gaim_separator(GtkWidget *menu)
+{
+	GtkWidget *menuitem;
+
+	menuitem = gtk_separator_menu_item_new();
+	gtk_widget_show(menuitem);
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+}
--- a/src/gtkutils.h	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/gtkutils.h	Mon Mar 10 05:30:31 2003 +0000
@@ -108,4 +108,11 @@
  */
 void gaim_gtk_toggle_sensitive(GtkWidget *widget, GtkWidget *to_toggle);
 
+/**
+ * Adds a seperator to a menu.
+ *
+ * @param menu   The menu to add a seperator to.
+ */
+void gaim_separator(GtkWidget *menu);
+
 #endif /* _GAIM_GTK_UTILS_H_ */
--- a/src/idle.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/idle.c	Mon Mar 10 05:30:31 2003 +0000
@@ -54,9 +54,6 @@
 #endif
 	int idle_time;
 
-	/* Not idle, really...  :) */
-	update_idle_times();
-
 	plugin_event(event_blist_update);
 
 	time(&t);
--- a/src/list.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/list.c	Mon Mar 10 05:30:31 2003 +0000
@@ -1,6 +1,7 @@
 /*
  * gaim
  *
+ * Copyright (C) 2003,      Sean Egan    <sean.egan@binghamton.edu>
  * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -34,6 +35,7 @@
 #include <ctype.h>
 #include "gaim.h"
 #include "prpl.h"
+#include "list.h"
 
 #ifdef _WIN32
 #include "win32dep.h"
@@ -41,204 +43,343 @@
 
 #define PATHSIZE 1024
 
-void remove_buddy(struct buddy *rem_b)
-{
-	if(rem_b->account->gc) {
-		struct group *rem_g = find_group_by_buddy(rem_b);
-
-		ui_remove_buddy(rem_b);
-
-		rem_g->members = g_slist_remove(rem_g->members, rem_b);
+struct gaim_buddy_list *gaimbuddylist = NULL;
+static struct gaim_blist_ui_ops *blist_ui_ops = NULL;
 
-		g_hash_table_destroy(rem_b->settings);
+/*****************************************************************************
+ * Private Utility functions                                                 *
+ *****************************************************************************/
+static GaimBlistNode *gaim_blist_get_last_sibling(GaimBlistNode *node)
+{
+	GaimBlistNode *n = node;
+	if (!n)
+		return NULL;
+	while (n->next)
+		n = n->next;
+	return n;
+}
+static GaimBlistNode *gaim_blist_get_last_child(GaimBlistNode *node)
+{
+	if (!node)
+		return NULL;
+	return gaim_blist_get_last_sibling(node->child);
+}
 
-		g_free(rem_b);
-	} else {
-		char *buf = g_strdup_printf(_("%s was not removed from your buddy "
-					"list, because your account (%s) is not logged in."),
-					rem_b->name, rem_b->account->username);
-		do_error_dialog(_("Buddy Not Removed"), buf, GAIM_ERROR);
-		g_free(buf);
+static void gaim_blist_print()
+{
+	GaimBlistNode *group = gaimbuddylist->root;
+	GaimBlistNode *buddy;
+	if (!gaimbuddylist)
+		return;
+	while (group) {
+		debug_printf("+-%s %d\n", ((struct group*)group)->name, group);
+		buddy = group->child;
+		while (buddy) {
+			debug_printf("|--- %d %s\t\t%d\n", ((struct buddy*)buddy)->present, ((struct buddy*)buddy)->name, ((struct buddy*)buddy)->idle);
+			buddy = buddy->next;
+		}
+		group = group->next;
 	}
 }
 
-void remove_group(struct group *rem_g)
-{
-	GSList *accounts;
-
-	for(accounts = gaim_accounts; accounts; accounts = accounts->next) {
-		struct gaim_account *account = accounts->data;
-		if(account->gc) {
-			GList *tmp = NULL;
-			GSList *buds = rem_g->members;
+/*****************************************************************************
+ * Public API functions                                                      *
+ *****************************************************************************/
 
-			while (buds) {
-				struct buddy *delb = (struct buddy *)buds->data;
-				buds = buds->next;
+struct gaim_buddy_list *gaim_blist_new()
+{
+	struct gaim_buddy_list *gbl = g_new0(struct gaim_buddy_list, 1);
+	gbl->ui_ops = blist_ui_ops;
+	return gbl;
+}
 
-				if(delb->account == account) {
-					tmp = g_list_append(tmp, g_strdup(delb->name));
-					remove_buddy(delb);	/* this should take care of removing
-										   the group_show if necessary */
-				}
-			}
-
-			if(tmp)
-				serv_remove_buddies(account->gc, tmp, rem_g->name);
+void  gaim_blist_show () 
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	if (ops)
+		ops->show(gaimbuddylist);
+}
 
-			while (tmp) {
-				g_free(tmp->data);
-				tmp = g_list_remove(tmp, tmp->data);
-			}
-		}
-	}
+void gaim_blist_destroy()
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	GaimBlistNode *node = gaimbuddylist->root;
+	if (ops)
+		ops->destroy(gaimbuddylist);
+}
 
-	if(rem_g->members) {
-		char *buf = g_strdup_printf(_("%d buddies from group %s were not "
-					"removed because their accounts were not logged in.  These "
-					"buddies, and the group were not removed.\n"),
-				g_slist_length(rem_g->members), rem_g->name);
-		do_error_dialog(_("Group Not Removed"), buf, GAIM_ERROR);
-		g_free(buf);
+void  gaim_blist_set_visible (gboolean show)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	if (ops)
+		ops->set_visible(gaimbuddylist, show);
+}
 
-		return;
-	}
-
-	ui_remove_group(rem_g);
-
-	groups = g_slist_remove(groups, rem_g);
-
-	g_free(rem_g);
-
-	/* don't flush buddy list to cache in order to be consistent with remove_buddy,
-	 * mostly. remove_group is only called from one place, so we'll let it handle it. */
+void  gaim_blist_update_buddy_status (struct buddy *buddy, int status)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	buddy->uc = status;
+	if (ops)
+		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
 }
 
-struct buddy *add_buddy(struct gaim_account *account, const char *group, const char *buddy, const char *show)
-{
-	struct buddy *b;
-	struct group *g;
-	const char *good;
-
-	if ((b = find_buddy(account, buddy)) != NULL)
-		return b;
+void gaim_blist_update_buddy_presence(struct buddy *buddy, int presence) {
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	if (!buddy->present && presence)
+		buddy->present = 2;
+	else if (buddy->present != 2)
+		buddy->present = presence;
+	if (ops)
+		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+}
 
-	g = find_group(group);
-
-	if (g == NULL)
-		g = add_group(group);
-
-	b = (struct buddy *)g_new0(struct buddy, 1);
-
-	if (!b)
-		return NULL;
 
+void  gaim_blist_update_buddy_idle (struct buddy *buddy, int idle)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	buddy->idle = idle;
+	if (ops)
+		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+}
+void  gaim_blist_update_buddy_evil (struct buddy *buddy, int warning)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	buddy->evil = warning;
+	if (ops)
+		ops->update(gaimbuddylist,(GaimBlistNode*)buddy);
+}
+void  gaim_blist_rename_buddy (struct buddy *buddy, const char *name)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+       	g_free(buddy->name);
+	buddy->name = g_strdup(name);
+	if (ops)
+		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+}
+void  gaim_blist_alias_buddy (struct buddy *buddy, const char *alias)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	g_free(buddy->alias);
+	buddy->alias = g_strdup(alias);
+	if (ops)
+		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+}
+void gaim_blist_rename_group(struct group *group, const char *name)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	g_free(group->name);
+	group->name = g_strdup(name);
+	if (ops)
+		ops->update(gaimbuddylist, (GaimBlistNode*)group);
+}
+struct buddy *gaim_buddy_new(struct gaim_account *account, const char *screenname, const char *alias)
+{
+	struct buddy *b = g_new0(struct buddy, 1);
 	b->account = account;
-	b->present = 0;
-
+	b->name  = g_strdup(screenname);
+	b->alias = g_strdup(alias);
 	b->settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-
-	good = buddy;
-
-	g_snprintf(b->name, sizeof(b->name), "%s", good);
-	if(show && show[0])
-		g_snprintf(b->alias, sizeof(b->alias), "%s", show);
-	else
-		b->alias[0] = '\0';
-
-	g->members = g_slist_append(g->members, b);
-
-	b->idle = 0;
-	b->caps = 0;
-
-	ui_add_buddy(account->gc, g, b);
+	((GaimBlistNode*)b)->type = GAIM_BLIST_BUDDY_NODE;
 
 	return b;
 }
-
-struct group *add_group(const char *group)
+void  gaim_blist_add_buddy (struct buddy *buddy, struct group *group, GaimBlistNode *node)
 {
-	struct group *g = find_group(group);
-	if (g)
-		return g;
-	g = (struct group *)g_new0(struct group, 1);
-	if (!g)
-		return NULL;
+	GaimBlistNode *n = node, *node2, *node3;
+	struct group *g = group;
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	if (!n) {
+		if (!g) {
+			g = gaim_group_new(_("Buddies"));
+			gaim_blist_add_group(g, NULL);
+		}
+		n = gaim_blist_get_last_child((GaimBlistNode*)g);
+	}
+
+	node2 = ((GaimBlistNode*)buddy)->next;
+	node3 = ((GaimBlistNode*)buddy)->prev;
+	
+	if (node2)
+		node2->prev = node3;
+	if (node3)
+		node3->next = node2;
 
-	strncpy(g->name, group, sizeof(g->name));
-	groups = g_slist_append(groups, g);
+	if (n) {
+		((GaimBlistNode*)buddy)->next = n->next;
+		((GaimBlistNode*)buddy)->prev = n;
+		((GaimBlistNode*)buddy)->parent = n->parent;
+		n->next = (GaimBlistNode*)buddy;
+	} else {
+		((GaimBlistNode*)g)->child = (GaimBlistNode*)buddy;
+		((GaimBlistNode*)buddy)->next = NULL;
+		((GaimBlistNode*)buddy)->prev = NULL;
+		((GaimBlistNode*)buddy)->parent = (GaimBlistNode*)g;
+	}
 
-	g->members = NULL;
+	g->members = g_slist_append(g->members, buddy);
+	
+	if (ops)
+		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+}
 
-	ui_add_group(g);
+struct group *gaim_group_new(const char *name)
+{
+	struct group *g = gaim_find_group(name);
+	if (!g) {
+		g= g_new0(struct group, 1);
+		g->name = g_strdup(name);
+		((GaimBlistNode*)g)->type = GAIM_BLIST_GROUP_NODE;
 
+	}
 	return g;
 }
 
-struct group *find_group(const char *group)
+void  gaim_blist_add_group (struct group *group, GaimBlistNode *node)
 {
-	struct group *g;
-	GSList *grp;
-	char *grpname = g_strdup(normalize(group));
+	struct gaim_blist_ui_ops *ops;
+
+	if (!gaimbuddylist)
+		gaimbuddylist = gaim_blist_new();
+	ops = gaimbuddylist->ui_ops;
+	
+	if (!gaimbuddylist->root) {
+		gaimbuddylist->root = (GaimBlistNode*)group;
+		return;
+	}
+	
+	if (gaim_find_group(group->name))
+		return;
+
+	if (!node) 
+		node = gaim_blist_get_last_sibling(gaimbuddylist->root);
 
-	grp = groups;
-	while (grp) {
-		g = (struct group *)grp->data;
-		if (!g_strcasecmp(normalize (g->name), grpname)) {
-			g_free(grpname);
-			return g;
-		}
-		grp = g_slist_next(grp);
-	}
-	g_free(grpname);
-	return NULL;
+	((GaimBlistNode*)group)->next = node ? node->next : NULL;
+	((GaimBlistNode*)group)->prev = node;
+	node->next = (GaimBlistNode*)group;
+
+	if (ops)
+		ops->update(gaimbuddylist, (GaimBlistNode*)group);
+}
+
+void  gaim_blist_remove_buddy (struct buddy *buddy)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+
+	GaimBlistNode *node = (GaimBlistNode*)buddy;
+	
+	if (node->prev)
+		node->prev->next = node->next;
+	if (node->next)
+		node->next->prev = node->prev;
+	
+	ops->remove(gaimbuddylist, node);
+	g_free(buddy->name);
+	g_free(buddy->alias);
+	g_free(buddy);
 }
 
-struct group *find_group_by_buddy(struct buddy *b)
+void  gaim_blist_remove_group (struct group *group)
 {
-	GSList *grp = groups;
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	GaimBlistNode *node = (GaimBlistNode*)group;
+	GaimBlistNode *child = node->child;
+	while (child) {
+		GaimBlistNode *n = child;
+		child = child->next;
+		gaim_blist_remove_buddy((struct buddy*)n);
+	}
+	ops->remove(gaimbuddylist, node);
+	g_free(group->name);
+	g_free(group);
+}
 
-	while(grp) {
-		struct group *g = grp->data;
-		if(g_slist_find(g->members, b))
-			return g;
-		grp = grp->next;
+char *gaim_get_buddy_alias_only(struct buddy *b) {
+        if(!b)
+                return NULL;
+        if(b->alias && b->alias[0])
+                return b->alias;
+        else if((misc_options & OPT_MISC_USE_SERVER_ALIAS) && b->server_alias)
+                return b->server_alias;
+        return NULL;
+}
+
+char *  gaim_get_buddy_alias (struct buddy *buddy)
+{
+	char *ret = gaim_get_buddy_alias_only(buddy);
+        if(!ret)
+                return buddy ? buddy->name : _("Unknown");
+        return ret;
+
+}
+
+struct buddy *gaim_find_buddy(struct gaim_account *account, const char *name)
+{
+	GaimBlistNode *group = gaimbuddylist->root;
+	GaimBlistNode *buddy;
+	if (!gaimbuddylist)
+		return NULL;
+	while (group) {
+		buddy = group->child;
+		while (buddy) {
+			if (!g_strcasecmp(((struct buddy*)buddy)->name, name) && account == ((struct buddy*)buddy)->account)
+				return (struct buddy*)buddy;
+			buddy = buddy->next;
+		}
+		group = group->next;
 	}
 	return NULL;
 }
 
-struct buddy *find_buddy(struct gaim_account *account, const char *who)
+struct group *gaim_find_group(const char *name)
 {
-	struct group *g;
-	struct buddy *b;
-	GSList *grp;
-	GSList *mem;
-	char *whoname = NULL;
-	char *(*norm)(const char *);
-
-	grp = groups;
-	while (grp) {
-		g = (struct group *)grp->data;
-
-		mem = g->members;
-		while (mem) {
-			b = (struct buddy *)mem->data;
-			/*
-			norm = (b->user->gc && b->user->gc->prpl->normalize) ? b->user->gc->prpl->normalize : normalize;
-			*/
-			norm = normalize;
-			whoname = g_strdup(norm(who));
-			if ((b->account == account || !account) && !strcmp(norm(b->name), whoname)) {
-				g_free(whoname);
-				return b;
-			}
-			g_free(whoname);
-			mem = mem->next;
-		}
-		grp = g_slist_next(grp);
+	GaimBlistNode *node;
+	if (!gaimbuddylist)
+		return NULL;
+	node = gaimbuddylist->root;
+	while(node) {
+		if (!strcmp(((struct group*)node)->name, name))
+			return (struct group*)node;
+		node = node->next;
 	}
 	return NULL;
 }
+struct group *gaim_find_buddys_group(struct buddy *buddy)
+{
+	return (struct group*)(((GaimBlistNode*)buddy)->parent);
+}
+
+GSList *gaim_group_get_accounts(struct group *g)
+{
+	GSList *l = NULL;
+	GaimBlistNode *child = ((GaimBlistNode *)g)->child;
+
+	while (child) {
+		if (!g_slist_find(l, ((struct buddy*)child)->account))
+			l = g_slist_append(l, ((struct buddy*)child)->account);
+		child = child->next;
+	}
+	return l;
+}
+
+void gaim_blist_remove_account(struct gaim_account *account)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	GaimBlistNode *group = gaimbuddylist->root;
+	GaimBlistNode *buddy;
+	if (!gaimbuddylist)
+		return;
+	while (group) {
+		buddy = group->child;
+		while (buddy) {
+			if (account == ((struct buddy*)buddy)->account) {
+				((struct buddy*)buddy)->present = 0;
+				ops->remove(gaimbuddylist, buddy);
+			}
+			buddy = buddy->next;
+		}
+		group = group->next;
+	}
+}
 
 void parse_toc_buddy_list(struct gaim_account *account, char *config)
 {
@@ -265,11 +406,12 @@
 					g_strlcpy(current, utf8, sizeof(current));
 					g_free(utf8);
 				}
-				if (!find_group(current)) {
-					add_group(current);
+				if (!gaim_find_group(current)) {
+					struct group *g = gaim_group_new(current);
+					gaim_blist_add_group(g, NULL);
 				}
-			} else if (*c == 'b') { /*&& !find_buddy(user, c + 2)) {*/
-				char nm[80], sw[BUDDY_ALIAS_MAXLEN], *a, *utf8 = NULL;
+			} else if (*c == 'b') { /*&& !gaim_find_buddy(user, c + 2)) {*/
+				char nm[80], sw[388], *a, *utf8 = NULL;
 
 				if ((a = strchr(c + 2, ':')) != NULL) {
 					*a++ = '\0';		/* nul the : */
@@ -291,8 +433,10 @@
 					g_free(utf8);
 				}
 
-				if (!find_buddy(account, nm)) {
-					add_buddy(account, current, nm, sw);
+				if (!gaim_find_buddy(account, nm)) {
+					struct buddy *b = gaim_buddy_new(account, nm, sw);
+					struct group *g = gaim_find_group(current);
+					gaim_blist_add_buddy(b, g, NULL);
 					bud = g_list_append(bud, nm);
 				}
 			} else if (*c == 'p') {
@@ -321,50 +465,7 @@
 	}
 }
 
-void toc_build_config(struct gaim_account *account, char *s, int len, gboolean show)
-{
-	GSList *grp = groups;
-	GSList *mem;
-	struct group *g;
-	struct buddy *b;
-	GSList *plist = account->permit;
-	GSList *dlist = account->deny;
-
-	int pos = 0;
-
-	if (!account->permdeny)
-		account->permdeny = 1;
-
-	pos += g_snprintf(&s[pos], len - pos, "m %d\n", account->permdeny);
-	while (len > pos && grp) {
-		g = (struct group *)grp->data;
-		if(gaim_group_on_account(g, account)) {
-			pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name);
-			mem = g->members;
-			while (len > pos && mem) {
-				b = (struct buddy *)mem->data;
-				if(b->account == account) {
-					pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", b->name,
-							(show && b->alias[0]) ? ":" : "",
-							(show && b->alias[0]) ? b->alias : "");
-				}
-				mem = mem->next;
-			}
-		}
-		grp = g_slist_next(grp);
-	}
-
-	while (len > pos && plist) {
-		pos += g_snprintf(&s[pos], len - pos, "p %s\n", (char *)plist->data);
-		plist = plist->next;
-	}
-
-	while (len > pos && dlist) {
-		pos += g_snprintf(&s[pos], len - pos, "d %s\n", (char *)dlist->data);
-		dlist = dlist->next;
-	}
-}
-
+#if 0
 /* translate an AIM 3 buddylist (*.lst) to a Gaim buddylist */
 static GString *translate_lst(FILE *src_fp)
 {
@@ -518,6 +619,7 @@
 
 	return dest;
 }
+#endif
 
 static gchar *get_screenname_filename(const char *name)
 {
@@ -535,7 +637,8 @@
 
 static gboolean gaim_blist_read(const char *filename);
 
-void do_import(struct gaim_account *account, const char *filename)
+
+static void do_import(struct gaim_account *account, const char *filename)
 {
 	GString *buf = NULL;
 	char first[64];
@@ -575,9 +678,13 @@
 	if ((first[0] == '\n') || (first[0] == '\r' && first[1] == '\n'))
 		fgets(first, 64, f);
 
+#if 0
 	if (!g_strncasecmp(first, "<xml", strlen("<xml"))) {
 		/* new gaim XML buddy list */
 		gaim_blist_read(path);
+		
+		/* We really don't need to bother doing stuf like translating AIM 3 buddy lists anymore */
+		
 	} else if (!g_strncasecmp(first, "Config {", strlen("Config {"))) {
 		/* AIM 4 buddy list */
 		debug_printf("aim 4\n");
@@ -593,22 +700,25 @@
 		debug_printf("gnomeicu\n");
 		rewind(f);
 		buf = translate_gnomeicu(f);
-	} else if (first[0] == 'm') {
-		/* Gaim buddy list - no translation */
-		char buf2[BUF_LONG * 2];
-		buf = g_string_new("");
-		rewind(f);
-		while (1) {
-			len = fread(buf2, 1, BUF_LONG * 2 - 1, f);
-			if (len <= 0)
-				break;
+
+	} else 
+#endif
+		if (first[0] == 'm') {
+			/* Gaim buddy list - no translation */
+			char buf2[BUF_LONG * 2];
+			buf = g_string_new("");
+			rewind(f);
+			while (1) {
+				len = fread(buf2, 1, BUF_LONG * 2 - 1, f);
+				if (len <= 0)
+					break;
 			buf2[len] = '\0';
 			buf = g_string_append(buf, buf2);
 			if (len != BUF_LONG * 2 - 1)
 				break;
+			}
 		}
-	}
-
+	
 	fclose(f);
 
 	if (buf) {
@@ -619,96 +729,6 @@
 	}
 }
 
-static gboolean is_blocked(struct buddy *b)
-{
-	struct gaim_account *account = b->account;
-
-	if (account->permdeny == PERMIT_ALL)
-		return FALSE;
-
-	if (account->permdeny == PERMIT_NONE) {
-		if (account->gc && g_strcasecmp(b->name, account->gc->username))
-			return TRUE;
-		else
-			return FALSE;
-	}
-
-	if (account->permdeny == PERMIT_SOME) {
-		char *x = g_strdup(normalize(b->name));
-		GSList *s = account->permit;
-		while (s) {
-			if (!g_strcasecmp(x, normalize(s->data)))
-				break;
-			s = s->next;
-		}
-		g_free(x);
-		if (s)
-			return FALSE;
-		return TRUE;
-	}
-
-	if (account->permdeny == DENY_SOME) {
-		char *x = g_strdup(normalize(b->name));
-		GSList *s = account->deny;
-		while (s) {
-			if (!g_strcasecmp(x, normalize(s->data)))
-				break;
-			s = s->next;
-		}
-		g_free(x);
-		if (s)
-			return TRUE;
-		return FALSE;
-	}
-
-	return FALSE;
-}
-
-void signoff_blocked(struct gaim_connection *gc)
-{
-	GSList *g = groups;
-	while (g) {
-		GSList *m = ((struct group *)g->data)->members;
-		while (m) {
-			struct buddy *b = m->data;
-			if (is_blocked(b))
-				serv_got_update(gc, b->name, 0, 0, 0, 0, 0, 0);
-			m = m->next;
-		}
-		g = g->next;
-	}
-}
-
-char *get_buddy_alias_only(struct buddy *b) {
-	if(!b)
-		return NULL;
-	if(b->alias[0])
-		return b->alias;
-	else if((misc_options & OPT_MISC_USE_SERVER_ALIAS) && b->server_alias[0])
-		return b->server_alias;
-	return NULL;
-}
-
-
-char *get_buddy_alias(struct buddy *b) {
-	char *ret = get_buddy_alias_only(b);
-	if(!ret)
-		return b ? b->name : _("Unknown");
-	return ret;
-}
-
-GSList *gaim_group_get_accounts(struct group *g) {
-	GSList *buds = g->members;
-	GSList *ret = NULL;
-	while(buds) {
-		struct buddy *b = buds->data;
-		if(!g_slist_find(ret, b->account))
-			ret = g_slist_append(ret, b->account);
-		buds = buds->next;
-	}
-	return ret;
-}
-
 gboolean gaim_group_on_account(struct group *g, struct gaim_account *account) {
 	GSList *buds = g->members;
 	while(buds) {
@@ -770,7 +790,8 @@
 			}
 		}
 		if(blist_parser_group_name) {
-			add_group(blist_parser_group_name);
+			struct group *g = gaim_group_new(blist_parser_group_name);
+			gaim_blist_add_group(g,NULL);
 		}
 	} else if(!strcmp(element_name, "person")) {
 		blist_parser_current_tag = BLIST_TAG_PERSON;
@@ -840,8 +861,9 @@
 		struct gaim_account *account = gaim_account_find(blist_parser_account_name,
 				blist_parser_account_protocol);
 		if(account) {
-			struct buddy *b = add_buddy(account, blist_parser_group_name,
-					blist_parser_buddy_name, blist_parser_buddy_alias);
+			struct buddy *b = gaim_buddy_new(account, blist_parser_buddy_name, blist_parser_buddy_alias);
+			struct group *g = gaim_find_group(blist_parser_group_name);
+			gaim_blist_add_buddy(b,g,NULL);
 			if(blist_parser_buddy_settings) {
 				g_hash_table_destroy(b->settings);
 				b->settings = blist_parser_buddy_settings;
@@ -1036,35 +1058,36 @@
 }
 
 static void gaim_blist_write(FILE *file, struct gaim_account *exp_acct) {
-	GSList *grps, *buds, *accounts;
+	GSList *accounts, *buds;
+	struct group *group;
+	struct buddy *bud;
 	fprintf(file, "<?xml version='1.0' encoding='UTF-8' ?>\n");
 	fprintf(file, "<gaim version=\"1\">\n");
 	fprintf(file, "\t<blist>\n");
 
-	for(grps = groups; grps; grps = grps->next) {
-		struct group *g = grps->data;
-		if(!exp_acct || gaim_group_on_account(g, exp_acct)) {
-			char *group_name = g_markup_escape_text(g->name, -1);
+	for(group = (struct group*)gaimbuddylist->root; group; group = (struct group*)((GaimBlistNode*)group)->next) {
+		if(!exp_acct || gaim_group_on_account(group, exp_acct)) {
+			char *group_name = g_markup_escape_text(group->name, -1);
 			fprintf(file, "\t\t<group name=\"%s\">\n", group_name);
-			for(buds = g->members; buds; buds = buds->next) {
-				struct buddy *b = buds->data;
-				if(!exp_acct || b->account == exp_acct) {
-					char *bud_name = g_markup_escape_text(b->name, -1);
+			for(buds = group->members; buds; buds = buds->next) {
+				bud = buds->data;
+				if(!exp_acct || bud->account == exp_acct) {
+					char *bud_name = g_markup_escape_text(bud->name, -1);
 					char *bud_alias = NULL;
-					char *acct_name = g_markup_escape_text(b->account->username, -1);
-					if(b->alias[0])
-						bud_alias= g_markup_escape_text(b->alias, -1);
+					char *acct_name = g_markup_escape_text(bud->account->username, -1);
+					if(bud->alias)
+						bud_alias= g_markup_escape_text(bud->alias, -1);
 					fprintf(file, "\t\t\t<person name=\"%s\">\n",
 							bud_alias ? bud_alias : bud_name);
 					fprintf(file, "\t\t\t\t<buddy protocol=\"%d\" "
-							"account=\"%s\">\n", b->account->protocol,
+							"account=\"%s\">\n", bud->account->protocol,
 							acct_name);
 					fprintf(file, "\t\t\t\t\t<name>%s</name>\n", bud_name);
 					if(bud_alias) {
 						fprintf(file, "\t\t\t\t\t<alias>%s</alias>\n",
 								bud_alias);
 					}
-					g_hash_table_foreach(b->settings,
+					g_hash_table_foreach(bud->settings,
 							blist_print_buddy_settings, file);
 					fprintf(file, "\t\t\t\t</buddy>\n");
 					fprintf(file, "\t\t\t</person>\n");
@@ -1218,3 +1241,8 @@
 		return NULL;
 	return g_strdup(g_hash_table_lookup(b->settings, key));
 }
+
+void gaim_set_blist_ui_ops(struct gaim_blist_ui_ops *ops)
+{
+	gaimbuddylist->ui_ops = blist_ui_ops = ops;
+}
--- a/src/log.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/log.c	Mon Mar 10 05:30:31 2003 +0000
@@ -328,37 +328,37 @@
 			g_snprintf(html, sizeof(html), "<I><FONT COLOR=GRAY>%s</FONT></I>", text);
 			break;
 		}
-	} else if (get_buddy_alias_only(who)) {
+	} else if (gaim_get_buddy_alias_only(who)) {
 		switch (what) {
 		case log_signon:
 			g_snprintf(text, sizeof(text), _("%s (%s) reported that %s (%s) signed on @ %s"),
-				   gc->username, gc->prpl->name, get_buddy_alias(who), who->name, full_date());
+				   gc->username, gc->prpl->name, gaim_get_buddy_alias(who), who->name, full_date());
 			g_snprintf(html, sizeof(html), "<B>%s</B>", text);
 			break;
 		case log_signoff:
 			g_snprintf(text, sizeof(text), _("%s (%s) reported that %s (%s) signed off @ %s"),
-				   gc->username, gc->prpl->name, get_buddy_alias(who), who->name, full_date());
+				   gc->username, gc->prpl->name, gaim_get_buddy_alias(who), who->name, full_date());
 			g_snprintf(html, sizeof(html), "<I><FONT COLOR=GRAY>%s</FONT></I>", text);
 			break;
 		case log_away:
 			g_snprintf(text, sizeof(text), _("%s (%s) reported that %s (%s) went away @ %s"),
-				   gc->username, gc->prpl->name, get_buddy_alias(who), who->name, full_date());
+				   gc->username, gc->prpl->name, gaim_get_buddy_alias(who), who->name, full_date());
 			g_snprintf(html, sizeof(html), "<FONT COLOR=OLIVE>%s</FONT>", text);
 			break;
 		case log_back:
 			g_snprintf(text, sizeof(text), _("%s (%s) reported that %s (%s) came back @ %s"),
-				   gc->username, gc->prpl->name, get_buddy_alias(who), who->name, full_date());
+				   gc->username, gc->prpl->name, gaim_get_buddy_alias(who), who->name, full_date());
 			g_snprintf(html, sizeof(html), "%s", text);
 			break;
 		case log_idle:
 			g_snprintf(text, sizeof(text), _("%s (%s) reported that %s (%s) became idle @ %s"),
-				   gc->username, gc->prpl->name, get_buddy_alias(who), who->name, full_date());
+				   gc->username, gc->prpl->name, gaim_get_buddy_alias(who), who->name, full_date());
 			g_snprintf(html, sizeof(html), "<FONT COLOR=GRAY>%s</FONT>", text);
 			break;
 		case log_unidle:
 			g_snprintf(text, sizeof(text),
 				   _("%s (%s) reported that %s (%s) returned from idle @ %s"), gc->username,
-				   gc->prpl->name, get_buddy_alias(who), who->name, full_date());
+				   gc->prpl->name, gaim_get_buddy_alias(who), who->name, full_date());
 			g_snprintf(html, sizeof(html), "%s", text);
 			break;
 		default:
--- a/src/main.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/main.c	Mon Mar 10 05:30:31 2003 +0000
@@ -50,6 +50,7 @@
 #include "sound.h"
 #include "gaim.h"
 #include "gaim-socket.h"
+#include "gtklist.h"
 #if HAVE_SIGNAL_H
 #include <signal.h>
 #endif
@@ -74,6 +75,7 @@
 
 
 int opt_away = 0;
+int docklet_count = 0;
 char *opt_away_arg = NULL;
 char *opt_rcfile_arg = NULL;
 int opt_debug = 0;
@@ -527,6 +529,7 @@
 	/* Set the UI operation structures. */
 	gaim_set_win_ui_ops(gaim_get_gtk_window_ui_ops());
 	gaim_set_xfer_ui_ops(gaim_get_gtk_xfer_ui_ops());
+	gaim_set_blist_ui_ops(gaim_get_gtk_blist_ui_ops());
 
 	setup_stock();
 
--- a/src/multi.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/multi.c	Mon Mar 10 05:30:31 2003 +0000
@@ -27,6 +27,7 @@
 #include "multi.h"
 #include "gaim.h"
 #include "conversation.h"
+#include "gtklist.h"
 
 #ifdef _WIN32
 #include "win32dep.h"
@@ -185,7 +186,7 @@
 		acctedit = NULL;
 	}
 	treeview = NULL;
-	if (!d && !blist && !mainwindow && !connections)
+	if (!d && !gtkblist->window && !mainwindow && !connections)
 		do_quit();
 }
 
@@ -1334,9 +1335,7 @@
 			}
 		}
 		if(!g->members) {
-			ui_remove_group(g);
-			groups = g_slist_remove(groups, g);
-			g_free(g);
+			gaim_blist_remove_group(g);
 		}
 	}
 
@@ -1475,18 +1474,15 @@
 };
 static GSList *meters = NULL;
 
-GtkWidget* create_meter_pixmap (GtkWidget *widget, struct gaim_connection *gc)
+GtkWidget* create_meter_pixmap (struct gaim_connection *gc)
 {
-	GdkPixmap *gdkpixmap;
-	GdkBitmap *mask;
-	GtkWidget *pixmap;
-
-	create_prpl_icon (widget, gc, &gdkpixmap, &mask);
-
-	pixmap = gtk_image_new_from_pixmap(gdkpixmap, mask);
-	gdk_pixmap_unref (gdkpixmap);
-	gdk_bitmap_unref (mask);
-	return pixmap;
+	GdkPixbuf *pb = create_prpl_icon(gc->account);
+	GdkPixbuf *scale = gdk_pixbuf_scale_simple(pb, 30,30,GDK_INTERP_BILINEAR);
+	GtkWidget *image =
+		gtk_image_new_from_pixbuf(scale);
+	g_object_unref(G_OBJECT(pb));
+	g_object_unref(G_OBJECT(scale));
+	return image;
 }
 
 static struct signon_meter *find_signon_meter(struct gaim_connection *gc)
@@ -1536,7 +1532,7 @@
 	if (mainwindow)
 		gtk_widget_hide(mainwindow);
 
-	show_buddy_list();
+	gaim_blist_show();
 
 	update_privacy_connections();
 	do_away_menu();
@@ -1552,7 +1548,6 @@
 								 GAIM_CONV_ACCOUNT_ONLINE);
 	}
 
-	redo_buddy_list();
 	gaim_setup(gc);
 
 	gc->account->connecting = FALSE;
@@ -1630,9 +1625,6 @@
 				 gc->account, gc->account->gc, gc);
 	gc->account->gc = NULL;	/* wasn't that awkward? */
 
-	/* take these buddies out of the edit tree */
-	build_edit_tree();
-
 	if (!acctedit)
 		return;
 
@@ -1700,7 +1692,7 @@
 	(*rows)++;
 	gtk_table_resize (table, *rows, 4);
 
-	graphic = create_meter_pixmap( widget , gc);
+	graphic = create_meter_pixmap(gc);
 
 	nest_vbox = gtk_vbox_new (FALSE, 0);
 
@@ -1901,7 +1893,9 @@
 	/* CONV XXX
 	convo_menu_remove(gc);
 	remove_icon_data(gc);
-	*/
+       	*/
+
+	gaim_blist_remove_account(gc->account);
 
 	/* core stuff */
 	/* remove this here so plugins get a sensible count of connections */
@@ -1920,7 +1914,6 @@
 	serv_close(gc);
 
 	/* more UI stuff */
-	redo_buddy_list();
 	do_away_menu();
 	do_proto_menu();
 
@@ -1941,7 +1934,7 @@
 		return;
 
 	destroy_all_dialogs();
-	destroy_buddy();
+	gaim_blist_destroy();
 
 	show_login();
 }
--- a/src/perl.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/perl.c	Mon Mar 10 05:30:31 2003 +0000
@@ -775,19 +775,17 @@
 
 	gc = (struct gaim_connection *)SvIV(ST(0));
 	if (g_slist_find(connections, gc))
-		buddy = find_buddy(gc->account, SvPV(ST(1), junk));
+		buddy = gaim_find_buddy(gc->account, SvPV(ST(1), junk));
 
 	if (!buddy)
 		XSRETURN(0);
 	XST_mPV(0, buddy->name);
-	XST_mPV(1, get_buddy_alias(buddy));
+	XST_mPV(1, gaim_get_buddy_alias(buddy));
 	XST_mPV(2, buddy->present ? "Online" : "Offline");
 	XST_mIV(3, buddy->evil);
 	XST_mIV(4, buddy->signon);
 	XST_mIV(5, buddy->idle);
-	XST_mIV(6, buddy->uc);
-	XST_mIV(7, buddy->caps);
-	XSRETURN(8);
+	XSRETURN(6);
 }
 
 XS (XS_GAIM_write_to_conv)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pounce.c	Mon Mar 10 05:30:31 2003 +0000
@@ -0,0 +1,615 @@
+/*
+ * gaim
+ *
+ * Copyright (C) 1998-2003, Mark Spencer <markster@marko.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "gaim.h"
+#include "prpl.h"
+#include "pounce.h"
+
+GtkWidget *bpmenu = NULL;
+
+void rem_bp(GtkWidget *w, struct buddy_pounce *b)
+{
+	buddy_pounces = g_list_remove(buddy_pounces, b);
+	//do_bp_menu();
+	save_prefs();
+}
+
+void do_pounce(struct gaim_connection *gc, char *name, int when)
+{
+	char *who;
+
+	struct buddy_pounce *b;
+	struct gaim_conversation *c;
+	struct gaim_account *account;
+
+	GList *bp = buddy_pounces;
+
+	who = g_strdup(normalize (name));
+
+	while (bp) {
+		b = (struct buddy_pounce *)bp->data;
+		bp = bp->next;	/* increment the list here because rem_bp can make our handle bad */
+
+		if (!(b->options & when))
+			continue;
+
+		account = gaim_account_find(b->pouncer, b->protocol);	/* find our user */
+		if (account == NULL)
+			continue;
+
+		/* check and see if we're signed on as the pouncer */
+		if (account->gc != gc)
+			continue;
+
+		if (!g_strcasecmp(who, normalize (b->name))) {	/* find someone to pounce */
+			if (b->options & OPT_POUNCE_POPUP) {
+				c = gaim_find_conversation(name);
+
+				if (c == NULL)
+					c = gaim_conversation_new(GAIM_CONV_IM, account, name);
+				else
+					gaim_conversation_set_account(c, account);
+			}
+			if (b->options & OPT_POUNCE_NOTIFY) {
+				char tmp[1024];
+
+				/* I know the line below is really ugly. I only did it this way
+				 * because I thought it'd be funny :-) */
+
+				g_snprintf(tmp, sizeof(tmp), 
+					   (when & OPT_POUNCE_TYPING) ? _("%s has started typing to you") :
+					   (when & OPT_POUNCE_SIGNON) ? _("%s has signed on") : 
+					   (when & OPT_POUNCE_UNIDLE) ? _("%s has returned from being idle") : 
+					   _("%s has returned from being away"), name);
+				
+				do_error_dialog(tmp, NULL, GAIM_INFO);
+			}
+			if (b->options & OPT_POUNCE_SEND_IM) {
+				if (strlen(b->message) > 0) {
+					c = gaim_find_conversation(name);
+
+					if (c == NULL)
+						c = gaim_conversation_new(GAIM_CONV_IM, account, name);
+					else
+						gaim_conversation_set_account(c, account);
+
+					gaim_conversation_write(c, NULL, b->message, -1,
+											WFLAG_SEND, time(NULL));
+
+					serv_send_im(account->gc, name, b->message, -1, 0);
+				}
+			}
+			if (b->options & OPT_POUNCE_COMMAND) {
+#ifndef _WIN32
+				int pid = fork();
+
+				if (pid == 0) {
+					char *args[4];
+					args[0] = "sh";
+					args[1] = "-c";
+					args[2] = b->command;
+					args[3] = NULL;
+					execvp(args[0], args);
+					_exit(0);
+				}
+#else
+				STARTUPINFO si;
+				PROCESS_INFORMATION pi;
+
+				ZeroMemory( &si, sizeof(si) );
+				si.cb = sizeof(si);
+				ZeroMemory( &pi, sizeof(pi) );
+
+				CreateProcess( NULL, b->command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
+				CloseHandle( pi.hProcess );
+				CloseHandle( pi.hThread );
+#endif /*_WIN32*/
+			}
+			/*	if (b->options & OPT_POUNCE_SOUND) {
+				if (strlen(b->sound))
+					play_file(b->sound);
+				else
+					play_sound(SND_POUNCE_DEFAULT);
+					}*/
+
+			if (!(b->options & OPT_POUNCE_SAVE))
+				rem_bp(NULL, b);
+
+		}
+	}
+	g_free(who);
+}
+
+static void new_bp_callback(GtkWidget *w, struct buddy *b)
+{
+	if (b)
+		show_new_bp(b->name, b->account->gc, b->idle, b->uc & UC_UNAVAILABLE, NULL);
+	else
+		show_new_bp(NULL, NULL, 0, 0, NULL);
+}
+
+static void edit_bp_callback(GtkWidget *w, struct buddy_pounce *b)
+{
+  show_new_bp(NULL, NULL, 0, 0, b);
+}
+
+/*static GtkTooltips *bp_tooltip = NULL;
+void do_bp_menu()
+{
+	GtkWidget *menuitem, *mess, *messmenu;
+	static GtkWidget *remmenu;
+	GtkWidget *remitem;
+	GtkWidget *sep;
+	GList *l;
+	struct buddy_pounce *b;
+	GList *bp = buddy_pounces;
+
+	/* Tooltip for editing bp's 
+	if(!bp_tooltip)
+		bp_tooltip = gtk_tooltips_new();
+
+	l = gtk_container_children(GTK_CONTAINER(bpmenu));
+
+	while (l) {
+		gtk_widget_destroy(GTK_WIDGET(l->data));
+		l = l->next;
+	}
+
+	remmenu = gtk_menu_new();
+
+	menuitem = gtk_menu_item_new_with_label(_("New Buddy Pounce"));
+	gtk_menu_shell_append(GTK_MENU(bpmenu), menuitem);
+	gtk_widget_show(menuitem);
+	g_signal_connect(GTK_OBJECT(menuitem), "activate", G_CALLBACK(new_bp_callback), NULL);
+
+
+	while (bp) {
+
+		b = (struct buddy_pounce *)bp->data;
+		remitem = gtk_menu_item_new_with_label(b->name);
+		gtk_menu_shell_append(GTK_MENU(remmenu), remitem);
+		gtk_widget_show(remitem);
+		g_signal_connect(GTK_OBJECT(remitem), "activate", G_CALLBACK(rem_bp), b);
+
+		bp = bp->next;
+
+	}
+
+	menuitem = gtk_menu_item_new_with_label(_("Remove Buddy Pounce"));
+	gtk_menu_shell_append(GTK_MENU(bpmenu), menuitem);
+	gtk_widget_show(menuitem);
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), remmenu);
+	gtk_widget_show(remmenu);
+
+	sep = gtk_hseparator_new();
+	menuitem = gtk_menu_item_new();
+	gtk_menu_shell_append(GTK_MENU(bpmenu), menuitem);
+	gtk_container_add(GTK_CONTAINER(menuitem), sep);
+	gtk_widget_set_sensitive(menuitem, FALSE);
+	gtk_widget_show(menuitem);
+	gtk_widget_show(sep);
+
+	bp = buddy_pounces;
+
+	while (bp) {
+
+		b = (struct buddy_pounce *)bp->data;
+
+		menuitem = gtk_menu_item_new_with_label(b->name);
+		gtk_menu_shell_append(GTK_MENU(bpmenu), menuitem);
+		messmenu = gtk_menu_new();
+		gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), messmenu);
+		gtk_widget_show(menuitem);
+
+		if (strlen(b->message))
+			mess = gtk_menu_item_new_with_label(b->message);
+		else
+			mess = gtk_menu_item_new_with_label(_("[no message]"));
+		gtk_menu_shell_append(GTK_MENU(messmenu), mess);
+		gtk_tooltips_set_tip(bp_tooltip, GTK_WIDGET(mess), _("[Click to edit]"), NULL);
+		gtk_widget_show(mess);
+		g_signal_connect(GTK_OBJECT(mess), "activate", G_CALLBACK(edit_bp_callback), b);
+		bp = bp->next;
+
+	}
+
+}
+*/
+/*------------------------------------------------------------------------*/
+/*  The dialog for new buddy pounces                                      */
+/*------------------------------------------------------------------------*/
+
+
+void do_new_bp(GtkWidget *w, struct addbp *b)
+{
+	struct buddy_pounce *bp;
+	
+	if (strlen(gtk_entry_get_text(GTK_ENTRY(b->nameentry))) == 0) {
+		do_error_dialog(_("Please enter a buddy to pounce."), NULL, GAIM_ERROR);
+		return;
+	}
+
+        if(!b->buddy_pounce)
+		bp = g_new0(struct buddy_pounce, 1);
+	else
+		bp = b->buddy_pounce;
+
+	
+	g_snprintf(bp->name, 80, "%s", gtk_entry_get_text(GTK_ENTRY(b->nameentry)));
+	g_snprintf(bp->message, 2048, "%s", gtk_entry_get_text(GTK_ENTRY(b->messentry)));
+	g_snprintf(bp->command, 2048, "%s", gtk_entry_get_text(GTK_ENTRY(b->commentry)));
+	g_snprintf(bp->sound, 2048, "%s", gtk_entry_get_text(GTK_ENTRY(b->soundentry)));
+	g_snprintf(bp->pouncer, 80, "%s", b->account->username);
+
+	bp->protocol = b->account->protocol;
+
+	bp->options = 0;
+
+	if (GTK_TOGGLE_BUTTON(b->popupnotify)->active)
+		bp->options |= OPT_POUNCE_NOTIFY;
+
+	if (GTK_TOGGLE_BUTTON(b->openwindow)->active)
+		bp->options |= OPT_POUNCE_POPUP;
+
+	if (GTK_TOGGLE_BUTTON(b->sendim)->active)
+		bp->options |= OPT_POUNCE_SEND_IM;
+
+	if (GTK_TOGGLE_BUTTON(b->command)->active)
+		bp->options |= OPT_POUNCE_COMMAND;
+
+	if (GTK_TOGGLE_BUTTON(b->sound)->active)
+		bp->options |= OPT_POUNCE_SOUND;
+
+	if (GTK_TOGGLE_BUTTON(b->p_signon)->active)
+		bp->options |= OPT_POUNCE_SIGNON;
+
+	if (GTK_TOGGLE_BUTTON(b->p_unaway)->active)
+		bp->options |= OPT_POUNCE_UNAWAY;
+
+	if (GTK_TOGGLE_BUTTON(b->p_unidle)->active)
+		bp->options |= OPT_POUNCE_UNIDLE;
+	
+	if (GTK_TOGGLE_BUTTON(b->p_typing)->active)
+		bp->options |= OPT_POUNCE_TYPING;
+
+	if (GTK_TOGGLE_BUTTON(b->save)->active)
+		bp->options |= OPT_POUNCE_SAVE;
+
+	if(!b->buddy_pounce)
+		buddy_pounces = g_list_append(buddy_pounces, bp);
+
+	//	do_bp_menu();
+
+	gtk_widget_destroy(b->window);
+
+	save_prefs();
+	g_free(b);
+}
+
+static void pounce_choose(GtkWidget *opt, struct addbp *b)
+{
+	struct gaim_account *account = gtk_object_get_user_data(GTK_OBJECT(opt));
+	b->account = account;
+}
+
+static GtkWidget *pounce_user_menu(struct addbp *b, struct gaim_connection *gc)
+{
+	GtkWidget *optmenu;
+	GtkWidget *menu;
+	GtkWidget *opt;
+	GSList *u = gaim_accounts;
+	struct gaim_account *account;
+	struct prpl *p;
+	int count = 0;
+	int place = 0;
+	char buf[2048];
+
+
+	optmenu = gtk_option_menu_new();
+
+	menu = gtk_menu_new();
+
+	while (u) {
+		account = (struct gaim_account *)u->data;
+		p = (struct prpl *)find_prpl(account->protocol);
+		g_snprintf(buf, sizeof buf, "%s (%s)", account->username, (p && p->name)?p->name:_("Unknown"));
+		opt = gtk_menu_item_new_with_label(buf);
+		gtk_object_set_user_data(GTK_OBJECT(opt), account);
+		g_signal_connect(GTK_OBJECT(opt), "activate", G_CALLBACK(pounce_choose), b);
+		gtk_menu_shell_append(GTK_MENU(menu), opt);
+		gtk_widget_show(opt);
+
+		if (b->account == account) {
+			gtk_menu_item_activate(GTK_MENU_ITEM(opt));
+			place = count;
+		}
+
+		count++;
+
+		u = u->next;
+	}
+
+	gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu);
+	gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), place);
+
+	b->menu = optmenu;
+
+	return optmenu;
+}
+
+
+void show_new_bp(char *name, struct gaim_connection *gc, int idle, int away, struct buddy_pounce *edit_bp)
+{
+	GtkWidget *label;
+	GtkWidget *bbox;
+	GtkWidget *vbox;
+	GtkWidget *button;
+	GtkWidget *frame;
+	GtkWidget *table;
+	GtkWidget *optmenu;
+	GtkWidget *sep;
+	GtkSizeGroup *sg;
+
+	struct addbp *b = g_new0(struct addbp, 1);
+	
+	if(edit_bp) {
+		b->buddy_pounce = edit_bp;
+		b->account = gaim_account_find(edit_bp->pouncer, edit_bp->protocol);
+	} else {
+		b->account = gc ? gc->account : gaim_accounts->data;
+		b->buddy_pounce = NULL;
+	}
+
+	GAIM_DIALOG(b->window);
+	gtk_window_set_policy(GTK_WINDOW(b->window), FALSE, TRUE, TRUE);
+	gtk_window_set_role(GTK_WINDOW(b->window), "new_bp");
+	gtk_window_set_title(GTK_WINDOW(b->window), _("Gaim - New Buddy Pounce"));
+	g_signal_connect(GTK_OBJECT(b->window), "destroy", G_CALLBACK(gtk_widget_destroy), b->window);
+	gtk_widget_realize(b->window);
+
+	vbox = gtk_vbox_new(FALSE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
+	gtk_container_add(GTK_CONTAINER(b->window), vbox);
+	gtk_widget_show(vbox);
+
+	/* <pounce type="who"> */
+	frame = gtk_frame_new(_("Pounce Who"));
+	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
+	gtk_widget_show(GTK_WIDGET(frame));
+
+	table = gtk_table_new(2, 2, FALSE);
+	gtk_container_add(GTK_CONTAINER(frame), table);
+	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
+	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+	gtk_table_set_row_spacings(GTK_TABLE(table), 5);
+	gtk_widget_show(table);
+
+	label = gtk_label_new(_("Account"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
+	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+	gtk_widget_show(label);
+
+	optmenu = pounce_user_menu(b, gc);
+	gtk_table_attach(GTK_TABLE(table), optmenu, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	gtk_widget_show(optmenu);
+
+	label = gtk_label_new(_("Buddy"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
+	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+	gtk_widget_show(label);
+
+	b->nameentry = gtk_entry_new();
+	gtk_table_attach(GTK_TABLE(table), b->nameentry, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	if (name !=NULL)
+		gtk_entry_set_text(GTK_ENTRY(b->nameentry), name);
+	else if(edit_bp)
+		gtk_entry_set_text(GTK_ENTRY(b->nameentry), edit_bp->name);
+	gtk_window_set_focus(GTK_WINDOW(b->window), b->nameentry);
+	gtk_widget_show(b->nameentry);
+	/* </pounce type="who"> */
+
+
+	/* <pounce type="when"> */
+	frame = gtk_frame_new(_("Pounce When"));
+	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
+	gtk_widget_show(GTK_WIDGET(frame));
+
+	table = gtk_table_new(2, 2, FALSE);
+	gtk_container_add(GTK_CONTAINER(frame), table);
+	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
+	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+	gtk_widget_show(table);
+	
+	b->p_signon = gtk_check_button_new_with_label(_("Pounce on sign on"));
+	if(edit_bp)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_signon), 
+		                           (edit_bp->options & OPT_POUNCE_SIGNON) ? TRUE : FALSE);
+	else
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_signon), TRUE);
+	gtk_table_attach(GTK_TABLE(table), b->p_signon, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+	gtk_widget_show(b->p_signon);
+
+	b->p_unaway = gtk_check_button_new_with_label(_("Pounce on return from away"));
+	if (away)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unaway), TRUE);
+	else if(edit_bp)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unaway), 
+					   (edit_bp->options & OPT_POUNCE_UNAWAY) ? TRUE : FALSE);
+	gtk_table_attach(GTK_TABLE(table), b->p_unaway, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	gtk_widget_show(b->p_unaway);
+
+	b->p_unidle = gtk_check_button_new_with_label(_("Pounce on return from idle"));
+	if (idle)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unidle), TRUE);
+	else if(edit_bp)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unidle), 
+				           (edit_bp->options & OPT_POUNCE_UNIDLE) ? TRUE : FALSE);
+	gtk_table_attach(GTK_TABLE(table), b->p_unidle, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+	gtk_widget_show(b->p_unidle);
+	
+	b->p_typing = gtk_check_button_new_with_label(_("Pounce when buddy is typing to you"));
+	if (edit_bp)		
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_typing),
+					   (edit_bp->options & OPT_POUNCE_TYPING) ? TRUE : FALSE);
+	gtk_table_attach(GTK_TABLE(table), b->p_typing,1,2,1,2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	gtk_widget_show(b->p_typing);
+
+	/* </pounce type="when"> */
+	
+	/* <pounce type="action"> */
+	frame = gtk_frame_new(_("Pounce Action"));
+	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
+	gtk_widget_show(GTK_WIDGET(frame));
+
+	table = gtk_table_new(4, 2, FALSE);
+	gtk_container_add(GTK_CONTAINER(frame), table);
+	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
+	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+	gtk_table_set_row_spacings(GTK_TABLE(table), 5);
+	gtk_widget_show(table);
+	
+	b->openwindow = gtk_check_button_new_with_label(_("Open IM Window"));
+	if(edit_bp)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->openwindow), 
+			                   (edit_bp->options & OPT_POUNCE_POPUP) ? TRUE : FALSE);
+	else
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->openwindow), FALSE);
+	gtk_table_attach(GTK_TABLE(table), b->openwindow, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+	gtk_widget_show(b->openwindow);
+	
+	b->popupnotify = gtk_check_button_new_with_label(_("Popup Notification"));
+	if(edit_bp)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->popupnotify), 
+					   (edit_bp->options & OPT_POUNCE_NOTIFY) ? TRUE : FALSE);
+	else
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->popupnotify), FALSE);
+	gtk_table_attach(GTK_TABLE(table), b->popupnotify, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
+	gtk_widget_show(b->popupnotify);
+
+	b->sendim = gtk_check_button_new_with_label(_("Send Message"));
+	if(edit_bp)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sendim), 
+					   (edit_bp->options & OPT_POUNCE_SEND_IM) ? TRUE : FALSE);
+	else
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sendim), TRUE);
+	gtk_table_attach(GTK_TABLE(table), b->sendim, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+	gtk_widget_show(b->sendim);
+
+	b->messentry = gtk_entry_new();
+	gtk_table_attach(GTK_TABLE(table), b->messentry, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	g_signal_connect(GTK_OBJECT(b->messentry), "activate", G_CALLBACK(do_new_bp), b);
+	if(edit_bp) {
+		gtk_widget_set_sensitive(GTK_WIDGET(b->messentry), 
+					(edit_bp->options & OPT_POUNCE_SEND_IM) ? TRUE : FALSE);
+		gtk_entry_set_text(GTK_ENTRY(b->messentry), edit_bp->message);
+	}
+	gtk_widget_show(b->messentry);
+
+	g_signal_connect(GTK_OBJECT(b->sendim), "clicked",
+					 G_CALLBACK(gaim_gtk_toggle_sensitive), b->messentry);
+
+	b->command = gtk_check_button_new_with_label(_("Execute command on pounce"));
+	gtk_table_attach(GTK_TABLE(table), b->command, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
+	if(edit_bp)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->command),
+					   (edit_bp->options & OPT_POUNCE_COMMAND) ? TRUE : FALSE);
+	else
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->command), FALSE);
+	gtk_widget_show(b->command);
+
+	b->commentry = gtk_entry_new();
+	gtk_table_attach(GTK_TABLE(table), b->commentry, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	g_signal_connect(GTK_OBJECT(b->commentry), "activate", G_CALLBACK(do_new_bp), b);
+	if(edit_bp) {
+		gtk_widget_set_sensitive(GTK_WIDGET(b->commentry), 
+					(edit_bp->options & OPT_POUNCE_COMMAND) ? TRUE : FALSE);
+		gtk_entry_set_text(GTK_ENTRY(b->commentry), edit_bp->command);
+	}
+	else
+		gtk_widget_set_sensitive(GTK_WIDGET(b->commentry), FALSE);
+	gtk_widget_show(b->commentry);
+	g_signal_connect(GTK_OBJECT(b->command), "clicked",
+					 G_CALLBACK(gaim_gtk_toggle_sensitive), b->commentry);
+	
+	b->sound = gtk_check_button_new_with_label(_("Play sound on pounce"));
+	if(edit_bp)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sound), 
+					   (edit_bp->options & OPT_POUNCE_SOUND) ? TRUE : FALSE);
+	else
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sound), FALSE);
+	gtk_table_attach(GTK_TABLE(table), b->sound, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
+	gtk_widget_show(b->sound);
+
+	b->soundentry = gtk_entry_new();
+	gtk_table_attach(GTK_TABLE(table), b->soundentry, 1, 2, 3, 4, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	g_signal_connect(GTK_OBJECT(b->soundentry), "activate", G_CALLBACK(do_new_bp), b);
+	if(edit_bp) {
+		gtk_widget_set_sensitive(GTK_WIDGET(b->soundentry), 
+					(edit_bp->options & OPT_POUNCE_SOUND) ? TRUE : FALSE);
+		gtk_entry_set_text(GTK_ENTRY(b->soundentry), edit_bp->sound);
+	} else 
+		gtk_widget_set_sensitive(GTK_WIDGET(b->soundentry), FALSE);
+	gtk_widget_show(b->soundentry);
+	g_signal_connect(GTK_OBJECT(b->sound), "clicked",
+					 G_CALLBACK(gaim_gtk_toggle_sensitive), b->soundentry);
+	/* </pounce type="action"> */
+
+	b->save = gtk_check_button_new_with_label(_("Save this pounce after activation"));
+	gtk_container_set_border_width(GTK_CONTAINER(b->save), 7);
+	if(edit_bp)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->save),
+					   (edit_bp->options & OPT_POUNCE_SAVE) ? TRUE : FALSE);
+	else
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->save), FALSE);
+	gtk_box_pack_start(GTK_BOX(vbox), b->save, FALSE, FALSE, 0);
+	gtk_widget_show(b->save);
+
+	sep = gtk_hseparator_new();
+	gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
+	gtk_widget_show(sep);
+	
+	bbox = gtk_hbox_new(FALSE, 5);
+	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+	gtk_widget_show(bbox);
+
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
+	button = gaim_pixbuf_button_from_stock(_("_Save"), "gtk-execute", GAIM_BUTTON_HORIZONTAL);
+	gtk_size_group_add_widget(sg, button);
+	g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(do_new_bp), b);
+	gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, FALSE, 0);
+	gtk_widget_show(button);
+
+	button = gaim_pixbuf_button_from_stock(_("C_ancel"), "gtk-cancel", GAIM_BUTTON_HORIZONTAL);
+	gtk_size_group_add_widget(sg, button);
+	g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_destroy), b->window);
+	gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, FALSE, 0);
+	gtk_widget_show(button);
+
+
+	gtk_widget_show(b->window);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pounce.h	Mon Mar 10 05:30:31 2003 +0000
@@ -0,0 +1,65 @@
+/*
+ * gaim
+ *
+ * Copyright (C) 1998-2003, Mark Spencer <markster@marko.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _POUNCE_H_
+#define _POUNCE_H_
+
+struct buddy_pounce {
+        char name[80];
+        char message[2048];
+        char command[2048];
+        char sound[2048];
+        
+        char pouncer[80];
+        int protocol;
+
+        int options;
+};
+
+struct addbp {
+	GtkWidget *window;
+	GtkWidget *nameentry;
+	GtkWidget *messentry;
+	GtkWidget *commentry;
+	GtkWidget *command;
+	GtkWidget *sendim;
+	GtkWidget *openwindow;
+	GtkWidget *popupnotify;
+	GtkWidget *p_signon;
+	GtkWidget *p_unaway;
+	GtkWidget *p_unidle;
+	GtkWidget *p_typing;
+	GtkWidget *save;
+	GtkWidget *menu;
+	GtkWidget *sound;
+	GtkWidget *soundentry;
+
+	struct gaim_account *account;
+	struct buddy_pounce *buddy_pounce;
+};
+
+void rem_bp(GtkWidget *w, struct buddy_pounce *b);
+
+void do_pounce(struct gaim_connection *gc, char *name, int when);
+
+void do_bp_menu();
+
+#endif /* _POUNCE_H_ */
--- a/src/prefs.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/prefs.c	Mon Mar 10 05:30:31 2003 +0000
@@ -36,6 +36,7 @@
 #include <gtk/gtk.h>
 #include "gtkimhtml.h"
 #include "gaim.h"
+#include "gtklist.h"
 #include "prpl.h"
 #include "proxy.h"
 #include "sound.h"
@@ -551,7 +552,8 @@
 	gaim_button(_("Show _numbers in groups"), &blist_options, OPT_BLIST_SHOW_GRPNUM, vbox);
 
 	vbox = make_frame (ret, _("Buddy Display"));
-	gaim_button(_("Show buddy type _icons"), &blist_options, OPT_BLIST_SHOW_PIXMAPS, vbox);
+	gaim_button(_("Show buddy _icons"), &blist_options, OPT_BLIST_SHOW_ICONS, vbox);
+	gaim_button(_("Show buddy t_ype icons"), &blist_options, OPT_BLIST_SHOW_PIXMAPS, vbox);
 	gaim_button(_("Show _warning levels"), &blist_options, OPT_BLIST_SHOW_WARN, vbox);
 	gaim_button(_("Show idle _times"), &blist_options, OPT_BLIST_SHOW_IDLETIME, vbox);
 	gaim_button(_("Grey i_dle buddies"), &blist_options, OPT_BLIST_GREY_IDLERS, vbox);
@@ -1949,8 +1951,7 @@
 	if (option == OPT_MISC_DEBUG)
 		show_debug();
 	else if(option == OPT_MISC_USE_SERVER_ALIAS) {
-		redo_buddy_list();
-		build_edit_tree();
+		/* XXX blist reset the aliases here */
 		gaim_conversation_foreach(gaim_conversation_autoset_title);
 	}
 }
@@ -1966,27 +1967,11 @@
 static void set_blist_option(GtkWidget *w, int option)
 {
 	blist_options ^= option;
-
-	if (!blist)
+	
+	if (!gtkblist)
 		return;
-
-	if (option == OPT_BLIST_NO_BUTTONS)
-		build_imchat_box(!(blist_options & OPT_BLIST_NO_BUTTONS));
-
-	if (option == OPT_BLIST_SHOW_GRPNUM)
-		update_num_groups();
-
-	if (option == OPT_BLIST_NO_MT_GRP)
-		toggle_show_empty_groups();
-
-	if ((option == OPT_BLIST_SHOW_BUTTON_XPM) || (option == OPT_BLIST_NO_BUTTONS))
-		update_button_pix();
-
-	if (option == OPT_BLIST_SHOW_PIXMAPS)
-		toggle_buddy_pixmaps();
-
-	if ((option == OPT_BLIST_GREY_IDLERS) || (option == OPT_BLIST_SHOW_IDLETIME))
-		update_idle_times();
+	
+	gaim_gtk_blist_refresh(gaimbuddylist);
 
 }
 
@@ -2309,8 +2294,8 @@
 			gaim_gtkconv_update_tabs();
 		else if (clear == (OPT_CHAT_BUTTON_TEXT | OPT_CHAT_BUTTON_XPM))
 			gaim_gtkconv_update_chat_button_style();
-	} else if (option == (int*)&blist_options) {
-		set_blist_tab();
+		//	} else if (option == (int*)&blist_options) {
+		//    set_blist_tab();
 	} else if (option == (int *)&conv_placement_option) {
 		gaim_conv_placement_set_active(conv_placement_option);
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/privacy.h	Mon Mar 10 05:30:31 2003 +0000
@@ -0,0 +1,26 @@
+/*
+ * gaim
+ *
+ * Copyright (C) 2003, Christian Hammond <chipx86@gnupdate.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "gaim.h"
+gboolean gaim_privacy_permit_add(struct gaim_account *account, const char *name);
+gboolean gaim_privacy_deny_add(struct gaim_account *account, const char *name);
+gboolean gaim_privacy_deny_remove(struct gaim_account *account, const char *name);
+gboolean gaim_privacy_permit_remove(struct gaim_account *account, const char *name);
--- a/src/protocols/gg/gg.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/gg/gg.c	Mon Mar 10 05:30:31 2003 +0000
@@ -1,6 +1,6 @@
 /*
  * gaim - Gadu-Gadu Protocol Plugin
- * $Id: gg.c 4941 2003-03-02 18:48:02Z faceprint $
+ * $Id: gg.c 4998 2003-03-10 05:30:31Z seanegan $
  *
  * Copyright (C) 2001 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
  * 
@@ -278,7 +278,7 @@
 {
 	GList *m = NULL;
 	struct proto_buddy_menu *pbm;
-	struct buddy *b = find_buddy(gc->account, who);
+	struct buddy *b = gaim_find_buddy(gc->account, who);
 	static char buf[AGG_BUF_LEN];
 
 	if (!b) {
@@ -798,7 +798,9 @@
 		}
 
 		debug_printf("import_buddies_server_results: uin: %s\n", name);
-		if (!find_buddy(gc->account, name)) {
+		if (!gaim_find_buddy(gc->account, name)) {
+			struct buddy *b;
+			struct group *g;
 			/* Default group if none specified on server */
 			gchar *group = g_strdup("Gadu-Gadu");
 			if (strlen(data_tbl[5])) {
@@ -810,7 +812,10 @@
 				g_strfreev(group_tbl);
 			}
 			/* Add Buddy to our userlist */
-			add_buddy(gc->account, group, name, strlen(show) ? show : name);
+			if (!(g = gaim_find_group(group)))
+				g = gaim_group_new(group);
+			b = gaim_buddy_new(gc->account, name, strlen(show) ? show : NULL);
+			gaim_blist_add_buddy(b,g,NULL);
 			gaim_blist_save();
 			g_free(group);
 		}
@@ -1243,8 +1248,11 @@
 	}
 }
 
-static char **agg_list_icon(int uc)
+static const char *agg_list_icon(struct gaim_account *a, struct buddy *b)
 {
+	return "gadu-gadu";
+}
+#if 0
 	guint status;
 	if (uc == UC_UNAVAILABLE)
 		return (char **)gg_sunred_xpm;
@@ -1259,6 +1267,7 @@
 		return (char **)gg_sunwhitered_xpm;
 	return (char **)gg_sunyellow_xpm;
 }
+#endif
 
 static void agg_set_permit_deny_dummy(struct gaim_connection *gc)
 {
--- a/src/protocols/icq/gaim_icq.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/icq/gaim_icq.c	Mon Mar 10 05:30:31 2003 +0000
@@ -274,7 +274,7 @@
 		icq_SendAuthMsg(iq->link, iq->uin);
 
 		g_snprintf(uin, sizeof(uin), "%ld", iq->uin);
-		if (find_buddy(iq->gc->account, uin))
+		if (gaim_find_buddy(iq->gc->account, uin))
 			return;
 
 		iqnew = g_memdup(iq, sizeof(struct icq_auth));
@@ -441,8 +441,11 @@
 	}
 }
 
-static char **icq_list_icon(int uc) {
-	guint status;
+static const char *icq_list_icon(struct gaim_account *a, struct buddy *b) {
+	return "icq";
+}
+
+/*	guint status;
 	if (uc == 0)
 		return icon_online_xpm;
 	status = uc >> 1;
@@ -459,7 +462,7 @@
 	if (status & STATUS_INVISIBLE)
 		return NULL;
 	return icon_online_xpm;
-}
+	}*/
 
 static void icq_get_info(struct gaim_connection *gc, char *who) {
 	struct icq_data *id = (struct icq_data *)gc->proto_data;
--- a/src/protocols/irc/irc.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/irc/irc.c	Mon Mar 10 05:30:31 2003 +0000
@@ -50,8 +50,6 @@
 #include "win32dep.h"
 #endif
 
-#include "pixmaps/protocols/irc/irc_icon.xpm"
-
 #define IRC_BUF_LEN 4096
 #define PDIWORDS 32
 
@@ -2426,10 +2424,10 @@
 	irc_write(idata->fd, buf, strlen(buf));
 }
 
-static char **
-irc_list_icon(int uc)
+static const char *
+irc_list_icon(struct gaim_account *a, struct buddy *b)
 {
-	return irc_icon_xpm;
+	return "irc";
 }
 
 static int 
--- a/src/protocols/jabber/jabber.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/jabber/jabber.c	Mon Mar 10 05:30:31 2003 +0000
@@ -964,9 +964,9 @@
 {
 	struct buddy *b;
 
-	if ((b = find_buddy(gc->account, buddyname)) != NULL) {
+	if ((b = gaim_find_buddy(gc->account, buddyname)) != NULL) {
 		debug_printf("removing buddy [1]: %s\n", buddyname);
-		remove_buddy(b);
+		gaim_blist_remove_buddy(b);
 		gaim_blist_save();
 	}
 }
@@ -1519,7 +1519,7 @@
 			jc->b = cnv = serv_got_joined_chat(GJ_GC(gjc), i++, gjid->user);
 			jc->id = gaim_chat_get_id(GAIM_CHAT(jc->b));
 			jc->state = JCS_ACTIVE;
-		} else if ((b = find_buddy(GJ_GC(gjc)->account, buddy)) == NULL) {
+		} else if ((b = gaim_find_buddy(GJ_GC(gjc)->account, buddy)) == NULL) {
 			g_free(buddy);
 			gaim_jid_free(gjid);
 			return;
@@ -1624,7 +1624,7 @@
 		 * If we don't already have the buddy on *our* buddylist,
 		 * ask if we want him or her added.
 		 */
-		if(find_buddy(jap->gc->account, jap->user) == NULL) {
+		if(gaim_find_buddy(jap->gc->account, jap->user) == NULL) {
 			show_got_added(jap->gc, NULL, jap->user, NULL, NULL);
 		}
 	}
@@ -1771,14 +1771,19 @@
 	 * Add or remove a buddy?  Change buddy's alias or group?
 	 */
 	if (BUD_SUB_TO_PEND(sub, ask) || BUD_SUBD_TO(sub, ask)) {
-		if ((b = find_buddy(GJ_GC(gjc)->account, buddyname)) == NULL) {
+		if ((b = gaim_find_buddy(GJ_GC(gjc)->account, buddyname)) == NULL) {
+			struct buddy *b = gaim_buddy_new(GJ_GC(gjc)->account, buddyname, name ? name : NULL);
+			struct group *g;
+			if (groupname) {
+				if (!(g = gaim_find_group(groupname)))
+					g = gaim_group_new(groupname);
+			} else
+				g = gaim_group_new(_("Buddies"));
 			debug_printf("adding buddy [4]: %s\n", buddyname);
-			b = add_buddy(GJ_GC(gjc)->account,
-					groupname ? groupname : _("Buddies"), buddyname,
-					name ? name : buddyname);
+			gaim_blist_add_buddy(b, g, NULL);
 			gaim_blist_save();
 		} else {
-			struct group *c_grp = find_group_by_buddy(b);
+			struct group *c_grp = gaim_find_buddys_group(b);
 
 			/*
 			 * If the buddy's in a new group or his/her alias is changed...
@@ -1792,9 +1797,9 @@
 				/*
 				 * seems rude, but it seems to be the only way...
 				 */
-				remove_buddy(b);
-				b = add_buddy(GJ_GC(gjc)->account, groupname, buddyname,
-					name ? name : buddyname);
+				gaim_blist_remove_buddy(b);
+				b = gaim_buddy_new(GJ_GC(gjc)->account, buddyname, name ? name : NULL);
+				gaim_blist_add_buddy(b, gaim_find_group(groupname), NULL);
 				gaim_blist_save();
 				if(present) {
 					serv_got_update(GJ_GC(gjc), buddyname, 1, 0, signon, idle,
@@ -1802,7 +1807,7 @@
 				}
 			} else if(name != NULL && strcmp(b->alias, name)) {
 				g_snprintf(b->alias, sizeof(b->alias), "%s", name);
-				handle_buddy_rename(b, buddyname);
+				gaim_blist_rename_buddy(b, buddyname);
 				gaim_blist_save();
 			}
 		}
@@ -2494,7 +2499,7 @@
 		y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item");
 		xmlnode_put_attrib(y, "jid", realwho);
 
-		buddy = find_buddy(gc->account, realwho);
+		buddy = gaim_find_buddy(gc->account, realwho);
 
 		/*
 		 * See if there's an explict (new?) alias for the buddy or we can pull
@@ -2520,7 +2525,7 @@
 		 */
 		if(group && group[0] != '\0') {
 			my_group = group;
-		} else if((buddy_group = find_group_by_buddy(buddy)) != NULL) {
+		} else if((buddy_group = gaim_find_buddys_group(buddy)) != NULL) {
 			my_group = buddy_group->name;
 		}
 
@@ -2762,8 +2767,11 @@
 		g_hash_table_foreach(jd->buddies, set_invisible_to_buddy_status, (gpointer) invisible);
 }
 
-static char **jabber_list_icon(int uc)
+static const char *jabber_list_icon(struct gaim_account *a, struct buddy *b)
 {
+	return "jabber";
+}
+/*
 	switch (uc) {
 	case UC_AWAY:
 		return available_away_xpm;
@@ -2778,7 +2786,7 @@
 	default:
 		return available_xpm;
 	}
-}
+	}*/
 
 static GList *jabber_chat_info(struct gaim_connection *gc)
 {
@@ -2897,7 +2905,7 @@
 		jc->gjid = gjid;
 		jc->gc = gc;
 		((struct jabber_data *)gc->proto_data)->chats = g_slist_append(jcs, jc);
-		add_buddy(gc->account, _("Chats"), realwho, realwho);
+		//	add_buddy(gc->account, _("Chats"), realwho, realwho);
 	}
 
 	jc->state = JCS_PENDING;
@@ -3202,7 +3210,7 @@
 static GList *jabber_buddy_menu(struct gaim_connection *gc, char *who) {
 	GList *m = NULL;
 	struct proto_buddy_menu *pbm;
-	struct buddy *b = find_buddy(gc->account, who);
+	struct buddy *b = gaim_find_buddy(gc->account, who);
 
 	if(b->uc == UC_ERROR)
 	{
--- a/src/protocols/msn/msn.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/msn/msn.c	Mon Mar 10 05:30:31 2003 +0000
@@ -30,6 +30,7 @@
 #include "pixmaps/protocols/msn/msn_away.xpm"
 #include "pixmaps/protocols/msn/msn_occ.xpm"
 
+#define BUDDY_ALIAS_MAXLEN 388
 
 static struct prpl *my_protocol = NULL;
 
@@ -365,7 +366,7 @@
 		g_snprintf(msg, sizeof(msg), _("The user %s (%s) wants to add %s to his or her buddy list."),
 				ap->user, ap->friend, ap->gc->username);
 
-		do_ask_dialog(msg, NULL, ap, _("Authorize"), msn_accept_add, _("Deny"), msn_cancel_add, my_protocol->plug ? my_protocol->plug->handle : NULL, FALSE);
+		//	do_ask_dialog(msg, NULL, ap, _("Authorize"), msn_accept_add, _("Deny"), msn_cancel_add, my_protocol->plug ? my_protocol->plug->handle : NULL, FALSE);
 	} else if (!g_strncasecmp(buf, "BLP", 3)) {
 		char *type, *tmp = buf;
 
@@ -536,10 +537,19 @@
 
 			while (md->fl) {
 				struct msn_buddy *mb = md->fl->data;
-				struct buddy *b = find_buddy(gc->account, mb->user);
+				struct buddy *b = gaim_find_buddy(gc->account, mb->user);
 				md->fl = g_slist_remove(md->fl, mb);
-				if(!b)
-					b = add_buddy(gc->account, _("Buddies"), mb->user, NULL);
+				if(!b) {
+					struct group *g;
+					printf("I'm adding %s now..\n", mb->user);
+					if (!(g = gaim_find_group(_("Buddies")))) {
+						printf("How could I not exitst!??!\n");
+						g = gaim_group_new(_("Buddies"));
+						gaim_blist_add_group(g, NULL);
+					}
+					b = gaim_buddy_new(gc->account, mb->user, NULL);
+					gaim_blist_add_buddy(b,g,NULL);
+				}
 				serv_got_alias(gc, mb->user, mb->friend);
 				g_free(mb->user);
 				g_free(mb->friend);
@@ -1580,8 +1590,11 @@
 	}
 }
 
-static char **msn_list_icon(int uc)
+static const char *msn_list_icon(struct gaim_account *a, struct buddy *b)
 {
+	return "msn";
+}
+/*
 	if (uc == 0)
 		return msn_online_xpm;
 	
@@ -1592,7 +1605,7 @@
 	
 	return msn_away_xpm;
 }
-
+*/
 static char *msn_get_away_text(int s)
 {
 	switch (s) {
@@ -1633,7 +1646,7 @@
 {
 	GList *m = NULL;
 	struct proto_buddy_menu *pbm;
-	struct buddy *b = find_buddy(gc->account, who);
+	struct buddy *b = gaim_find_buddy(gc->account, who);
 	static char buf[MSN_BUF_LEN];
 
 #if 0
--- a/src/protocols/msn/switchboard.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/msn/switchboard.c	Mon Mar 10 05:30:31 2003 +0000
@@ -95,8 +95,8 @@
 			struct gaim_conversation *cnv;
 			struct buddy *b;
 
-			if ((b = find_buddy(gc->account, user)) != NULL)
-				username = get_buddy_alias(b);
+			if ((b = gaim_find_buddy(gc->account, user)) != NULL)
+				username = gaim_get_buddy_alias(b);
 			else
 				username = user;
 
@@ -105,7 +105,7 @@
 
 			if ((cnv = gaim_find_conversation(user)))
 				gaim_conversation_write(cnv, NULL, msgbuf, -1,
-										WFLAG_SYSTEM, time(NULL));
+							WFLAG_SYSTEM, time(NULL));
 
 			msn_kill_switch(ms);
 			return 0;
--- a/src/protocols/napster/napster.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/napster/napster.c	Mon Mar 10 05:30:31 2003 +0000
@@ -47,8 +47,6 @@
 #include "win32dep.h"
 #endif
 
-#include "pixmaps/protocols/napster/napster.xpm"
-
 /* for win32 compatability */
 G_MODULE_IMPORT GSList *connections;
 
@@ -554,9 +552,9 @@
 	}
 }
 
-static char** nap_list_icon(int uc)
+static const char* nap_list_icon(struct gaim_account *a, struct buddy *b)
 {
-	return napster_xpm;
+	return "napster";
 }
 
 static struct prpl *my_protocol = NULL;
--- a/src/protocols/oscar/oscar.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/oscar/oscar.c	Mon Mar 10 05:30:31 2003 +0000
@@ -2202,13 +2202,13 @@
 
 	if (g_slist_find(connections, gc)) {
 		struct oscar_data *od = gc->proto_data;
-		struct buddy *buddy = find_buddy(gc->account, data->name);
-		struct group *group = find_group_by_buddy(buddy);
+		struct buddy *buddy = gaim_find_buddy(gc->account, data->name);
+		struct group *group = gaim_find_buddys_group(buddy);
 		if (buddy && group) {
 			debug_printf("ssi: adding buddy %s to group %s\n", buddy->name, group->name);
 			aim_ssi_sendauthrequest(od->sess, od->conn, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list."));
 			if (!aim_ssi_itemlist_finditem(od->sess->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY))
-				aim_ssi_addbuddy(od->sess, od->conn, buddy->name, group->name, get_buddy_alias_only(buddy), NULL, NULL, 1);
+				aim_ssi_addbuddy(od->sess, od->conn, buddy->name, group->name, gaim_get_buddy_alias_only(buddy), NULL, NULL, 1);
 		}
 	}
 }
@@ -2233,9 +2233,9 @@
 	struct buddy *buddy;
 	gchar *dialog_msg, *nombre;
 
-	buddy = find_buddy(gc->account, name);
-	if (buddy && (get_buddy_alias_only(buddy)))
-		nombre = g_strdup_printf("%s (%s)", name, get_buddy_alias_only(buddy));
+	buddy = gaim_find_buddy(gc->account, name);
+	if (buddy && (gaim_get_buddy_alias_only(buddy)))
+		nombre = g_strdup_printf("%s (%s)", name, gaim_get_buddy_alias_only(buddy));
 	else
 		nombre = g_strdup(name);
 
@@ -2259,9 +2259,9 @@
 		struct buddy *buddy;
 		gchar message;
 		message = 0;
-		buddy = find_buddy(gc->account, data->name);
+		buddy = gaim_find_buddy(gc->account, data->name);
 		aim_im_sendch4(od->sess, data->name, AIM_ICQMSG_AUTHGRANTED, &message);
-		show_got_added(gc, NULL, data->name, (buddy ? get_buddy_alias_only(buddy) : NULL), NULL);
+		show_got_added(gc, NULL, data->name, (buddy ? gaim_get_buddy_alias_only(buddy) : NULL), NULL);
 #else
 		aim_ssi_sendauthreply(od->sess, od->conn, data->name, 0x01, NULL);
 #endif
@@ -3948,13 +3948,10 @@
 static void oscar_get_away(struct gaim_connection *g, char *who) {
 	struct oscar_data *od = (struct oscar_data *)g->proto_data;
 	if (od->icq) {
-		struct buddy *budlight = find_buddy(g->account, who);
+		struct buddy *budlight = gaim_find_buddy(g->account, who);
 		if (budlight)
 			if ((budlight->uc & 0xffff0000) >> 16)
-				if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
-					aim_im_sendch2_geticqaway(od->sess, who, (budlight->uc & 0xffff0000) >> 16);
-				else
-					debug_printf("Error: Remote client does not support retrieval of status messages.\n");
+				aim_im_sendch2_geticqaway(od->sess, who, (budlight->uc & 0xffff0000) >> 16);
 			else
 				debug_printf("Error: The user %s has no status message, therefore not requesting.\n", who);
 		else
@@ -4155,11 +4152,11 @@
 	aim_add_buddy(od->sess, od->conn, name);
 #else
 	if ((od->sess->ssi.received_data) && !(aim_ssi_itemlist_exists(od->sess->ssi.local, name))) {
-		struct buddy *buddy = find_buddy(gc->account, name);
-		struct group *group = find_group_by_buddy(buddy);
+		struct buddy *buddy = gaim_find_buddy(gc->account, name);
+		struct group *group = gaim_find_buddys_group(buddy);
 		if (buddy && group) {
 			debug_printf("ssi: adding buddy %s to group %s\n", name, group->name);
-			aim_ssi_addbuddy(od->sess, od->conn, buddy->name, group->name, get_buddy_alias_only(buddy), NULL, NULL, 0);
+			aim_ssi_addbuddy(od->sess, od->conn, buddy->name, group->name, gaim_get_buddy_alias_only(buddy), NULL, NULL, 0);
 		}
 	}
 #endif
@@ -4182,11 +4179,11 @@
 #else
 	if (od->sess->ssi.received_data) {
 		while (buddies) {
-			struct buddy *buddy = find_buddy(gc->account, (const char *)buddies->data);
-			struct group *group = find_group_by_buddy(buddy);
+			struct buddy *buddy = gaim_find_buddy(gc->account, (const char *)buddies->data);
+			struct group *group = gaim_find_buddys_group(buddy);
 			if (buddy && group) {
 				debug_printf("ssi: adding buddy %s to group %s\n", (const char *)buddies->data, group->name);
-				aim_ssi_addbuddy(od->sess, od->conn, buddy->name, group->name, get_buddy_alias_only(buddy), NULL, NULL, 0);
+				aim_ssi_addbuddy(od->sess, od->conn, buddy->name, group->name, gaim_get_buddy_alias_only(buddy), NULL, NULL, 0);
 			}
 			buddies = buddies->next;
 		}
@@ -4342,7 +4339,7 @@
 					char *gname_utf8 = gaim_try_conv_to_utf8(gname);
 					char *alias = aim_ssi_getalias(sess->ssi.local, gname, curitem->name);
 					char *alias_utf8 = gaim_try_conv_to_utf8(alias);
-					struct buddy *buddy = find_buddy(gc->account, curitem->name);
+					struct buddy *buddy = gaim_find_buddy(gc->account, curitem->name);
 					/* Should gname be freed here? -- elb */
 					free(alias);
 					if (buddy) {
@@ -4350,8 +4347,14 @@
 						if (alias_utf8)
 							strcpy(buddy->alias, alias_utf8);
 					} else {
+						struct group *g;
+						buddy = gaim_buddy_new(gc->account, curitem->name, alias_utf8);
+						
+						if (!(g = gaim_find_group(gname_utf8 ? gname_utf8 : _("Orphans"))))
+							g = gaim_group_new(gname_utf8 ? gname_utf8 : _("Orphans"));
+						
 						debug_printf("ssi: adding buddy %s to group %s to local list\n", curitem->name, gname);
-						add_buddy(gc->account, (gname_utf8 ? gname_utf8 : "orphans"), curitem->name, alias_utf8);
+						gaim_blist_add_buddy(buddy, g, NULL);
 						tmp++;
 					}
 					free(gname_utf8);
@@ -4433,7 +4436,7 @@
 						free(alias);
 					} else {
 						debug_printf("ssi: adding buddy %s from local list to server list\n", buddy->name);
-						aim_ssi_addbuddy(sess, od->conn, buddy->name, group->name, get_buddy_alias_only(buddy), NULL, NULL, 0);
+						aim_ssi_addbuddy(sess, od->conn, buddy->name, group->name, gaim_get_buddy_alias_only(buddy), NULL, NULL, 0);
 					}
 				}
 			}
@@ -4541,9 +4544,9 @@
 
 	debug_printf("ssi: %s has given you permission to add him to your buddy list\n", sn);
 
-	buddy = find_buddy(gc->account, sn);
-	if (buddy && (get_buddy_alias_only(buddy)))
-		nombre = g_strdup_printf("%s (%s)", sn, get_buddy_alias_only(buddy));
+	buddy = gaim_find_buddy(gc->account, sn);
+	if (buddy && (gaim_get_buddy_alias_only(buddy)))
+		nombre = g_strdup_printf("%s (%s)", sn, gaim_get_buddy_alias_only(buddy));
 	else
 		nombre = g_strdup(sn);
 
@@ -4575,9 +4578,9 @@
 
 	debug_printf("ssi: received authorization request from %s\n", sn);
 
-	buddy = find_buddy(gc->account, sn);
-	if (buddy && (get_buddy_alias_only(buddy)))
-		nombre = g_strdup_printf("%s (%s)", sn, get_buddy_alias_only(buddy));
+	buddy = gaim_find_buddy(gc->account, sn);
+	if (buddy && (gaim_get_buddy_alias_only(buddy)))
+		nombre = g_strdup_printf("%s (%s)", sn, gaim_get_buddy_alias_only(buddy));
 	else
 		nombre = g_strdup(sn);
 
@@ -4610,9 +4613,9 @@
 
 	debug_printf("ssi: received authorization reply from %s.  Reply is 0x%04hhx\n", sn, reply);
 
-	buddy = find_buddy(gc->account, sn);
-	if (buddy && (get_buddy_alias_only(buddy)))
-		nombre = g_strdup_printf("%s (%s)", sn, get_buddy_alias_only(buddy));
+	buddy = gaim_find_buddy(gc->account, sn);
+	if (buddy && (gaim_get_buddy_alias_only(buddy)))
+		nombre = g_strdup_printf("%s (%s)", sn, gaim_get_buddy_alias_only(buddy));
 	else
 		nombre = g_strdup(sn);
 
@@ -4641,9 +4644,9 @@
 	sn = va_arg(ap, char *);
 	va_end(ap);
 
-	buddy = find_buddy(gc->account, sn);
+	buddy = gaim_find_buddy(gc->account, sn);
 	debug_printf("ssi: %s added you to their buddy list\n", sn);
-	show_got_added(gc, NULL, sn, (buddy ? get_buddy_alias_only(buddy) : NULL), NULL);
+	show_got_added(gc, NULL, sn, (buddy ? gaim_get_buddy_alias_only(buddy) : NULL), NULL);
 
 	return 1;
 }
@@ -4799,8 +4802,41 @@
 	return 0;
 }
 
-static char **oscar_list_icon(int uc) {
-	if (uc == 0)
+static const char *oscar_list_icon(struct gaim_account *a, struct buddy *b) {
+	if (!b) {
+		if (isdigit(a->username[0]))
+			return "icq";
+		else
+			return "aim";
+	}
+				
+	if (isdigit(b->name[0]))
+		return "icq";
+	return "aim";
+}
+
+static const char **oscar_list_emblems(struct buddy *b, char **se, char **sw, char **nw, char **ne)
+{
+	char *emblems[4] = {NULL,NULL,NULL,NULL};
+	int i = 0;
+
+	if (b->uc & UC_UNAVAILABLE) 
+		emblems[i++] = "away";
+	if (b->uc & UC_WIRELESS)
+		emblems[i++] = "wireless";
+	if (b->uc & UC_AOL)
+		emblems[i++] = "aol";
+	if (b->uc & UC_ADMIN)
+		emblems[i++] = "admin";
+	if (b->uc & UC_AB && i < 4)
+		emblems[i++] = "activebuddy";
+	*se = emblems[0];
+	*sw = emblems[1];
+	*nw = emblems[2];
+	*ne = emblems[3];
+}
+
+/*	if (uc == 0)
 		return (char **)icon_online_xpm;
 	if (uc & 0xffff0000) {
 		uc >>= 16;
@@ -4833,7 +4869,8 @@
 	if (uc & UC_NORMAL)
 		return (char **)free_icon_xpm;
 	return NULL;
-}
+*/
+
 
 /*
  * We have just established a socket with the other dude, so set up some handlers.
@@ -5016,12 +5053,9 @@
 	struct oscar_data *od = gc->proto_data;
 	od->evilhack = g_slist_append(od->evilhack, g_strdup(normalize(who)));
 	if (od->icq) {
-		struct buddy *budlight = find_buddy(gc->account, who);
+		struct buddy *budlight = gaim_find_buddy(gc->account, who);
 		if (budlight)
-			if ((budlight->uc >> 16) & (AIM_ICQ_STATE_AWAY || AIM_ICQ_STATE_DND || AIM_ICQ_STATE_OUT || AIM_ICQ_STATE_BUSY || AIM_ICQ_STATE_CHAT))
-				if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
-					aim_im_sendch2_geticqaway(od->sess, who, (budlight->uc & 0xffff0000) >> 16);
-				else {
+			if ((budlight->uc >> 16) & (AIM_ICQ_STATE_AWAY || AIM_ICQ_STATE_DND || AIM_ICQ_STATE_OUT || AIM_ICQ_STATE_BUSY || AIM_ICQ_STATE_CHAT)) {
 					char *state_msg = gaim_icq_status((budlight->uc & 0xffff0000) >> 16);
 					char *dialog_msg = g_strdup_printf(_("<B>UIN:</B> %s<BR><B>Status:</B> %s<HR><I>Remote client does not support sending status messages.</I><BR>"), who, state_msg);
 					g_show_info_text(gc, who, 2, dialog_msg, NULL);
@@ -5049,7 +5083,7 @@
 	int at;
 
 	switch(gc->account->permdeny) {
-	case 1:
+	case 1: 
 		aim_bos_changevisibility(od->sess, od->conn, AIM_VISIBILITYCHANGE_DENYADD, gc->username);
 		break;
 	case 2:
@@ -5185,7 +5219,7 @@
 		m = g_list_append(m, pbm);
 #endif
 	} else {
-		struct buddy *b = find_buddy(gc->account, who);
+		struct buddy *b = gaim_find_buddy(gc->account, who);
 
 		if (!b || (b->uc & UC_UNAVAILABLE)) {
 			pbm = g_new0(struct proto_buddy_menu, 1);
@@ -5329,8 +5363,8 @@
 		for (curb=group->members; curb; curb=g_slist_next(curb)) {
 			struct buddy *buddy = curb->data;
 			if (buddy->account == gc->account && aim_ssi_waitingforauth(od->sess->ssi.local, group->name, buddy->name)) {
-				if (get_buddy_alias_only(buddy))
-					nombre = g_strdup_printf(" %s (%s)", buddy->name, get_buddy_alias_only(buddy));
+				if (gaim_get_buddy_alias_only(buddy))
+					nombre = g_strdup_printf(" %s (%s)", buddy->name, gaim_get_buddy_alias_only(buddy));
 				else
 					nombre = g_strdup_printf(" %s", buddy->name);
 				tmp = g_strdup_printf("%s<BR>%s", text, nombre);
@@ -5545,6 +5579,7 @@
 	ret->options = OPT_PROTO_MAIL_CHECK | OPT_PROTO_BUDDY_ICON | OPT_PROTO_IM_IMAGE;
 	ret->name = g_strdup("AIM/ICQ");
 	ret->list_icon = oscar_list_icon;
+	ret->list_emblems = oscar_list_emblems;
 	ret->away_states = oscar_away_states;
 	ret->actions = oscar_actions;
 	ret->buddy_menu = oscar_buddy_menu;
--- a/src/protocols/toc/toc.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/toc/toc.c	Mon Mar 10 05:30:31 2003 +0000
@@ -272,6 +272,50 @@
 	g_free(gc->proto_data);
 }
 
+static void toc_build_config(struct gaim_account *account, char *s, int len, gboolean show)
+{
+	GSList *grp = groups;
+	GSList *mem;
+	struct group *g;
+	struct buddy *b;
+	GSList *plist = account->permit;
+	GSList *dlist = account->deny;
+
+	int pos = 0;
+
+	if (!account->permdeny)
+		account->permdeny = 1;
+
+	pos += g_snprintf(&s[pos], len - pos, "m %d\n", account->permdeny);
+	while (len > pos && grp) {
+		g = (struct group *)grp->data;
+		if(gaim_group_on_account(g, account)) {
+			pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name);
+			mem = g->members;
+			while (len > pos && mem) {
+				b = (struct buddy *)mem->data;
+				if(b->account == account) {
+					pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", b->name,
+							(show && b->alias[0]) ? ":" : "",
+							(show && b->alias[0]) ? b->alias : "");
+				}
+				mem = mem->next;
+			}
+		}
+		grp = g_slist_next(grp);
+	}
+
+	while (len > pos && plist) {
+		pos += g_snprintf(&s[pos], len - pos, "p %s\n", (char *)plist->data);
+		plist = plist->next;
+	}
+
+	while (len > pos && dlist) {
+		pos += g_snprintf(&s[pos], len - pos, "d %s\n", (char *)dlist->data);
+		dlist = dlist->next;
+	}
+}
+
 static int escape_message(char *msg)
 {
 	char *c, *cpy;
@@ -1241,8 +1285,11 @@
 	sflap_send(gc, "", 0, TYPE_KEEPALIVE);
 }
 
-static char **toc_list_icon(int uc)
+static const char *toc_list_icon(struct gaim_account *a, struct buddy *b)
 {
+	return "aim";
+}
+/*
 	if (uc & UC_UNAVAILABLE)
 		return (char **)away_icon_xpm;
 	if (uc & UC_AOL)
@@ -1256,7 +1303,7 @@
 	if (uc & UC_WIRELESS)
 		return (char **)wireless_icon_xpm;
 	return NULL;
-}
+	}*/
 
 static GList *toc_buddy_menu(struct gaim_connection *gc, char *who)
 {
@@ -1286,7 +1333,6 @@
 	g_snprintf(buf2, sizeof(buf2), "toc_add_permit %s", normalize(who));
 	sflap_send(gc, buf2, -1, TYPE_DATA);
 	toc_set_config(gc);
-	signoff_blocked(gc);
 }
 
 static void toc_add_deny(struct gaim_connection *gc, const char *who)
@@ -1297,7 +1343,6 @@
 	g_snprintf(buf2, sizeof(buf2), "toc_add_deny %s", normalize(who));
 	sflap_send(gc, buf2, -1, TYPE_DATA);
 	toc_set_config(gc);
-	signoff_blocked(gc);
 }
 
 static void toc_set_permit_deny(struct gaim_connection *gc)
@@ -1363,7 +1408,6 @@
 		break;
 	}
 	toc_set_config(gc);
-	signoff_blocked(gc);
 }
 
 static void toc_rem_permit(struct gaim_connection *gc, const char *who)
--- a/src/protocols/yahoo/yahoo.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/yahoo/yahoo.c	Mon Mar 10 05:30:31 2003 +0000
@@ -475,8 +475,10 @@
 			}
 			buddies = g_strsplit(split[1], ",", -1);
 			for (bud = buddies; bud && *bud; bud++)
-				if (!find_buddy(gc->account, *bud)) {
-					add_buddy(gc->account, split[0], *bud, *bud);
+				if (!gaim_find_buddy(gc->account, *bud)) {
+					struct buddy *b = gaim_buddy_new(gc->account, *bud, NULL);
+					struct group *g = gaim_group_new(split[0]);
+					gaim_blist_add_buddy(b,g,NULL);
 					export = TRUE;
 				}
 			g_strfreev(buddies);
@@ -519,7 +521,7 @@
 		else
 			serv_got_typing_stopped(gc, from);
 	} else if (!g_strncasecmp(msg, "GAME", strlen("GAME"))) {
-		struct buddy *bud = find_buddy(gc->account, from);
+		struct buddy *bud = gaim_find_buddy(gc->account, from);
 		void *free1=NULL, *free2=NULL;
 		if (!bud)
 			debug_printf("%s is playing a game, and doesn't want you to know.\n", from);
@@ -1009,16 +1011,19 @@
 	g_free(yd);
 }
 
-static char **yahoo_list_icon(int uc)
+static const char *yahoo_list_icon(struct gaim_account *a, struct buddy *b)
 {
-	if ((uc >> 2) == YAHOO_STATUS_IDLE)
-		return status_idle_xpm;
-	else if (uc & UC_UNAVAILABLE)
-		return status_away_xpm;
-	else if (uc & YAHOO_STATUS_GAME)
-		return status_game_xpm;
-	return status_here_xpm;
+	return "yahoo";
 }
+/*
+  if ((uc >> 2) == YAHOO_STATUS_IDLE)
+  return status_idle_xpm;
+  else if (uc & UC_UNAVAILABLE)
+  return status_away_xpm;
+  else if (uc & YAHOO_STATUS_GAME)
+  return status_game_xpm;
+  return status_here_xpm;
+  }*/
 
 static char *yahoo_get_status_string(enum yahoo_status a)
 {
@@ -1069,7 +1074,7 @@
 	GList *m = NULL;
 	struct proto_buddy_menu *pbm;
 	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
-	struct buddy *b = find_buddy(gc->account, who); /* this should never be null. if it is,
+	struct buddy *b = gaim_find_buddy(gc->account, who); /* this should never be null. if it is,
 						  segfault and get the bug report. */
 	static char buf[1024];
 	static char buf2[1024];
@@ -1311,7 +1316,7 @@
 	if (!yd->logged_in)
 		return;
 
-	g = find_group_by_buddy(find_buddy(gc->account, who));
+	g = gaim_find_buddys_group(gaim_find_buddy(gc->account, who));
 	if (g)
 		group = g->name;
 	else
--- a/src/protocols/zephyr/zephyr.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/protocols/zephyr/zephyr.c	Mon Mar 10 05:30:31 2003 +0000
@@ -320,10 +320,10 @@
 
 			if (ZParseLocations(&notice, NULL, &nlocs, &user) != ZERR_NONE)
 				return;
-			if ((b = find_buddy(zgc->account, user)) == NULL) {
+			if ((b = gaim_find_buddy(zgc->account, user)) == NULL) {
 				char *e = strchr(user, '@');
 				if (e) *e = '\0';
-				b = find_buddy(zgc->account, user);
+				b = gaim_find_buddy(zgc->account, user);
 			}
 			if (!b) {
 				free(user);
@@ -366,7 +366,7 @@
 			buf2 = zephyr_to_html(buf);
 			g_free(buf);
 			if (!g_strcasecmp(notice.z_class, "MESSAGE") &&
-					!g_strcasecmp(notice.z_class_inst, "PERSONAL")) {
+                            !g_strcasecmp(notice.z_class_inst, "PERSONAL")) {
 				if (!g_strcasecmp(notice.z_message, "Automated reply:"))
 					away = TRUE;
 				else
@@ -375,7 +375,7 @@
 			} else {
 				zephyr_triple *zt1, *zt2;
 				zt1 = new_triple(notice.z_class, notice.z_class_inst,
-								notice.z_recipient);
+                                                 notice.z_recipient);
 				zt2 = find_sub_by_triple(zt1);
 				if (!zt2) {
 					/* we shouldn't be subscribed to this message. ignore. */
@@ -402,7 +402,7 @@
 						send_inst = g_strdup_printf("%s %s",sendertmp,notice.z_class_inst);
 					}
 					serv_got_chat_in(zgc, zt2->id, send_inst, FALSE,
-								buf2, time(NULL));
+                                                         buf2, time(NULL));
 					g_free(sendertmp);
 					g_free(send_inst);
 				}
@@ -569,13 +569,17 @@
 {
 	FILE *fd;
 	gchar buff[BUFSIZ], *filename;
-
+        struct group *g = gaim_group_new("Anyone");
+        struct buddy *b;
+        
 	filename = g_strconcat(gaim_home_dir(), "/.anyone", NULL);
 	if ((fd = fopen(filename, "r")) != NULL) {
 		while (fgets(buff, BUFSIZ, fd)) {
 			strip_comments(buff);
-			if (buff[0])
-				add_buddy(zgc->account, "Anyone", buff, buff);
+			if (buff[0]) {
+                                b = gaim_buddy_new(zgc->account, buff, NULL);
+				gaim_blist_add_buddy(b, g, NULL);
+                        }
 		}
 		fclose(fd);
 	}
--- a/src/prpl.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/prpl.c	Mon Mar 10 05:30:31 2003 +0000
@@ -20,6 +20,7 @@
  */
 
 #include "gaim.h"
+#include "gtkutils.h"
 #include "prpl.h"
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -590,6 +591,24 @@
 	/* Update the buddy icon for this user. */
 	conv = gaim_find_conversation(who);
 
+	/* XXX Buddy Icon should probalby be part of struct buddy instead of this weird global
+	 * linked list stuff. */
+
+	if (gaim_find_buddy(gc->account, who)) { 
+		/* This is one of our buddies, so we'll cache this icon for our buddy list */
+		
+		/* Because only OSCAR does buddy icons right now, I don't feel so bad doing nothing to
+		   save what protocol this is from. */
+		char *filename = g_build_filename(gaim_user_dir(), "icons", normalize(who), NULL);
+		FILE *file = NULL;
+
+		file = fopen(filename, "wb");
+		if (!file)
+			return;
+		fwrite(data, 1, len, file);
+		fclose(file);
+	}
+	
 	if (conv != NULL && gaim_conversation_get_gc(conv) == gc)
 		gaim_gtkconv_update_buddy_icon(conv);
 }
@@ -652,7 +671,7 @@
 {
 	char buf[BUF_LONG];
 	struct got_add *ga = g_new0(struct got_add, 1);
-	struct buddy *b = find_buddy(gc->account, who);
+	struct buddy *b = gaim_find_buddy(gc->account, who);
 
 	ga->gc = gc;
 	ga->who = g_strdup(who);
--- a/src/prpl.h	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/prpl.h	Mon Mar 10 05:30:31 2003 +0000
@@ -179,8 +179,18 @@
 	struct gaim_plugin *plug;     /**< The base plugin structure. */
 	char *name;
 
-	/** Returns the XPM associated with the given user class. */
-	char **(* list_icon)(int);
+	/** 
+	 * Returns the base icon name for the given buddy and account.  
+	 * If buddy is NULL, it will return the name to use for the account's icon
+	 */
+	const char *(* list_icon)(struct gaim_account *account, struct buddy *buddy);
+
+	/**
+	 * Fills the four char**'s with string identifiers for "emblems" that the UI will
+	 * interpret and display as relevant
+	 */
+	void (* list_emblems)(struct buddy *buddy, char **se, char **sw, char **nw, char **ne);
+	
 	GList *(* away_states)(struct gaim_connection *gc);
 	GList *(* actions)(struct gaim_connection *gc);
 	/* user_opts is a GList* of g_malloc'd struct proto_user_opts */
--- a/src/server.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/server.c	Mon Mar 10 05:30:31 2003 +0000
@@ -39,6 +39,8 @@
 #include "pixmaps/cancel.xpm"
 #include "pixmaps/tb_search.xpm"
 
+#include "pounce.h"
+
 void serv_login(struct gaim_account *account)
 {
 	struct prpl *p = find_prpl(account->protocol);
@@ -351,16 +353,19 @@
 }
 
 void serv_got_alias(struct gaim_connection *gc, char *who, char *alias) {
-	struct buddy *b = find_buddy(gc->account, who);
+	struct buddy *b = gaim_find_buddy(gc->account, who);
 	if(!b)
 		return;
 
+	if (b->server_alias)
+		g_free(b->server_alias);
+
 	if(alias)
-		g_snprintf(b->server_alias, sizeof(b->server_alias), "%s", alias);
+		b->server_alias = g_strdup(alias);
 	else
-		b->server_alias[0] = '\0';
+	       b->server_alias = NULL;
 
-	handle_buddy_rename(b, b->name);
+	//gaim_blist_rename_buddy(b, b->name);
 }
 
 /*
@@ -656,8 +661,8 @@
 	if (gc->away) {
 		time_t t;
 		char *tmpmsg;
-		struct buddy *b = find_buddy(gc->account, name);
-		char *alias = b ? get_buddy_alias(b) : name;
+		struct buddy *b = gaim_find_buddy(gc->account, name);
+		char *alias = b ? gaim_get_buddy_alias(b) : name;
 		int row;
 		struct queued_away_response *qar;
 
@@ -845,14 +850,14 @@
 void serv_got_update(struct gaim_connection *gc, char *name, int loggedin,
 					 int evil, time_t signon, time_t idle, int type, guint caps)
 {
-	struct buddy *b = find_buddy(gc->account, name);
+	struct buddy *b = gaim_find_buddy(gc->account, name);
 
 	if (signon && (gc->prpl->options & OPT_PROTO_CORRECT_TIME)) {
 		char *tmp = g_strdup(normalize(name));
 		if (!g_strcasecmp(tmp, normalize(gc->username))) {
 			gc->evil = evil;
 			gc->correction_time = (signon - gc->login_time);
-			update_idle_times();
+			/*update_idle_times();*/
 		}
 		g_free(tmp);
 	}
@@ -866,11 +871,8 @@
 	/* server with what's in our record.  We want to */
 	/* store things how THEY want it... */
 	if (strcmp(name, b->name)) {
-		char *who = g_strdup(b->name);
-		g_snprintf(b->name, sizeof(b->name), "%s", name);
-		handle_buddy_rename(b, who);
+		gaim_blist_rename_buddy(b, name);
 		gaim_blist_save();
-		g_free(who);
 	}
 
 	if (!b->idle && idle) {
@@ -883,8 +885,8 @@
 		system_log(log_unidle, gc, b, OPT_LOG_BUDDY_IDLE);
 	}
 
-	b->idle = idle;
-	b->evil = evil;
+	gaim_blist_update_buddy_idle(b, idle);
+	gaim_blist_update_buddy_evil(b, evil);
 
 	if ((b->uc & UC_UNAVAILABLE) && !(type & UC_UNAVAILABLE)) {
 		do_pounce(gc, b->name, OPT_POUNCE_UNAWAY);
@@ -895,15 +897,13 @@
 		system_log(log_away, gc, b, OPT_LOG_BUDDY_AWAY);
 	}
 
-	b->uc = type;
-	if (caps)
-		b->caps = caps;
-
-	b->signon = signon;
+	gaim_blist_update_buddy_status(b, type);
+	
+	gaim_blist_update_buddy_presence(b, loggedin);
 
 	if (loggedin) {
 		if (!b->present) {
-			b->present = 1;
+			//b->present = 1;
 			do_pounce(gc, b->name, OPT_POUNCE_SIGNON);
 			plugin_event(event_buddy_signon, gc, b->name);
 			system_log(log_signon, gc, b, OPT_LOG_BUDDY_SIGNON);
@@ -915,8 +915,6 @@
 		}
 		b->present = 0;
 	}
-
-	set_buddy(gc, b);
 }
 
 
--- a/src/stock.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/stock.c	Mon Mar 10 05:30:31 2003 +0000
@@ -54,7 +54,10 @@
 	{ GAIM_STOCK_TEXT_NORMAL,   "buttons", "text_normal.png"          },
 	{ GAIM_STOCK_TEXT_SMALLER,  "buttons", "text_smaller.png"         },
 	{ GAIM_STOCK_UPLOAD,        NULL,      GTK_STOCK_GO_UP            },
-	{ GAIM_STOCK_WARN,          NULL,      GTK_STOCK_DIALOG_WARNING   }
+	{ GAIM_STOCK_WARN,          NULL,      GTK_STOCK_DIALOG_WARNING   },
+	{ GAIM_STOCK_IM,            NULL,      GTK_STOCK_CONVERT          },
+	{ GAIM_STOCK_CHAT,          NULL,      GTK_STOCK_JUMP_TO          },
+	{ GAIM_STOCK_AWAY,          "buttons",      "away.xpm"                 }
 };
 
 static gint stock_icon_count = sizeof(stock_icons) / sizeof(*stock_icons);
--- a/src/stock.h	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/stock.h	Mon Mar 10 05:30:31 2003 +0000
@@ -45,6 +45,9 @@
 #define GAIM_STOCK_TEXT_SMALLER   "gaim-text-smaller"
 #define GAIM_STOCK_UPLOAD         "gaim-upload"
 #define GAIM_STOCK_WARN           "gaim-warn"
+#define GAIM_STOCK_IM             "gaim-im"
+#define GAIM_STOCK_CHAT           "gaim-chat"
+#define GAIM_STOCK_AWAY           "gaim-away"
 /*@}*/
 
 /**
--- a/src/ui.h	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/ui.h	Mon Mar 10 05:30:31 2003 +0000
@@ -32,6 +32,7 @@
 #include "core.h"
 #include "multi.h"
 #include "gtkconv.h"
+#include "pounce.h"
 #include "gtkft.h"
 #include "gtkutils.h"
 #include "stock.h"
@@ -211,23 +212,6 @@
 	char message[2048];
 };
 
-/****************************
- * I thought I'd place these here by the same reasoning used above (for away_message)
- * This helps aleviate warnings from dialogs.c where the show_new_bp function references
- * buddy_pounce in the parameter list when ui.h doesn't know about buddy_pounce
- * **************************
- */
-struct buddy_pounce {
-        char name[80];
-        char message[2048];
-        char command[2048];
-        char sound[2048];
-        
-        char pouncer[80];
-        int protocol;
-
-        int options;
-};
 
 
 /* this is used for queuing messages received while away. This is really a UI function
@@ -261,6 +245,7 @@
 extern GList *log_conversations; /* this should be moved to conversations.c */
 extern GSList *away_messages; /* this should be moved to away.c */
 extern GtkWidget *mainwindow;
+extern int docklet_count;
 
 /* Globals in away.c */
 extern struct away_message *awaymessage;
@@ -270,12 +255,6 @@
 extern GtkWidget *awayqueue;
 extern GtkListStore *awayqueuestore;
 
-/* Globals in buddy.c */
-extern GtkWidget *buddies;
-extern GtkWidget *bpmenu;
-extern GtkWidget *blist;
-extern int docklet_count;
-
 /* Globals in buddy_chat.c */
 #if 0
 extern GList *chats;	/* list of all chats (only use for tabbing!) */
--- a/src/util.c	Mon Mar 10 04:51:10 2003 +0000
+++ b/src/util.c	Mon Mar 10 05:30:31 2003 +0000
@@ -45,6 +45,7 @@
 #include <math.h>
 #include "gaim.h"
 #include "prpl.h"
+#include "gtklist.h"
 
 #include <sys/socket.h>
 #include <arpa/inet.h>
@@ -815,7 +816,7 @@
 	GSList *awy = away_messages;
 	struct away_message *a, *message = NULL;
 
-	if (!blist) {
+	if (!gtkblist->window) {
 		return;
 	}