src/blist.c

changeset 6695
2a63688f0d6d
parent 6640
007eb21016b4
child 6706
fdd12f90fcf6
--- a/src/blist.c	Tue Sep 02 03:34:37 2003 +0000
+++ b/src/blist.c	Tue Sep 02 03:41:10 2003 +0000
@@ -49,6 +49,7 @@
 		n = n->next;
 	return n;
 }
+
 static GaimBlistNode *gaim_blist_get_last_child(GaimBlistNode *node)
 {
 	if (!node)
@@ -75,18 +76,24 @@
 static void blist_pref_cb(const char *name, GaimPrefType typ, gpointer value, gpointer data)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
-	GaimBlistNode *group, *buddy;
+	GaimBlistNode *gnode, *cnode, *bnode;
 
 	if (!ops)
 		return;
 
-	for(group = gaimbuddylist->root; group; group = group->next) {
-		if(!GAIM_BLIST_NODE_IS_GROUP(group))
+	for(gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
+		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for(buddy = group->child; buddy; buddy = buddy->next) {
-			if(!GAIM_BLIST_NODE_IS_BUDDY(buddy))
-				continue;
-			ops->update(gaimbuddylist, buddy);
+		for(cnode = gnode->child; cnode; cnode = cnode->next) {
+			if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+				for(bnode = cnode->child; bnode; bnode = bnode->next) {
+					if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
+						continue;
+					ops->update(gaimbuddylist, bnode);
+				}
+			} else if(GAIM_BLIST_NODE_IS_CHAT(cnode)) {
+				ops->update(gaimbuddylist, cnode);
+			}
 		}
 	}
 }
@@ -126,7 +133,7 @@
 	return gaimbuddylist;
 }
 
-void  gaim_blist_show () 
+void  gaim_blist_show ()
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 	if (ops)
@@ -147,7 +154,7 @@
 		ops->set_visible(gaimbuddylist, show);
 }
 
-void  gaim_blist_update_buddy_status (struct buddy *buddy, int status)
+void  gaim_blist_update_buddy_status (GaimBuddy *buddy, int status)
 {
 	struct gaim_blist_ui_ops *ops;
 
@@ -168,7 +175,7 @@
 		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
 }
 
-static gboolean presence_update_timeout_cb(struct buddy *buddy) {
+static gboolean presence_update_timeout_cb(GaimBuddy *buddy) {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 	GaimConversation *conv;
 
@@ -195,7 +202,7 @@
 	return FALSE;
 }
 
-void gaim_blist_update_buddy_presence(struct buddy *buddy, int presence) {
+void gaim_blist_update_buddy_presence(GaimBuddy *buddy, int presence) {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 	gboolean do_timer = FALSE;
 
@@ -203,12 +210,16 @@
 		buddy->present = GAIM_BUDDY_SIGNING_ON;
 		gaim_signal_emit(gaim_blist_get_handle(), "buddy-signed-on", buddy);
 		do_timer = TRUE;
-		((struct group *)((GaimBlistNode *)buddy)->parent)->online++;
+		((GaimContact*)((GaimBlistNode*)buddy)->parent)->online++;
+		if(((GaimContact*)((GaimBlistNode*)buddy)->parent)->online == 1)
+			((GaimGroup *)((GaimBlistNode *)buddy)->parent->parent)->online++;
 	} else if(GAIM_BUDDY_IS_ONLINE(buddy) && !presence) {
 		buddy->present = GAIM_BUDDY_SIGNING_OFF;
 		gaim_signal_emit(gaim_blist_get_handle(), "buddy-signed-off", buddy);
 		do_timer = TRUE;
-		((struct group *)((GaimBlistNode *)buddy)->parent)->online--;
+		((GaimContact*)((GaimBlistNode*)buddy)->parent)->online--;
+		if(((GaimContact*)((GaimBlistNode*)buddy)->parent)->online == 0)
+			((GaimGroup *)((GaimBlistNode *)buddy)->parent->parent)->online--;
 	}
 
 	if(do_timer) {
@@ -222,26 +233,29 @@
 }
 
 
-void  gaim_blist_update_buddy_idle (struct buddy *buddy, int idle)
+void  gaim_blist_update_buddy_idle (GaimBuddy *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)
+
+void  gaim_blist_update_buddy_evil (GaimBuddy *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_update_buddy_icon(struct buddy *buddy) {
+
+void gaim_blist_update_buddy_icon(GaimBuddy *buddy) {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 	if(ops)
 		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
 }
-void  gaim_blist_rename_buddy (struct buddy *buddy, const char *name)
+
+void  gaim_blist_rename_buddy (GaimBuddy *buddy, const char *name)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 	g_free(buddy->name);
@@ -250,7 +264,7 @@
 		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
 }
 
-void gaim_blist_alias_chat(struct chat *chat, const char *alias)
+void gaim_blist_alias_chat(GaimBlistChat *chat, const char *alias)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 
@@ -265,7 +279,7 @@
 		ops->update(gaimbuddylist, (GaimBlistNode*)chat);
 }
 
-void  gaim_blist_alias_buddy (struct buddy *buddy, const char *alias)
+void  gaim_blist_alias_buddy (GaimBuddy *buddy, const char *alias)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 	GaimConversation *conv;
@@ -286,7 +300,7 @@
 		gaim_conversation_autoset_title(conv);
 }
 
-void  gaim_blist_server_alias_buddy (struct buddy *buddy, const char *alias)
+void  gaim_blist_server_alias_buddy (GaimBuddy *buddy, const char *alias)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 	GaimConversation *conv;
@@ -307,10 +321,10 @@
 		gaim_conversation_autoset_title(conv);
 }
 
-void gaim_blist_rename_group(struct group *group, const char *name)
+void gaim_blist_rename_group(GaimGroup *group, const char *name)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
-	struct group *dest_group;
+	GaimGroup *dest_group;
 	GaimBlistNode *prev, *child, *next;
 	GSList *accts;
 
@@ -325,11 +339,15 @@
 		while(child)
 		{
 			next = child->next;
-			if(GAIM_BLIST_NODE_IS_BUDDY(child)) {
-				gaim_blist_add_buddy((struct buddy *)child, dest_group, prev);
+			if(GAIM_BLIST_NODE_IS_CONTACT(child)) {
+				GaimBlistNode *bnode;
+				gaim_blist_add_contact((GaimContact *)child, dest_group, prev);
+				for(bnode = child->child; bnode; bnode = bnode->next)
+					gaim_blist_add_buddy((GaimBuddy*)bnode, (GaimContact*)child,
+							NULL, bnode->prev);
 				prev = child;
 			} else if(GAIM_BLIST_NODE_IS_CHAT(child)) {
-				gaim_blist_add_chat((struct chat *)child, dest_group, prev);
+				gaim_blist_add_chat((GaimBlistChat *)child, dest_group, prev);
 				prev = child;
 			} else {
 				gaim_debug(GAIM_DEBUG_ERROR, "blist",
@@ -355,15 +373,15 @@
 	}
 }
 
-struct chat *gaim_chat_new(GaimAccount *account, const char *alias, GHashTable *components)
+GaimBlistChat *gaim_blist_chat_new(GaimAccount *account, const char *alias, GHashTable *components)
 {
-	struct chat *chat;
+	GaimBlistChat *chat;
 	struct gaim_blist_ui_ops *ops;
 
 	if(!components)
 		return NULL;
 
-	chat = g_new0(struct chat, 1);
+	chat = g_new0(GaimBlistChat, 1);
 	chat->account = account;
 	if(alias && strlen(alias))
 		chat->alias = g_strdup(alias);
@@ -381,7 +399,7 @@
 	return chat;
 }
 
-char *gaim_chat_get_display_name(struct chat *chat)
+char *gaim_blist_chat_get_display_name(GaimBlistChat *chat)
 {
 	char *name;
 
@@ -408,12 +426,12 @@
 	return name;
 }
 
-struct buddy *gaim_buddy_new(GaimAccount *account, const char *screenname, const char *alias)
+GaimBuddy *gaim_buddy_new(GaimAccount *account, const char *screenname, const char *alias)
 {
-	struct buddy *b;
+	GaimBuddy *b;
 	struct gaim_blist_ui_ops *ops;
 
-	b = g_new0(struct buddy, 1);
+	b = g_new0(GaimBuddy, 1);
 	b->account = account;
 	b->name  = g_strdup(screenname);
 	b->alias = g_strdup(alias);
@@ -428,10 +446,10 @@
 	return b;
 }
 
-void gaim_blist_add_chat(struct chat *chat, struct group *group, GaimBlistNode *node)
+void gaim_blist_add_chat(GaimBlistChat *chat, GaimGroup *group, GaimBlistNode *node)
 {
 	GaimBlistNode *n = node, *cnode = (GaimBlistNode*)chat;
-	struct group *g = group;
+	GaimGroup *g = group;
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 	gboolean save = FALSE;
 
@@ -442,7 +460,7 @@
 					gaim_blist_get_last_sibling(gaimbuddylist->root));
 		}
 	} else {
-		g = (struct group*)n->parent;
+		g = (GaimGroup*)n->parent;
 	}
 
 	/* if we're moving to overtop of ourselves, do nothing */
@@ -453,10 +471,10 @@
 		/* This chat was already in the list and is
 		 * being moved.
 		 */
-		((struct group *)cnode->parent)->totalsize--;
+		((GaimGroup *)cnode->parent)->totalsize--;
 		if (gaim_account_is_connected(chat->account)) {
-			((struct group *)cnode->parent)->online--;
-			((struct group *)cnode->parent)->currentsize--;
+			((GaimGroup *)cnode->parent)->online--;
+			((GaimGroup *)cnode->parent)->currentsize--;
 		}
 		if(cnode->next)
 			cnode->next->prev = cnode->prev;
@@ -477,10 +495,10 @@
 		cnode->prev = n;
 		cnode->parent = n->parent;
 		n->next = cnode;
-		((struct group *)n->parent)->totalsize++;
+		((GaimGroup *)n->parent)->totalsize++;
 		if (gaim_account_is_connected(chat->account)) {
-			((struct group *)n->parent)->online++;
-			((struct group *)n->parent)->currentsize++;
+			((GaimGroup *)n->parent)->online++;
+			((GaimGroup *)n->parent)->currentsize++;
 		}
 	} else {
 		if(((GaimBlistNode*)g)->child)
@@ -502,83 +520,111 @@
 		gaim_blist_save();
 }
 
-void  gaim_blist_add_buddy (struct buddy *buddy, struct group *group, GaimBlistNode *node)
+void  gaim_blist_add_buddy (GaimBuddy *buddy, GaimContact *contact, GaimGroup *group, GaimBlistNode *node)
 {
-	GaimBlistNode *n = node, *bnode = (GaimBlistNode*)buddy;
-	struct group *g = group;
+	GaimBlistNode *cnode, *bnode;
+	GaimGroup *g;
+	GaimContact *c;
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	gboolean save = FALSE;
 	struct _gaim_hbuddy *hb;
-	gboolean save = FALSE;
+
+	g_return_if_fail(buddy != NULL);
+
+	bnode = (GaimBlistNode *)buddy;
 
-	if (!n) {
-		if (!g) {
+	/* if we're moving to overtop of ourselves, do nothing */
+	if(bnode == node || (!node && bnode->parent &&
+				contact && bnode->parent == (GaimBlistNode*)contact
+				&& bnode == bnode->parent->child))
+		return;
+
+	if(node && GAIM_BLIST_NODE_IS_BUDDY(node)) {
+		c = (GaimContact*)node->parent;
+		g = (GaimGroup*)node->parent->parent;
+	} else if(contact) {
+		c = contact;
+		g = (GaimGroup*)((GaimBlistNode*)c)->parent;
+	} else  {
+		if(group) {
+			g = group;
+		} else {
 			g = gaim_group_new(_("Buddies"));
 			gaim_blist_add_group(g,
 					gaim_blist_get_last_sibling(gaimbuddylist->root));
 		}
-	} else {
-		g = (struct group*)n->parent;
+		c = gaim_contact_new();
+		gaim_blist_add_contact(c, g,
+				gaim_blist_get_last_child((GaimBlistNode*)g));
 	}
 
-	/* if we're moving to overtop of ourselves, do nothing */
-	if(bnode == n)
-		return;
+	cnode = (GaimBlistNode *)c;
 
-	if (bnode->parent) {
-		/* This buddy was already in the list and is
-		 * being moved.
-		 */
-		((struct group *)bnode->parent)->totalsize--;
-		if (gaim_account_is_connected(buddy->account))
-			((struct group *)bnode->parent)->currentsize--;
-		if (GAIM_BUDDY_IS_ONLINE(buddy))
-			((struct group *)bnode->parent)->online--;
+	if(bnode->parent) {
+		if(GAIM_BUDDY_IS_ONLINE(buddy)) {
+			((GaimContact*)bnode->parent)->online--;
+			if(((GaimContact*)bnode->parent)->online == 0)
+				((GaimGroup*)bnode->parent->parent)->online--;
+		}
+		if(gaim_account_is_connected(buddy->account)) {
+			((GaimContact*)bnode->parent)->currentsize--;
+			if(((GaimContact*)bnode->parent)->currentsize == 0)
+				((GaimGroup*)bnode->parent->parent)->currentsize--;
+		}
+		((GaimContact*)bnode->parent)->totalsize--;
+		/* the group totalsize will be taken care of by remove_contact below */
+
+		if(bnode->parent->parent != (GaimBlistNode*)g)
+			serv_move_buddy(buddy, (GaimGroup *)bnode->parent->parent, g);
 
 		if(bnode->next)
 			bnode->next->prev = bnode->prev;
 		if(bnode->prev)
 			bnode->prev->next = bnode->next;
-		if(bnode->parent->child == bnode)
+		if(bnode->parent->child == bnode) {
 			bnode->parent->child = bnode->next;
+			if(!bnode->parent->child)
+				gaim_blist_remove_contact((GaimContact*)bnode->parent);
+		}
 
 		ops->remove(gaimbuddylist, bnode);
 
-		if (bnode->parent != ((GaimBlistNode*)g)) {
-			serv_move_buddy(buddy, (struct group*)bnode->parent, g);
-		}
 		save = TRUE;
 	}
 
-	if (n) {
-		if(n->next)
-			n->next->prev = (GaimBlistNode*)buddy;
-		((GaimBlistNode*)buddy)->next = n->next;
-		((GaimBlistNode*)buddy)->prev = n;
-		((GaimBlistNode*)buddy)->parent = n->parent;
-		n->next = (GaimBlistNode*)buddy;
-		((struct group *)n->parent)->totalsize++;
-		if (gaim_account_is_connected(buddy->account))
-			((struct group *)n->parent)->currentsize++;
-		if (GAIM_BUDDY_IS_ONLINE(buddy))
-			((struct group *)n->parent)->online++;
+	if(node && GAIM_BLIST_NODE_IS_BUDDY(node)) {
+		if(node->next)
+			node->next->prev = bnode;
+		bnode->next = node->next;
+		bnode->prev = node;
+		bnode->parent = node->parent;
+		node->next = bnode;
 	} else {
-		if(((GaimBlistNode*)g)->child)
-			((GaimBlistNode*)g)->child->prev = (GaimBlistNode*)buddy;
-		((GaimBlistNode*)buddy)->prev = NULL;
-		((GaimBlistNode*)buddy)->next = ((GaimBlistNode*)g)->child;
-		((GaimBlistNode*)g)->child = (GaimBlistNode*)buddy;
-		((GaimBlistNode*)buddy)->parent = (GaimBlistNode*)g;
-		g->totalsize++;
-		if (gaim_account_is_connected(buddy->account))
-			g->currentsize++;
-		if (GAIM_BUDDY_IS_ONLINE(buddy))
-			g->online++;
+		if(cnode->child)
+			cnode->child->prev = bnode;
+		bnode->prev = NULL;
+		bnode->next = cnode->child;
+		cnode->child = bnode;
+		bnode->parent = cnode;
 	}
 
+	if(GAIM_BUDDY_IS_ONLINE(buddy)) {
+		((GaimContact*)bnode->parent)->online++;
+		if(((GaimContact*)bnode->parent)->online == 1)
+			((GaimGroup*)bnode->parent->parent)->online++;
+	}
+	if(gaim_account_is_connected(buddy->account)) {
+		((GaimContact*)bnode->parent)->currentsize++;
+		if(((GaimContact*)bnode->parent)->currentsize == 1)
+			((GaimGroup*)bnode->parent->parent)->currentsize++;
+	}
+	((GaimContact*)bnode->parent)->totalsize++;
+
+
 	hb = g_malloc(sizeof(struct _gaim_hbuddy));
 	hb->name = g_strdup(normalize(buddy->name));
 	hb->account = buddy->account;
-	hb->group = ((GaimBlistNode*)buddy)->parent;
+	hb->group = ((GaimBlistNode*)buddy)->parent->parent;
 
 	if (g_hash_table_lookup(gaimbuddylist->buddies, (gpointer)hb)) {
 		/* This guy already exists */
@@ -594,13 +640,28 @@
 		gaim_blist_save();
 }
 
-struct group *gaim_group_new(const char *name)
+GaimContact *gaim_contact_new()
 {
-	struct group *g = gaim_find_group(name);
+	struct gaim_blist_ui_ops *ops;
+	GaimContact *c = g_new0(GaimContact, 1);
+	((GaimBlistNode*)c)->type = GAIM_BLIST_CONTACT_NODE;
+
+	c->totalsize = c->currentsize = c->online = 0;
+
+	ops = gaim_get_blist_ui_ops();
+	if (ops != NULL && ops->new_node != NULL)
+		ops->new_node((GaimBlistNode *)c);
+
+	return c;
+}
+
+GaimGroup *gaim_group_new(const char *name)
+{
+	GaimGroup *g = gaim_find_group(name);
 
 	if (!g) {
 		struct gaim_blist_ui_ops *ops;
-		g= g_new0(struct group, 1);
+		g= g_new0(GaimGroup, 1);
 		g->name = g_strdup(name);
 		g->totalsize = 0;
 		g->currentsize = 0;
@@ -618,7 +679,81 @@
 	return g;
 }
 
-void  gaim_blist_add_group (struct group *group, GaimBlistNode *node)
+void gaim_blist_add_contact(GaimContact *contact, GaimGroup *group, GaimBlistNode *node)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+	GaimGroup *g;
+	GaimBlistNode *gnode, *cnode;
+	gboolean save = FALSE;
+
+	if(!contact)
+		return;
+
+	if(node && (GAIM_BLIST_NODE_IS_CONTACT(node) ||
+				GAIM_BLIST_NODE_IS_CHAT(node)))
+		g = (GaimGroup*)node->parent;
+	else if(group)
+		g = group;
+	else {
+		g = gaim_group_new(_("Buddies"));
+		gaim_blist_add_group(g,
+				gaim_blist_get_last_sibling(gaimbuddylist->root));
+	}
+
+	gnode = (GaimBlistNode*)g;
+	cnode = (GaimBlistNode*)contact;
+
+	if(cnode->parent) {
+
+		ops->remove(gaimbuddylist, cnode);
+
+		if(gnode->child == cnode)
+			gnode->child = cnode->next;
+		if(cnode->prev)
+			cnode->prev->next = cnode->next;
+		if(cnode->next)
+			cnode->next->prev = cnode->prev;
+
+
+		if(contact->online > 0)
+			((GaimGroup*)cnode->parent)->online--;
+		if(contact->currentsize > 0)
+			((GaimGroup*)cnode->parent)->currentsize--;
+		((GaimGroup*)cnode->parent)->totalsize--;
+
+		save = TRUE;
+	}
+
+	if(node && (GAIM_BLIST_NODE_IS_CONTACT(node) ||
+				GAIM_BLIST_NODE_IS_CHAT(node))) {
+		if(node->next)
+			node->next->prev = cnode;
+		cnode->next = node->next;
+		cnode->prev = node;
+		cnode->parent = node->parent;
+		node->next = cnode;
+	} else {
+		if(gnode->child)
+			gnode->child->prev = cnode;
+		cnode->prev = NULL;
+		cnode->next = gnode->child;
+		gnode->child = cnode;
+		cnode->parent = gnode;
+	}
+
+	if(contact->online > 0)
+		g->online++;
+	if(contact->currentsize > 0)
+		g->currentsize++;
+	g->totalsize++;
+
+	if(ops && cnode->child)
+		ops->update(gaimbuddylist, cnode);
+	if (save)
+		gaim_blist_save();
+}
+
+void  gaim_blist_add_group (GaimGroup *group, GaimBlistNode *node)
 {
 	struct gaim_blist_ui_ops *ops;
 	GaimBlistNode *gnode = (GaimBlistNode*)group;
@@ -652,7 +787,7 @@
 		save = TRUE;
 	}
 
-	if (node) {
+	if (node && GAIM_BLIST_NODE_IS_GROUP(node)) {
 		gnode->next = node->next;
 		gnode->prev = node;
 		if(node->next)
@@ -675,33 +810,70 @@
 		gaim_blist_save();
 }
 
-void  gaim_blist_remove_buddy (struct buddy *buddy)
+void gaim_blist_remove_contact(GaimContact* contact)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 
-	GaimBlistNode *gnode, *node = (GaimBlistNode*)buddy;
-	struct group *group;
+	GaimBlistNode *gnode, *cnode = (GaimBlistNode*)contact;
+
+	gnode = cnode->parent;
+
+	if(cnode->child) {
+		while(cnode->child) {
+			gaim_blist_remove_buddy((GaimBuddy*)cnode->child);
+		}
+	} else {
+		if(ops)
+			ops->remove(gaimbuddylist, cnode);
+
+		if(gnode->child == cnode)
+			gnode->child = cnode->next;
+		if(cnode->prev)
+			cnode->prev->next = cnode->next;
+		if(cnode->next)
+			cnode->next->prev = cnode->prev;
+
+		g_free(contact);
+	}
+}
+
+void  gaim_blist_remove_buddy (GaimBuddy *buddy)
+{
+	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
+
+	GaimBlistNode *cnode, *node = (GaimBlistNode*)buddy;
+	GaimGroup *group;
 	struct _gaim_hbuddy hb, *key;
 	struct buddy *val;
 
-	gnode = node->parent;
-	group = (struct group *)gnode;
+	cnode = node->parent;
+	group = (GaimGroup *)cnode->parent;
 
-	if(gnode->child == node)
-		gnode->child = node->next;
+	if(GAIM_BUDDY_IS_ONLINE(buddy)) {
+		((GaimContact*)cnode)->online--;
+		if(((GaimContact*)cnode)->online == 0)
+			group->online--;
+	}
+	if(gaim_account_is_connected(buddy->account)) {
+		((GaimContact*)cnode)->currentsize--;
+		if(((GaimContact*)cnode)->currentsize == 0)
+			group->currentsize--;
+	}
+	((GaimContact*)cnode)->totalsize--;
+
 	if (node->prev)
 		node->prev->next = node->next;
 	if (node->next)
 		node->next->prev = node->prev;
-	group->totalsize--;
-	if (gaim_account_is_connected(buddy->account))
-		group->currentsize--;
-	if (GAIM_BUDDY_IS_ONLINE(buddy))
-		group->online--;
+	if(cnode->child == node) {
+		cnode->child = node->next;
+		if(!cnode->child)
+			gaim_blist_remove_contact((GaimContact*)cnode);
+	}
 
 	hb.name = normalize(buddy->name);
 	hb.account = buddy->account;
-	hb.group = ((GaimBlistNode*)buddy)->parent;
+	hb.group = ((GaimBlistNode*)buddy)->parent->parent;
 	if (g_hash_table_lookup_extended(gaimbuddylist->buddies, &hb, (gpointer *)&key, (gpointer *)&val)) {
 		g_hash_table_remove(gaimbuddylist->buddies, &hb);
 		g_free(key->name);
@@ -718,15 +890,15 @@
 	g_free(buddy);
 }
 
-void  gaim_blist_remove_chat (struct chat *chat)
+void  gaim_blist_remove_chat (GaimBlistChat *chat)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 
 	GaimBlistNode *gnode, *node = (GaimBlistNode*)chat;
-	struct group *group;
+	GaimGroup *group;
 
 	gnode = node->parent;
-	group = (struct group *)gnode;
+	group = (GaimGroup *)gnode;
 
 	if(gnode->child == node)
 		gnode->child = node->next;
@@ -746,7 +918,7 @@
 	g_free(chat);
 }
 
-void  gaim_blist_remove_group (struct group *group)
+void  gaim_blist_remove_group (GaimGroup *group)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
 	GaimBlistNode *node = (GaimBlistNode*)group;
@@ -787,7 +959,36 @@
 	g_free(group);
 }
 
-char *gaim_get_buddy_alias_only(struct buddy *b) {
+GaimBuddy *gaim_contact_get_priority_buddy(GaimContact *contact) {
+	GaimBuddy *top = NULL;
+	GaimBlistNode *bnode;
+
+	for(bnode = ((GaimBlistNode*)contact)->child; bnode; bnode = bnode->next) {
+		GaimBuddy *buddy;
+		if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
+			continue;
+		buddy = (GaimBuddy*)bnode;
+		if(!top) {
+			top = buddy;
+		} else if(GAIM_BUDDY_IS_ONLINE(buddy)) {
+			if(!GAIM_BUDDY_IS_ONLINE(top)) {
+				top = buddy;
+			} else if(!(buddy->uc & UC_UNAVAILABLE) && !buddy->idle &&
+					(top->uc & UC_UNAVAILABLE || top->idle)) {
+				top = buddy;
+			} else if(!buddy->idle && top->idle) {
+				top = buddy;
+			} else if(top->uc & UC_UNAVAILABLE && top->idle &&
+					(!(buddy->uc & UC_UNAVAILABLE) || !buddy->idle)) {
+				top = buddy;
+			}
+		}
+	}
+
+	return top;
+}
+
+const char *gaim_get_buddy_alias_only(GaimBuddy *b) {
 	if(!b)
 		return NULL;
 
@@ -803,9 +1004,9 @@
 	return NULL;
 }
 
-char *  gaim_get_buddy_alias (struct buddy *buddy)
+const char *  gaim_get_buddy_alias (GaimBuddy *buddy)
 {
-	char *ret = gaim_get_buddy_alias_only(buddy);
+	const char *ret = gaim_get_buddy_alias_only(buddy);
 
 	if(!ret)
 		return buddy ? buddy->name : _("Unknown");
@@ -813,9 +1014,9 @@
 	return ret;
 }
 
-struct buddy *gaim_find_buddy(GaimAccount *account, const char *name)
+GaimBuddy *gaim_find_buddy(GaimAccount *account, const char *name)
 {
-	struct buddy *buddy;
+	GaimBuddy *buddy;
 	struct _gaim_hbuddy hb;
 	GaimBlistNode *group;
 
@@ -862,25 +1063,25 @@
 	return ret;
 }
 
-struct group *gaim_find_group(const char *name)
+GaimGroup *gaim_find_group(const char *name)
 {
 	GaimBlistNode *node;
 	if (!gaimbuddylist)
 		return NULL;
 	node = gaimbuddylist->root;
 	while(node) {
-		if (!strcmp(((struct group*)node)->name, name))
-			return (struct group*)node;
+		if (!strcmp(((GaimGroup *)node)->name, name))
+			return (GaimGroup *)node;
 		node = node->next;
 	}
 	return NULL;
 }
 
-struct chat *
+GaimBlistChat *
 gaim_blist_find_chat(GaimAccount *account, const char *name)
 {
 	char *chat_name;
-	struct chat *chat;
+	GaimBlistChat *chat;
 	GaimPlugin *prpl;
 	GaimPluginProtocolInfo *prpl_info = NULL;
 	struct proto_chat_entry *pce;
@@ -894,7 +1095,7 @@
 		for (node = group->child; node != NULL; node = node->next) {
 			if (GAIM_BLIST_NODE_IS_CHAT(node)) {
 
-				chat = (struct chat *)node;
+				chat = (GaimBlistChat*)node;
 
 				prpl = gaim_find_prpl(gaim_account_get_protocol(chat->account));
 				prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl);
@@ -918,97 +1119,126 @@
 	return NULL;
 }
 
-struct group *
-gaim_blist_chat_get_group(struct chat *chat)
+GaimGroup *
+gaim_blist_chat_get_group(GaimBlistChat *chat)
 {
 	g_return_val_if_fail(chat != NULL, NULL);
 
-	return (struct group *)(((GaimBlistNode *)chat)->parent);
+	return (GaimGroup *)(((GaimBlistNode *)chat)->parent);
 }
 
-struct group *gaim_find_buddys_group(struct buddy *buddy)
+GaimGroup *gaim_find_buddys_group(GaimBuddy *buddy)
 {
 	if (!buddy)
 		return NULL;
-	return (struct group*)(((GaimBlistNode*)buddy)->parent);
+	return (GaimGroup *)(((GaimBlistNode*)buddy)->parent->parent);
 }
 
-GSList *gaim_group_get_accounts(struct group *g)
+GSList *gaim_group_get_accounts(GaimGroup *g)
 {
 	GSList *l = NULL;
-	GaimBlistNode *child = ((GaimBlistNode *)g)->child;
+	GaimBlistNode *gnode, *cnode, *bnode;
+
+	gnode = (GaimBlistNode *)g;
 
-	while (child) {
-		GaimAccount *account = NULL;
-		if (GAIM_BLIST_NODE_IS_BUDDY(child))
-			account = ((struct buddy *)child)->account;
-		else if (GAIM_BLIST_NODE_IS_CHAT(child))
-			account = ((struct chat *)child)->account;
-		if (!g_slist_find(l, account))
-			l = g_slist_append(l, account);
-		child = child->next;
+	for(cnode = gnode->child;  cnode; cnode = cnode->next) {
+		if (GAIM_BLIST_NODE_IS_CHAT(cnode)) {
+			if(!g_slist_find(l, ((GaimBlistChat *)cnode)->account))
+				l = g_slist_append(l, ((GaimBlistChat *)cnode)->account);
+		} else if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+			for(bnode = cnode->child; bnode; bnode = bnode->next) {
+				if(GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
+					if(!g_slist_find(l, ((GaimBuddy *)bnode)->account))
+						l = g_slist_append(l, ((GaimBuddy *)bnode)->account);
+				}
+			}
+		}
 	}
+
 	return l;
 }
 
 void gaim_blist_add_account(GaimAccount *account)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
-	GaimBlistNode *group, *buddy;
+	GaimBlistNode *gnode, *cnode, *bnode;
 
 	if(!gaimbuddylist)
 		return;
 
-	for(group = gaimbuddylist->root; group; group = group->next) {
-		if(!GAIM_BLIST_NODE_IS_GROUP(group))
+	if(!ops)
+		return;
+
+	for(gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
+		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for(buddy = group->child; buddy; buddy = buddy->next) {
-			if(GAIM_BLIST_NODE_IS_BUDDY(buddy)) {
-				if (account == ((struct buddy*)buddy)->account) {
-					((struct group *)group)->currentsize++;
-					if(ops)
-						ops->update(gaimbuddylist, buddy);
-				}
-			} else if(GAIM_BLIST_NODE_IS_CHAT(buddy)) {
-				if (account == ((struct chat*)buddy)->account) {
-					((struct group *)group)->online++;
-					((struct group *)group)->currentsize++;
-					if(ops)
-						ops->update(gaimbuddylist, buddy);
-				}
+		for(cnode = gnode->child; cnode; cnode = cnode->next) {
+			if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+					for(bnode = cnode->child; bnode; bnode = bnode->next) {
+						if(GAIM_BLIST_NODE_IS_BUDDY(bnode) &&
+								((GaimBuddy*)bnode)->account == account) {
+							((GaimContact*)cnode)->currentsize++;
+							if(((GaimContact*)cnode)->currentsize == 1)
+								((GaimGroup*)gnode)->currentsize++;
+							if(GAIM_BUDDY_IS_ONLINE((GaimBuddy*)bnode)) {
+								((GaimContact*)cnode)->online++;
+								if(((GaimContact*)cnode)->online == 1)
+									((GaimGroup*)gnode)->online++;
+							}
+							ops->update(gaimbuddylist, bnode);
+						}
+					}
+					ops->update(gaimbuddylist, cnode);
+			} else if(GAIM_BLIST_NODE_IS_CHAT(cnode) &&
+					((GaimBlistChat*)cnode)->account == account) {
+					((GaimGroup *)gnode)->online++;
+					((GaimGroup *)gnode)->currentsize++;
+					ops->update(gaimbuddylist, cnode);
 			}
 		}
+		ops->update(gaimbuddylist, gnode);
 	}
 }
 
 void gaim_blist_remove_account(GaimAccount *account)
 {
 	struct gaim_blist_ui_ops *ops = gaimbuddylist->ui_ops;
-	GaimBlistNode *group, *buddy;
+	GaimBlistNode *gnode, *cnode, *bnode;
 
 	if (!gaimbuddylist)
 		return;
 
-	for(group = gaimbuddylist->root; group; group = group->next) {
-		if(!GAIM_BLIST_NODE_IS_GROUP(group))
+	for(gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
+		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for(buddy = group->child; buddy; buddy = buddy->next) {
-			if(GAIM_BLIST_NODE_IS_BUDDY(buddy)) {
-				if (account == ((struct buddy*)buddy)->account) {
-					if (GAIM_BUDDY_IS_ONLINE((struct buddy*)buddy))
-						((struct group *)group)->online--;
-					((struct buddy*)buddy)->present = GAIM_BUDDY_OFFLINE;
-					((struct group *)group)->currentsize--;
-					if(ops)
-						ops->remove(gaimbuddylist, buddy);
+		for(cnode = gnode->child; cnode; cnode = cnode->next) {
+			if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+				for(bnode = cnode->child; bnode; bnode = bnode->next) {
+					if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
+						continue;
+					if(account == ((GaimBuddy *)bnode)->account) {
+						if(((GaimBuddy*)bnode)->present == GAIM_BUDDY_ONLINE ||
+								((GaimBuddy*)bnode)->present == GAIM_BUDDY_SIGNING_ON) {
+							((GaimContact*)cnode)->online--;
+							if(((GaimContact*)cnode)->online == 0)
+								((GaimGroup*)gnode)->online--;
+						}
+						((GaimContact*)cnode)->currentsize--;
+						if(((GaimContact*)cnode)->currentsize == 0)
+							((GaimGroup*)gnode)->currentsize--;
+
+						((GaimBuddy*)bnode)->present = GAIM_BUDDY_OFFLINE;
+
+						if(ops)
+							ops->remove(gaimbuddylist, bnode);
+					}
 				}
-			} else if(GAIM_BLIST_NODE_IS_CHAT(buddy)) {
-				if (account == ((struct chat*)buddy)->account) {
-					((struct group *)group)->online--;
-					((struct group *)group)->currentsize--;
-					if(ops)
-						ops->remove(gaimbuddylist, buddy);
-				}
+			} else if(GAIM_BLIST_NODE_IS_CHAT(cnode) &&
+					((GaimBlistChat*)cnode)->account == account) {
+				((GaimGroup*)gnode)->currentsize--;
+				((GaimGroup*)gnode)->online--;
+				if(ops)
+					ops->remove(gaimbuddylist, cnode);
 			}
 		}
 	}
@@ -1040,7 +1270,7 @@
 					g_free(utf8);
 				}
 				if (!gaim_find_group(current)) {
-					struct group *g = gaim_group_new(current);
+					GaimGroup *g = gaim_group_new(current);
 					gaim_blist_add_group(g,
 							gaim_blist_get_last_sibling(gaimbuddylist->root));
 				}
@@ -1070,9 +1300,9 @@
 				}
 
 				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,
+					GaimBuddy *b = gaim_buddy_new(account, nm, sw);
+					GaimGroup *g = gaim_find_group(current);
+					gaim_blist_add_buddy(b, NULL, g,
 							gaim_blist_get_last_child((GaimBlistNode*)g));
 					bud = g_list_append(bud, g_strdup(nm));
 				}
@@ -1304,7 +1534,7 @@
 		char *file = gaim_user_dir();
 		GaimProtocol prpl_num;
 		int protocol;
-		
+
 		prpl_num = gaim_account_get_protocol(account);
 
 		protocol = prpl_num;
@@ -1394,23 +1624,33 @@
 	}
 }
 
-gboolean gaim_group_on_account(struct group *g, GaimAccount *account) {
-	GaimBlistNode *bnode;
-	for(bnode = g->node.child; bnode; bnode = bnode->next) {
-		struct buddy *b = (struct buddy *)bnode;
-		if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
-			continue;
-		if((!account && gaim_account_is_connected(b->account))
-				|| b->account == account)
-			return TRUE;
+gboolean gaim_group_on_account(GaimGroup *g, GaimAccount *account) {
+	GaimBlistNode *cnode, *bnode;
+	for(cnode = ((GaimBlistNode *)g)->child; cnode; cnode = cnode->next) {
+		if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+			for(bnode = cnode->child; bnode; bnode = bnode->next) {
+				if(GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
+					GaimBuddy *buddy = (GaimBuddy *)bnode;
+					if((!account && gaim_account_is_connected(buddy->account))
+							|| buddy->account == account)
+						return TRUE;
+				}
+			}
+		} else if(GAIM_BLIST_NODE_IS_CHAT(cnode)) {
+			GaimBlistChat *chat = (GaimBlistChat *)cnode;
+			if((!account && gaim_account_is_connected(chat->account))
+					|| chat->account == account)
+				return TRUE;
+		}
 	}
 	return FALSE;
 }
 
 static gboolean blist_safe_to_write = FALSE;
 
+GaimGroup *blist_parser_group = NULL;
+GaimContact *blist_parser_contact = NULL;
 static char *blist_parser_group_name = NULL;
-static char *blist_parser_person_name = NULL;
 static char *blist_parser_account_name = NULL;
 static int blist_parser_account_protocol = 0;
 static char *blist_parser_chat_alias = NULL;
@@ -1432,7 +1672,7 @@
 	BLIST_TAG_GROUP,
 	BLIST_TAG_CHAT,
 	BLIST_TAG_COMPONENT,
-	BLIST_TAG_PERSON,
+	BLIST_TAG_CONTACT,
 	BLIST_TAG_BUDDY,
 	BLIST_TAG_NAME,
 	BLIST_TAG_ALIAS,
@@ -1466,10 +1706,17 @@
 			}
 		}
 		if(blist_parser_group_name) {
-			struct group *g = gaim_group_new(blist_parser_group_name);
-			gaim_blist_add_group(g,
+			blist_parser_group = gaim_group_new(blist_parser_group_name);
+			gaim_blist_add_group(blist_parser_group,
 					gaim_blist_get_last_sibling(gaimbuddylist->root));
 		}
+	} else if(!strcmp(element_name, "contact")) {
+		tag_stack = g_list_prepend(tag_stack,
+				GINT_TO_POINTER(BLIST_TAG_CONTACT));
+
+		blist_parser_contact = gaim_contact_new();
+		gaim_blist_add_contact(blist_parser_contact, blist_parser_group,
+				gaim_blist_get_last_sibling(((GaimBlistNode*)blist_parser_group)->child));
 	} else if(!strcmp(element_name, "chat")) {
 		tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_CHAT));
 		for(i=0; attribute_names[i]; i++) {
@@ -1480,14 +1727,6 @@
 				blist_parser_account_protocol = atoi(attribute_values[i]);
 			}
 		}
-	} else if(!strcmp(element_name, "person")) {
-		tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_PERSON));
-		for(i=0; attribute_names[i]; i++) {
-			if(!strcmp(attribute_names[i], "name")) {
-				g_free(blist_parser_person_name);
-				blist_parser_person_name = g_strdup(attribute_values[i]);
-			}
-		}
 	} else if(!strcmp(element_name, "buddy")) {
 		tag_stack = g_list_prepend(tag_stack, GINT_TO_POINTER(BLIST_TAG_BUDDY));
 		for(i=0; attribute_names[i]; i++) {
@@ -1550,18 +1789,21 @@
 		tag_stack = g_list_delete_link(tag_stack, tag_stack);
 	} else if(!strcmp(element_name, "group")) {
 		if(blist_parser_group_settings) {
-			struct group *g = gaim_find_group(blist_parser_group_name);
+			GaimGroup *g = gaim_find_group(blist_parser_group_name);
 			g_hash_table_destroy(g->settings);
 			g->settings = blist_parser_group_settings;
 		}
 		tag_stack = g_list_delete_link(tag_stack, tag_stack);
 		blist_parser_group_settings = NULL;
+		blist_parser_group = NULL;
+		blist_parser_group_name = NULL;
 	} else if(!strcmp(element_name, "chat")) {
 		GaimAccount *account = gaim_accounts_find(blist_parser_account_name,
 				blist_parser_account_protocol);
 		if(account) {
-			struct chat *chat = gaim_chat_new(account, blist_parser_chat_alias, blist_parser_chat_components);
-			struct group *g = gaim_find_group(blist_parser_group_name);
+			GaimBlistChat *chat = gaim_blist_chat_new(account,
+					blist_parser_chat_alias, blist_parser_chat_components);
+			GaimGroup *g = gaim_find_group(blist_parser_group_name);
 			gaim_blist_add_chat(chat,g,
 					gaim_blist_get_last_child((GaimBlistNode*)g));
 			if(blist_parser_chat_settings) {
@@ -1576,18 +1818,18 @@
 		blist_parser_chat_components = NULL;
 		blist_parser_chat_settings = NULL;
 		tag_stack = g_list_delete_link(tag_stack, tag_stack);
-	} else if(!strcmp(element_name, "person")) {
-		g_free(blist_parser_person_name);
-		blist_parser_person_name = NULL;
+	} else if(!strcmp(element_name, "contact")) {
+		if(blist_parser_contact && !blist_parser_contact->node.child)
+			gaim_blist_remove_contact(blist_parser_contact);
+		blist_parser_contact = NULL;
 		tag_stack = g_list_delete_link(tag_stack, tag_stack);
 	} else if(!strcmp(element_name, "buddy")) {
 		GaimAccount *account = gaim_accounts_find(blist_parser_account_name,
 				blist_parser_account_protocol);
 		if(account) {
-			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,
-					gaim_blist_get_last_child((GaimBlistNode*)g));
+			GaimBuddy *b = gaim_buddy_new(account, blist_parser_buddy_name, blist_parser_buddy_alias);
+			gaim_blist_add_buddy(b,blist_parser_contact, blist_parser_group,
+					gaim_blist_get_last_child((GaimBlistNode*)blist_parser_contact));
 			if(blist_parser_buddy_settings) {
 				g_hash_table_destroy(b->settings);
 				b->settings = blist_parser_buddy_settings;
@@ -1797,24 +2039,6 @@
 			g_free(msg);
 		}
 	} else if(g_list_length(gaim_accounts_get_all())) {
-#if 0
-		GMainContext *ctx;
-
-		/* rob wants to inform the user that their buddy lists are
-		 * being converted */
-		msg = g_strdup_printf(_("Gaim is converting your old buddy lists "
-					"to a new format, which will now be located at %s"),
-				filename);
-		gaim_notify_info(NULL, NULL, _("Converting Buddy List"), msg);
-		g_free(msg);
-
-		/* now, let gtk actually display the dialog before we start anything */
-		ctx = g_main_context_default();
-
-		while(g_main_context_pending(ctx))
-			g_main_context_iteration(ctx, FALSE);
-#endif
-
 		/* read in the old lists, then save to the new format */
 		for(accts = gaim_accounts_get_all(); accts; accts = accts->next) {
 			do_import(accts->data, NULL);
@@ -1861,6 +2085,24 @@
 	g_free(data_val);
 }
 
+static void blist_print_cnode_settings(gpointer key, gpointer data,
+		gpointer user_data) {
+	char *key_val;
+	char *data_val;
+	FILE *file = user_data;
+
+	if(!key || !data)
+		return;
+
+	key_val = g_markup_escape_text(key, -1);
+	data_val = g_markup_escape_text(data, -1);
+
+	fprintf(file, "\t\t\t\t<setting name=\"%s\">%s</setting>\n", key_val,
+			data_val);
+	g_free(key_val);
+	g_free(data_val);
+}
+
 static void blist_print_chat_components(gpointer key, gpointer data,
 		gpointer user_data) {
 	char *key_val;
@@ -1879,54 +2121,62 @@
 	g_free(data_val);
 }
 
+static void print_buddy(FILE *file, GaimBuddy *buddy) {
+	char *bud_name = g_markup_escape_text(buddy->name, -1);
+	char *bud_alias = NULL;
+	char *acct_name = g_markup_escape_text(buddy->account->username, -1);
+	if(buddy->alias)
+		bud_alias= g_markup_escape_text(buddy->alias, -1);
+	fprintf(file, "\t\t\t\t<buddy protocol=\"%d\" "
+			"account=\"%s\">\n",
+			gaim_account_get_protocol(buddy->account),
+			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(buddy->settings, blist_print_buddy_settings, file);
+	fprintf(file, "\t\t\t\t</buddy>\n");
+	g_free(bud_name);
+	g_free(bud_alias);
+	g_free(acct_name);
+}
+
 static void gaim_blist_write(FILE *file, GaimAccount *exp_acct) {
 	GList *accounts;
 	GSList *buds;
-	GaimBlistNode *gnode,*bnode;
-	struct group *group;
-	struct buddy *bud;
+	GaimBlistNode *gnode, *cnode, *bnode;
 	fprintf(file, "<?xml version='1.0' encoding='UTF-8' ?>\n");
 	fprintf(file, "<gaim version=\"1\">\n");
 	fprintf(file, "\t<blist>\n");
 
 	for(gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
+		GaimGroup *group;
+
 		if(!GAIM_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		group = (struct group *)gnode;
+
+		group = (GaimGroup *)gnode;
 		if(!exp_acct || gaim_group_on_account(group, exp_acct)) {
 			char *group_name = g_markup_escape_text(group->name, -1);
 			fprintf(file, "\t\t<group name=\"%s\">\n", group_name);
 			g_hash_table_foreach(group->settings, blist_print_group_settings, file);
-			for(bnode = gnode->child; bnode; bnode = bnode->next) {
-				if(GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
-					bud = (struct buddy *)bnode;
-					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(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",
-								gaim_account_get_protocol(bud->account),
-								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);
+			for(cnode = gnode->child; cnode; cnode = cnode->next) {
+				if(GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+					fprintf(file, "\t\t\t<contact>\n");
+
+					for(bnode = cnode->child; bnode; bnode = bnode->next) {
+						if(GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
+							GaimBuddy *buddy = (GaimBuddy *)bnode;
+							if(!exp_acct || buddy->account == exp_acct) {
+								print_buddy(file, buddy);
+							}
 						}
-						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");
-						g_free(bud_name);
-						g_free(bud_alias);
-						g_free(acct_name);
 					}
-				} else if(GAIM_BLIST_NODE_IS_CHAT(bnode)) {
-					struct chat *chat = (struct chat *)bnode;
+
+					fprintf(file, "\t\t\t</contact>\n");
+				} else if(GAIM_BLIST_NODE_IS_CHAT(cnode)) {
+					GaimBlistChat *chat = (GaimBlistChat *)cnode;
 					if(!exp_acct || chat->account == exp_acct) {
 						char *acct_name = g_markup_escape_text(chat->account->username, -1);
 						fprintf(file, "\t\t\t<chat protocol=\"%d\" account=\"%s\">\n",
@@ -1939,9 +2189,8 @@
 						}
 						g_hash_table_foreach(chat->components,
 								blist_print_chat_components, file);
-						/* works for chats too, I don't feel like renaming */
 						g_hash_table_foreach(chat->settings,
-								blist_print_buddy_settings, file);
+								blist_print_cnode_settings, file);
 						fprintf(file, "\t\t\t</chat>\n");
 						g_free(acct_name);
 					}
@@ -2026,20 +2275,20 @@
 	g_free(filename_real);
 }
 
-void gaim_group_set_setting(struct group *g, const char *key,
+void gaim_group_set_setting(GaimGroup *g, const char *key,
 		const char *value) {
 	if(!g)
 		return;
 	g_hash_table_replace(g->settings, g_strdup(key), g_strdup(value));
 }
 
-char *gaim_group_get_setting(struct group *g, const char *key) {
+char *gaim_group_get_setting(GaimGroup *g, const char *key) {
 	if(!g)
 		return NULL;
 	return g_strdup(g_hash_table_lookup(g->settings, key));
 }
 
-void gaim_chat_set_setting(struct chat *c, const char *key,
+void gaim_blist_chat_set_setting(GaimBlistChat *c, const char *key,
 		const char *value)
 {
 	if(!c)
@@ -2047,21 +2296,21 @@
 	g_hash_table_replace(c->settings, g_strdup(key), g_strdup(value));
 }
 
-char *gaim_chat_get_setting(struct chat *c, const char *key)
+char *gaim_blist_chat_get_setting(GaimBlistChat *c, const char *key)
 {
 	if(!c)
 		return NULL;
 	return g_strdup(g_hash_table_lookup(c->settings, key));
 }
 
-void gaim_buddy_set_setting(struct buddy *b, const char *key,
+void gaim_buddy_set_setting(GaimBuddy *b, const char *key,
 		const char *value) {
 	if(!b)
 		return;
 	g_hash_table_replace(b->settings, g_strdup(key), g_strdup(value));
 }
 
-char *gaim_buddy_get_setting(struct buddy *b, const char *key) {
+char *gaim_buddy_get_setting(GaimBuddy *b, const char *key) {
 	if(!b)
 		return NULL;
 	return g_strdup(g_hash_table_lookup(b->settings, key));
@@ -2078,14 +2327,14 @@
 	return blist_ui_ops;
 }
 
-int gaim_blist_get_group_size(struct group *group, gboolean offline) {
+int gaim_blist_get_group_size(GaimGroup *group, gboolean offline) {
 	if(!group)
 		return 0;
 
 	return offline ? group->totalsize : group->currentsize;
 }
 
-int gaim_blist_get_group_online_count(struct group *group) {
+int gaim_blist_get_group_online_count(GaimGroup *group) {
 	if(!group)
 		return 0;
 

mercurial