changeset 25335:5b9345469776

propagate from branch 'im.pidgin.imhtml.customlinks' (head 5b6fe9ec607dbcafe1e078d3b80e2bbe8ebc4778) to branch 'im.pidgin.pidgin.next.minor' (head 556fa372887a6af3fc1e74ef733926a25b88b10c)
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Thu, 27 Nov 2008 21:15:43 +0000
parents 9bdd3ab8087f (diff) 284fd17c6020 (current diff)
children 6d4b56b81871
files ChangeLog.API
diffstat 138 files changed, 8551 insertions(+), 3157 deletions(-) [+]
line wrap: on
line diff
--- a/.mtn-ignore	Sun Nov 23 18:30:31 2008 +0000
+++ b/.mtn-ignore	Thu Nov 27 21:15:43 2008 +0000
@@ -10,6 +10,7 @@
 .*\.def$
 .*\.dll$
 .*\.exe$
+.*\.loT$
 intltool-.*
 Doxyfile(\.mingw)?$
 aclocal.m4
--- a/COPYRIGHT	Sun Nov 23 18:30:31 2008 +0000
+++ b/COPYRIGHT	Thu Nov 27 21:15:43 2008 +0000
@@ -220,6 +220,7 @@
 Tuomas Kuosmanen
 Tero Kuusela
 Richard Laager
+Jacky Lam
 Scott Lamb
 Dennis Lambe Jr.
 Joe LaPenna
@@ -307,7 +308,7 @@
 Ted Percival
 Eduardo Pérez
 Matt Perry
-Diego Petten
+Diego Petten
 Nathan Peterson
 Sebastián E. Peyrott
 Celso Pinto
@@ -323,7 +324,7 @@
 Jory A. Pratt
 Brent Priddy
 Justin Pryzby
-Florian Quze
+Florian Quèze
 Ignacio Casal Quinteiro
 Federicco Mena Quintero
 Yosef Radchenko
@@ -477,6 +478,7 @@
 Jared Yanovich
 Timmy Yee
 Nickolai Zeldovich
+Tom Zickel
 Marco Ziech
 Piotr Zielinski
 Jeroen Zwartepoorte
--- a/ChangeLog	Sun Nov 23 18:30:31 2008 +0000
+++ b/ChangeLog	Thu Nov 27 21:15:43 2008 +0000
@@ -8,6 +8,13 @@
 	  --with-system-ssl-certs and GnuTLS need to include these in the
 	  system certs directory.
 	* Corrected maximum message lengths for Yahoo!
+	* Fix some problems with Gadu-Gadu buddy icons (Adam Strzelecki)
+	* Enable auto-reply on Zephyr, to emulate 'zaway' (Toby Schaffer)
+	* The Buddy State Notification plugin no longer prints duplicate
+	  notifications when the same buddy is in multiple groups (Florian Quèze)
+	* The Buddy State Notification plugin no longer turns JID's, MSN Passport
+	  ID's, etc. into links (Florian Quèze)
+	* Fix a crash in SIMPLE when a malformed message is received.
 
 	Pidgin:
 	* On GTK+ 2.14 and higher, we're using the gtk-tooltip-delay setting
@@ -18,6 +25,8 @@
 	  To completely disable tooltips (e.g. if you had an old tooltip_delay
 	  of zero), add this to ~/.purple/gtkrc-2.0:
 	      gtk-enable-tooltips = 0
+	* Moved the release notification dialog to a mini-dialog in the
+	  buddylist.  (Thanks to Casey Ho)
 
 	Finch:
 	* Allow binding meta+arrow keys for actions.
--- a/ChangeLog.API	Sun Nov 23 18:30:31 2008 +0000
+++ b/ChangeLog.API	Thu Nov 27 21:15:43 2008 +0000
@@ -1,6 +1,30 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
 version 2.6.0 (??/??/????):
+	libpurple:
+		Added:
+		* purple_buddy_get_protocol_data
+		* purple_buddy_set_protocol_data
+		* purple_connection_get_protocol_data
+		* purple_connection_set_protocol_data
+		* purple_buddy_get_local_buddy_alias
+		* purple_blist_get_buddies
+		* purple_blist_get_ui_data
+		* purple_blist_set_ui_data
+		* purple_blist_node_get_ui_data
+		* purple_blist_node_set_ui_data
+		* PURPLE_BLIST_NODE
+		* PURPLE_GROUP
+		* PURPLE_CONTACT
+		* PURPLE_BUDDY
+		* PURPLE_CHAT
+		* purple_request_field_get_group
+		* purple_request_field_get_ui_data
+		* purple_request_field_set_ui_data
+
+		Deprecated:
+		* purple_buddy_get_local_alias
+
 	pidgin:
 		Added:
 		* gtk_imhtml_class_register_protocol
--- a/Makefile.am	Sun Nov 23 18:30:31 2008 +0000
+++ b/Makefile.am	Thu Nov 27 21:15:43 2008 +0000
@@ -10,6 +10,7 @@
 		README.mingw \
 		config.h.mingw \
 		doxy2devhelp.xsl \
+		fix-casts.sh \
 		gaim.pc.in \
 		gaim-uninstalled.pc.in \
 		intltool-extract.in \
@@ -34,6 +35,7 @@
 	(cd po ; intltool-update -m 2>&1 | grep -v '^mismatched quotes.*\.py$$' | sed "s|current directory|po directory|" | grep . ; if [ $$? = 0 ] ; then exit 1 ; else exit 0 ; fi)
 	LC_ALL=C sort -c -t/ -u po/POTFILES.in
 	LC_ALL=C sort -c -t/ -u po/POTFILES.skip
+	iconv -f utf8 -t utf8 COPYRIGHT | cmp COPYRIGHT -
 
 version-check: commit-check
 # We don't want to release development versions.
@@ -58,7 +60,7 @@
 # Ensure we're working from a tag...
 	test x`mtn automate select t:v$(PACKAGE_VERSION)` = x`mtn automate get_base_revision_id`
 # ... and have no changes in the working copy.
-	test x`mtn diff | grep -v '^#'` = x
+	test "x`mtn diff | grep -v '^#'`" = x
 
 release: version-check distcheck packages
 
--- a/autogen.sh	Sun Nov 23 18:30:31 2008 +0000
+++ b/autogen.sh	Thu Nov 27 21:15:43 2008 +0000
@@ -66,7 +66,7 @@
 	CMD=$1
 
 	printf "%s" "checking for ${CMD}... "
-	BIN=`which ${CMD} 2> /dev/null`
+	BIN=`which ${CMD} 2>/dev/null`
 
 	if [ x"${BIN}" = x"" ] ; then
 		echo "not found."
--- a/finch/gntblist.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/finch/gntblist.c	Thu Nov 27 21:15:43 2008 +0000
@@ -357,7 +357,7 @@
 	int color = 0;
 
 	if (PURPLE_BLIST_NODE_IS_CONTACT(node))
-		node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node);
+		node = PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node)));
 	if (!PURPLE_BLIST_NODE_IS_BUDDY(node))
 		return 0;
 
@@ -388,7 +388,7 @@
 	if (fnode && fnode->signed_timer)
 		flag |= GNT_TEXT_FLAG_BLINK;
 	else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
-		node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact *)node);
+		node = PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node)));
 		fnode = FINCH_GET_DATA(node);
 		if (fnode && fnode->signed_timer)
 			flag |= GNT_TEXT_FLAG_BLINK;
@@ -886,7 +886,7 @@
 	const char *name = NULL;
 
 	if (PURPLE_BLIST_NODE_IS_CONTACT(node))
-		node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node);  /* XXX: this can return NULL?! */
+		node = PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node)));  /* XXX: this can return NULL?! */
 
 	if (node == NULL)
 		return NULL;
@@ -1027,7 +1027,7 @@
 		return;
 
 	if (PURPLE_BLIST_NODE_IS_CONTACT(node))
-		node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node);
+		node = PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node)));
 
 	if (PURPLE_BLIST_NODE_IS_BUDDY(node))
 	{
@@ -1438,16 +1438,16 @@
 	if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 		PurpleBuddy *b = (PurpleBuddy*) node;
 		type = PURPLE_LOG_IM;
-		name = g_strdup(b->name);
-		account = b->account;
+		name = g_strdup(purple_buddy_get_name(b));
+		account = purple_buddy_get_account(b);
 	} else if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
 		PurpleChat *c = (PurpleChat*) node;
 		PurplePluginProtocolInfo *prpl_info = NULL;
 		type = PURPLE_LOG_CHAT;
-		account = c->account;
+		account = purple_chat_get_account(c);
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(account)));
 		if (prpl_info && prpl_info->get_chat_name) {
-			name = prpl_info->get_chat_name(c->components);
+			name = prpl_info->get_chat_name(purple_chat_get_components(c));
 		}
 	} else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
 		finch_log_show_contact((PurpleContact *)node);
@@ -1571,8 +1571,8 @@
 		ggblist->tagged = g_list_prepend(ggblist->tagged, node);
 	}
 	if (PURPLE_BLIST_NODE_IS_CONTACT(node))
-		node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node);
-	if (PURPLE_BLIST_NODE_IS_BUDDY(node))
+		update_buddy_display(purple_contact_get_priority_buddy(PURPLE_CONTACT(node)), ggblist);
+	else if (PURPLE_BLIST_NODE_IS_BUDDY(node))
 		update_buddy_display((PurpleBuddy*)node, ggblist);
 	else
 		update_node_display(node, ggblist);
@@ -1612,7 +1612,7 @@
 				purple_blist_add_group((PurpleGroup*)node, (PurpleBlistNode*)tg);
 			} else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
 				update_buddy_display(purple_contact_get_priority_buddy((PurpleContact*)node), ggblist);
-				if ((PurpleBlistNode*)tg == target) {
+				if (PURPLE_BLIST_NODE(tg) == target) {
 					/* The target is a group, just add the contact to the group. */
 					purple_blist_add_contact((PurpleContact*)node, tg, NULL);
 				} else if (tc) {
@@ -1624,7 +1624,7 @@
 				}
 			} else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 				update_buddy_display((PurpleBuddy*)node, ggblist);
-				if ((PurpleBlistNode*)tg == target) {
+				if (PURPLE_BLIST_NODE(tg) == target) {
 					/* The target is a group. Add this buddy in a new contact under this group. */
 					purple_blist_add_buddy((PurpleBuddy*)node, NULL, tg, NULL);
 				} else if (PURPLE_BLIST_NODE_IS_CONTACT(target)) {
@@ -1639,7 +1639,7 @@
 				}
 			} else if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
 				update_node_display(node, ggblist);
-				if ((PurpleBlistNode*)tg == target)
+				if (PURPLE_BLIST_NODE(tg) == target)
 					purple_blist_add_chat((PurpleChat*)node, tg, NULL);
 				else
 					purple_blist_add_chat((PurpleChat*)node, NULL, target);
@@ -1685,7 +1685,7 @@
 		create_group_menu(GNT_MENU(context), NULL);
 		title = g_strdup(_("Buddy List"));
 	} else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
-		ggblist->cnode = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node);
+		ggblist->cnode = PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node)));
 		create_buddy_menu(GNT_MENU(context), (PurpleBuddy*)ggblist->cnode);
 		title = g_strdup(purple_contact_get_alias((PurpleContact*)node));
 	} else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
@@ -2207,6 +2207,7 @@
 {
 	PurpleSavedStatus *current;
 	const char *message, *newmessage;
+	char *escnewmessage;
 	PurpleStatusPrimitive prim, newprim;
 	StatusBoxItem *item;
 
@@ -2216,6 +2217,7 @@
 
 	newmessage = gnt_entry_get_text(GNT_ENTRY(ggblist->statustext));
 	item = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(ggblist->status));
+	escnewmessage = newmessage ? g_markup_escape_text(newmessage, -1) : NULL;
 
 	switch (item->type) {
 		case STATUS_PRIMITIVE:
@@ -2228,16 +2230,16 @@
 			goto end;  /* 'New' or 'Saved' is selected, but this should never happen. */
 	}
 
-	if (newprim != prim || ((message && !newmessage) ||
-				(!message && newmessage) ||
-				(message && newmessage && g_utf8_collate(message, newmessage) != 0)))
+	if (newprim != prim || ((message && !escnewmessage) ||
+				(!message && escnewmessage) ||
+				(message && escnewmessage && g_utf8_collate(message, escnewmessage) != 0)))
 	{
-		PurpleSavedStatus *status = purple_savedstatus_find_transient_by_type_and_message(newprim, newmessage);
+		PurpleSavedStatus *status = purple_savedstatus_find_transient_by_type_and_message(newprim, escnewmessage);
 									/* Holy Crap! That's a LAWNG function name */
 		if (status == NULL)
 		{
 			status = purple_savedstatus_new(NULL, newprim);
-			purple_savedstatus_set_message(status, newmessage);
+			purple_savedstatus_set_message(status, escnewmessage);
 		}
 
 		purple_savedstatus_activate(status);
@@ -2245,6 +2247,7 @@
 
 	gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree);
 end:
+	g_free(escnewmessage);
 	if (ggblist->typing)
 		g_source_remove(ggblist->typing);
 	ggblist->typing = 0;
@@ -2412,8 +2415,8 @@
 
 	switch (purple_blist_node_get_type(n1)) {
 		case PURPLE_BLIST_CONTACT_NODE:
-			n1 = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)n1);
-			n2 = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)n2);
+			n1 = PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(n1)));
+			n2 = PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(n2)));
 			/* now compare the presence of the priority buddies */
 		case PURPLE_BLIST_BUDDY_NODE:
 			ret = purple_presence_compare(purple_buddy_get_presence((PurpleBuddy*)n1),
--- a/finch/gntconv.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/finch/gntconv.c	Thu Nov 27 21:15:43 2008 +0000
@@ -496,8 +496,9 @@
 	buddies = purple_find_buddies(account, name);
 	for (cur = buddies; cur != NULL; cur = cur->next) {
 		PurpleBlistNode *node = cur->data;
-		if ((node != NULL) && ((node->prev != NULL) || (node->next != NULL))) {
-			finch_log_show_contact((PurpleContact *)node->parent);
+		if ((node != NULL) &&
+				(purple_blist_node_get_sibling_prev(node) || purple_blist_node_get_sibling_next(node))) {
+			finch_log_show_contact((PurpleContact *)purple_blist_node_get_parent(node));
 			g_slist_free(buddies);
 			return;
 		}
@@ -529,7 +530,7 @@
 	gnt_menuitem_set_submenu(item, GNT_MENU(sub));
 
 	for (; buds; buds = g_slist_delete_link(buds, buds)) {
-		PurpleBlistNode *node = (PurpleBlistNode *)purple_buddy_get_contact((PurpleBuddy *)buds->data);
+		PurpleBlistNode *node = PURPLE_BLIST_NODE(purple_buddy_get_contact(PURPLE_BUDDY(buds->data)));
 		for (node = purple_blist_node_get_first_child(node); node != NULL;
 				node = purple_blist_node_get_sibling_next(node)) {
 			PurpleBuddy *buddy = (PurpleBuddy *)node;
--- a/finch/gntlog.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/finch/gntlog.c	Thu Nov 27 21:15:43 2008 +0000
@@ -458,12 +458,16 @@
 
 	for (child = purple_blist_node_get_first_child((PurpleBlistNode*)contact); child;
 			child = purple_blist_node_get_sibling_next(child)) {
+		const char *name;
+		PurpleAccount *account;
 		if (!PURPLE_BLIST_NODE_IS_BUDDY(child))
 			continue;
 
-		logs = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, ((PurpleBuddy *)child)->name,
-						((PurpleBuddy *)child)->account), logs);
-		total_log_size += purple_log_get_total_size(PURPLE_LOG_IM, ((PurpleBuddy *)child)->name, ((PurpleBuddy *)child)->account);
+		name = purple_buddy_get_name((PurpleBuddy *)child);
+		account = purple_buddy_get_account((PurpleBuddy *)child);
+		logs = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, name,
+						account), logs);
+		total_log_size += purple_log_get_total_size(PURPLE_LOG_IM, name, account);
 	}
 	logs = g_list_sort(logs, purple_log_compare);
 
--- a/finch/gntrequest.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/finch/gntrequest.c	Thu Nov 27 21:15:43 2008 +0000
@@ -39,6 +39,12 @@
 #include "debug.h"
 #include "util.h"
 
+/* XXX: Until gobjectification ... */
+#undef FINCH_GET_DATA
+#undef FINCH_SET_DATA
+#define FINCH_GET_DATA(obj)  purple_request_field_get_ui_data(obj)
+#define FINCH_SET_DATA(obj, data)  purple_request_field_set_ui_data(obj, data)
+
 typedef struct
 {
 	void *user_data;
@@ -633,7 +639,8 @@
 			}
 			else if (type == PURPLE_REQUEST_FIELD_ACCOUNT)
 			{
-				accountlist = FINCH_SET_DATA(field, create_account_field(field));
+				accountlist = create_account_field(field);
+				FINCH_SET_DATA(field, accountlist);
 			}
 			else
 			{
--- a/finch/libgnt/gnttextview.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/finch/libgnt/gnttextview.c	Thu Nov 27 21:15:43 2008 +0000
@@ -67,6 +67,7 @@
 gnt_text_view_draw(GntWidget *widget)
 {
 	GntTextView *view = GNT_TEXT_VIEW(widget);
+	int n;
 	int i = 0;
 	GList *lines;
 	int rows, scrcol;
@@ -76,10 +77,11 @@
 	wbkgd(widget->window, gnt_color_pair(GNT_COLOR_NORMAL));
 	werase(widget->window);
 
+	n = g_list_length(view->list);
 	if ((view->flags & GNT_TEXT_VIEW_TOP_ALIGN) &&
-			g_list_length(view->list) < widget->priv.height) {
+			n < widget->priv.height) {
 		GList *now = view->list;
-		comp = widget->priv.height - g_list_length(view->list);
+		comp = widget->priv.height - n;
 		view->list = g_list_nth_prev(view->list, comp);
 		if (!view->list) {
 			view->list = g_list_first(now);
@@ -236,6 +238,7 @@
 static char *
 gnt_text_view_get_p(GntTextView *view, int x, int y)
 {
+	int n;
 	int i = 0;
 	GntWidget *wid = GNT_WIDGET(view);
 	GntTextLine *line;
@@ -244,10 +247,11 @@
 	GntTextSegment *seg;
 	gchar *pos;
 
+	n = g_list_length(view->list);
 	y = wid->priv.height - y;
-	if (g_list_length(view->list) < y) {
+	if (n < y) {
 		x = 0;
-		y = g_list_length(view->list) - 1;
+		y = n - 1;
 	}
 
 	lines = g_list_nth(view->list, y - 1);
--- a/finch/libgnt/gntwm.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/finch/libgnt/gntwm.c	Thu Nov 27 21:15:43 2008 +0000
@@ -201,7 +201,7 @@
 	GString *text = g_string_new("act: ");
 	if (message)
 		gnt_widget_destroy(message);
-	if (g_list_length(act) == 0)
+	if (!act)
 		return;
 	for (iter = act; iter; iter = iter->next) {
 		GntWS *ws = iter->data;
@@ -927,6 +927,7 @@
 	GntWidget *tree, *win;
 	GList *iter;
 	GntWM *wm = GNT_WM(bindable);
+	int n;
 	if (wm->_list.window || wm->menu)
 		return TRUE;
 
@@ -950,8 +951,9 @@
 				gnt_tree_create_row(GNT_TREE(tree), action->label), NULL);
 	}
 	g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(action_list_activate), wm);
-	gnt_widget_set_size(tree, 0, g_list_length(wm->acts));
-	gnt_widget_set_position(win, 0, getmaxy(stdscr) - 3 - g_list_length(wm->acts));
+	n = g_list_length(wm->acts);
+	gnt_widget_set_size(tree, 0, n);
+	gnt_widget_set_position(win, 0, getmaxy(stdscr) - 3 - n);
 
 	gnt_widget_show(win);
 	return TRUE;
--- a/finch/plugins/grouping.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/finch/plugins/grouping.c	Thu Nov 27 21:15:43 2008 +0000
@@ -87,7 +87,7 @@
 
 	switch (purple_blist_node_get_type(node)) {
 		case PURPLE_BLIST_CONTACT_NODE:
-			node = (PurpleBlistNode*)purple_contact_get_priority_buddy((PurpleContact*)node);
+			node = PURPLE_BLIST_NODE(purple_contact_get_priority_buddy(PURPLE_CONTACT(node)));
 			ret = PURPLE_BUDDY_IS_ONLINE((PurpleBuddy*)node) ? &online : &offline;
 			break;
 		case PURPLE_BLIST_BUDDY_NODE:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fix-casts.sh	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if [ $# -eq 0 ]; then
+	echo "Usage: `basename "$0"` PurpleFoo..."
+	echo
+	echo "This script searches the *current working directory* and replaces casts"
+	echo "with GObject-style type checking and casting macros."
+	echo 'For example, "(PurpleBuddy *)b" becomes "PURPLE_BUDDY(b)".'
+	exit 0
+fi
+
+for struct in $* ; do
+	cast=`echo $struct | sed "s|[A-Z]|_\0|g" | tr "a-z" "A-Z" | sed "s|^_||"`
+	for file in `grep -rl "([[:space:]]*$struct[[:space:]]*\*[[:space:]]*)" . --include=*.c --exclude=purple-client-bindings.c` ; do
+		sed -i "s|([[:space:]]*$struct[[:space:]]*\*[[:space:]]*)[[:space:]]*(|$cast(|g" $file
+		sed -i "s|([[:space:]]*$struct[[:space:]]*\*[[:space:]]*)[[:space:]]*\([^(][^,);]*\)|$cast(\1)|g" $file
+	done
+done
--- a/libpurple/Makefile.am	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/Makefile.am	Thu Nov 27 21:15:43 2008 +0000
@@ -75,8 +75,13 @@
 	stringref.c \
 	stun.c \
 	sound.c \
+	sound-theme-loader.c \
+	sound-theme.c \
 	sslconn.c \
 	upnp.c \
+	theme.c \
+	theme-loader.c \
+	theme-manager.c \
 	util.c \
 	value.c \
 	version.c \
@@ -128,8 +133,13 @@
 	stringref.h \
 	stun.h \
 	sound.h \
+	sound-theme-loader.h \
+	sound-theme.h \
 	sslconn.h \
 	upnp.h \
+	theme.h \
+	theme-loader.h \
+	theme-manager.h \
 	util.h \
 	value.h \
 	xmlnode.h \
--- a/libpurple/account.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/account.c	Thu Nov 27 21:15:43 2008 +0000
@@ -2248,8 +2248,8 @@
 
 		/* Make a list of what group each buddy is in */
 		for (cur = buddies; cur != NULL; cur = cur->next) {
-			PurpleBlistNode *node = cur->data;
-			groups = g_list_append(groups, node->parent->parent);
+			PurpleBuddy *buddy = cur->data;
+			groups = g_list_append(groups, purple_buddy_get_group(buddy));
 		}
 
 		if (prpl_info->add_buddies != NULL)
@@ -2499,23 +2499,26 @@
 	purple_accounts_remove(account);
 
 	/* Remove this account's buddies */
-	for (gnode = purple_get_blist()->root; gnode != NULL; gnode = gnode->next) {
+	for (gnode = purple_blist_get_root();
+	     gnode != NULL;
+		 gnode = purple_blist_node_get_sibling_next(gnode))
+	{
 		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
 
-		cnode = gnode->child;
+		cnode = purple_blist_node_get_first_child(gnode);
 		while (cnode) {
-			PurpleBlistNode *cnode_next = cnode->next;
+			PurpleBlistNode *cnode_next = purple_blist_node_get_sibling_next(cnode);
 
 			if(PURPLE_BLIST_NODE_IS_CONTACT(cnode)) {
-				bnode = cnode->child;
+				bnode = purple_blist_node_get_first_child(cnode);
 				while (bnode) {
-					PurpleBlistNode *bnode_next = bnode->next;
+					PurpleBlistNode *bnode_next = purple_blist_node_get_sibling_next(bnode);
 
 					if (PURPLE_BLIST_NODE_IS_BUDDY(bnode)) {
 						PurpleBuddy *b = (PurpleBuddy *)bnode;
 
-						if (b->account == account)
+						if (purple_buddy_get_account(b) == account)
 							purple_blist_remove_buddy(b);
 					}
 					bnode = bnode_next;
@@ -2523,7 +2526,7 @@
 			} else if (PURPLE_BLIST_NODE_IS_CHAT(cnode)) {
 				PurpleChat *c = (PurpleChat *)cnode;
 
-				if (c->account == account)
+				if (purple_chat_get_account(c) == account)
 					purple_blist_remove_chat(c);
 			}
 			cnode = cnode_next;
--- a/libpurple/blist.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/blist.c	Thu Nov 27 21:15:43 2008 +0000
@@ -699,6 +699,24 @@
 	return purplebuddylist ? purplebuddylist->root : NULL;
 }
 
+GHashTable *
+purple_blist_get_buddies()
+{
+	return purplebuddylist ? purplebuddylist->buddies : NULL;
+}
+
+void *
+purple_blist_get_ui_data()
+{
+	return purplebuddylist->ui_data;
+}
+
+void
+purple_blist_set_ui_data(void *ui_data)
+{
+	purplebuddylist->ui_data = ui_data;
+}
+
 void purple_blist_show()
 {
 	PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
@@ -774,12 +792,28 @@
 	return node? node->prev : NULL;
 }
 
+void *
+purple_blist_node_get_ui_data(const PurpleBlistNode *node)
+{
+	g_return_val_if_fail(node, NULL);
+
+	return node->ui_data;
+}
+
+void
+purple_blist_node_set_ui_data(PurpleBlistNode *node, void *ui_data) {
+	g_return_if_fail(node);
+
+	node->ui_data = ui_data;
+}
+
 void
 purple_blist_update_buddy_status(PurpleBuddy *buddy, PurpleStatus *old_status)
 {
 	PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
 	PurplePresence *presence;
 	PurpleStatus *status;
+	PurpleBlistNode *cnode;
 
 	g_return_if_fail(buddy != NULL);
 
@@ -794,16 +828,18 @@
 
 		purple_signal_emit(purple_blist_get_handle(), "buddy-signed-on", buddy);
 
-		((PurpleContact*)((PurpleBlistNode*)buddy)->parent)->online++;
-		if (((PurpleContact*)((PurpleBlistNode*)buddy)->parent)->online == 1)
-			((PurpleGroup *)((PurpleBlistNode *)buddy)->parent->parent)->online++;
+		cnode = buddy->node.parent;
+		if (++(PURPLE_CONTACT(cnode)->online) == 1)
+			PURPLE_GROUP(cnode->parent)->online++;
 	} else if (!purple_status_is_online(status) &&
 				purple_status_is_online(old_status)) {
+
 		purple_blist_node_set_int(&buddy->node, "last_seen", time(NULL));
 		purple_signal_emit(purple_blist_get_handle(), "buddy-signed-off", buddy);
-		((PurpleContact*)((PurpleBlistNode*)buddy)->parent)->online--;
-		if (((PurpleContact*)((PurpleBlistNode*)buddy)->parent)->online == 0)
-			((PurpleGroup *)((PurpleBlistNode *)buddy)->parent->parent)->online--;
+
+		cnode = buddy->node.parent;
+		if (--(PURPLE_CONTACT(cnode)->online) == 0)
+			PURPLE_GROUP(cnode->parent)->online--;
 	} else {
 		purple_signal_emit(purple_blist_get_handle(),
 		                 "buddy-status-changed", buddy, old_status,
@@ -1232,6 +1268,23 @@
 	return buddy->icon;
 }
 
+gpointer
+purple_buddy_get_protocol_data(const PurpleBuddy *buddy)
+{
+	g_return_val_if_fail(buddy != NULL, NULL);
+
+	return buddy->proto_data;
+}
+
+void
+purple_buddy_set_protocol_data(PurpleBuddy *buddy, gpointer data)
+{
+	g_return_if_fail(buddy != NULL);
+
+	buddy->proto_data = data;
+}
+
+
 void purple_blist_add_chat(PurpleChat *chat, PurpleGroup *group, PurpleBlistNode *node)
 {
 	PurpleBlistNode *cnode = (PurpleBlistNode*)chat;
@@ -1339,7 +1392,7 @@
 		g = (PurpleGroup*)node->parent->parent;
 	} else if (contact) {
 		c = contact;
-		g = (PurpleGroup *)((PurpleBlistNode *)c)->parent;
+		g = PURPLE_GROUP(PURPLE_BLIST_NODE(c)->parent);
 	} else {
 		g = group;
 		if (g == NULL)
@@ -1421,16 +1474,14 @@
 	}
 
 	if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
-		((PurpleContact*)bnode->parent)->online++;
-		if (((PurpleContact*)bnode->parent)->online == 1)
-			((PurpleGroup*)bnode->parent->parent)->online++;
+		if (++(PURPLE_CONTACT(bnode->parent)->online) == 1)
+			PURPLE_GROUP(bnode->parent->parent)->online++;
 	}
 	if (purple_account_is_connected(buddy->account)) {
-		((PurpleContact*)bnode->parent)->currentsize++;
-		if (((PurpleContact*)bnode->parent)->currentsize == 1)
-			((PurpleGroup*)bnode->parent->parent)->currentsize++;
+		if (++(PURPLE_CONTACT(bnode->parent)->currentsize) == 1)
+			PURPLE_GROUP(bnode->parent->parent)->currentsize++;
 	}
-	((PurpleContact*)bnode->parent)->totalsize++;
+	PURPLE_CONTACT(bnode->parent)->totalsize++;
 
 	hb = g_new(struct _purple_hbuddy, 1);
 	hb->name = g_strdup(purple_normalize(buddy->account, buddy->name));
@@ -1546,7 +1597,7 @@
 	g_return_if_fail(contact != NULL);
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CONTACT((PurpleBlistNode*)contact));
 
-	if ((PurpleBlistNode*)contact == node)
+	if (PURPLE_BLIST_NODE(contact) == node)
 		return;
 
 	if (node && (PURPLE_BLIST_NODE_IS_CONTACT(node) ||
@@ -2044,6 +2095,12 @@
 	return buddy->name;
 }
 
+const char *purple_buddy_get_local_buddy_alias(PurpleBuddy *buddy)
+{
+	g_return_val_if_fail(buddy, NULL);
+	return buddy->alias;
+}
+
 const char *purple_buddy_get_server_alias(PurpleBuddy *buddy)
 {
         g_return_val_if_fail(buddy != NULL, NULL);
@@ -2288,7 +2345,7 @@
 {
 	g_return_val_if_fail(buddy != NULL, NULL);
 
-	return (PurpleContact*)((PurpleBlistNode*)buddy)->parent;
+	return PURPLE_CONTACT(PURPLE_BLIST_NODE(buddy)->parent);
 }
 
 PurplePresence *purple_buddy_get_presence(const PurpleBuddy *buddy)
--- a/libpurple/blist.h	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/blist.h	Thu Nov 27 21:15:43 2008 +0000
@@ -75,12 +75,19 @@
 
 } PurpleBlistNodeFlags;
 
+#define PURPLE_BLIST_NODE(obj) ((PurpleBlistNode *)(obj))
+
 #define PURPLE_BLIST_NODE_HAS_FLAG(b, f) (purple_blist_node_get_flags((PurpleBlistNode*)(b)) & (f))
 #define PURPLE_BLIST_NODE_SHOULD_SAVE(b) (! PURPLE_BLIST_NODE_HAS_FLAG(b, PURPLE_BLIST_NODE_FLAG_NO_SAVE))
 
 #define PURPLE_BLIST_NODE_NAME(n) (purple_blist_node_get_type(n) == PURPLE_BLIST_CHAT_NODE  ? purple_chat_get_name((PurpleChat*)n) :        \
 				     purple_blist_node_get_type(n) == PURPLE_BLIST_BUDDY_NODE ? purple_buddy_get_name((PurpleBuddy*)n) : NULL)
 
+#define PURPLE_GROUP(obj) ((PurpleGroup *)(obj))
+#define PURPLE_CONTACT(obj) ((PurpleContact *)(obj))
+#define PURPLE_BUDDY(obj) ((PurpleBuddy *)(obj))
+#define PURPLE_CHAT(obj) ((PurpleChat *)(obj))
+
 #include "account.h"
 #include "buddyicon.h"
 #include "status.h"
@@ -156,9 +163,6 @@
 	PurpleAccount *account; /**< The account this chat is attached to */
 };
 
-#endif /* PURPLE_HIDE_STRUCTS && PURPLE_BLIST_STRUCTS */
-
-
 /**
  * The Buddy List
  */
@@ -168,6 +172,8 @@
 	void *ui_data;                /**< UI-specific data. */
 };
 
+#endif /* PURPLE_HIDE_STRUCTS && PURPLE_BLIST_STRUCTS */
+
 /**
  * Buddy list UI operations.
  *
@@ -236,6 +242,30 @@
 PurpleBlistNode *purple_blist_get_root(void);
 
 /**
+ * Returns the hash table of every buddy in the list.
+ *
+ * @return The hash table of every buddy in the list.
+ * @since 2.6.0
+ */
+GHashTable *purple_blist_get_buddies(void);
+
+/**
+ * Returns the UI data for the list.
+ *
+ * @return The UI data for the list.
+ * @since 2.6.0
+ */
+void *purple_blist_get_ui_data(void);
+
+/**
+ * Sets the UI data for the list.
+ *
+ * @param ui_data The UI data for the list.
+ * @since 2.6.0
+ */
+void purple_blist_set_ui_data(void *ui_data);
+
+/**
  * Returns the next node of a given node. This function is to be used to iterate
  * over the tree returned by purple_get_blist.
  *
@@ -302,6 +332,24 @@
 PurpleBlistNode *purple_blist_node_get_sibling_prev(PurpleBlistNode *node);
 
 /**
+ * Returns the UI data of a given node.
+ *
+ * @param node The node.
+ * @return The UI data.
+ * @since 2.6.0
+ */
+void *purple_blist_node_get_ui_data(const PurpleBlistNode *node);
+
+/**
+ * Sets the UI data of a given node.
+ *
+ * @param node The node.
+ * @param ui_data The UI data.
+ * @since 2.6.0
+ */
+void purple_blist_node_set_ui_data(PurpleBlistNode *node, void *ui_data);
+
+/**
  * Shows the buddy list, creating a new one if necessary.
  */
 void purple_blist_show(void);
@@ -470,6 +518,32 @@
 PurpleBuddyIcon *purple_buddy_get_icon(const PurpleBuddy *buddy);
 
 /**
+ * Returns a buddy's protocol-specific data.
+ *
+ * This should only be called from the associated prpl.
+ *
+ * @param buddy The buddy.
+ * @return      The protocol data.
+ *
+ * @see purple_buddy_set_protocol_data()
+ * @since 2.6.0
+ */
+gpointer purple_buddy_get_protocol_data(const PurpleBuddy *buddy);
+
+/**
+ * Sets a buddy's protocol-specific data.
+ *
+ * This should only be called from the associated prpl.
+ *
+ * @param buddy The buddy.
+ * @param data  The data.
+ *
+ * @see purple_buddy_get_protocol_data()
+ * @since 2.6.0
+ */
+void purple_buddy_set_protocol_data(PurpleBuddy *buddy, gpointer data);
+
+/**
  * Returns a buddy's contact.
  *
  * @param buddy The buddy.
@@ -659,6 +733,7 @@
  */
 const char *purple_buddy_get_contact_alias(PurpleBuddy *buddy);
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_BLIST_C_)
 /**
  * Returns the correct alias for this user, ignoring server aliases.  Used
  * when a user-recognizable name is required.  In order: buddy's alias; buddy's
@@ -666,8 +741,10 @@
  * 
  * @param buddy  The buddy whose alias will be returned.
  * @return       The appropriate name or alias.
+ * @deprecated   Try purple_buddy_get_alias(), if server aliases are okay.
  */
 const char *purple_buddy_get_local_alias(PurpleBuddy *buddy);
+#endif
 
 /**
  * Returns the correct name to display for a buddy. In order of precedence:
@@ -680,6 +757,15 @@
 const char *purple_buddy_get_alias(PurpleBuddy *buddy);
 
 /**
+ * Returns the local alias for the buddy, or @c NULL if none exists.
+ *
+ * @param buddy  The buddy
+ * @return       The local alias for the buddy
+ * @since 2.6.0
+ */
+const char *purple_buddy_get_local_buddy_alias(PurpleBuddy *buddy);
+
+/**
  * Returns the correct name to display for a blist chat.
  *
  * @param chat   The chat whose name will be returned.
--- a/libpurple/buddyicon.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/buddyicon.c	Thu Nov 27 21:15:43 2008 +0000
@@ -889,7 +889,9 @@
 
 	if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
 		PurpleBlistNode *child;
-		for (child = node->child ; child ; child = child->next)
+		for (child = purple_blist_node_get_first_child(node);
+		     child;
+			 child = purple_blist_node_get_sibling_next(child))
 		{
 			PurpleBuddy *buddy;
 			PurpleConversation *conv;
--- a/libpurple/connection.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/connection.c	Thu Nov 27 21:15:43 2008 +0000
@@ -285,7 +285,7 @@
 	buddies = purple_find_buddies(account, NULL);
 	while (buddies != NULL) {
 		PurpleBuddy *buddy = buddies->data;
-		buddy->proto_data = NULL;
+		purple_buddy_set_protocol_data(buddy, NULL);
 		buddies = g_slist_delete_link(buddies, buddies);
 	}
 
@@ -427,6 +427,13 @@
 	gc->display_name = g_strdup(name);
 }
 
+void
+purple_connection_set_protocol_data(PurpleConnection *connection, void *proto_data) {
+	g_return_if_fail(connection != NULL);
+
+	connection->proto_data = proto_data;
+}
+
 PurpleConnectionState
 purple_connection_get_state(const PurpleConnection *gc)
 {
@@ -467,6 +474,13 @@
 	return gc->display_name;
 }
 
+void *
+purple_connection_get_protocol_data(const PurpleConnection *connection) {
+	g_return_val_if_fail(connection != NULL, NULL);
+
+	return connection->proto_data;
+}
+
 void
 purple_connection_update_progress(PurpleConnection *gc, const char *text,
 								size_t step, size_t count)
--- a/libpurple/connection.h	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/connection.h	Thu Nov 27 21:15:43 2008 +0000
@@ -354,6 +354,15 @@
 void purple_connection_set_display_name(PurpleConnection *gc, const char *name);
 
 /**
+ * Sets the protocol data for a connection.
+ *
+ * @param connection The PurpleConnection.
+ * @param proto_data The protocol data to set for the connection.
+ * @since 2.6.0
+ */
+void purple_connection_set_protocol_data(PurpleConnection *connection, void *proto_data);
+
+/**
  * Returns the connection state.
  *
  * @param gc The connection.
@@ -408,6 +417,16 @@
 const char *purple_connection_get_display_name(const PurpleConnection *gc);
 
 /**
+ * Gets the protocol data from a connection.
+ *
+ * @param connection The PurpleConnection.
+ *
+ * @return The protocol data for the connection.
+ * @since 2.6.0
+ */
+void *purple_connection_get_protocol_data(const PurpleConnection *connection);
+
+/**
  * Updates the connection progress.
  *
  * @param gc    The connection.
--- a/libpurple/conversation.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/conversation.c	Thu Nov 27 21:15:43 2008 +0000
@@ -665,7 +665,7 @@
 			text = purple_buddy_get_contact_alias(b);
 	} else if(purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
 		if(account && ((chat = purple_blist_find_chat(account, name)) != NULL))
-			text = chat->alias;
+			text = purple_chat_get_name(chat);
 	}
 
 
@@ -912,7 +912,7 @@
 
 				if (purple_account_get_alias(account) != NULL)
 					alias = account->alias;
-				else if (b != NULL && strcmp(b->name, purple_buddy_get_contact_alias(b)))
+				else if (b != NULL && strcmp(purple_buddy_get_name(b), purple_buddy_get_contact_alias(b)))
 					alias = purple_buddy_get_contact_alias(b);
 				else if (purple_connection_get_display_name(gc) != NULL)
 					alias = purple_connection_get_display_name(gc);
--- a/libpurple/core.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/core.c	Thu Nov 27 21:15:43 2008 +0000
@@ -46,10 +46,12 @@
 #include "signals.h"
 #include "smiley.h"
 #include "sound.h"
+#include "sound-theme-loader.h"
 #include "sslconn.h"
 #include "status.h"
 #include "stun.h"
 #include "util.h"
+#include "theme-manager.h"
 
 #ifdef HAVE_DBUS
 #  ifndef DBUS_API_SUBJECT_TO_CHANGE
@@ -143,6 +145,7 @@
 
 	purple_plugins_probe(G_MODULE_SUFFIX);
 
+	purple_theme_manager_init();
 	/* The buddy icon code uses the imgstore, so init it early. */
 	purple_imgstore_init();
 
@@ -171,7 +174,6 @@
 	purple_xfers_init();
 	purple_idle_init();
 	purple_smileys_init();
-
 	/*
 	 * Call this early on to try to auto-detect our IP address and
 	 * hopefully save some time later.
@@ -180,6 +182,8 @@
 
 	if (ops != NULL && ops->ui_init != NULL)
 		ops->ui_init();
+	
+	purple_theme_manager_refresh();
 
 	return TRUE;
 }
@@ -215,6 +219,7 @@
 	purple_status_uninit();
 	purple_prefs_uninit();
 	purple_sound_uninit();
+	purple_theme_manager_uninit();
 	purple_xfers_uninit();
 	purple_proxy_uninit();
 	purple_dnsquery_uninit();
--- a/libpurple/dnsquery.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/dnsquery.c	Thu Nov 27 21:15:43 2008 +0000
@@ -345,6 +345,12 @@
 {
 	g_return_if_fail(resolver != NULL);
 
+	/* Keep this before the kill() call below. */
+	if (resolver->inpa != 0) {
+		purple_input_remove(resolver->inpa);
+		resolver->inpa = 0;
+	}
+
 	/*
 	 * We might as well attempt to kill our child process.  It really
 	 * doesn't matter if this fails, because children will expire on
@@ -353,9 +359,6 @@
 	if (resolver->dns_pid > 0)
 		kill(resolver->dns_pid, SIGKILL);
 
-	if (resolver->inpa != 0)
-		purple_input_remove(resolver->inpa);
-
 	close(resolver->fd_in);
 	close(resolver->fd_out);
 
--- a/libpurple/log.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/log.c	Thu Nov 27 21:15:43 2008 +0000
@@ -588,11 +588,11 @@
 	void *handle = purple_log_get_handle();
 
 	purple_prefs_add_none("/purple/logging");
-	purple_prefs_add_bool("/purple/logging/log_ims", FALSE);
-	purple_prefs_add_bool("/purple/logging/log_chats", FALSE);
+	purple_prefs_add_bool("/purple/logging/log_ims", TRUE);
+	purple_prefs_add_bool("/purple/logging/log_chats", TRUE);
 	purple_prefs_add_bool("/purple/logging/log_system", FALSE);
 
-	purple_prefs_add_string("/purple/logging/format", "txt");
+	purple_prefs_add_string("/purple/logging/format", "html");
 
 	html_logger = purple_log_logger_new("html", _("HTML"), 11,
 									  NULL,
@@ -1952,22 +1952,28 @@
 		set->name = set->normalized_name = name;
 
 		/* Search the buddy list to find the account and to determine if this is a buddy. */
-		for (gnode = purple_get_blist()->root; !found && gnode != NULL; gnode = gnode->next)
+		for (gnode = purple_blist_get_root();
+		     !found && gnode != NULL;
+			 gnode = purple_blist_node_get_sibling_next(gnode))
 		{
 			if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 				continue;
 
-			for (cnode = gnode->child; !found && cnode != NULL; cnode = cnode->next)
+			for (cnode = purple_blist_node_get_first_child(gnode);
+			     !found && cnode != NULL;
+				 cnode = purple_blist_node_get_sibling_next(cnode))
 			{
 				if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 					continue;
 
-				for (bnode = cnode->child; !found && bnode != NULL; bnode = bnode->next)
+				for (bnode = purple_blist_node_get_first_child(cnode);
+				     !found && bnode != NULL;
+					 bnode = purple_blist_node_get_sibling_next(bnode))
 				{
 					PurpleBuddy *buddy = (PurpleBuddy *)bnode;
 
-					if (!strcmp(buddy->name, name)) {
-						set->account = buddy->account;
+					if (!strcmp(purple_buddy_get_name(buddy), name)) {
+						set->account = purple_buddy_get_account(buddy);
 						set->buddy = TRUE;
 						found = TRUE;
 					}
--- a/libpurple/notify.h	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/notify.h	Thu Nov 27 21:15:43 2008 +0000
@@ -236,7 +236,8 @@
  * Adds a stock button that will be displayed in the search results dialog.
  *
  * @param results The search results object.
- * @param type    Type of the button. (TODO: Only one button of a given type can be displayed.)
+ * @param type    Type of the button. (TODO: Only one button of a given type
+ *                can be displayed.)
  * @param cb      Function that will be called on the click event.
  */
 void purple_notify_searchresults_button_add(PurpleNotifySearchResults *results,
@@ -245,8 +246,9 @@
 
 
 /**
- * Adds a plain labelled button that will be displayed in the search results dialog.
- * 
+ * Adds a plain labelled button that will be displayed in the search results
+ * dialog.
+ *
  * @param results The search results object
  * @param label   The label to display
  * @param cb      Function that will be called on the click event
@@ -267,7 +269,7 @@
  * Returns a newly created search result column object.
  *
  * @param title Title of the column. NOTE: Title will get g_strdup()ed.
- * 
+ *
  * @return The new search column object.
  */
 PurpleNotifySearchColumn *purple_notify_searchresults_column_new(const char *title);
@@ -470,53 +472,58 @@
  * The text is essentially a stripped-down format of HTML, the same that
  * IMs may send.
  *
- * @param gc		         The PurpleConnection handle associated with the information.
- * @param who				 The username associated with the information.
- * @param user_info          The PurpleNotifyUserInfo which contains the information
- * @param cb                 The callback to call when the user closes
- *                           the notification.
- * @param user_data          The data to pass to the callback.
+ * @param gc         The PurpleConnection handle associated with the information.
+ * @param who        The username associated with the information.
+ * @param user_info  The PurpleNotifyUserInfo which contains the information
+ * @param cb         The callback to call when the user closes the notification.
+ * @param user_data  The data to pass to the callback.
  *
- * @return A UI-specific handle.
+ * @return  A UI-specific handle.
  */
 void *purple_notify_userinfo(PurpleConnection *gc, const char *who,
 						   PurpleNotifyUserInfo *user_info, PurpleNotifyCloseCallback cb,
 						   gpointer user_data);
 
 /**
- * Create a new PurpleNotifyUserInfo which is suitable for passing to purple_notify_userinfo()
+ * Create a new PurpleNotifyUserInfo which is suitable for passing to
+ * purple_notify_userinfo()
  *
- * @return A new PurpleNotifyUserInfo, which the caller must destroy when done
+ * @return  A new PurpleNotifyUserInfo, which the caller must destroy when done
  */
 PurpleNotifyUserInfo *purple_notify_user_info_new(void);
 
 /**
  * Destroy a PurpleNotifyUserInfo
  *
- * @param user_info          The PurpleNotifyUserInfo
+ * @param user_info  The PurpleNotifyUserInfo
  */
 void purple_notify_user_info_destroy(PurpleNotifyUserInfo *user_info);
 
 /**
- * Retrieve the array of PurpleNotifyUserInfoEntry objects from a PurpleNotifyUserInfo
- *
- * This GList may be manipulated directly with normal GList functions such as g_list_insert(). Only 
- * PurpleNotifyUserInfoEntry are allowed in the list.  If a PurpleNotifyUserInfoEntry item is added to the list,
- * it should not be g_free()'d by the caller; PurpleNotifyUserInfo will g_free it when destroyed.
+ * Retrieve the array of PurpleNotifyUserInfoEntry objects from a
+ * PurpleNotifyUserInfo
  *
- * To remove a PurpleNotifyUserInfoEntry, use purple_notify_user_info_remove_entry(). Do not use the GList directly.
+ * This GList may be manipulated directly with normal GList functions such
+ * as g_list_insert(). Only PurpleNotifyUserInfoEntry are allowed in the
+ * list.  If a PurpleNotifyUserInfoEntry item is added to the list, it
+ * should not be g_free()'d by the caller; PurpleNotifyUserInfo will g_free
+ * it when destroyed.
  *
- * @param user_info          The PurpleNotifyUserInfo
+ * To remove a PurpleNotifyUserInfoEntry, use
+ * purple_notify_user_info_remove_entry(). Do not use the GList directly.
  *
- * @constreturn              A GList of PurpleNotifyUserInfoEntry objects
+ * @param user_info  The PurpleNotifyUserInfo
+ *
+ * @constreturn A GList of PurpleNotifyUserInfoEntry objects
  */
 GList *purple_notify_user_info_get_entries(PurpleNotifyUserInfo *user_info);
 
 /**
- * Create a textual representation of a PurpleNotifyUserInfo, separating entries with newline
+ * Create a textual representation of a PurpleNotifyUserInfo, separating
+ * entries with newline
  *
- * @param user_info          The PurpleNotifyUserInfo
- * @param newline            The separation character
+ * @param user_info  The PurpleNotifyUserInfo
+ * @param newline    The separation character
  */
 char *purple_notify_user_info_get_text_with_newline(PurpleNotifyUserInfo *user_info, const char *newline);
 
@@ -524,46 +531,58 @@
  * Add a label/value pair to a PurpleNotifyUserInfo object.
  * PurpleNotifyUserInfo keeps track of the order in which pairs are added.
  *
- * @param user_info          The PurpleNotifyUserInfo
- * @param label              A label, which for example might be displayed by a UI with a colon after it ("Status:"). Do not include a colon.
- *                           If NULL, value will be displayed without a label.
- * @param value              The value, which might be displayed by a UI after the label.
- *                           If NULL, label will still be displayed; the UI should then treat label as independent
- *                           and not include a colon if it would otherwise.
+ * @param user_info  The PurpleNotifyUserInfo
+ * @param label      A label, which for example might be displayed by a
+ *                   UI with a colon after it ("Status:"). Do not include
+ *                   a colon.  If NULL, value will be displayed without a
+ *                   label.
+ * @param value      The value, which might be displayed by a UI after
+ *                   the label.  If NULL, label will still be displayed;
+ *                   the UI should then treat label as independent and not
+ *                   include a colon if it would otherwise.
  */
 void purple_notify_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value);
 
 /**
  * Prepend a label/value pair to a PurpleNotifyUserInfo object
  *
- * @param user_info          The PurpleNotifyUserInfo
- * @param label              A label, which for example might be displayed by a UI with a colon after it ("Status:"). Do not include a colon.
- *                           If NULL, value will be displayed without a label.
- * @param value              The value, which might be displayed by a UI after the label.
- *                           If NULL, label will still be displayed; the UI should then treat label as independent
- *                           and not include a colon if it would otherwise.
+ * @param user_info  The PurpleNotifyUserInfo
+ * @param label      A label, which for example might be displayed by a
+ *                   UI with a colon after it ("Status:"). Do not include
+ *                   a colon.  If NULL, value will be displayed without a
+ *                   label.
+ * @param value      The value, which might be displayed by a UI after
+ *                   the label.  If NULL, label will still be displayed;
+ *                   the UI should then treat label as independent and not
+ *                   include a colon if it would otherwise.
  */
 void purple_notify_user_info_prepend_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value);
 
 /**
- * Remove a PurpleNotifyUserInfoEntry from a PurpleNotifyUserInfo object without freeing the entry.
+ * Remove a PurpleNotifyUserInfoEntry from a PurpleNotifyUserInfo object
+ * without freeing the entry.
  *
- * @param user_info          The PurpleNotifyUserInfo
- * @param user_info_entry    The PurpleNotifyUserInfoEntry
+ * @param user_info        The PurpleNotifyUserInfo
+ * @param user_info_entry  The PurpleNotifyUserInfoEntry
  */
 void purple_notify_user_info_remove_entry(PurpleNotifyUserInfo *user_info, PurpleNotifyUserInfoEntry *user_info_entry);
+
 /**
  * Create a new PurpleNotifyUserInfoEntry
  *
- * If added to a PurpleNotifyUserInfo object, this should not be free()'d, as PurpleNotifyUserInfo will do so
- * when destroyed.  purple_notify_user_info_add_pair() and purple_notify_user_info_prepend_pair() are convenience
- * methods for creating entries and adding them to a PurpleNotifyUserInfo.
+ * If added to a PurpleNotifyUserInfo object, this should not be free()'d,
+ * as PurpleNotifyUserInfo will do so when destroyed.
+ * purple_notify_user_info_add_pair() and
+ * purple_notify_user_info_prepend_pair() are convenience methods for
+ * creating entries and adding them to a PurpleNotifyUserInfo.
  *
- * @param label              A label, which for example might be displayed by a UI with a colon after it ("Status:"). Do not include a colon.
- *                           If NULL, value will be displayed without a label.
- * @param value              The value, which might be displayed by a UI after the label.
- *                           If NULL, label will still be displayed; the UI should then treat label as independent
- *                           and not include a colon if it would otherwise.
+ * @param label  A label, which for example might be displayed by a UI
+ *               with a colon after it ("Status:"). Do not include a
+ *               colon.  If NULL, value will be displayed without a label.
+ * @param value  The value, which might be displayed by a UI after the
+ *               label.  If NULL, label will still be displayed; the UI
+ *               should then treat label as independent and not include a
+ *               colon if it would otherwise.
  *
  * @result A new PurpleNotifyUserInfoEntry
  */
@@ -572,71 +591,74 @@
 /**
  * Add a section break.  A UI might display this as a horizontal line.
  *
- * @param user_info          The PurpleNotifyUserInfo
+ * @param user_info  The PurpleNotifyUserInfo
  */
 void purple_notify_user_info_add_section_break(PurpleNotifyUserInfo *user_info);
 
 /**
  * Prepend a section break.  A UI might display this as a horizontal line.
  *
- * @param user_info          The PurpleNotifyUserInfo
+ * @param user_info  The PurpleNotifyUserInfo
  * @since 2.5.0
  */
 void purple_notify_user_info_prepend_section_break(PurpleNotifyUserInfo *user_info);
-	
+
 /**
- * Add a section header.  A UI might display this in a different font from other text.
+ * Add a section header.  A UI might display this in a different font
+ * from other text.
  *
- * @param user_info          The PurpleNotifyUserInfo
- * @param label              The name of the section
+ * @param user_info  The PurpleNotifyUserInfo
+ * @param label      The name of the section
  */
 void purple_notify_user_info_add_section_header(PurpleNotifyUserInfo *user_info, const char *label);
-	
+
 /**
- * Prepend a section header.  A UI might display this in a different font from other text.
+ * Prepend a section header.  A UI might display this in a different font
+ * from other text.
  *
- * @param user_info          The PurpleNotifyUserInfo
- * @param label              The name of the section
+ * @param user_info  The PurpleNotifyUserInfo
+ * @param label      The name of the section
  * @since 2.5.0
  */
 void purple_notify_user_info_prepend_section_header(PurpleNotifyUserInfo *user_info, const char *label);
-	
+
 /**
- * Remove the last item which was added to a PurpleNotifyUserInfo. This could be used to remove a section header which is not needed.
+ * Remove the last item which was added to a PurpleNotifyUserInfo. This
+ * could be used to remove a section header which is not needed.
  */
 void purple_notify_user_info_remove_last_item(PurpleNotifyUserInfo *user_info);
 
 /**
  * Get the label for a PurpleNotifyUserInfoEntry
  *
- * @param user_info_entry     The PurpleNotifyUserInfoEntry
+ * @param user_info_entry  The PurpleNotifyUserInfoEntry
  *
- * @result                    The label
+ * @return  The label
  */
 const gchar *purple_notify_user_info_entry_get_label(PurpleNotifyUserInfoEntry *user_info_entry);
 
 /**
  * Set the label for a PurpleNotifyUserInfoEntry
  *
- * @param user_info_entry     The PurpleNotifyUserInfoEntry
- * @param label			      The label
+ * @param user_info_entry  The PurpleNotifyUserInfoEntry
+ * @param label            The label
  */
 void purple_notify_user_info_entry_set_label(PurpleNotifyUserInfoEntry *user_info_entry, const char *label);
 
 /**
  * Get the value for a PurpleNotifyUserInfoEntry
  *
- * @param user_info_entry     The PurpleNotifyUserInfoEntry
+ * @param user_info_entry  The PurpleNotifyUserInfoEntry
  *
- * @result                    The value
+ * @result  The value
  */
 const gchar *purple_notify_user_info_entry_get_value(PurpleNotifyUserInfoEntry *user_info_entry);
 
 /**
  * Set the value for a PurpleNotifyUserInfoEntry
  *
- * @param user_info_entry     The PurpleNotifyUserInfoEntry
- * @param value				  The value
+ * @param user_info_entry  The PurpleNotifyUserInfoEntry
+ * @param value            The value
  */
 void purple_notify_user_info_entry_set_value(PurpleNotifyUserInfoEntry *user_info_entry, const char *value);
 
@@ -644,17 +666,17 @@
 /**
  * Get the type of a PurpleNotifyUserInfoEntry
  *
- * @param user_info_entry     The PurpleNotifyUserInfoEntry
+ * @param user_info_entry  The PurpleNotifyUserInfoEntry
  *
- * @result					  The PurpleNotifyUserInfoEntryType
+ * @return  The PurpleNotifyUserInfoEntryType
  */
 PurpleNotifyUserInfoEntryType purple_notify_user_info_entry_get_type(PurpleNotifyUserInfoEntry *user_info_entry);
 
 /**
  * Set the type of a PurpleNotifyUserInfoEntry
  *
- * @param user_info_entry     The PurpleNotifyUserInfoEntry
- * @param type				  The PurpleNotifyUserInfoEntryType
+ * @param user_info_entry  The PurpleNotifyUserInfoEntry
+ * @param type             The PurpleNotifyUserInfoEntryType
  */
 void purple_notify_user_info_entry_set_type(PurpleNotifyUserInfoEntry *user_info_entry,
 										  PurpleNotifyUserInfoEntryType type);
--- a/libpurple/plugins/autoaccept.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/plugins/autoaccept.c	Thu Nov 27 21:15:43 2008 +0000
@@ -95,7 +95,7 @@
 	char *dirname;
 
 	account = xfer->account;
-	node = (PurpleBlistNode *)purple_find_buddy(account, xfer->who);
+	node = PURPLE_BLIST_NODE(purple_find_buddy(account, xfer->who));
 
 	if (!node)
 	{
--- a/libpurple/plugins/statenotify.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/plugins/statenotify.c	Thu Nov 27 21:15:43 2008 +0000
@@ -32,13 +32,17 @@
 		return;
 	g_return_if_fail(conv->type == PURPLE_CONV_TYPE_IM);
 
+	/* Prevent duplicate notifications for buddies in multiple groups */
+	if (buddy != purple_find_buddy(buddy->account, buddy->name))
+		return;
+
 	who = purple_buddy_get_alias(buddy);
 	escaped = g_markup_escape_text(who, -1);
 
 	g_snprintf(buf, sizeof(buf), message, escaped);
 	g_free(escaped);
 
-	purple_conv_im_write(conv->u.im, NULL, buf, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_ACTIVE_ONLY, time(NULL));
+	purple_conv_im_write(conv->u.im, NULL, buf, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_ACTIVE_ONLY | PURPLE_MESSAGE_NO_LINKIFY, time(NULL));
 }
 
 static void
--- a/libpurple/plugins/tcl/tcl_cmds.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/plugins/tcl/tcl_cmds.c	Thu Nov 27 21:15:43 2008 +0000
@@ -401,9 +401,9 @@
 		return NULL;
 
 	if (!strcmp(type, "buddy")) {
-		node = (PurpleBlistNode *)purple_find_buddy(account, name);
+		node = PURPLE_BLIST_NODE(purple_find_buddy(account, name));
 	} else if (!strcmp(type, "group")) {
-		node = (PurpleBlistNode *)purple_blist_find_chat(account, name);
+		node = PURPLE_BLIST_NODE(purple_blist_find_chat(account, name));
 	}
 
 	return node;
--- a/libpurple/pounce.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/pounce.c	Thu Nov 27 21:15:43 2008 +0000
@@ -1042,35 +1042,39 @@
 static void
 buddy_state_cb(PurpleBuddy *buddy, PurplePounceEvent event)
 {
-	purple_pounce_execute(buddy->account, buddy->name, event);
+	PurpleAccount *account = purple_buddy_get_account(buddy);
+	const gchar *name = purple_buddy_get_name(buddy);
+
+	purple_pounce_execute(account, name, event);
 }
 
 static void
 buddy_status_changed_cb(PurpleBuddy *buddy, PurpleStatus *old_status,
                         PurpleStatus *status)
 {
+	PurpleAccount *account = purple_buddy_get_account(buddy);
+	const gchar *name = purple_buddy_get_name(buddy);
 	gboolean old_available, available;
 
 	available = purple_status_is_available(status);
 	old_available = purple_status_is_available(old_status);
 
 	if (available && !old_available)
-		purple_pounce_execute(buddy->account, buddy->name,
-		                    PURPLE_POUNCE_AWAY_RETURN);
+		purple_pounce_execute(account, name, PURPLE_POUNCE_AWAY_RETURN);
 	else if (!available && old_available)
-		purple_pounce_execute(buddy->account, buddy->name,
-		                    PURPLE_POUNCE_AWAY);
+		purple_pounce_execute(account, name, PURPLE_POUNCE_AWAY);
 }
 
 static void
 buddy_idle_changed_cb(PurpleBuddy *buddy, gboolean old_idle, gboolean idle)
 {
+	PurpleAccount *account = purple_buddy_get_account(buddy);
+	const gchar *name = purple_buddy_get_name(buddy);
+
 	if (idle && !old_idle)
-		purple_pounce_execute(buddy->account, buddy->name,
-		                    PURPLE_POUNCE_IDLE);
+		purple_pounce_execute(account, name, PURPLE_POUNCE_IDLE);
 	else if (!idle && old_idle)
-		purple_pounce_execute(buddy->account, buddy->name,
-		                    PURPLE_POUNCE_IDLE_RETURN);
+		purple_pounce_execute(account, name, PURPLE_POUNCE_IDLE_RETURN);
 }
 
 static void
--- a/libpurple/privacy.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/privacy.c	Thu Nov 27 21:15:43 2008 +0000
@@ -224,8 +224,10 @@
 	while (list != NULL)
 	{
 		PurpleBuddy *buddy = list->data;
-		if (!g_slist_find_custom(account->permit, buddy->name, (GCompareFunc)g_utf8_collate))
-			purple_privacy_permit_add(account, buddy->name, local);
+		const gchar *name = purple_buddy_get_name(buddy);
+
+		if (!g_slist_find_custom(account->permit, name, (GCompareFunc)g_utf8_collate))
+			purple_privacy_permit_add(account, name, local);
 		list = g_slist_delete_link(list, list);
 	}
 }
--- a/libpurple/protocols/bonjour/bonjour.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Thu Nov 27 21:15:43 2008 +0000
@@ -261,9 +261,10 @@
 
 
 static void bonjour_remove_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group) {
-	if (buddy->proto_data) {
-		bonjour_buddy_delete(buddy->proto_data);
-		buddy->proto_data = NULL;
+	BonjourBuddy *bb = purple_buddy_get_protocol_data(buddy);
+	if (bb) {
+		bonjour_buddy_delete(bb);
+		purple_buddy_set_protocol_data(buddy, NULL);
 	}
 }
 
@@ -303,7 +304,7 @@
 	PurpleBuddy *buddy = purple_find_buddy(connection->account, who);
 	BonjourBuddy *bb;
 
-	if (buddy == NULL || buddy->proto_data == NULL)
+	if (buddy == NULL || (bb = purple_buddy_get_protocol_data(buddy)) == NULL)
 	{
 		/*
 		 * This buddy is not in our buddy list, and therefore does not really
@@ -312,7 +313,6 @@
 		return;
 	}
 
-	bb = buddy->proto_data;
 	bonjour_jabber_close_conversation(bb->conversation);
 	bb->conversation = NULL;
 }
@@ -351,7 +351,7 @@
 {
 	PurplePresence *presence;
 	PurpleStatus *status;
-	BonjourBuddy *bb = buddy->proto_data;
+	BonjourBuddy *bb = purple_buddy_get_protocol_data(buddy);
 	const char *status_description;
 	const char *message;
 
@@ -417,8 +417,7 @@
 {
 	PurpleBuddy *buddy = purple_find_buddy(connection->account, who);
 
-	return (buddy != NULL && buddy->proto_data != NULL);
-
+	return (buddy != NULL && purple_buddy_get_protocol_data(buddy) != NULL);
 }
 
 static gboolean
--- a/libpurple/protocols/bonjour/bonjour_ft.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/bonjour/bonjour_ft.c	Thu Nov 27 21:15:43 2008 +0000
@@ -386,10 +386,9 @@
 
 	buddy = purple_find_buddy(xfer->account, xfer->who);
 	/* this buddy is offline. */
-	if (buddy == NULL || buddy->proto_data == NULL)
+	if (buddy == NULL || (bb = purple_buddy_get_protocol_data(buddy)) == NULL)
 		return;
 
-	bb = (BonjourBuddy *)buddy->proto_data;
 	/* Assume it is the first IP. We could do something like keep track of which one is in use or something. */
 	if (bb->ips)
 		xf->buddy_ip = g_strdup(bb->ips->data);
@@ -410,6 +409,7 @@
 	const char *type, *id;
 	BonjourData *bd;
 	PurpleXfer *xfer;
+	const gchar *name = NULL;
 
 	if(pc == NULL || packet == NULL || pb == NULL)
 		return;
@@ -419,6 +419,8 @@
 
 	purple_debug_info("bonjour", "xep-si-parse.\n");
 
+	name = purple_buddy_get_name(pb);
+
 	type = xmlnode_get_attrib(packet, "type");
 	id = xmlnode_get_attrib(packet, "id");
 	if(type) {
@@ -446,31 +448,34 @@
 
 				/* TODO: Make sure that it is advertising a bytestreams transfer */
 
-				bonjour_xfer_receive(pc, id, sid, pb->name, filesize, filename, XEP_BYTESTREAMS);
+				bonjour_xfer_receive(pc, id, sid, name, filesize, filename, XEP_BYTESTREAMS);
 
 				parsed_receive = TRUE;
 			}
 
 			if (!parsed_receive) {
+				BonjourData *bd = purple_connection_get_protocol_data(pc);
+
 				purple_debug_info("bonjour", "rejecting unrecognized si SET offer.\n");
-				xep_ft_si_reject((BonjourData *)pc->proto_data, id, pb->name, "403", "cancel");
+				xep_ft_si_reject(bd, id, name, "403", "cancel");
 				/*TODO: Send Cancel (501) */
 			}
 		} else if(!strcmp(type, "result")) {
 			purple_debug_info("bonjour", "si offer Message type - RESULT.\n");
 
-			xfer = bonjour_si_xfer_find(bd, id, pb->name);
+			xfer = bonjour_si_xfer_find(bd, id, name);
 
 			if(xfer == NULL) {
+				BonjourData *bd = purple_connection_get_protocol_data(pc);
 				purple_debug_info("bonjour", "xfer find fail.\n");
-				xep_ft_si_reject((BonjourData *)pc->proto_data, id, pb->name, "403", "cancel");
+				xep_ft_si_reject(bd, id, name, "403", "cancel");
 			} else
 				bonjour_bytestreams_init(xfer);
 
 		} else if(!strcmp(type, "error")) {
 			purple_debug_info("bonjour", "si offer Message type - ERROR.\n");
 
-			xfer = bonjour_si_xfer_find(bd, id, pb->name);
+			xfer = bonjour_si_xfer_find(bd, id, name);
 
 			if(xfer == NULL)
 				purple_debug_info("bonjour", "xfer find fail.\n");
@@ -498,7 +503,7 @@
 	purple_debug_info("bonjour", "xep-bytestreams-parse.\n");
 
 	type = xmlnode_get_attrib(packet, "type");
-	from = pb->name;
+	from = purple_buddy_get_name(pb);
 	query = xmlnode_get_child(packet,"query");
 	if(type) {
 		if(!strcmp(type, "set")) {
@@ -838,8 +843,10 @@
 static void
 bonjour_bytestreams_connect(PurpleXfer *xfer, PurpleBuddy *pb)
 {
+	PurpleAccount *account = NULL;
 	XepXfer *xf;
 	char dstaddr[41];
+	const gchar *name = NULL;
 	unsigned char hashval[20];
 	char *p;
 	int i;
@@ -853,7 +860,10 @@
 	if(!xf)
 		return;
 
-	p = g_strdup_printf("%s%s%s", xf->sid, pb->name, purple_account_get_username(pb->account));
+	name = purple_buddy_get_name(pb);
+	account = purple_buddy_get_account(pb);
+
+	p = g_strdup_printf("%s%s%s", xf->sid, name, purple_account_get_username(account));
 	purple_cipher_digest_region("sha1", (guchar *)p, strlen(p),
 				    sizeof(hashval), hashval, NULL);
 	g_free(p);
--- a/libpurple/protocols/bonjour/buddy.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/bonjour/buddy.c	Thu Nov 27 21:15:43 2008 +0000
@@ -157,8 +157,8 @@
 		purple_blist_add_buddy(buddy, NULL, group, NULL);
 	}
 
-	buddy->proto_data = bonjour_buddy;
 	name = purple_buddy_get_name(buddy);
+	purple_buddy_set_protocol_data(buddy, bonjour_buddy);
 
 	/* Create the alias for the buddy using the first and the last name */
 	if (bonjour_buddy->nick)
@@ -210,8 +210,8 @@
 	if (PURPLE_BLIST_NODE_SHOULD_SAVE(pb)) {
 		purple_prpl_got_user_status(purple_buddy_get_account(pb),
 					    purple_buddy_get_name(pb), "offline", NULL);
-		bonjour_buddy_delete(pb->proto_data);
-		pb->proto_data = NULL;
+		bonjour_buddy_delete(purple_buddy_get_protocol_data(pb));
+		purple_buddy_set_protocol_data(pb, NULL);
 	} else {
 		purple_account_remove_buddy(purple_buddy_get_account(pb), pb, NULL);
 		purple_blist_remove_buddy(pb);
--- a/libpurple/protocols/bonjour/jabber.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Thu Nov 27 21:15:43 2008 +0000
@@ -240,17 +240,21 @@
 _match_buddies_by_address(gpointer key, gpointer value, gpointer data)
 {
 	PurpleBuddy *pb = value;
+	PurpleAccount *account = NULL;
+	BonjourBuddy *bb = NULL;
 	struct _match_buddies_by_address_t *mbba = data;
 
+	account = purple_buddy_get_account(pb);
+	bb = purple_buddy_get_protocol_data(pb);
+
 	/*
 	 * If the current PurpleBuddy's data is not null and the PurpleBuddy's account
 	 * is the same as the account requesting the check then continue to determine
 	 * whether one of the buddies IPs matches the target IP.
 	 */
-	if (mbba->jdata->account == pb->account && pb->proto_data != NULL)
+	if (mbba->jdata->account == account && bb != NULL)
 	{
 		const char *ip;
-		BonjourBuddy *bb = pb->proto_data;
 		GSList *tmp = bb->ips;
 
 		while(tmp) {
@@ -268,7 +272,7 @@
 _send_data_write_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
 	PurpleBuddy *pb = data;
-	BonjourBuddy *bb = pb->proto_data;
+	BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
 	BonjourJabberConversation *bconv = bb->conversation;
 	int ret, writelen;
 
@@ -285,13 +289,16 @@
 	if (ret < 0 && errno == EAGAIN)
 		return;
 	else if (ret <= 0) {
-		PurpleConversation *conv;
+		PurpleConversation *conv = NULL;
+		PurpleAccount *account = NULL;
 		const char *error = g_strerror(errno);
 
 		purple_debug_error("bonjour", "Error sending message to buddy %s error: %s\n",
 				   purple_buddy_get_name(pb), error ? error : "(null)");
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account);
+		account = purple_buddy_get_account(pb);
+
+		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, account);
 		if (conv != NULL)
 			purple_conversation_write(conv, NULL,
 				  _("Unable to send message."),
@@ -310,7 +317,7 @@
 {
 	gint ret;
 	int len = strlen(message);
-	BonjourBuddy *bb = pb->proto_data;
+	BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
 	BonjourJabberConversation *bconv = bb->conversation;
 
 	/* If we're not ready to actually send, append it to the buffer */
@@ -328,13 +335,16 @@
 	if (ret == -1 && errno == EAGAIN)
 		ret = 0;
 	else if (ret <= 0) {
-		PurpleConversation *conv;
+		PurpleConversation *conv = NULL;
+		PurpleAccount *account = NULL;
 		const char *error = g_strerror(errno);
 
 		purple_debug_error("bonjour", "Error sending message to buddy %s error: %s\n",
 				   purple_buddy_get_name(pb), error ? error : "(null)");
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account);
+		account = purple_buddy_get_account(pb);
+
+		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, account);
 		if (conv != NULL)
 			purple_conversation_write(conv, NULL,
 				  _("Unable to send message."),
@@ -386,9 +396,11 @@
 			purple_debug_warning("bonjour", "receive error: %s\n", err ? err : "(null)");
 
 			bonjour_jabber_close_conversation(bconv);
-			if (bconv->pb != NULL && bconv->pb->proto_data != NULL) {
-				BonjourBuddy *bb = bconv->pb->proto_data;
-				bb->conversation = NULL;
+			if (bconv->pb != NULL) {
+				BonjourBuddy *bb = purple_buddy_get_protocol_data(bconv->pb);
+				
+				if(bb != NULL)
+					bb->conversation = NULL;
 			}
 
 			/* I guess we really don't need to notify the user.
@@ -396,7 +408,8 @@
 		}
 		return;
 	} else if (len == 0) { /* The other end has closed the socket */
-		purple_debug_warning("bonjour", "Connection closed (without stream end) by %s.\n", (bconv->pb && bconv->pb->name) ? bconv->pb->name : "(unknown)");
+		const gchar *name = purple_buddy_get_name(bconv->pb);
+		purple_debug_warning("bonjour", "Connection closed (without stream end) by %s.\n", (name) ? name : "(unknown)");
 		bonjour_jabber_stream_ended(bconv);
 		return;
 	} else {
@@ -415,15 +428,19 @@
 }
 
 void bonjour_jabber_stream_ended(BonjourJabberConversation *bconv) {
+	const gchar *name = NULL;
+	
+	if(bconv->pb != NULL)
+		name = purple_buddy_get_name(bconv->pb);
 
-	purple_debug_info("bonjour", "Recieved conversation close notification from %s.\n", bconv->pb ? bconv->pb->name : "(unknown)");
+	purple_debug_info("bonjour", "Recieved conversation close notification from %s.\n", name ? name : "(unknown)");
 
 	/* Inform the user that the conversation has been closed */
 	if (bconv != NULL) {
 		BonjourBuddy *bb = NULL;
 
 		if(bconv->pb != NULL)
-			bb = bconv->pb->proto_data;
+			bb = purple_buddy_get_protocol_data(bconv->pb);
 #if 0
 		if(bconv->pb != NULL) {
 			PurpleConversation *conv;
@@ -469,7 +486,7 @@
 		BonjourBuddy *bb = NULL;
 
 		if(bconv->pb) {
-			bb = bconv->pb->proto_data;
+			bb = purple_buddy_get_protocol_data(bconv->pb);
 			bname = purple_buddy_get_name(bconv->pb);
 		}
 
@@ -648,7 +665,7 @@
 	mbba = g_new0(struct _match_buddies_by_address_t, 1);
 	mbba->address = address_text;
 	mbba->jdata = jdata;
-	g_hash_table_foreach(purple_get_blist()->buddies, _match_buddies_by_address, mbba);
+	g_hash_table_foreach(purple_blist_get_buddies(), _match_buddies_by_address, mbba);
 
 	if (mbba->matched_buddies == NULL) {
 		purple_debug_info("bonjour", "We don't like invisible buddies, this is not a superheros comic\n");
@@ -747,17 +764,20 @@
 _connected_to_buddy(gpointer data, gint source, const gchar *error)
 {
 	PurpleBuddy *pb = data;
-	BonjourBuddy *bb = pb->proto_data;
+	BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
 
 	bb->conversation->connect_data = NULL;
 
 	if (source < 0) {
-		PurpleConversation *conv;
+		PurpleConversation *conv = NULL;
+		PurpleAccount *account = NULL;
 
 		purple_debug_error("bonjour", "Error connecting to buddy %s at %s:%d error: %s\n",
 				   purple_buddy_get_name(pb), bb->conversation->ip, bb->port_p2pj, error ? error : "(null)");
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account);
+		account = purple_buddy_get_account(pb);
+
+		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, account);
 		if (conv != NULL)
 			purple_conversation_write(conv, NULL,
 				  _("Unable to send the message, the conversation couldn't be started."),
@@ -770,12 +790,15 @@
 
 	if (!bonjour_jabber_send_stream_init(bb->conversation, source)) {
 		const char *err = g_strerror(errno);
-		PurpleConversation *conv;
+		PurpleConversation *conv = NULL;
+		PurpleAccount *account = NULL;
 
 		purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n",
 				   purple_buddy_get_name(pb), bb->conversation->ip, bb->port_p2pj, err ? err : "(null)");
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account);
+		account = purple_buddy_get_account(pb);
+
+		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, account);
 		if (conv != NULL)
 			purple_conversation_write(conv, NULL,
 				  _("Unable to send the message, the conversation couldn't be started."),
@@ -795,14 +818,14 @@
 
 void
 bonjour_jabber_conv_match_by_name(BonjourJabberConversation *bconv) {
-	PurpleBuddy *pb;
+	PurpleBuddy *pb = NULL;
+	BonjourBuddy *bb = NULL;
 
 	g_return_if_fail(bconv->ip != NULL);
 	g_return_if_fail(bconv->pb == NULL);
 
 	pb = purple_find_buddy(bconv->account, bconv->buddy_name);
-	if (pb && pb->proto_data) {
-		BonjourBuddy *bb = pb->proto_data;
+	if (pb && (bb = purple_buddy_get_protocol_data(pb))) {
 		const char *ip;
 		GSList *tmp = bb->ips;
 
@@ -852,7 +875,7 @@
 	mbba = g_new0(struct _match_buddies_by_address_t, 1);
 	mbba->address = bconv->ip;
 	mbba->jdata = jdata;
-	g_hash_table_foreach(purple_get_blist()->buddies, _match_buddies_by_address, mbba);
+	g_hash_table_foreach(purple_blist_get_buddies(), _match_buddies_by_address, mbba);
 
 	/* If there is exactly one match, use it */
 	if(mbba->matched_buddies != NULL) {
@@ -860,7 +883,7 @@
 			purple_debug_error("bonjour", "More than one buddy matched for ip %s.\n", bconv->ip);
 		else {
 			PurpleBuddy *pb = mbba->matched_buddies->data;
-			BonjourBuddy *bb = pb->proto_data;
+			BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
 
 			purple_debug_info("bonjour", "Matched buddy %s to incoming conversation using IP (%s)\n",
 				purple_buddy_get_name(pb), bconv->ip);
@@ -900,12 +923,10 @@
 	g_return_val_if_fail(to != NULL, NULL);
 
 	pb = purple_find_buddy(jdata->account, to);
-	if (pb == NULL || pb->proto_data == NULL)
+	if (pb == NULL || (bb = purple_buddy_get_protocol_data(pb)) == NULL)
 		/* You can not send a message to an offline buddy */
 		return NULL;
 
-	bb = (BonjourBuddy *) pb->proto_data;
-
 	/* Check if there is a previously open conversation */
 	if (bb->conversation == NULL)
 	{
@@ -952,7 +973,7 @@
 	int ret;
 
 	pb = _find_or_start_conversation(jdata, to);
-	if (pb == NULL || pb->proto_data == NULL) {
+	if (pb == NULL || (bb = purple_buddy_get_protocol_data(pb)) == NULL) {
 		purple_debug_info("bonjour", "Can't send a message to an offline buddy (%s).\n", to);
 		/* You can not send a message to an offline buddy */
 		return -10000;
@@ -960,8 +981,6 @@
 
 	purple_markup_html_to_xhtml(body, &xhtml, &message);
 
-	bb = pb->proto_data;
-
 	message_node = xmlnode_new("message");
 	xmlnode_set_attrib(message_node, "to", bb->name);
 	xmlnode_set_attrib(message_node, "from", purple_account_get_username(jdata->account));
@@ -1011,7 +1030,7 @@
 
 	/* Disconnect this conv. from the buddy here so it can't be disposed of twice.*/
 	if(bconv->pb != NULL) {
-		BonjourBuddy *bb = bconv->pb->proto_data;
+		BonjourBuddy *bb = purple_buddy_get_protocol_data(bconv->pb);
 		if (bb->conversation == bconv)
 			bb->conversation = NULL;
 	}
@@ -1040,7 +1059,7 @@
 				tmp_next = xfers->next;
 				/* We only need to cancel this if it hasn't actually started transferring. */
 				/* This will change if we ever support IBB transfers. */
-				if (strcmp(xfer->who, bconv->pb->name) == 0
+				if (strcmp(xfer->who, purple_buddy_get_name(bconv->pb)) == 0
 						&& (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_NOT_STARTED
 							|| purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_UNKNOWN)) {
 					purple_xfer_cancel_remote(xfer);
@@ -1099,7 +1118,7 @@
 
 		buddies = purple_find_buddies(jdata->account, NULL);
 		for (l = buddies; l; l = l->next) {
-			BonjourBuddy *bb = ((PurpleBuddy*) l->data)->proto_data;
+			BonjourBuddy *bb = purple_buddy_get_protocol_data((PurpleBuddy*) l->data);
 			if (bb != NULL) {
 				bonjour_jabber_close_conversation(bb->conversation);
 				bb->conversation = NULL;
@@ -1168,11 +1187,14 @@
 	if(pb == NULL)
 		return FALSE;
 
-	acc = pb->account;
+	acc = purple_buddy_get_account(pb);
 
 	for(l = acc->deny; l != NULL; l = l->next) {
-		if(!purple_utf8_strcasecmp(pb->name, (char *)l->data)) {
-			purple_debug_info("bonjour", "%s has been blocked by %s.\n", pb->name, acc->username);
+		const gchar *name = purple_buddy_get_name(pb);
+		const gchar *username = purple_account_get_username(acc);
+
+		if(!purple_utf8_strcasecmp(name, (char *)l->data)) {
+			purple_debug_info("bonjour", "%s has been blocked by %s.\n", name, username);
 			blocked = TRUE;
 			break;
 		}
@@ -1189,8 +1211,10 @@
 		return;
 
 	if(connection == NULL) {
-		if(pb->account != NULL)
-			connection = (pb->account)->gc;
+		PurpleAccount *account = purple_buddy_get_account(pb);
+
+		if(account != NULL)
+			connection = purple_account_get_connection(account);
 	}
 
 	if(check_if_blocked(pb))
--- a/libpurple/protocols/bonjour/mdns_avahi.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/bonjour/mdns_avahi.c	Thu Nov 27 21:15:43 2008 +0000
@@ -124,7 +124,7 @@
 	g_return_if_fail(r != NULL);
 
 	pb = purple_find_buddy(account, name);
-	bb = (pb != NULL) ? pb->proto_data : NULL;
+	bb = (pb != NULL) ? purple_buddy_get_protocol_data(pb) : NULL;
 
 	switch (event) {
 		case AVAHI_RESOLVER_FAILURE:
@@ -252,7 +252,7 @@
 			purple_debug_info("bonjour", "_browser_callback - Remove service\n");
 			pb = purple_find_buddy(account, name);
 			if (pb != NULL) {
-				BonjourBuddy *bb = pb->proto_data;
+				BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
 				AvahiBuddyImplData *b_impl;
 				GSList *l;
 				AvahiSvcResolverData *rd_search;
--- a/libpurple/protocols/gg/buddylist.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/gg/buddylist.c	Thu Nov 27 21:15:43 2008 +0000
@@ -41,37 +41,46 @@
 	GGPInfo *info = gc->proto_data;
 	PurpleAccount *account = purple_connection_get_account(gc);
 
-	PurpleBuddyList *blist;
 	PurpleBlistNode *gnode, *cnode, *bnode;
 	PurpleBuddy *buddy;
 	uin_t *userlist = NULL;
 	gchar *types = NULL;
 	int size = 0;
 
-	if ((blist = purple_get_blist()) == NULL)
-	    return;
-
-	for (gnode = blist->root; gnode != NULL; gnode = gnode->next) {
+	for (gnode = purple_blist_get_root();
+	     gnode != NULL;
+	     gnode = purple_blist_node_get_sibling_next(gnode))
+	{
 		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
 
-		for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) {
+		for (cnode = purple_blist_node_get_first_child(gnode);
+		     cnode != NULL;
+		     cnode = purple_blist_node_get_sibling_next(cnode))
+		{
 			if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
 
-			for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) {
+			for (bnode = purple_blist_node_get_first_child(cnode);
+			     bnode != NULL;
+			     bnode = purple_blist_node_get_sibling_next(bnode))
+			{
+				const gchar *name = NULL;
+
 				if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
 
 				buddy = (PurpleBuddy *)bnode;
 
-				if (buddy->account != account)
+				if (purple_buddy_get_account(buddy) != account)
 					continue;
 
+				name = purple_buddy_get_name(buddy);
+
 				size++;
 				userlist = (uin_t *) g_renew(uin_t, userlist, size);
 				types    = (gchar *) g_renew(gchar, types, size);
-				userlist[size - 1] = ggp_str_to_uin(buddy->name);
+				userlist[size - 1] = ggp_str_to_uin(name);
 				types[size - 1]    = GG_USER_NORMAL;
 				purple_debug_info("gg", "ggp_buddylist_send: adding %d\n",
 						userlist[size - 1]);
@@ -173,36 +182,45 @@
 void ggp_buddylist_offline(PurpleConnection *gc)
 {
 	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleBuddyList *blist;
 	PurpleBlistNode *gnode, *cnode, *bnode;
 	PurpleBuddy *buddy;
 
-	if ((blist = purple_get_blist()) == NULL)
-		return;
-
-	for (gnode = blist->root; gnode != NULL; gnode = gnode->next) {
+	for (gnode = purple_blist_get_root();
+	     gnode != NULL;
+	     gnode = purple_blist_node_get_sibling_next(gnode))
+	{
 		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
 
-		for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) {
+		for (cnode = purple_blist_node_get_first_child(gnode);
+		     cnode != NULL;
+		     cnode = purple_blist_node_get_sibling_next(cnode))
+		{
 			if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
 
-			for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) {
+			for (bnode = purple_blist_node_get_first_child(cnode);
+			     bnode != NULL;
+			     bnode = purple_blist_node_get_sibling_next(bnode))
+			{
+				const gchar *name = NULL;
+
 				if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
 
 				buddy = (PurpleBuddy *)bnode;
+				
+				name = purple_buddy_get_name(buddy);
 
-				if (buddy->account != account)
+				if (purple_buddy_get_account(buddy) != account)
 					continue;
 
 				purple_prpl_got_user_status(
-					account, buddy->name, "offline", NULL);
+					account, name, "offline", NULL);
 
 				purple_debug_info("gg",
 					"ggp_buddylist_offline: gone: %s\n",
-					buddy->name);
+					name);
 			}
 		}
 	}
@@ -212,7 +230,6 @@
 /* char *ggp_buddylist_dump(PurpleAccount *account) {{{ */
 char *ggp_buddylist_dump(PurpleAccount *account)
 {
-	PurpleBuddyList *blist;
 	PurpleBlistNode *gnode, *cnode, *bnode;
 	PurpleGroup *group;
 	PurpleBuddy *buddy;
@@ -220,33 +237,42 @@
 	char *buddylist = g_strdup("");
 	char *ptr;
 
-	if ((blist = purple_get_blist()) == NULL)
-		return NULL;
-
-	for (gnode = blist->root; gnode != NULL; gnode = gnode->next) {
+	for (gnode = purple_blist_get_root();
+	     gnode != NULL;
+	     gnode = purple_blist_node_get_sibling_next(gnode))
+	{
 		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
 
 		group = (PurpleGroup *)gnode;
 
-		for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) {
+		for (cnode = purple_blist_node_get_first_child(gnode);
+		     cnode != NULL;
+		     cnode = purple_blist_node_get_sibling_next(cnode))
+		{
 			if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
 
-			for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) {
-				gchar *newdata, *name, *alias, *gname;
+			for (bnode = purple_blist_node_get_first_child(cnode);
+			     bnode != NULL;
+			     bnode = purple_blist_node_get_sibling_next(bnode))
+			{
+				gchar *newdata;
+				const gchar *name, *alias, *gname;
 				gchar *cp_alias, *cp_gname;
 
 				if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
 
 				buddy = (PurpleBuddy *)bnode;
-				if (buddy->account != account)
+				if (purple_buddy_get_account(buddy) != account)
 					continue;
 
-				name = buddy->name;
-				alias = buddy->alias ? buddy->alias : buddy->name;
-				gname = group->name;
+				name = purple_buddy_get_name(buddy);
+				alias = purple_buddy_get_alias(buddy);
+				if(alias == NULL)
+					alias = name;
+				gname = purple_group_get_name(group);
 
 				cp_gname = charset_convert(gname, "UTF-8", "CP1250");
 				cp_alias = charset_convert(alias, "UTF-8", "CP1250");
--- a/libpurple/protocols/gg/gg.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/gg/gg.c	Thu Nov 27 21:15:43 2008 +0000
@@ -61,7 +61,6 @@
  *
  * @return Zero if proxy setup is valid, otherwise -1.
  */
-/* static int ggp_setup_proxy(PurpleAccount *account) {{{ */
 static int ggp_setup_proxy(PurpleAccount *account)
 {
 	PurpleProxyInfo *gpi;
@@ -88,11 +87,7 @@
 
 	return 0;
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_async_token_handler(gpointer _gc, gint fd, PurpleInputCondition cond) {{{ */
 static void ggp_async_token_handler(gpointer _gc, gint fd, PurpleInputCondition cond)
 {
 	PurpleConnection *gc = _gc;
@@ -157,11 +152,7 @@
 	token->cb = NULL;
 	cb(gc);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_token_request(PurpleConnection *gc, GGPTokenCallback cb) {{{ */
 static void ggp_token_request(PurpleConnection *gc, GGPTokenCallback cb)
 {
 	PurpleAccount *account;
@@ -199,7 +190,6 @@
  *
  * @param Current action handler.
  */
-/* static void ggp_action_buddylist_get(PurplePluginAction *action) {{{ */
 static void ggp_action_buddylist_get(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *)action->context;
@@ -209,14 +199,12 @@
 
 	gg_userlist_request(info->session, GG_USERLIST_GET, NULL);
 }
-/* }}} */
 
 /**
  * Upload the buddylist to the server.
  *
  * @param action Current action handler.
  */
-/* static void ggp_action_buddylist_put(PurplePluginAction *action) {{{ */
 static void ggp_action_buddylist_put(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *)action->context;
@@ -232,14 +220,12 @@
 	gg_userlist_request(info->session, GG_USERLIST_PUT, buddylist);
 	g_free(buddylist);
 }
-/* }}} */
 
 /**
  * Delete buddylist from the server.
  *
  * @param action Current action handler.
  */
-/* static void ggp_action_buddylist_delete(PurplePluginAction *action) {{{ */
 static void ggp_action_buddylist_delete(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *)action->context;
@@ -249,11 +235,7 @@
 
 	gg_userlist_request(info->session, GG_USERLIST_PUT, NULL);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, const char *file) {{{ */
 static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, const char *filename)
 {
 	PurpleAccount *account = purple_connection_get_account(gc);
@@ -284,11 +266,7 @@
 
 	g_free(buddylist);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_callback_buddylist_load_ok(PurpleConnection *gc, gchar *file) {{{ */
 static void ggp_callback_buddylist_load_ok(PurpleConnection *gc, gchar *file)
 {
 	PurpleAccount *account = purple_connection_get_account(gc);
@@ -334,11 +312,7 @@
 			purple_connection_get_account(gc), NULL, NULL,
 			gc);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_action_buddylist_load(PurplePluginAction *action) {{{ */
 static void ggp_action_buddylist_load(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *)action->context;
@@ -349,11 +323,7 @@
 			purple_connection_get_account(gc), NULL, NULL,
 			gc);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_callback_register_account_ok(PurpleConnection *gc, PurpleRequestFields *fields) {{{ */
 static void ggp_callback_register_account_ok(PurpleConnection *gc,
 					     PurpleRequestFields *fields)
 {
@@ -435,11 +405,7 @@
 	g_free(token->id);
 	g_free(token);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_callback_register_account_cancel(PurpleConnection *gc, PurpleRequestFields *fields) {{{ */
 static void ggp_callback_register_account_cancel(PurpleConnection *gc,
 						 PurpleRequestFields *fields)
 {
@@ -453,11 +419,7 @@
 	g_free(token);
 
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_register_user_dialog(PurpleConnection *gc) {{{ */
 static void ggp_register_user_dialog(PurpleConnection *gc)
 {
 	PurpleAccount *account;
@@ -510,13 +472,9 @@
 		purple_connection_get_account(gc), NULL, NULL,
 		gc);
 }
-/* }}} */
 
 /* ----- PUBLIC DIRECTORY SEARCH ---------------------------------------- */
 
-/*
- */
-/* static void ggp_callback_show_next(PurpleConnection *gc, GList *row, gpointer user_data) {{{ */
 static void ggp_callback_show_next(PurpleConnection *gc, GList *row, gpointer user_data)
 {
 	GGPInfo *info = gc->proto_data;
@@ -533,21 +491,13 @@
 	ggp_search_add(info->searches, seq, form);
 	purple_debug_info("gg", "ggp_callback_show_next(): Added seq %u", seq);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_callback_add_buddy(PurpleConnection *gc, GList *row, gpointer user_data) {{{ */
 static void ggp_callback_add_buddy(PurpleConnection *gc, GList *row, gpointer user_data)
 {
 	purple_blist_request_add_buddy(purple_connection_get_account(gc),
 				     g_list_nth_data(row, 0), NULL, NULL);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_callback_im(PurpleConnection *gc, GList *row, gpointer user_data) {{{ */
 static void ggp_callback_im(PurpleConnection *gc, GList *row, gpointer user_data)
 {
 	PurpleAccount *account;
@@ -560,11 +510,7 @@
 	conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name);
 	purple_conversation_present(conv);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_callback_find_buddies(PurpleConnection *gc, PurpleRequestFields *fields) {{{ */
 static void ggp_callback_find_buddies(PurpleConnection *gc, PurpleRequestFields *fields)
 {
 	GGPInfo *info = gc->proto_data;
@@ -611,11 +557,7 @@
 	ggp_search_add(info->searches, seq, form);
 	purple_debug_info("gg", "ggp_callback_find_buddies(): Added seq %u", seq);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_find_buddies(PurplePluginAction *action) {{{ */
 static void ggp_find_buddies(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *)action->context;
@@ -672,13 +614,9 @@
 		purple_connection_get_account(gc), NULL, NULL,
 		gc);
 }
-/* }}} */
 
 /* ----- CHANGE PASSWORD ------------------------------------------------ */
 
-/*
- */
-/* static void ggp_callback_change_passwd_ok(PurpleConnection *gc, PurpleRequestFields *fields) {{{ */
 static void ggp_callback_change_passwd_ok(PurpleConnection *gc, PurpleRequestFields *fields)
 {
 	PurpleAccount *account;
@@ -750,11 +688,7 @@
 	g_free(info->token->data);
 	g_free(info->token);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_change_passwd_dialog(PurpleConnection *gc) {{{ */
 static void ggp_change_passwd_dialog(PurpleConnection *gc)
 {
 	PurpleRequestFields *fields;
@@ -811,24 +745,16 @@
 
 	g_free(msg);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_change_passwd(PurplePluginAction *action) {{{ */
 static void ggp_change_passwd(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *)action->context;
 
 	ggp_token_request(gc, ggp_change_passwd_dialog);
 }
-/* }}} */
 
 /* ----- CONFERENCES ---------------------------------------------------- */
 
-/*
- */
-/* static void ggp_callback_add_to_chat_ok(PurpleConnection *gc, PurpleRequestFields *fields) {{{ */
 static void ggp_callback_add_to_chat_ok(PurpleConnection *gc, PurpleRequestFields *fields)
 {
 	GGPInfo *info = gc->proto_data;
@@ -842,11 +768,7 @@
 	ggp_confer_participants_add_uin(gc, sel->data, info->tmp_buddy);
 	info->tmp_buddy = 0;
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_bmenu_add_to_chat(PurpleBlistNode *node, gpointer ignored) {{{ */
 static void ggp_bmenu_add_to_chat(PurpleBlistNode *node, gpointer ignored)
 {
 	PurpleBuddy *buddy;
@@ -892,13 +814,9 @@
 			gc);
 	g_free(msg);
 }
-/* }}} */
 
 /* ----- BLOCK BUDDIES -------------------------------------------------- */
 
-/*
- */
-/* static void ggp_bmenu_block(PurpleBlistNode *node, gpointer ignored) {{{ */
 static void ggp_bmenu_block(PurpleBlistNode *node, gpointer ignored)
 {
 	PurpleConnection *gc;
@@ -924,7 +842,6 @@
 		purple_debug_info("gg", "send: uin=%d; mode=BLOCKED\n", uin);
 	}
 }
-/* }}} */
 
 /* ---------------------------------------------------------------------- */
 /* ----- INTERNAL CALLBACKS --------------------------------------------- */
@@ -943,7 +860,6 @@
  * @param status ID of the status.
  * @param descr  Description.
  */
-/* static void ggp_generic_status_handler(PurpleConnection *gc, uin_t uin, int status, const char *descr) {{{ */
 static void ggp_generic_status_handler(PurpleConnection *gc, uin_t uin,
 				       int status, const char *descr)
 {
@@ -983,11 +899,7 @@
 	g_free(from);
 	g_free(msg);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_sr_close_cb(gpointer user_data) {{{ */
 static void ggp_sr_close_cb(gpointer user_data)
 {
 	GGPSearchForm *form = user_data;
@@ -997,7 +909,6 @@
 	purple_debug_info("gg", "ggp_sr_close_cb(): Removed seq %u", form->seq);
 	ggp_search_form_destroy(form);
 }
-/* }}} */
 
 /**
  * Translate a status' ID to a more user-friendly name.
@@ -1006,7 +917,6 @@
  *
  * @return The user-friendly name of the status.
  */
-/* static const char *ggp_status_by_id(unsigned int id) {{{ */
 static const char *ggp_status_by_id(unsigned int id)
 {
 	const char *st;
@@ -1029,11 +939,7 @@
 
 	return st;
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_pubdir_handle_info(PurpleConnection *gc, gg_pubdir50_t req, GGPSearchForm *form) {{{ */
 static void ggp_pubdir_handle_info(PurpleConnection *gc, gg_pubdir50_t req,
 				   GGPSearchForm *form)
 {
@@ -1092,11 +998,7 @@
 	g_free(who);
 	purple_notify_user_info_destroy(user_info);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_pubdir_handle_full(PurpleConnection *gc, gg_pubdir50_t req, GGPSearchForm *form) {{{ */
 static void ggp_pubdir_handle_full(PurpleConnection *gc, gg_pubdir50_t req,
 				   GGPSearchForm *form)
 {
@@ -1196,11 +1098,7 @@
 		purple_notify_searchresults_new_rows(gc, results, form->window);
 	}
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_pubdir_reply_handler(PurpleConnection *gc, gg_pubdir50_t req) {{{ */
 static void ggp_pubdir_reply_handler(PurpleConnection *gc, gg_pubdir50_t req)
 {
 	GGPInfo *info = gc->proto_data;
@@ -1239,15 +1137,56 @@
 			break;
 	}
 }
-/* }}} */
+
+static void ggp_recv_image_handler(PurpleConnection *gc, const struct gg_event *ev)
+{
+	gint imgid = 0;
+	GGPInfo *info = gc->proto_data;
+	GList *entry = g_list_first(info->pending_richtext_messages);
+	gchar *handlerid = g_strdup_printf("IMGID_HANDLER-%i", ev->event.image_reply.crc32);
+
+	imgid = purple_imgstore_add_with_id(
+		g_memdup(ev->event.image_reply.image, ev->event.image_reply.size),
+		ev->event.image_reply.size,
+		ev->event.image_reply.filename);
+
+	purple_debug_info("gg", "ggp_recv_image_handler: got image with crc32: %u\n", ev->event.image_reply.crc32);
+
+	while(entry) {
+		if (strstr((gchar *)entry->data, handlerid) != NULL) {
+			gchar **split = g_strsplit((gchar *)entry->data, handlerid, 3);
+			gchar *text = g_strdup_printf("%s%i%s", split[0], imgid, split[1]);
+			purple_debug_info("gg", "ggp_recv_image_handler: found message matching crc32: %s\n", (gchar *)entry->data);
+			g_strfreev(split);
+			info->pending_richtext_messages = g_list_remove(info->pending_richtext_messages, entry->data);
+			/* We don't have any more images to download */
+			if (strstr(text, "<IMG ID=\"IMGID_HANDLER") == NULL) {
+				gchar *buf = g_strdup_printf("%lu", (unsigned long int)ev->event.msg.sender);
+				serv_got_im(gc, buf, text, PURPLE_MESSAGE_IMAGES, ev->event.msg.time);
+				g_free(buf);
+				purple_debug_info("gg", "ggp_recv_image_handler: richtext message: %s\n", text);
+				g_free(text);
+				break;
+			}
+			info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, text);
+			break;
+		}
+		entry = g_list_next(entry);
+	}
+	g_free(handlerid);
+
+	return;
+}
+
 
 /**
  * Dispatch a message received from a buddy.
  *
  * @param gc PurpleConnection.
  * @param ev Gadu-Gadu event structure.
+ *
+ * Image receiving, some code borrowed from Kadu http://www.kadu.net
  */
-/* static void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event *ev) {{{ */
 static void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event *ev)
 {
 	GGPInfo *info = gc->proto_data;
@@ -1264,7 +1203,109 @@
 	msg = g_markup_escape_text(tmp, -1);
 	g_free(tmp);
 
-	purple_debug_info("gg", "msg form (%s): %s (class = %d; rcpt_count = %d)\n",
+	/* We got richtext message */
+	if (ev->event.msg.formats_length)
+	{
+		gboolean got_image = FALSE, bold = FALSE, italic = FALSE, under = FALSE;
+		char *cformats = (char *)ev->event.msg.formats;
+		char *cformats_end = cformats + ev->event.msg.formats_length;
+		gint increased_len = 0;
+		struct gg_msg_richtext_format *actformat;
+		struct gg_msg_richtext_image *actimage;
+		GString *message = g_string_new(msg);
+		gchar *handlerid;
+
+		purple_debug_info("gg", "ggp_recv_message_handler: richtext msg from (%s): %s %i formats\n", from, msg, ev->event.msg.formats_length);
+
+		while (cformats < cformats_end)
+		{
+			gint byteoffset;
+			actformat = (struct gg_msg_richtext_format *)cformats;
+			cformats += sizeof(struct gg_msg_richtext_format);
+			byteoffset = g_utf8_offset_to_pointer(message->str, actformat->position + increased_len) - message->str;
+
+			if(actformat->position == 0 && actformat->font == 0) {
+				purple_debug_warning("gg", "ggp_recv_message_handler: bogus formatting (inc: %i)\n", increased_len);
+				continue;
+			}
+			purple_debug_info("gg", "ggp_recv_message_handler: format at pos: %i, image:%i, bold:%i, italic: %i, under:%i (inc: %i)\n",
+				actformat->position,
+				(actformat->font & GG_FONT_IMAGE) != 0,
+				(actformat->font & GG_FONT_BOLD) != 0,
+				(actformat->font & GG_FONT_ITALIC) != 0,
+				(actformat->font & GG_FONT_UNDERLINE) != 0,
+				increased_len);
+
+			if (actformat->font & GG_FONT_IMAGE) {
+				got_image = TRUE;
+				actimage = (struct gg_msg_richtext_image*)(cformats);
+				cformats += sizeof(struct gg_msg_richtext_image);
+				purple_debug_info("gg", "ggp_recv_message_handler: image received, size: %d, crc32: %i\n", actimage->size, actimage->crc32);
+
+				/* Checking for errors, image size shouldn't be
+				 * larger than 255.000 bytes */
+				if (actimage->size > 255000) {
+					purple_debug_warning("gg", "ggp_recv_message_handler: received image large than 255 kb\n");
+					continue;
+				}
+
+				gg_image_request(info->session, ev->event.msg.sender,
+					actimage->size, actimage->crc32);
+
+				handlerid = g_strdup_printf("<IMG ID=\"IMGID_HANDLER-%i\">", actimage->crc32);
+				g_string_insert(message, byteoffset, handlerid);
+				increased_len += strlen(handlerid);
+				g_free(handlerid);
+				continue;
+			}
+
+			if (actformat->font & GG_FONT_BOLD) {
+				if (bold == FALSE) {
+					g_string_insert(message, byteoffset, "<b>");
+					increased_len += 3;
+					bold = TRUE;
+				}
+			} else if (bold) {
+				g_string_insert(message, byteoffset, "</b>");
+				increased_len += 4;
+				bold = FALSE;
+			}
+
+			if (actformat->font & GG_FONT_ITALIC) {
+				if (italic == FALSE) {
+					g_string_insert(message, byteoffset, "<i>");
+					increased_len += 3;
+					italic = TRUE;
+				}
+			} else if (italic) {
+				g_string_insert(message, byteoffset, "</i>");
+				increased_len += 4;
+				italic = FALSE;
+			}
+
+			if (actformat->font & GG_FONT_UNDERLINE) {
+				if (under == FALSE) {
+					g_string_insert(message, byteoffset, "<u>");
+					increased_len += 3;
+					under = TRUE;
+				}
+			} else if (under) {
+				g_string_insert(message, byteoffset, "</u>");
+				increased_len += 4;
+				under = FALSE;
+			}
+		}
+
+		msg = message->str;
+		g_string_free(message, FALSE);
+
+		if (got_image) {
+			info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, msg);
+			return;
+		}
+	}
+
+	purple_debug_info("gg", "ggp_recv_message_handler: msg from (%s): %s (class = %d; rcpt_count = %d)\n",
 			from, msg, ev->event.msg.msgclass,
 			ev->event.msg.recipients_count);
 
@@ -1301,11 +1342,32 @@
 	g_free(msg);
 	g_free(from);
 }
-/* }}} */
+
+static void ggp_send_image_handler(PurpleConnection *gc, const struct gg_event *ev)
+{
+	GGPInfo *info = gc->proto_data;
+	PurpleStoredImage *image;
+	gint imgid = GPOINTER_TO_INT(g_hash_table_lookup(info->pending_images, &ev->event.image_request.crc32));
+
+	purple_debug_info("gg", "ggp_send_image_handler: image request received, crc32: %u\n", ev->event.image_request.crc32);
 
-/*
- */
-/* static void ggp_callback_recv(gpointer _gc, gint fd, PurpleInputCondition cond) {{{ */
+	if(imgid)
+	{
+		if((image = purple_imgstore_find_by_id(imgid))) {
+			gint image_size = purple_imgstore_get_size(image);
+			gconstpointer image_bin = purple_imgstore_get_data(image);
+			const char *image_filename = purple_imgstore_get_filename(image);
+
+			purple_debug_info("gg", "ggp_send_image_handler: sending image imgid: %i, crc: %u\n", imgid, ev->event.image_request.crc32);
+			gg_image_reply(info->session, (unsigned long int)ev->event.image_request.sender, image_filename, image_bin, image_size);
+			purple_imgstore_unref(image);
+		} else {
+			purple_debug_error("gg", "ggp_send_image_handler: image imgid: %i, crc: %u in hash but not found in imgstore!\n", imgid, ev->event.image_request.crc32);
+		}
+		g_hash_table_remove(info->pending_images, &ev->event.image_request.crc32);
+	}
+}
+
 static void ggp_callback_recv(gpointer _gc, gint fd, PurpleInputCondition cond)
 {
 	PurpleConnection *gc = _gc;
@@ -1330,11 +1392,18 @@
 			ggp_recv_message_handler(gc, ev);
 			break;
 		case GG_EVENT_ACK:
+			/* Changing %u to %i fixes compiler warning */
 			purple_debug_info("gg",
-				"message sent to: %u, delivery status=%d, seq=%d\n",
+				"ggp_callback_recv: message sent to: %i, delivery status=%d, seq=%d\n",
 				ev->event.ack.recipient, ev->event.ack.status,
 				ev->event.ack.seq);
 			break;
+		case GG_EVENT_IMAGE_REPLY:
+			ggp_recv_image_handler(gc, ev);
+			break;
+		case GG_EVENT_IMAGE_REQUEST:
+			ggp_send_image_handler(gc, ev);
+			break;
 		case GG_EVENT_NOTIFY:
 		case GG_EVENT_NOTIFY_DESCR:
 			{
@@ -1426,11 +1495,7 @@
 
 	gg_free_event(ev);
 }
-/* }}} */
 
-/*
- */
-/* static void ggp_async_login_handler(gpointer _gc, gint fd, PurpleInputCondition cond) {{{ */
 static void ggp_async_login_handler(gpointer _gc, gint fd, PurpleInputCondition cond)
 {
 	PurpleConnection *gc = _gc;
@@ -1519,20 +1584,16 @@
 
 	gg_free_event(ev);
 }
-/* }}} */
 
 /* ---------------------------------------------------------------------- */
 /* ----- PurplePluginProtocolInfo ----------------------------------------- */
 /* ---------------------------------------------------------------------- */
 
-/* static const char *ggp_list_icon(PurpleAccount *account, PurpleBuddy *buddy) {{{ */
 static const char *ggp_list_icon(PurpleAccount *account, PurpleBuddy *buddy)
 {
 	return "gadu-gadu";
 }
-/* }}} */
 
-/* static char *ggp_status_text(PurpleBuddy *b) {{{ */
 static char *ggp_status_text(PurpleBuddy *b)
 {
 	PurpleStatus *status;
@@ -1558,20 +1619,21 @@
 		return text;
 	}
 }
-/* }}} */
 
-/* static void ggp_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) {{{ */
 static void ggp_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
 {
 	PurpleStatus *status;
 	char *text, *tmp;
-	const char *msg, *name;
+	const char *msg, *name, *alias;
 
 	g_return_if_fail(b != NULL);
 
 	status = purple_presence_get_active_status(purple_buddy_get_presence(b));
 	msg = purple_status_get_attr_string(status, "message");
 	name = purple_status_get_name(status);
+	alias = purple_buddy_get_alias(b);
+
+	purple_notify_user_info_add_pair (user_info, _("Alias"), alias);
 
 	if (msg != NULL) {
 		text = g_markup_escape_text(msg, -1);
@@ -1588,9 +1650,7 @@
 		purple_notify_user_info_add_pair(user_info, _("Status"), name);
 	}
 }
-/* }}} */
 
-/* static GList *ggp_status_types(PurpleAccount *account) {{{ */
 static GList *ggp_status_types(PurpleAccount *account)
 {
 	PurpleStatusType *type;
@@ -1634,9 +1694,7 @@
 
 	return types;
 }
-/* }}} */
 
-/* static GList *ggp_blist_node_menu(PurpleBlistNode *node) {{{ */
 static GList *ggp_blist_node_menu(PurpleBlistNode *node)
 {
 	PurpleMenuAction *act;
@@ -1666,9 +1724,7 @@
 
 	return m;
 }
-/* }}} */
 
-/* static GList *ggp_chat_info(PurpleConnection *gc) {{{ */
 static GList *ggp_chat_info(PurpleConnection *gc)
 {
 	GList *m = NULL;
@@ -1682,9 +1738,7 @@
 
 	return m;
 }
-/* }}} */
 
-/* static void ggp_login(PurpleAccount *account) {{{ */
 static void ggp_login(PurpleAccount *account)
 {
 	PurpleConnection *gc;
@@ -1706,11 +1760,14 @@
 	info->chats_count = 0;
 	info->token = NULL;
 	info->searches = ggp_search_new();
+	info->pending_richtext_messages = NULL;
+	info->pending_images = g_hash_table_new(g_int_hash, g_int_equal);
 
 	gc->proto_data = info;
 
 	glp->uin = ggp_get_uin(account);
 	glp->password = (char *)purple_account_get_password(account);
+	glp->image_size = 255;
 
 	presence = purple_account_get_presence(account);
 	status = purple_presence_get_active_status(presence);
@@ -1730,9 +1787,7 @@
 	gc->inpa = purple_input_add(info->session->fd, PURPLE_INPUT_READ,
 				  ggp_async_login_handler, gc);
 }
-/* }}} */
 
-/* static void ggp_close(PurpleConnection *gc) {{{ */
 static void ggp_close(PurpleConnection *gc)
 {
 
@@ -1760,6 +1815,8 @@
 		purple_notify_close_with_handle(gc);
 
 		ggp_search_destroy(info->searches);
+		g_list_free(info->pending_richtext_messages);
+		g_hash_table_destroy(info->pending_images);
 		g_free(info);
 		gc->proto_data = NULL;
 	}
@@ -1771,25 +1828,108 @@
 
 	purple_debug_info("gg", "Connection closed.\n");
 }
-/* }}} */
 
-/* static int ggp_send_im(PurpleConnection *gc, const char *who, const char *msg, PurpleMessageFlags flags) {{{ */
 static int ggp_send_im(PurpleConnection *gc, const char *who, const char *msg,
 		       PurpleMessageFlags flags)
 {
 	GGPInfo *info = gc->proto_data;
 	char *tmp, *plain;
-	int ret = 0;
+	int ret = 1;
+	unsigned char format[1024];
+	unsigned int format_length = sizeof(struct gg_msg_richtext);
+	gint pos = 0;
+	GData *attribs;
+	const char *start, *end = NULL, *last;
 
-	if (strlen(msg) == 0) {
+	if (msg == NULL || *msg == '\0') {
 		return 0;
 	}
 
-	purple_debug_info("gg", "ggp_send_im: msg = %s\n", msg);
-	plain = purple_unescape_html(msg);
+	last = msg;
+
+	/* Check if the message is richtext */
+	/* TODO: Check formatting, too */
+	if(purple_markup_find_tag("img", last, &start, &end, &attribs)) {
+
+		GString *string_buffer = g_string_new(NULL);
+		struct gg_msg_richtext fmt;
+
+		do {
+			PurpleStoredImage *image;
+			const char *id;
+
+			/* Add text before the image */
+			if(start - last) {
+				pos = pos + g_utf8_strlen(last, start - last);
+				g_string_append_len(string_buffer, last, start - last);
+			}
+
+			if((id = g_datalist_get_data(&attribs, "id")) && (image = purple_imgstore_find_by_id(atoi(id)))) {
+				struct gg_msg_richtext_format actformat;
+				struct gg_msg_richtext_image actimage;
+				gint image_size = purple_imgstore_get_size(image);
+				gconstpointer image_bin = purple_imgstore_get_data(image);
+				const char *image_filename = purple_imgstore_get_filename(image);
+				uint32_t crc32 = gg_crc32(0, image_bin, image_size);
+
+				g_hash_table_insert(info->pending_images, &crc32, GINT_TO_POINTER(atoi(id)));
+				purple_imgstore_ref(image);
+				purple_debug_info("gg", "ggp_send_im_richtext: got crc: %i for imgid: %i\n", crc32, atoi(id));
+
+				actformat.font = GG_FONT_IMAGE;
+				actformat.position = pos;
+
+				actimage.unknown1 = 0x0109;
+				actimage.size = gg_fix32(image_size);
+				actimage.crc32 = gg_fix32(crc32);
+
+				if (actimage.size > 255000) {
+					purple_debug_warning("gg", "ggp_send_im_richtext: image over 255kb!\n");
+					continue;
+				}
+
+				purple_debug_info("gg", "ggp_send_im_richtext: adding images to richtext, size: %i, crc32: %u, name: %s\n", actimage.size, actimage.crc32, image_filename);
+
+				memcpy(format + format_length, &actformat, sizeof(actformat));
+				format_length += sizeof(actformat);
+				memcpy(format + format_length, &actimage, sizeof(actimage));
+				format_length += sizeof(actimage);
+			} else {
+				purple_debug_error("gg", "ggp_send_im_richtext: image not found in the image store!");
+			}
+
+			last = end + 1;
+			g_datalist_clear(&attribs);
+
+		} while(purple_markup_find_tag("img", last, &start, &end, &attribs));
+
+		/* Add text after the images */
+		if(last && *last) {
+			pos = pos + g_utf8_strlen(last, -1);
+			g_string_append(string_buffer, last);
+		}
+
+		fmt.flag = 2;
+		fmt.length = format_length - sizeof(fmt);
+		memcpy(format, &fmt, sizeof(fmt));
+
+		purple_debug_info("gg", "ggp_send_im: richtext msg = %s\n", string_buffer->str);
+		plain = purple_unescape_html(string_buffer->str);
+		g_string_free(string_buffer, TRUE);
+	} else {
+		purple_debug_info("gg", "ggp_send_im: msg = %s\n", msg);
+		plain = purple_unescape_html(msg);
+	}
+
 	tmp = charset_convert(plain, "UTF-8", "CP1250");
 
-	if (NULL == tmp || strlen(tmp) == 0) {
+	if (tmp && (format_length - sizeof(struct gg_msg_richtext))) {
+		if(gg_send_message_richtext(info->session, GG_CLASS_CHAT, ggp_str_to_uin(who), (unsigned char *)tmp, format, format_length) < 0) {
+			ret = -1;
+		} else {
+			ret = 1;
+		}
+	} else if (NULL == tmp || *tmp == 0) {
 		ret = 0;
 	} else if (strlen(tmp) > GG_MSG_MAXSIZE) {
 		ret = -E2BIG;
@@ -1805,9 +1945,7 @@
 
 	return ret;
 }
-/* }}} */
 
-/* static void ggp_get_info(PurpleConnection *gc, const char *name) { {{{ */
 static void ggp_get_info(PurpleConnection *gc, const char *name)
 {
 	GGPInfo *info = gc->proto_data;
@@ -1825,9 +1963,7 @@
 	ggp_search_add(info->searches, seq, form);
 	purple_debug_info("gg", "ggp_get_info(): Added seq %u", seq);
 }
-/* }}} */
 
-/* static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) {{{ */
 static int ggp_to_gg_status(PurpleStatus *status, char **msg)
 {
 	const char *status_id = purple_status_get_id(status);
@@ -1872,9 +2008,7 @@
 		return new_status;
 	}
 }
-/* }}} */
 
-/* static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) {{{ */
 static void ggp_set_status(PurpleAccount *account, PurpleStatus *status)
 {
 	PurpleConnection *gc;
@@ -1900,34 +2034,29 @@
 	ggp_status_fake_to_self(account);
 
 }
-/* }}} */
 
-/* static void ggp_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {{{ */
 static void ggp_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
 {
 	PurpleAccount *account;
 	GGPInfo *info = gc->proto_data;
+	const gchar *name = purple_buddy_get_name(buddy);
 
-	gg_add_notify(info->session, ggp_str_to_uin(buddy->name));
+	gg_add_notify(info->session, ggp_str_to_uin(name));
 
 	account = purple_connection_get_account(gc);
-	if (strcmp(purple_account_get_username(account), buddy->name) == 0) {
+	if (strcmp(purple_account_get_username(account), name) == 0) {
 		ggp_status_fake_to_self(account);
 	}
 }
-/* }}} */
 
-/* static void ggp_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {{{ */
 static void ggp_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
 						 PurpleGroup *group)
 {
 	GGPInfo *info = gc->proto_data;
 
-	gg_remove_notify(info->session, ggp_str_to_uin(buddy->name));
+	gg_remove_notify(info->session, ggp_str_to_uin(purple_buddy_get_name(buddy)));
 }
-/* }}} */
 
-/* static void ggp_join_chat(PurpleConnection *gc, GHashTable *data) {{{ */
 static void ggp_join_chat(PurpleConnection *gc, GHashTable *data)
 {
 	GGPInfo *info = gc->proto_data;
@@ -1960,15 +2089,11 @@
 				purple_account_get_username(account), NULL,
 				PURPLE_CBFLAGS_NONE, TRUE);
 }
-/* }}} */
 
-/* static char *ggp_get_chat_name(GHashTable *data) { {{{ */
 static char *ggp_get_chat_name(GHashTable *data) {
 	return g_strdup(g_hash_table_lookup(data, "name"));
 }
-/* }}} */
 
-/* static int ggp_chat_send(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags) {{{ */
 static int ggp_chat_send(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags)
 {
 	PurpleConversation *conv;
@@ -2020,9 +2145,7 @@
 
 	return 0;
 }
-/* }}} */
 
-/* static void ggp_keepalive(PurpleConnection *gc) {{{ */
 static void ggp_keepalive(PurpleConnection *gc)
 {
 	GGPInfo *info = gc->proto_data;
@@ -2037,9 +2160,7 @@
 			_("Not connected to the server."));
 	}
 }
-/* }}} */
 
-/* static void ggp_register_user(PurpleAccount *account) {{{ */
 static void ggp_register_user(PurpleAccount *account)
 {
 	PurpleConnection *gc = purple_account_get_connection(account);
@@ -2049,9 +2170,7 @@
 
 	ggp_token_request(gc, ggp_register_user_dialog);
 }
-/* }}} */
 
-/* static GList *ggp_actions(PurplePlugin *plugin, gpointer context) {{{ */
 static GList *ggp_actions(PurplePlugin *plugin, gpointer context)
 {
 	GList *m = NULL;
@@ -2091,19 +2210,15 @@
 
 	return m;
 }
-/* }}} */
 
-/* static gboolean ggp_offline_message(const PurpleBuddy *buddy) {{{ */
 static gboolean ggp_offline_message(const PurpleBuddy *buddy)
 {
 	return TRUE;
 }
-/* }}} */
 
-/* prpl_info setup {{{ */
 static PurplePluginProtocolInfo prpl_info =
 {
-	OPT_PROTO_REGISTER_NOSCREENNAME,
+	OPT_PROTO_REGISTER_NOSCREENNAME | OPT_PROTO_IM_IMAGE,
 	NULL,				/* user_splits */
 	NULL,				/* protocol_options */
 	{"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY},	/* icon_spec */
@@ -2173,36 +2288,34 @@
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
 	NULL
 };
-/* }}} */
 
-/* PurplePluginInfo setup {{{ */
 static PurplePluginInfo info = {
-	PURPLE_PLUGIN_MAGIC,		/* magic */
-	PURPLE_MAJOR_VERSION,		/* major_version */
-	PURPLE_MINOR_VERSION,		/* minor_version */
-	PURPLE_PLUGIN_PROTOCOL,		/* plugin type */
-	NULL,				/* ui_requirement */
-	0,				/* flags */
-	NULL,				/* dependencies */
+	PURPLE_PLUGIN_MAGIC,			/* magic */
+	PURPLE_MAJOR_VERSION,			/* major_version */
+	PURPLE_MINOR_VERSION,			/* minor_version */
+	PURPLE_PLUGIN_PROTOCOL,			/* plugin type */
+	NULL,					/* ui_requirement */
+	0,					/* flags */
+	NULL,					/* dependencies */
 	PURPLE_PRIORITY_DEFAULT,		/* priority */
 
-	"prpl-gg",			/* id */
-	"Gadu-Gadu",			/* name */
-	DISPLAY_VERSION,		/* version */
+	"prpl-gg",				/* id */
+	"Gadu-Gadu",				/* name */
+	DISPLAY_VERSION,			/* version */
 
 	N_("Gadu-Gadu Protocol Plugin"),	/* summary */
 	N_("Polish popular IM"),		/* description */
-	"boler@sourceforge.net",	/* author */
-	PURPLE_WEBSITE,			/* homepage */
+	"boler@sourceforge.net",		/* author */
+	PURPLE_WEBSITE,				/* homepage */
 
-	NULL,				/* load */
-	NULL,				/* unload */
-	NULL,				/* destroy */
+	NULL,					/* load */
+	NULL,					/* unload */
+	NULL,					/* destroy */
 
-	NULL,				/* ui_info */
-	&prpl_info,			/* extra_info */
-	NULL,				/* prefs_info */
-	ggp_actions,			/* actions */
+	NULL,					/* ui_info */
+	&prpl_info,				/* extra_info */
+	NULL,					/* prefs_info */
+	ggp_actions,				/* actions */
 
 	/* padding */
 	NULL,
@@ -2210,9 +2323,7 @@
 	NULL,
 	NULL
 };
-/* }}} */
 
-/* static void purple_gg_debug_handler(int level, const char * format, va_list args) {{{ */
 static void purple_gg_debug_handler(int level, const char * format, va_list args) {
 	PurpleDebugLevel purple_level;
 	char *msg = g_strdup_vprintf(format, args);
@@ -2235,11 +2346,7 @@
 	purple_debug(purple_level, "gg", "%s", msg);
 	g_free(msg);
 }
-/* }}} */
 
-/*
- */
-/* static void init_plugin(PurplePlugin *plugin) {{{ */
 static void init_plugin(PurplePlugin *plugin)
 {
 	PurpleAccountOption *option;
@@ -2253,7 +2360,6 @@
 
 	gg_debug_handler = purple_gg_debug_handler;
 }
-/* }}} */
 
 PURPLE_INIT_PLUGIN(gg, init_plugin, info);
 
--- a/libpurple/protocols/gg/gg.h	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/gg/gg.h	Thu Nov 27 21:15:43 2008 +0000
@@ -65,9 +65,10 @@
 	uin_t tmp_buddy;
 	int chats_count;
 
+	GList *pending_richtext_messages;
+	GHashTable *pending_images;
 } GGPInfo;
 
-
 #endif /* _PURPLE_GG_H */
 
 /* vim: set ts=8 sts=0 sw=8 noet: */
--- a/libpurple/protocols/irc/cmds.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/irc/cmds.c	Thu Nov 27 21:15:43 2008 +0000
@@ -71,7 +71,7 @@
 int irc_cmd_ctcp(struct irc_conn *irc, const char *cmd, const char *target, const char **args)
 {
 	/* we have defined args as args[0] is target and args[1] is ctcp command */
-        char *buf;
+	char *buf;
 	GString *string;
 	
 	/* check if we have args */
@@ -141,11 +141,11 @@
 			action[strlen(action) - 1] = '\0';
 		if (purple_conversation_get_type(convo) == PURPLE_CONV_TYPE_CHAT)
 			serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)),
-			         	 purple_connection_get_display_name(gc),
-				         0, action, time(NULL));
+			                 purple_connection_get_display_name(gc),
+			                 0, action, time(NULL));
 		else
 			purple_conv_im_write(PURPLE_CONV_IM(convo), purple_connection_get_display_name(gc),
-			                  action, 0, time(NULL));
+			                     action, 0, time(NULL));
 		g_free(action);
 	}
 
@@ -156,7 +156,6 @@
 {
 	char *buf;
 
-
 	if (!args || !args[0])
 		return 0;
 
--- a/libpurple/protocols/irc/dcc_send.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/irc/dcc_send.c	Thu Nov 27 21:15:43 2008 +0000
@@ -302,7 +302,7 @@
 
 	if (sock < 0) {
 		purple_notify_error(gc, NULL, _("File Transfer Failed"),
-		                  _("Could not open a listening port."));
+		                    _("Could not open a listening port."));
 		purple_xfer_cancel_local(xfer);
 		return;
 	}
@@ -313,14 +313,14 @@
 	purple_debug_misc("irc", "port is %hu\n", port);
 	/* Monitor the listening socket */
 	xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ,
-	                               irc_dccsend_send_connected, xfer);
+	                                 irc_dccsend_send_connected, xfer);
 
 	/* Send the intended recipient the DCC request */
 	arg[0] = xfer->who;
 	inet_aton(purple_network_get_my_ip(irc->fd), &addr);
 	arg[1] = tmp = g_strdup_printf("\001DCC SEND \"%s\" %u %hu %" G_GSIZE_FORMAT "\001",
-	                         xfer->filename, ntohl(addr.s_addr),
-	                         port, xfer->size);
+	                               xfer->filename, ntohl(addr.s_addr),
+	                               port, xfer->size);
 
 	irc_cmd_privmsg(gc->proto_data, "msg", NULL, arg);
 	g_free(tmp);
@@ -343,7 +343,7 @@
 	if (xd->listen_data == NULL) {
 		purple_xfer_unref(xfer);
 		purple_notify_error(gc, NULL, _("File Transfer Failed"),
-		                  _("Could not open a listening port."));
+		                    _("Could not open a listening port."));
 		purple_xfer_cancel_local(xfer);
 	}
 
--- a/libpurple/protocols/irc/irc.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/irc/irc.c	Thu Nov 27 21:15:43 2008 +0000
@@ -564,7 +564,7 @@
 {
 	struct irc_conn *irc = (struct irc_conn *)gc->proto_data;
 	struct irc_buddy *ib = g_new0(struct irc_buddy, 1);
-	ib->name = g_strdup(buddy->name);
+	ib->name = g_strdup(purple_buddy_get_name(buddy));
 	g_hash_table_insert(irc->buddies, ib->name, ib);
 
 	/* if the timer isn't set, this is during signon, so we don't want to flood
@@ -577,7 +577,7 @@
 static void irc_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
 {
 	struct irc_conn *irc = (struct irc_conn *)gc->proto_data;
-	g_hash_table_remove(irc->buddies, buddy->name);
+	g_hash_table_remove(irc->buddies, purple_buddy_get_name(buddy));
 }
 
 static void read_input(struct irc_conn *irc, int len)
--- a/libpurple/protocols/irc/msgs.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/irc/msgs.c	Thu Nov 27 21:15:43 2008 +0000
@@ -79,6 +79,7 @@
 	PurpleConnection *gc;
 	PurpleStatus *status;
 	PurpleBlistNode *gnode, *cnode, *bnode;
+	PurpleAccount *account;
 
 	if ((gc = purple_account_get_connection(irc->account)) == NULL
 	    || PURPLE_CONNECTION_IS_CONNECTED(gc))
@@ -86,6 +87,7 @@
 
 	purple_connection_set_display_name(gc, nick);
 	purple_connection_set_state(gc, PURPLE_CONNECTED);
+	account = purple_connection_get_account(gc);
 
 	/* If we're away then set our away message */
 	status = purple_account_get_active_status(irc->account);
@@ -95,20 +97,29 @@
 	}
 
 	/* this used to be in the core, but it's not now */
-	for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
+	for (gnode = purple_blist_get_root();
+	     gnode;
+	     gnode = purple_blist_node_get_sibling_next(gnode))
+	{
 		if(!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
+		for(cnode = purple_blist_node_get_first_child(gnode);
+		    cnode;
+		    cnode = purple_blist_node_get_sibling_next(cnode))
+		{
 			if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			for(bnode = cnode->child; bnode; bnode = bnode->next) {
+			for(bnode = purple_blist_node_get_first_child(cnode);
+			    bnode;
+			    bnode = purple_blist_node_get_sibling_next(bnode))
+			{
 				PurpleBuddy *b;
 				if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
 				b = (PurpleBuddy *)bnode;
-				if(b->account == gc->account) {
+				if(purple_buddy_get_account(b) == account) {
 					struct irc_buddy *ib = g_new0(struct irc_buddy, 1);
-					ib->name = g_strdup(b->name);
+					ib->name = g_strdup(purple_buddy_get_name(b));
 					g_hash_table_insert(irc->buddies, ib->name, ib);
 				}
 			}
@@ -123,10 +134,10 @@
 void irc_msg_default(struct irc_conn *irc, const char *name, const char *from, char **args)
 {
 	char *clean;
-        /* This, too, should be escaped somehow (smarter) */
-        clean = purple_utf8_salvage(args[0]);
+	/* This, too, should be escaped somehow (smarter) */
+	clean = purple_utf8_salvage(args[0]);
 	purple_debug(PURPLE_DEBUG_INFO, "irc", "Unrecognized message: %s\n", clean);
-        g_free(clean);
+	g_free(clean);
 }
 
 void irc_msg_features(struct irc_conn *irc, const char *name, const char *from, char **args)
@@ -814,8 +825,8 @@
 		purple_conversation_set_data(convo, IRC_NAMES_FLAG,
 					   GINT_TO_POINTER(FALSE));
 		/* Until purple_conversation_present does something that
-                 * one would expect in Pidgin, this call produces buggy
-                 * behavior both for the /join and auto-join cases. */
+		 * one would expect in Pidgin, this call produces buggy
+		 * behavior both for the /join and auto-join cases. */
 		/* purple_conversation_present(convo); */
 		return;
 	}
@@ -1043,7 +1054,7 @@
 		return;
 
 	/* Undernet likes to :-quote the channel name, for no good reason
-         * that I can see.  This catches that. */
+	 * that I can see.  This catches that. */
 	channel = (args[0][0] == ':') ? &args[0][1] : args[0];
 
 	convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, channel, irc->account);
@@ -1056,8 +1067,8 @@
 	if (!purple_utf8_strcasecmp(nick, purple_connection_get_display_name(gc))) {
 		char *escaped = g_markup_escape_text(args[1], -1);
 		msg = g_strdup_printf(_("You have parted the channel%s%s"),
-                                      (args[1] && *args[1]) ? ": " : "",
-									  (escaped && *escaped) ? escaped : "");
+		                      (args[1] && *args[1]) ? ": " : "",
+		                      (escaped && *escaped) ? escaped : "");
 		g_free(escaped);
 		purple_conv_chat_write(PURPLE_CONV_CHAT(convo), channel, msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
 		g_free(msg);
@@ -1168,7 +1179,7 @@
 			serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), nick, 0, msg, time(NULL));
 		else
 			purple_debug_error("irc", "Got a %s on %s, which does not exist\n",
-			                 notice ? "NOTICE" : "PRIVMSG", to);
+			                   notice ? "NOTICE" : "PRIVMSG", to);
 	}
 	g_free(msg);
 	g_free(nick);
--- a/libpurple/protocols/irc/parse.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/irc/parse.c	Thu Nov 27 21:15:43 2008 +0000
@@ -494,7 +494,7 @@
 		}
 	}
 	result[j] = '\0';
-        return result;
+	return result;
 }
 
 const char *irc_nick_skip_mode(struct irc_conn *irc, const char *nick)
@@ -732,9 +732,9 @@
 static void irc_parse_error_cb(struct irc_conn *irc, char *input)
 {
 	char *clean;
-        /* This really should be escaped somehow that you can tell what
-         * the junk was -- but as it is, it can crash glib. */
-        clean = purple_utf8_salvage(input);
+	/* This really should be escaped somehow that you can tell what
+	 * the junk was -- but as it is, it can crash glib. */
+	clean = purple_utf8_salvage(input);
 	purple_debug(PURPLE_DEBUG_WARNING, "irc", "Unrecognized string: %s\n", clean);
-        g_free(clean);
+	g_free(clean);
 }
--- a/libpurple/protocols/jabber/adhoccommands.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/jabber/adhoccommands.c	Thu Nov 27 21:15:43 2008 +0000
@@ -211,8 +211,9 @@
 	if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 		JabberAdHocCommands *cmd = data;
 		PurpleBuddy *buddy = (PurpleBuddy *) node;
-		JabberStream *js = purple_account_get_connection(buddy->account)->proto_data;
-		
+		PurpleAccount *account = purple_buddy_get_account(buddy);
+		JabberStream *js = purple_account_get_connection(account)->proto_data;
+
 		jabber_adhoc_execute(js, cmd);
 	}
 }
--- a/libpurple/protocols/jabber/buddy.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Thu Nov 27 21:15:43 2008 +0000
@@ -419,7 +419,7 @@
 {
 	PurpleStoredImage *img;
 	JabberIq *iq;
-	JabberStream *js = gc->proto_data;
+	JabberStream *js = purple_connection_get_protocol_data(gc);
 	xmlnode *vc_node;
 	const struct tag_attr *tag_attr;
 
@@ -496,7 +496,7 @@
 	PurplePresence *gpresence;
 	PurpleStatus *status;
 	
-	if(((JabberStream*)gc->proto_data)->pep) {
+	if(((JabberStream*)purple_connection_get_protocol_data(gc))->pep) {
 		/* XEP-0084: User Avatars */
 		if(img) {
 			/*
@@ -568,7 +568,7 @@
 				g_free(base64avatar);
 				
 				/* publish the avatar itself */
-				jabber_pep_publish((JabberStream*)gc->proto_data, publish);
+				jabber_pep_publish((JabberStream*)purple_connection_get_protocol_data(gc), publish);
 				
 				/* next step: publish the metadata */
 				publish = xmlnode_new("publish");
@@ -594,7 +594,7 @@
 				g_free(heightstring);
 				
 				/* publish the metadata */
-				jabber_pep_publish((JabberStream*)gc->proto_data, publish);
+				jabber_pep_publish((JabberStream*)purple_connection_get_protocol_data(gc), publish);
 				
 				g_free(hash);
 			} else { /* if(img) */
@@ -611,7 +611,7 @@
 				xmlnode_new_child(metadata, "stop");
 				
 				/* publish the metadata */
-				jabber_pep_publish((JabberStream*)gc->proto_data, publish);
+				jabber_pep_publish((JabberStream*)purple_connection_get_protocol_data(gc), publish);
 			}
 		} else {
 			purple_debug(PURPLE_DEBUG_ERROR, "jabber",
@@ -966,7 +966,7 @@
 		}
 #endif
 	} else {
-		gboolean multiple_resources = jbi->jb->resources && (g_list_length(jbi->jb->resources) > 1);
+		gboolean multiple_resources = jbi->jb->resources && jbi->jb->resources->next;
 
 		for(resources = jbi->jb->resources; resources; resources = resources->next) {
 			char *purdy = NULL;
@@ -1797,7 +1797,7 @@
 
 void jabber_buddy_get_info(PurpleConnection *gc, const char *who)
 {
-	JabberStream *js = gc->proto_data;
+	JabberStream *js = purple_connection_get_protocol_data(gc);
 	char *bare_jid = jabber_get_bare_jid(who);
 
 	if(bare_jid) {
@@ -1848,10 +1848,10 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
-	js = gc->proto_data;
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	js = purple_connection_get_protocol_data(gc);
 
-	jabber_buddy_set_invisibility(js, buddy->name, TRUE);
+	jabber_buddy_set_invisibility(js, purple_buddy_get_name(buddy), TRUE);
 }
 
 static void jabber_buddy_make_visible(PurpleBlistNode *node, gpointer data)
@@ -1863,10 +1863,10 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
-	js = gc->proto_data;
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	js = purple_connection_get_protocol_data(gc);
 
-	jabber_buddy_set_invisibility(js, buddy->name, FALSE);
+	jabber_buddy_set_invisibility(js, purple_buddy_get_name(buddy), FALSE);
 }
 
 static void jabber_buddy_cancel_presence_notification(PurpleBlistNode *node,
@@ -1879,11 +1879,11 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
-	js = gc->proto_data;
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	js = purple_connection_get_protocol_data(gc);
 
 	/* I wonder if we should prompt the user before doing this */
-	jabber_presence_subscription_set(js, buddy->name, "unsubscribed");
+	jabber_presence_subscription_set(js, purple_buddy_get_name(buddy), "unsubscribed");
 }
 
 static void jabber_buddy_rerequest_auth(PurpleBlistNode *node, gpointer data)
@@ -1895,10 +1895,10 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
-	js = gc->proto_data;
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	js = purple_connection_get_protocol_data(gc);
 
-	jabber_presence_subscription_set(js, buddy->name, "subscribe");
+	jabber_presence_subscription_set(js, purple_buddy_get_name(buddy), "subscribe");
 }
 
 
@@ -1911,18 +1911,18 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
-	js = gc->proto_data;
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	js = purple_connection_get_protocol_data(gc);
 
-	jabber_presence_subscription_set(js, buddy->name, "unsubscribe");
+	jabber_presence_subscription_set(js, purple_buddy_get_name(buddy), "unsubscribe");
 }
 
 static void jabber_buddy_login(PurpleBlistNode *node, gpointer data) {
 	if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 		/* simply create a directed presence of the current status */
 		PurpleBuddy *buddy = (PurpleBuddy *) node;
-		PurpleConnection *gc = purple_account_get_connection(buddy->account);
-		JabberStream *js = gc->proto_data;
+		PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+		JabberStream *js = purple_connection_get_protocol_data(gc);
 		PurpleAccount *account = purple_connection_get_account(gc);
 		PurplePresence *gpresence = purple_account_get_presence(account);
 		PurpleStatus *status = purple_presence_get_active_status(gpresence);
@@ -1936,7 +1936,7 @@
 		
 		g_free(msg);
 		
-		xmlnode_set_attrib(presence, "to", buddy->name);
+		xmlnode_set_attrib(presence, "to", purple_buddy_get_name(buddy));
 		
 		jabber_send(js, presence);
 		xmlnode_free(presence);
@@ -1947,12 +1947,13 @@
 	if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 		/* simply create a directed unavailable presence */
 		PurpleBuddy *buddy = (PurpleBuddy *) node;
-		JabberStream *js = purple_account_get_connection(buddy->account)->proto_data;
+		PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+		JabberStream *js = purple_connection_get_protocol_data(gc);
 		xmlnode *presence;
 		
 		presence = jabber_presence_create_js(js, JABBER_BUDDY_STATE_UNAVAILABLE, NULL, 0);
 		
-		xmlnode_set_attrib(presence, "to", buddy->name);
+		xmlnode_set_attrib(presence, "to", purple_buddy_get_name(buddy));
 		
 		jabber_send(js, presence);
 		xmlnode_free(presence);
@@ -1961,9 +1962,10 @@
 
 static GList *jabber_buddy_menu(PurpleBuddy *buddy)
 {
-	PurpleConnection *gc = purple_account_get_connection(buddy->account);
-	JabberStream *js = gc->proto_data;
-	JabberBuddy *jb = jabber_buddy_find(js, buddy->name, TRUE);
+	PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	JabberStream *js = purple_connection_get_protocol_data(gc);
+	const char *name = purple_buddy_get_name(buddy);
+	JabberBuddy *jb = jabber_buddy_find(js, name, TRUE);
 	GList *jbrs;
 
 	GList *m = NULL;
@@ -2018,7 +2020,7 @@
 	 * that gateways on the roster can be identified by having no '@' in their jid. This is a faily safe assumption, since
 	 * people don't tend to have a server or other service there.
 	 */
-	if (g_utf8_strchr(buddy->name, -1, '@') == NULL) {
+	if (g_utf8_strchr(name, -1, '@') == NULL) {
 		act = purple_menu_action_new(_("Log In"),
 									 PURPLE_CALLBACK(jabber_buddy_login),
 									 NULL, NULL);
@@ -2486,7 +2488,7 @@
 void jabber_user_search_begin(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *) action->context;
-	JabberStream *js = gc->proto_data;
+	JabberStream *js = purple_connection_get_protocol_data(gc);
 
 	purple_request_input(gc, _("Enter a User Directory"), _("Enter a User Directory"),
 			_("Select a user directory to search"),
--- a/libpurple/protocols/jabber/google.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/jabber/google.c	Thu Nov 27 21:15:43 2008 +0000
@@ -283,6 +283,7 @@
 	xmlnode *group;
 	PurpleBuddy *b;
 	JabberBuddy *jb;
+	const char *balias;
 
 	js = (JabberStream*)(gc->proto_data);
 
@@ -309,13 +310,14 @@
 		g = purple_buddy_get_group(b);
 
 		group = xmlnode_new_child(item, "group");
-		xmlnode_insert_data(group, g->name, -1);
+		xmlnode_insert_data(group, purple_group_get_name(g), -1);
 
 		buddies = buddies->next;
 	}
 
+	balias = purple_buddy_get_local_buddy_alias(b);
 	xmlnode_set_attrib(item, "jid", who);
-	xmlnode_set_attrib(item, "name", b->alias ? b->alias : "");
+	xmlnode_set_attrib(item, "name", balias ? balias : "");
 	xmlnode_set_attrib(item, "gr:t", "B");
 	xmlnode_set_attrib(query, "xmlns:gr", "google:roster");
 	xmlnode_set_attrib(query, "gr:ext", "2");
@@ -348,6 +350,7 @@
 	xmlnode *item;
 	xmlnode *group;
 	PurpleBuddy *b;
+	const char *balias;
 
 	g_return_if_fail(gc != NULL);
 	g_return_if_fail(who != NULL);
@@ -357,7 +360,7 @@
 	if (!js || !js->server_caps & JABBER_CAP_GOOGLE_ROSTER)
 		return;
 
-	buddies = purple_find_buddies(js->gc->account, who);
+	buddies = purple_find_buddies(purple_connection_get_account(js->gc), who);
 	if(!buddies)
 		return;
 
@@ -375,13 +378,14 @@
 		g = purple_buddy_get_group(b);
 
 		group = xmlnode_new_child(item, "group");
-		xmlnode_insert_data(group, g->name, -1);
+		xmlnode_insert_data(group, purple_group_get_name(g), -1);
 
 		buddies = buddies->next;
 	}
 
+	balias = purple_buddy_get_local_buddy_alias(b);
 	xmlnode_set_attrib(item, "jid", who);
-	xmlnode_set_attrib(item, "name", b->alias ? b->alias : "");
+	xmlnode_set_attrib(item, "name", balias ? balias : "");
 	xmlnode_set_attrib(query, "xmlns:gr", "google:roster");
 	xmlnode_set_attrib(query, "gr:ext", "2");
 
--- a/libpurple/protocols/jabber/jabber.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Thu Nov 27 21:15:43 2008 +0000
@@ -1479,13 +1479,14 @@
 {
 	JabberStream *js;
 	JabberBuddy *jb = NULL;
+	PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(b));
 
-	if(!b->account->gc)
+	if(!gc)
 		return NULL;
 
-	js = b->account->gc->proto_data;
+	js = gc->proto_data;
 	if(js)
-		jb = jabber_buddy_find(js, b->name, FALSE);
+		jb = jabber_buddy_find(js, purple_buddy_get_name(b), FALSE);
 
 	if(!PURPLE_BUDDY_IS_ONLINE(b)) {
 		if(jb && (jb->subscription & JABBER_SUB_PENDING ||
@@ -1499,9 +1500,11 @@
 {
 	char *ret = NULL;
 	JabberBuddy *jb = NULL;
-	
-	if (b->account->gc && b->account->gc->proto_data)
-		jb = jabber_buddy_find(b->account->gc->proto_data, b->name, FALSE);
+	PurpleAccount *account = purple_buddy_get_account(b);
+	PurpleConnection *gc = purple_account_get_connection(account);
+
+	if (gc && gc->proto_data)
+		jb = jabber_buddy_find(gc->proto_data, purple_buddy_get_name(b), FALSE);
 
 	if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && (jb->subscription & JABBER_SUB_PENDING || !(jb->subscription & JABBER_SUB_TO))) {
 		ret = g_strdup(_("Not Authorized"));
@@ -1530,14 +1533,19 @@
 void jabber_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
 {
 	JabberBuddy *jb;
+	PurpleAccount *account;
+	PurpleConnection *gc;
 
 	g_return_if_fail(b != NULL);
-	g_return_if_fail(b->account != NULL);
-	g_return_if_fail(b->account->gc != NULL);
-	g_return_if_fail(b->account->gc->proto_data != NULL);
+
+	account = purple_buddy_get_account(b);
+	g_return_if_fail(account != NULL);
 
-	jb = jabber_buddy_find(b->account->gc->proto_data, b->name,
-			FALSE);
+	gc = purple_account_get_connection(account);
+	g_return_if_fail(gc != NULL);
+	g_return_if_fail(gc->proto_data != NULL);
+
+	jb = jabber_buddy_find(gc->proto_data, purple_buddy_get_name(b), FALSE);
 
 	if(jb) {
 		JabberBuddyResource *jbr = NULL;
@@ -1873,19 +1881,24 @@
 	if(!(jid = jabber_id_new(name)))
 		return NULL;
 
-	for(gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
+	for(gnode = purple_blist_get_root(); gnode;
+			gnode = purple_blist_node_get_sibling_next(gnode)) {
+		for(cnode = purple_blist_node_get_first_child(gnode);
+				cnode;
+				cnode = purple_blist_node_get_sibling_next(cnode)) {
 			PurpleChat *chat = (PurpleChat*)cnode;
 			const char *room, *server;
+			GHashTable *components;
 			if(!PURPLE_BLIST_NODE_IS_CHAT(cnode))
 				continue;
 
-			if(chat->account != account)
+			if (purple_chat_get_account(chat) != account)
 				continue;
 
-			if(!(room = g_hash_table_lookup(chat->components, "room")))
+			components = purple_chat_get_components(chat);
+			if(!(room = g_hash_table_lookup(components, "room")))
 				continue;
-			if(!(server = g_hash_table_lookup(chat->components, "server")))
+			if(!(server = g_hash_table_lookup(components, "server")))
 				continue;
 
 			if(jid->node && jid->domain &&
--- a/libpurple/protocols/jabber/message.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/jabber/message.c	Thu Nov 27 21:15:43 2008 +0000
@@ -913,19 +913,15 @@
 		return FALSE;
 	}
 
-	jb = jabber_buddy_find(js, who, FALSE);
-	if (!jb) {
-		purple_debug_error("jabber",
-			"jabber_conv_support_custom smileys: could not find buddy\n");
-		return FALSE;
-	}
-	
-	
-
 	switch (purple_conversation_get_type(conv)) {
 		/* for the time being, we will not support custom smileys in MUCs */
 		case PURPLE_CONV_TYPE_IM:
-			return jabber_buddy_has_capability(jb, XEP_0231_NAMESPACE);
+			jb = jabber_buddy_find(js, who, FALSE);
+			if (jb) {
+				return jabber_buddy_has_capability(jb, XEP_0231_NAMESPACE);
+			} else {
+				return FALSE;
+			}
 			break;
 		default:
 			return FALSE;
--- a/libpurple/protocols/jabber/parser.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/jabber/parser.c	Thu Nov 27 21:15:43 2008 +0000
@@ -114,7 +114,8 @@
 		xmlnode *packet = js->current;
 		js->current = NULL;
 		jabber_process_packet(js, &packet);
-		xmlnode_free(packet);
+		if (packet != NULL)
+			xmlnode_free(packet);
 	}
 }
 
@@ -137,11 +138,19 @@
 {
 	JabberStream *js = user_data;
 
+	if (error->level == XML_ERR_WARNING && error->message != NULL
+			&& strcmp(error->message, "xmlns: URI vcard-temp is not absolute\n") == 0)
+		/*
+		 * This message happens when parsing vcards, and is normal, so don't
+		 * bother logging it because people scare easily.
+		 */
+		return;
+
 	purple_debug_error("jabber", "XML parser error for JabberStream %p: "
-								 "Domain %i, code %i, level %i: %s\n",
+								 "Domain %i, code %i, level %i: %s",
 					   js,
 					   error->domain, error->code, error->level,
-					   (error->message ? error->message : "(null)"));
+					   (error->message ? error->message : "(null)\n"));
 }
 
 static xmlSAXHandler jabber_parser_libxml = {
--- a/libpurple/protocols/jabber/presence.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/jabber/presence.c	Thu Nov 27 21:15:43 2008 +0000
@@ -459,7 +459,7 @@
 
 		if (buddy) {
 			jb = jabber_buddy_find(js, from, TRUE);
-			if ((jb->subscription & JABBER_SUB_TO))
+			if ((jb->subscription & (JABBER_SUB_TO | JABBER_SUB_PENDING)))
 				onlist = TRUE;
 		}
 
--- a/libpurple/protocols/jabber/roster.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/jabber/roster.c	Thu Nov 27 21:15:43 2008 +0000
@@ -80,15 +80,16 @@
 
 		buddies = g_slist_remove(buddies, b);
 
-		if((l = g_slist_find_custom(g2, g->name, (GCompareFunc)strcmp))) {
-			const char *servernick;
+		if((l = g_slist_find_custom(g2, purple_group_get_name(g), (GCompareFunc)strcmp))) {
+			const char *servernick, *balias;
 
 			/* Previously stored serverside / buddy-supplied alias */
 			if((servernick = purple_blist_node_get_string((PurpleBlistNode*)b, "servernick")))
 				serv_got_alias(js->gc, jid, servernick);
 
 			/* Alias from our roster retrieval */
-			if(alias && (!b->alias || strcmp(b->alias, alias)))
+			balias = purple_buddy_get_local_buddy_alias(b);
+			if(alias && (!balias || strcmp(balias, alias)))
 				purple_serv_got_private_alias(js->gc, jid, alias);
 			g_free(l->data);
 			g2 = g_slist_delete_link(g2, l);
@@ -119,11 +120,13 @@
 		/* If we just learned about ourself, then fake our status,
 		 * because we won't be receiving a normal presence message
 		 * about ourself. */
-		if(!strcmp(b->name, my_bare_jid)) {
+		if(!strcmp(purple_buddy_get_name(b), my_bare_jid)) {
 			PurplePresence *gpresence;
 			PurpleStatus *status;
+			PurpleAccount *account;
 
-			gpresence = purple_account_get_presence(js->gc->account);
+			account = purple_connection_get_account(js->gc);
+			gpresence = purple_account_get_presence(account);
 			status = purple_presence_get_active_status(gpresence);
 			jabber_presence_fake_to_self(js, status);
 		}
@@ -273,6 +276,7 @@
 	GSList *groups = NULL, *l;
 	JabberIq *iq;
 	xmlnode *query, *item, *group;
+	const char *balias;
 
 	if (js->currently_parsing_roster_push)
 		return;
@@ -289,7 +293,7 @@
 		while(buddies) {
 			b = buddies->data;
 			g = purple_buddy_get_group(b);
-			groups = g_slist_append(groups, g->name);
+			groups = g_slist_append(groups, (char *)purple_group_get_name(g));
 			buddies = g_slist_remove(buddies, b);
 		}
 	}
@@ -301,7 +305,8 @@
 
 	xmlnode_set_attrib(item, "jid", name);
 
-	xmlnode_set_attrib(item, "name", b->alias ? b->alias : "");
+	balias = purple_buddy_get_local_buddy_alias(b);
+	xmlnode_set_attrib(item, "name", balias ? balias : "");
 
 	for(l = groups; l; l = l->next) {
 		group = xmlnode_new_child(item, "group");
@@ -327,14 +332,16 @@
 	JabberBuddy *jb;
 	JabberBuddyResource *jbr;
 	char *my_bare_jid;
+	const char *name;
 
 	if(!js->roster_parsed)
 		return;
 
-	if(!(who = jabber_get_bare_jid(buddy->name)))
+	name = purple_buddy_get_name(buddy);
+	if(!(who = jabber_get_bare_jid(name)))
 		return;
 
-	jb = jabber_buddy_find(js, buddy->name, FALSE);
+	jb = jabber_buddy_find(js, name, FALSE);
 
 	jabber_roster_update(js, who, NULL);
 
@@ -375,6 +382,7 @@
 	GSList *buddies, *groups = NULL;
 	PurpleBuddy *b;
 	PurpleGroup *g;
+	const char *gname;
 
 	if(!old_group || !new_group || !strcmp(old_group, new_group))
 		return;
@@ -383,10 +391,11 @@
 	while(buddies) {
 		b = buddies->data;
 		g = purple_buddy_get_group(b);
-		if(!strcmp(g->name, old_group))
+		gname = purple_group_get_name(g);
+		if(!strcmp(gname, old_group))
 			groups = g_slist_append(groups, (char*)new_group); /* ick */
 		else
-			groups = g_slist_append(groups, g->name);
+			groups = g_slist_append(groups, (char*)gname);
 		buddies = g_slist_remove(buddies, b);
 	}
 	jabber_roster_update(gc->proto_data, name, groups);
@@ -397,15 +406,17 @@
 		PurpleGroup *group, GList *moved_buddies)
 {
 	GList *l;
+	const char *gname = purple_group_get_name(group);
 	for(l = moved_buddies; l; l = l->next) {
 		PurpleBuddy *buddy = l->data;
-		jabber_roster_group_change(gc, buddy->name, old_name, group->name);
+		jabber_roster_group_change(gc, purple_buddy_get_name(buddy), old_name, gname);
 	}
 }
 
 void jabber_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
 		PurpleGroup *group) {
-	GSList *buddies = purple_find_buddies(gc->account, buddy->name);
+	const char *name = purple_buddy_get_name(buddy);
+	GSList *buddies = purple_find_buddies(purple_connection_get_account(gc), name);
 
 	buddies = g_slist_remove(buddies, buddy);
 	if(buddies != NULL) {
@@ -416,11 +427,11 @@
 		while(buddies) {
 			tmpbuddy = buddies->data;
 			tmpgroup = purple_buddy_get_group(tmpbuddy);
-			groups = g_slist_append(groups, tmpgroup->name);
+			groups = g_slist_append(groups, (char *)purple_group_get_name(tmpgroup));
 			buddies = g_slist_remove(buddies, tmpbuddy);
 		}
 
-		jabber_roster_update(gc->proto_data, buddy->name, groups);
+		jabber_roster_update(gc->proto_data, name, groups);
 		g_slist_free(groups);
 	} else {
 		JabberIq *iq = jabber_iq_new_query(gc->proto_data, JABBER_IQ_SET,
@@ -428,7 +439,7 @@
 		xmlnode *query = xmlnode_get_child(iq->node, "query");
 		xmlnode *item = xmlnode_new_child(query, "item");
 
-		xmlnode_set_attrib(item, "jid", buddy->name);
+		xmlnode_set_attrib(item, "jid", name);
 		xmlnode_set_attrib(item, "subscription", "remove");
 
 		jabber_iq_send(iq);
--- a/libpurple/protocols/jabber/si.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/jabber/si.c	Thu Nov 27 21:15:43 2008 +0000
@@ -798,7 +798,7 @@
 		if (!(sh->jid && sh->host && sh->port > 0))
 			continue;
 
-		purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and sh->jid %p",
+		purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and sh->jid %p\n",
 						  jsx, jsx->streamhosts, sh->jid);
 		if(g_list_find_custom(jsx->streamhosts, sh->jid, jabber_si_compare_jid) != NULL)
 			continue;
@@ -1085,7 +1085,7 @@
 
 			purple_notify_error(jsx->js->gc, _("File Send Failed"), _("File Send Failed"), msg);
 			g_free(msg);
-		} else if(g_list_length(jb->resources) == 1) {
+		} else if(!jb->resources->next) {
 			/* only 1 resource online (probably our most common case)
 			 * so no need to ask who to send to */
 			jbr = jb->resources->data;
--- a/libpurple/protocols/msn/msn.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/msn/msn.c	Thu Nov 27 21:15:43 2008 +0000
@@ -457,23 +457,27 @@
 	PurpleConnection *gc;
 	MsnSession *session;
 	MsnMobileData *data;
+	PurpleAccount *account;
+	const char *name;
 
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
+	account = purple_buddy_get_account(buddy);
+	gc = purple_account_get_connection(account);
+	name = purple_buddy_get_name(buddy);
 
 	session = gc->proto_data;
 
 	data = g_new0(MsnMobileData, 1);
 	data->gc = gc;
-	data->passport = buddy->name;
+	data->passport = name;
 
 	purple_request_input(gc, NULL, _("Send a mobile message."), NULL,
 					   NULL, TRUE, FALSE, NULL,
 					   _("Page"), G_CALLBACK(send_to_mobile_cb),
 					   _("Close"), G_CALLBACK(close_mobile_page_cb),
-					   purple_connection_get_account(gc), purple_buddy_get_name(buddy), NULL,
+					   account, name, NULL,
 					   data);
 }
 
@@ -505,6 +509,7 @@
 {
 	PurpleBuddy *buddy;
 	PurpleConnection *gc;
+	PurpleAccount *account;
 
 	MsnSession *session;
 	MsnSwitchBoard *swboard;
@@ -514,13 +519,14 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
+	account = purple_buddy_get_account(buddy);
+	gc = purple_account_get_connection(account);
 
 	session = gc->proto_data;
 
 	swboard = msn_switchboard_new(session);
 	msn_switchboard_request(swboard);
-	msn_switchboard_request_add_user(swboard, buddy->name);
+	msn_switchboard_request_add_user(swboard, purple_buddy_get_name(buddy));
 
 	/* TODO: This might move somewhere else, after USR might be */
 	swboard->chat_id = msn_switchboard_get_chat_id();
@@ -528,9 +534,9 @@
 	swboard->flag = MSN_SB_FLAG_IM;
 
 	/* Local alias > Display name > Username */
-	if ((alias = purple_account_get_alias(buddy->account)) == NULL)
+	if ((alias = purple_account_get_alias(account)) == NULL)
 		if ((alias = purple_connection_get_display_name(gc)) == NULL)
-			alias = purple_account_get_username(buddy->account);
+			alias = purple_account_get_username(account);
 
 	purple_conv_chat_add_user(PURPLE_CONV_CHAT(swboard->conv),
 	                          alias, NULL, PURPLE_CBFLAGS_NONE, TRUE);
@@ -613,7 +619,7 @@
 static const char *
 msn_list_emblems(PurpleBuddy *b)
 {
-	MsnUser *user = b->proto_data;
+	MsnUser *user = purple_buddy_get_protocol_data(b);
 
 	if (user != NULL) {
 		if (user->clientid & MSN_CLIENT_CAP_BOT)
@@ -676,7 +682,7 @@
 	PurplePresence *presence = purple_buddy_get_presence(buddy);
 	PurpleStatus *status = purple_presence_get_active_status(presence);
 
-	user = buddy->proto_data;
+	user = purple_buddy_get_protocol_data(buddy);
 
 	if (purple_presence_is_online(presence))
 	{
@@ -906,7 +912,7 @@
 
 	g_return_val_if_fail(buddy != NULL, NULL);
 
-	user = buddy->proto_data;
+	user = purple_buddy_get_protocol_data(buddy);
 
 	if (user != NULL)
 	{
@@ -919,8 +925,8 @@
 		}
 	}
 
-	if (g_ascii_strcasecmp(buddy->name,
-	                       purple_account_get_username(buddy->account)))
+	if (g_ascii_strcasecmp(purple_buddy_get_name(buddy),
+				purple_account_get_username(purple_buddy_get_account(buddy))))
 	{
 		act = purple_menu_action_new(_("Initiate _Chat"),
 		                           PURPLE_CALLBACK(initiate_chat_cb),
@@ -1196,6 +1202,9 @@
 		purple_debug_info("msn", "prepare to send online Message\n");
 		if (g_ascii_strcasecmp(who, username))
 		{
+			if (flags & PURPLE_MESSAGE_AUTO_RESP) {
+				msn_message_set_flag(msg, 'U');
+			}
 			if (msn_user_is_yahoo(account, who)) {
 				/*we send the online and offline Message to Yahoo User via UBM*/
 				purple_debug_info("msn", "send to Yahoo User\n");
@@ -1385,13 +1394,14 @@
 {
 	MsnSession *session;
 	MsnUserList *userlist;
-	const char *who;
+	const char *who, *gname;
 
 	session = gc->proto_data;
 	userlist = session->userlist;
-	who = msn_normalize(gc->account, buddy->name);
-
-	purple_debug_info("msn", "Add user:%s to group:%s\n", who, (group && group->name) ? group->name : "(null)");
+	who = msn_normalize(purple_connection_get_account(gc), purple_buddy_get_name(buddy));
+
+	gname = group ? purple_group_get_name(group) : NULL;
+	purple_debug_info("msn", "Add user:%s to group:%s\n", who, gname ? gname : "(null)");
 	if (!session->logged_in)
 	{
 #if 0
@@ -1425,7 +1435,7 @@
 	/* XXX - Would group ever be NULL here?  I don't think so...
 	 * shx: Yes it should; MSN handles non-grouped buddies, and this is only
 	 * internal. */
-	msn_userlist_add_buddy(userlist, who, group ? group->name : NULL);
+	msn_userlist_add_buddy(userlist, who, gname);
 }
 
 static void
@@ -1441,7 +1451,7 @@
 		return;
 
 	/* XXX - Does buddy->name need to be msn_normalize'd here?  --KingAnt */
-	msn_userlist_rem_buddy(userlist, buddy->name);
+	msn_userlist_rem_buddy(userlist, purple_buddy_get_name(buddy));
 }
 
 static void
@@ -1694,20 +1704,22 @@
 				 PurpleGroup *group, GList *moved_buddies)
 {
 	MsnSession *session;
+	const char *gname;
 
 	session = gc->proto_data;
 
 	g_return_if_fail(session != NULL);
 	g_return_if_fail(session->userlist != NULL);
 
+	gname = purple_group_get_name(group);
 	if (msn_userlist_find_group_with_name(session->userlist, old_name) != NULL)
 	{
-		msn_contact_rename_group(session, old_name, group->name);
+		msn_contact_rename_group(session, old_name, gname);
 	}
 	else
 	{
 		/* not found */
-		msn_add_group(session, NULL, group->name);
+		msn_add_group(session, NULL, gname);
 	}
 }
 
@@ -1767,20 +1779,22 @@
 {
 	MsnSession *session;
 	MsnCmdProc *cmdproc;
+	const char *gname;
 
 	session = gc->proto_data;
 	cmdproc = session->notification->cmdproc;
-
-	purple_debug_info("msn", "Remove group %s\n", group->name);
+	gname = purple_group_get_name(group);
+
+	purple_debug_info("msn", "Remove group %s\n", gname);
 	/*we can't delete the default group*/
-	if(!strcmp(group->name, MSN_INDIVIDUALS_GROUP_NAME)||
-		!strcmp(group->name, MSN_NON_IM_GROUP_NAME))
+	if(!strcmp(gname, MSN_INDIVIDUALS_GROUP_NAME)||
+		!strcmp(gname, MSN_NON_IM_GROUP_NAME))
 	{
 		purple_debug_info("msn", "This group can't be removed, returning.\n");
 		return ;
 	}
 
-	msn_del_group(session, group->name);
+	msn_del_group(session, gname);
 }
 
 /**
@@ -1797,17 +1811,19 @@
 	if (b)
 	{
 		char *tmp;
-
-		if (b->alias && b->alias[0])
+		const char *alias;
+
+		alias = purple_buddy_get_local_buddy_alias(b);
+		if (alias && alias[0])
 		{
-			char *aliastext = g_markup_escape_text(b->alias, -1);
+			char *aliastext = g_markup_escape_text(alias, -1);
 			purple_notify_user_info_add_pair(user_info, _("Alias"), aliastext);
 			g_free(aliastext);
 		}
 
-		if (b->server_alias)
+		if ((alias = purple_buddy_get_server_alias(b)) != NULL)
 		{
-			char *nicktext = g_markup_escape_text(b->server_alias, -1);
+			char *nicktext = g_markup_escape_text(alias, -1);
 			tmp = g_strdup_printf("<font sml=\"msn\">%s</font><br>", nicktext);
 			purple_notify_user_info_add_pair(user_info, _("Nickname"), tmp);
 			g_free(tmp);
--- a/libpurple/protocols/msn/notification.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/msn/notification.c	Thu Nov 27 21:15:43 2008 +0000
@@ -491,7 +491,7 @@
 	 * command and we are processing it */
 	if (cmd->payload == NULL) {
 		cmdproc->last_cmd->payload_cb = msg_cmd_post;
-		cmd->payload_len = atoi(cmd->params[4]);
+		cmd->payload_len = atoi(cmd->params[3]);
 	} else {
 		g_return_if_fail(cmd->payload_cb != NULL);
 
--- a/libpurple/protocols/msn/servconn.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/msn/servconn.c	Thu Nov 27 21:15:43 2008 +0000
@@ -69,8 +69,7 @@
 		return;
 	}
 
-	if (servconn->connected)
-		msn_servconn_disconnect(servconn);
+	msn_servconn_disconnect(servconn);
 
 	if (servconn->destroy_cb)
 		servconn->destroy_cb(servconn);
--- a/libpurple/protocols/msn/session.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/msn/session.c	Thu Nov 27 21:15:43 2008 +0000
@@ -269,16 +269,21 @@
 	 * being logged in. This no longer happens, so we manually iterate
 	 * over the whole buddy list to identify sync issues.
 	 */
-	for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
+	for (gnode = purple_blist_get_root(); gnode;
+			gnode = purple_blist_node_get_sibling_next(gnode)) {
 		PurpleGroup *group = (PurpleGroup *)gnode;
 		const char *group_name;
 		if(!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		group_name = group->name;
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
+		group_name = purple_group_get_name(group);
+		for(cnode = purple_blist_node_get_first_child(gnode);
+				cnode;
+				cnode = purple_blist_node_get_sibling_next(cnode)) {
 			if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			for(bnode = cnode->child; bnode; bnode = bnode->next) {
+			for(bnode = purple_blist_node_get_first_child(cnode);
+					bnode;
+					bnode = purple_blist_node_get_sibling_next(bnode)) {
 				PurpleBuddy *b;
 				if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
--- a/libpurple/protocols/msn/soap.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/msn/soap.c	Thu Nov 27 21:15:43 2008 +0000
@@ -1,6 +1,6 @@
 /**
  * @file soap.c
- * 	C file for SOAP connection related process
+ * Functions relating to SOAP connections.
  *
  * purple
  *
@@ -56,6 +56,7 @@
 	gboolean connected;
 
 	guint event_handle;
+	guint run_timer;
 	GString *buf;
 	gsize handled_len;
 	gsize body_len;
@@ -69,22 +70,99 @@
 	MsnSoapRequest *current_request;
 } MsnSoapConnection;
 
-static void msn_soap_connection_destroy_foreach_cb(gpointer item, gpointer data);
 static gboolean msn_soap_connection_run(gpointer data);
 
-static MsnSoapConnection *msn_soap_connection_new(MsnSession *session,
-	const char *host);
-static void msn_soap_connection_handle_next(MsnSoapConnection *conn);
-static void msn_soap_connection_destroy(MsnSoapConnection *conn);
+static MsnSoapConnection *
+msn_soap_connection_new(MsnSession *session, const char *host)
+{
+	MsnSoapConnection *conn = g_new0(MsnSoapConnection, 1);
+	conn->session = session;
+	conn->host = g_strdup(host);
+	conn->queue = g_queue_new();
+	return conn;
+}
+
+static void
+msn_soap_message_destroy(MsnSoapMessage *message)
+{
+	g_slist_foreach(message->headers, (GFunc)g_free, NULL);
+	g_slist_free(message->headers);
+	g_free(message->action);
+	if (message->xml)
+		xmlnode_free(message->xml);
+	g_free(message);
+}
+
+static void
+msn_soap_request_destroy(MsnSoapRequest *req, gboolean keep_message)
+{
+	g_free(req->path);
+	if (!keep_message)
+		msn_soap_message_destroy(req->message);
+	g_free(req);
+}
+
+static void
+msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect)
+{
+	if (conn->event_handle) {
+		purple_input_remove(conn->event_handle);
+		conn->event_handle = 0;
+	}
+
+	if (conn->run_timer) {
+		purple_timeout_remove(conn->run_timer);
+		conn->run_timer = 0;
+	}
 
-static void msn_soap_message_send_internal(MsnSession *session, MsnSoapMessage *message,
-	const char *host, const char *path, gboolean secure,
-	MsnSoapCallback cb, gpointer cb_data, gboolean first);
+	if (conn->message) {
+		msn_soap_message_destroy(conn->message);
+		conn->message = NULL;
+	}
+
+	if (conn->buf) {
+		g_string_free(conn->buf, TRUE);
+		conn->buf = NULL;
+	}
+
+	if (conn->ssl && (disconnect || conn->close_when_done)) {
+		purple_ssl_close(conn->ssl);
+		conn->ssl = NULL;
+	}
+
+	if (conn->current_request) {
+		msn_soap_request_destroy(conn->current_request, FALSE);
+		conn->current_request = NULL;
+	}
+}
 
-static void msn_soap_request_destroy(MsnSoapRequest *req, gboolean keep_message);
-static void msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect);
-static gboolean msn_soap_write_cb_internal(gpointer data, gint fd, PurpleInputCondition cond, gboolean initial);
-static void msn_soap_process(MsnSoapConnection *conn);
+static void
+msn_soap_connection_destroy_foreach_cb(gpointer item, gpointer data)
+{
+	MsnSoapRequest *req = item;
+
+	if (req->cb)
+		req->cb(req->message, NULL, req->cb_data);
+
+	msn_soap_request_destroy(req, FALSE);
+}
+
+static void
+msn_soap_connection_destroy(MsnSoapConnection *conn)
+{
+	if (conn->current_request) {
+		MsnSoapRequest *req = conn->current_request;
+		conn->current_request = NULL;
+		msn_soap_connection_destroy_foreach_cb(req, conn);
+	}
+
+	msn_soap_connection_sanitize(conn, TRUE);
+	g_queue_foreach(conn->queue, msn_soap_connection_destroy_foreach_cb, conn);
+	g_queue_free(conn->queue);
+
+	g_free(conn->host);
+	g_free(conn);
+}
 
 static gboolean
 msn_soap_cleanup_each(gpointer key, gpointer value, gpointer data)
@@ -112,13 +190,12 @@
 		g_hash_table_foreach_remove(sess->soap_table, msn_soap_cleanup_each,
 			&t);
 
-		if (g_hash_table_size(sess->soap_table) == 0) {
-			purple_timeout_remove(sess->soap_cleanup_handle);
-			sess->soap_cleanup_handle = 0;
-		}
+		if (g_hash_table_size(sess->soap_table) != 0)
+			return TRUE;
 	}
 
-	return TRUE;
+	sess->soap_cleanup_handle = 0;
+	return FALSE;
 }
 
 static MsnSoapConnection *
@@ -147,38 +224,54 @@
 	return conn;
 }
 
-static MsnSoapConnection *
-msn_soap_connection_new(MsnSession *session, const char *host)
+static void
+msn_soap_connection_handle_next(MsnSoapConnection *conn)
 {
-	MsnSoapConnection *conn = g_new0(MsnSoapConnection, 1);
-	conn->session = session;
-	conn->host = g_strdup(host);
-	conn->queue = g_queue_new();
-	return conn;
+	msn_soap_connection_sanitize(conn, FALSE);
+
+	conn->run_timer = purple_timeout_add(0, msn_soap_connection_run, conn);
+
+	if (conn->current_request) {
+		MsnSoapRequest *req = conn->current_request;
+		conn->current_request = NULL;
+		msn_soap_connection_destroy_foreach_cb(req, conn);
+	}
 }
 
 static void
-msn_soap_connected_cb(gpointer data, PurpleSslConnection *ssl,
-		PurpleInputCondition cond)
+msn_soap_message_send_internal(MsnSession *session, MsnSoapMessage *message,
+	const char *host, const char *path, gboolean secure,
+	MsnSoapCallback cb, gpointer cb_data, gboolean first)
 {
-	MsnSoapConnection *conn = data;
+	MsnSoapConnection *conn = msn_soap_get_connection(session, host);
+	MsnSoapRequest *req = g_new0(MsnSoapRequest, 1);
 
-	conn->connected = TRUE;
+	req->path = g_strdup(path);
+	req->message = message;
+	req->secure = secure;
+	req->cb = cb;
+	req->cb_data = cb_data;
 
-	if (conn->event_handle == 0)
-		conn->event_handle = purple_timeout_add(0, msn_soap_connection_run, conn);
+	if (first) {
+		g_queue_push_head(conn->queue, req);
+	} else {
+		g_queue_push_tail(conn->queue, req);
+	}
+
+	if (conn->run_timer == 0)
+		conn->run_timer = purple_timeout_add(0, msn_soap_connection_run,
+			conn);
 }
 
-static void
-msn_soap_error_cb(PurpleSslConnection *ssl, PurpleSslErrorType error,
-		gpointer data)
+void
+msn_soap_message_send(MsnSession *session, MsnSoapMessage *message,
+	const char *host, const char *path, gboolean secure,
+	MsnSoapCallback cb, gpointer cb_data)
 {
-	MsnSoapConnection *conn = data;
+	g_return_if_fail(message != NULL);
 
-	/* sslconn already frees the connection in case of error */
-	conn->ssl = NULL;
-
-	g_hash_table_remove(conn->session->soap_table, conn->host);
+	msn_soap_message_send_internal(session, message, host, path, secure,
+		cb, cb_data, FALSE);
 }
 
 static gboolean
@@ -259,65 +352,17 @@
 }
 
 static void
-msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond)
+msn_soap_message_add_header(MsnSoapMessage *message,
+		const char *name, const char *value)
 {
-	MsnSoapConnection *conn = data;
-	int count = 0, cnt, perrno;
-	/* This buffer needs to be larger than any packets received from
-		login.live.com or Adium will fail to receive the packet
-		(something weird with the login.live.com server). With NSS it works
-		fine, so I believe it's some bug with OS X */ 
-	char buf[16 * 1024];
-	gsize cursor;
-
-	if (conn->message == NULL) {
-		conn->message = msn_soap_message_new(NULL, NULL);
-	}
-
-	if (conn->buf == NULL) {
-		conn->buf = g_string_new_len(buf, 0);
-	}
-
-	cursor = conn->buf->len;
-	while ((cnt = purple_ssl_read(conn->ssl, buf, sizeof(buf))) > 0) {
-		purple_debug_info("soap", "read %d bytes\n", cnt);
-		count += cnt;
-		g_string_append_len(conn->buf, buf, cnt);
-	}
+	char *header = g_strdup_printf("%s: %s\r\n", name, value);
 
-	perrno = errno;
-	if (cnt < 0 && perrno != EAGAIN)
-		purple_debug_info("soap", "read: %s\n", g_strerror(perrno));
-
-#ifndef MSN_UNSAFE_DEBUG
-	if (conn->current_request->secure)
-		purple_debug_misc("soap", "Received secure request.\n");
-	else
-#endif
-	if (count != 0)
-		purple_debug_misc("soap", "current %s\n", conn->buf->str + cursor);
-
-	/* && count is necessary for Adium, on OS X the last read always
-	   return an error, so we want to proceed anyway. See #5212 for
-	   discussion on this and the above buffer size issues */
-	if(cnt < 0 && errno == EAGAIN && count == 0)
-		return;
-
-	/* msn_soap_process could alter errno */
-	msn_soap_process(conn);
-	
-	if (cnt < 0 && perrno != EAGAIN) {
-		/* It's possible msn_soap_process closed the ssl connection */
-		if (conn->ssl) {
-			purple_ssl_close(conn->ssl);
-			conn->ssl = NULL;
-			msn_soap_connection_handle_next(conn);
-		}
-	}
+	message->headers = g_slist_prepend(message->headers, header);
 }
 
 static void
-msn_soap_process(MsnSoapConnection *conn) {
+msn_soap_process(MsnSoapConnection *conn)
+{
 	gboolean handled = FALSE;
 	char *cursor;
 	char *linebreak;
@@ -429,9 +474,61 @@
 }
 
 static void
-msn_soap_write_cb(gpointer data, gint fd, PurpleInputCondition cond)
+msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond)
 {
-	msn_soap_write_cb_internal(data, fd, cond, FALSE);
+	MsnSoapConnection *conn = data;
+	int count = 0, cnt, perrno;
+	/* This buffer needs to be larger than any packets received from
+		login.live.com or Adium will fail to receive the packet
+		(something weird with the login.live.com server). With NSS it works
+		fine, so I believe it's some bug with OS X */
+	char buf[16 * 1024];
+	gsize cursor;
+
+	if (conn->message == NULL) {
+		conn->message = msn_soap_message_new(NULL, NULL);
+	}
+
+	if (conn->buf == NULL) {
+		conn->buf = g_string_new_len(buf, 0);
+	}
+
+	cursor = conn->buf->len;
+	while ((cnt = purple_ssl_read(conn->ssl, buf, sizeof(buf))) > 0) {
+		purple_debug_info("soap", "read %d bytes\n", cnt);
+		count += cnt;
+		g_string_append_len(conn->buf, buf, cnt);
+	}
+
+	perrno = errno;
+	if (cnt < 0 && perrno != EAGAIN)
+		purple_debug_info("soap", "read: %s\n", g_strerror(perrno));
+
+#ifndef MSN_UNSAFE_DEBUG
+	if (conn->current_request->secure)
+		purple_debug_misc("soap", "Received secure request.\n");
+	else
+#endif
+	if (count != 0)
+		purple_debug_misc("soap", "current %s\n", conn->buf->str + cursor);
+
+	/* && count is necessary for Adium, on OS X the last read always
+	   return an error, so we want to proceed anyway. See #5212 for
+	   discussion on this and the above buffer size issues */
+	if(cnt < 0 && errno == EAGAIN && count == 0)
+		return;
+
+	/* msn_soap_process could alter errno */
+	msn_soap_process(conn);
+
+	if (cnt < 0 && perrno != EAGAIN) {
+		/* It's possible msn_soap_process closed the ssl connection */
+		if (conn->ssl) {
+			purple_ssl_close(conn->ssl);
+			conn->ssl = NULL;
+			msn_soap_connection_handle_next(conn);
+		}
+	}
 }
 
 static gboolean
@@ -441,7 +538,8 @@
 	MsnSoapConnection *conn = data;
 	int written;
 
-	if (cond != PURPLE_INPUT_WRITE) return TRUE;
+	if (cond != PURPLE_INPUT_WRITE)
+		return TRUE;
 
 	written = purple_ssl_write(conn->ssl, conn->buf->str + conn->handled_len,
 		conn->buf->len - conn->handled_len);
@@ -451,7 +549,8 @@
 	else if (written <= 0) {
 		purple_ssl_close(conn->ssl);
 		conn->ssl = NULL;
-		if (!initial) msn_soap_connection_handle_next(conn);
+		if (!initial)
+			msn_soap_connection_handle_next(conn);
 		return FALSE;
 	}
 
@@ -475,13 +574,54 @@
 	return TRUE;
 }
 
+static void
+msn_soap_write_cb(gpointer data, gint fd, PurpleInputCondition cond)
+{
+	msn_soap_write_cb_internal(data, fd, cond, FALSE);
+}
+
+static void
+msn_soap_error_cb(PurpleSslConnection *ssl, PurpleSslErrorType error,
+		gpointer data)
+{
+	MsnSoapConnection *conn = data;
+
+	/* sslconn already frees the connection in case of error */
+	conn->ssl = NULL;
+
+	g_hash_table_remove(conn->session->soap_table, conn->host);
+}
+
+static void
+msn_soap_connected_cb(gpointer data, PurpleSslConnection *ssl,
+		PurpleInputCondition cond)
+{
+	MsnSoapConnection *conn = data;
+
+	conn->connected = TRUE;
+
+	if (conn->run_timer == 0)
+		conn->run_timer = purple_timeout_add(0, msn_soap_connection_run, conn);
+}
+
+MsnSoapMessage *
+msn_soap_message_new(const char *action, xmlnode *xml)
+{
+	MsnSoapMessage *message = g_new0(MsnSoapMessage, 1);
+
+	message->action = g_strdup(action);
+	message->xml = xml;
+
+	return message;
+}
+
 static gboolean
 msn_soap_connection_run(gpointer data)
 {
 	MsnSoapConnection *conn = data;
 	MsnSoapRequest *req = g_queue_peek_head(conn->queue);
 
-	conn->event_handle = 0;
+	conn->run_timer = 0;
 
 	if (req) {
 		if (conn->ssl == NULL) {
@@ -532,13 +672,13 @@
 			if (!msn_soap_write_cb_internal(conn, conn->ssl->fd, PURPLE_INPUT_WRITE, TRUE)) {
 				/* Not connected => reconnect and retry */
 				purple_debug_info("soap", "not connected, reconnecting\n");
-				
+
 				conn->connected = FALSE;
 				conn->current_request = NULL;
 				msn_soap_connection_sanitize(conn, FALSE);
-				
+
 				g_queue_push_head(conn->queue, req);
-				conn->event_handle = purple_timeout_add(0, msn_soap_connection_run, conn);
+				conn->run_timer = purple_timeout_add(0, msn_soap_connection_run, conn);
 			}
 
 			g_free(body);
@@ -547,151 +687,3 @@
 
 	return FALSE;
 }
-
-void
-msn_soap_message_send(MsnSession *session, MsnSoapMessage *message,
-	const char *host, const char *path, gboolean secure,
-	MsnSoapCallback cb, gpointer cb_data)
-{
-	msn_soap_message_send_internal(session, message, host, path, secure,
-		cb, cb_data, FALSE);
-}
-
-static void
-msn_soap_message_send_internal(MsnSession *session, MsnSoapMessage *message,
-	const char *host, const char *path, gboolean secure,
-	MsnSoapCallback cb, gpointer cb_data, gboolean first)
-{
-	MsnSoapConnection *conn = msn_soap_get_connection(session, host);
-	MsnSoapRequest *req = g_new0(MsnSoapRequest, 1);
-
-	req->path = g_strdup(path);
-	req->message = message;
-	req->secure = secure;
-	req->cb = cb;
-	req->cb_data = cb_data;
-
-	if (first) {
-		g_queue_push_head(conn->queue, req);
-	} else {
-		g_queue_push_tail(conn->queue, req);
-	}
-
-	if (conn->event_handle == 0)
-		conn->event_handle = purple_timeout_add(0, msn_soap_connection_run,
-			conn);
-}
-
-static void
-msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect)
-{
-	if (conn->event_handle) {
-		purple_input_remove(conn->event_handle);
-		conn->event_handle = 0;
-	}
-
-	if (conn->message) {
-		msn_soap_message_destroy(conn->message);
-		conn->message = NULL;
-	}
-
-	if (conn->buf) {
-		g_string_free(conn->buf, TRUE);
-		conn->buf = NULL;
-	}
-
-	if (conn->ssl && (disconnect || conn->close_when_done)) {
-		purple_ssl_close(conn->ssl);
-		conn->ssl = NULL;
-	}
-
-	if (conn->current_request) {
-		msn_soap_request_destroy(conn->current_request, FALSE);
-		conn->current_request = NULL;
-	}
-}
-
-static void
-msn_soap_connection_handle_next(MsnSoapConnection *conn)
-{
-	msn_soap_connection_sanitize(conn, FALSE);
-
-	conn->event_handle = purple_timeout_add(0, msn_soap_connection_run,	conn);
-
-	if (conn->current_request) {
-		MsnSoapRequest *req = conn->current_request;
-		conn->current_request = NULL;
-		msn_soap_connection_destroy_foreach_cb(req, conn);
-	}
-}
-
-static void
-msn_soap_connection_destroy_foreach_cb(gpointer item, gpointer data)
-{
-	MsnSoapRequest *req = item;
-
-	if (req->cb)
-		req->cb(req->message, NULL, req->cb_data);
-
-	msn_soap_request_destroy(req, FALSE);
-}
-
-static void
-msn_soap_connection_destroy(MsnSoapConnection *conn)
-{
-	if (conn->current_request) {
-		MsnSoapRequest *req = conn->current_request;
-		conn->current_request = NULL;
-		msn_soap_connection_destroy_foreach_cb(req, conn);
-	}
-
-	msn_soap_connection_sanitize(conn, TRUE);
-	g_queue_foreach(conn->queue, msn_soap_connection_destroy_foreach_cb, conn);
-	g_queue_free(conn->queue);
-
-	g_free(conn->host);
-	g_free(conn);
-}
-
-MsnSoapMessage *
-msn_soap_message_new(const char *action, xmlnode *xml)
-{
-	MsnSoapMessage *message = g_new0(MsnSoapMessage, 1);
-
-	message->action = g_strdup(action);
-	message->xml = xml;
-
-	return message;
-}
-
-void
-msn_soap_message_destroy(MsnSoapMessage *message)
-{
-	if (message) {
-		g_slist_foreach(message->headers, (GFunc)g_free, NULL);
-		g_slist_free(message->headers);
-		g_free(message->action);
-		if (message->xml)
-			xmlnode_free(message->xml);
-		g_free(message);
-	}
-}
-
-void
-msn_soap_message_add_header(MsnSoapMessage *message,
-		const char *name, const char *value)
-{
-	char *header = g_strdup_printf("%s: %s\r\n", name, value);
-
-	message->headers = g_slist_prepend(message->headers, header);
-}
-
-static void
-msn_soap_request_destroy(MsnSoapRequest *req, gboolean keep_message)
-{
-	g_free(req->path);
-	if (!keep_message)
-		msn_soap_message_destroy(req->message);
-	g_free(req);
-}
-
--- a/libpurple/protocols/msn/soap.h	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/msn/soap.h	Thu Nov 27 21:15:43 2008 +0000
@@ -44,13 +44,8 @@
 
 MsnSoapMessage *msn_soap_message_new(const char *action, xmlnode *xml);
 
-void msn_soap_message_add_header(MsnSoapMessage *req,
-	const char *name, const char *value);
-
 void msn_soap_message_send(MsnSession *session, MsnSoapMessage *message,
 	const char *host, const char *path, gboolean secure,
 	MsnSoapCallback cb, gpointer cb_data);
 
-void msn_soap_message_destroy(MsnSoapMessage *message);
-
 #endif
--- a/libpurple/protocols/msn/switchboard.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/msn/switchboard.c	Thu Nov 27 21:15:43 2008 +0000
@@ -81,6 +81,9 @@
 
 	swboard->destroying = TRUE;
 
+	if (swboard->reconn_timeout_h > 0)
+		purple_timeout_remove(swboard->reconn_timeout_h);
+
 	/* If it linked us is because its looking for trouble */
 	while (swboard->slplinks != NULL)
 		msn_slplink_destroy(swboard->slplinks->data);
@@ -577,6 +580,7 @@
 	MsnTransaction *trans;
 	char *payload;
 	gsize payload_len;
+	char flag;
 
 	g_return_if_fail(swboard != NULL);
 	g_return_if_fail(msg     != NULL);
@@ -590,32 +594,35 @@
 	msn_message_show_readable(msg, "SB SEND", FALSE);
 #endif
 
+	flag = msn_message_get_flag(msg);
 	trans = msn_transaction_new(cmdproc, "MSG", "%c %" G_GSIZE_FORMAT,
-								msn_message_get_flag(msg), payload_len);
+								flag, payload_len);
 
 	/* Data for callbacks */
 	msn_transaction_set_data(trans, msg);
 
-	if (msg->type == MSN_MSG_TEXT)
-	{
-		msg->ack_ref = TRUE;
-		msn_message_ref(msg);
-		swboard->ack_list = g_list_append(swboard->ack_list, msg);
-		msn_transaction_set_timeout_cb(trans, msg_timeout);
-	}
-	else if (msg->type == MSN_MSG_SLP)
-	{
-		msg->ack_ref = TRUE;
-		msn_message_ref(msg);
-		swboard->ack_list = g_list_append(swboard->ack_list, msg);
-		msn_transaction_set_timeout_cb(trans, msg_timeout);
+	if (flag != 'U') {
+		if (msg->type == MSN_MSG_TEXT)
+		{
+			msg->ack_ref = TRUE;
+			msn_message_ref(msg);
+			swboard->ack_list = g_list_append(swboard->ack_list, msg);
+			msn_transaction_set_timeout_cb(trans, msg_timeout);
+		}
+		else if (msg->type == MSN_MSG_SLP)
+		{
+			msg->ack_ref = TRUE;
+			msn_message_ref(msg);
+			swboard->ack_list = g_list_append(swboard->ack_list, msg);
+			msn_transaction_set_timeout_cb(trans, msg_timeout);
 #if 0
-		if (msg->ack_cb != NULL)
-		{
-			msn_transaction_add_cb(trans, "ACK", msg_ack);
-			msn_transaction_add_cb(trans, "NAK", msg_nak);
+			if (msg->ack_cb != NULL)
+			{
+				msn_transaction_add_cb(trans, "ACK", msg_ack);
+				msn_transaction_add_cb(trans, "NAK", msg_nak);
+			}
+#endif
 		}
-#endif
 	}
 
 	trans->payload = payload;
@@ -806,7 +813,7 @@
 ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	purple_debug_misc("msn", "get UBM...\n");
-	cmd->payload_len = atoi(cmd->params[4]);
+	cmd->payload_len = atoi(cmd->params[3]);
 	cmdproc->last_cmd->payload_cb = msg_cmd_post;
 }
 
--- a/libpurple/protocols/msn/user.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/msn/user.c	Thu Nov 27 21:15:43 2008 +0000
@@ -275,9 +275,8 @@
 		b = purple_buddy_new(account, passport, NULL);
 		purple_blist_add_buddy(b, NULL, g, NULL);
 	}
-	b->proto_data = user;
+	purple_buddy_set_protocol_data(b, user);
 	/*Update the blist Node info*/
-//	purple_blist_node_set_string(&(b->node), "", "");
 }
 
 /*check if the msn user is online*/
--- a/libpurple/protocols/msn/userlist.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/msn/userlist.c	Thu Nov 27 21:15:43 2008 +0000
@@ -876,31 +876,37 @@
 msn_userlist_load(MsnSession *session)
 {
 	PurpleBlistNode *gnode, *cnode, *bnode;
-	PurpleConnection *gc = purple_account_get_connection(session->account);
+	PurpleAccount *account = session->account;
+	PurpleConnection *gc = purple_account_get_connection(account);
 	GSList *l;
 	MsnUser * user;
 
 	g_return_if_fail(gc != NULL);
 
-	for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next)
+	for (gnode = purple_blist_get_root(); gnode;
+			gnode = purple_blist_node_get_sibling_next(gnode))
 	{
 		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for (cnode = gnode->child; cnode; cnode = cnode->next)
+		for (cnode = purple_blist_node_get_first_child(gnode);
+				cnode;
+				cnode = purple_blist_node_get_sibling_next(cnode))
 		{
 			if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			for (bnode = cnode->child; bnode; bnode = bnode->next)
+			for (bnode = purple_blist_node_get_first_child(cnode);
+					bnode;
+					bnode = purple_blist_node_get_sibling_next(bnode))
 			{
 				PurpleBuddy *b;
 				if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
 				b = (PurpleBuddy *)bnode;
-				if (b->account == gc->account)
+				if (purple_buddy_get_account(b) == account)
 				{
 					user = msn_userlist_find_add_user(session->userlist,
-						b->name,NULL);
-					b->proto_data = user;
+						purple_buddy_get_name(b), NULL);
+					purple_buddy_set_protocol_data(b, user);
 					msn_user_set_op(user, MSN_LIST_FL_OP);
 				}
 			}
--- a/libpurple/protocols/myspace/README	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/myspace/README	Thu Nov 27 21:15:43 2008 +0000
@@ -10,9 +10,6 @@
 
 For features and TODO, see http://developer.pidgin.im/wiki/MySpaceIM
 
-Windows installation: Unzip the archive to C:\Program Files\Pidgin
-Unix/source installation: run "make install"
-
 Usage:
 
 Login using your _email address_ you use to login to myspace.com. You can't
--- a/libpurple/protocols/myspace/message.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/myspace/message.c	Thu Nov 27 21:15:43 2008 +0000
@@ -613,6 +613,7 @@
 		const gchar *sep, 
 		const gchar *begin, const gchar *end)
 {
+	int num_items;
 	gchar **strings;
 	gchar **strings_tmp;
 	gchar *joined;
@@ -621,8 +622,10 @@
 
 	g_return_val_if_fail(msg != NULL, NULL);
 
+	num_items = g_list_length(msg);
+
 	/* Add one for NULL terminator for g_strjoinv(). */
-	strings = (gchar **)g_new0(gchar *, g_list_length(msg) + 1);
+	strings = (gchar **)g_new0(gchar *, num_items + 1);
 
 	strings_tmp = strings;
 	g_list_foreach(msg, gf, &strings_tmp);
@@ -632,7 +635,7 @@
 	g_free(joined);
 
 	/* Clean up. */
-	for (i = 0; i < g_list_length(msg); ++i) {
+	for (i = 0; i < num_items; ++i) {
 		g_free(strings[i]);
 	}
 
--- a/libpurple/protocols/myspace/myspace.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Thu Nov 27 21:15:43 2008 +0000
@@ -988,7 +988,7 @@
 
 		buddy = purple_buddy_new(session->account, username, NULL);
 		user->buddy = buddy;
-		buddy->proto_data = (gpointer)user;
+		purple_buddy_set_protocol_data(buddy, (gpointer)user);
 	}
 
 	/* Update user structure with new information */
@@ -1041,7 +1041,7 @@
 	user = msim_find_user(session, username);
 
 	/* If is on buddy list, lookup by uid since it is faster. */
-	if (user && (uid = purple_blist_node_get_int(&user->buddy->node, "UserID"))) {
+	if (user && (uid = purple_blist_node_get_int((PurpleBlistNode *)user->buddy, "UserID"))) {
 		user_to_lookup = g_strdup_printf("%d", uid);
 	} else {
 		/* Looking up buddy not on blist. Lookup by whatever user entered. */
@@ -1267,7 +1267,7 @@
 		/* See finch/gnthistory.c */
 		buddy = cur->data;
 
-		uid = purple_blist_node_get_int(&buddy->node, "UserID");
+		uid = purple_blist_node_get_int((PurpleBlistNode *)buddy, "UserID");
 		name = purple_buddy_get_name(buddy);
 
 		if (uid == wanted_uid)
@@ -1987,7 +1987,7 @@
 		user = msim_get_user_from_buddy(buddy);
 
 		/* All buddies on list should have a UserID integer associated with them. */
-		purple_blist_node_set_int(&buddy->node, "UserID", msim_msg_get_integer(msg, "f"));
+		purple_blist_node_set_int((PurpleBlistNode *)buddy, "UserID", msim_msg_get_integer(msg, "f"));
 		
 		msim_store_user_info(session, msg, NULL);
 	} else {
@@ -2080,10 +2080,14 @@
 	MsimMessage *msg;
 	MsimMessage *msg_persist;
 	MsimMessage *body;
+	const char *name, *gname;
 
 	session = (MsimSession *)gc->proto_data;
+	name = purple_buddy_get_name(buddy);
+	gname = group ? purple_group_get_name(group) : NULL;
+
 	purple_debug_info("msim", "msim_add_buddy: want to add %s to %s\n", 
-			buddy->name, (group && group->name) ? group->name : "(no group)");
+			name, gname ? gname : "(no group)");
 
 	msg = msim_msg_new(
 			"addbuddy", MSIM_TYPE_BOOLEAN, TRUE,
@@ -2092,7 +2096,7 @@
 			"reason", MSIM_TYPE_STRING, g_strdup(""),
 			NULL);
 
-	if (!msim_postprocess_outgoing(session, msg, buddy->name, "newprofileid", "reason")) {
+	if (!msim_postprocess_outgoing(session, msg, name, "newprofileid", "reason")) {
 		purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("'addbuddy' command failed."));
 		msim_msg_free(msg);
 		return;
@@ -2104,7 +2108,7 @@
 
 	body = msim_msg_new(
 			"ContactID", MSIM_TYPE_STRING, g_strdup("<uid>"),
-			"GroupName", MSIM_TYPE_STRING, g_strdup(group->name),
+			"GroupName", MSIM_TYPE_STRING, g_strdup(gname),
 			"Position", MSIM_TYPE_INTEGER, 1000,
 			"Visibility", MSIM_TYPE_INTEGER, 1,
 			"NickName", MSIM_TYPE_STRING, g_strdup(""),
@@ -2125,7 +2129,7 @@
 		"body", MSIM_TYPE_DICTIONARY, body,
 		NULL);
 
-	if (!msim_postprocess_outgoing(session, msg_persist, buddy->name, "body", NULL))
+	if (!msim_postprocess_outgoing(session, msg_persist, name, "body", NULL))
 	{
 		purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("persist command failed"));
 		msim_msg_free(msg_persist);
@@ -2301,7 +2305,7 @@
 		/* Next, see if on buddy list and know uid. */
 		buddy = purple_find_buddy(session->account, username);
 		if (buddy) {
-			uid = purple_blist_node_get_int(&buddy->node, "UserID");
+			uid = purple_blist_node_get_int((PurpleBlistNode *)buddy, "UserID");
 		} else {
 			uid = 0;
 		}
@@ -2343,8 +2347,10 @@
 	MsimMessage *persist_msg;
 	MsimMessage *blocklist_msg;
 	GList *blocklist_updates;
+	const char *name;
 
 	session = (MsimSession *)gc->proto_data;
+	name = purple_buddy_get_name(buddy);
 
 	delbuddy_msg = msim_msg_new(
 				"delbuddy", MSIM_TYPE_BOOLEAN, TRUE,
@@ -2352,7 +2358,7 @@
 				/* 'delprofileid' with uid will be inserted here. */
 				NULL);
 
-	if (!msim_postprocess_outgoing(session, delbuddy_msg, buddy->name, "delprofileid", NULL)) {
+	if (!msim_postprocess_outgoing(session, delbuddy_msg, name, "delprofileid", NULL)) {
 		purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("'delbuddy' command failed"));
 		msim_msg_free(delbuddy_msg);
 		return;
@@ -2371,7 +2377,7 @@
 			"body", MSIM_TYPE_STRING, g_strdup("ContactID=<uid>"),
 			NULL);
 
-	if (!msim_postprocess_outgoing(session, persist_msg, buddy->name, "body", NULL)) {
+	if (!msim_postprocess_outgoing(session, persist_msg, name, "body", NULL)) {
 		purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("persist command failed"));
 		msim_msg_free(persist_msg);
 		return;
@@ -2393,7 +2399,7 @@
 			"idlist", MSIM_TYPE_LIST, blocklist_updates,
 			NULL);
 
-	if (!msim_postprocess_outgoing(session, blocklist_msg, buddy->name, "idlist", NULL)) {
+	if (!msim_postprocess_outgoing(session, blocklist_msg, name, "idlist", NULL)) {
 		purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("blocklist command failed"));
 		msim_msg_free(blocklist_msg);
 		return;
@@ -2747,12 +2753,16 @@
 	MsimSession *session;
 	MsimUser *user;
 	const gchar *display_name, *headline;
+	PurpleAccount *account;
+	PurpleConnection *gc;
 
 	g_return_val_if_fail(buddy != NULL, NULL);
 
 	user = msim_get_user_from_buddy(buddy);
 
-	session = (MsimSession *)buddy->account->gc->proto_data;
+	account = purple_buddy_get_account(buddy);
+	gc = purple_account_get_connection(account);
+	session = (MsimSession *)gc->proto_data;
 	g_return_val_if_fail(MSIM_SESSION_VALID(session), NULL);
 
 	display_name = headline = NULL;
@@ -2800,8 +2810,10 @@
 
 	if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
 		MsimSession *session;
-
-		session = (MsimSession *)buddy->account->gc->proto_data;
+		PurpleAccount *account = purple_buddy_get_account(buddy);
+		PurpleConnection *gc = purple_account_get_connection(account);
+
+		session = (MsimSession *)gc->proto_data;
 
 		g_return_if_fail(MSIM_SESSION_VALID(session));
 
@@ -2882,7 +2894,7 @@
 	user = msim_get_user_from_buddy(buddy);
 
 	/* All buddies on list should have 'uid' integer associated with them. */
-	purple_blist_node_set_int(&buddy->node, "UserID", uid);
+	purple_blist_node_set_int((PurpleBlistNode *)buddy, "UserID", uid);
 
 	/* Stores a few fields in the MsimUser, relevant to the buddy itself.
 	 * AvatarURL, Headline, ContactID. */
--- a/libpurple/protocols/myspace/user.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/myspace/user.c	Thu Nov 27 21:15:43 2008 +0000
@@ -57,16 +57,14 @@
 		return NULL;
 	}
 
-	if (!buddy->proto_data) {
+	if (!(user = purple_buddy_get_protocol_data(buddy))) {
 		/* No MsimUser for this buddy; make one. */
 
 		/* TODO: where is this freed? */
 		user = g_new0(MsimUser, 1);
 		user->buddy = buddy;
-		buddy->proto_data = (gpointer)user;
-	} 
-
-	user = (MsimUser *)(buddy->proto_data);
+		purple_buddy_set_protocol_data(buddy, (gpointer)user);
+	}
 
 	return user;
 }
@@ -105,7 +103,7 @@
 		purple_notify_user_info_add_pair(user_info, _("User"), user->username);
 	}
 
-	uid = purple_blist_node_get_int(&user->buddy->node, "UserID");
+	uid = purple_blist_node_get_int((PurpleBlistNode *)user->buddy, "UserID");
 
 	if (full) {
 		/* TODO: link to username, if available */
@@ -198,7 +196,9 @@
 static void msim_set_artist_or_title(MsimUser *user, const char *new_artist, const char *new_title)
 {
 	PurplePresence *presence;
+	PurpleAccount *account;
 	const char *prev_artist, *prev_title;
+	const char *name;
 
 	prev_artist = NULL;
 	prev_title = NULL;
@@ -208,8 +208,11 @@
 	if (new_title && !strlen(new_title))
 		new_title = NULL;
 
+	account = purple_buddy_get_account(user->buddy);
+	name = purple_buddy_get_name(user->buddy);
+
 	if (!new_artist && !new_title) {
-		purple_prpl_got_user_status_deactive(user->buddy->account, user->buddy->name, "tune");
+		purple_prpl_got_user_status_deactive(account, name, "tune");
 		return;
 	}
 
@@ -229,7 +232,7 @@
 	if (!new_title)
 		new_title = prev_title;
 
-	purple_prpl_got_user_status(user->buddy->account, user->buddy->name, "tune",
+	purple_prpl_got_user_status(account, name, "tune",
 			PURPLE_TUNE_TITLE, new_title,
 			PURPLE_TUNE_ARTIST, new_artist,
 			NULL);
@@ -245,12 +248,13 @@
 void 
 msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user)
 {
+	const char *name = user->buddy ? purple_buddy_get_name(user->buddy) : NULL;
 	if (g_str_equal(key_str, "UserID") || g_str_equal(key_str, "ContactID")) {
 		/* Save to buddy list, if it exists, for quick cached uid lookup with msim_uid2username_from_blist(). */
 		if (user->buddy)
 		{
-			purple_debug_info("msim", "associating uid %s with username %s\n", key_str, user->buddy->name);
-			purple_blist_node_set_int(&user->buddy->node, "UserID", atol(value_str));
+			purple_debug_info("msim", "associating uid %s with username %s\n", key_str, name);
+			purple_blist_node_set_int((PurpleBlistNode *)user->buddy, "UserID", atol(value_str));
 		}
 		/* Need to store in MsimUser, too? What if not on blist? */
 	} else if (g_str_equal(key_str, "Age")) {
@@ -300,9 +304,8 @@
 		/* Instead of showing 'no photo' picture, show nothing. */
 		if (g_str_equal(user->image_url, "http://x.myspace.com/images/no_pic.gif"))
 		{
-			purple_buddy_icons_set_for_user(user->buddy->account,
-				user->buddy->name,
-				NULL, 0, NULL);
+			purple_buddy_icons_set_for_user(purple_buddy_get_account(user->buddy),
+				name, NULL, 0, NULL);
 			return;
 		}
 
@@ -539,8 +542,10 @@
 		const gchar *error_message)
 {
 	MsimUser *user;
+	const char *name;
 
 	user = (MsimUser *)user_data;
+	name = purple_buddy_get_name(user->buddy);
 
 	purple_debug_info("msim_downloaded_buddy_icon",
 			"Downloaded %" G_GSIZE_FORMAT " bytes\n", len);
@@ -548,13 +553,12 @@
 	if (!url_text) {
 		purple_debug_info("msim_downloaded_buddy_icon",
 				"failed to download icon for %s",
-				user->buddy->name);
+				name);
 		return;
 	}
 
-	purple_buddy_icons_set_for_user(user->buddy->account,
-			user->buddy->name,
-			g_memdup((gchar *)url_text, len), len, 
+	purple_buddy_icons_set_for_user(purple_buddy_get_account(user->buddy),
+			name, g_memdup((gchar *)url_text, len), len,
 			/* Use URL itself as buddy icon "checksum" (TODO: ETag) */
 			user->image_url);		/* checksum */
 }
--- a/libpurple/protocols/myspace/zap.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/myspace/zap.c	Thu Nov 27 21:15:43 2008 +0000
@@ -177,13 +177,13 @@
 	buddy = (PurpleBuddy *)node;
 
 	/* Find the session */
-	account = buddy->account;
+	account = purple_buddy_get_account(buddy);
 	gc = purple_account_get_connection(account);
 	session = (MsimSession *)gc->proto_data;
 
 	zap = GPOINTER_TO_INT(zap_num_ptr);
 
-	purple_prpl_send_attention(session->gc, buddy->name, zap);
+	purple_prpl_send_attention(session->gc, purple_buddy_get_name(buddy), zap);
 }
 
 /** Return menu, if any, for a buddy list node. */
--- a/libpurple/protocols/novell/novell.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/novell/novell.c	Thu Nov 27 21:15:43 2008 +0000
@@ -293,7 +293,7 @@
 								nm_user_record_get_display_id(user_record));
 
 		alias = purple_buddy_get_alias(buddy);
-		if (alias == NULL || *alias == '\0' || (strcmp(alias, buddy->name) == 0)) {
+		if (alias == NULL || *alias == '\0' || (strcmp(alias, purple_buddy_get_name(buddy)) == 0)) {
 			purple_blist_alias_buddy(buddy,
 								   nm_user_record_get_full_name(user_record));
 
@@ -1175,10 +1175,12 @@
 	const char *status_id;
 	const char *text = NULL;
 	const char *dn;
+	const char *name;
 	int idle = 0;
 	gboolean loggedin = TRUE;
 
-	account = buddy->account;
+	account = purple_buddy_get_account(buddy);
+	name = purple_buddy_get_name(buddy);
 
 	switch (novellstatus) {
 		case NM_STATUS_AVAILABLE:
@@ -1205,7 +1207,7 @@
 	}
 
 	/* Get status text for the user */
-	dn = nm_lookup_dn(user, buddy->name);
+	dn = nm_lookup_dn(user, name);
 	if (dn) {
 		NMUserRecord *user_record = nm_find_user_record(user, dn);
 		if (user_record) {
@@ -1213,9 +1215,9 @@
 		}
 	}
 
-	purple_prpl_got_user_status(account, buddy->name, status_id,
+	purple_prpl_got_user_status(account, name, status_id,
 							  "message", text, NULL);
-	purple_prpl_got_user_idle(account, buddy->name,
+	purple_prpl_got_user_idle(account, name,
 							(novellstatus == NM_STATUS_AWAY_IDLE), idle);
 }
 
@@ -1230,44 +1232,46 @@
 	PurpleBlistNode *bnode;
 	PurpleGroup *group;
 	PurpleBuddy *buddy;
-	PurpleBuddyList *blist;
 	GSList *rem_list = NULL;
 	GSList *l;
 	NMFolder *folder = NULL;
 	const char *gname = NULL;
 
-	if ((blist = purple_get_blist())) {
-		for (gnode = blist->root; gnode; gnode = gnode->next) {
-			if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
+	for (gnode = purple_blist_get_root(); gnode;
+			gnode = purple_blist_node_get_sibling_next(gnode)) {
+		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
+			continue;
+		group = (PurpleGroup *) gnode;
+		gname = purple_group_get_name(group);
+		for (cnode = purple_blist_node_get_first_child(gnode);
+				cnode;
+				cnode = purple_blist_node_get_sibling_next(cnode)) {
+			if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			group = (PurpleGroup *) gnode;
-			for (cnode = gnode->child; cnode; cnode = cnode->next) {
-				if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
+			for (bnode = purple_blist_node_get_first_child(cnode);
+					bnode;
+					bnode = purple_blist_node_get_sibling_next(bnode)) {
+				if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
-				for (bnode = cnode->child; bnode; bnode = bnode->next) {
-					if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
-						continue;
-					buddy = (PurpleBuddy *) bnode;
-					if (buddy->account == user->client_data) {
-						gname = group->name;
-						if (strcmp(group->name, NM_ROOT_FOLDER_NAME) == 0)
-							gname = "";
-						folder = nm_find_folder(user, gname);
-						if (folder == NULL ||
-							!nm_folder_find_contact_by_display_id(folder, buddy->name)) {
-							rem_list = g_slist_append(rem_list, buddy);
-						}
+				buddy = (PurpleBuddy *) bnode;
+				if (purple_buddy_get_account(buddy) == user->client_data) {
+					if (strcmp(gname, NM_ROOT_FOLDER_NAME) == 0)
+						gname = "";
+					folder = nm_find_folder(user, gname);
+					if (folder == NULL ||
+							!nm_folder_find_contact_by_display_id(folder, purple_buddy_get_name(buddy))) {
+						rem_list = g_slist_append(rem_list, buddy);
 					}
 				}
 			}
 		}
-
-		if (rem_list) {
-			for (l = rem_list; l; l = l->next) {
-				purple_blist_remove_buddy(l->data);
-			}
-			g_slist_free(rem_list);
+	}
+
+	if (rem_list) {
+		for (l = rem_list; l; l = l->next) {
+			purple_blist_remove_buddy(l->data);
 		}
+		g_slist_free(rem_list);
 	}
 }
 
@@ -1613,14 +1617,14 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 
 	user = gc->proto_data;
 	if (user == NULL)
 		return;
 
 	/* We should already have a userrecord for the buddy */
-	user_record = nm_find_user_record(user, buddy->name);
+	user_record = nm_find_user_record(user, purple_buddy_get_name(buddy));
 	if (user_record == NULL)
 		return;
 
@@ -2538,7 +2542,7 @@
 	NMContact *contact;
 	NMUser *user;
 	NMERR_T rc = NM_OK;
-	const char *alias, *gname;
+	const char *alias, *gname, *bname;
 
 	if (gc == NULL || buddy == NULL || group == NULL)
 		return;
@@ -2554,22 +2558,22 @@
 		return;
 
 	contact = nm_create_contact();
-	nm_contact_set_dn(contact, buddy->name);
+	nm_contact_set_dn(contact, purple_buddy_get_name(buddy));
 
 	/* Remove the PurpleBuddy (we will add it back after adding it
 	 * to the server side list). Save the alias if there is one.
 	 */
 	alias = purple_buddy_get_alias(buddy);
-	if (alias && strcmp(alias, buddy->name))
+	bname = purple_buddy_get_name(buddy);
+	if (alias && strcmp(alias, bname))
 		nm_contact_set_display_name(contact, alias);
 
 	purple_blist_remove_buddy(buddy);
 	buddy = NULL;
 
-	if (strcmp(group->name, NM_ROOT_FOLDER_NAME) == 0) {
+	gname = purple_group_get_name(group);
+	if (strcmp(gname, NM_ROOT_FOLDER_NAME) == 0) {
 		gname = "";
-	} else {
-		gname = group->name;
 	}
 
 	folder = nm_find_folder(user, gname);
@@ -2603,11 +2607,10 @@
 		return;
 
 	user = (NMUser *) gc->proto_data;
-	if (user && (dn = nm_lookup_dn(user, buddy->name))) {
-		if (strcmp(group->name, NM_ROOT_FOLDER_NAME) == 0) {
+	if (user && (dn = nm_lookup_dn(user, purple_buddy_get_name(buddy)))) {
+		gname = purple_group_get_name(group);
+		if (strcmp(gname, NM_ROOT_FOLDER_NAME) == 0) {
 			gname = "";
-		} else {
-			gname = group->name;
 		}
 		folder = nm_find_folder(user, gname);
 		if (folder) {
@@ -2637,7 +2640,7 @@
 
 	user = (NMUser *) gc->proto_data;
 	if (user) {
-		NMFolder *folder = nm_find_folder(user, group->name);
+		NMFolder *folder = nm_find_folder(user, purple_group_get_name(group));
 
 		if (folder) {
 			rc = nm_send_remove_folder(user, folder,
@@ -2684,9 +2687,11 @@
 				}
 
 				if (group) {
+					const char *balias;
 					buddy = purple_find_buddy_in_group(user->client_data,
 													 name, group);
-					if (buddy && strcmp(buddy->alias, alias))
+					balias = buddy ? purple_buddy_get_local_buddy_alias(buddy) : NULL;
+					if (balias && strcmp(balias, alias))
 						purple_blist_alias_buddy(buddy, alias);
 				}
 
@@ -2777,8 +2782,9 @@
 
 	user = gc->proto_data;
 	if (user) {
+		const char *gname = purple_group_get_name(group);
 		/* Does new folder exist already? */
-		if (nm_find_folder(user, group->name)) {
+		if (nm_find_folder(user, gname)) {
 			/* purple_blist_rename_group() adds the buddies
 			 * to the new group and removes the old group...
 			 * so there is nothing more to do here.
@@ -2793,7 +2799,7 @@
 
 		folder = nm_find_folder(user, old_name);
 		if (folder) {
-			rc = nm_send_rename_folder(user, folder, group->name,
+			rc = nm_send_rename_folder(user, folder, gname,
 									   _rename_folder_resp_cb, NULL);
 			_check_for_disconnect(user, rc);
 		}
@@ -2819,12 +2825,12 @@
 	if (buddy == NULL)
 		return;
 
-	gc = purple_account_get_connection(buddy->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 	if (gc == NULL || (user = gc->proto_data) == NULL)
 		return;
 
 	if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
-		user_record = nm_find_user_record(user, buddy->name);
+		user_record = nm_find_user_record(user, purple_buddy_get_name(buddy));
 		if (user_record) {
 			status = nm_user_record_get_status(user_record);
 			text = nm_user_record_get_status_text(user_record);
@@ -2923,14 +2929,16 @@
 {
 	const char *text = NULL;
 	const char *dn = NULL;
-
-	if (buddy && buddy->account) {
-		PurpleConnection *gc = purple_account_get_connection(buddy->account);
+	PurpleAccount *account;
+
+	account = buddy ? purple_buddy_get_account(buddy) : NULL;
+	if (buddy && account) {
+		PurpleConnection *gc = purple_account_get_connection(account);
 
 		if (gc && gc->proto_data) {
 			NMUser *user = gc->proto_data;
 
-			dn = nm_lookup_dn(user, buddy->name);
+			dn = nm_lookup_dn(user, purple_buddy_get_name(buddy));
 			if (dn) {
 				NMUserRecord *user_record = nm_find_user_record(user, dn);
 
--- a/libpurple/protocols/oscar/oscar.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Thu Nov 27 21:15:43 2008 +0000
@@ -807,11 +807,13 @@
 	PurpleStatus *status = NULL;
 	gchar *message = NULL, *itmsurl = NULL, *tmp;
 	gboolean is_away;
+	const char *bname;
 
 	od = gc->proto_data;
 
+	bname = purple_buddy_get_name(b);
 	if (userinfo == NULL)
-		userinfo = aim_locate_finduserinfo(od, b->name);
+		userinfo = aim_locate_finduserinfo(od, bname);
 
 	if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL)))
 		return;
@@ -884,7 +886,7 @@
 
 	if (b) {
 		if (purple_presence_is_online(presence)) {
-			if (aim_snvalid_icq(b->name) || is_away || !message || !(*message)) {
+			if (aim_snvalid_icq(bname) || is_away || !message || !(*message)) {
 				/* Append the status name for online ICQ statuses, away AIM statuses, and for all buddies with no message.
 				 * If the status name and the message are the same, only show one. */
 				const char *status_name = purple_status_get_name(status);
@@ -901,8 +903,8 @@
 
 		} else {
 			if (aim_ssi_waitingforauth(od->ssi.local,
-									   aim_ssi_itemlist_findparentname(od->ssi.local, b->name),
-									   b->name)) {
+									   aim_ssi_itemlist_findparentname(od->ssi.local, bname),
+									   bname)) {
 				/* Note if an offline buddy is not authorized */
 				tmp = g_strdup_printf("%s%s%s",
 									  _("Not Authorized"),
@@ -931,6 +933,7 @@
 	PurpleGroup *g = NULL;
 	struct buddyinfo *bi = NULL;
 	char *tmp;
+	const char *bname, *gname = NULL;
 
 	od = gc->proto_data;
 	account = purple_connection_get_account(gc);
@@ -938,14 +941,16 @@
 	if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL)))
 		return;
 
+	bname = purple_buddy_get_name(b);
 	if (userinfo == NULL)
-		userinfo = aim_locate_finduserinfo(od, b->name);
+		userinfo = aim_locate_finduserinfo(od, bname);
 
 	if (b == NULL)
 		b = purple_find_buddy(account, userinfo->sn);
 
 	if (b != NULL) {
 		g = purple_buddy_get_group(b);
+		gname = purple_group_get_name(g);
 		presence = purple_buddy_get_presence(b);
 		status = purple_presence_get_active_status(presence);
 	}
@@ -969,8 +974,8 @@
 		g_free(tmp);
 	}
 
-	if ((b != NULL) && (b->name != NULL) && (g != NULL) && (g->name != NULL)) {
-		tmp = aim_ssi_getcomment(od->ssi.local, g->name, b->name);
+	if ((b != NULL) && (bname != NULL) && (g != NULL) && (gname != NULL)) {
+		tmp = aim_ssi_getcomment(od->ssi.local, gname, bname);
 		if (tmp != NULL) {
 			char *tmp2 = g_markup_escape_text(tmp, strlen(tmp));
 			g_free(tmp);
@@ -2444,6 +2449,7 @@
 	PurpleAccount *account;
 	PurpleBuddy *buddy;
 	PurpleGroup *group;
+	const char *bname, *gname;
 
 	gc = data->gc;
 	od = gc->proto_data;
@@ -2456,15 +2462,17 @@
 
 	if (group != NULL)
 	{
+		bname = purple_buddy_get_name(buddy);
+		gname = purple_group_get_name(group);
 		purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n",
-				   buddy->name, group->name);
+				   bname, gname);
 		aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list."));
-		if (!aim_ssi_itemlist_finditem(od->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY))
+		if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY))
 		{
-			aim_ssi_addbuddy(od, buddy->name, group->name, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE);
+			aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE);
 
 			/* Mobile users should always be online */
-			if (buddy->name[0] == '+') {
+			if (bname[0] == '+') {
 				purple_prpl_got_user_status(account,
 						purple_buddy_get_name(buddy),
 						OSCAR_STATUS_ID_AVAILABLE, NULL);
@@ -2504,8 +2512,8 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
-	purple_auth_sendrequest(gc, buddy->name);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	purple_auth_sendrequest(gc, purple_buddy_get_name(buddy));
 }
 
 /* When other people ask you for authorization */
@@ -3890,9 +3898,9 @@
 	user_info = purple_notify_user_info_new();
 
 	g_snprintf(who, sizeof(who), "%u", info->uin);
-	buddy = purple_find_buddy(purple_connection_get_account(gc), who);
+	buddy = purple_find_buddy(account, who);
 	if (buddy != NULL)
-		bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(buddy->account, buddy->name));
+		bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, purple_buddy_get_name(buddy)));
 	else
 		bi = NULL;
 
@@ -3909,7 +3917,7 @@
 	}
 	oscar_user_info_convert_and_add(account, user_info, _("First Name"), info->first);
 	oscar_user_info_convert_and_add(account, user_info, _("Last Name"), info->last);
-	if (info->email && info->email[0] && (utf8 = oscar_utf8_try_convert(gc->account, info->email))) {
+	if (info->email && info->email[0] && (utf8 = oscar_utf8_try_convert(account, info->email))) {
 		buf = g_strdup_printf("<a href=\"mailto:%s\">%s</a>", utf8, utf8);
 		purple_notify_user_info_add_pair(user_info, _("Email Address"), buf);
 		g_free(buf);
@@ -3918,7 +3926,7 @@
 	if (info->numaddresses && info->email2) {
 		int i;
 		for (i = 0; i < info->numaddresses; i++) {
-			if (info->email2[i] && info->email2[i][0] && (utf8 = oscar_utf8_try_convert(gc->account, info->email2[i]))) {
+			if (info->email2[i] && info->email2[i][0] && (utf8 = oscar_utf8_try_convert(account, info->email2[i]))) {
 				buf = g_strdup_printf("<a href=\"mailto:%s\">%s</a>", utf8, utf8);
 				purple_notify_user_info_add_pair(user_info, _("Email Address"), buf);
 				g_free(buf);
@@ -3953,7 +3961,7 @@
 		snprintf(age, sizeof(age), "%hhd", info->age);
 		purple_notify_user_info_add_pair(user_info, _("Age"), age);
 	}
-	if (info->personalwebpage && info->personalwebpage[0] && (utf8 = oscar_utf8_try_convert(gc->account, info->personalwebpage))) {
+	if (info->personalwebpage && info->personalwebpage[0] && (utf8 = oscar_utf8_try_convert(account, info->personalwebpage))) {
 		buf = g_strdup_printf("<a href=\"%s\">%s</a>", utf8, utf8);
 		purple_notify_user_info_add_pair(user_info, _("Personal Web Page"), buf);
 		g_free(buf);
@@ -3989,7 +3997,7 @@
 		oscar_user_info_convert_and_add(account, user_info, _("Division"), info->workdivision);
 		oscar_user_info_convert_and_add(account, user_info, _("Position"), info->workposition);
 
-		if (info->workwebpage && info->workwebpage[0] && (utf8 = oscar_utf8_try_convert(gc->account, info->workwebpage))) {
+		if (info->workwebpage && info->workwebpage[0] && (utf8 = oscar_utf8_try_convert(account, info->workwebpage))) {
 			char *webpage = g_strdup_printf("<a href=\"%s\">%s</a>", utf8, utf8);
 			purple_notify_user_info_add_pair(user_info, _("Web Page"), webpage);
 			g_free(webpage);
@@ -4023,7 +4031,7 @@
 	if (info->uin && info->nick && info->nick[0] && (utf8 = oscar_utf8_try_convert(account, info->nick))) {
 		g_snprintf(who, sizeof(who), "%u", info->uin);
 		serv_got_alias(gc, who, utf8);
-		if ((b = purple_find_buddy(gc->account, who))) {
+		if ((b = purple_find_buddy(account, who))) {
 			purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8);
 		}
 		g_free(utf8);
@@ -4791,14 +4799,17 @@
 oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
 	OscarData *od;
 	PurpleAccount *account;
+	const char *bname, *gname;
 
 	od = (OscarData *)gc->proto_data;
 	account = purple_connection_get_account(gc);
-
-	if (!aim_snvalid(buddy->name)) {
+	bname = purple_buddy_get_name(buddy);
+	gname = purple_group_get_name(group);
+
+	if (!aim_snvalid(bname)) {
 		gchar *buf;
-		buf = g_strdup_printf(_("Could not add the buddy %s because the username is invalid.  Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), buddy->name);
-		if (!purple_conv_present_error(buddy->name, account, buf))
+		buf = g_strdup_printf(_("Could not add the buddy %s because the username is invalid.  Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), bname);
+		if (!purple_conv_present_error(bname, account, buf))
 			purple_notify_error(gc, NULL, _("Unable to Add"), buf);
 		g_free(buf);
 
@@ -4808,34 +4819,34 @@
 		return;
 	}
 
-	if ((od->ssi.received_data) && !(aim_ssi_itemlist_finditem(od->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY))) {
+	if ((od->ssi.received_data) && !(aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY))) {
 		purple_debug_info("oscar",
-				   "ssi: adding buddy %s to group %s\n", buddy->name, group->name);
-		aim_ssi_addbuddy(od, buddy->name, group->name, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0);
+				   "ssi: adding buddy %s to group %s\n", bname, gname);
+		aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0);
 
 		/* Mobile users should always be online */
-		if (buddy->name[0] == '+') {
+		if (bname[0] == '+') {
 			purple_prpl_got_user_status(account,
-					purple_buddy_get_name(buddy),
-					OSCAR_STATUS_ID_AVAILABLE, NULL);
+					bname, OSCAR_STATUS_ID_AVAILABLE, NULL);
 			purple_prpl_got_user_status(account,
-					purple_buddy_get_name(buddy),
-					OSCAR_STATUS_ID_MOBILE, NULL);
+					bname, OSCAR_STATUS_ID_MOBILE, NULL);
 		}
 	}
 
 	/* XXX - Should this be done from AIM accounts, as well? */
 	if (od->icq)
-		aim_icq_getalias(od, buddy->name);
+		aim_icq_getalias(od, bname);
 }
 
 void oscar_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
 	OscarData *od = (OscarData *)gc->proto_data;
 
 	if (od->ssi.received_data) {
+		const char *gname = purple_group_get_name(group);
+		const char *bname = purple_buddy_get_name(buddy);
 		purple_debug_info("oscar",
-				   "ssi: deleting buddy %s from group %s\n", buddy->name, group->name);
-		aim_ssi_delbuddy(od, buddy->name, group->name);
+				   "ssi: deleting buddy %s from group %s\n", bname, gname);
+		aim_ssi_delbuddy(od, bname, gname);
 	}
 }
 
@@ -4867,7 +4878,8 @@
 	OscarData *od = (OscarData *)gc->proto_data;
 
 	if (od->ssi.received_data) {
-		if (aim_ssi_itemlist_finditem(od->ssi.local, group->name, NULL, AIM_SSI_TYPE_GROUP)) {
+		const char *gname = purple_group_get_name(group);
+		if (aim_ssi_itemlist_finditem(od->ssi.local, gname, NULL, AIM_SSI_TYPE_GROUP)) {
 			GList *cur, *groups = NULL;
 			PurpleAccount *account = purple_connection_get_account(gc);
 
@@ -4877,25 +4889,25 @@
 				/* node is PurpleBuddy, parent is a PurpleContact.
 				 * We must go two levels up to get the Group */
 				groups = g_list_append(groups,
-						node->parent->parent);
+						purple_buddy_get_group((PurpleBuddy*)node));
 			}
 
 			purple_account_remove_buddies(account, moved_buddies, groups);
 			purple_account_add_buddies(account, moved_buddies);
 			g_list_free(groups);
 			purple_debug_info("oscar",
-					   "ssi: moved all buddies from group %s to %s\n", old_name, group->name);
+					   "ssi: moved all buddies from group %s to %s\n", old_name, gname);
 		} else {
-			aim_ssi_rename_group(od, old_name, group->name);
+			aim_ssi_rename_group(od, old_name, gname);
 			purple_debug_info("oscar",
-					   "ssi: renamed group %s to %s\n", old_name, group->name);
+					   "ssi: renamed group %s to %s\n", old_name, gname);
 		}
 	}
 }
 
 void oscar_remove_group(PurpleConnection *gc, PurpleGroup *group)
 {
-	aim_ssi_delgroup(gc->proto_data, group->name);
+	aim_ssi_delgroup(gc->proto_data, purple_group_get_name(group));
 }
 
 static gboolean purple_ssi_rerequestdata(gpointer data) {
@@ -5004,33 +5016,44 @@
 		/* Buddies */
 		cur = NULL;
 		if ((blist = purple_get_blist()) != NULL) {
-			for (gnode = blist->root; gnode; gnode = gnode->next) {
+			for (gnode = purple_blist_get_root(); gnode;
+					gnode = purple_blist_node_get_sibling_next(gnode)) {
+				const char *gname;
 				if(!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 					continue;
 				g = (PurpleGroup *)gnode;
-				for (cnode = gnode->child; cnode; cnode = cnode->next) {
+				gname = purple_group_get_name(g);
+				for (cnode = purple_blist_node_get_first_child(gnode);
+						cnode;
+						cnode = purple_blist_node_get_sibling_next(cnode)) {
 					if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 						continue;
-					for (bnode = cnode->child; bnode; bnode = bnode->next) {
+					for (bnode = purple_blist_node_get_first_child(cnode);
+							bnode;
+							bnode = purple_blist_node_get_sibling_next(bnode)) {
+						const char *bname;
 						if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 							continue;
 						b = (PurpleBuddy *)bnode;
-						if (b->account == gc->account) {
-							if (aim_ssi_itemlist_exists(od->ssi.local, b->name)) {
+						bname = purple_buddy_get_name(b);
+						if (purple_buddy_get_account(b) == account) {
+							if (aim_ssi_itemlist_exists(od->ssi.local, bname)) {
 								/* If the buddy is an ICQ user then load his nickname */
 								const char *servernick = purple_blist_node_get_string((PurpleBlistNode*)b, "servernick");
 								char *alias;
+								const char *balias;
 								if (servernick)
-									serv_got_alias(gc, b->name, servernick);
+									serv_got_alias(gc, bname, servernick);
 
 								/* Store local alias on server */
-								alias = aim_ssi_getalias(od->ssi.local, g->name, b->name);
-								if (!alias && b->alias && strlen(b->alias))
-									aim_ssi_aliasbuddy(od, g->name, b->name, b->alias);
+								alias = aim_ssi_getalias(od->ssi.local, gname, bname);
+								balias = purple_buddy_get_local_buddy_alias(b);
+								if (!alias && balias && *balias)
+									aim_ssi_aliasbuddy(od, gname, bname, balias);
 								g_free(alias);
 							} else {
 								purple_debug_info("oscar",
-										"ssi: removing buddy %s from local list\n", b->name);
+										"ssi: removing buddy %s from local list\n", bname);
 								/* We can't actually remove now because it will screw up our looping */
 								cur = g_slist_prepend(cur, b);
 							}
@@ -5126,15 +5149,15 @@
 					} else
 						alias_utf8 = NULL;
 
-					b = purple_find_buddy_in_group(gc->account, curitem->name, g);
+					b = purple_find_buddy_in_group(account, curitem->name, g);
 					if (b) {
 						/* Get server stored alias */
 						purple_blist_alias_buddy(b, alias_utf8);
 					} else {
-						b = purple_buddy_new(gc->account, curitem->name, alias_utf8);
+						b = purple_buddy_new(account, curitem->name, alias_utf8);
 
 						purple_debug_info("oscar",
-								   "ssi: adding buddy %s to group %s to local list\n", curitem->name, g->name);
+								   "ssi: adding buddy %s to group %s to local list\n", curitem->name, gname);
 						purple_blist_add_buddy(b, NULL, g, NULL);
 					}
 					if (!aim_sncmp(curitem->name, account->username)) {
@@ -5147,7 +5170,7 @@
 					}
 
 					/* Mobile users should always be online */
-					if (b->name[0] == '+') {
+					if (curitem->name[0] == '+') {
 						purple_prpl_got_user_status(account,
 								purple_buddy_get_name(b),
 								OSCAR_STATUS_ID_AVAILABLE, NULL);
@@ -5361,13 +5384,11 @@
 		purple_blist_add_buddy(b, NULL, g, NULL);
 
 		/* Mobile users should always be online */
-		if (b->name[0] == '+') {
+		if (name[0] == '+') {
 			purple_prpl_got_user_status(account,
-					purple_buddy_get_name(b),
-					OSCAR_STATUS_ID_AVAILABLE, NULL);
+					name, OSCAR_STATUS_ID_AVAILABLE, NULL);
 			purple_prpl_got_user_status(account,
-					purple_buddy_get_name(b),
-					OSCAR_STATUS_ID_MOBILE, NULL);
+					name, OSCAR_STATUS_ID_MOBILE, NULL);
 		}
 
 	}
@@ -5699,7 +5720,8 @@
 
 const char *oscar_list_icon_icq(PurpleAccount *a, PurpleBuddy *b)
 {
-	if ((b == NULL) || (b->name == NULL) || aim_snvalid_sms(b->name))
+	const char *name = b ? purple_buddy_get_name(b) : NULL;
+	if ((b == NULL) || (name == NULL) || aim_snvalid_sms(name))
 	{
 		if (a == NULL || aim_snvalid_icq(purple_account_get_username(a)))
 			return "icq";
@@ -5707,14 +5729,15 @@
 			return "aim";
 	}
 
-	if (aim_snvalid_icq(b->name))
+	if (aim_snvalid_icq(name))
 		return "icq";
 	return "aim";
 }
 
 const char *oscar_list_icon_aim(PurpleAccount *a, PurpleBuddy *b)
 {
-	if ((b == NULL) || (b->name == NULL) || aim_snvalid_sms(b->name))
+	const char *name = b ? purple_buddy_get_name(b) : NULL;
+	if ((b == NULL) || (name == NULL) || aim_snvalid_sms(name))
 	{
 		if (a != NULL && aim_snvalid_icq(purple_account_get_username(a)))
 			return "icq";
@@ -5722,7 +5745,7 @@
 			return "aim";
 	}
 
-	if (aim_snvalid_icq(b->name))
+	if (aim_snvalid_icq(name))
 		return "icq";
 	return "aim";
 }
@@ -5736,14 +5759,16 @@
 	PurpleStatus *status;
 	const char *status_id;
 	aim_userinfo_t *userinfo = NULL;
-
-	account = b->account;
+	const char *name;
+
+	account = purple_buddy_get_account(b);
+	name = purple_buddy_get_name(b);
 	if (account != NULL)
-		gc = account->gc;
+		gc = purple_account_get_connection(account);
 	if (gc != NULL)
 		od = gc->proto_data;
 	if (od != NULL)
-		userinfo = aim_locate_finduserinfo(od, b->name);
+		userinfo = aim_locate_finduserinfo(od, name);
 
 	presence = purple_buddy_get_presence(b);
 	status = purple_presence_get_active_status(presence);
@@ -5751,9 +5776,9 @@
 
 	if (purple_presence_is_online(presence) == FALSE) {
 		char *gname;
-		if ((b->name) && (od) && (od->ssi.received_data) &&
-			(gname = aim_ssi_itemlist_findparentname(od->ssi.local, b->name)) &&
-			(aim_ssi_waitingforauth(od->ssi.local, gname, b->name))) {
+		if ((name) && (od) && (od->ssi.received_data) &&
+			(gname = aim_ssi_itemlist_findparentname(od->ssi.local, name)) &&
+			(aim_ssi_waitingforauth(od->ssi.local, gname, name))) {
 			return "not-authorized";
 		}
 	}
@@ -5776,15 +5801,17 @@
 void oscar_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
 {
 	PurpleConnection *gc;
+	PurpleAccount *account;
 	OscarData *od;
 	aim_userinfo_t *userinfo;
 
 	if (!PURPLE_BUDDY_IS_ONLINE(b))
 		return;
 
-	gc = b->account->gc;
+	account = purple_buddy_get_account(b);
+	gc = purple_account_get_connection(account);
 	od = gc->proto_data;
-	userinfo = aim_locate_finduserinfo(od, b->name);
+	userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
 
 	oscar_user_info_append_status(gc, user_info, b, userinfo, /* strip_html_tags */ TRUE);
 
@@ -5812,8 +5839,9 @@
 
 	if ((od != NULL) && !purple_presence_is_online(presence))
 	{
-		char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, b->name);
-		if (aim_ssi_waitingforauth(od->ssi.local, gname, b->name))
+		const char *name = purple_buddy_get_name(b);
+		char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, name);
+		if (aim_ssi_waitingforauth(od->ssi.local, gname, name))
 			ret = g_strdup(_("Not Authorized"));
 		else
 			ret = g_strdup(_("Offline"));
@@ -6058,7 +6086,7 @@
 		return;
 	}
 
-	aim_ssi_editcomment(od, g->name, data->name, text);
+	aim_ssi_editcomment(od, purple_group_get_name(g), data->name, text);
 
 	if (!aim_sncmp(data->name, gc->account->username))
 		purple_check_comment(od, text);
@@ -6076,11 +6104,15 @@
 	char *comment;
 	gchar *comment_utf8;
 	gchar *title;
+	PurpleAccount *account;
+	const char *name;
 
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
+	name = purple_buddy_get_name(buddy);
+	account = purple_buddy_get_account(buddy);
+	gc = purple_account_get_connection(account);
 	od = gc->proto_data;
 
 	if (!(g = purple_buddy_get_group(buddy)))
@@ -6088,11 +6120,11 @@
 
 	data = g_new(struct name_data, 1);
 
-	comment = aim_ssi_getcomment(od->ssi.local, g->name, buddy->name);
-	comment_utf8 = comment ? oscar_utf8_try_convert(gc->account, comment) : NULL;
+	comment = aim_ssi_getcomment(od->ssi.local, purple_group_get_name(g), name);
+	comment_utf8 = comment ? oscar_utf8_try_convert(account, comment) : NULL;
 
 	data->gc = gc;
-	data->name = g_strdup(purple_buddy_get_name(buddy));
+	data->name = g_strdup(name);
 	data->nick = g_strdup(purple_buddy_get_alias_only(buddy));
 
 	title = g_strdup_printf(_("Buddy Comment for %s"), data->name);
@@ -6100,7 +6132,7 @@
 					   comment_utf8, TRUE, FALSE, NULL,
 					   _("_OK"), G_CALLBACK(oscar_ssi_editcomment),
 					   _("_Cancel"), G_CALLBACK(oscar_free_name_data),
-					   purple_connection_get_account(gc), data->name, NULL,
+					   account, data->name, NULL,
 					   data);
 	g_free(title);
 
@@ -6132,26 +6164,28 @@
 	PurpleConnection *gc;
 	gchar *buf;
 	struct oscar_ask_directim_data *data;
+	PurpleAccount *account;
 
 	node = object;
 
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *)node;
-	gc = purple_account_get_connection(buddy->account);
+	account = purple_buddy_get_account(buddy);
+	gc = purple_account_get_connection(account);
 
 	data = g_new0(struct oscar_ask_directim_data, 1);
-	data->who = g_strdup(buddy->name);
+	data->who = g_strdup(purple_buddy_get_name(buddy));
 	data->od = gc->proto_data;
 	buf = g_strdup_printf(_("You have selected to open a Direct IM connection with %s."),
-			buddy->name);
+			data->who);
 
 	purple_request_action(gc, NULL, buf,
 			_("Because this reveals your IP address, it "
 			  "may be considered a security risk.  Do you "
 			  "wish to continue?"),
 			0, /* Default action is "connect" */
-			purple_connection_get_account(gc), data->who, NULL,
+			account, data->who, NULL,
 			data, 2,
 			_("C_onnect"), G_CALLBACK(oscar_ask_directim_yes_cb),
 			_("_Cancel"), G_CALLBACK(oscar_ask_directim_no_cb));
@@ -6167,7 +6201,7 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *)node;
-	gc = purple_account_get_connection(buddy->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 
 	aim_locate_getinfoshort(gc->proto_data, purple_buddy_get_name(buddy), 0x00000003);
 }
@@ -6180,13 +6214,16 @@
 	GList *menu;
 	PurpleMenuAction *act;
 	aim_userinfo_t *userinfo;
-
-	gc = purple_account_get_connection(buddy->account);
+	PurpleAccount *account;
+	const char *bname = purple_buddy_get_name(buddy);
+
+	account = purple_buddy_get_account(buddy);
+	gc = purple_account_get_connection(account);
 	od = gc->proto_data;
-	userinfo = aim_locate_finduserinfo(od, buddy->name);
+	userinfo = aim_locate_finduserinfo(od, bname);
 	menu = NULL;
 
-	if (od->icq && aim_snvalid_icq(purple_buddy_get_name(buddy)))
+	if (od->icq && aim_snvalid_icq(bname))
 	{
 		act = purple_menu_action_new(_("Get AIM Info"),
 								   PURPLE_CALLBACK(oscar_get_aim_info_cb),
@@ -6210,7 +6247,7 @@
 #endif
 
 	if (userinfo &&
-		aim_sncmp(purple_account_get_username(buddy->account), buddy->name) &&
+		aim_sncmp(purple_account_get_username(account), bname) &&
 		PURPLE_BUDDY_IS_ONLINE(buddy))
 	{
 		if (userinfo->capabilities & OSCAR_CAPABILITY_DIRECTIM)
@@ -6234,8 +6271,8 @@
 	if (od->ssi.received_data)
 	{
 		char *gname;
-		gname = aim_ssi_itemlist_findparentname(od->ssi.local, buddy->name);
-		if (gname && aim_ssi_waitingforauth(od->ssi.local, gname, buddy->name))
+		gname = aim_ssi_itemlist_findparentname(od->ssi.local, bname);
+		if (gname && aim_ssi_waitingforauth(od->ssi.local, gname, bname))
 		{
 			act = purple_menu_action_new(_("Re-request Authorization"),
 			                           PURPLE_CALLBACK(purple_auth_sendrequest_menu),
@@ -6392,26 +6429,37 @@
 	OscarData *od = gc->proto_data;
 	gchar *nombre, *text, *tmp;
 	PurpleBlistNode *gnode, *cnode, *bnode;
+	PurpleAccount *account;
 	int num=0;
 
 	text = g_strdup("");
-
-	for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
+	account = purple_connection_get_account(gc);
+
+	for (gnode = purple_blist_get_root(); gnode;
+			gnode = purple_blist_node_get_sibling_next(gnode)) {
 		PurpleGroup *group = (PurpleGroup *)gnode;
+		const char *gname;
 		if(!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for (cnode = gnode->child; cnode; cnode = cnode->next) {
+		gname = purple_group_get_name(group);
+		for (cnode = purple_blist_node_get_first_child(gnode);
+				cnode;
+				cnode = purple_blist_node_get_sibling_next(cnode)) {
 			if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			for (bnode = cnode->child; bnode; bnode = bnode->next) {
+			for (bnode = purple_blist_node_get_first_child(cnode);
+					bnode;
+					bnode = purple_blist_node_get_sibling_next(bnode)) {
 				PurpleBuddy *buddy = (PurpleBuddy *)bnode;
+				const char *bname;
 				if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
-				if (buddy->account == gc->account && aim_ssi_waitingforauth(od->ssi.local, group->name, buddy->name)) {
+				bname = purple_buddy_get_name(buddy);
+				if (purple_buddy_get_account(buddy) == account && aim_ssi_waitingforauth(od->ssi.local, gname, bname)) {
 					if (purple_buddy_get_alias_only(buddy))
-						nombre = g_strdup_printf(" %s (%s)", buddy->name, purple_buddy_get_alias_only(buddy));
+						nombre = g_strdup_printf(" %s (%s)", bname, purple_buddy_get_alias_only(buddy));
 					else
-						nombre = g_strdup_printf(" %s", buddy->name);
+						nombre = g_strdup_printf(" %s", bname);
 					tmp = g_strdup_printf("%s%s<br>", text, nombre);
 					g_free(text);
 					text = tmp;
--- a/libpurple/protocols/qq/buddy_info.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/qq/buddy_info.c	Thu Nov 27 21:15:43 2008 +0000
@@ -608,7 +608,7 @@
 	gchar *alias_utf8;
 	PurpleAccount *account = purple_connection_get_account(gc);
 
-	qd = (qq_data *) gc->proto_data;
+	qd = (qq_data *)purple_connection_get_protocol_data(gc);
 
 	uid = strtol(segments[QQ_INFO_UID], NULL, 10);
 	who = uid_to_purple_name(uid);
@@ -627,15 +627,16 @@
 		buddy = purple_find_buddy(gc->account, who);
 	}
 
-	if (buddy == NULL || buddy->proto_data == NULL) {
+	/* if the buddy is null, the api will catch it and return null here */
+	bd = purple_buddy_get_protocol_data(buddy);
+
+	if (buddy == NULL || bd) {
 		g_free(who);
 		g_free(alias_utf8);
 		return;
 	}
 
 	/* update buddy list (including myself, if myself is the buddy) */
-	bd = (qq_buddy_data *)buddy->proto_data;
-
 	bd->age = strtol(segments[QQ_INFO_AGE], NULL, 10);
 	bd->gender = strtol(segments[QQ_INFO_GENDER], NULL, 10);
 	bd->face = strtol(segments[QQ_INFO_FACE], NULL, 10);
@@ -764,8 +765,7 @@
 	for (it = buddies; it; it = it->next) {
 		buddy = it->data;
 		if (buddy == NULL) continue;
-		if (buddy->proto_data == NULL) continue;
-		bd = (qq_buddy_data *)buddy->proto_data;
+		if ((bd = purple_buddy_get_protocol_data(buddy)) == NULL) continue;
 		if (bd->uid == 0) continue;	/* keep me as end of packet*/
 		if (bd->uid == qd->uid) continue;
 		bytes += qq_put32(buf + bytes, bd->uid);
--- a/libpurple/protocols/qq/buddy_list.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/qq/buddy_list.c	Thu Nov 27 21:15:43 2008 +0000
@@ -326,7 +326,7 @@
 #endif
 
 		buddy = qq_buddy_find_or_new(gc, bd.uid);
-		if (buddy == NULL || buddy->proto_data == NULL) {
+		if (buddy == NULL || purple_buddy_get_protocol_data(buddy) == NULL) {
 			g_free(bd.nickname);
 			continue;
 		}
@@ -334,7 +334,7 @@
 		bd.last_update = time(NULL);
 		qq_update_buddy_status(gc, bd.uid, bd.status, bd.comm_flag);
 
-		g_memmove(buddy->proto_data, &bd, sizeof(qq_buddy_data));
+		g_memmove(purple_buddy_get_protocol_data(buddy), &bd, sizeof(qq_buddy_data));
 		/* nickname has been copy to buddy_data do not free
 		   g_free(bd.nickname);
 		*/
@@ -641,9 +641,10 @@
 	for (it = buddies; it; it = it->next) {
 		buddy = it->data;
 		if (buddy == NULL) continue;
-		if (buddy->proto_data == NULL) continue;
 
-		bd = (qq_buddy_data *)buddy->proto_data;
+		bd = purple_buddy_get_protocol_data(buddy);
+		if (bd == NULL) continue;
+
 		if (bd->uid == 0) continue;
 		if (bd->uid == qd->uid) continue;	/* my status is always online in my buddy list */
 		if (tm_limit < bd->last_update) continue;
@@ -663,16 +664,20 @@
 	GSList *buddies, *it;
 	gint count = 0;
 
-	qd = (qq_data *) (gc->proto_data);
+	qd = (qq_data *)purple_connection_get_protocol_data(gc);
 
 	buddies = purple_find_buddies(purple_connection_get_account(gc), NULL);
 	for (it = buddies; it; it = it->next) {
+		qq_buddy_data *qbd = NULL;
+
 		buddy = it->data;
 		if (buddy == NULL) continue;
-		if (buddy->proto_data == NULL) continue;
 
-		qq_buddy_data_free(buddy->proto_data);
-		buddy->proto_data = NULL;
+		qbd = purple_buddy_get_protocol_data(buddy);
+		if (qbd == NULL) continue;
+
+		qq_buddy_data_free(qbd);
+		purple_buddy_set_protocol_data(buddy, NULL);
 
 		count++;
 	}
--- a/libpurple/protocols/qq/buddy_opt.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/qq/buddy_opt.c	Thu Nov 27 21:15:43 2008 +0000
@@ -101,6 +101,7 @@
 {
 	gchar *who;
 	PurpleBuddy *buddy;
+	qq_buddy_data *bd;
 
 	g_return_val_if_fail(gc != NULL, NULL);
 
@@ -113,11 +114,12 @@
 		purple_debug_error("QQ", "Can not find purple buddy of %d\n", uid);
 		return NULL;
 	}
-	if (buddy->proto_data == NULL) {
+	
+	if ((bd = purple_buddy_get_protocol_data(buddy)) == NULL) {
 		purple_debug_error("QQ", "Can not find buddy data of %d\n", uid);
 		return NULL;
 	}
-	return (qq_buddy_data *)buddy->proto_data;
+	return bd;
 }
 
 void qq_buddy_data_free(qq_buddy_data *bd)
@@ -150,7 +152,7 @@
 
 	purple_debug_info("QQ", "Add new purple buddy: [%s]\n", who);
 	buddy = purple_buddy_new(gc->account, who, NULL);	/* alias is NULL */
-	buddy->proto_data = NULL;
+	purple_buddy_set_protocol_data(buddy, NULL);
 
 	g_free(who);
 
@@ -163,11 +165,14 @@
 
 static void qq_buddy_free(PurpleBuddy *buddy)
 {
+	qq_buddy_data *bd;
+
 	g_return_if_fail(buddy);
-	if (buddy->proto_data)	{
-		qq_buddy_data_free(buddy->proto_data);
+
+	if ((bd = purple_buddy_get_protocol_data(buddy)) != NULL) {
+		qq_buddy_data_free(bd);
 	}
-	buddy->proto_data = NULL;
+	purple_buddy_set_protocol_data(buddy, NULL);
 	purple_blist_remove_buddy(buddy);
 }
 
@@ -187,6 +192,7 @@
 PurpleBuddy *qq_buddy_find_or_new(PurpleConnection *gc, guint32 uid)
 {
 	PurpleBuddy *buddy;
+	qq_buddy_data *bd;
 
 	g_return_val_if_fail(gc->account != NULL && uid != 0, NULL);
 
@@ -198,11 +204,12 @@
 		}
 	}
 
-	if (buddy->proto_data != NULL) {
+	if (purple_buddy_get_protocol_data(buddy) != NULL) {
 		return buddy;
 	}
 
-	buddy->proto_data = qq_buddy_data_new(uid);
+	bd = qq_buddy_data_new(uid);
+	purple_buddy_set_protocol_data(buddy, bd);
 	return buddy;
 }
 
@@ -691,7 +698,7 @@
 	if (!qd->is_login)
 		return;		/* IMPORTANT ! */
 
-	uid = purple_name_to_uid(buddy->name);
+	uid = purple_name_to_uid(purple_buddy_get_name(buddy));
 	if (uid > 0) {
 		if (qd->client_version > 2005) {
 			request_add_buddy_no_auth_ex(gc, uid);
@@ -782,6 +789,7 @@
 	gchar **segments;
 	gchar *dest_uid, *reply;
 	PurpleBuddy *buddy;
+	qq_buddy_data *bd;
 
 	g_return_if_fail(data != NULL && data_len != 0);
 	g_return_if_fail(uid != 0);
@@ -826,10 +834,10 @@
 	if (buddy == NULL) {
 		buddy = qq_buddy_new(gc, uid);
 	}
-	if (buddy != NULL && buddy->proto_data != NULL) {
+	if (buddy != NULL && (bd = purple_buddy_get_protocol_data(buddy)) != NULL) {
 		/* Not authorized now, free buddy data */
-		qq_buddy_data_free(buddy->proto_data);
-		buddy->proto_data = NULL;
+		qq_buddy_data_free(bd);
+		purple_buddy_set_protocol_data(buddy, NULL);
 	}
 
 	add_buddy_authorize_input(gc, uid, NULL, 0);
@@ -905,6 +913,7 @@
 void qq_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
 {
 	qq_data *qd;
+	qq_buddy_data *bd;
 	guint32 uid;
 
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
@@ -914,7 +923,7 @@
 	if (!qd->is_login)
 		return;
 
-	uid = purple_name_to_uid(buddy->name);
+	uid = purple_name_to_uid(purple_buddy_get_name(buddy));
 	if (uid > 0 && uid != qd->uid) {
 		if (qd->client_version > 2005) {
 			qq_request_auth_code(gc, QQ_AUTH_INFO_BUDDY, QQ_AUTH_INFO_REMOVE_BUDDY, uid);
@@ -924,11 +933,11 @@
 		}
 	}
 
-	if (buddy->proto_data) {
-		qq_buddy_data_free(buddy->proto_data);
-		buddy->proto_data = NULL;
+	if ((bd = purple_buddy_get_protocol_data(buddy)) != NULL) {
+		qq_buddy_data_free(bd);
+		purple_buddy_set_protocol_data(buddy, NULL);
 	} else {
-		purple_debug_warning("QQ", "Empty buddy data of %s\n", buddy->name);
+		purple_debug_warning("QQ", "Empty buddy data of %s\n", purple_buddy_get_name(buddy));
 	}
 
 	/* Do not call purple_blist_remove_buddy,
@@ -1216,6 +1225,7 @@
 	gint bytes;
 	gchar **segments;
 	gchar *primary, *secondary;
+	qq_buddy_data *bd;
 
 	g_return_if_fail(from != NULL && to != NULL);
 
@@ -1255,10 +1265,10 @@
 	g_return_if_fail(uid != 0);
 
 	buddy = qq_buddy_find(gc, uid);
-	if (buddy != NULL && buddy->proto_data != NULL) {
+	if (buddy != NULL && (bd = purple_buddy_get_protocol_data(buddy)) != NULL) {
 		/* Not authorized now, free buddy data */
-		qq_buddy_data_free(buddy->proto_data);
-		buddy->proto_data = NULL;
+		qq_buddy_data_free(bd);
+		purple_buddy_set_protocol_data(buddy, NULL);
 	}
 }
 
--- a/libpurple/protocols/qq/group_internal.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/qq/group_internal.c	Thu Nov 27 21:15:43 2008 +0000
@@ -102,16 +102,21 @@
 
 void qq_room_update_chat_info(PurpleChat *chat, qq_room_data *rmd)
 {
+	GHashTable *components;
+
 	if (rmd->title_utf8 != NULL && strlen(rmd->title_utf8) > 0) {
 		purple_blist_alias_chat(chat, rmd->title_utf8);
 	}
-	g_hash_table_replace(chat->components,
+
+	components = purple_chat_get_components(chat);
+
+	g_hash_table_replace(components,
 		     g_strdup(QQ_ROOM_KEY_INTERNAL_ID),
 		     g_strdup_printf("%d", rmd->id));
-	g_hash_table_replace(chat->components,
+	g_hash_table_replace(components,
 		     g_strdup(QQ_ROOM_KEY_EXTERNAL_ID),
 		     g_strdup_printf("%d", rmd->ext_id));
-	g_hash_table_replace(chat->components,
+	g_hash_table_replace(components,
 		     g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(rmd->title_utf8));
 }
 
@@ -249,11 +254,13 @@
 		member->uid = member_uid;
 		buddy = purple_find_buddy(purple_connection_get_account(gc), uid_to_purple_name(member_uid));
 		if (buddy != NULL) {
-			bd = (qq_buddy_data *) buddy->proto_data;
+			const gchar *alias = NULL;
+
+			bd = purple_buddy_get_protocol_data(buddy);
 			if (bd != NULL && bd->nickname != NULL)
 				member->nickname = g_strdup(bd->nickname);
-			else if (buddy->alias != NULL)
-				member->nickname = g_strdup(buddy->alias);
+			else if ((alias = purple_buddy_get_alias(buddy)) != NULL)
+				member->nickname = g_strdup(alias);
 		}
 		rmd->members = g_list_append(rmd->members, member);
 	}
@@ -382,16 +389,19 @@
 	}
 
 	count = 0;
-	for (node = ((PurpleBlistNode *) purple_group)->child; node != NULL; node = node->next) {
+	for (node = purple_blist_node_get_first_child((PurpleBlistNode *)purple_group);
+	     node != NULL;
+		 node = purple_blist_node_get_sibling_next(node))
+	{
 		if ( !PURPLE_BLIST_NODE_IS_CHAT(node)) {
 			continue;
 		}
 		/* got one */
 		chat = (PurpleChat *) node;
-		if (account != chat->account)	/* not qq account*/
+		if (account != purple_chat_get_account(chat))	/* not qq account*/
 			continue;
 
-		rmd = room_data_new_by_hashtable(gc, chat->components);
+		rmd = room_data_new_by_hashtable(gc, purple_chat_get_components(chat));
 		qd->groups = g_list_append(qd->groups, rmd);
 		count++;
 	}
--- a/libpurple/protocols/qq/im.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/qq/im.c	Thu Nov 27 21:15:43 2008 +0000
@@ -246,7 +246,7 @@
 		/* create no-auth buddy */
 		b = qq_buddy_new(gc, im_header->uid_from);
 	}
-	bd = (b == NULL) ? NULL : (qq_buddy_data *) b->proto_data;
+	bd = (b == NULL) ? NULL : purple_buddy_get_protocol_data(b);
 	if (bd != NULL) {
 		bd->client_tag = im_header->version_from;
 	}
@@ -359,7 +359,7 @@
 		/* create no-auth buddy */
 		b = qq_buddy_new(gc, im_header->uid_from);
 	}
-	bd = (b == NULL) ? NULL : (qq_buddy_data *) b->proto_data;
+	bd = (b == NULL) ? NULL : purple_buddy_get_protocol_data(b);
 	if (bd != NULL) {
 		bd->client_tag = im_header->version_from;
 	}
--- a/libpurple/protocols/qq/qq.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/qq/qq.c	Thu Nov 27 21:15:43 2008 +0000
@@ -245,7 +245,7 @@
 	qq_buddy_data *bd;
 	GString *status;
 
-	bd = (qq_buddy_data *) b->proto_data;
+	bd = purple_buddy_get_protocol_data(b);
 	if (bd == NULL)
 		return NULL;
 
@@ -268,9 +268,9 @@
 	case QQ_BUDDY_ONLINE_INVISIBLE:
 		g_string_append(status, _("Invisible"));
 		break;
-	case QQ_BUDDY_ONLINE_BUSY:
-		g_string_append(status, _("Busy"));
-		break;
+	case QQ_BUDDY_ONLINE_BUSY:
+		g_string_append(status, _("Busy"));
+		break;
 	default:
 		g_string_printf(status, _("Unknown-%d"), bd->status);
 	}
@@ -288,7 +288,7 @@
 
 	g_return_if_fail(b != NULL);
 
-	bd = (qq_buddy_data *) b->proto_data;
+	bd = purple_buddy_get_protocol_data(b);
 	if (bd == NULL)
 		return;
 
@@ -379,11 +379,12 @@
 	qq_data *qd;
 	qq_buddy_data *buddy;
 
-	if (!b || !(account = b->account) ||
-		!(gc = purple_account_get_connection(account)) || !(qd = gc->proto_data))
+	if (!b || !(account = purple_buddy_get_account(b)) ||
+		!(gc = purple_account_get_connection(account)) ||
+		!(qd = purple_connection_get_protocol_data(gc)))
 		return NULL;
 
-	buddy = (qq_buddy_data *)b->proto_data;
+	buddy = purple_buddy_get_protocol_data(b);
 	if (!buddy) {
 		return "not-authorized";
 	}
@@ -416,9 +417,9 @@
 			"invisible", _("Invisible"), FALSE, TRUE, FALSE);
 	types = g_list_append(types, status);
 
-	status = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE,
-			"busy", _("Busy"), TRUE, TRUE, FALSE);
-	types = g_list_append(types, status);
+	status = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE,
+			"busy", _("Busy"), TRUE, TRUE, FALSE);
+	types = g_list_append(types, status);
 
 	status = purple_status_type_new_full(PURPLE_STATUS_OFFLINE,
 			"offline", _("Offline"), FALSE, TRUE, FALSE);
@@ -795,8 +796,9 @@
 static void action_chat_quit(PurpleBlistNode * node)
 {
 	PurpleChat *chat = (PurpleChat *)node;
-	PurpleConnection *gc = purple_account_get_connection(chat->account);
-	GHashTable *components = chat -> components;
+	PurpleAccount *account = purple_chat_get_account(chat);
+	PurpleConnection *gc = purple_account_get_connection(account);
+	GHashTable *components = purple_chat_get_components(chat);
 	gchar *num_str;
 	guint32 room_id;
 
@@ -814,8 +816,9 @@
 static void action_chat_get_info(PurpleBlistNode * node)
 {
 	PurpleChat *chat = (PurpleChat *)node;
-	PurpleConnection *gc = purple_account_get_connection(chat->account);
-	GHashTable *components = chat -> components;
+	PurpleAccount *account = purple_chat_get_account(chat);
+	PurpleConnection *gc = purple_account_get_connection(account);
+	GHashTable *components = purple_chat_get_components(chat);
 	gchar *num_str;
 	guint32 room_id;
 
@@ -902,7 +905,7 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 
 	qq_add_buddy(gc, buddy, NULL);
 }
@@ -915,7 +918,7 @@
 	PurpleConnection *gc = purple_account_get_connection(buddy->account);
 	qq_data *qd = gc->proto_data;
 	*/
-	qq_buddy_data *bd = (qq_buddy_data *)buddy->proto_data;
+	qq_buddy_data *bd = purple_buddy_get_protocol_data(buddy);
 
 	if (bd == NULL) {
 		act = purple_menu_action_new(_("Add Buddy"),
--- a/libpurple/protocols/qq/qq_network.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/qq/qq_network.c	Thu Nov 27 21:15:43 2008 +0000
@@ -126,8 +126,8 @@
 	/* get new server */
 	index  = rand() % count;
 	it = g_list_nth(qd->servers, index);
-    qd->curr_server = it->data;		/* do not free server_name */
-    if (qd->curr_server == NULL || strlen(qd->curr_server) <= 0 ) {
+	qd->curr_server = it->data;		/* do not free server_name */
+	if (qd->curr_server == NULL || strlen(qd->curr_server) <= 0 ) {
 		purple_debug_info("QQ", "Server name at %d is empty\n", index);
 		return FALSE;
 	}
--- a/libpurple/protocols/qq/send_file.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/qq/send_file.c	Thu Nov 27 21:15:43 2008 +0000
@@ -804,7 +804,7 @@
 			    "Received a FACE ip detect from %d, so he/she must be online :)\n", sender_uid);
 
 		b = purple_find_buddy(gc->account, sender_name);
-		bd = (b == NULL) ? NULL : (qq_buddy_data *) b->proto_data;
+		bd = (b == NULL) ? NULL : purple_buddy_get_protocol_data(b);
 		if (bd) {
 			if(0 != info->remote_real_ip) {
 				g_memmove(&(bd->ip), &info->remote_real_ip, sizeof(bd->ip));
--- a/libpurple/protocols/sametime/sametime.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/sametime/sametime.c	Thu Nov 27 21:15:43 2008 +0000
@@ -658,7 +658,6 @@
   */
 
   PurpleAccount *acct;
-  PurpleBuddyList *blist;
   PurpleBlistNode *gn, *cn, *bn;
   PurpleGroup *grp;
   PurpleBuddy *bdy;
@@ -669,10 +668,8 @@
   acct = purple_connection_get_account(gc);
   g_return_if_fail(acct != NULL);
 
-  blist = purple_get_blist();
-  g_return_if_fail(blist != NULL);
-
-  for(gn = blist->root; gn; gn = gn->next) {
+  for(gn = purple_blist_get_root(); gn;
+		  gn = purple_blist_node_get_sibling_next(gn)) {
     const char *owner;
     const char *gname;
     enum mwSametimeGroupType gtype;
@@ -697,13 +694,13 @@
     /* the group's actual name may be different from the purple group's
        name. Find whichever is there */
     gname = purple_blist_node_get_string(gn, GROUP_KEY_NAME);
-    if(! gname) gname = grp->name;
+    if(! gname) gname = purple_group_get_name(grp);
 
     /* we save this, but never actually honor it */
     gopen = ! purple_blist_node_get_bool(gn, GROUP_KEY_COLLAPSED);
 
     stg = mwSametimeGroup_new(stlist, gtype, gname);
-    mwSametimeGroup_setAlias(stg, grp->name);
+    mwSametimeGroup_setAlias(stg, purple_group_get_name(grp));
     mwSametimeGroup_setOpen(stg, gopen);
 
     /* don't attempt to put buddies in a dynamic group, it breaks
@@ -711,27 +708,31 @@
     if(gtype == mwSametimeGroup_DYNAMIC)
       continue;
 
-    for(cn = gn->child; cn; cn = cn->next) {
+    for(cn = purple_blist_node_get_first_child(gn);
+			cn;
+			cn = purple_blist_node_get_sibling_next(cn)) {
       if(! PURPLE_BLIST_NODE_IS_CONTACT(cn)) continue;
 
-      for(bn = cn->child; bn; bn = bn->next) {
+      for(bn = purple_blist_node_get_first_child(cn);
+			  bn;
+			  bn = purple_blist_node_get_sibling_next(bn)) {
 	if(! PURPLE_BLIST_NODE_IS_BUDDY(bn)) continue;
 	if(! PURPLE_BLIST_NODE_SHOULD_SAVE(bn)) continue;
 
 	bdy = (PurpleBuddy *) bn;
 
-	if(bdy->account == acct) {
+	if(purple_buddy_get_account(bdy) == acct) {
 	  struct mwSametimeUser *stu;
 	  enum mwSametimeUserType utype;
 
-	  idb.user = bdy->name;
+	  idb.user = (char *)purple_buddy_get_name(bdy);
 
 	  utype = purple_blist_node_get_int(bn, BUDDY_KEY_TYPE);
 	  if(! utype) utype = mwSametimeUser_NORMAL;
 
 	  stu = mwSametimeUser_new(stg, utype, &idb);
-	  mwSametimeUser_setShortName(stu, bdy->server_alias);
-	  mwSametimeUser_setAlias(stu, bdy->alias);
+	  mwSametimeUser_setShortName(stu, purple_buddy_get_server_alias(bdy));
+	  mwSametimeUser_setAlias(stu, purple_buddy_get_local_buddy_alias(bdy));
 	}
       }
     }
@@ -811,7 +812,7 @@
 
 static gboolean buddy_is_external(PurpleBuddy *b) {
   g_return_val_if_fail(b != NULL, FALSE);
-  return purple_str_has_prefix(b->name, "@E ");
+  return purple_str_has_prefix(purple_buddy_get_name(b), "@E ");
 }
 
 
@@ -820,7 +821,7 @@
 static void buddy_add(struct mwPurplePluginData *pd,
 		      PurpleBuddy *buddy) {
 
-  struct mwAwareIdBlock idb = { mwAware_USER, (char *) buddy->name, NULL };
+  struct mwAwareIdBlock idb = { mwAware_USER, (char *) purple_buddy_get_name(buddy), NULL };
   struct mwAwareList *list;
 
   PurpleGroup *group;
@@ -885,7 +886,7 @@
   GList *add;
   
   n = purple_blist_node_get_string((PurpleBlistNode *) group, GROUP_KEY_NAME);
-  if(! n) n = group->name;
+  if(! n) n = purple_group_get_name(group);
 
   idb.user = (char *) n;
   add = g_list_prepend(NULL, &idb);
@@ -921,7 +922,8 @@
 	     NSTR(name), NSTR(alias));
 
   /* first attempt at finding the group, by the name key */
-  for(gn = blist->root; gn; gn = gn->next) {
+  for(gn = purple_blist_get_root(); gn;
+		  gn = purple_blist_node_get_sibling_next(gn)) {
     const char *n, *o;
     if(! PURPLE_BLIST_NODE_IS_GROUP(gn)) continue;
     n = purple_blist_node_get_string(gn, GROUP_KEY_NAME);
@@ -1001,23 +1003,27 @@
 
   g_return_if_fail(group != NULL);
 
-  DEBUG_INFO("clearing members from pruned group %s\n", NSTR(group->name));
+  DEBUG_INFO("clearing members from pruned group %s\n", NSTR(purple_group_get_name(group)));
 
   gc = purple_account_get_connection(acct);
   g_return_if_fail(gc != NULL);
 
   gn = (PurpleBlistNode *) group;
 
-  for(cn = gn->child; cn; cn = cn->next) {
+  for(cn = purple_blist_node_get_first_child(gn);
+		  cn;
+		  cn = purple_blist_node_get_sibling_next(cn)) {
     if(! PURPLE_BLIST_NODE_IS_CONTACT(cn)) continue;
 
-    for(bn = cn->child; bn; bn = bn->next) {
+    for(bn = purple_blist_node_get_first_child(cn);
+			bn;
+			bn = purple_blist_node_get_sibling_next(bn)) {
       PurpleBuddy *gb = (PurpleBuddy *) bn;
 
       if(! PURPLE_BLIST_NODE_IS_BUDDY(bn)) continue;
       
-      if(gb->account == acct) {
-	DEBUG_INFO("clearing %s from group\n", NSTR(gb->name));
+      if(purple_buddy_get_account(gb) == acct) {
+	DEBUG_INFO("clearing %s from group\n", NSTR(purple_buddy_get_name(gb)));
 	prune = g_list_prepend(prune, gb);
       }
     }
@@ -1054,7 +1060,7 @@
 
   g_return_if_fail(group != NULL);
 
-  DEBUG_INFO("pruning membership of group %s\n", NSTR(group->name));
+  DEBUG_INFO("pruning membership of group %s\n", NSTR(purple_group_get_name(group)));
 
   acct = purple_connection_get_account(gc);
   g_return_if_fail(acct != NULL);
@@ -1073,18 +1079,22 @@
 
   gn = (PurpleBlistNode *) group;
 
-  for(cn = gn->child; cn; cn = cn->next) {
+  for(cn = purple_blist_node_get_first_child(gn);
+		  cn;
+		  cn = purple_blist_node_get_sibling_next(cn)) {
     if(! PURPLE_BLIST_NODE_IS_CONTACT(cn)) continue;
 
-    for(bn = cn->child; bn; bn = bn->next) {
+    for(bn = purple_blist_node_get_first_child(cn);
+			bn;
+			bn = purple_blist_node_get_sibling_next(bn)) {
       PurpleBuddy *gb = (PurpleBuddy *) bn;
 
       if(! PURPLE_BLIST_NODE_IS_BUDDY(bn)) continue;
 
       /* if the account is correct and they're not in our table, mark
 	 them for pruning */
-      if(gb->account == acct && !g_hash_table_lookup(stusers, gb->name)) {
-	DEBUG_INFO("marking %s for pruning\n", NSTR(gb->name));
+      if(purple_buddy_get_account(gb) == acct && !g_hash_table_lookup(stusers, purple_buddy_get_name(gb))) {
+	DEBUG_INFO("marking %s for pruning\n", NSTR(purple_buddy_get_name(gb)));
 	prune = g_list_prepend(prune, gb);
       }
     }
@@ -1140,7 +1150,8 @@
   g_list_free(gtl);
 
   /* find all groups which should be pruned from the local list */
-  for(gn = blist->root; gn; gn = gn->next) {
+  for(gn = purple_blist_get_root(); gn;
+		  gn = purple_blist_node_get_sibling_next(gn)) {
     PurpleGroup *grp = (PurpleGroup *) gn;
     const char *gname, *owner;
     struct mwSametimeGroup *stgrp;
@@ -1159,12 +1170,12 @@
     /* we actually are synching by this key as opposed to the group
        title, which can be different things in the st list */
     gname = purple_blist_node_get_string(gn, GROUP_KEY_NAME);
-    if(! gname) gname = grp->name;
+    if(! gname) gname = purple_group_get_name(grp);
 
     stgrp = g_hash_table_lookup(stgroups, gname);
     if(! stgrp) {
       /* remove the whole group */
-      DEBUG_INFO("marking group %s for pruning\n", grp->name);
+      DEBUG_INFO("marking group %s for pruning\n", purple_group_get_name(grp));
       g_prune = g_list_prepend(g_prune, grp);
 
     } else {
@@ -1279,6 +1290,7 @@
 
   GString *str;
   char *tmp;
+  const char *gname;
 
   g_return_if_fail(pd != NULL);
 
@@ -1290,11 +1302,12 @@
   str = g_string_new(NULL);
 
   tmp = (char *) purple_blist_node_get_string(node, GROUP_KEY_NAME);
-
-  g_string_append_printf(str, _("<b>Group Title:</b> %s<br>"), group->name);
+  gname = purple_group_get_name(group);
+
+  g_string_append_printf(str, _("<b>Group Title:</b> %s<br>"), gname);
   g_string_append_printf(str, _("<b>Notes Group ID:</b> %s<br>"), tmp);
 
-  tmp = g_strdup_printf(_("Info for Group %s"), group->name);
+  tmp = g_strdup_printf(_("Info for Group %s"), gname);
 
   purple_notify_formatted(gc, tmp, _("Notes Address Book Information"),
 			NULL, str->str, NULL, NULL);
@@ -1351,19 +1364,24 @@
   PurpleBlistNode *gnode, *cnode, *bnode;
   GList *add_buds = NULL;
 
-  for(gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
+  for(gnode = purple_blist_get_root(); gnode;
+		  gnode = purple_blist_node_get_sibling_next(gnode)) {
     if(! PURPLE_BLIST_NODE_IS_GROUP(gnode)) continue;
 
-    for(cnode = gnode->child; cnode; cnode = cnode->next) {
+    for(cnode = purple_blist_node_get_first_child(gnode);
+			cnode;
+			cnode = purple_blist_node_get_sibling_next(cnode)) {
       if(! PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 	continue;
-      for(bnode = cnode->child; bnode; bnode = bnode->next) {
+      for(bnode = purple_blist_node_get_first_child(cnode);
+			  bnode;
+			  bnode = purple_blist_node_get_sibling_next(bnode)) {
 	PurpleBuddy *b;
 	if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 	  continue;
-	
+
 	b = (PurpleBuddy *)bnode;
-	if(b->account == acct) {
+	if(purple_buddy_get_account(b) == acct) {
 	  add_buds = g_list_append(add_buds, b);
 	}
       }
@@ -1383,7 +1401,6 @@
   PurpleConnection *gc;
   PurpleAccount *acct;
   struct mwStorageUnit *unit;
-  PurpleBuddyList *blist;
   PurpleBlistNode *l;
 
   gc = pd->gc;
@@ -1394,8 +1411,8 @@
   mwServiceStorage_load(pd->srvc_store, unit, fetch_blist_cb, pd, NULL); 
 
   /* find all the NAB groups and subscribe to them */
-  blist = purple_get_blist();
-  for(l = blist->root; l; l = l->next) {
+  for(l = purple_blist_get_root(); l;
+		  l = purple_blist_node_get_sibling_next(l)) {
     PurpleGroup *group = (PurpleGroup *) l;
     enum mwSametimeGroupType gt;
     const char *owner;
@@ -1445,7 +1462,7 @@
 					 MW_PLUGIN_DEFAULT_HOST);
 
   if(purple_account_get_bool(account, MW_KEY_FORCE, FALSE) ||
-     (! strcmp(current_host, host)) ||
+     !host || (! strcmp(current_host, host)) ||
      (purple_proxy_connect(NULL, account, host, port, connect_cb, pd) == NULL)) {
 
     /* if we're configured to force logins, or if we're being
@@ -3234,10 +3251,10 @@
 static char *mw_prpl_status_text(PurpleBuddy *b) {
   PurpleConnection *gc;
   struct mwPurplePluginData *pd;
-  struct mwAwareIdBlock t = { mwAware_USER, b->name, NULL };
+  struct mwAwareIdBlock t = { mwAware_USER, (char *)purple_buddy_get_name(b), NULL };
   const char *ret = NULL;
 
-  if ((gc = purple_account_get_connection(b->account))
+  if ((gc = purple_account_get_connection(purple_buddy_get_account(b)))
       && (pd = gc->proto_data))
     ret = mwServiceAware_getText(pd->srvc_aware, &t);
 
@@ -3294,13 +3311,13 @@
 static void mw_prpl_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) {
   PurpleConnection *gc;
   struct mwPurplePluginData *pd = NULL;
-  struct mwAwareIdBlock idb = { mwAware_USER, b->name, NULL };
+  struct mwAwareIdBlock idb = { mwAware_USER, (char *)purple_buddy_get_name(b), NULL };
 
   const char *message = NULL;
   const char *status;
   char *tmp;
 
-  if ((gc = purple_account_get_connection(b->account))
+  if ((gc = purple_account_get_connection(purple_buddy_get_account(b)))
       && (pd = gc->proto_data))
      message = mwServiceAware_getText(pd->srvc_aware, &idb);
 
@@ -3316,7 +3333,7 @@
   }
 
   if(full && pd != NULL) {
-    tmp = user_supports_text(pd->srvc_aware, b->name);
+    tmp = user_supports_text(pd->srvc_aware, purple_buddy_get_name(b));
     if(tmp) {
 	  purple_notify_user_info_add_pair(user_info, _("Supports"), tmp);
       g_free(tmp);
@@ -3378,7 +3395,7 @@
   struct mwConference *conf;
   struct mwIdBlock idb = { NULL, NULL };
 
-  acct = buddy->account;
+  acct = purple_buddy_get_account(buddy);
   gc = purple_account_get_connection(acct);
   pd = gc->proto_data;
   srvc = pd->srvc_conf;
@@ -3392,7 +3409,7 @@
   conf = mwConference_new(srvc, topic);
   mwConference_open(conf);
 
-  idb.user = buddy->name;
+  idb.user = (char *)purple_buddy_get_name(buddy);
   mwConference_invite(conf, &idb, invite);
 }
 
@@ -3412,7 +3429,7 @@
   
   g_return_if_fail(buddy != NULL);
 
-  acct = buddy->account;
+  acct = purple_buddy_get_account(buddy);
   g_return_if_fail(acct != NULL);
 
   gc = purple_account_get_connection(acct);
@@ -3432,7 +3449,7 @@
   msgA = _("Create conference with user");
   msgB = _("Please enter a topic for the new conference, and an invitation"
 	   " message to be sent to %s");
-  msg1 = g_strdup_printf(msgB, buddy->name);
+  msg1 = g_strdup_printf(msgB, purple_buddy_get_name(buddy));
 
   purple_request_fields(gc, _("New Conference"),
 		      msgA, msg1, fields,
@@ -3469,7 +3486,7 @@
       blist_menu_conf_create(buddy, msg);
 
     } else {
-      struct mwIdBlock idb = { buddy->name, NULL };
+      struct mwIdBlock idb = { (char *)purple_buddy_get_name(buddy), NULL };
       mwConference_invite(d, &idb, msg);
     }
   }
@@ -3490,7 +3507,7 @@
   const char *msgB;
   char *msg;
 
-  acct = buddy->account;
+  acct = purple_buddy_get_account(buddy);
   g_return_if_fail(acct != NULL);
 
   gc = purple_account_get_connection(acct);
@@ -3518,7 +3535,7 @@
   msgB = _("Select a conference from the list below to send an invite to"
 	   " user %s. Select \"Create New Conference\" if you'd like to"
 	   " create a new conference to invite this user to.");
-  msg = g_strdup_printf(msgB, buddy->name);
+  msg = g_strdup_printf(msgB, purple_buddy_get_name(buddy));
 
   purple_request_fields(gc, _("Invite to Conference"),
 		      msgA, msg, fields,
@@ -3540,7 +3557,7 @@
   g_return_if_fail(node != NULL);
   g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
-  acct = buddy->account;
+  acct = purple_buddy_get_account(buddy);
   g_return_if_fail(acct != NULL);
 
   gc = purple_account_get_connection(acct);
@@ -4180,8 +4197,8 @@
   if(b) {
     guint32 type;
 
-    if(b->server_alias) {
-		purple_notify_user_info_add_pair(user_info, _("Full Name"), b->server_alias);
+    if(purple_buddy_get_server_alias(b)) {
+		purple_notify_user_info_add_pair(user_info, _("Full Name"), purple_buddy_get_server_alias(b));
     }
 
     type = purple_blist_node_get_int((PurpleBlistNode *) b, BUDDY_KEY_CLIENT);
@@ -4323,10 +4340,10 @@
 
 static void notify_add(PurpleConnection *gc, GList *row, void *user_data) {
   BuddyAddData *data = user_data;
-  char *group_name = NULL;
+  const char *group_name = NULL;
   
   if (data && data->group) {
-    group_name = data->group->name;
+    group_name = purple_group_get_name(data->group);
   }
 
   purple_blist_request_add_buddy(purple_connection_get_account(gc),
@@ -4408,14 +4425,14 @@
 
   buddy = data->buddy;
 
-  gc = purple_account_get_connection(buddy->account);
+  gc = purple_account_get_connection(purple_buddy_get_account(buddy));
   pd = gc->proto_data;
 
   if(results)
     res = results->data;
 
   if(!code && res && res->matches) {
-    if(g_list_length(res->matches) == 1) {
+    if(!res->matches->next) {
       struct mwResolveMatch *match = res->matches->data;
       
       /* only one? that might be the right one! */
@@ -4509,7 +4526,7 @@
 
   srvc = pd->srvc_resolve;
 
-  query = g_list_prepend(NULL, buddy->name);
+  query = g_list_prepend(NULL, (char *)purple_buddy_get_name(buddy));
   flags = mwResolveFlag_FIRST | mwResolveFlag_USERS;
 
   req = mwServiceResolve_resolve(srvc, query, flags, add_buddy_resolved,
@@ -4562,7 +4579,7 @@
 
     /* convert PurpleBuddy into a mwAwareIdBlock */
     idb->type = mwAware_USER;
-    idb->user = (char *) b->name;
+    idb->user = (char *) purple_buddy_get_name(b);
     idb->community = NULL;
 
     /* put idb into the list associated with the buddy's group */
@@ -4587,7 +4604,7 @@
 				 PurpleBuddy *buddy, PurpleGroup *group) {
 
   struct mwPurplePluginData *pd;
-  struct mwAwareIdBlock idb = { mwAware_USER, buddy->name, NULL };
+  struct mwAwareIdBlock idb = { mwAware_USER, (char *)purple_buddy_get_name(buddy), NULL };
   struct mwAwareList *list;
 
   GList *rem = g_list_prepend(NULL, &idb);
--- a/libpurple/protocols/silc/buddy.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/silc/buddy.c	Thu Nov 27 21:15:43 2008 +0000
@@ -322,9 +322,12 @@
 silcpurple_buddy_keyagr(PurpleBlistNode *node, gpointer data)
 {
 	PurpleBuddy *buddy;
+	PurpleAccount *account;
 
 	buddy = (PurpleBuddy *)node;
-	silcpurple_buddy_keyagr_do(buddy->account->gc, buddy->name, FALSE);
+	account = purple_buddy_get_account(buddy);
+	silcpurple_buddy_keyagr_do(purple_account_get_connection(account),
+			purple_buddy_get_name(buddy), FALSE);
 }
 
 
@@ -341,12 +344,12 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	b = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(b->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(b));
 	sg = gc->proto_data;
 
 	/* Find client entry */
 	clients = silc_client_get_clients_local(sg->client, sg->conn,
-						b->name, FALSE);
+						purple_buddy_get_name(b), FALSE);
 	if (!clients)
 		return;
 
@@ -467,9 +470,9 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 
-	silcpurple_buddy_privkey(gc, buddy->name);
+	silcpurple_buddy_privkey(gc, purple_buddy_get_name(buddy));
 }
 
 
@@ -596,9 +599,9 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 
-	silcpurple_buddy_getkey(gc, buddy->name);
+	silcpurple_buddy_getkey(gc, purple_buddy_get_name(buddy));
 }
 
 static void
@@ -613,7 +616,7 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	b = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(b->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(b));
 	sg = gc->proto_data;
 
 	pkfile = purple_blist_node_get_string(node, "public-key");
@@ -624,7 +627,7 @@
 		return;
 	}
 
-	silcpurple_show_public_key(sg, b->name, public_key, NULL, NULL);
+	silcpurple_show_public_key(sg, purple_buddy_get_name(b), public_key, NULL, NULL);
 	silc_pkcs_public_key_free(public_key);
 }
 
@@ -686,6 +689,7 @@
 	if (b) {
 		/* See if we have this buddy's public key.  If we do use that
 		   to search the details. */
+		gpointer proto_data;
 		filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key");
 		if (filename) {
 			/* Call WHOIS.  The user info is displayed in the WHOIS
@@ -695,15 +699,15 @@
 			return;
 		}
 
-		if (!b->proto_data) {
+		if (!(proto_data = purple_buddy_get_protocol_data(b))) {
 			g_snprintf(tmp, sizeof(tmp),
-				   _("User %s is not present in the network"), b->name);
+				   _("User %s is not present in the network"), purple_buddy_get_name(b));
 			purple_notify_error(gc, _("User Information"),
 					  _("Cannot get user information"), tmp);
 			return;
 		}
 
-		client_entry = silc_client_get_client_by_id(client, conn, b->proto_data);
+		client_entry = silc_client_get_client_by_id(client, conn, proto_data);
 		if (client_entry) {
 			/* Call WHOIS.  The user info is displayed in the WHOIS
 			   command reply. */
@@ -721,7 +725,7 @@
 {
 	char tmp[512];
 	g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not trusted"),
-		   r->b->name);
+		   purple_buddy_get_name(r->b));
 	purple_notify_error(r->client->application, _("Add Buddy"), tmp,
 			    _("You cannot receive buddy notifications until you "
 			      "import his/her public key.  You can use the Get Public Key "
@@ -1033,7 +1037,7 @@
 
 	/* Now verify the public key */
 	r->offline_pk = silc_pkcs_public_key_encode(r->public_key, &r->offline_pk_len);
-	silcpurple_verify_public_key(r->client, r->conn, r->b->name,
+	silcpurple_verify_public_key(r->client, r->conn, purple_buddy_get_name(r->b),
 				     SILC_CONN_CLIENT, r->public_key,
 				     silcpurple_add_buddy_save, r);
 }
@@ -1071,7 +1075,7 @@
 {
 	char tmp[512];
 	g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"),
-		   r->b->name);
+		   purple_buddy_get_name(r->b));
 	purple_request_action(r->client->application, _("Add Buddy"), tmp,
 			      _("To add the buddy you must import his/her public key. "
 				"Press Import to import a public key."), 0,
@@ -1209,6 +1213,7 @@
 	const char *filename;
 	SilcClientEntry client_entry = NULL;
 	SilcUInt16 cmd_ident;
+	const char *name;
 
 	filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key");
 
@@ -1246,17 +1251,19 @@
 	silc_dlist_start(clients);
 	client_entry = silc_dlist_get(clients);
 
+	name = purple_buddy_get_name(b);
+
 	/* If we searched using public keys and more than one entry was found
 	   the same person is logged on multiple times. */
-	if (silc_dlist_count(clients) > 1 && r->pubkey_search && b->name) {
+	if (silc_dlist_count(clients) > 1 && r->pubkey_search && name) {
 		if (r->init) {
 			/* Find the entry that closest matches to the
 			   buddy nickname. */
 			SilcClientEntry entry;
 			silc_dlist_start(clients);
 			while ((entry = silc_dlist_get(clients))) {
-				if (!g_ascii_strncasecmp(b->name, entry->nickname,
-						 strlen(b->name))) {
+				if (!g_ascii_strncasecmp(name, entry->nickname,
+						 strlen(name))) {
 					client_entry = entry;
 					break;
 				}
@@ -1271,7 +1278,7 @@
 	/* The client was found.  Now get its public key and verify
 	   that before adding the buddy. */
 	memset(&userpk, 0, sizeof(userpk));
-	b->proto_data = silc_memdup(&client_entry->id, sizeof(client_entry->id));
+	purple_buddy_set_protocol_data(b, silc_memdup(&client_entry->id, sizeof(client_entry->id)));
 	r->client_id = client_entry->id;
 
 	/* Get the public key from attributes, if not present then
@@ -1335,7 +1342,7 @@
 	SilcClientConnection conn = sg->conn;
 	SilcPurpleBuddyRes r;
 	SilcBuffer attrs;
-	const char *filename, *name = b->name;
+	const char *filename, *name = purple_buddy_get_name(b);
 
 	r = silc_calloc(1, sizeof(*r));
 	if (!r)
@@ -1395,31 +1402,33 @@
 
 void silcpurple_send_buddylist(PurpleConnection *gc)
 {
-	PurpleBuddyList *blist;
 	PurpleBlistNode *gnode, *cnode, *bnode;
 	PurpleBuddy *buddy;
 	PurpleAccount *account;
 
 	account = purple_connection_get_account(gc);
 
-	if ((blist = purple_get_blist()) != NULL)
+	for (gnode = purple_blist_get_root();
+			gnode != NULL;
+			gnode = purple_blist_node_get_sibling_next(gnode))
 	{
-		for (gnode = blist->root; gnode != NULL; gnode = gnode->next)
+		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
+			continue;
+		for (cnode = purple_blist_node_get_first_child(gnode);
+				cnode != NULL;
+				cnode = purple_blist_node_get_sibling_next(cnode))
 		{
-			if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
+			if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			for (cnode = gnode->child; cnode != NULL; cnode = cnode->next)
+			for (bnode = purple_blist_node_get_first_child(cnode);
+					bnode != NULL;
+					bnode = purple_blist_node_get_sibling_next(bnode))
 			{
-				if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
+				if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
-				for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
-				{
-					if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
-						continue;
-					buddy = (PurpleBuddy *)bnode;
-					if (purple_buddy_get_account(buddy) == account)
-						silcpurple_add_buddy_i(gc, buddy, TRUE);
-				}
+				buddy = (PurpleBuddy *)bnode;
+				if (purple_buddy_get_account(buddy) == account)
+					silcpurple_add_buddy_i(gc, buddy, TRUE);
 			}
 		}
 	}
@@ -1428,7 +1437,7 @@
 void silcpurple_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
 			   PurpleGroup *group)
 {
-	silc_free(buddy->proto_data);
+	silc_free(purple_buddy_get_protocol_data(buddy));
 }
 
 void silcpurple_idle_set(PurpleConnection *gc, int idle)
@@ -1469,10 +1478,12 @@
 
 char *silcpurple_status_text(PurpleBuddy *b)
 {
-	SilcPurple sg = b->account->gc->proto_data;
+	PurpleAccount *account = purple_buddy_get_account(b);
+	PurpleConnection *gc = purple_account_get_connection(account);
+	SilcPurple sg = gc->proto_data;
 	SilcClient client = sg->client;
 	SilcClientConnection conn = sg->conn;
-	SilcClientID *client_id = b->proto_data;
+	SilcClientID *client_id = purple_buddy_get_protocol_data(b);
 	SilcClientEntry client_entry;
 	SilcAttributePayload attr;
 	SilcAttributeMood mood = 0;
@@ -1533,10 +1544,12 @@
 
 void silcpurple_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
 {
-	SilcPurple sg = b->account->gc->proto_data;
+	PurpleAccount *account = purple_buddy_get_account(b);
+	PurpleConnection *gc = purple_account_get_connection(account);
+	SilcPurple sg = gc->proto_data;
 	SilcClient client = sg->client;
 	SilcClientConnection conn = sg->conn;
-	SilcClientID *client_id = b->proto_data;
+	SilcClientID *client_id = purple_buddy_get_protocol_data(b);
 	SilcClientEntry client_entry;
 	char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr;
 	char tmp[256];
@@ -1610,12 +1623,12 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	b = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(b->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(b));
 	sg = gc->proto_data;
 
 	/* Call KILL */
 	silc_client_command_call(sg->client, sg->conn, NULL, "KILL",
-				 b->name, "Killed by operator", NULL);
+				 purple_buddy_get_name(b), "Killed by operator", NULL);
 }
 
 typedef struct {
@@ -1633,7 +1646,8 @@
 
 GList *silcpurple_buddy_menu(PurpleBuddy *buddy)
 {
-	PurpleConnection *gc = purple_account_get_connection(buddy->account);
+	PurpleAccount *account = purple_buddy_get_account(buddy);
+	PurpleConnection *gc = purple_account_get_connection(account);
 	SilcPurple sg = gc->proto_data;
 	SilcClientConnection conn = sg->conn;
 	const char *pkfile = NULL;
@@ -1645,7 +1659,7 @@
 	pkfile = purple_blist_node_get_string((PurpleBlistNode *) buddy, "public-key");
 	client_entry = silc_client_get_client_by_id(sg->client,
 						    sg->conn,
-						    buddy->proto_data);
+						    purple_buddy_get_protocol_data(buddy));
 
 	if (client_entry &&
 	    silc_client_private_message_key_is_set(sg->client,
--- a/libpurple/protocols/silc/chat.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/silc/chat.c	Thu Nov 27 21:15:43 2008 +0000
@@ -182,7 +182,9 @@
 silcpurple_chat_getinfo_menu(PurpleBlistNode *node, gpointer data)
 {
 	PurpleChat *chat = (PurpleChat *)node;
-	silcpurple_chat_getinfo(chat->account->gc, chat->components);
+	PurpleAccount *account = purple_chat_get_account(chat);
+	silcpurple_chat_getinfo(purple_account_get_connection(account),
+			purple_chat_get_components(chat));
 }
 
 
@@ -496,11 +498,11 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
-				 g_hash_table_lookup(chat->components, "channel"),
+				 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
 				 "+C", NULL);
 }
 
@@ -549,7 +551,7 @@
 	g_hash_table_replace(comp, "passphrase", g_strdup(passphrase));
 
 	cn = purple_chat_new(sg->account, alias, comp);
-	g = (PurpleGroup *)p->c->node.parent;
+	g = purple_chat_get_group(p->c);
 	purple_blist_add_chat(cn, g, (PurpleBlistNode *)p->c);
 
 	/* Associate to a real channel */
@@ -583,7 +585,7 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	p = silc_calloc(1, sizeof(*p));
@@ -591,7 +593,7 @@
 		return;
 	p->sg = sg;
 
-	p->channel = g_hash_table_lookup(chat->components, "channel");
+	p->channel = g_hash_table_lookup(purple_chat_get_components(chat), "channel");
 	p->c = purple_blist_find_chat(sg->account, p->channel);
 
 	fields = purple_request_fields_new();
@@ -633,11 +635,11 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
-				 g_hash_table_lookup(chat->components, "channel"),
+				 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
 				 "-f", NULL);
 }
 
@@ -652,7 +654,7 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	if (!sg->conn)
@@ -663,7 +665,7 @@
 	   (default key). */
 
 	/* Call CMODE */
-	channel = g_hash_table_lookup(chat->components, "channel");
+	channel = g_hash_table_lookup(purple_chat_get_components(chat), "channel");
 	silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", channel,
 				 "+f", NULL);
 }
@@ -729,13 +731,13 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	if (!sg->conn)
 		return;
 
-	ch = g_strdup(g_hash_table_lookup(chat->components, "channel"));
+	ch = g_strdup(g_hash_table_lookup(purple_chat_get_components(chat), "channel"));
 	channel = silc_client_get_channel(sg->client, sg->conn, (char *)ch);
 	if (!channel)
 		return;
@@ -764,11 +766,11 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
-				 g_hash_table_lookup(chat->components, "channel"),
+				 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
 				 "-t", NULL);
 }
 
@@ -782,11 +784,11 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
-				 g_hash_table_lookup(chat->components, "channel"),
+				 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
 				 "+t", NULL);
 }
 
@@ -800,11 +802,11 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
-				 g_hash_table_lookup(chat->components, "channel"),
+				 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
 				 "-p", NULL);
 }
 
@@ -818,11 +820,11 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
-				 g_hash_table_lookup(chat->components, "channel"),
+				 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
 				 "+p", NULL);
 }
 
@@ -836,11 +838,11 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
-				 g_hash_table_lookup(chat->components, "channel"),
+				 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
 				 "-s", NULL);
 }
 
@@ -854,11 +856,11 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node));
 
 	chat = (PurpleChat *) node;
-	gc = purple_account_get_connection(chat->account);
+	gc = purple_account_get_connection(purple_chat_get_account(chat));
 	sg = gc->proto_data;
 
 	silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
-				 g_hash_table_lookup(chat->components, "channel"),
+				 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
 				 "+s", NULL);
 }
 
@@ -877,8 +879,8 @@
 
 GList *silcpurple_chat_menu(PurpleChat *chat)
 {
-	GHashTable *components = chat->components;
-	PurpleConnection *gc = purple_account_get_connection(chat->account);
+	GHashTable *components = purple_chat_get_components(chat);
+	PurpleConnection *gc = purple_account_get_connection(purple_chat_get_account(chat));
 	SilcPurple sg = gc->proto_data;
 	SilcClientConnection conn = sg->conn;
 	const char *chname = NULL;
--- a/libpurple/protocols/silc/ops.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/silc/ops.c	Thu Nov 27 21:15:43 2008 +0000
@@ -431,6 +431,7 @@
 	va_list va;
 	PurpleConnection *gc = client->application;
 	SilcPurple sg = gc->proto_data;
+	PurpleAccount *account = purple_connection_get_account(gc);
 	PurpleConversation *convo;
 	SilcClientEntry client_entry, client_entry2;
 	SilcChannelEntry channel;
@@ -856,19 +857,22 @@
 				silc_free(pk);
 
 				/* Find buddy by associated public key */
-				for (gnode = purple_get_blist()->root; gnode;
-				     gnode = gnode->next) {
+				for (gnode = purple_blist_get_root(); gnode;
+				     gnode = purple_blist_node_get_sibling_next(gnode)) {
 					if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 						continue;
-					for (cnode = gnode->child; cnode; cnode = cnode->next) {
+					for (cnode = purple_blist_node_get_first_child(gnode);
+							cnode;
+							cnode = purple_blist_node_get_sibling_next(cnode)) {
 						if( !PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 							continue;
-						for (bnode = cnode->child; bnode;
-						     bnode = bnode->next) {
+						for (bnode = purple_blist_node_get_first_child(cnode);
+								bnode;
+								bnode = purple_blist_node_get_sibling_next(bnode)) {
 							if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 								continue;
 							b = (PurpleBuddy *)bnode;
-							if (b->account != gc->account)
+							if (purple_buddy_get_account(b) != account)
 								continue;
 							f = purple_blist_node_get_string(bnode, "public-key");
 							if (f && !strcmp(f, buf))
@@ -889,9 +893,9 @@
 				}
 			}
 
-			silc_free(b->proto_data);
-			b->proto_data = silc_memdup(&client_entry->id,
-						    sizeof(client_entry->id));
+			silc_free(purple_buddy_get_protocol_data(b));
+			purple_buddy_set_protocol_data(b, silc_memdup(&client_entry->id,
+						    sizeof(client_entry->id)));
 			if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
 				break;
 			} else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
--- a/libpurple/protocols/simple/simple.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/simple/simple.c	Thu Nov 27 21:15:43 2008 +0000
@@ -196,33 +196,41 @@
 {
 	struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data;
 	struct simple_buddy *b;
-	if(strncmp("sip:", buddy->name, 4)) {
-		gchar *buf = g_strdup_printf("sip:%s", buddy->name);
+	const char *name = purple_buddy_get_name(buddy);
+	if(strncmp("sip:", name, 4)) {
+		gchar *buf = g_strdup_printf("sip:%s", name);
 		purple_blist_rename_buddy(buddy, buf);
 		g_free(buf);
 	}
-	if(!g_hash_table_lookup(sip->buddies, buddy->name)) {
+	if(!g_hash_table_lookup(sip->buddies, name)) {
 		b = g_new0(struct simple_buddy, 1);
-		purple_debug_info("simple", "simple_add_buddy %s\n", buddy->name);
-		b->name = g_strdup(buddy->name);
+		purple_debug_info("simple", "simple_add_buddy %s\n", name);
+		b->name = g_strdup(name);
 		g_hash_table_insert(sip->buddies, b->name, b);
 	} else {
-		purple_debug_info("simple", "buddy %s already in internal list\n", buddy->name);
+		purple_debug_info("simple", "buddy %s already in internal list\n", name);
 	}
 }
 
 static void simple_get_buddies(PurpleConnection *gc) {
 	PurpleBlistNode *gnode, *cnode, *bnode;
+	PurpleAccount *account;
 
 	purple_debug_info("simple", "simple_get_buddies\n");
 
-	for(gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
+	account = purple_connection_get_account(gc);
+	for(gnode = purple_blist_get_root(); gnode;
+			gnode = purple_blist_node_get_sibling_next(gnode)) {
 		if(!PURPLE_BLIST_NODE_IS_GROUP(gnode)) continue;
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
+		for(cnode = purple_blist_node_get_first_child(gnode);
+				cnode;
+				cnode = purple_blist_node_get_sibling_next(cnode)) {
 			if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) continue;
-			for(bnode = cnode->child; bnode; bnode = bnode->next) {
+			for(bnode = purple_blist_node_get_first_child(cnode);
+					bnode;
+					bnode = purple_blist_node_get_sibling_next(bnode)) {
 				if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) continue;
-				if(((PurpleBuddy*)bnode)->account == gc->account)
+				if(purple_buddy_get_account((PurpleBuddy*)bnode) == account)
 					simple_add_buddy(gc, (PurpleBuddy*)bnode, (PurpleGroup *)gnode);
 			}
 		}
@@ -231,9 +239,10 @@
 
 static void simple_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
 {
+	const char *name = purple_buddy_get_name(buddy);
 	struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data;
-	struct simple_buddy *b = g_hash_table_lookup(sip->buddies, buddy->name);
-	g_hash_table_remove(sip->buddies, buddy->name);
+	struct simple_buddy *b = g_hash_table_lookup(sip->buddies, name);
+	g_hash_table_remove(sip->buddies, name);
 	g_free(b->name);
 	g_free(b);
 }
@@ -922,7 +931,7 @@
 			purple_blist_add_buddy(b, NULL, g, NULL);
 			purple_blist_alias_buddy(b, uri);
 			bs = g_new0(struct simple_buddy, 1);
-			bs->name = g_strdup(b->name);
+			bs->name = g_strdup(purple_buddy_get_name(b));
 			g_hash_table_insert(sip->buddies, bs->name, bs);
 		}
 		xmlnode_free(isc);
@@ -1630,6 +1639,13 @@
 		cur[0] = '\0';
 		purple_debug_info("simple", "\n\nreceived - %s\n######\n%s\n#######\n\n", ctime(&currtime), conn->inbuf);
 		msg = sipmsg_parse_header(conn->inbuf);
+
+		if(!msg) {
+			/* Should we re-use this error message (from lower in the function)? */
+			purple_debug_misc("simple", "received a incomplete sip msg: %s\n", conn->inbuf);
+			return;
+		}
+
 		cur[0] = '\r';
 		cur += 2;
 		restlen = conn->inbufused - (cur - conn->inbuf);
--- a/libpurple/protocols/yahoo/yahoo.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Thu Nov 27 21:15:43 2008 +0000
@@ -385,7 +385,7 @@
 	for (i = list; i; i = i->next) {
 		b = i->data;
 		g = purple_buddy_get_group(b);
-		if (!purple_utf8_strcasecmp(group, g->name)) {
+		if (!purple_utf8_strcasecmp(group, purple_group_get_name(g))) {
 			purple_debug(PURPLE_DEBUG_MISC, "yahoo",
 				"Oh good, %s is in the right group (%s).\n", name, group);
 			list = g_slist_delete_link(list, i);
@@ -423,7 +423,8 @@
 	for (i = list; i; i = i->next) {
 		b = i->data;
 		g = purple_buddy_get_group(b);
-		purple_debug(PURPLE_DEBUG_MISC, "yahoo", "Deleting Buddy %s from group %s.\n", name, g->name);
+		purple_debug(PURPLE_DEBUG_MISC, "yahoo", "Deleting Buddy %s from group %s.\n", name,
+				purple_group_get_name(g));
 		purple_blist_remove_buddy(b);
 	}
 }
@@ -2027,21 +2028,23 @@
 		return;
 
 	group = purple_buddy_get_group(buddy);
-	name = g_strdup(buddy->name);
-	account = buddy->account;
+	name = g_strdup(purple_buddy_get_name(buddy));
+	account = purple_buddy_get_account(buddy);
 
 	purple_debug(PURPLE_DEBUG_INFO, "blist",
-		"Removing '%s' from buddy list.\n", buddy->name);
+		"Removing '%s' from buddy list.\n", name);
 	purple_account_remove_buddy(account, buddy, group);
 	purple_blist_remove_buddy(buddy);
 
-	serv_add_deny(account->gc, name);
+	serv_add_deny(purple_account_get_connection(account), name);
 
 	g_free(name);
 }
 
-static void keep_buddy(PurpleBuddy *b) {
-	purple_privacy_deny_remove(b->account, b->name, 1);
+static void keep_buddy(PurpleBuddy *b)
+{
+	purple_privacy_deny_remove(purple_buddy_get_account(b),
+			purple_buddy_get_name(b), 1);
 }
 
 static void yahoo_process_ignore(PurpleConnection *gc, struct yahoo_packet *pkt) {
@@ -3121,11 +3124,12 @@
 	YahooFriend *f;
 	PurplePresence *presence;
 
-	if (!b || !(account = b->account) || !(gc = purple_account_get_connection(account)) ||
-					     !(yd = gc->proto_data))
+	if (!b || !(account = purple_buddy_get_account(b)) ||
+			!(gc = purple_account_get_connection(account)) ||
+			!(yd = gc->proto_data))
 		return NULL;
 
-	f = yahoo_friend_find(gc, b->name);
+	f = yahoo_friend_find(gc, purple_buddy_get_name(b));
 	if (!f) {
 		return "not-authorized";
 	}
@@ -3185,7 +3189,7 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 	yd = gc->proto_data;
 	id = yd->conf_id;
 
@@ -3197,7 +3201,7 @@
 	yahoo_c_join(gc, components);
 	g_hash_table_destroy(components);
 
-	yahoo_c_invite(gc, id, "Join my conference...", buddy->name);
+	yahoo_c_invite(gc, id, "Join my conference...", purple_buddy_get_name(buddy));
 }
 
 static void yahoo_presence_settings(PurpleBlistNode *node, gpointer data) {
@@ -3206,9 +3210,9 @@
 	int presence_val = GPOINTER_TO_INT(data);
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
-
-	yahoo_friend_update_presence(gc, buddy->name, presence_val);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+
+	yahoo_friend_update_presence(gc, purple_buddy_get_name(buddy), presence_val);
 }
 
 static void yahoo_game(PurpleBlistNode *node, gpointer data) {
@@ -3226,10 +3230,10 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 	yd = (struct yahoo_data *) gc->proto_data;
 
-	f = yahoo_friend_find(gc, buddy->name);
+	f = yahoo_friend_find(gc, purple_buddy_get_name(buddy));
 	if (!f)
 		return;
 
@@ -3251,8 +3255,10 @@
 	YahooFriend *f = NULL;
 	const char *msg;
 	char *msg2;
-
-	f = yahoo_friend_find(b->account->gc, b->name);
+	PurpleAccount *account;
+
+	account = purple_buddy_get_account(b);
+	f = yahoo_friend_find(purple_account_get_connection(account), purple_buddy_get_name(b));
 	if (!f)
 		return g_strdup(_("Not on server list"));
 
@@ -3281,8 +3287,10 @@
 	char *escaped;
 	char *status = NULL;
 	const char *presence = NULL;
-
-	f = yahoo_friend_find(b->account->gc, b->name);
+	PurpleAccount *account;
+
+	account = purple_buddy_get_account(b);
+	f = yahoo_friend_find(purple_account_get_connection(account), purple_buddy_get_name(b));
 	if (!f)
 		status = g_strdup_printf("\n%s", _("Not on server list"));
 	else {
@@ -3333,7 +3341,7 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 
 	yahoo_add_buddy(gc, buddy, NULL);
 }
@@ -3347,9 +3355,9 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(buddy->account);
-
-	yahoo_chat_goto(gc, buddy->name);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+
+	yahoo_chat_goto(gc, purple_buddy_get_name(buddy));
 }
 
 static GList *build_presence_submenu(YahooFriend *f, PurpleConnection *gc) {
@@ -3393,9 +3401,10 @@
 static void yahoo_doodle_blist_node(PurpleBlistNode *node, gpointer data)
 {
 	PurpleBuddy *b = (PurpleBuddy *)node;
-	PurpleConnection *gc = b->account->gc;
-
-	yahoo_doodle_initiate(gc, b->name);
+	PurpleAccount *account = purple_buddy_get_account(b);
+	PurpleConnection *gc = purple_account_get_connection(account);
+
+	yahoo_doodle_initiate(gc, purple_buddy_get_name(b));
 }
 
 static GList *yahoo_buddy_menu(PurpleBuddy *buddy)
@@ -3403,12 +3412,12 @@
 	GList *m = NULL;
 	PurpleMenuAction *act;
 
-	PurpleConnection *gc = purple_account_get_connection(buddy->account);
+	PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 	struct yahoo_data *yd = gc->proto_data;
 	static char buf2[1024];
 	YahooFriend *f;
 
-	f = yahoo_friend_find(gc, buddy->name);
+	f = yahoo_friend_find(gc, purple_buddy_get_name(buddy));
 
 	if (!f && !yd->wm) {
 		act = purple_menu_action_new(_("Add Buddy"),
@@ -3935,19 +3944,20 @@
 	const char *group = NULL;
 	char *group2;
 	YahooFriend *f;
+	const char *bname;
 
 	if (!yd->logged_in)
 		return;
 
-	if (!purple_privacy_check(purple_connection_get_account(gc),
-			purple_buddy_get_name(buddy)))
+	bname = purple_buddy_get_name(buddy);
+	if (!purple_privacy_check(purple_connection_get_account(gc), bname))
 		return;
 
-	f = yahoo_friend_find(gc, purple_buddy_get_name(buddy));
+	f = yahoo_friend_find(gc, bname);
 
 	g = purple_buddy_get_group(buddy);
 	if (g)
-		group = g->name;
+		group = purple_group_get_name(g);
 	else
 		group = "Buddies";
 
@@ -3960,7 +3970,7 @@
 	                  1, purple_connection_get_display_name(gc),
 	                  302, "319",
 	                  300, "319",
-	                  7, buddy->name,
+	                  7, bname,
 	                  334, "0",
 	                  301, "319",
 	                  303, "319"
@@ -3974,19 +3984,22 @@
 static void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
 {
 	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
-        struct yahoo_packet *pkt;
+	struct yahoo_packet *pkt;
 	GSList *buddies, *l;
 	PurpleGroup *g;
 	gboolean remove = TRUE;
 	char *cg;
-
-	if (!(yahoo_friend_find(gc, buddy->name)))
+	const char *bname, *gname;
+
+	bname = purple_buddy_get_name(buddy);
+	if (!(yahoo_friend_find(gc, bname)))
 		return;
 
-	buddies = purple_find_buddies(purple_connection_get_account(gc), buddy->name);
+	gname = purple_group_get_name(group);
+	buddies = purple_find_buddies(purple_connection_get_account(gc), bname);
 	for (l = buddies; l; l = l->next) {
 		g = purple_buddy_get_group(l->data);
-		if (purple_utf8_strcasecmp(group->name, g->name)) {
+		if (purple_utf8_strcasecmp(gname, purple_group_get_name(g))) {
 			remove = FALSE;
 			break;
 		}
@@ -3995,12 +4008,12 @@
 	g_slist_free(buddies);
 
 	if (remove)
-		g_hash_table_remove(yd->friends, buddy->name);
-
-	cg = yahoo_string_encode(gc, group->name, NULL);
+		g_hash_table_remove(yd->friends, bname);
+
+	cg = yahoo_string_encode(gc, gname, NULL);
 	pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0);
 	yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
-	                  7, buddy->name, 65, cg);
+	                  7, bname, 65, cg);
 	yahoo_packet_send_and_free(pkt, yd);
 	g_free(cg);
 }
@@ -4109,7 +4122,7 @@
 	struct yahoo_packet *pkt;
 	char *gpn, *gpo;
 
-	gpn = yahoo_string_encode(gc, group->name, NULL);
+	gpn = yahoo_string_encode(gc, purple_group_get_name(group), NULL);
 	gpo = yahoo_string_encode(gc, old_name, NULL);
 	if (!strcmp(gpn, gpo)) {
 		g_free(gpn);
--- a/libpurple/protocols/yahoo/yahoo_profile.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_profile.c	Thu Nov 27 21:15:43 2008 +0000
@@ -699,8 +699,9 @@
 			info_data->name);
 
 	if (b) {
-		if(b->alias && b->alias[0]) {
-			char *aliastext = g_markup_escape_text(b->alias, -1);
+		const char *balias = purple_buddy_get_local_buddy_alias(b);
+		if(balias && balias[0]) {
+			char *aliastext = g_markup_escape_text(balias, -1);
 			purple_notify_user_info_add_pair(user_info, _("Alias"), aliastext); 
 			g_free(aliastext);
 		}
@@ -715,7 +716,7 @@
 		/* Add the normal tooltip pairs */
 		yahoo_tooltip_text(b, user_info, TRUE);
 
-		if ((f = yahoo_friend_find(info_data->gc, b->name))) {
+		if ((f = yahoo_friend_find(info_data->gc, purple_buddy_get_name(b)))) {
 			const char *ip;
 			if ((ip = yahoo_friend_get_ip(f)))
 				purple_notify_user_info_add_pair(user_info, _("IP Address"), ip);
@@ -1215,7 +1216,9 @@
 				 * in which case the user may or may not actually exist.
 				 * Hence this extra step.
 				 */
-				f = yahoo_friend_find(b->account->gc, b->name);
+				PurpleAccount *account = purple_buddy_get_account(b);
+				f = yahoo_friend_find(purple_account_get_connection(account),
+						purple_buddy_get_name(b));
 			}
 			g_string_append_printf(str, "%s<br><br>",
 				f?  _("Could not retrieve the user's profile. "
--- a/libpurple/protocols/yahoo/yahoochat.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoochat.c	Thu Nov 27 21:15:43 2008 +0000
@@ -513,13 +513,13 @@
 
 	c = purple_find_chat(gc, YAHOO_CHAT_ID);
 
-	if (room && (!c || purple_conv_chat_has_left(PURPLE_CONV_CHAT(c))) && members &&
-	   ((g_list_length(members) > 1) ||
+	if (room && (!c || purple_conv_chat_has_left(PURPLE_CONV_CHAT(c))) &&
+	    members && (members->next ||
 	     !g_ascii_strcasecmp(members->data, purple_connection_get_display_name(gc)))) {
-		int i;
+		GList *l;
 		GList *flags = NULL;
-		for (i = 0; i < g_list_length(members); i++)
-			flags = g_list_append(flags, GINT_TO_POINTER(PURPLE_CBFLAGS_NONE));
+		for (l = members; l; l = l->next)
+			flags = g_list_prepend(flags, GINT_TO_POINTER(PURPLE_CBFLAGS_NONE));
 		if (c && purple_conv_chat_has_left(PURPLE_CONV_CHAT(c))) {
 			/* this might be a hack, but oh well, it should nicely */
 			char *tmpmsg;
--- a/libpurple/protocols/zephyr/zephyr.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/protocols/zephyr/zephyr.c	Thu Nov 27 21:15:43 2008 +0000
@@ -343,15 +343,15 @@
    Converts strings to utf-8 if necessary using user specified encoding
 */
 
-static gchar *zephyr_recv_convert(PurpleConnection *gc,gchar *string, int len)
+static gchar *zephyr_recv_convert(PurpleConnection *gc, gchar *string)
 {
 	gchar *utf8;
 	GError *err = NULL;
 	zephyr_account *zephyr = gc->proto_data;
-	if (g_utf8_validate(string, len, NULL)) {
+	if (g_utf8_validate(string, -1, NULL)) {
 		return g_strdup(string);
 	} else {
-		utf8 = g_convert(string, len, "UTF-8", zephyr->encoding, NULL, NULL, &err);
+		utf8 = g_convert(string, -1, "UTF-8", zephyr->encoding, NULL, NULL, &err);
 		if (err) {
 			purple_debug_error("zephyr", "recv conversion error: %s\n", err->message);
 			utf8 = g_strdup(_("(There was an error converting this message.	 Check the 'Encoding' option in the Account Editor)"));
@@ -732,7 +732,7 @@
 	return ret;
 }
 
-static gboolean pending_zloc(zephyr_account *zephyr,char *who)
+static gboolean pending_zloc(zephyr_account *zephyr, const char *who)
 {
 	GList *curr;
 
@@ -771,6 +771,8 @@
 			int nlocs;
 			char *user;
 			PurpleBuddy *b;
+			const char *bname;
+
 			/* XXX add real error reporting */
 			if (ZParseLocations(&notice, NULL, &nlocs, &user) != ZERR_NONE)
 				return;
@@ -780,15 +782,19 @@
 				b = purple_find_buddy(gc->account,stripped_user);
 				g_free(stripped_user);
 			}
-			if ((b && pending_zloc(zephyr,b->name)) || pending_zloc(zephyr,user)) {
+
+			bname = b ? purple_buddy_get_name(b) : NULL;
+			if ((b && pending_zloc(zephyr,bname)) || pending_zloc(zephyr,user)) {
 				ZLocations_t locs;
 				int one = 1;
 				PurpleNotifyUserInfo *user_info = purple_notify_user_info_new();
 				char *tmp;
+				const char *balias;
 
-				purple_notify_user_info_add_pair(user_info, _("User"), (b ? b->name : user));
-				if (b && b->alias)
-					purple_notify_user_info_add_pair(user_info, _("Alias"), b->alias);
+				purple_notify_user_info_add_pair(user_info, _("User"), (b ? bname : user));
+				balias = purple_buddy_get_local_buddy_alias(b);
+				if (b && balias)
+					purple_notify_user_info_add_pair(user_info, _("Alias"), balias);
 
 				if (!nlocs) {
 					purple_notify_user_info_add_pair(user_info, NULL, _("Hidden or not logged-in"));
@@ -801,14 +807,14 @@
 					purple_notify_user_info_add_pair(user_info, _("Location"), tmp);
 					g_free(tmp);
 				}
-				purple_notify_userinfo(gc, (b ? b->name : user), 
+				purple_notify_userinfo(gc, (b ? bname : user), 
 						     user_info, NULL, NULL);
 				purple_notify_user_info_destroy(user_info);
 			} else {
 				if (nlocs>0) 
-					purple_prpl_got_user_status(gc->account, b ? b->name : user, "available", NULL);
+					purple_prpl_got_user_status(gc->account, b ? bname : user, "available", NULL);
 				else 
-					purple_prpl_got_user_status(gc->account, b ? b->name : user, "offline", NULL);
+					purple_prpl_got_user_status(gc->account, b ? bname : user, "offline", NULL);
 			}
 
 			g_free(user);
@@ -820,7 +826,7 @@
 		PurpleConvChat *gcc;
 		char *ptr = (char *) notice.z_message + (strlen(notice.z_message) + 1);
 		int len; 
-		char *sendertmp = g_strdup_printf("%s", zephyr->username);
+		char *stripped_sender;
 		int signature_length = strlen(notice.z_message);
 		int message_has_no_body = 0;
 		PurpleMessageFlags flags = 0;
@@ -843,24 +849,23 @@
 			tmpescape = g_markup_escape_text(buf, -1);
 			g_free(buf);
 			buf2 = zephyr_to_html(tmpescape);
-			buf3 = zephyr_recv_convert(gc,buf2, strlen(buf2));
+			buf3 = zephyr_recv_convert(gc, buf2);
 			g_free(buf2);
 			g_free(tmpescape);
 		}
 
+		stripped_sender = zephyr_strip_local_realm(zephyr,notice.z_sender);
+
 		if (!g_ascii_strcasecmp(notice.z_class, "MESSAGE") && !g_ascii_strcasecmp(notice.z_class_inst, "PERSONAL") 
 		    && !g_ascii_strcasecmp(notice.z_recipient,zephyr->username)) {
-			gchar* stripped_sender;
 			if (!g_ascii_strcasecmp(notice.z_message, "Automated reply:"))
 				flags |= PURPLE_MESSAGE_AUTO_RESP;
-			stripped_sender = zephyr_strip_local_realm(zephyr,notice.z_sender);
 			
 			if (!g_ascii_strcasecmp(notice.z_opcode,"PING"))
 				serv_got_typing(gc,stripped_sender,ZEPHYR_TYPING_RECV_TIMEOUT, PURPLE_TYPING);
 			else
 				serv_got_im(gc, stripped_sender, buf3, flags, time(NULL));
 
-			g_free(stripped_sender);
 		} else {
 			zephyr_triple *zt1, *zt2;
 			gchar *send_inst_utf8;
@@ -878,15 +883,17 @@
 				serv_got_joined_chat(gc, zt2->id, zt2->name);
 				zephyr_chat_set_topic(gc,zt2->id,notice.z_class_inst);
 			}
-			g_free(sendertmp); /* fix memory leak? */
-			/* If the person is in the default Realm, then strip the 
-			   Realm from the sender field */
-			sendertmp = zephyr_strip_local_realm(zephyr,notice.z_sender);
-			send_inst = g_strdup_printf("%s %s",sendertmp,notice.z_class_inst);					
-			send_inst_utf8 = zephyr_recv_convert(gc,send_inst, strlen(send_inst));
-			if (!send_inst_utf8) {
-				purple_debug_error("zephyr","send_inst %s became null\n", send_inst);
-				send_inst_utf8 = "malformed instance";
+
+			if (!g_ascii_strcasecmp(notice.z_class_inst,"PERSONAL"))
+				send_inst_utf8 = g_strdup(stripped_sender);
+			else {
+				send_inst = g_strdup_printf("[%s] %s",notice.z_class_inst,stripped_sender);
+				send_inst_utf8 = zephyr_recv_convert(gc,send_inst);
+				g_free(send_inst);
+				if (!send_inst_utf8) {
+					purple_debug_error("zephyr","Failed to convert instance for sender %s.\n", stripped_sender);
+					send_inst_utf8 = g_strdup(stripped_sender);
+				}
 			}
 
 			gconv1 = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
@@ -895,24 +902,22 @@
 #ifndef INET_ADDRSTRLEN
 #define INET_ADDRSTRLEN 16
 #endif
-			if (!purple_conv_chat_find_user(gcc, sendertmp)) {
+			if (!purple_conv_chat_find_user(gcc, stripped_sender)) {
 				gchar ipaddr[INET_ADDRSTRLEN];
 #ifdef HAVE_INET_NTOP
 				inet_ntop(AF_INET, &notice.z_sender_addr.s_addr, ipaddr, sizeof(ipaddr));
 #else
 				memcpy(ipaddr,inet_ntoa(notice.z_sender_addr),sizeof(ipaddr));
 #endif
-				purple_conv_chat_add_user(gcc, sendertmp, ipaddr, PURPLE_CBFLAGS_NONE, TRUE);
+				purple_conv_chat_add_user(gcc, stripped_sender, ipaddr, PURPLE_CBFLAGS_NONE, TRUE);
 			}
-			g_free(sendertmp);
 			serv_got_chat_in(gc, zt2->id, send_inst_utf8, 0, buf3, time(NULL));
-			g_free(send_inst);
 			g_free(send_inst_utf8);
-				
+
 			free_triple(zt1);
 		}
+		g_free(stripped_sender);
 		g_free(buf3);
-		
 	}
 }
 
@@ -1142,6 +1147,7 @@
 				/* XXX fix */
 				char *user; 
 				PurpleBuddy *b;
+				const char *bname;
 				int nlocs = 0;
 				parse_tree *locations;
 				gchar *locval;
@@ -1161,15 +1167,18 @@
 					nlocs = 1;
 				}
 	
-				if ((b && pending_zloc(zephyr,b->name)) || pending_zloc(zephyr,user) || pending_zloc(zephyr,local_zephyr_normalize(zephyr,user))){
+				bname = b ? purple_buddy_get_name(b) : NULL;
+				if ((b && pending_zloc(zephyr,bname)) || pending_zloc(zephyr,user) || pending_zloc(zephyr,local_zephyr_normalize(zephyr,user))){
 					PurpleNotifyUserInfo *user_info = purple_notify_user_info_new();
 					char *tmp;
+					const char *balias;
 
-					purple_notify_user_info_add_pair(user_info, _("User"), (b ? b->name : user));
+					purple_notify_user_info_add_pair(user_info, _("User"), (b ? bname : user));
 
-					if (b && b->alias)
-						purple_notify_user_info_add_pair(user_info, _("Alias"), b->alias);
-											
+					balias = b ? purple_buddy_get_local_buddy_alias(b) : NULL;
+					if (balias)
+						purple_notify_user_info_add_pair(user_info, _("Alias"), balias);
+
 					if (!nlocs) {
 						purple_notify_user_info_add_pair(user_info, NULL, _("Hidden or not logged-in"));
 					} else {
@@ -1180,14 +1189,14 @@
 						g_free(tmp);
 					}
 
-					purple_notify_userinfo(gc, b ? b->name : user,
+					purple_notify_userinfo(gc, b ? bname : user,
 							     user_info, NULL, NULL);
 					purple_notify_user_info_destroy(user_info);
 				} else {
 					if (nlocs>0) 
-						purple_prpl_got_user_status(gc->account, b ? b->name : user, "available", NULL);
+						purple_prpl_got_user_status(gc->account, b ? bname : user, "available", NULL);
 					else 
-						purple_prpl_got_user_status(gc->account, b ? b->name : user, "offline", NULL);
+						purple_prpl_got_user_status(gc->account, b ? bname : user, "offline", NULL);
 				}
 			}
 			else if (!g_ascii_strncasecmp(spewtype,"subscribed",10)) {
@@ -1247,38 +1256,44 @@
 
 static gint check_loc(gpointer_data)
 {
-        PurpleBlistNode *gnode, *cnode, *bnode;
-        ZLocations_t locations;
-        int numlocs;
-        int one = 1;
+	PurpleBlistNode *gnode, *cnode, *bnode;
+	ZLocations_t locations;
+	int numlocs;
+	int one = 1;
 
-	for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
+	for (gnode = purple_blist_get_root(); gnode;
+			gnode = purple_blist_node_get_sibling_next(gnode)) {
 		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for (cnode = gnode->child; cnode; cnode = cnode->next) {
+		for (cnode = purple_blist_node_get_first_child(gnode);
+				cnode;
+				cnode = purple_blist_node_get_sibling_next(cnode)) {
 			if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			for (bnode = cnode->child; bnode; bnode = bnode->next) {
+			for (bnode = purple_blist_node_get_first_child(cnode);
+					bnode;
+					bnode = purple_blist_node_get_sibling_next(bnode)) {
 				PurpleBuddy *b = (PurpleBuddy *) bnode;
 
 				if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
-				if (b->account->gc == zgc) {
+				if (purple_buddy_get_account(b)->gc == zgc) {
 					char *chk;
-                                        chk = local_zephyr_normalize(b->name);
-                                        ZLocateUser(chk,&numlocs, ZAUTH);
-                                        if (numlocs) {
-                                                int i;
-                                                for(i=0;i<numlocs;i++) {
-                                                        ZGetLocations(&locations,&one);
-                                                        serv_got_update(zgc,b->name,1,0,0,0,0);
-                                                }
-                                        }
-                                }
-                        }
-                }
-        }
-        return TRUE;
+					const char *bname = purple_buddy_get_name(b);
+					chk = local_zephyr_normalize(bname);
+					ZLocateUser(chk,&numlocs, ZAUTH);
+					if (numlocs) {
+						int i;
+						for(i=0;i<numlocs;i++) {
+							ZGetLocations(&locations,&one);
+							serv_got_update(zgc,bname,1,0,0,0,0);
+						}
+					}
+				}
+			}
+		}
+	}
+	return TRUE;
 }
 
 #else
@@ -1289,6 +1304,7 @@
 	ZAsyncLocateData_t ald;
 	PurpleConnection *gc = (PurpleConnection *)data;
 	zephyr_account *zephyr = gc->proto_data;
+	PurpleAccount *account = purple_connection_get_account(gc);
 
 	if (use_zeph02(zephyr)) {
 		ald.user = NULL;
@@ -1296,22 +1312,28 @@
 		ald.version = NULL;
 	}
 
-	for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
+	for (gnode = purple_blist_get_root(); gnode;
+			gnode = purple_blist_node_get_sibling_next(gnode)) {
 		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for (cnode = gnode->child; cnode; cnode = cnode->next) {
+		for (cnode = purple_blist_node_get_first_child(gnode);
+				cnode;
+				cnode = purple_blist_node_get_sibling_next(cnode)) {
 			if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			for (bnode = cnode->child; bnode; bnode = bnode->next) {
+			for (bnode = purple_blist_node_get_first_child(cnode);
+					bnode;
+					bnode = purple_blist_node_get_sibling_next(bnode)) {
 				PurpleBuddy *b = (PurpleBuddy *) bnode;
 
 				if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
-				if (b->account->gc == gc) {
+				if (purple_buddy_get_account(b) == account) {
 					const char *chk;
+					const char *name = purple_buddy_get_name(b);
 
-					chk = local_zephyr_normalize(zephyr,b->name);
-					purple_debug_info("zephyr","chk: %s b->name %s\n",chk,b->name);
+					chk = local_zephyr_normalize(zephyr,name);
+					purple_debug_info("zephyr","chk: %s b->name %s\n",chk,name);
 					/* XXX add real error reporting */
 					/* doesn't matter if this fails or not; we'll just move on to the next one */
 					if (use_zeph02(zephyr)) {
@@ -1324,9 +1346,9 @@
 							for(i=0;i<numlocs;i++) {
 								ZGetLocations(&locations,&one);
 								if (nlocs>0) 
-									purple_prpl_got_user_status(gc->account,b->name,"available",NULL);
+									purple_prpl_got_user_status(account,name,"available",NULL);
 								else 
-									purple_prpl_got_user_status(gc->account,b->name,"offline",NULL);
+									purple_prpl_got_user_status(account,name,"offline",NULL);
 							}
 						}
 #else
@@ -1571,7 +1593,7 @@
 #ifdef WIN32
 	username = purple_account_get_username(account);
 #endif
-	gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_NO_URLDESC;
+	gc->flags |= PURPLE_CONNECTION_AUTO_RESP | PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_NO_URLDESC;
 	gc->proto_data = zephyr=g_new0(zephyr_account,1); 
 
 	zephyr->account = account;
@@ -1934,6 +1956,7 @@
 	PurpleBuddy *b;
 	char *fname;
 	FILE *fd;
+	PurpleAccount *account;
 	zephyr_account* zephyr = gc->proto_data;
 	fname = g_strdup_printf("%s/.anyone", purple_home_dir());
 	fd = g_fopen(fname, "w");
@@ -1942,18 +1965,25 @@
 		return;
 	}
 
-	for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
+	account = purple_connection_get_account(gc);
+	for (gnode = purple_blist_get_root();
+			gnode;
+			gnode = purple_blist_node_get_sibling_next(gnode)) {
 		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for (cnode = gnode->child; cnode; cnode = cnode->next) {
+		for (cnode = purple_blist_node_get_first_child(gnode);
+				cnode;
+				cnode = purple_blist_node_get_sibling_next(cnode)) {
 			if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			for (bnode = cnode->child; bnode; bnode = bnode->next) {
+			for (bnode = purple_blist_node_get_first_child(cnode);
+					bnode;
+					bnode = purple_blist_node_get_sibling_next(bnode)) {
 				if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
 				b = (PurpleBuddy *) bnode;
-				if (b->account == gc->account) {
-					gchar *stripped_user = zephyr_strip_local_realm(zephyr,b->name);
+				if (purple_buddy_get_account(b) == account) {
+					gchar *stripped_user = zephyr_strip_local_realm(zephyr, purple_buddy_get_name(b));
 					fprintf(fd, "%s\n", stripped_user);
 					g_free(stripped_user);
 				}
@@ -2496,26 +2526,31 @@
 	PurpleBlistNode *gnode, *cnode;
 
 	/* XXX needs to be %host%,%canon%, and %me% clean */
-	for(gnode = purple_get_blist()->root; gnode; gnode = gnode->next) {
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
+	for(gnode = purple_blist_get_root(); gnode;
+			gnode = purple_blist_node_get_sibling_next(gnode)) {
+		for(cnode = purple_blist_node_get_first_child(gnode);
+				cnode;
+				cnode = purple_blist_node_get_sibling_next(cnode)) {
 			PurpleChat *chat = (PurpleChat*)cnode;
 			char *zclass, *inst, *recip;
 			char** triple;
+			GHashTable *components;
 			if(!PURPLE_BLIST_NODE_IS_CHAT(cnode))
 				continue;
-			if(chat->account !=account)
-				continue;
-			if(!(zclass = g_hash_table_lookup(chat->components, "class")))
+			if(purple_chat_get_account(chat) != account)
 				continue;
-			if(!(inst = g_hash_table_lookup(chat->components, "instance")))
+			components = purple_chat_get_components(chat);
+			if(!(zclass = g_hash_table_lookup(components, "class")))
+				continue;
+			if(!(inst = g_hash_table_lookup(components, "instance")))
 				inst = g_strdup("");
-			if(!(recip = g_hash_table_lookup(chat->components, "recipient")))
+			if(!(recip = g_hash_table_lookup(components, "recipient")))
 				recip = g_strdup("");
 			/*			purple_debug_info("zephyr","in zephyr_find_blist_chat name: %s\n",name?name:""); */
 			triple = g_strsplit(name,",",3);
 			if (!g_ascii_strcasecmp(triple[0],zclass) && !g_ascii_strcasecmp(triple[1],inst) && !g_ascii_strcasecmp(triple[2],recip))
 				return chat;
-			
+
 		}
 	}
 	return NULL;
@@ -2580,7 +2615,7 @@
 												gc->account);
 	gcc = purple_conversation_get_chat_data(gconv);
 
-	topic_utf8 = zephyr_recv_convert(gc,(gchar *)topic,strlen(topic));
+	topic_utf8 = zephyr_recv_convert(gc,(gchar *)topic);
 	purple_conv_chat_set_topic(gcc,sender,topic_utf8);
 	g_free(topic_utf8);
 	return;
--- a/libpurple/proxy.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/proxy.c	Thu Nov 27 21:15:43 2008 +0000
@@ -944,12 +944,15 @@
 
 			} else if((header = g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: Basic"))) {
 				gchar *t1, *t2;
+				const char *username, *password;
+
+				username = purple_proxy_info_get_username(connect_data->gpi);
+				password = purple_proxy_info_get_password(connect_data->gpi);
 
 				t1 = g_strdup_printf("%s:%s",
-					purple_proxy_info_get_username(connect_data->gpi),
-					purple_proxy_info_get_password(connect_data->gpi) ?
-					purple_proxy_info_get_password(connect_data->gpi) : "");
-				t2 = purple_base64_encode((const guchar *)t1, strlen(t1));
+									 username ? username : "",
+									 password ? password : "");
+				t2 = purple_base64_encode((guchar *)t1, strlen(t1));
 				g_free(t1);
 
 				request = g_strdup_printf(
--- a/libpurple/request.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/request.c	Thu Nov 27 21:15:43 2008 +0000
@@ -23,6 +23,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+#define _PURPLE_REQUEST_C_
+
 #include "internal.h"
 
 #include "notify.h"
@@ -137,6 +139,23 @@
 	return purple_request_field_is_required(field);
 }
 
+gpointer
+purple_request_field_get_ui_data(const PurpleRequestField *field)
+{
+	g_return_val_if_fail(field != NULL, NULL);
+
+	return field->ui_data;
+}
+
+void
+purple_request_field_set_ui_data(PurpleRequestField *field,
+                                 gpointer ui_data)
+{
+	g_return_if_fail(field != NULL);
+
+	field->ui_data = ui_data;
+}
+
 gboolean
 purple_request_fields_all_required_filled(const PurpleRequestFields *fields)
 {
@@ -443,6 +462,14 @@
 	return field->type;
 }
 
+PurpleRequestFieldGroup *
+purple_request_field_get_group(const PurpleRequestField *field)
+{
+	g_return_val_if_fail(field != NULL, NULL);
+
+	return field->group;
+}
+
 const char *
 purple_request_field_get_id(const PurpleRequestField *field)
 {
@@ -887,7 +914,7 @@
 	purple_request_field_list_clear_selected(field);
 
 	if (!purple_request_field_list_get_multi_select(field) &&
-		g_list_length(items) > 1)
+		items && items->next)
 	{
 		purple_debug_warning("request",
 						   "More than one item added to non-multi-select "
--- a/libpurple/request.h	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/request.h	Thu Nov 27 21:15:43 2008 +0000
@@ -30,6 +30,9 @@
 #include <glib-object.h>
 #include <glib.h>
 
+/** @copydoc _PurpleRequestField */
+typedef struct _PurpleRequestField PurpleRequestField;
+
 #include "account.h"
 
 #define PURPLE_DEFAULT_ACTION_NONE	-1
@@ -93,10 +96,11 @@
 
 } PurpleRequestFieldGroup;
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_REQUEST_C_)
 /**
  * A request field.
  */
-typedef struct
+struct _PurpleRequestField
 {
 	PurpleRequestFieldType type;
 	PurpleRequestFieldGroup *group;
@@ -176,7 +180,8 @@
 
 	void *ui_data;
 
-} PurpleRequestField;
+};
+#endif
 
 /**
  * Request UI operations.
@@ -521,6 +526,16 @@
 PurpleRequestFieldType purple_request_field_get_type(const PurpleRequestField *field);
 
 /**
+ * Returns the group for the field.
+ *
+ * @param field The field.
+ *
+ * @return The UI data.
+ * @since 2.6.0
+ */
+PurpleRequestFieldGroup *purple_request_field_get_group(const PurpleRequestField *field);
+
+/**
  * Returns the ID of a field.
  *
  * @param field The field.
@@ -565,6 +580,28 @@
  */
 gboolean purple_request_field_is_required(const PurpleRequestField *field);
 
+/**
+ * Returns the ui_data for a field.
+ *
+ * @param field The field.
+ *
+ * @return The UI data.
+ * @since 2.6.0
+ */
+gpointer purple_request_field_get_ui_data(const PurpleRequestField *field);
+
+/**
+ * Sets the ui_data for a field.
+ *
+ * @param field The field.
+ * @param ui_data The UI data.
+ *
+ * @return The UI data.
+ * @since 2.6.0
+ */
+void purple_request_field_set_ui_data(PurpleRequestField *field,
+                                      gpointer ui_data);
+
 /*@}*/
 
 /**************************************************************************/
--- a/libpurple/roomlist.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/roomlist.c	Thu Nov 27 21:15:43 2008 +0000
@@ -265,6 +265,11 @@
 	g_return_if_fail(room != NULL);
 	g_return_if_fail(list->fields != NULL);
 
+	/* If this is the first call for this room, grab the first field in
+	 * the Roomlist's fields.  Otherwise, grab the field that is one
+	 * more than the number of fields already present for the room.
+         * (This works because g_list_nth_data() is zero-indexed and
+         * g_list_length() is one-indexed.) */
 	if (!room->fields)
 		f = list->fields->data;
 	else
--- a/libpurple/server.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/server.c	Thu Nov 27 21:15:43 2008 +0000
@@ -230,7 +230,7 @@
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
 	if(b && prpl_info && prpl_info->alias_buddy) {
-		prpl_info->alias_buddy(gc, b->name, b->alias);
+		prpl_info->alias_buddy(gc, purple_buddy_get_name(b), purple_buddy_get_local_buddy_alias(b));
 	}
 }
 
@@ -247,18 +247,21 @@
 
 	while (buddies != NULL)
 	{
+		const char *server_alias;
+
 		b = buddies->data;
 		buddies = g_slist_delete_link(buddies, buddies);
 
-		if((b->server_alias == NULL && alias == NULL) ||
-		    (b->server_alias && alias && !strcmp(b->server_alias, alias)))
+		server_alias = purple_buddy_get_server_alias(b);
+		if((server_alias == NULL && alias == NULL) ||
+		    (server_alias && alias && !strcmp(server_alias, alias)))
 		{
 			continue;
 		}
 
 		purple_blist_server_alias_buddy(b, alias);
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, b->name, account);
+		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, purple_buddy_get_name(b), account);
 		if(conv != NULL && alias != NULL &&
 		   who != NULL && strcmp(alias, who))
 		{
@@ -289,11 +292,13 @@
 	buddies = purple_find_buddies(account, who);
 
 	while(buddies != NULL) {
+		const char *balias;
 		b = buddies->data;
 
 		buddies = g_slist_delete_link(buddies, buddies);
 
-		if((!b->alias && !alias) || (b->alias && alias && !strcmp(b->alias, alias)))
+		balias = purple_buddy_get_local_buddy_alias(b);
+		if((!balias && !alias) || (balias && alias && !strcmp(balias, alias)))
 			continue;
 
 		purple_blist_alias_buddy(b, alias);
@@ -367,7 +372,9 @@
 
 	if(gc && og && ng) {
 		if (prpl_info && prpl_info->group_buddy) {
-			prpl_info->group_buddy(gc, b->name, og->name, ng->name);
+			prpl_info->group_buddy(gc, purple_buddy_get_name(b),
+			                       purple_group_get_name(og),
+								   purple_group_get_name(ng));
 		}
 	}
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/sound-theme-loader.c	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,115 @@
+/*
+ * SoundThemeLoader for LibPurple
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+#include "sound-theme-loader.h"
+#include "sound-theme.h"
+#include "util.h"
+#include "xmlnode.h"
+
+/*****************************************************************************
+ * Sound Theme Builder                                                      
+ *****************************************************************************/
+
+static PurpleTheme *
+purple_sound_loader_build(const gchar *dir)
+{
+	xmlnode *root_node = NULL, *sub_node;
+	gchar *filename_full, *data;
+	PurpleSoundTheme *theme = NULL;
+
+	/* Find the theme file */
+	g_return_val_if_fail(dir != NULL, NULL);
+	filename_full = g_build_filename(dir, "theme.xml", NULL);
+
+	if (g_file_test(filename_full, G_FILE_TEST_IS_REGULAR))
+		root_node = xmlnode_from_file(dir, "theme.xml", "sound themes", "sound-loader");
+
+	g_free(filename_full);
+	g_return_val_if_fail(root_node != NULL, NULL);
+
+	/* Parse the tree */	
+	sub_node = xmlnode_get_child(root_node, "description");
+	data = xmlnode_get_data(sub_node);
+
+	if (xmlnode_get_attrib(root_node, "name") != NULL) {
+		theme = g_object_new(PURPLE_TYPE_SOUND_THEME,
+				    "type", "sound",
+				    "name", xmlnode_get_attrib(root_node, "name"),
+				    "author", xmlnode_get_attrib(root_node, "author"),
+				    "image", xmlnode_get_attrib(root_node, "image"),
+				    "directory", dir,
+				    "description", data, NULL);
+
+		sub_node = xmlnode_get_child(root_node, "event");
+
+		while (sub_node) {
+			purple_sound_theme_set_file(theme,
+						    xmlnode_get_attrib(sub_node, "name"),
+						    xmlnode_get_attrib(sub_node, "file"));
+			sub_node = xmlnode_get_next_twin(sub_node);
+		}
+	}
+
+	xmlnode_free(root_node);	
+	g_free(data);
+	return PURPLE_THEME(theme);
+}
+
+/******************************************************************************
+ * GObject Stuff                                                              
+ *****************************************************************************/
+
+static void
+purple_sound_theme_loader_class_init(PurpleSoundThemeLoaderClass *klass)
+{
+	PurpleThemeLoaderClass *loader_klass = PURPLE_THEME_LOADER_CLASS(klass);
+
+	loader_klass->purple_theme_loader_build = purple_sound_loader_build;
+}
+
+
+GType 
+purple_sound_theme_loader_get_type(void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (PurpleSoundThemeLoaderClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      (GClassInitFunc)purple_sound_theme_loader_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (PurpleSoundThemeLoader),
+      0,      /* n_preallocs */
+      NULL,    /* instance_init */
+      NULL,   /* value table */
+    };
+    type = g_type_register_static(PURPLE_TYPE_THEME_LOADER,
+                                   "PurpleSoundThemeLoader",
+                                   &info, 0);
+  }
+  return type;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/sound-theme-loader.h	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,71 @@
+/**
+ * @file sound-loader.h  Purple Sound Theme Loader Class API
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PURPLE_SOUND_THEME_LOADER_H_
+#define _PURPLE_SOUND_THEME_LOADER_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include "theme-loader.h"
+
+/**
+ * A purple sound theme loader. extends PurpleThemeLoader (theme-loader.h)
+ * This is a class designed to build sound themes
+ *
+ * PurpleSoundThemeLoader is a GObject.
+ */
+typedef struct _PurpleSoundThemeLoader        PurpleSoundThemeLoader;
+typedef struct _PurpleSoundThemeLoaderClass   PurpleSoundThemeLoaderClass;
+
+#define PURPLE_TYPE_SOUND_THEME_LOADER			  (purple_sound_theme_loader_get_type ())
+#define PURPLE_SOUND_THEME_LOADER(obj)			  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PURPLE_TYPE_SOUND_THEME_LOADER, PurpleSoundThemeLoader))
+#define PURPLE_SOUND_THEME_LOADER_CLASS(klass)		  (G_TYPE_CHECK_CLASS_CAST ((klass), PURPLE_TYPE_SOUND_THEME_LOADER, PurpleSoundThemeLoaderClass))
+#define PURPLE_IS_SOUND_THEME_LOADER(obj)	  	  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PURPLE_TYPE_SOUND_THEME_LOADER))
+#define PURPLE_IS_SOUND_THEME_LOADER_CLASS(klass) 	  (G_TYPE_CHECK_CLASS_TYPE ((klass), PURPLE_TYPE_SOUND_THEME_LOADER))
+#define PURPLE_SOUND_THEME_LOADER_GET_CLASS(obj)  	  (G_TYPE_INSTANCE_GET_CLASS ((obj), PURPLE_TYPE_SOUND_THEME_LOADER, PurpleSoundThemeLoaderClass))
+
+struct _PurpleSoundThemeLoader
+{
+	PurpleThemeLoader parent;
+};
+
+struct _PurpleSoundThemeLoaderClass
+{
+	PurpleThemeLoaderClass parent_class;
+};
+
+/**************************************************************************/
+/** @name Purple Theme-Loader API                                         */
+/**************************************************************************/
+G_BEGIN_DECLS
+
+/**
+ * GObject foo.
+ * @internal.
+ */
+GType purple_sound_theme_loader_get_type(void);
+
+G_END_DECLS
+#endif /* _PURPLE_SOUND_THEME_LOADER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/sound-theme.c	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,163 @@
+/*
+ * Sound Themes for LibPurple
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+#include "sound-theme.h"
+
+#define PURPLE_SOUND_THEME_GET_PRIVATE(Gobject) \
+	((PurpleSoundThemePrivate *) ((PURPLE_SOUND_THEME(Gobject))->priv))
+
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+typedef struct {
+	/* used to store filenames of diffrent sounds */
+	GHashTable *sound_files;
+} PurpleSoundThemePrivate;
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+
+/******************************************************************************
+ * GObject Stuff                                                              
+ *****************************************************************************/
+
+static void
+purple_sound_theme_init(GTypeInstance *instance,
+			gpointer klass)
+{
+	PurpleSoundThemePrivate *priv;
+
+	(PURPLE_SOUND_THEME(instance))->priv = g_new0(PurpleSoundThemePrivate, 1);
+
+	priv = PURPLE_SOUND_THEME_GET_PRIVATE(instance);
+
+	priv->sound_files = g_hash_table_new_full (g_str_hash,
+						   g_str_equal,
+						   g_free,
+						   g_free);
+}
+
+static void 
+purple_sound_theme_finalize (GObject *obj)
+{
+	PurpleSoundThemePrivate *priv;
+
+	priv = PURPLE_SOUND_THEME_GET_PRIVATE(obj);
+	
+	g_hash_table_destroy(priv->sound_files);
+
+	parent_class->finalize (obj);
+}
+
+static void
+purple_sound_theme_class_init (PurpleSoundThemeClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+        obj_class->finalize = purple_sound_theme_finalize;
+}
+
+GType 
+purple_sound_theme_get_type (void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (PurpleSoundThemeClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      (GClassInitFunc)purple_sound_theme_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (PurpleSoundTheme),
+      0,      /* n_preallocs */
+      purple_sound_theme_init,    /* instance_init */
+      NULL,   /* value table */
+    };
+    type = g_type_register_static (PURPLE_TYPE_THEME,
+                                   "PurpleSoundTheme",
+                                   &info, 0);
+  }
+  return type;
+}
+
+
+/*****************************************************************************
+ * Public API functions                                                      
+ *****************************************************************************/
+
+const gchar *
+purple_sound_theme_get_file(PurpleSoundTheme *theme,
+			    const gchar *event)
+{
+	PurpleSoundThemePrivate *priv;
+
+	g_return_val_if_fail(PURPLE_IS_SOUND_THEME(theme), NULL);
+
+	priv = PURPLE_SOUND_THEME_GET_PRIVATE(theme);
+	
+	return g_hash_table_lookup(priv->sound_files, event);
+}
+
+gchar *
+purple_sound_theme_get_file_full(PurpleSoundTheme *theme,
+				 const gchar *event)
+{
+	const gchar *filename;
+
+	g_return_val_if_fail(PURPLE_IS_SOUND_THEME(theme), NULL);
+
+	filename = purple_sound_theme_get_file(theme, event);
+	
+	g_return_val_if_fail(filename, NULL);
+
+	return g_build_filename(purple_theme_get_dir(PURPLE_THEME(theme)), filename, NULL);
+}
+
+void 
+purple_sound_theme_set_file(PurpleSoundTheme *theme,
+			    const gchar *event, 
+			    const gchar *filename)
+{
+	PurpleSoundThemePrivate *priv;
+	g_return_if_fail(PURPLE_IS_SOUND_THEME(theme));
+	
+	priv = PURPLE_SOUND_THEME_GET_PRIVATE(theme);
+
+	if (filename != NULL)g_hash_table_replace(priv->sound_files,
+                 	             g_strdup(event),
+                        	     g_strdup(filename));
+	else g_hash_table_remove(priv->sound_files, event);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/sound-theme.h	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,102 @@
+/**
+ * @file sound-theme.h  Purple Sound Theme Abstact Class API
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PURPLE_SOUND_THEME_H_
+#define _PURPLE_SOUND_THEME_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include "theme.h"
+#include "sound.h"
+
+/**
+ * extends PurpleTheme (theme.h)
+ * A purple sound theme.
+ * This is an object for Purple to represent a sound theme.
+ *
+ * PurpleSoundTheme is a PurpleTheme Object.
+ */
+typedef struct _PurpleSoundTheme        PurpleSoundTheme;
+typedef struct _PurpleSoundThemeClass   PurpleSoundThemeClass;
+
+#define PURPLE_TYPE_SOUND_THEME		  	(purple_sound_theme_get_type ())
+#define PURPLE_SOUND_THEME(obj)		  	(G_TYPE_CHECK_INSTANCE_CAST ((obj), PURPLE_TYPE_SOUND_THEME, PurpleSoundTheme))
+#define PURPLE_SOUND_THEME_CLASS(klass)	  	(G_TYPE_CHECK_CLASS_CAST ((klass), PURPLE_TYPE_SOUND_THEME, PurpleSoundThemeClass))
+#define PURPLE_IS_SOUND_THEME(obj)	  	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), PURPLE_TYPE_SOUND_THEME))
+#define PURPLE_IS_SOUND_THEME_CLASS(klass) 	(G_TYPE_CHECK_CLASS_TYPE ((klass), PURPLE_TYPE_SOUND_THEME))
+#define PURPLE_SOUND_THEME_GET_CLASS(obj)  	(G_TYPE_INSTANCE_GET_CLASS ((obj), PURPLE_TYPE_SOUND_THEME, PurpleSoundThemeClass))
+
+struct _PurpleSoundTheme
+{
+	PurpleTheme parent;
+	gpointer priv;
+};
+
+struct _PurpleSoundThemeClass
+{
+	PurpleThemeClass parent_class;
+};
+
+/**************************************************************************/
+/** @name Purple Sound Theme API                                          */
+/**************************************************************************/
+G_BEGIN_DECLS
+
+/**
+ * GObject foo.
+ * @internal.
+ */
+GType purple_sound_theme_get_type(void);
+
+/**
+ * Returns a copy of the filename for the sound event
+ *
+ * @param event		the purple sound event to look up
+ *
+ * @returns the filename of the sound event
+ */
+const gchar *purple_sound_theme_get_file(PurpleSoundTheme *theme,
+				   const gchar *event);
+/**
+ * Returns a copy of the directory and filename for the sound event
+ *
+ * @param event		the purple sound event to look up
+ *
+ * @returns the directory + '/' + filename of the sound event
+ */
+gchar *purple_sound_theme_get_file_full(PurpleSoundTheme *theme,
+					const gchar *event);
+/**
+ * Sets the filename for a given sound event
+ *
+ * @param event		the purple sound event to look up
+ * @param filename		the name of the file to be used for the event
+ */
+void purple_sound_theme_set_file(PurpleSoundTheme *theme,
+				const gchar *event, 
+			    	const gchar *filename);
+
+G_END_DECLS
+#endif /* _PURPLE_SOUND_THEME_H_ */
--- a/libpurple/sound.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/sound.c	Thu Nov 27 21:15:43 2008 +0000
@@ -25,6 +25,8 @@
 #include "blist.h"
 #include "prefs.h"
 #include "sound.h"
+#include "sound-theme-loader.h"
+#include "theme-manager.h"
 
 static PurpleSoundUiOps *sound_ui_ops = NULL;
 
@@ -134,6 +136,8 @@
 	purple_prefs_add_none("/purple/sound");
 	purple_prefs_add_int("/purple/sound/while_status", STATUS_AVAILABLE);
 	memset(last_played, 0, sizeof(last_played));
+
+	purple_theme_manager_register_type(g_object_new(PURPLE_TYPE_SOUND_THEME_LOADER, "type", "sound", NULL));
 }
 
 void
--- a/libpurple/status.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/status.c	Thu Nov 27 21:15:43 2008 +0000
@@ -612,7 +612,8 @@
 
 		if (old_status != NULL)
 		{
-			tmp = g_strdup_printf(_("%s (%s) changed status from %s to %s"), buddy_alias, buddy->name,
+			tmp = g_strdup_printf(_("%s (%s) changed status from %s to %s"), buddy_alias,
+			                      purple_buddy_get_name(buddy),
 			                      purple_status_get_name(old_status),
 			                      purple_status_get_name(new_status));
 			logtmp = g_markup_escape_text(tmp, -1);
@@ -623,19 +624,21 @@
 
 			if (purple_status_is_active(new_status))
 			{
-				tmp = g_strdup_printf(_("%s (%s) is now %s"), buddy_alias, buddy->name,
+				tmp = g_strdup_printf(_("%s (%s) is now %s"), buddy_alias,
+				                      purple_buddy_get_name(buddy),
 				                      purple_status_get_name(new_status));
 				logtmp = g_markup_escape_text(tmp, -1);
 			}
 			else
 			{
-				tmp = g_strdup_printf(_("%s (%s) is no longer %s"), buddy_alias, buddy->name,
+				tmp = g_strdup_printf(_("%s (%s) is no longer %s"), buddy_alias,
+				                      purple_buddy_get_name(buddy),
 				                      purple_status_get_name(new_status));
 				logtmp = g_markup_escape_text(tmp, -1);
 			}
 		}
 
-		log = purple_account_get_log(buddy->account, FALSE);
+		log = purple_account_get_log(purple_buddy_get_account(buddy), FALSE);
 		if (log != NULL)
 		{
 			purple_log_write(log, PURPLE_MESSAGE_SYSTEM, buddy_alias,
@@ -1132,13 +1135,13 @@
 	PurpleAccount *account;
 
 	g_return_val_if_fail(buddy != NULL, NULL);
-	account = buddy->account;
+	account = purple_buddy_get_account(buddy);
 
 	presence = purple_presence_new(PURPLE_PRESENCE_CONTEXT_BUDDY);
 
-	presence->u.buddy.name    = g_strdup(buddy->name);
-	presence->u.buddy.account = buddy->account;
-	presence->statuses = purple_prpl_get_statuses(buddy->account, presence);
+	presence->u.buddy.name    = g_strdup(purple_buddy_get_name(buddy));
+	presence->u.buddy.account = account;
+	presence->statuses = purple_prpl_get_statuses(account, presence);
 
 	presence->u.buddy.buddy = buddy;
 
@@ -1234,12 +1237,13 @@
 		time_t current_time, gboolean old_idle, gboolean idle)
 {
 	PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+	PurpleAccount *account = purple_buddy_get_account(buddy);
 
 	if (!old_idle && idle)
 	{
 		if (purple_prefs_get_bool("/purple/logging/log_system"))
 		{
-			PurpleLog *log = purple_account_get_log(buddy->account, FALSE);
+			PurpleLog *log = purple_account_get_log(account, FALSE);
 
 			if (log != NULL)
 			{
@@ -1259,7 +1263,7 @@
 	{
 		if (purple_prefs_get_bool("/purple/logging/log_system"))
 		{
-			PurpleLog *log = purple_account_get_log(buddy->account, FALSE);
+			PurpleLog *log = purple_account_get_log(account, FALSE);
 
 			if (log != NULL)
 			{
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/theme-loader.c	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,186 @@
+/*
+ * ThemeLoaders for LibPurple
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+#include "theme-loader.h"
+
+#define PURPLE_THEME_LOADER_GET_PRIVATE(PurpleThemeLoader) \
+	((PurpleThemeLoaderPrivate *) ((PurpleThemeLoader)->priv))
+
+void purple_theme_loader_set_type_string(PurpleThemeLoader *loader, const gchar *type);
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+typedef struct {
+	gchar *type;
+} PurpleThemeLoaderPrivate;
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+
+enum {
+	PROP_ZERO = 0,
+	PROP_TYPE,
+};
+
+/******************************************************************************
+ * GObject Stuff                                                              *
+ *****************************************************************************/
+
+static void
+purple_theme_loader_get_property(GObject *obj, guint param_id, GValue *value,
+						 GParamSpec *psec)
+{
+	PurpleThemeLoader *theme_loader = PURPLE_THEME_LOADER(obj);
+
+	switch(param_id) {
+		case PROP_TYPE:
+			g_value_set_string(value, purple_theme_loader_get_type_string(theme_loader));
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, psec);
+			break;
+	}
+}
+
+static void
+purple_theme_loader_set_property(GObject *obj, guint param_id, const GValue *value,
+						 GParamSpec *psec)
+{
+	PurpleThemeLoader *loader = PURPLE_THEME_LOADER(obj);
+
+	switch(param_id) {
+		case PROP_TYPE:
+			purple_theme_loader_set_type_string(loader, g_value_get_string(value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, psec);
+			break;
+	}
+}
+
+static void
+purple_theme_loader_init(GTypeInstance *instance,
+			gpointer klass)
+{
+	PurpleThemeLoader *loader = PURPLE_THEME_LOADER(instance);
+	loader->priv = g_new0(PurpleThemeLoaderPrivate, 1);
+}
+
+static void
+purple_theme_loader_finalize(GObject *obj)
+{
+	PurpleThemeLoader *loader = PURPLE_THEME_LOADER(obj);	
+	PurpleThemeLoaderPrivate *priv = PURPLE_THEME_LOADER_GET_PRIVATE(loader);
+
+	g_free(priv->type);
+
+	parent_class->finalize (obj);
+}
+
+static void
+purple_theme_loader_class_init (PurpleThemeLoaderClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	GParamSpec *pspec;
+	
+	parent_class = g_type_class_peek_parent (klass);
+
+	obj_class->get_property = purple_theme_loader_get_property;
+	obj_class->set_property = purple_theme_loader_set_property;
+	obj_class->finalize = purple_theme_loader_finalize;
+
+	/* TYPE STRING (read only) */
+	pspec = g_param_spec_string("type", "Type",
+				    "The string represtenting the type of the theme",
+				    NULL,
+				    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+	g_object_class_install_property(obj_class, PROP_TYPE, pspec);
+}
+
+
+GType 
+purple_theme_loader_get_type (void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (PurpleThemeLoaderClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      (GClassInitFunc)purple_theme_loader_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (PurpleThemeLoader),
+      0,      /* n_preallocs */
+      purple_theme_loader_init,    /* instance_init */
+      NULL,   /* value table */
+    };
+    type = g_type_register_static (G_TYPE_OBJECT,
+                                   "PurpleThemeLoader",
+                                   &info, G_TYPE_FLAG_ABSTRACT);
+  }
+  return type;
+}
+
+
+/*****************************************************************************
+ * Public API functions                                                      
+ *****************************************************************************/
+
+
+const gchar *
+purple_theme_loader_get_type_string (PurpleThemeLoader *theme_loader)
+{
+	PurpleThemeLoaderPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_THEME_LOADER(theme_loader), NULL);
+
+	priv = PURPLE_THEME_LOADER_GET_PRIVATE(theme_loader);
+	return priv->type;
+}
+
+/* < private > */
+void
+purple_theme_loader_set_type_string(PurpleThemeLoader *loader, const gchar *type)
+{
+	PurpleThemeLoaderPrivate *priv;
+
+	g_return_if_fail(PURPLE_IS_THEME_LOADER(loader));
+
+	priv = PURPLE_THEME_LOADER_GET_PRIVATE(loader);
+
+	g_free(priv->type);
+	priv->type = g_strdup(type);
+}
+
+PurpleTheme *
+purple_theme_loader_build(PurpleThemeLoader *loader, const gchar *dir)
+{
+	return PURPLE_THEME_LOADER_GET_CLASS(loader)->purple_theme_loader_build(dir);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/theme-loader.h	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,92 @@
+/**
+ * @file theme-loader.h  Purple Theme Loader Abstact Class API
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PURPLE_THEME_LOADER_H_
+#define _PURPLE_THEME_LOADER_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include "theme.h"
+
+/**
+ * A purple theme loader.
+ * This is an abstract class for Purple to use with the Purple theme manager.
+ * The loader is responsible for building each type of theme
+ *
+ * PurpleThemeLoader is a GObject.
+ */
+typedef struct _PurpleThemeLoader        PurpleThemeLoader;
+typedef struct _PurpleThemeLoaderClass   PurpleThemeLoaderClass;
+
+#define PURPLE_TYPE_THEME_LOADER		  (purple_theme_loader_get_type ())
+#define PURPLE_THEME_LOADER(obj)	 	  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PURPLE_TYPE_THEME_LOADER, PurpleThemeLoader))
+#define PURPLE_THEME_LOADER_CLASS(klass)	  (G_TYPE_CHECK_CLASS_CAST ((klass), PURPLE_TYPE_THEME_LOADER, PurpleThemeLoaderClass))
+#define PURPLE_IS_THEME_LOADER(obj)	  	  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PURPLE_TYPE_THEME_LOADER))
+#define PURPLE_IS_THEME_LOADER_CLASS(klass) 	  (G_TYPE_CHECK_CLASS_TYPE ((klass), PURPLE_TYPE_THEME_LOADER))
+#define PURPLE_THEME_LOADER_GET_CLASS(obj)  	  (G_TYPE_INSTANCE_GET_CLASS ((obj), PURPLE_TYPE_THEME_LOADER, PurpleThemeLoaderClass))
+
+struct _PurpleThemeLoader
+{
+	GObject parent;
+	gpointer priv;
+};
+
+struct _PurpleThemeLoaderClass
+{
+	GObjectClass parent_class;
+	PurpleTheme *((*purple_theme_loader_build)(const gchar*));
+};
+
+/**************************************************************************/
+/** @name Purple Theme-Loader API                                         */
+/**************************************************************************/
+G_BEGIN_DECLS
+
+/**
+ * GObject foo.
+ * @internal.
+ */
+GType purple_theme_loader_get_type(void);
+
+/**
+ * Returns the string represtenting the type of the theme loader
+ *
+ * @param self 		the theme loader
+ *
+ * @returns 		the string represting this type
+ */
+const gchar *purple_theme_loader_get_type_string(PurpleThemeLoader *self);
+
+/**
+ * Creates a new PurpleTheme
+ *
+ * @param dir 		the directory containing the theme
+ *
+ * @returns 		PurpleTheme containing the information from the directory
+ */
+PurpleTheme *purple_theme_loader_build(PurpleThemeLoader *loader, const gchar *dir);
+
+G_END_DECLS
+#endif /* _PURPLE_THEME_LOADER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/theme-manager.c	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,302 @@
+/*
+ * Themes for LibPurple
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+#include <string.h>
+
+#include "theme-manager.h"
+#include "util.h"
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+
+static GHashTable *theme_table = NULL;
+
+/*****************************************************************************
+ * GObject Stuff                                                     
+ ****************************************************************************/
+
+GType 
+purple_theme_manager_get_type(void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (PurpleThemeManagerClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      NULL,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (PurpleThemeManager),
+      0,      /* n_preallocs */
+      NULL,    /* instance_init */
+      NULL,   /* Value Table */
+    };
+    type = g_type_register_static(G_TYPE_OBJECT,
+                                   "PurpleThemeManager",
+                                   &info, 0);
+  }
+  return type;
+}
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+/* makes a key of <type> + '/' + <name> */
+static gchar *
+purple_theme_manager_make_key(const gchar *name, const gchar *type)
+{
+	g_return_val_if_fail(name && strlen(name), NULL);
+	g_return_val_if_fail(type && strlen(type), NULL);		
+	return g_strconcat(type, "/", name, NULL);
+}
+
+/* returns TRUE if theme is of type "user_data" */ 
+static gboolean
+purple_theme_manager_is_theme_type(gchar *key,
+                  gpointer value,
+                  gchar *user_data)
+{
+	return g_str_has_prefix(key, g_strconcat(user_data, "/", NULL));
+}
+
+static gboolean
+purple_theme_manager_is_theme(gchar *key,
+                  gpointer value,
+                  gchar *user_data)
+{
+	return PURPLE_IS_THEME(value);
+}
+
+static void
+purple_theme_manager_function_wrapper(gchar *key,
+                  		      gpointer value,
+                		      PTFunc user_data)
+{
+	if (PURPLE_IS_THEME(value))
+		(* user_data)(value);
+}
+
+static void
+purple_theme_manager_build_dir(const gchar *root)
+{
+
+	gchar *purple_dir, *theme_dir;
+	const gchar *name = NULL, *type = NULL;
+	GDir *rdir, *tdir;
+	PurpleThemeLoader *loader;
+
+	rdir = g_dir_open(root, 0, NULL);
+
+	g_return_if_fail(rdir);
+
+	/* Parses directory by root/name/purple/type */
+	while((name = g_dir_read_name(rdir))) {
+		purple_dir = g_build_filename(root, name, "purple", NULL);
+		tdir =  g_dir_open(purple_dir, 0, NULL);
+	
+		if(!tdir) {
+			g_free(purple_dir);
+
+			continue;
+		}
+
+		while((type = g_dir_read_name(tdir))) {
+			if((loader = g_hash_table_lookup(theme_table, type))) {
+				PurpleTheme *theme = NULL;
+
+				theme_dir = g_build_filename(purple_dir, type, NULL);
+
+				theme = purple_theme_loader_build(loader, theme_dir);
+
+				if(PURPLE_IS_THEME(theme))
+					purple_theme_manager_add_theme(theme);
+			}
+		}
+
+		g_dir_close(tdir);
+		g_free(purple_dir);
+	}
+
+	g_dir_close(rdir);
+}
+
+/*****************************************************************************
+ * Public API functions                                                      *
+ *****************************************************************************/
+
+void
+purple_theme_manager_init(void)
+{
+	theme_table = g_hash_table_new_full(g_str_hash,
+               	                             g_str_equal,
+               	                             g_free,
+               	                             g_object_unref);
+}
+
+void 
+purple_theme_manager_refresh()
+{
+	gchar *path = NULL;
+	const gchar *xdg = NULL;
+	gint i = 0;
+
+	g_hash_table_foreach_remove(theme_table,
+                	            (GHRFunc) purple_theme_manager_is_theme,
+                	            NULL);
+
+	/* Add themes from ~/.purple */
+	path = g_build_filename(purple_user_dir(), "themes", NULL);
+	purple_theme_manager_build_dir(path);
+	g_free(path);
+
+	/* look for XDG_DATA_HOME.  If we don't have it use ~/.local, and add it */
+	if((xdg = g_getenv("XDG_DATA_HOME")) != NULL)
+		path = g_build_filename(xdg, "themes", NULL);
+	else
+		path = g_build_filename(purple_home_dir(), ".local", "themes", NULL);
+
+	purple_theme_manager_build_dir(path);
+	g_free(path);
+
+	/* now dig through XDG_DATA_DIRS and add those too */
+	xdg = g_getenv("XDG_DATA_DIRS");
+	if(xdg) {
+		gchar **xdg_dirs = g_strsplit(xdg, G_SEARCHPATH_SEPARATOR_S, 0);
+
+		for(i = 0; xdg_dirs[i]; i++) {
+			path = g_build_filename(xdg_dirs[i], "themes", NULL);
+			purple_theme_manager_build_dir(path);
+			g_free(path);
+		}
+
+		g_strfreev(xdg_dirs);
+	}
+}
+
+void 
+purple_theme_manager_uninit()
+{
+	g_hash_table_destroy(theme_table);
+}
+
+
+void
+purple_theme_manager_register_type(PurpleThemeLoader *loader)
+{
+	gchar *type;
+
+	g_return_if_fail(PURPLE_IS_THEME_LOADER(loader));
+
+	type = g_strdup(purple_theme_loader_get_type_string(loader));
+	g_return_if_fail(type);
+
+	/* if something is already there do nothing */
+	if (! g_hash_table_lookup(theme_table, type)) 
+		g_hash_table_insert(theme_table, type, loader);
+}
+
+void
+purple_theme_manager_unregister_type(PurpleThemeLoader *loader)
+{
+	const gchar *type;
+
+	g_return_if_fail(PURPLE_IS_THEME_LOADER(loader));
+
+	type = purple_theme_loader_get_type_string(loader);
+	g_return_if_fail(type);
+
+	if (g_hash_table_lookup(theme_table, type) == loader){
+
+		g_hash_table_remove(theme_table, type);
+
+		g_hash_table_foreach_remove(theme_table,
+                	                    (GHRFunc)purple_theme_manager_is_theme_type,
+                	                    (gpointer)type);		
+	}/* only free if given registered loader */
+}
+
+PurpleTheme *
+purple_theme_manager_find_theme(const gchar *name,
+				const gchar *type)
+{
+	gchar *key;
+	PurpleTheme *theme;
+
+	key = purple_theme_manager_make_key(name, type);
+
+	g_return_val_if_fail(key, NULL);
+
+	theme = g_hash_table_lookup(theme_table, key);
+
+	g_free(key);
+
+	return theme;
+}
+
+
+void 
+purple_theme_manager_add_theme(PurpleTheme *theme)
+{
+	gchar *key;
+	
+	g_return_if_fail(PURPLE_IS_THEME(theme));
+
+	key = purple_theme_manager_make_key(purple_theme_get_name(theme),
+			  		    purple_theme_get_type_string(theme));
+
+	g_return_if_fail(key);
+
+	/* if something is already there do nothing */
+	if (g_hash_table_lookup(theme_table, key) == NULL) 
+		g_hash_table_insert(theme_table, key, theme);
+}
+
+void
+purple_theme_manager_remove_theme(PurpleTheme *theme)
+{
+	gchar *key;
+
+	g_return_if_fail(PURPLE_IS_THEME(theme));
+
+	key = purple_theme_manager_make_key(purple_theme_get_name(theme),
+				  	    purple_theme_get_type_string(theme));
+
+	g_return_if_fail(key);
+
+	g_hash_table_remove(theme_table, key);	
+
+	g_free(key);	
+}
+
+void 
+purple_theme_manager_for_each_theme(PTFunc func)
+{
+	g_return_if_fail(func);
+
+	g_hash_table_foreach(theme_table,
+			     (GHFunc) purple_theme_manager_function_wrapper,
+			     func);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/theme-manager.h	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,125 @@
+/**
+ * @file thememanager.h  Theme Manager API
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef __PURPLE_THEME_MANAGER_H__
+#define __PURPLE_THEME_MANAGER_H__
+
+#include <glib-object.h>
+#include <glib.h>
+#include "theme.h"
+#include "theme-loader.h"
+
+typedef void (*PTFunc) (PurpleTheme *);
+
+typedef struct _PurpleThemeManager PurpleThemeManager;
+typedef struct _PurpleThemeManagerClass PurpleThemeManagerClass;
+
+#define PURPLE_TYPE_THEME_MANAGER            (purple_theme_manager_get_type ())
+#define PURPLE_THEME_MANAGER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_THEME_MANAGER, PurpleThemeManager))
+#define PURPLE_THEME_MANAGER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PURPLE_TYPE_THEME_MANAGER, PurpleThemeManagerClass))
+#define PURPLE_IS_THEME_MANAGER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PURPLE_TYPE_THEME_MANAGER))
+#define PURPLE_IS_THEME_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PURPLE_TYPE_THEME_MANAGER))
+#define PURPLE_GET_THEME_MANAGER_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PURPLE_TYPE_THEME_MANAGER, PurpleThemeManagerClass))
+
+struct _PurpleThemeManager {
+	GObject parent;
+};
+
+struct _PurpleThemeManagerClass {
+	GObjectClass parent_class;
+};
+
+/**************************************************************************/
+/** @name Purple Theme Manager API                                        */
+/**************************************************************************/
+G_BEGIN_DECLS
+
+/**
+ * GObject foo.
+ * @internal.
+ */
+GType purple_theme_manager_get_type (void);
+
+/**
+ * Initalizes the theme manager
+ */
+void purple_theme_manager_init (void);
+
+/**
+ * Uninitalizes the manager then frees all the themes an loaders it is responsible for 
+ */
+void purple_theme_manager_uninit (void);
+
+/**
+ * Rebuilds all the themes in the theme manager
+ * (removes all current themes but keeps the added loaders)
+ */
+void purple_theme_manager_refresh(void);
+
+/**
+ * Finds the PurpleTheme object stored by the theme manager
+ * 
+ * @param name		the name of the PurpleTheme
+ * @param type 		the type of the PurpleTheme
+ *
+ * @returns 	The PurpleTheme or NULL if it wasn't found
+ */
+PurpleTheme *purple_theme_manager_find_theme(const gchar *name, const gchar *type);
+
+/**
+ * Adds a PurpleTheme to the theme manager, if the theme already exits it does nothing
+ *
+ * @param theme 	the PurpleTheme to add to the manager
+ */
+void purple_theme_manager_add_theme(PurpleTheme *theme);
+
+/**
+ * Removes a PurpleTheme from the theme manager, and frees the theme
+ * @param theme 	the PurpleTheme to remove from the manager
+ */
+void purple_theme_manager_remove_theme(PurpleTheme *theme);
+
+/**
+ * Addes a Loader to the theme manager so it knows how to build themes
+ * @param loader 	the PurpleThemeLoader to add
+ */
+void purple_theme_manager_register_type(PurpleThemeLoader *loader);
+
+/**
+ * Removes the loader and all themes of the same type from the loader
+ * @param loader 	the PurpleThemeLoader to be removed
+ */
+void purple_theme_manager_unregister_type(PurpleThemeLoader *loader);
+
+/**
+ * Calles the given function on each purple theme
+ *
+ * @param func 		the PTFunc to be applied to each theme
+ */
+void purple_theme_manager_for_each_theme(PTFunc func); 
+
+G_END_DECLS
+#endif /* __PURPLE_THEME_MANAGER_H__ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/theme.c	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,407 @@
+/*
+ * Themes for LibPurple
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+#include "theme.h"
+#include "util.h"
+
+#include <string.h>
+
+#define PURPLE_THEME_GET_PRIVATE(PurpleTheme) \
+	((PurpleThemePrivate *) ((PurpleTheme)->priv))
+
+void purple_theme_set_type_string(PurpleTheme *theme, const gchar *type);
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+typedef struct {
+	gchar *name;
+	gchar *description;
+	gchar *author;
+	gchar *type;
+	gchar *dir;
+	gchar *img;
+} PurpleThemePrivate;
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+
+enum {
+	PROP_ZERO = 0,
+	PROP_NAME,
+	PROP_DESCRIPTION,
+	PROP_AUTHOR,
+	PROP_TYPE,
+	PROP_DIR,
+	PROP_IMAGE
+};
+
+/******************************************************************************
+ * GObject Stuff                                                              *
+ *****************************************************************************/
+
+static void
+purple_theme_get_property(GObject *obj, guint param_id, GValue *value,
+						 GParamSpec *psec)
+{
+	PurpleTheme *theme = PURPLE_THEME(obj);
+
+	switch(param_id) {
+		case PROP_NAME:
+			g_value_set_string(value, purple_theme_get_name(theme));
+			break;
+		case PROP_DESCRIPTION:
+			g_value_set_string(value, purple_theme_get_description(theme));
+			break;
+		case PROP_AUTHOR:
+			g_value_set_string(value, purple_theme_get_author(theme));
+			break;
+		case PROP_TYPE:
+			g_value_set_string(value, purple_theme_get_type_string(theme));
+			break;
+		case PROP_DIR:
+			g_value_set_string(value, purple_theme_get_dir(theme));
+			break;
+		case PROP_IMAGE:
+			g_value_set_string(value, purple_theme_get_image(theme));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, psec);
+			break;
+	}
+}
+
+static void
+purple_theme_set_property(GObject *obj, guint param_id, const GValue *value,
+						 GParamSpec *psec)
+{
+	PurpleTheme *theme = PURPLE_THEME(obj);
+
+	switch(param_id) {
+		case PROP_NAME:
+			purple_theme_set_name(theme, g_value_get_string(value));
+			break;
+		case PROP_DESCRIPTION:
+			purple_theme_set_description(theme, g_value_get_string(value));
+			break;
+		case PROP_AUTHOR:
+			purple_theme_set_author(theme, g_value_get_string(value));
+			break;
+		case PROP_TYPE:
+			purple_theme_set_type_string(theme, g_value_get_string(value));
+			break;
+		case PROP_DIR:
+			purple_theme_set_dir(theme, g_value_get_string(value));
+			break;
+		case PROP_IMAGE:
+			purple_theme_set_image(theme, g_value_get_string(value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, psec);
+			break;
+	}
+}
+
+static void
+purple_theme_init(GTypeInstance *instance,
+			gpointer klass)
+{
+	PurpleTheme *theme = PURPLE_THEME(instance);
+	theme->priv = g_new0(PurpleThemePrivate, 1);
+}
+
+static void
+purple_theme_finalize(GObject *obj)
+{
+	PurpleTheme *theme = PURPLE_THEME(obj);	
+	PurpleThemePrivate *priv = PURPLE_THEME_GET_PRIVATE(theme);
+	
+	g_free(priv->name);
+	g_free(priv->description);
+	g_free(priv->author);
+	g_free(priv->type);
+	g_free(priv->dir);
+	g_free(priv->img);
+
+	G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+purple_theme_class_init (PurpleThemeClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	GParamSpec *pspec;
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	obj_class->get_property = purple_theme_get_property;
+	obj_class->set_property = purple_theme_set_property;
+	obj_class->finalize = purple_theme_finalize;
+	
+	/* NAME */
+	pspec = g_param_spec_string("name", "Name",
+				    "The name of the theme",
+				    NULL,
+				    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+	g_object_class_install_property(obj_class, PROP_NAME, pspec);
+
+	/* DESCRIPTION */
+	pspec = g_param_spec_string("description", "Description",
+				    "The description of the theme",
+				    NULL,
+				    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+	g_object_class_install_property(obj_class, PROP_DESCRIPTION, pspec);
+
+	/* AUTHOR */
+	pspec = g_param_spec_string("author", "Author",
+				    "The author of the theme",
+				    NULL,
+				    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+	g_object_class_install_property(obj_class, PROP_AUTHOR, pspec);
+
+	/* TYPE STRING (read only) */
+	pspec = g_param_spec_string("type", "Type",
+				    "The string represtenting the type of the theme",
+				    NULL,
+				    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+	g_object_class_install_property(obj_class, PROP_TYPE, pspec);
+
+	/* DIRECTORY */
+	pspec = g_param_spec_string("directory", "Directory",
+				    "The directory that contains the theme and all its files",
+				    NULL,
+				    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+	g_object_class_install_property(obj_class, PROP_DIR, pspec);
+
+	/* PREVIEW IMAGE */
+	pspec = g_param_spec_string("image", "Image",
+				    "A preview image of the theme",
+				    NULL,
+				    G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_IMAGE, pspec);
+}
+
+
+GType 
+purple_theme_get_type (void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (PurpleThemeClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      (GClassInitFunc)purple_theme_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (PurpleTheme),
+      0,      /* n_preallocs */
+      purple_theme_init,    /* instance_init */
+      NULL,   /* value table */
+    };
+    type = g_type_register_static (G_TYPE_OBJECT,
+                                   "PurpleTheme",
+                                   &info, G_TYPE_FLAG_ABSTRACT);
+  }
+  return type;
+}
+
+/******************************************************************************
+ * Helper Functions
+ *****************************************************************************/
+
+static gchar*
+theme_clean_text(const gchar *text)
+{
+	gchar *clean_text = g_markup_escape_text(text, strlen(text));	
+	g_strdelimit(clean_text, "\n", ' ');
+	purple_str_strip_char(clean_text, '\r');
+	return clean_text;
+}
+
+/*****************************************************************************
+ * Public API functions                                                      
+ *****************************************************************************/
+
+const gchar *
+purple_theme_get_name(PurpleTheme *theme)
+{
+	PurpleThemePrivate *priv;
+
+	g_return_val_if_fail(PURPLE_IS_THEME(theme), NULL);
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+	return priv->name;
+}
+
+void
+purple_theme_set_name(PurpleTheme *theme, const gchar *name)
+{
+	PurpleThemePrivate *priv;
+
+	g_return_if_fail(PURPLE_IS_THEME(theme));
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+
+	g_free(priv->name);
+	priv->name = theme_clean_text(name);
+}
+
+const gchar *
+purple_theme_get_description(PurpleTheme *theme)
+{
+	PurpleThemePrivate *priv;
+
+	g_return_val_if_fail(PURPLE_IS_THEME(theme), NULL);
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+	return priv->description;
+}
+
+void
+purple_theme_set_description(PurpleTheme *theme, const gchar *description)
+{
+	PurpleThemePrivate *priv;
+
+	g_return_if_fail(PURPLE_IS_THEME(theme));
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+
+	g_free(priv->description);
+	priv->description = theme_clean_text(description);
+}
+
+const gchar *
+purple_theme_get_author(PurpleTheme *theme)
+{
+	PurpleThemePrivate *priv;
+
+	g_return_val_if_fail(PURPLE_IS_THEME(theme), NULL);
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+	return priv->author;
+}
+
+void
+purple_theme_set_author(PurpleTheme *theme, const gchar *author)
+{
+	PurpleThemePrivate *priv;
+
+	g_return_if_fail(PURPLE_IS_THEME(theme));
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+
+	g_free(priv->author);
+	priv->author = theme_clean_text(author);
+}
+
+const gchar *
+purple_theme_get_type_string(PurpleTheme *theme)
+{
+	PurpleThemePrivate *priv;
+
+	g_return_val_if_fail(PURPLE_IS_THEME(theme), NULL);
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+	return priv->type;
+}
+
+/* < private > */
+void
+purple_theme_set_type_string(PurpleTheme *theme, const gchar *type)
+{
+	PurpleThemePrivate *priv;
+
+	g_return_if_fail(PURPLE_IS_THEME(theme));
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+
+	g_free(priv->type);
+	priv->type = g_strdup(type);
+}
+
+const gchar *
+purple_theme_get_dir(PurpleTheme *theme) 
+{
+	PurpleThemePrivate *priv;
+
+	g_return_val_if_fail(PURPLE_IS_THEME(theme), NULL);
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+	return priv->dir;
+}
+
+void
+purple_theme_set_dir(PurpleTheme *theme, const gchar *dir)
+{
+	PurpleThemePrivate *priv;
+
+	g_return_if_fail(PURPLE_IS_THEME(theme));
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+
+	g_free(priv->dir);
+	priv->dir = g_strdup(dir);
+}
+
+const gchar *
+purple_theme_get_image(PurpleTheme *theme)
+{
+	PurpleThemePrivate *priv;
+
+	g_return_val_if_fail(PURPLE_IS_THEME(theme), NULL);
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+
+	return priv->img;
+}
+
+gchar *
+purple_theme_get_image_full(PurpleTheme *theme)
+{
+	const gchar *filename = purple_theme_get_image(theme);
+	
+	g_return_val_if_fail(filename, NULL);
+
+	return g_build_filename(purple_theme_get_dir(PURPLE_THEME(theme)), filename, NULL);
+}
+
+void 
+purple_theme_set_image(PurpleTheme *theme, const gchar *img)
+{	
+	PurpleThemePrivate *priv;
+
+	g_return_if_fail(PURPLE_IS_THEME(theme));
+
+	priv = PURPLE_THEME_GET_PRIVATE(theme);
+
+	g_free(priv->img);
+	priv->img = g_strdup(img);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/theme.h	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,175 @@
+/**
+ * @file theme.h  Purple Theme Abstact Class API
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PURPLE_THEME_H_
+#define _PURPLE_THEME_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include "imgstore.h"
+
+/**
+ * A purple theme.
+ * This is an abstract class for Purple to use with the Purple theme manager.
+ *
+ * PurpleTheme is a GObject.
+ */
+typedef struct _PurpleTheme        PurpleTheme;
+typedef struct _PurpleThemeClass   PurpleThemeClass;
+
+#define PURPLE_TYPE_THEME		  (purple_theme_get_type ())
+#define PURPLE_THEME(obj)		  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PURPLE_TYPE_THEME, PurpleTheme))
+#define PURPLE_THEME_CLASS(klass)	  (G_TYPE_CHECK_CLASS_CAST ((klass), PURPLE_TYPE_THEME, PurpleThemeClass))
+#define PURPLE_IS_THEME(obj)	  	  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PURPLE_TYPE_THEME))
+#define PURPLE_IS_THEME_CLASS(klass) 	  (G_TYPE_CHECK_CLASS_TYPE ((klass), PURPLE_TYPE_THEME))
+#define PURPLE_THEME_GET_CLASS(obj)  	  (G_TYPE_INSTANCE_GET_CLASS ((obj), PURPLE_TYPE_THEME, PurpleThemeClass))
+
+struct _PurpleTheme
+{
+	GObject parent;
+	gpointer priv;
+};
+
+struct _PurpleThemeClass
+{
+	GObjectClass parent_class;
+};
+
+/**************************************************************************/
+/** @name Purple Theme API                                                */
+/**************************************************************************/
+G_BEGIN_DECLS
+
+/**
+ * GObject foo.
+ * @internal.
+ */
+GType purple_theme_get_type(void);
+
+/**
+ * Returns the name of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ *
+ * @return The string representating the name of the theme
+ */
+const gchar *purple_theme_get_name(PurpleTheme *theme);
+
+/**
+ * Sets the name of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ * @param name 		the name of the PurpleTheme object
+ */
+void purple_theme_set_name(PurpleTheme *theme, const gchar *name);
+
+/**
+ * Returns the description of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ *
+ * @return A short description of the theme
+ */
+const gchar *purple_theme_get_description(PurpleTheme *theme);
+
+/**
+ * Sets the description of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ * @param description	the description of the PurpleTheme object
+ */
+void purple_theme_set_description(PurpleTheme *theme, const gchar *description);
+
+/**
+ * Returns the author of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ *
+ * @return The author of the theme
+ */
+const gchar *purple_theme_get_author(PurpleTheme *theme);
+
+/**
+ * Sets the author of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ * @param author	the author of the PurpleTheme object
+ */
+void purple_theme_set_author(PurpleTheme *theme, const gchar *author);
+
+/**
+ * Returns the type (string) of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ *
+ * @return The string represtenting the type
+ */
+const gchar *purple_theme_get_type_string(PurpleTheme *theme);
+
+/**
+ * Returns the directory of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ *
+ * @return The string represtenting the theme directory 
+ */
+const gchar *purple_theme_get_dir(PurpleTheme *theme);
+
+/**
+ * Sets the directory of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ * @param dir		the directory of the PurpleTheme object
+ */
+void purple_theme_set_dir(PurpleTheme *theme, const gchar *dir);
+
+/**
+ * Returns the image preview of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ *
+ * @return The image preview of the PurpleTheme object
+ */
+const gchar *purple_theme_get_image(PurpleTheme *theme);
+
+/**
+ * Returns the image preview and directory of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ *
+ * @return The image preview of the PurpleTheme object
+ */
+gchar *purple_theme_get_image_full(PurpleTheme *theme);
+
+/**
+ * Sets the directory of the PurpleTheme object
+ * 
+ * @param theme 	the purple theme
+ * @param img		the image preview of the PurpleTheme object
+ */
+void purple_theme_set_image(PurpleTheme *theme, const gchar *img);
+
+G_END_DECLS
+#endif /* _PURPLE_THEME_H_ */
--- a/libpurple/util.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/util.c	Thu Nov 27 21:15:43 2008 +0000
@@ -2774,70 +2774,7 @@
 xmlnode *
 purple_util_read_xml_from_file(const char *filename, const char *description)
 {
-	const char *user_dir = purple_user_dir();
-	gchar *filename_full;
-	GError *error = NULL;
-	gchar *contents = NULL;
-	gsize length;
-	xmlnode *node = NULL;
-
-	g_return_val_if_fail(user_dir != NULL, NULL);
-
-	purple_debug_info("util", "Reading file %s from directory %s\n",
-					filename, user_dir);
-
-	filename_full = g_build_filename(user_dir, filename, NULL);
-
-	if (!g_file_test(filename_full, G_FILE_TEST_EXISTS))
-	{
-		purple_debug_info("util", "File %s does not exist (this is not "
-						"necessarily an error)\n", filename_full);
-		g_free(filename_full);
-		return NULL;
-	}
-
-	if (!g_file_get_contents(filename_full, &contents, &length, &error))
-	{
-		purple_debug_error("util", "Error reading file %s: %s\n",
-						 filename_full, error->message);
-		g_error_free(error);
-	}
-
-	if ((contents != NULL) && (length > 0))
-	{
-		node = xmlnode_from_str(contents, length);
-
-		/* If we were unable to parse the file then save its contents to a backup file */
-		if (node == NULL)
-		{
-			gchar *filename_temp;
-
-			filename_temp = g_strdup_printf("%s~", filename);
-			purple_debug_error("util", "Error parsing file %s.  Renaming old "
-							 "file to %s\n", filename_full, filename_temp);
-			purple_util_write_data_to_file(filename_temp, contents, length);
-			g_free(filename_temp);
-		}
-
-		g_free(contents);
-	}
-
-	/* If we could not parse the file then show the user an error message */
-	if (node == NULL)
-	{
-		gchar *title, *msg;
-		title = g_strdup_printf(_("Error Reading %s"), filename);
-		msg = g_strdup_printf(_("An error was encountered reading your "
-					"%s.  They have not been loaded, and the old file "
-					"has been renamed to %s~."), description, filename_full);
-		purple_notify_error(NULL, NULL, title, msg);
-		g_free(title);
-		g_free(msg);
-	}
-
-	g_free(filename_full);
-
-	return node;
+	return xmlnode_from_file(purple_user_dir(), filename, description, "util");
 }
 
 /*
--- a/libpurple/xmlnode.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/xmlnode.c	Thu Nov 27 21:15:43 2008 +0000
@@ -730,6 +730,78 @@
 	return ret;
 }
 
+xmlnode *
+xmlnode_from_file(const char *dir,const char *filename, const char *description, const char *process)
+{
+	gchar *filename_full;
+	GError *error = NULL;
+	gchar *contents = NULL;
+	gsize length;
+	xmlnode *node = NULL;
+
+	g_return_val_if_fail(dir != NULL, NULL);
+
+	purple_debug_info(process, "Reading file %s from directory %s\n",
+					filename, dir);
+
+	filename_full = g_build_filename(dir, filename, NULL);
+
+	if (!g_file_test(filename_full, G_FILE_TEST_EXISTS))
+	{
+		purple_debug_info(process, "File %s does not exist (this is not "
+						"necessarily an error)\n", filename_full);
+		g_free(filename_full);
+		return NULL;
+	}
+
+	if (!g_file_get_contents(filename_full, &contents, &length, &error))
+	{
+		purple_debug_error(process, "Error reading file %s: %s\n",
+						 filename_full, error->message);
+		g_error_free(error);
+	}
+
+	if ((contents != NULL) && (length > 0))
+	{
+		node = xmlnode_from_str(contents, length);
+
+		/* If we were unable to parse the file then save its contents to a backup file */
+		if (node == NULL)
+		{
+			gchar *filename_temp, *filename_temp_full;
+
+			filename_temp = g_strdup_printf("%s~", filename);
+			filename_temp_full = g_build_filename(dir, filename_temp, NULL);
+
+			purple_debug_error("util", "Error parsing file %s.  Renaming old "
+							 "file to %s\n", filename_full, filename_temp);
+			purple_util_write_data_to_file_absolute(filename_temp_full, contents, length);
+
+			g_free(filename_temp_full);
+			g_free(filename_temp);
+		}
+
+		g_free(contents);
+	}
+
+	/* If we could not parse the file then show the user an error message */
+	if (node == NULL)
+	{
+		gchar *title, *msg;
+		title = g_strdup_printf(_("Error Reading %s"), filename);
+		msg = g_strdup_printf(_("An error was encountered reading your "
+					"%s.  The file has not been loaded, and the old file "
+					"has been renamed to %s~."), description, filename_full);
+		purple_notify_error(NULL, NULL, title, msg);
+		g_free(title);
+		g_free(msg);
+	}
+
+	g_free(filename_full);
+
+	return node;
+}
+
 static void
 xmlnode_copy_foreach_ns(gpointer key, gpointer value, gpointer user_data)
 {
--- a/libpurple/xmlnode.h	Sun Nov 23 18:30:31 2008 +0000
+++ b/libpurple/xmlnode.h	Thu Nov 27 21:15:43 2008 +0000
@@ -26,6 +26,8 @@
 #ifndef _PURPLE_XMLNODE_H_
 #define _PURPLE_XMLNODE_H_
 
+#include <glib.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -297,6 +299,20 @@
  */
 void xmlnode_free(xmlnode *node);
 
+/**
+ * Creates a node from a XML File.  Calling this on the
+ * root node of an XML document will parse the entire document
+ * into a tree of nodes, and return the xmlnode of the root.
+ *
+ * @param str  The string of xml.
+ * @param description  The description of the file being parsed
+ * @process  The utility that is calling xmlnode_from_file
+ *
+ * @return The new node.
+ */
+xmlnode *xmlnode_from_file(const char *dir, const char *filename, 
+			   const char *description, const char *process);
+
 #ifdef __cplusplus
 }
 #endif
--- a/pidgin/Makefile.am	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/Makefile.am	Thu Nov 27 21:15:43 2008 +0000
@@ -5,7 +5,6 @@
 		Makefile.mingw \
 		pidgin.pc.in \
 		pidgin-uninstalled.pc.in \
-		pidginstock-artwork.c \
 		win32/IdleTracker/Makefile.mingw \
 		win32/IdleTracker/idletrack.c \
 		win32/IdleTracker/idletrack.h \
@@ -79,6 +78,8 @@
 	pidginstock.c \
 	gtkaccount.c \
 	gtkblist.c \
+	gtkblist-theme-loader.c \
+	gtkblist-theme.c \
 	gtkcelllayout.c \
 	gtkcellrendererexpander.c \
 	gtkcellrendererprogress.c \
@@ -95,6 +96,8 @@
 	gtkeventloop.c \
 	gtkexpander.c \
 	gtkft.c \
+	gtkicon-theme.c \
+	gtkicon-theme-loader.c \
 	gtkidle.c \
 	gtkimhtml.c \
 	gtkimhtmltoolbar.c \
@@ -117,6 +120,7 @@
 	gtksourceiter.c \
 	gtksourceundomanager.c \
 	gtksourceview-marshal.c \
+	gtkstatus-icon-theme.c \
 	gtkstatusbox.c \
 	gtkthemes.c \
 	gtkutils.c \
@@ -128,6 +132,8 @@
 	eggtrayicon.h \
 	gtkaccount.h \
 	gtkblist.h \
+	gtkblist-theme-loader.h \
+	gtkblist-theme.h \
 	gtkcelllayout.h \
 	gtkcellrendererexpander.h \
 	gtkcellrendererprogress.h \
@@ -147,6 +153,8 @@
 	gtkeventloop.h \
 	gtkexpander.h \
 	gtkft.h \
+	gtkicon-theme.h \
+	gtkicon-theme-loader.h \
 	gtkidle.h \
 	gtkgaim-compat.h \
 	gtkimhtml.h \
@@ -170,6 +178,7 @@
 	gtksourceiter.h \
 	gtksourceundomanager.h \
 	gtksourceview-marshal.h \
+	gtkstatus-icon-theme.h \
 	gtkstatusbox.h \
 	pidginstock.h \
 	gtkthemes.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkblist-theme-loader.c	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,274 @@
+/*
+ * GTKBlistThemeLoader for Pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+#include <stdlib.h>
+
+#include "xmlnode.h"
+
+#include "gtkblist-theme-loader.h"
+#include "gtkblist-theme.h"
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+#define DEFAULT_TEXT_COLOR "black"
+/*****************************************************************************
+ * Buddy List Theme Builder                                                      
+ *****************************************************************************/
+
+static PurpleTheme *
+pidgin_blist_loader_build(const gchar *dir)
+{
+	xmlnode *root_node = NULL, *sub_node, *sub_sub_node;
+	gchar *filename_full, *data;
+	const gchar *temp;
+	gboolean sucess = TRUE;
+	GdkColor *bgcolor, *expanded_bgcolor, *collapsed_bgcolor, *contact_color;
+	GdkColor color;
+	FontColorPair *expanded, *collapsed, *contact, *online, *away, *offline, *idle, *message, *status;
+	PidginBlistLayout *layout;
+	PidginBlistTheme *theme;
+
+	/* Find the theme file */
+	g_return_val_if_fail(dir != NULL, NULL);
+	filename_full = g_build_filename(dir, "theme.xml", NULL);
+
+	if (g_file_test(filename_full, G_FILE_TEST_IS_REGULAR))
+		root_node = xmlnode_from_file(dir, "theme.xml", "buddy list themes", "blist-loader");
+
+	g_free(filename_full);
+	g_return_val_if_fail(root_node != NULL, NULL);
+
+	sub_node = xmlnode_get_child(root_node, "description");
+	data = xmlnode_get_data(sub_node);
+
+	/* init all structs and colors */
+	bgcolor = g_new0(GdkColor, 1);
+	expanded_bgcolor = g_new0(GdkColor, 1);
+	collapsed_bgcolor = g_new0(GdkColor, 1); 
+
+	layout = g_new0(PidginBlistLayout, 1);
+
+	contact_color = g_new0(GdkColor, 1);
+
+	expanded = g_new0(FontColorPair, 1);
+	collapsed = g_new0(FontColorPair, 1);
+	contact = g_new0(FontColorPair, 1);
+	online = g_new0(FontColorPair, 1);
+	away = g_new0(FontColorPair, 1);
+	offline = g_new0(FontColorPair, 1);
+	idle = g_new0(FontColorPair, 1);
+	message = g_new0(FontColorPair, 1); 
+	status = g_new0(FontColorPair, 1);
+
+	/* <blist> */
+	if ((sucess = (sub_node = xmlnode_get_child(root_node, "blist")) != NULL)) {
+		if ((temp = xmlnode_get_attrib(sub_node, "color")) != NULL && gdk_color_parse(temp, bgcolor))
+			gdk_colormap_alloc_color(gdk_colormap_get_system(), bgcolor, FALSE, TRUE);
+		else {
+			g_free(bgcolor);
+			bgcolor = NULL;
+		}
+	}
+
+	/* <groups> */
+	if ((sucess = sucess && (sub_node = xmlnode_get_child(root_node, "groups")) != NULL
+		     && (sub_sub_node = xmlnode_get_child(sub_node, "expanded")) != NULL)) {
+
+		expanded->font = g_strdup(xmlnode_get_attrib(sub_sub_node, "font"));
+
+		if ((temp = xmlnode_get_attrib(sub_sub_node, "text_color")) != NULL && gdk_color_parse(temp, &color))
+			expanded->color = g_strdup(temp);
+		else expanded->color = g_strdup(DEFAULT_TEXT_COLOR);
+	
+
+		if ((temp = xmlnode_get_attrib(sub_sub_node, "background")) != NULL && gdk_color_parse(temp, expanded_bgcolor))
+			gdk_colormap_alloc_color(gdk_colormap_get_system(), expanded_bgcolor, FALSE, TRUE);
+		else {
+			g_free(expanded_bgcolor);
+			expanded_bgcolor = NULL;
+		}
+	}
+
+	if ((sucess = sucess && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "collapsed")) != NULL)) {
+
+		collapsed->font = g_strdup(xmlnode_get_attrib(sub_sub_node, "font"));
+
+		if((temp = xmlnode_get_attrib(sub_sub_node, "text_color")) != NULL && gdk_color_parse(temp, &color))
+			collapsed->color = g_strdup(temp);
+		else collapsed->color = g_strdup(DEFAULT_TEXT_COLOR);
+
+		if ((temp = xmlnode_get_attrib(sub_sub_node, "background")) != NULL && gdk_color_parse(temp, collapsed_bgcolor))
+			gdk_colormap_alloc_color(gdk_colormap_get_system(), collapsed_bgcolor, FALSE, TRUE);
+		else {
+			g_free(collapsed_bgcolor);
+			collapsed_bgcolor = NULL;
+		}
+	}
+
+	/* <buddys> */
+	if ((sucess = sucess && (sub_node = xmlnode_get_child(root_node, "buddys")) != NULL &&
+		     (sub_sub_node = xmlnode_get_child(sub_node, "placement")) != NULL)) { 
+
+		layout->status_icon = (temp = xmlnode_get_attrib(sub_sub_node, "status_icon")) != NULL ? atoi(temp) : 0;
+		layout->text = (temp = xmlnode_get_attrib(sub_sub_node, "name")) != NULL ? atoi(temp) : 1;
+		layout->emblem = (temp = xmlnode_get_attrib(sub_sub_node, "emblem")) != NULL ? atoi(temp) : 2;
+		layout->protocol_icon = (temp = xmlnode_get_attrib(sub_sub_node, "protocol_icon")) != NULL ? atoi(temp) : 3;
+		layout->buddy_icon = (temp = xmlnode_get_attrib(sub_sub_node, "buddy_icon")) != NULL ? atoi(temp) : 4;		
+		layout->show_status = (temp = xmlnode_get_attrib(sub_sub_node, "status_icon")) != NULL ? atoi(temp) != 0 : 1;
+	}
+
+	if ((sucess = sucess && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "background")) != NULL)) {
+		if(gdk_color_parse(xmlnode_get_attrib(sub_sub_node, "color"), contact_color))
+			gdk_colormap_alloc_color(gdk_colormap_get_system(), contact_color, FALSE, TRUE);
+		else {
+			g_free(contact_color);
+			contact_color = NULL;
+		}
+	}
+	
+	if ((sucess = sucess && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "contact_text")) != NULL)) {
+		contact->font = g_strdup(xmlnode_get_attrib(sub_sub_node, "font"));
+		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
+			contact->color = g_strdup(temp);
+		else contact->color = g_strdup(DEFAULT_TEXT_COLOR);
+	}
+
+	if ((sucess = sucess && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "online_text")) != NULL)) {
+		online->font = g_strdup(xmlnode_get_attrib(sub_sub_node, "font"));
+		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
+			online->color = g_strdup(temp);
+		else online->color = g_strdup(DEFAULT_TEXT_COLOR);
+	}
+
+	if ((sucess = sucess && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "away_text")) != NULL)) {
+		away->font = g_strdup(xmlnode_get_attrib(sub_sub_node, "font"));
+		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
+			away->color = g_strdup(temp);
+		else away->color = g_strdup(DEFAULT_TEXT_COLOR);
+	}
+
+	if ((sucess = sucess && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "offline_text")) != NULL)) {
+		offline->font = g_strdup(xmlnode_get_attrib(sub_sub_node, "font"));
+		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
+			online->color = g_strdup(temp);
+		else online->color = g_strdup(DEFAULT_TEXT_COLOR);
+	}
+
+	if ((sucess = sucess && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "idle_text")) != NULL)) {
+		idle->font = g_strdup(xmlnode_get_attrib(sub_sub_node, "font"));
+		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
+			idle->color = g_strdup(temp);
+		else online->color = g_strdup(DEFAULT_TEXT_COLOR);
+	}
+	
+	if ((sucess = sucess && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "message_text")) != NULL)) {
+		message->font = g_strdup(xmlnode_get_attrib(sub_sub_node, "font"));
+		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
+			message->color = g_strdup(temp);
+		else message->color = g_strdup(DEFAULT_TEXT_COLOR);
+	}
+	
+	if ((sucess = sucess && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "status_text")) != NULL)) {
+		status->font = g_strdup(xmlnode_get_attrib(sub_sub_node, "font"));
+		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
+			status->color = g_strdup(temp);
+		else status->color = g_strdup(DEFAULT_TEXT_COLOR);
+	}
+
+	/* name is required for theme manager */
+	sucess = sucess && xmlnode_get_attrib(root_node, "name") != NULL;
+
+	/* the new theme */
+	theme = g_object_new(PIDGIN_TYPE_BLIST_THEME,
+			    "type", "blist",
+			    "name", xmlnode_get_attrib(root_node, "name"),
+			    "author", xmlnode_get_attrib(root_node, "author"),
+			    "image", xmlnode_get_attrib(root_node, "image"),
+			    "directory", dir,
+			    "description", data,
+			    "background-color", bgcolor,
+			    "layout", layout,
+			    "expanded-color", expanded_bgcolor,
+			    "expanded-text", expanded,
+			    "collapsed-color", collapsed_bgcolor,
+			    "collapsed-text", collapsed,
+			    "contact-color", contact_color,
+			    "contact", contact,
+			    "online", online,
+			    "away", away,
+			    "offline", offline,
+			    "idle", idle,
+			    "message", message,
+			    "status", status, NULL);
+
+	xmlnode_free(root_node);	
+	g_free(data);
+
+	/* malformed xml file - also frees all partial data*/
+	if (!sucess) {
+		g_object_unref(theme);
+		theme = NULL;
+	}
+
+	return PURPLE_THEME(theme);
+}
+
+/******************************************************************************
+ * GObject Stuff                                                              
+ *****************************************************************************/
+
+static void
+pidgin_blist_theme_loader_class_init(PidginBlistThemeLoaderClass *klass)
+{
+	PurpleThemeLoaderClass *loader_klass = PURPLE_THEME_LOADER_CLASS(klass);
+
+	loader_klass->purple_theme_loader_build = pidgin_blist_loader_build;
+}
+
+
+GType 
+pidgin_blist_theme_loader_get_type(void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (PidginBlistThemeLoaderClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      (GClassInitFunc)pidgin_blist_theme_loader_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (PidginBlistThemeLoader),
+      0,      /* n_preallocs */
+      NULL,    /* instance_init */
+      NULL,   /* value table */
+    };
+    type = g_type_register_static(PURPLE_TYPE_THEME_LOADER,
+                                   "PidginBlistThemeLoader",
+                                   &info, 0);
+  }
+  return type;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkblist-theme-loader.h	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,71 @@
+/**
+ * @file gtkblist-loader.h  Pidgin Buddy List Theme Loader Class API
+ */
+
+/* pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PIDGIN_BLIST_THEME_LOADER_H_
+#define _PIDGIN_BLIST_THEME_LOADER_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include "theme-loader.h"
+
+/**
+ * A pidgin buddy list theme loader. extends PurpleThemeLoader (theme-loader.h)
+ * This is a class designed to build sound themes
+ *
+ * PidginBlistThemeLoader is a GObject.
+ */
+typedef struct _PidginBlistThemeLoader        PidginBlistThemeLoader;
+typedef struct _PidginBlistThemeLoaderClass   PidginBlistThemeLoaderClass;
+
+#define PIDGIN_TYPE_BLIST_THEME_LOADER			  (pidgin_blist_theme_loader_get_type ())
+#define PIDGIN_BLIST_THEME_LOADER(obj)			  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIDGIN_TYPE_BLIST_THEME_LOADER, PidginBlistThemeLoader))
+#define PIDGIN_BLIST_THEME_LOADER_CLASS(klass)		  (G_TYPE_CHECK_CLASS_CAST ((klass), PIDGIN_TYPE_BLIST_THEME_LOADER, PidginBlistThemeLoaderClass))
+#define PIDGIN_IS_BLIST_THEME_LOADER(obj)	  	  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIDGIN_TYPE_BLIST_THEME_LOADER))
+#define PIDGIN_IS_BLIST_THEME_LOADER_CLASS(klass) 	  (G_TYPE_CHECK_CLASS_TYPE ((klass), PIDGIN_TYPE_BLIST_THEME_LOADER))
+#define PIDGIN_BLIST_THEME_LOADER_GET_CLASS(obj)  	  (G_TYPE_INSTANCE_GET_CLASS ((obj), PIDGIN_TYPE_BLIST_THEME_LOADER, PidginBlistThemeLoaderClass))
+
+struct _PidginBlistThemeLoader
+{
+	PurpleThemeLoader parent;
+};
+
+struct _PidginBlistThemeLoaderClass
+{
+	PurpleThemeLoaderClass parent_class;
+};
+
+/**************************************************************************/
+/** @name Buddy List Theme-Loader API                                     */
+/**************************************************************************/
+G_BEGIN_DECLS
+
+/**
+ * GObject foo.
+ * @internal.
+ */
+GType pidgin_blist_theme_loader_get_type(void);
+
+G_END_DECLS
+#endif /* _PIDGIN_BLIST_THEME_LOADER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkblist-theme.c	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,743 @@
+/*
+ * Buddy List Themes for Pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+#include "gtkblist-theme.h"
+
+#define PIDGIN_BLIST_THEME_GET_PRIVATE(Gobject) \
+	((PidginBlistThemePrivate *) ((PIDGIN_BLIST_THEME(Gobject))->priv))
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+typedef struct {
+	/* Buddy list */
+	gdouble opacity;
+	GdkColor *bgcolor;
+	PidginBlistLayout *layout;
+	
+	/* groups */
+	GdkColor *expanded_color;
+	FontColorPair *expanded;
+
+	GdkColor *collapsed_color;
+	FontColorPair *collapsed;
+
+	/* buddy */
+	GdkColor *contact_color;
+
+	FontColorPair *contact;
+
+	FontColorPair *online;
+	FontColorPair *away;
+	FontColorPair *offline;
+	FontColorPair *idle;
+	FontColorPair *message;
+
+	FontColorPair *status;
+
+} PidginBlistThemePrivate;
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+	PROP_ZERO = 0,
+	PROP_BACKGROUND_COLOR,
+	PROP_OPACITY,
+	PROP_LAYOUT,
+	PROP_EXPANDED_COLOR,
+	PROP_EXPANDED_TEXT,
+	PROP_COLLAPSED_COLOR,
+	PROP_COLLAPSED_TEXT,
+	PROP_CONTACT_COLOR,
+	PROP_CONTACT,
+	PROP_ONLINE,
+	PROP_AWAY,
+	PROP_OFFLINE,
+	PROP_IDLE,
+	PROP_MESSAGE,
+	PROP_STATUS,
+};
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+
+void
+free_font_and_color(FontColorPair *pair) 
+{
+	if(pair != NULL){
+		if (pair->font)
+			g_free(pair->font);
+		if (pair->color)
+			g_free(pair->color);
+		g_free(pair);
+	}
+}
+
+/******************************************************************************
+ * GObject Stuff                                                              
+ *****************************************************************************/
+
+static void
+pidgin_blist_theme_init(GTypeInstance *instance,
+			gpointer klass)
+{
+	(PIDGIN_BLIST_THEME(instance))->priv = g_new0(PidginBlistThemePrivate, 1);
+}
+
+static void
+pidgin_blist_theme_get_property(GObject *obj, guint param_id, GValue *value,
+						 GParamSpec *psec)
+{
+	PidginBlistTheme *theme = PIDGIN_BLIST_THEME(obj);
+
+	switch(param_id) {
+		case PROP_BACKGROUND_COLOR:
+			g_value_set_pointer(value, pidgin_blist_theme_get_background_color(theme));
+			break;
+		case PROP_OPACITY:
+			g_value_set_double(value, pidgin_blist_theme_get_opacity(theme));
+			break;
+		case PROP_LAYOUT:
+			g_value_set_pointer(value, pidgin_blist_theme_get_layout(theme));
+			break;
+		case PROP_EXPANDED_COLOR:
+			g_value_set_pointer(value, pidgin_blist_theme_get_expanded_background_color(theme));
+			break;
+		case PROP_EXPANDED_TEXT:
+			g_value_set_pointer(value, pidgin_blist_theme_get_expanded_text_info(theme));
+			break;
+		case PROP_COLLAPSED_COLOR:
+			g_value_set_pointer(value, pidgin_blist_theme_get_collapsed_background_color(theme));
+			break;
+		case PROP_COLLAPSED_TEXT:
+			g_value_set_pointer(value, pidgin_blist_theme_get_collapsed_text_info(theme));
+			break;
+		case PROP_CONTACT_COLOR:
+			g_value_set_pointer(value, pidgin_blist_theme_get_contact_color(theme));
+			break;
+		case PROP_CONTACT:
+			g_value_set_pointer(value, pidgin_blist_theme_get_contact_text_info(theme));
+			break;
+		case PROP_ONLINE:
+			g_value_set_pointer(value, pidgin_blist_theme_get_online_text_info(theme));
+			break;
+		case PROP_AWAY:
+			g_value_set_pointer(value, pidgin_blist_theme_get_away_text_info(theme));
+			break;
+		case PROP_OFFLINE:
+			g_value_set_pointer(value, pidgin_blist_theme_get_offline_text_info(theme));
+			break;
+		case PROP_IDLE:
+			g_value_set_pointer(value, pidgin_blist_theme_get_idle_text_info(theme));
+			break;
+		case PROP_MESSAGE:
+			g_value_set_pointer(value, pidgin_blist_theme_get_unread_message_text_info(theme));
+			break;
+		case PROP_STATUS:
+			g_value_set_pointer(value, pidgin_blist_theme_get_status_text_info(theme));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, psec);
+			break;
+	}
+}
+
+static void
+pidgin_blist_theme_set_property(GObject *obj, guint param_id, const GValue *value,
+						 GParamSpec *psec)
+{
+	PidginBlistTheme *theme = PIDGIN_BLIST_THEME(obj);
+
+	switch(param_id) {
+		case PROP_BACKGROUND_COLOR:
+			pidgin_blist_theme_set_background_color(theme, g_value_get_pointer(value));
+			break;
+		case PROP_OPACITY:
+			pidgin_blist_theme_set_opacity(theme, g_value_get_double(value));
+			break;
+		case PROP_LAYOUT:
+			pidgin_blist_theme_set_layout(theme, g_value_get_pointer(value));
+			break;
+		case PROP_EXPANDED_COLOR:
+			pidgin_blist_theme_set_expanded_background_color(theme, g_value_get_pointer(value));
+			break;
+		case PROP_EXPANDED_TEXT:
+			pidgin_blist_theme_set_expanded_text_info(theme, g_value_get_pointer(value));
+			break;
+		case PROP_COLLAPSED_COLOR:
+			pidgin_blist_theme_set_collapsed_background_color(theme, g_value_get_pointer(value));
+			break;
+		case PROP_COLLAPSED_TEXT:
+			pidgin_blist_theme_set_collapsed_text_info(theme, g_value_get_pointer(value));
+			break;
+		case PROP_CONTACT_COLOR:
+			pidgin_blist_theme_set_contact_color(theme, g_value_get_pointer(value));
+			break;
+		case PROP_CONTACT:
+			pidgin_blist_theme_set_contact_text_info(theme, g_value_get_pointer(value));
+			break;
+		case PROP_ONLINE:
+			pidgin_blist_theme_set_online_text_info(theme, g_value_get_pointer(value));
+			break;
+		case PROP_AWAY:
+			pidgin_blist_theme_set_away_text_info(theme, g_value_get_pointer(value));
+			break;
+		case PROP_OFFLINE:
+			pidgin_blist_theme_set_offline_text_info(theme, g_value_get_pointer(value));
+			break;
+		case PROP_IDLE:
+			pidgin_blist_theme_set_idle_text_info(theme, g_value_get_pointer(value));
+			break;
+		case PROP_MESSAGE:
+			pidgin_blist_theme_set_unread_message_text_info(theme, g_value_get_pointer(value));
+			break;
+		case PROP_STATUS:
+			pidgin_blist_theme_set_status_text_info(theme, g_value_get_pointer(value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, psec);
+			break;
+	}
+}
+static void 
+pidgin_blist_theme_finalize (GObject *obj)
+{
+	PidginBlistThemePrivate *priv;
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(obj);
+
+	/* Buddy List */
+	g_free(priv->layout);
+	
+	/* Group */
+	free_font_and_color(priv->expanded);
+	free_font_and_color(priv->collapsed);
+
+	/* Buddy */
+	free_font_and_color(priv->contact);
+	free_font_and_color(priv->online);
+	free_font_and_color(priv->away);
+	free_font_and_color(priv->offline);
+	free_font_and_color(priv->message);
+	free_font_and_color(priv->status);
+
+	g_free(priv);
+
+	parent_class->finalize (obj);
+}
+
+static void
+pidgin_blist_theme_class_init (PidginBlistThemeClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	GParamSpec *pspec;
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	obj_class->get_property = pidgin_blist_theme_get_property;
+	obj_class->set_property = pidgin_blist_theme_set_property;
+	obj_class->finalize = pidgin_blist_theme_finalize;
+
+	/* Buddy List */
+	pspec = g_param_spec_pointer("background-color", "Background Color",
+				    "The background color for the buddy list",
+				    G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_BACKGROUND_COLOR, pspec);
+
+	pspec = g_param_spec_pointer("layout", "Layout",
+                                     "The layout of icons, name, and status of the blist",
+                                     G_PARAM_READWRITE);
+
+	g_object_class_install_property(obj_class, PROP_LAYOUT, pspec);
+
+	/* Group */
+	pspec = g_param_spec_pointer("expanded-color", "Expanded Background Color",
+				    "The background color of an expanded group",
+				    G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_EXPANDED_COLOR, pspec);
+
+	pspec = g_param_spec_pointer("expanded-text", "Expanded Text",
+                                     "The text information for when a group is expanded",
+                                     G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_EXPANDED_TEXT, pspec);
+
+	pspec = g_param_spec_pointer("collapsed-color", "Collapsed Background Color",
+				    "The background color of a collapsed group",
+				    G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_COLLAPSED_COLOR, pspec);
+
+	pspec = g_param_spec_pointer("collapsed-text", "Collapsed Text",
+                                     "The text information for when a group is collapsed",
+                                     G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_COLLAPSED_TEXT, pspec);
+
+	/* Buddy */
+	pspec = g_param_spec_pointer("contact-color", "Contact/Chat Background Color",
+				    "The background color of a contact or chat",
+				    G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_CONTACT_COLOR, pspec);
+
+	pspec = g_param_spec_pointer("contact", "Contact Text",
+                                     "The text information for when a contact is expanded",
+                                     G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_CONTACT, pspec);
+
+	pspec = g_param_spec_pointer("online", "On-line Text",
+                                     "The text information for when a buddy is online",
+                                     G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_ONLINE, pspec);
+
+	pspec = g_param_spec_pointer("away", "Away Text",
+                                     "The text information for when a buddy is away",
+                                     G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_AWAY, pspec);
+
+	pspec = g_param_spec_pointer("offline", "Off-line Text",
+                                     "The text information for when a buddy is off-line",
+                                     G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_OFFLINE, pspec);
+
+	pspec = g_param_spec_pointer("idle", "Idle Text",
+                                     "The text information for when a buddy is idle",
+                                     G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_IDLE, pspec);
+
+	pspec = g_param_spec_pointer("message", "Message Text",
+                                     "The text information for when a buddy is has an unread message",
+                                     G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_MESSAGE, pspec);
+
+	pspec = g_param_spec_pointer("status", "Status Text",
+                                     "The text information for a buddy's status",
+                                     G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_STATUS, pspec);
+}
+
+GType 
+pidgin_blist_theme_get_type (void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static GTypeInfo info = {
+      sizeof (PidginBlistThemeClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      (GClassInitFunc)pidgin_blist_theme_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (PidginBlistTheme),
+      0,      /* n_preallocs */
+      pidgin_blist_theme_init,    /* instance_init */
+      NULL,   /* value table */
+    };
+    type = g_type_register_static (PURPLE_TYPE_THEME,
+                                   "PidginBlistTheme",
+                                   &info, 0);
+  }
+  return type;
+}
+
+
+/*****************************************************************************
+ * Public API functions                                                      
+ *****************************************************************************/
+
+/* get methods */
+GdkColor *
+pidgin_blist_theme_get_background_color(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->bgcolor;
+}
+
+gdouble
+pidgin_blist_theme_get_opacity(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), 1.0);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->opacity;
+}
+
+PidginBlistLayout *
+pidgin_blist_theme_get_layout(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->layout;
+}
+
+GdkColor *
+pidgin_blist_theme_get_expanded_background_color(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->expanded_color;
+}
+
+FontColorPair *
+pidgin_blist_theme_get_expanded_text_info(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->expanded;
+}
+
+GdkColor *
+pidgin_blist_theme_get_collapsed_background_color(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->collapsed_color;
+}
+
+FontColorPair *
+pidgin_blist_theme_get_collapsed_text_info(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->collapsed;
+}
+
+GdkColor *
+pidgin_blist_theme_get_contact_color(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->contact_color;
+}
+
+FontColorPair *
+pidgin_blist_theme_get_contact_text_info(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->contact;
+}
+
+FontColorPair *
+pidgin_blist_theme_get_online_text_info(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->online;
+}
+
+FontColorPair *
+pidgin_blist_theme_get_away_text_info(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->away;
+}
+
+FontColorPair *
+pidgin_blist_theme_get_offline_text_info(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->offline;
+}
+
+FontColorPair *
+pidgin_blist_theme_get_idle_text_info(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->idle;
+}
+
+FontColorPair *
+pidgin_blist_theme_get_unread_message_text_info(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->message;
+}
+
+FontColorPair *
+pidgin_blist_theme_get_status_text_info(PidginBlistTheme *theme)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_BLIST_THEME(theme), NULL);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	return priv->status;
+}
+
+/* Set Methods */
+void
+pidgin_blist_theme_set_background_color(PidginBlistTheme *theme, GdkColor *color)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	priv->bgcolor = color;
+}
+
+void
+pidgin_blist_theme_set_opacity(PidginBlistTheme *theme, gdouble opacity)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme) || opacity < 0.0 || opacity > 1.0);
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	priv->opacity = opacity;
+}
+
+void
+pidgin_blist_theme_set_layout(PidginBlistTheme *theme, PidginBlistLayout *layout)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	g_free(priv->layout);
+	priv->layout = layout;
+}
+
+void
+pidgin_blist_theme_set_expanded_background_color(PidginBlistTheme *theme, GdkColor *color)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	priv->expanded_color = color;
+}
+
+void
+pidgin_blist_theme_set_expanded_text_info(PidginBlistTheme *theme, FontColorPair *pair)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	free_font_and_color(priv->expanded); 
+	priv->expanded = pair;
+}
+
+void
+pidgin_blist_theme_set_collapsed_background_color(PidginBlistTheme *theme, GdkColor *color)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	priv->collapsed_color = color;
+}
+
+void
+pidgin_blist_theme_set_collapsed_text_info(PidginBlistTheme *theme, FontColorPair *pair)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	free_font_and_color(priv->collapsed); 
+	priv->collapsed = pair;
+}
+
+void
+pidgin_blist_theme_set_contact_color(PidginBlistTheme *theme, GdkColor *color)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	priv->contact_color = color;
+}
+
+void
+pidgin_blist_theme_set_contact_text_info(PidginBlistTheme *theme, FontColorPair *pair)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	free_font_and_color(priv->contact); 
+	priv->contact = pair;
+}
+
+void
+pidgin_blist_theme_set_online_text_info(PidginBlistTheme *theme, FontColorPair *pair)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	free_font_and_color(priv->online); 
+	priv->online = pair;
+}
+
+void
+pidgin_blist_theme_set_away_text_info(PidginBlistTheme *theme, FontColorPair *pair)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	free_font_and_color(priv->away); 
+	priv->away = pair;
+}
+
+void
+pidgin_blist_theme_set_offline_text_info(PidginBlistTheme *theme, FontColorPair *pair)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	free_font_and_color(priv->offline); 
+	priv->offline = pair;
+}
+
+void
+pidgin_blist_theme_set_idle_text_info(PidginBlistTheme *theme, FontColorPair *pair)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	free_font_and_color(priv->idle); 
+	priv->idle = pair;
+}
+
+void
+pidgin_blist_theme_set_unread_message_text_info(PidginBlistTheme *theme, FontColorPair *pair)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	free_font_and_color(priv->message); 
+	priv->message = pair;
+}
+
+void
+pidgin_blist_theme_set_status_text_info(PidginBlistTheme *theme, FontColorPair *pair)
+{
+	PidginBlistThemePrivate *priv;
+
+	g_return_if_fail(PIDGIN_IS_BLIST_THEME(theme));
+
+	priv = PIDGIN_BLIST_THEME_GET_PRIVATE(G_OBJECT(theme));
+
+	free_font_and_color(priv->status); 
+	priv->status = pair;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkblist-theme.h	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,317 @@
+/**
+ * @file gtkblist-theme.h GTK+ Buddy List Theme API
+ */
+
+/* pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PIDGIN_BLIST_THEME_H_
+#define _PIDGIN_BLIST_THEME_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "theme.h"
+
+/**
+ * extends PurpleTheme (theme.h)
+ * A pidgin buddy list theme.
+ * This is an object for Purple to represent a buddy list theme.
+ *
+ * PidginBlistTheme is a PurpleTheme Object.
+ */
+typedef struct _PidginBlistTheme        PidginBlistTheme;
+typedef struct _PidginBlistThemeClass   PidginBlistThemeClass;
+
+#define PIDGIN_TYPE_BLIST_THEME		  	(pidgin_blist_theme_get_type ())
+#define PIDGIN_BLIST_THEME(obj)		  	(G_TYPE_CHECK_INSTANCE_CAST ((obj), PIDGIN_TYPE_BLIST_THEME, PidginBlistTheme))
+#define PIDGIN_BLIST_THEME_CLASS(klass)	  	(G_TYPE_CHECK_CLASS_CAST ((klass), PIDGIN_TYPE_BLIST_THEME, PidginBlistThemeClass))
+#define PIDGIN_IS_BLIST_THEME(obj)	  	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIDGIN_TYPE_BLIST_THEME))
+#define PIDGIN_IS_BLIST_THEME_CLASS(klass) 	(G_TYPE_CHECK_CLASS_TYPE ((klass), PIDGIN_TYPE_BLIST_THEME))
+#define PIDGIN_BLIST_THEME_GET_CLASS(obj)  	(G_TYPE_INSTANCE_GET_CLASS ((obj), PIDGIN_TYPE_BLIST_THEME, PidginBlistThemeClass))
+
+struct _PidginBlistTheme
+{
+	PurpleTheme parent;
+	gpointer priv;
+};
+
+struct _PidginBlistThemeClass
+{
+	PurpleThemeClass parent_class;
+};
+
+typedef struct
+{
+	gchar *font;
+	gchar *color;
+
+} FontColorPair;
+
+typedef struct
+{
+	gint status_icon;
+	gint text;
+	gint emblem;
+	gint protocol_icon;
+	gint buddy_icon;
+	gboolean show_status; 
+
+} PidginBlistLayout;
+
+/**************************************************************************/
+/** @name FontColorPair API 		                                  */
+/**************************************************************************/
+
+/**
+ * Frees a font and color pair
+ */
+void free_font_and_color(FontColorPair *pair);
+
+/**************************************************************************/
+/** @name Purple Buddy List Theme API                                     */
+/**************************************************************************/
+G_BEGIN_DECLS
+
+/**
+ * GObject foo.
+ * @internal.
+ */
+GType pidgin_blist_theme_get_type(void);
+
+/* get methods */
+
+/**
+ * Returns the background color of the buddy list
+ *
+ * @returns 	a gdk color
+ */
+ GdkColor *pidgin_blist_theme_get_background_color(PidginBlistTheme *theme);
+
+/**
+ * Returns the opacity of the buddy list window
+ * (0.0 or clear to 1.0 fully Opaque)
+ *
+ * @returns 	the opacity
+ */
+gdouble pidgin_blist_theme_get_opacity(PidginBlistTheme *theme);
+
+/**
+ * Returns the layout to be used with the buddy list
+ *
+ * @returns 	the buddy list layout
+ */
+ PidginBlistLayout *pidgin_blist_theme_get_layout(PidginBlistTheme *theme);
+
+/**
+ * Returns the background color to be used with expanded groups
+ *
+ * @returns 	a gdk color
+ */
+ GdkColor *pidgin_blist_theme_get_expanded_background_color(PidginBlistTheme *theme);
+
+/**
+ * Returns the text font and color to be used with expanded groups
+ *
+ * @returns 	a font and color pair
+ */
+ FontColorPair *pidgin_blist_theme_get_expanded_text_info(PidginBlistTheme *theme);
+
+/**
+ * Returns the background color to be used with collapsed groups
+ *
+ * @returns 	a gdk color
+ */
+ GdkColor *pidgin_blist_theme_get_collapsed_background_color(PidginBlistTheme *theme);
+
+/**
+ * Returns the text font and color to be used with collapsed groups
+ *
+ * @returns 	a font and color pair
+ */
+ FontColorPair *pidgin_blist_theme_get_collapsed_text_info(PidginBlistTheme *theme);
+
+/**
+ * Returns the colors to be used for contacts and chats
+ *
+ * @returns 	a gdkcolor for contacts and chats
+ */
+ GdkColor *pidgin_blist_theme_get_contact_color(PidginBlistTheme *theme);
+
+/**
+ * Returns the text font and color to be used for expanded contacts
+ *
+ * @returns 	a font and color pair
+ */
+ FontColorPair *pidgin_blist_theme_get_contact_text_info(PidginBlistTheme *theme);
+
+/**
+ * Returns the text font and color to be used for online buddies
+ *
+ * @returns 	a font and color pair
+ */
+ FontColorPair *pidgin_blist_theme_get_online_text_info(PidginBlistTheme *theme);
+
+/**
+ * Returns the text font and color to be used for away and idle buddies
+ *
+ * @returns 	a font and color pair
+ */
+ FontColorPair *pidgin_blist_theme_get_away_text_info(PidginBlistTheme *theme);
+
+/**
+ * Returns the text font and color to be used for offline buddies
+ *
+ * @returns 	a font and color pair
+ */
+ FontColorPair *pidgin_blist_theme_get_offline_text_info(PidginBlistTheme *theme);
+
+/**
+ * Returns the text font and color to be used for idle buddies
+ *
+ * @returns 	a font and color pair
+ */
+ FontColorPair *pidgin_blist_theme_get_idle_text_info(PidginBlistTheme *theme);
+
+/**
+ * Returns the text font and color to be used for buddies with unread messages
+ *
+ * @returns 	a font and color pair
+ */
+ FontColorPair *pidgin_blist_theme_get_unread_message_text_info(PidginBlistTheme *theme);
+
+/**
+ * Returns the text font and color to be used for a buddy's status message 
+ *
+ * @returns 	a font and color pair
+ */
+ FontColorPair *pidgin_blist_theme_get_status_text_info(PidginBlistTheme *theme);
+
+/* Set Methods */
+
+/**
+ * Sets the background color to be used for this buddy list theme
+ *
+ * @param color		the new background color
+ */
+void pidgin_blist_theme_set_background_color(PidginBlistTheme *theme, GdkColor *color);
+
+/**
+ * Sets the opacity to be used for this buddy list theme
+ *
+ * @param opacity	the new opacity setting
+ */
+void pidgin_blist_theme_set_opacity(PidginBlistTheme *theme, gdouble opacity);
+
+/**
+ * Sets the buddy list layout to be used for this buddy list theme
+ *
+ * @param layout		the new layout
+ */
+void pidgin_blist_theme_set_layout(PidginBlistTheme *theme, PidginBlistLayout *layout);
+
+/**
+ * Sets the background color to be used for expanded groups
+ *
+ * @param color		the new background color
+ */
+void pidgin_blist_theme_set_expanded_background_color(PidginBlistTheme *theme, GdkColor *color);
+
+/**
+ * Sets the text color and font to be used for expanded groups
+ *
+ * @param pair		the new text font at color pair
+ */
+void pidgin_blist_theme_set_expanded_text_info(PidginBlistTheme *theme, FontColorPair *pair);
+
+/**
+ * Sets the background color to be used for collapsed groups
+ *
+ * @param color		the new background color
+ */
+void pidgin_blist_theme_set_collapsed_background_color(PidginBlistTheme *theme, GdkColor *color);
+
+/**
+ * Sets the text color and font to be used for expanded groups
+ *
+ * @param pair		the new text font at color pair
+ */
+void pidgin_blist_theme_set_collapsed_text_info(PidginBlistTheme *theme, FontColorPair *pair);
+
+/**
+ * Sets the background color to be used for contacts and chats
+ *
+ * @param color		the color to use for contacts and chats
+ */
+void pidgin_blist_theme_set_contact_color(PidginBlistTheme *theme, GdkColor *color);
+
+/**
+ * Sets the text color and font to be used for expanded contacts
+ *
+ * @param pair		the new text font at color pair
+ */
+void pidgin_blist_theme_set_contact_text_info(PidginBlistTheme *theme, FontColorPair *pair);
+
+/**
+ * Sets the text color and font to be used for online buddies
+ *
+ * @param pair		the new text font at color pair
+ */
+void pidgin_blist_theme_set_online_text_info(PidginBlistTheme *theme, FontColorPair *pair);
+
+/**
+ * Sets the text color and font to be used for away and idle buddies
+ *
+ * @param pair		the new text font at color pair
+ */
+void pidgin_blist_theme_set_away_text_info(PidginBlistTheme *theme, FontColorPair *pair);
+
+/**
+ * Sets the text color and font to be used for offline buddies
+ *
+ * @param pair		the new text font at color pair
+ */
+void pidgin_blist_theme_set_offline_text_info(PidginBlistTheme *theme, FontColorPair *pair);
+
+/**
+ * Sets the text color and font to be used for idle buddies
+ *
+ * @param pair		the new text font at color pair
+ */
+void pidgin_blist_theme_set_idle_text_info(PidginBlistTheme *theme, FontColorPair *pair);
+
+/**
+ * Sets the text color and font to be used for buddies with an unread message
+ *
+ * @param pair		the new text font at color pair
+ */
+void pidgin_blist_theme_set_unread_message_text_info(PidginBlistTheme *theme, FontColorPair *pair);
+
+/**
+ * Sets the text color and font to be used for buddy status messages
+ *
+ * @param pair		the new text font at color pair
+ */
+void pidgin_blist_theme_set_status_text_info(PidginBlistTheme *theme, FontColorPair *pair);
+
+G_END_DECLS
+#endif /* _PIDGIN_BLIST_THEME_H_ */
--- a/pidgin/gtkblist.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtkblist.c	Thu Nov 27 21:15:43 2008 +0000
@@ -38,6 +38,8 @@
 #include "request.h"
 #include "signals.h"
 #include "pidginstock.h"
+#include "theme-loader.h"
+#include "theme-manager.h"
 #include "util.h"
 
 #include "gtkaccount.h"
@@ -58,6 +60,8 @@
 #include "gtkstatusbox.h"
 #include "gtkscrollbook.h"
 #include "gtksmiley.h"
+#include "gtkblist-theme-loader.h"
+#include "gtkblist-theme.h"
 #include "gtkutils.h"
 #include "pidgin/minidialog.h"
 #include "pidgin/pidgintooltip.h"
@@ -121,6 +125,9 @@
 	 *  is showing; @c NULL otherwise.
 	 */
 	PidginMiniDialog *signed_on_elsewhere;
+
+	PidginBlistTheme *current_theme;
+
 } PidginBuddyListPrivate;
 
 #define PIDGIN_BUDDY_LIST_GET_PRIVATE(list) \
@@ -179,17 +186,6 @@
 	} conv;
 } PidginBlistNode;
 
-static char dim_grey_string[8] = "";
-static char *dim_grey(void)
-{
-	if (!gtkblist)
-		return "dim grey";
-	if (!dim_grey_string[0]) {
-		snprintf(dim_grey_string, sizeof(dim_grey_string), "%s", pidgin_get_dim_grey_string(gtkblist->treeview)); 
-	}
-	return dim_grey_string;
-}
-
 /***************************************************
  *              Callbacks                          *
  ***************************************************/
@@ -329,17 +325,24 @@
 
 static void gtk_blist_menu_info_cb(GtkWidget *w, PurpleBuddy *b)
 {
-	pidgin_retrieve_user_info(b->account->gc, purple_buddy_get_name(b));
+	PurpleAccount *account = purple_buddy_get_account(b);
+
+	pidgin_retrieve_user_info(purple_account_get_connection(account),
+	                          purple_buddy_get_name(b));
 }
 
 static void gtk_blist_menu_im_cb(GtkWidget *w, PurpleBuddy *b)
 {
-	pidgin_dialogs_im_with_user(b->account, b->name);
+	pidgin_dialogs_im_with_user(purple_buddy_get_account(b),
+	                            purple_buddy_get_name(b));
 }
 
 static void gtk_blist_menu_send_file_cb(GtkWidget *w, PurpleBuddy *b)
 {
-	serv_send_file(b->account->gc, b->name, NULL);
+	PurpleAccount *account = purple_buddy_get_account(b);
+
+	serv_send_file(purple_account_get_connection(account),
+	               purple_buddy_get_name(b), NULL);
 }
 
 static void gtk_blist_menu_move_to_cb(GtkWidget *w, PurpleBlistNode *node)
@@ -364,7 +367,7 @@
 static PurpleConversation *
 find_conversation_with_buddy(PurpleBuddy *buddy)
 {
-	PidginBlistNode *ui = buddy->node.ui_data;
+	PidginBlistNode *ui = purple_blist_node_get_ui_data(PURPLE_BLIST_NODE(buddy));
 	if (ui)
 		return ui->conv.conv;
 	return purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
@@ -374,15 +377,20 @@
 
 static void gtk_blist_join_chat(PurpleChat *chat)
 {
+	PurpleAccount *account;
 	PurpleConversation *conv;
 	PurplePluginProtocolInfo *prpl_info;
+	GHashTable *components;
 	const char *name;
 	char *chat_name;
 
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(chat->account)));
+	account = purple_chat_get_account(chat);
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(account)));
+
+	components = purple_chat_get_components(chat);
 
 	if (prpl_info && prpl_info->get_chat_name)
-		chat_name = prpl_info->get_chat_name(chat->components);
+		chat_name = prpl_info->get_chat_name(components);
 	else
 		chat_name = NULL;
 
@@ -392,14 +400,14 @@
 		name = purple_chat_get_name(chat);
 
 	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, name,
-											   chat->account);
+	                                             account);
 
 	if (conv != NULL) {
 		pidgin_conv_attach_to_conversation(conv);
 		purple_conversation_present(conv);
 	}
 
-	serv_join_chat(chat->account->gc, chat->components);
+	serv_join_chat(purple_account_get_connection(account), components);
 	g_free(chat_name);
 }
 
@@ -434,15 +442,15 @@
 	gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &val);
 	node = g_value_get_pointer(&val);
 
-	switch (node->type) {
+	switch (purple_blist_node_get_type(node)) {
 	case PURPLE_BLIST_CONTACT_NODE:
-		text = purple_contact_get_alias((PurpleContact *)node);
+		text = purple_contact_get_alias(PURPLE_CONTACT(node));
 		break;
 	case PURPLE_BLIST_BUDDY_NODE:
-		text = purple_buddy_get_alias((PurpleBuddy *)node);
+		text = purple_buddy_get_alias(PURPLE_BUDDY(node));
 		break;
 	case PURPLE_BLIST_GROUP_NODE:
-		text = ((PurpleGroup *)node)->name;
+		text = purple_group_get_name(PURPLE_GROUP(node));
 		break;
 	default:
 		g_return_if_reached();
@@ -470,17 +478,24 @@
 	for (tmp = merges; tmp; tmp = tmp->next) {
 		PurpleBlistNode *node = tmp->data;
 		PurpleBlistNode *b;
+		PurpleBlistNodeType type;
 		int i = 0;
 
-		if (node->type == PURPLE_BLIST_BUDDY_NODE)
-			node = node->parent;
-
-		if (node->type != PURPLE_BLIST_CONTACT_NODE)
+		type = purple_blist_node_get_type(node);
+
+		if(type == PURPLE_BLIST_BUDDY_NODE)
+			node = purple_blist_node_get_parent(node);
+
+		if(type == PURPLE_BLIST_CONTACT_NODE)
 			continue;
-		
-
-		for (b = node->child; b; b = b->next)
+
+		for (b = purple_blist_node_get_first_child(node);
+		     b;
+		     b = purple_blist_node_get_sibling_next(b))
+		{
 			i++;
+		}
+
 		if (i > max) {
 			contact = node;
 			max = i;
@@ -493,8 +508,8 @@
 	/* Merge all those buddies into this contact */
 	for (tmp = merges; tmp; tmp = tmp->next) {
 		PurpleBlistNode *node = tmp->data;
-		if (node->type == PURPLE_BLIST_BUDDY_NODE)
-			node = node->parent;
+		if (purple_blist_node_get_type(node) == PURPLE_BLIST_BUDDY_NODE)
+			node = purple_blist_node_get_parent(node);
 
 		if (node == contact)
 			continue;
@@ -516,9 +531,11 @@
 	int i = 0;
 	char *a = g_utf8_casefold(alias, -1);
 
-	for (contact = group->child; contact; contact = contact->next) {
+	for (contact = purple_blist_node_get_first_child(group);
+	     contact != NULL;
+	     contact = purple_blist_node_get_sibling_next(contact)) {
 		char *node_alias;
-		if (contact->type != PURPLE_BLIST_CONTACT_NODE)
+		if (purple_blist_node_get_type(contact) != PURPLE_BLIST_CONTACT_NODE)
 			continue;
 
 		node_alias = g_utf8_casefold(purple_contact_get_alias((PurpleContact *)contact), -1);
@@ -530,11 +547,14 @@
 		}
 		g_free(node_alias);
 
-		for (buddy = contact->child; buddy; buddy = buddy->next) {
-			if (buddy->type != PURPLE_BLIST_BUDDY_NODE)
+		for (buddy = purple_blist_node_get_first_child(contact);
+		     buddy;
+		     buddy = purple_blist_node_get_sibling_next(buddy))
+		{
+			if (purple_blist_node_get_type(buddy) != PURPLE_BLIST_BUDDY_NODE)
 				continue;
 
-			node_alias = g_utf8_casefold(purple_buddy_get_alias((PurpleBuddy *)buddy), -1);
+			node_alias = g_utf8_casefold(purple_buddy_get_alias(PURPLE_BUDDY(buddy)), -1);
 			if (node_alias && !g_utf8_collate(node_alias, a)) {
 				merges = g_list_append(merges, buddy);
 				i++;
@@ -576,39 +596,45 @@
 	gtk_tree_view_set_enable_search (GTK_TREE_VIEW(gtkblist->treeview), TRUE);
 	g_object_set(G_OBJECT(gtkblist->text_rend), "editable", FALSE, NULL);
 
-	switch (node->type)
+	switch (purple_blist_node_get_type(node))
 	{
 		case PURPLE_BLIST_CONTACT_NODE:
 			{
-				PurpleContact *contact = (PurpleContact *)node;
-				struct _pidgin_blist_node *gtknode = (struct _pidgin_blist_node *)node->ui_data;
-
-				if (contact->alias || gtknode->contact_expanded) {
+				PurpleContact *contact = PURPLE_CONTACT(node);
+				struct _pidgin_blist_node *gtknode =
+					(struct _pidgin_blist_node *)purple_blist_node_get_ui_data(node);
+
+				if (purple_contact_get_alias(contact) || gtknode->contact_expanded) {
 					purple_blist_alias_contact(contact, arg2);
-					gtk_blist_auto_personize(node->parent, arg2);
+					gtk_blist_auto_personize(purple_blist_node_get_parent(node), arg2);
 				} else {
 					PurpleBuddy *buddy = purple_contact_get_priority_buddy(contact);
 					purple_blist_alias_buddy(buddy, arg2);
 					serv_alias_buddy(buddy);
-					gtk_blist_auto_personize(node->parent, arg2);
+					gtk_blist_auto_personize(purple_blist_node_get_parent(node), arg2);
 				}
 			}
 			break;
 
 		case PURPLE_BLIST_BUDDY_NODE:
-			purple_blist_alias_buddy((PurpleBuddy*)node, arg2);
-			serv_alias_buddy((PurpleBuddy *)node);
-			gtk_blist_auto_personize(node->parent->parent, arg2);
+			{
+				PurpleGroup *group = purple_buddy_get_group(PURPLE_BUDDY(node));
+
+				purple_blist_alias_buddy(PURPLE_BUDDY(node), arg2);
+				serv_alias_buddy(PURPLE_BUDDY(node));
+				gtk_blist_auto_personize(PURPLE_BLIST_NODE(group), arg2);
+			}
 			break;
 		case PURPLE_BLIST_GROUP_NODE:
 			dest = purple_find_group(arg2);
-			if (dest != NULL && strcmp(arg2, ((PurpleGroup*) node)->name)) {
-				pidgin_dialogs_merge_groups((PurpleGroup*) node, arg2);
-			} else
-				purple_blist_rename_group((PurpleGroup*)node, arg2);
+			if (dest != NULL && strcmp(arg2, purple_group_get_name(PURPLE_GROUP(node)))) {
+				pidgin_dialogs_merge_groups(PURPLE_GROUP(node), arg2);
+			} else {
+				purple_blist_rename_group(PURPLE_GROUP(node), arg2);
+			}
 			break;
 		case PURPLE_BLIST_CHAT_NODE:
-			purple_blist_alias_chat((PurpleChat*)node, arg2);
+			purple_blist_alias_chat(PURPLE_CHAT(node), arg2);
 			break;
 		default:
 			break;
@@ -695,7 +721,7 @@
 
 	if (!(get_iter_from_node(node, &iter))) {
 		/* This is either a bug, or the buddy is in a collapsed contact */
-		node = node->parent;
+		node = purple_blist_node_get_parent(node);
 		if (!get_iter_from_node(node, &iter))
 			/* Now it's definitely a bug */
 			return;
@@ -718,7 +744,8 @@
 
 static void gtk_blist_menu_bp_cb(GtkWidget *w, PurpleBuddy *b)
 {
-	pidgin_pounce_editor_show(b->account, b->name, NULL);
+	pidgin_pounce_editor_show(purple_buddy_get_account(b),
+	                          purple_buddy_get_name(b), NULL);
 }
 
 static void gtk_blist_menu_showlog_cb(GtkWidget *w, PurpleBlistNode *node)
@@ -732,19 +759,19 @@
 	if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 		PurpleBuddy *b = (PurpleBuddy*) node;
 		type = PURPLE_LOG_IM;
-		name = g_strdup(b->name);
-		account = b->account;
+		name = g_strdup(purple_buddy_get_name(b));
+		account = purple_buddy_get_account(b);
 	} else if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
-		PurpleChat *c = (PurpleChat*) node;
+		PurpleChat *c = PURPLE_CHAT(node);
 		PurplePluginProtocolInfo *prpl_info = NULL;
 		type = PURPLE_LOG_CHAT;
-		account = c->account;
+		account = purple_chat_get_account(c);
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(account)));
 		if (prpl_info && prpl_info->get_chat_name) {
-			name = prpl_info->get_chat_name(c->components);
+			name = prpl_info->get_chat_name(purple_chat_get_components(c));
 		}
 	} else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
-		pidgin_log_show_contact((PurpleContact *)node);
+		pidgin_log_show_contact(PURPLE_CONTACT(node));
 		pidgin_clear_cursor(gtkblist->window);
 		return;
 	} else {
@@ -777,7 +804,10 @@
 		gboolean setting = !purple_blist_node_get_bool(node, "show_offline");
 
 		purple_blist_node_set_bool(node, "show_offline", setting);
-		for (bnode = node->child; bnode != NULL; bnode = bnode->next) {
+		for (bnode = purple_blist_node_get_first_child(node);
+		     bnode != NULL;
+		     bnode = purple_blist_node_get_sibling_next(bnode))
+		{
 			purple_blist_node_set_bool(bnode, "show_offline", setting);
 			pidgin_blist_update(purple_get_blist(), bnode);
 		}
@@ -786,9 +816,15 @@
 		gboolean setting = !purple_blist_node_get_bool(node, "show_offline");
 
 		purple_blist_node_set_bool(node, "show_offline", setting);
-		for (cnode = node->child; cnode != NULL; cnode = cnode->next) {
+		for (cnode = purple_blist_node_get_first_child(node);
+		     cnode != NULL;
+		     cnode = purple_blist_node_get_sibling_next(cnode))
+		{
 			purple_blist_node_set_bool(cnode, "show_offline", setting);
-			for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) {
+			for (bnode = purple_blist_node_get_first_child(cnode);
+			     bnode != NULL;
+			     bnode = purple_blist_node_get_sibling_next(bnode))
+			{
 				purple_blist_node_set_bool(bnode, "show_offline", setting);
 				pidgin_blist_update(purple_get_blist(), bnode);
 			}
@@ -900,9 +936,10 @@
 static void
 pidgin_blist_update_privacy_cb(PurpleBuddy *buddy)
 {
-	if (buddy->node.ui_data == NULL || ((struct _pidgin_blist_node*)buddy->node.ui_data)->row == NULL)
+	struct _pidgin_blist_node *ui_data = purple_blist_node_get_ui_data(PURPLE_BLIST_NODE(buddy));
+	if (ui_data == NULL || ui_data->row == NULL)
 		return;
-	pidgin_blist_update_buddy(purple_get_blist(), (PurpleBlistNode*)(buddy), TRUE);
+	pidgin_blist_update_buddy(purple_get_blist(), PURPLE_BLIST_NODE(buddy), TRUE);
 }
 
 static void
@@ -1030,7 +1067,7 @@
 	GtkWidget *img = NULL;
 	PidginJoinChatData *data = NULL;
 
-	gtkblist = PIDGIN_BLIST(purple_get_blist());
+	gtkblist = purple_blist_get_ui_data();
 	img = gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION,
 					gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE));
 	data = g_new0(PidginJoinChatData, 1);
@@ -1790,7 +1827,8 @@
 	return handled;
 }
 
-static gboolean gtk_blist_button_press_cb(GtkWidget *tv, GdkEventButton *event, gpointer user_data)
+static gboolean 
+gtk_blist_button_press_cb(GtkWidget *tv, GdkEventButton *event, gpointer user_data)
 {
 	GtkTreePath *path;
 	PurpleBlistNode *node;
@@ -2494,7 +2532,7 @@
 				node = g_value_get_pointer(&val);
 
 				if (PURPLE_BLIST_NODE_IS_BUDDY(node) || PURPLE_BLIST_NODE_IS_CONTACT(node)) {
-					PurpleBuddy *b = PURPLE_BLIST_NODE_IS_BUDDY(node) ? (PurpleBuddy*)node : purple_contact_get_priority_buddy((PurpleContact*)node);
+					PurpleBuddy *b = PURPLE_BLIST_NODE_IS_BUDDY(node) ? PURPLE_BUDDY(node) : purple_contact_get_priority_buddy(PURPLE_CONTACT(node));
 					pidgin_dnd_file_manage(sd, b->account, b->name);
 					gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t);
 				} else {
@@ -2979,6 +3017,22 @@
 	pidgin_tooltip_destroy();
 }
 
+static void
+pidgin_blist_align_tooltip(struct tooltip_data *td, GtkWidget *widget) 
+{ 
+	GtkTextDirection dir = gtk_widget_get_direction(widget); 
+
+	if (dir == GTK_TEXT_DIR_RTL) 
+	{
+		char* layout_name = purple_markup_strip_html(pango_layout_get_text(td->name_layout));
+		PangoDirection dir = pango_find_base_dir(layout_name, -1);
+		if (dir == PANGO_DIRECTION_RTL || dir == PANGO_DIRECTION_NEUTRAL)
+			pango_layout_set_alignment(td->name_layout, PANGO_ALIGN_RIGHT); 
+		g_free(layout_name);
+		pango_layout_set_alignment(td->layout, PANGO_ALIGN_RIGHT); 
+	}
+}
+
 static gboolean
 pidgin_blist_create_tooltip_for_node(GtkWidget *widget, gpointer data, int *w, int *h)
 {
@@ -2998,11 +3052,13 @@
 	if (PURPLE_BLIST_NODE_IS_CHAT(node) ||
 	   PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 		struct tooltip_data *td = create_tip_for_node(node, TRUE);
+		pidgin_blist_align_tooltip(td, gtkblist->tipwindow);
 		gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td);
 	} else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
 		PurpleGroup *group = (PurpleGroup*)node;
 		GSList *accounts;
 		struct tooltip_data *td = create_tip_for_node(node, TRUE);
+		pidgin_blist_align_tooltip(td, gtkblist->tipwindow);
 		gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td);
 
 		/* Accounts with buddies in group */
@@ -3022,6 +3078,7 @@
 		{
 			if(PURPLE_BLIST_NODE_IS_BUDDY(child) && buddy_is_displayable((PurpleBuddy*)child)) {
 				struct tooltip_data *td = create_tip_for_node(child, (b == (PurpleBuddy*)child));
+				pidgin_blist_align_tooltip(td, gtkblist->tipwindow);
 				if (b == (PurpleBuddy *)child) {
 					gtkblist->tooltipdata = g_list_prepend(gtkblist->tooltipdata, td);
 				} else {
@@ -3301,6 +3358,7 @@
 	if (PURPLE_BLIST_NODE_IS_CHAT(node))
 	{
 		PurpleChat *chat;
+		GList *connections;
 		GList *cur;
 		struct proto_chat_entry *pce;
 		char *name, *value;
@@ -3311,7 +3369,8 @@
 		prpl = purple_find_prpl(purple_account_get_protocol_id(chat->account));
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
-		if (g_list_length(purple_connections_get_all()) > 1)
+		connections = purple_connections_get_all();
+		if (connections && connections->next)
 		{
 			tmp = g_markup_escape_text(chat->account->username, -1);
 			g_string_append_printf(str, _("<b>Account:</b> %s"), tmp);
@@ -3381,6 +3440,7 @@
 		PurpleBuddy *b;
 		PurplePresence *presence;
 		PurpleNotifyUserInfo *user_info;
+		GList *connections;
 		char *tmp;
 		time_t idle_secs, signon;
 
@@ -3402,7 +3462,8 @@
 		user_info = purple_notify_user_info_new();
 
 		/* Account */
-		if (full && g_list_length(purple_connections_get_all()) > 1)
+		connections = purple_connections_get_all();
+		if (full && connections && connections->next)
 		{
 			tmp = g_markup_escape_text(purple_account_get_username(
 									   purple_buddy_get_account(b)), -1);
@@ -3776,19 +3837,22 @@
 	return ret;
 }
 
-gchar *pidgin_blist_get_name_markup(PurpleBuddy *b, gboolean selected, gboolean aliased)
-{
-	const char *name;
-	char *esc, *text = NULL;
+gchar *
+pidgin_blist_get_name_markup(PurpleBuddy *b, gboolean selected, gboolean aliased)
+{
+	const char *name, *name_color, *name_font, *status_color, *status_font;
+	char *text = NULL;
 	PurplePlugin *prpl;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleContact *contact;
 	PurplePresence *presence;
 	struct _pidgin_blist_node *gtkcontactnode = NULL;
-	char *idletime = NULL, *statustext = NULL;
-	time_t t;
+	char *idletime = NULL, *statustext = NULL, *nametext = NULL;
 	PurpleConversation *conv = find_conversation_with_buddy(b);
 	gboolean hidden_conv = FALSE;
+	gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
+	FontColorPair *pair;
+	PidginBlistTheme *theme;
 
 	if (conv != NULL) {
 		PidginBlistNode *ui = b->node.ui_data;
@@ -3802,178 +3866,168 @@
 	}
 
 	/* XXX Good luck cleaning up this crap */
-	contact = (PurpleContact*)((PurpleBlistNode*)b)->parent;
+	contact = PURPLE_CONTACT(PURPLE_BLIST_NODE(b)->parent);
 	if(contact)
-		gtkcontactnode = ((PurpleBlistNode*)contact)->ui_data;
-
-	if(gtkcontactnode && !gtkcontactnode->contact_expanded && contact->alias)
+		gtkcontactnode = purple_blist_node_get_ui_data(PURPLE_BLIST_NODE(contact));
+
+	/* Name */
+	if (gtkcontactnode && !gtkcontactnode->contact_expanded && contact->alias)
 		name = contact->alias;
 	else
 		name = purple_buddy_get_alias(b);
 	
-	esc = g_markup_escape_text(name, strlen(name));
+	nametext = g_markup_escape_text(name, strlen(name));
 
 	presence = purple_buddy_get_presence(b);
 
-	if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons") && aliased)
-	{
-		if (!selected && purple_presence_is_idle(presence))
-		{
-			text = g_strdup_printf("<span color='%s'>%s</span>",
-					       dim_grey(), esc);
-			g_free(esc);
-			if (hidden_conv) {
-				char *tmp = text;
-				text = g_strdup_printf("<b>%s</b>", text);
+	/* Name is all that is needed */
+	if (aliased && biglist) {
+
+		/* Status Info */
+		prpl = purple_find_prpl(purple_account_get_protocol_id(b->account));
+	
+		if (prpl != NULL)
+			prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+	
+		if (prpl_info && prpl_info->status_text && b->account->gc) {
+			char *tmp = prpl_info->status_text(b);
+			const char *end;
+	
+			if(tmp && !g_utf8_validate(tmp, -1, &end)) {
+				char *new = g_strndup(tmp,
+						g_utf8_pointer_to_offset(tmp, end));
+				g_free(tmp);
+				tmp = new;
+			}
+			/* add ... to messages that are too long, GTK 2.6+ does it automatically */
+#if !GTK_CHECK_VERSION(2,6,0)
+			if(tmp) {
+				char buf[32];
+				char *c = tmp;
+				int length = 0, vis=0;
+				gboolean inside = FALSE;
+				g_strdelimit(tmp, "\n", ' ');
+				purple_str_strip_char(tmp, '\r');
+	
+				while(*c && vis < 20) {
+					if(*c == '&')
+						inside = TRUE;
+					else if(*c == ';')
+						inside = FALSE;
+					if(!inside)
+						vis++;
+					c = g_utf8_next_char(c); /* this is fun */
+				}
+	
+				length = c - tmp;
+
+				if(vis == 20)
+					g_snprintf(buf, sizeof(buf), "%%.%ds...", length);
+				else
+					g_snprintf(buf, sizeof(buf), "%%s ");
+	
+				statustext = g_strdup_printf(buf, tmp);purple_presence_is_idle(presence)
+	
 				g_free(tmp);
 			}
-			return text;
-		}
-		else if (hidden_conv)
-		{
-			char *tmp = esc;
-			esc = g_strdup_printf("<b>%s</b>", esc);
-			g_free(tmp);
-		}
-		return esc;
-	}
-
-	prpl = purple_find_prpl(purple_account_get_protocol_id(b->account));
-
-	if (prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-
-	if (prpl_info && prpl_info->status_text && b->account->gc) {
-		char *tmp = prpl_info->status_text(b);
-		const char *end;
-
-		if(tmp && !g_utf8_validate(tmp, -1, &end)) {
-			char *new = g_strndup(tmp,
-					g_utf8_pointer_to_offset(tmp, end));
-			g_free(tmp);
-			tmp = new;
+#else	
+			if(tmp) {
+				g_strdelimit(tmp, "\n", ' ');
+				purple_str_strip_char(tmp, '\r');
+			}
+			statustext = tmp;
+#endif	
 		}
-
-#if !GTK_CHECK_VERSION(2,6,0)
-		if(tmp) {
-			char buf[32];
-			char *c = tmp;
-			int length = 0, vis=0;
-			gboolean inside = FALSE;
-			g_strdelimit(tmp, "\n", ' ');
-			purple_str_strip_char(tmp, '\r');
-
-			while(*c && vis < 20) {
-				if(*c == '&')
-					inside = TRUE;
-				else if(*c == ';')
-					inside = FALSE;
-				if(!inside)
-					vis++;
-				c = g_utf8_next_char(c); /* this is fun */
-			}
-
-			length = c - tmp;
-
-			if(vis == 20)
-				g_snprintf(buf, sizeof(buf), "%%.%ds...", length);
-			else
-				g_snprintf(buf, sizeof(buf), "%%s ");
-
-			statustext = g_strdup_printf(buf, tmp);
-
-			g_free(tmp);
-		}
-#else
-		if(tmp) {
-			g_strdelimit(tmp, "\n", ' ');
-			purple_str_strip_char(tmp, '\r');
-		}
-		statustext = tmp;
-#endif
-	}
-
-	if(!purple_presence_is_online(presence) && !statustext)
-		statustext = g_strdup(_("Offline"));
-	else if (!statustext)
-		text = g_strdup(esc);
-
-	if (purple_presence_is_idle(presence)) {
-		if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time")) {
+	
+		if(!purple_presence_is_online(presence) && !statustext)
+				statustext = g_strdup(_("Offline"));
+		
+		/* Idle Text */ 
+		if (purple_presence_is_idle(presence) && purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time")) {
 			time_t idle_secs = purple_presence_get_idle_time(presence);
 
 			if (idle_secs > 0) {
 				int iday, ihrs, imin;
+				time_t t;
 
 				time(&t);
 				iday = (t - idle_secs) / (24 * 60 * 60);
 				ihrs = ((t - idle_secs) / 60 / 60) % 24;
 				imin = ((t - idle_secs) / 60) % 60;
-
-                if (iday)
+	
+               			if (iday)
 					idletime = g_strdup_printf(_("Idle %dd %dh %02dm"), iday, ihrs, imin);
 				else if (ihrs)
 					idletime = g_strdup_printf(_("Idle %dh %02dm"), ihrs, imin);
 				else
 					idletime = g_strdup_printf(_("Idle %dm"), imin);
-			}
-			else
-				idletime = g_strdup(_("Idle"));
-
-			if (!selected) {
-				g_free(text);
-				text = g_strdup_printf("<span color='%s'>%s</span>\n"
-					"<span color='%s' size='smaller'>%s%s%s</span>",
-					dim_grey(), esc, dim_grey(),
-					idletime != NULL ? idletime : "",
-					(idletime != NULL && statustext != NULL) ? " - " : "",
-					statustext != NULL ? statustext : "");
-			}
-		}
-		else if (!selected && !statustext) {/* We handle selected text later */
-			g_free(text);
-			text = g_strdup_printf("<span color='%s'>%s</span>", dim_grey(), esc);
-		} else if (!selected && !text) {
-			g_free(text);
-			text = g_strdup_printf("<span color='%s'>%s</span>\n"
-				"<span color='%s' size='smaller'>%s</span>",
-				dim_grey(), esc, dim_grey(),
-				statustext != NULL ? statustext : "");
+
+			} else idletime = g_strdup(_("Idle"));
 		}
-	} else if (!PURPLE_BUDDY_IS_ONLINE(b)) {
-		if (!selected && !statustext) {/* We handle selected text later */
-			g_free(text);
-			text = g_strdup_printf("<span color='%s'>%s</span>", dim_grey(), esc);
-		} else if (!selected && !text)
-			text = g_strdup_printf("<span color='%s'>%s</span>\n"
-				"<span color='%s' size='smaller'>%s</span>",
-				dim_grey(), esc, dim_grey(),
-				statustext != NULL ? statustext : "");
-
-	}
-	/* Not idle and not selected */
-	else if (!selected && !text)
-	{
-		text = g_strdup_printf("%s\n"
-			"<span color='%s' size='smaller'>%s</span>",
-			esc, dim_grey(),
-			statustext != NULL ? statustext :  "");
-	}
-
-	/* It is selected. */
-	if ((selected && !text) || (selected && idletime)) {
-		g_free(text);
-		text = g_strdup_printf("%s\n"
-			"<span size='smaller'>%s%s%s</span>",
-			esc,
-			idletime != NULL ? idletime : "",
-			(idletime != NULL && statustext != NULL) ? " - " : "",
-			statustext != NULL ? statustext :  "");
-	}
-
-	g_free(idletime);
-	g_free(statustext);
-	g_free(esc);
+	}
+
+	/* choose the colors of the text */
+	theme = pidgin_blist_get_theme();
+
+	if (theme == NULL) {
+		status_color = name_color = "dim grey";
+		status_font = name_font = "";
+
+	} else  if (purple_presence_is_idle(presence)) {
+		pair = pidgin_blist_theme_get_idle_text_info(theme);
+		status_color = name_color = (pair != NULL && pair->color != NULL) ? pair->color : "dim grey";
+		status_font = name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
+
+	} else if (!purple_presence_is_online(presence)) {
+		pair = pidgin_blist_theme_get_offline_text_info(theme);
+		name_color = (pair != NULL && pair->color != NULL) ? pair->color : "black";
+		name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
+
+		pair = pidgin_blist_theme_get_status_text_info(theme);
+		status_color = (pair != NULL && pair->color != NULL) ? g_strdup(pair->color) : "dim grey";
+		status_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
+
+	} else if (purple_presence_is_available(presence)) {
+		pair = pidgin_blist_theme_get_online_text_info(theme);
+		name_color = (pair != NULL && pair->color != NULL) ? g_strdup(pair->color) : "black";
+		name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
+
+		pair = pidgin_blist_theme_get_status_text_info(theme);
+		status_color = (pair != NULL && pair->color != NULL) ? pair->color : "dim grey";
+		status_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
+
+	} else {
+		pair = pidgin_blist_theme_get_away_text_info(theme);
+		name_color = (pair != NULL && pair->color != NULL) ? pair->color : "black";
+		name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
+
+		pair = pidgin_blist_theme_get_status_text_info(theme);
+		status_color = (pair != NULL && pair->color != NULL) ? pair->color : "dim grey";
+		status_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
+	}
+
+	if (aliased && selected) {
+		name_color = "black";
+		status_color = "black";
+	}
+
+	/* Put it all together */
+	if (aliased && biglist && (statustext || idletime)) {
+		/* using <span size='smaller'> breaks the status, so it must be seperated into <small><span>*/
+		text = g_strdup_printf("<span font_desc='%s' foreground='%s'>%s</span>\n"
+				 	"<small><span font_desc='%s' foreground='%s'>%s%s%s</span></small>", 
+					name_font, name_color, nametext, status_font, status_color, 
+					idletime != NULL ? idletime : "",
+				        (idletime != NULL && statustext != NULL) ? " - " : "",
+				        statustext != NULL ? statustext : ""); 
+
+	} else text = g_strdup_printf("<span font_desc='%s' color='%s'>%s</span>", name_font, name_color, nametext); 
+
+	g_free(nametext);
+	if (statustext)
+		g_free(statustext);
+	if (idletime)
+		g_free(idletime);
 
 	if (hidden_conv) {
 		char *tmp = text;
@@ -5219,11 +5273,144 @@
 }
 #endif
 
+/* builds the blist layout according to to the current theme */
+static void
+pidgin_blist_build_layout(PurpleBuddyList *list)
+{
+	GtkTreeViewColumn *column;
+	PidginBlistLayout *layout;
+	PidginBlistTheme *theme;
+	GtkCellRenderer *rend;
+	gint i, status_icon = 0, text = 1, emblem = 2, protocol_icon = 3, buddy_icon = 4;
+	
+
+	column = gtkblist->text_column;
+
+	if ((theme = pidgin_blist_get_theme()) != NULL && (layout = pidgin_blist_theme_get_layout(theme)) != NULL) {
+		status_icon = layout->status_icon ;				
+		text = layout->text;
+		emblem = layout->emblem;
+		protocol_icon = layout->protocol_icon;
+		buddy_icon = layout->buddy_icon;
+	}
+
+	gtk_tree_view_column_clear(column);
+
+	/* group */
+	rend = pidgin_cell_renderer_expander_new();
+	gtk_tree_view_column_pack_start(column, rend, FALSE);
+	gtk_tree_view_column_set_attributes(column, rend,
+					    "visible", GROUP_EXPANDER_VISIBLE_COLUMN,
+					    "expander-visible", GROUP_EXPANDER_COLUMN,
+#if GTK_CHECK_VERSION(2,6,0)
+					    "sensitive", GROUP_EXPANDER_COLUMN,
+					    "cell-background-gdk", BGCOLOR_COLUMN,
+#endif
+					    NULL);
+
+	/* contact */
+	rend = pidgin_cell_renderer_expander_new();
+	gtk_tree_view_column_pack_start(column, rend, FALSE);
+	gtk_tree_view_column_set_attributes(column, rend,
+					    "visible", CONTACT_EXPANDER_VISIBLE_COLUMN,
+					    "expander-visible", CONTACT_EXPANDER_COLUMN,
+#if GTK_CHECK_VERSION(2,6,0)
+					    "sensitive", CONTACT_EXPANDER_COLUMN,
+					    "cell-background-gdk", BGCOLOR_COLUMN,
+#endif  
+					    NULL);
+
+	for (i = 0; i < 5; i++) {
+
+		if (status_icon == i) {		
+			/* status icons */
+			rend = gtk_cell_renderer_pixbuf_new();
+			gtk_tree_view_column_pack_start(column, rend, FALSE);
+			gtk_tree_view_column_set_attributes(column, rend,
+							    "pixbuf", STATUS_ICON_COLUMN,
+							    "visible", STATUS_ICON_VISIBLE_COLUMN,
+#if GTK_CHECK_VERSION(2,6,0)
+							    "cell-background-gdk", BGCOLOR_COLUMN,
+#endif	
+							    NULL);
+			g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL);
+
+		} else if (text == i) {
+			/* name */
+			gtkblist->text_rend = rend = gtk_cell_renderer_text_new();
+			gtk_tree_view_column_pack_start(column, rend, TRUE);
+			gtk_tree_view_column_set_attributes(column, rend,
+#if GTK_CHECK_VERSION(2,6,0)
+							    "cell-background-gdk", BGCOLOR_COLUMN,
+#endif
+							    "markup", NAME_COLUMN,
+							    NULL);
+#if GTK_CHECK_VERSION(2,6,0)
+			g_signal_connect(G_OBJECT(rend), "editing-started", G_CALLBACK(gtk_blist_renderer_editing_started_cb), NULL);
+			g_signal_connect(G_OBJECT(rend), "editing-canceled", G_CALLBACK(gtk_blist_renderer_editing_cancelled_cb), list);
+#endif
+			g_signal_connect(G_OBJECT(rend), "edited", G_CALLBACK(gtk_blist_renderer_edited_cb), list);
+			g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL);
+#if GTK_CHECK_VERSION(2,6,0)
+			g_object_set(rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+#endif
+
+			/* idle */
+			rend = gtk_cell_renderer_text_new();
+			g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL);
+			gtk_tree_view_column_pack_start(column, rend, FALSE);
+			gtk_tree_view_column_set_attributes(column, rend,
+							    "markup", IDLE_COLUMN,
+							    "visible", IDLE_VISIBLE_COLUMN,
+#if GTK_CHECK_VERSION(2,6,0)
+							    "cell-background-gdk", BGCOLOR_COLUMN,
+#endif
+							    NULL);
+		} else if (emblem == i) {
+			/* emblem */
+			rend = gtk_cell_renderer_pixbuf_new();
+			g_object_set(rend, "xalign", 1.0, "yalign", 0.5, "ypad", 0, "xpad", 3, NULL);
+			gtk_tree_view_column_pack_start(column, rend, FALSE);
+			gtk_tree_view_column_set_attributes(column, rend, "pixbuf", EMBLEM_COLUMN,
+#if GTK_CHECK_VERSION(2,6,0)
+									  "cell-background-gdk", BGCOLOR_COLUMN,
+#endif
+									  "visible", EMBLEM_VISIBLE_COLUMN, NULL);
+
+		} else if (protocol_icon == i) {
+			/* protocol icon */
+			rend = gtk_cell_renderer_pixbuf_new();
+			gtk_tree_view_column_pack_start(column, rend, FALSE);
+			gtk_tree_view_column_set_attributes(column, rend,
+							   "pixbuf", PROTOCOL_ICON_COLUMN,
+							   "visible", PROTOCOL_ICON_VISIBLE_COLUMN,
+#if GTK_CHECK_VERSION(2,6,0)
+							   "cell-background-gdk", BGCOLOR_COLUMN,
+#endif
+							  NULL);
+			g_object_set(rend, "xalign", 0.0, "xpad", 3, "ypad", 0, NULL);
+
+		} else if (buddy_icon == i) {
+			/* buddy icon */
+			rend = gtk_cell_renderer_pixbuf_new();
+			g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL);
+			gtk_tree_view_column_pack_start(column, rend, FALSE);
+			gtk_tree_view_column_set_attributes(column, rend, "pixbuf", BUDDY_ICON_COLUMN,
+#if GTK_CHECK_VERSION(2,6,0)
+							    "cell-background-gdk", BGCOLOR_COLUMN,
+#endif
+							    "visible", BUDDY_ICON_VISIBLE_COLUMN,
+							    NULL);
+		}
+
+	}/* end for loop */
+
+}
+
 static void pidgin_blist_show(PurpleBuddyList *list)
 {
 	PidginBuddyListPrivate *priv;
 	void *handle;
-	GtkCellRenderer *rend;
 	GtkTreeViewColumn *column;
 	GtkWidget *menu;
 	GtkWidget *ebox;
@@ -5249,6 +5436,8 @@
 	gtkblist = PIDGIN_BLIST(list);
 	priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
 
+	priv->current_theme = PIDGIN_BLIST_THEME(purple_theme_manager_find_theme(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"), "blist"));
+
 	gtkblist->empty_avatar = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
 	gdk_pixbuf_fill(gtkblist->empty_avatar, 0x00000000);
 
@@ -5281,8 +5470,8 @@
 	gtk_item_factory_create_items(gtkblist->ift, sizeof(blist_menu) / sizeof(*blist_menu),
 								  blist_menu, NULL);
 	pidgin_load_accels();
-	g_signal_connect(G_OBJECT(accel_group), "accel-changed",
-														G_CALLBACK(pidgin_save_accels_cb), NULL);
+	g_signal_connect(G_OBJECT(accel_group), "accel-changed", G_CALLBACK(pidgin_save_accels_cb), NULL);
+
 	menu = gtk_item_factory_get_widget(gtkblist->ift, "<PurpleMain>");
 	gtkblist->menutray = pidgin_menu_tray_new();
 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtkblist->menutray);
@@ -5432,105 +5621,16 @@
 
 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(gtkblist->treeview), FALSE);
 
+	/* expander columns */
 	column = gtk_tree_view_column_new();
 	gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column);
 	gtk_tree_view_column_set_visible(column, FALSE);
 	gtk_tree_view_set_expander_column(GTK_TREE_VIEW(gtkblist->treeview), column);
 
-	gtkblist->text_column = column = gtk_tree_view_column_new ();
-	rend = pidgin_cell_renderer_expander_new();
-	gtk_tree_view_column_pack_start(column, rend, FALSE);
-	gtk_tree_view_column_set_attributes(column, rend,
-					    "visible", GROUP_EXPANDER_VISIBLE_COLUMN,
-					    "expander-visible", GROUP_EXPANDER_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
-					    "sensitive", GROUP_EXPANDER_COLUMN,
-					    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
-					    NULL);
-
-	rend = pidgin_cell_renderer_expander_new();
-	gtk_tree_view_column_pack_start(column, rend, FALSE);
-	gtk_tree_view_column_set_attributes(column, rend,
-					    "expander-visible", CONTACT_EXPANDER_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
-					    "sensitive", CONTACT_EXPANDER_COLUMN,
-					    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
-					    "visible", CONTACT_EXPANDER_VISIBLE_COLUMN,
-					    NULL);
-
-	rend = gtk_cell_renderer_pixbuf_new();
-	gtk_tree_view_column_pack_start(column, rend, FALSE);
-	gtk_tree_view_column_set_attributes(column, rend,
-					    "pixbuf", STATUS_ICON_COLUMN,
-					    "visible", STATUS_ICON_VISIBLE_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
-					    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
-					    NULL);
-	g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL);
-
-	gtkblist->text_rend = rend = gtk_cell_renderer_text_new();
-	gtk_tree_view_column_pack_start (column, rend, TRUE);
-	gtk_tree_view_column_set_attributes(column, rend,
-#if GTK_CHECK_VERSION(2,6,0)
-					    	    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
-										"markup", NAME_COLUMN,
-										NULL);
-#if GTK_CHECK_VERSION(2,6,0)
-	g_signal_connect(G_OBJECT(rend), "editing-started", G_CALLBACK(gtk_blist_renderer_editing_started_cb), NULL);
-	g_signal_connect(G_OBJECT(rend), "editing-canceled", G_CALLBACK(gtk_blist_renderer_editing_cancelled_cb), list);
-#endif
-	g_signal_connect(G_OBJECT(rend), "edited", G_CALLBACK(gtk_blist_renderer_edited_cb), list);
-	g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL);
-#if GTK_CHECK_VERSION(2,6,0)
-	g_object_set(rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#endif
-	gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), column);
-
-	rend = gtk_cell_renderer_text_new();
-	g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL);
-	gtk_tree_view_column_pack_start(column, rend, FALSE);
-	gtk_tree_view_column_set_attributes(column, rend,
-					    "markup", IDLE_COLUMN,
-					    "visible", IDLE_VISIBLE_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
-					    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
-					    NULL);
-
-	rend = gtk_cell_renderer_pixbuf_new();
-	g_object_set(rend, "xalign", 1.0, "yalign", 0.5, "ypad", 0, "xpad", 3, NULL);
-	gtk_tree_view_column_pack_start(column, rend, FALSE);
-	gtk_tree_view_column_set_attributes(column, rend, "pixbuf", EMBLEM_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
-							  "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
-							  "visible", EMBLEM_VISIBLE_COLUMN, NULL);
-
-	rend = gtk_cell_renderer_pixbuf_new();
-	gtk_tree_view_column_pack_start(column, rend, FALSE);
-	gtk_tree_view_column_set_attributes(column, rend,
-					   "pixbuf", PROTOCOL_ICON_COLUMN,
-					   "visible", PROTOCOL_ICON_VISIBLE_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
-					   "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
-					  NULL);
-	g_object_set(rend, "xalign", 0.0, "xpad", 3, "ypad", 0, NULL);
-
-	rend = gtk_cell_renderer_pixbuf_new();
-	g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL);
-	gtk_tree_view_column_pack_start(column, rend, FALSE);
-	gtk_tree_view_column_set_attributes(column, rend, "pixbuf", BUDDY_ICON_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
-					    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
-					    "visible", BUDDY_ICON_VISIBLE_COLUMN,
-					    NULL);
-
+	/* everything else column */
+	gtkblist->text_column = gtk_tree_view_column_new ();
+	gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), gtkblist->text_column);
+	pidgin_blist_build_layout(list);
 
 	g_signal_connect(G_OBJECT(gtkblist->treeview), "row-activated", G_CALLBACK(gtk_blist_row_activated_cb), NULL);
 	g_signal_connect(G_OBJECT(gtkblist->treeview), "row-expanded", G_CALLBACK(gtk_blist_row_expanded_cb), NULL);
@@ -5957,13 +6057,18 @@
 		GtkTreeIter iter;
 		GtkTreePath *path;
 		gboolean expanded;
-		GdkColor bgcolor;
+		GdkColor *bgcolor = NULL;
 		GdkPixbuf *avatar = NULL;
+		PidginBlistTheme *theme = NULL;
 
 		if(!insert_node(list, gnode, &iter))
 			return;
 
-		bgcolor = gtkblist->treeview->style->bg[GTK_STATE_ACTIVE];
+		if ((theme = pidgin_blist_get_theme()) == NULL)
+			bgcolor = NULL;
+		else if (purple_blist_node_get_bool(gnode, "collapsed") || count <= 0)
+			bgcolor = pidgin_blist_theme_get_collapsed_background_color(theme);
+		else bgcolor = pidgin_blist_theme_get_expanded_background_color(theme);
 
 		path = gtk_tree_model_get_path(GTK_TREE_MODEL(gtkblist->treemodel), &iter);
 		expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(gtkblist->treeview), path);
@@ -5981,7 +6086,7 @@
 				   STATUS_ICON_COLUMN, NULL,
 				   NAME_COLUMN, title,
 				   NODE_COLUMN, gnode,
-	/*			   BGCOLOR_COLUMN, &bgcolor,     */
+				   BGCOLOR_COLUMN, bgcolor,
 				   GROUP_EXPANDER_COLUMN, TRUE,
 				   GROUP_EXPANDER_VISIBLE_COLUMN, TRUE,
 				   CONTACT_EXPANDER_VISIBLE_COLUMN, FALSE,
@@ -6004,6 +6109,9 @@
 	char *mark, *esc;
 	PurpleBlistNode *selected_node = NULL;
 	GtkTreeIter iter;
+	FontColorPair *pair;
+	gchar *text_color, *text_font;
+	PidginBlistTheme *theme;
 
 	group = (PurpleGroup*)gnode;
 
@@ -6019,8 +6127,20 @@
 		           purple_blist_get_group_size(group, FALSE));
 	}
 
+	theme = pidgin_blist_get_theme();
+	if (theme == NULL)
+		pair = NULL;
+	else if 
+		(expanded) pair = pidgin_blist_theme_get_expanded_text_info(theme);
+	else pair = pidgin_blist_theme_get_collapsed_text_info(theme);
+
+	
+	text_color = (selected || pair == NULL || pair->color == NULL) ? "black" : pair->color;
+	text_font = (pair == NULL || pair->font == NULL) ? "" : pair->font;
+
 	esc = g_markup_escape_text(group->name, -1);
-	mark = g_strdup_printf("<span weight='bold'>%s</span>%s", esc ? esc : "", group_count);
+	mark = g_strdup_printf("<span foreground='%s' font_desc='%s'><b>%s</b>%s</span>",
+							text_color, text_font, esc ? esc : "", group_count);
 
 	g_free(esc);
 	return mark;
@@ -6028,14 +6148,15 @@
 
 static void buddy_node(PurpleBuddy *buddy, GtkTreeIter *iter, PurpleBlistNode *node)
 {
-	PurplePresence *presence;
+	PurplePresence *presence = purple_buddy_get_presence(buddy);
 	GdkPixbuf *status, *avatar, *emblem, *prpl_icon;
+	GdkColor *color = NULL;
 	char *mark;
 	char *idle = NULL;
 	gboolean expanded = ((struct _pidgin_blist_node *)(node->parent->ui_data))->contact_expanded;
 	gboolean selected = (gtkblist->selected_node == node);
 	gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
-	presence = purple_buddy_get_presence(buddy);
+	PidginBlistTheme *theme;	
 
 	if (editing_blist)
 		return;
@@ -6059,35 +6180,38 @@
 	emblem = pidgin_blist_get_emblem((PurpleBlistNode*) buddy);
 	mark = pidgin_blist_get_name_markup(buddy, selected, TRUE);
 
+	theme = pidgin_blist_get_theme();
+
 	if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time") &&
-		purple_presence_is_idle(presence) &&
-		!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"))
+		purple_presence_is_idle(presence) && !biglist)
 	{
 		time_t idle_secs = purple_presence_get_idle_time(presence);
 
 		if (idle_secs > 0)
 		{
+			FontColorPair *pair = NULL;
+			const gchar *textcolor;
 			time_t t;
 			int ihrs, imin;
 			time(&t);
+
 			ihrs = (t - idle_secs) / 3600;
 			imin = ((t - idle_secs) / 60) % 60;
-			idle = g_strdup_printf("%d:%02d", ihrs, imin);
-		}
-	}
-
-	if (purple_presence_is_idle(presence))
-	{
-		if (idle && !selected) {
-			char *i2 = g_strdup_printf("<span color='%s'>%s</span>",
-						   dim_grey(), idle);
-			g_free(idle);
-			idle = i2;
+
+			if (!selected && theme != NULL && (pair = pidgin_blist_theme_get_idle_text_info(theme)) != NULL && pair->color != NULL)
+				textcolor = pair->color;
+			else textcolor = "black";
+
+			idle = g_strdup_printf("<span color='%s' font_desc='%s'>%d:%02d</span>", textcolor, 
+					      (pair == NULL || pair->font == NULL) ? "" : pair->font, ihrs, imin);
 		}
 	}
 
 	prpl_icon = pidgin_create_prpl_icon(buddy->account, PIDGIN_PRPL_ICON_SMALL);
 
+	if (theme != NULL)
+		color = pidgin_blist_theme_get_contact_color(theme);
+
 	gtk_tree_store_set(gtkblist->treemodel, iter,
 			   STATUS_ICON_COLUMN, status,
 			   STATUS_ICON_VISIBLE_COLUMN, TRUE,
@@ -6100,7 +6224,7 @@
 			   EMBLEM_VISIBLE_COLUMN, (emblem != NULL),
 			   PROTOCOL_ICON_COLUMN, prpl_icon,
 			   PROTOCOL_ICON_VISIBLE_COLUMN, purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"),
-			   BGCOLOR_COLUMN, NULL,
+			   BGCOLOR_COLUMN, color,
 			   CONTACT_EXPANDER_COLUMN, NULL,
 			   CONTACT_EXPANDER_VISIBLE_COLUMN, expanded,
 			   GROUP_EXPANDER_VISIBLE_COLUMN, FALSE,
@@ -6158,19 +6282,37 @@
 
 		if(gtknode->contact_expanded) {
 			GdkPixbuf *status;
-			char *mark;
+			gchar *mark;
+			GdkColor *color = NULL;
+			PidginBlistTheme *theme = pidgin_blist_get_theme();
+			gboolean selected = (gtkblist->selected_node == cnode);
+			
+			mark = g_markup_escape_text(purple_contact_get_alias(contact), -1);
+
+			if (theme != NULL) {
+				FontColorPair *pair = pidgin_blist_theme_get_contact_text_info(theme);
+				color = pidgin_blist_theme_get_contact_color(theme);
+
+				if (pair != NULL) {
+					gchar *temp = g_strdup_printf("<span foreground='%s' font_desc='%s'>%s</span>",
+								     (selected || pair->color == NULL) ? "black" : pair->color,
+								     (pair->font == NULL) ? "" : pair->font, mark);
+				
+					g_free(mark);
+					mark = temp;
+				}
+			}
 
 			status = pidgin_blist_get_status_icon(cnode,
 					 biglist? PIDGIN_STATUS_ICON_LARGE : PIDGIN_STATUS_ICON_SMALL);
-
-			mark = g_markup_escape_text(purple_contact_get_alias(contact), -1);
+			
 			gtk_tree_store_set(gtkblist->treemodel, &iter,
 					   STATUS_ICON_COLUMN, status,
 					   STATUS_ICON_VISIBLE_COLUMN, TRUE,
 					   NAME_COLUMN, mark,
 					   IDLE_COLUMN, NULL,
 					   IDLE_VISIBLE_COLUMN, FALSE,
-					   BGCOLOR_COLUMN, NULL,
+					   BGCOLOR_COLUMN, color,
 					   BUDDY_ICON_COLUMN, NULL,
 					   CONTACT_EXPANDER_COLUMN, TRUE,
 					   CONTACT_EXPANDER_VISIBLE_COLUMN, TRUE,
@@ -6238,12 +6380,16 @@
 	if(purple_account_is_connected(chat->account)) {
 		GtkTreeIter iter;
 		GdkPixbuf *status, *avatar, *emblem, *prpl_icon;
-		char *mark;
+		gchar *mark, *color, *font, *tmp;
 		gboolean showicons = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
 		gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
 		PidginBlistNode *ui;
 		PurpleConversation *conv;
 		gboolean hidden;
+		GdkColor *bgcolor = NULL;
+		FontColorPair *pair;
+		PidginBlistTheme *theme;
+		gboolean selected = (gtkblist->selected_node == node);
 
 		if (!insert_node(list, node, &iter))
 			return;
@@ -6263,14 +6409,29 @@
 		else
 			avatar = NULL;
 
-		mark = g_markup_escape_text(purple_chat_get_name(chat), -1);
-		if (hidden) {
-			char *bold = g_strdup_printf("<b>%s</b>", mark);
-			g_free(mark);
-			mark = bold;
-		}
+		mark = g_markup_escape_text(purple_chat_get_name(chat), -1);	
+	
+		theme = pidgin_blist_get_theme();
+
+		if (theme == NULL) 
+			pair = NULL;
+		else if (hidden) 
+			pair = pidgin_blist_theme_get_unread_message_text_info(theme);
+		else pair = pidgin_blist_theme_get_online_text_info(theme); 
+			
+		font = (pair == NULL || pair->font == NULL) ? "" : g_strdup(pair->font);
+		color = (selected || pair == NULL || pair->color == NULL) ? "black" : g_strdup(pair->color);
+
+		tmp = g_strdup_printf("<span font_desc='%s' color='%s' weight='%s'>%s</span>", 
+				      font, color, hidden ? "bold" : "normal", mark);
+
+		g_free(mark);
+		mark = tmp;
 
 		prpl_icon = pidgin_create_prpl_icon(chat->account, PIDGIN_PRPL_ICON_SMALL);
+		
+		if (theme != NULL)
+			bgcolor = pidgin_blist_theme_get_contact_color(theme);
 
 		gtk_tree_store_set(gtkblist->treemodel, &iter,
 				STATUS_ICON_COLUMN, status,
@@ -6282,6 +6443,7 @@
 				PROTOCOL_ICON_COLUMN, prpl_icon,
 				PROTOCOL_ICON_VISIBLE_COLUMN, purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"),
 				NAME_COLUMN, mark,
+				BGCOLOR_COLUMN, bgcolor,
 				GROUP_EXPANDER_VISIBLE_COLUMN, FALSE,
 				-1);
 
@@ -6294,6 +6456,7 @@
 			g_object_unref(avatar);
 		if(prpl_icon)
 			g_object_unref(prpl_icon);
+
 	} else {
 		pidgin_blist_hide_node(list, node, TRUE);
 	}
@@ -7153,6 +7316,33 @@
 			(GSourceFunc)buddy_signonoff_timeout_cb, buddy);
 }
 
+void 
+pidgin_blist_set_theme(PidginBlistTheme *theme)
+{
+	PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
+	PurpleBuddyList *list = purple_get_blist();
+
+	if (theme != NULL)
+		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/blist/theme", 
+				purple_theme_get_name(PURPLE_THEME(theme)));
+	else purple_prefs_set_string(PIDGIN_PREFS_ROOT "/blist/theme", "");
+
+	priv->current_theme = theme;
+
+	pidgin_blist_build_layout(list);
+
+	pidgin_blist_refresh(list);
+}
+
+
+PidginBlistTheme *
+pidgin_blist_get_theme()
+{
+	PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);	
+	
+	return priv->current_theme;
+}
+
 void pidgin_blist_init(void)
 {
 	void *gtk_blist_handle = pidgin_blist_get_handle();
@@ -7181,6 +7371,9 @@
 	/* This pref is used in pidgintooltip.c. */
 	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/tooltip_delay", 500);
 #endif
+	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/blist/theme", "");
+
+	purple_theme_manager_register_type(g_object_new(PIDGIN_TYPE_BLIST_THEME_LOADER, "type", "blist", NULL));
 
 	/* Register our signals */
 	purple_signal_register(gtk_blist_handle, "gtkblist-hiding",
--- a/pidgin/gtkblist.h	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtkblist.h	Thu Nov 27 21:15:43 2008 +0000
@@ -59,6 +59,7 @@
 
 #include "pidgin.h"
 #include "blist.h"
+#include "gtkblist-theme.h"
 
 /**************************************************************************
  * @name Structures
@@ -250,6 +251,19 @@
  */
 void pidgin_blist_add_alert(GtkWidget *widget);
 
+/**
+ * Sets the current theme for Pidgin to use
+ *
+ * @param theme	the new theme to use
+ */
+void pidgin_blist_set_theme(PidginBlistTheme *theme);
+
+/**
+ * Gets Pidgin's current buddy list theme
+ *
+ * @returns	the current theme 
+ */
+PidginBlistTheme *pidgin_blist_get_theme(void);
 
 /**************************************************************************
  * @name GTK+ Buddy List sorting functions
--- a/pidgin/gtkcellrendererexpander.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtkcellrendererexpander.c	Thu Nov 27 21:15:43 2008 +0000
@@ -228,7 +228,7 @@
 }
 
 
-static void pidgin_cell_renderer_expander_render (GtkCellRenderer *cell,
+static void pidgin_cell_renderer_expander_render(GtkCellRenderer *cell,
 					       GdkWindow       *window,
 					       GtkWidget       *widget,
 					       GdkRectangle    *background_area,
@@ -237,7 +237,7 @@
 					       guint            flags)
 {
 	PidginCellRendererExpander *cellexpander = (PidginCellRendererExpander *) cell;
-	
+	gboolean set;
 	gint width, height;
 	GtkStateType state;
 
@@ -270,7 +270,10 @@
 			    cell_area->x + cell->xpad + (width / 2),
 			    cell_area->y + cell->ypad + (height / 2),
 			    cell->is_expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED);
-	if (cell->is_expanded)
+
+	/* only draw the line if the color isn't set - this prevents a bug where the hline appears only under the expander */
+	g_object_get(cellexpander, "cell-background-set", &set, NULL);
+	if (cell->is_expanded && !set)
 		gtk_paint_hline (widget->style, window, state, NULL, widget, NULL, 0, 
 				 widget->allocation.width, cell_area->y + cell_area->height);
 }
--- a/pidgin/gtkconv.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtkconv.c	Thu Nov 27 21:15:43 2008 +0000
@@ -201,11 +201,11 @@
 
 	switch (purple_conversation_get_type(conv)) {
 		case PURPLE_CONV_TYPE_IM:
-			node = (PurpleBlistNode*)purple_find_buddy(conv->account, conv->name);
+			node = PURPLE_BLIST_NODE(purple_find_buddy(conv->account, conv->name));
 			node = node ? node->parent : NULL;
 			break;
 		case PURPLE_CONV_TYPE_CHAT:
-			node = (PurpleBlistNode*)purple_blist_find_chat(conv->account, conv->name);
+			node = PURPLE_BLIST_NODE(purple_blist_find_chat(conv->account, conv->name));
 			break;
 		default:
 			break;
@@ -3860,7 +3860,7 @@
 			{
 				PurpleBlistNode *node;
 
-				node = (PurpleBlistNode *) purple_buddy_get_contact((PurpleBuddy *)l->data);
+				node = PURPLE_BLIST_NODE(purple_buddy_get_contact(PURPLE_BUDDY(l->data)));
 
 				for (node = node->child; node != NULL; node = node->next)
 				{
@@ -5043,9 +5043,9 @@
 static PidginConversation *
 pidgin_conv_find_gtkconv(PurpleConversation * conv)
 {
-	PurpleBuddy *bud = purple_find_buddy(conv->account, conv->name), *b;
+	PurpleBuddy *bud = purple_find_buddy(conv->account, conv->name);
 	PurpleContact *c;
-	PurpleBlistNode *cn;
+	PurpleBlistNode *cn, *bn;
 
 	if (!bud)
 		return NULL;
@@ -5053,8 +5053,9 @@
 	if (!(c = purple_buddy_get_contact(bud)))
 		return NULL;
 
-	cn = (PurpleBlistNode *)c;
-	for (b = (PurpleBuddy *)cn->child; b; b = (PurpleBuddy *) ((PurpleBlistNode *)b)->next) {
+	cn = PURPLE_BLIST_NODE(c);
+	for (bn = purple_blist_node_get_first_child(cn); bn; bn = purple_blist_node_get_sibling_next(bn)) {
+		PurpleBuddy *b = PURPLE_BUDDY(bn);
 		PurpleConversation *conv;
 		if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, b->name, b->account))) {
 			if (conv->ui_data)
--- a/pidgin/gtkdialogs.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtkdialogs.c	Thu Nov 27 21:15:43 2008 +0000
@@ -1056,8 +1056,8 @@
 	g_return_if_fail(contact != NULL);
 	g_return_if_fail(buddy != NULL);
 
-	if (((PurpleBlistNode*)contact)->child == (PurpleBlistNode*)buddy &&
-			!((PurpleBlistNode*)buddy)->next) {
+	if (PURPLE_BLIST_NODE(contact)->child == PURPLE_BLIST_NODE(buddy) &&
+	    PURPLE_BLIST_NODE(buddy)->next == NULL) {
 		pidgin_dialogs_remove_buddy(buddy);
 	} else {
 		gchar *text;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkicon-theme-loader.c	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,115 @@
+/*
+ * PidginIconThemeLoader for Pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+#include "gtkicon-theme-loader.h"
+#include "gtkstatus-icon-theme.h"
+
+#include "xmlnode.h"
+
+/*****************************************************************************
+ * Icon Theme Builder                                                      
+ *****************************************************************************/
+
+static PurpleTheme *
+pidgin_icon_loader_build(const gchar *dir)
+{
+	xmlnode *root_node = NULL, *sub_node;
+	gchar *filename_full, *data;
+	PidginIconTheme *theme = NULL;
+
+	/* Find the theme file */
+	g_return_val_if_fail(dir != NULL, NULL);
+	filename_full = g_build_filename(dir, "theme.xml", NULL);
+
+	if (g_file_test(filename_full, G_FILE_TEST_IS_REGULAR))
+		root_node = xmlnode_from_file(dir, "theme.xml", "sound themes", "sound-loader");
+
+	g_free(filename_full);
+	g_return_val_if_fail(root_node != NULL, NULL);
+
+	/* Parse the tree */	
+	sub_node = xmlnode_get_child(root_node, "description");
+	data = xmlnode_get_data(sub_node);
+
+	if (xmlnode_get_attrib(root_node, "name") != NULL) {
+		theme = g_object_new(PIDGIN_TYPE_STATUS_ICON_THEME,
+				    "type", "status-icon",
+				    "name", xmlnode_get_attrib(root_node, "name"),
+				    "author", xmlnode_get_attrib(root_node, "author"),
+				    "image", xmlnode_get_attrib(root_node, "image"),
+				    "directory", dir,
+				    "description", data, NULL);
+	
+		sub_node = xmlnode_get_child(root_node, "icon");
+
+		while (sub_node){
+			pidgin_icon_theme_set_icon(theme,
+						   xmlnode_get_attrib(sub_node, "id"),
+						   xmlnode_get_attrib(sub_node, "file"));
+			sub_node = xmlnode_get_next_twin(sub_node);
+		}
+	}
+
+	xmlnode_free(root_node);	
+	g_free(data);
+	return PURPLE_THEME(theme);
+}
+
+/******************************************************************************
+ * GObject Stuff                                                              
+ *****************************************************************************/
+
+static void
+pidgin_icon_theme_loader_class_init (PidginIconThemeLoaderClass *klass)
+{
+	PurpleThemeLoaderClass *loader_klass = PURPLE_THEME_LOADER_CLASS(klass);
+
+	loader_klass->purple_theme_loader_build = pidgin_icon_loader_build;
+}
+
+
+GType 
+pidgin_icon_theme_loader_get_type (void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (PidginIconThemeLoaderClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      (GClassInitFunc)pidgin_icon_theme_loader_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (PidginIconThemeLoader),
+      0,      /* n_preallocs */
+      NULL,    /* instance_init */
+      NULL,   /* value table */
+    };
+    type = g_type_register_static (PURPLE_TYPE_THEME_LOADER,
+                                   "PidginIconThemeLoader",
+                                   &info, 0);
+  }
+  return type;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkicon-theme-loader.h	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,71 @@
+/**
+ * @file gtkicon-loader.h  Pidgin Icon Theme Loader Class API
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PIDGIN_ICON_THEME_LOADER_H_
+#define _PIDGIN_ICON_THEME_LOADER_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include "theme-loader.h"
+
+/**
+ * A pidgin icon theme loader. Extends PurpleThemeLoader (theme-loader.h)
+ * This is a class designed to build icon themes
+ *
+ * PidginIconThemeLoader is a GObject.
+ */
+typedef struct _PidginIconThemeLoader       PidginIconThemeLoader;
+typedef struct _PidginIconThemeLoaderClass   PidginIconThemeLoaderClass;
+
+#define PIDGIN_TYPE_ICON_THEME_LOADER			  (pidgin_icon_theme_loader_get_type ())
+#define PIDGIN_ICON_THEME_LOADER(obj)			  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIDGIN_TYPE_ICON_THEME_LOADER, PidginIconThemeLoader))
+#define PIDGIN_ICON_THEME_LOADER_CLASS(klass)		  (G_TYPE_CHECK_CLASS_CAST ((klass), PIDGIN_TYPE_ICON_THEME_LOADER, PidginIconThemeLoaderClass))
+#define PIDGIN_IS_ICON_THEME_LOADER(obj)	  	  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIDGIN_TYPE_ICON_THEME_LOADER))
+#define PIDGIN_IS_ICON_THEME_LOADER_CLASS(klass) 	  (G_TYPE_CHECK_CLASS_TYPE ((klass), PIDGIN_TYPE_ICON_THEME_LOADER))
+#define PIDGIN_ICON_THEME_LOADER_GET_CLASS(obj)  	  (G_TYPE_INSTANCE_GET_CLASS ((obj), PIDGIN_TYPE_ICON_THEME_LOADER, PidginIconThemeLoaderClass))
+
+struct _PidginIconThemeLoader
+{
+	PurpleThemeLoader parent;
+};
+
+struct _PidginIconThemeLoaderClass
+{
+	PurpleThemeLoaderClass parent_class;
+};
+
+/**************************************************************************/
+/** @name Pidgin Icon Theme-Loader API                                    */
+/**************************************************************************/
+G_BEGIN_DECLS
+
+/**
+ * GObject foo.
+ * @internal.
+ */
+GType pidgin_icon_theme_loader_get_type(void);
+
+G_END_DECLS
+#endif /* _PIDGIN_ICON_THEME_LOADER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkicon-theme.c	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,147 @@
+/*
+ * Icon Themes for Pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+#include "gtkicon-theme.h"
+#include "pidginstock.h"
+
+#include <gtk/gtk.h>
+
+#define PIDGIN_ICON_THEME_GET_PRIVATE(Gobject) \
+	((PidginIconThemePrivate *) ((PIDGIN_ICON_THEME(Gobject))->priv))
+
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+typedef struct {
+	/* used to store filenames of diffrent icons */
+	GHashTable *icon_files;
+} PidginIconThemePrivate;
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * GObject Stuff                                                              
+ *****************************************************************************/
+
+static void
+pidgin_icon_theme_init(GTypeInstance *instance,
+			gpointer klass)
+{
+	PidginIconThemePrivate *priv;
+
+	(PIDGIN_ICON_THEME(instance))->priv = g_new0(PidginIconThemePrivate, 1);
+
+	priv = PIDGIN_ICON_THEME_GET_PRIVATE(instance);
+
+	priv->icon_files = g_hash_table_new_full(g_str_hash,
+						   g_str_equal,
+						   g_free,
+						   g_free);
+}
+
+static void 
+pidgin_icon_theme_finalize(GObject *obj)
+{
+	PidginIconThemePrivate *priv;
+
+	priv = PIDGIN_ICON_THEME_GET_PRIVATE(obj);
+	
+	g_hash_table_destroy(priv->icon_files);
+	g_free(priv);
+
+	parent_class->finalize(obj);
+}
+
+static void
+pidgin_icon_theme_class_init(PidginIconThemeClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	parent_class = g_type_class_peek_parent(klass);
+
+        obj_class->finalize = pidgin_icon_theme_finalize;
+}
+
+GType 
+pidgin_icon_theme_get_type(void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (PidginIconThemeClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      (GClassInitFunc)pidgin_icon_theme_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (PidginIconTheme),
+      0,      /* n_preallocs */
+      pidgin_icon_theme_init,    /* instance_init */
+      NULL,   /* value table */
+    };
+    type = g_type_register_static(PURPLE_TYPE_THEME,
+                                   "PidginIconTheme",
+                                   &info, G_TYPE_FLAG_ABSTRACT);
+  }
+  return type;
+}
+
+
+/*****************************************************************************
+ * Public API functions                                                      
+ *****************************************************************************/
+
+const gchar *
+pidgin_icon_theme_get_icon(PidginIconTheme *theme,
+			    const gchar *id)
+{
+	PidginIconThemePrivate *priv;
+
+	g_return_val_if_fail(PIDGIN_IS_ICON_THEME(theme), NULL);
+
+	priv = PIDGIN_ICON_THEME_GET_PRIVATE(theme);
+	
+	return g_hash_table_lookup(priv->icon_files, id);
+}
+
+void 
+pidgin_icon_theme_set_icon(PidginIconTheme *theme,
+			    const gchar *id, 
+			    const gchar *filename)
+{
+	PidginIconThemePrivate *priv;
+	g_return_if_fail(PIDGIN_IS_ICON_THEME(theme));
+	
+	priv = PIDGIN_ICON_THEME_GET_PRIVATE(theme);
+
+	if (filename != NULL)
+		g_hash_table_replace(priv->icon_files,
+                 	             g_strdup(id),
+                        	     g_strdup(filename));
+	else g_hash_table_remove(priv->icon_files, id);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkicon-theme.h	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,92 @@
+/**
+ * @file icon-theme.h  Pidgin Icon Theme  Class API
+ */
+
+/* pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PIDGIN_ICON_THEME_H_
+#define _PIDGIN_ICON_THEME_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include "theme.h"
+
+/**
+ * extends PurpleTheme (theme.h)
+ * A pidgin icon theme.
+ * This object represents a Pidgin icon theme.
+ *
+ * PidginIconTheme is a PurpleTheme Object.
+ */
+typedef struct _PidginIconTheme        PidginIconTheme;
+typedef struct _PidginIconThemeClass   PidginIconThemeClass;
+
+#define PIDGIN_TYPE_ICON_THEME		  	(pidgin_icon_theme_get_type ())
+#define PIDGIN_ICON_THEME(obj)		  	(G_TYPE_CHECK_INSTANCE_CAST ((obj), PIDGIN_TYPE_ICON_THEME, PidginIconTheme))
+#define PIDGIN_ICON_THEME_CLASS(klass)	  	(G_TYPE_CHECK_CLASS_CAST ((klass), PIDGIN_TYPE_ICON_THEME, PidginIconThemeClass))
+#define PIDGIN_IS_ICON_THEME(obj)	  	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIDGIN_TYPE_ICON_THEME))
+#define PIDGIN_IS_ICON_THEME_CLASS(klass) 	(G_TYPE_CHECK_CLASS_TYPE ((klass), PIDGIN_TYPE_ICON_THEME))
+#define PIDGIN_ICON_THEME_GET_CLASS(obj)  	(G_TYPE_INSTANCE_GET_CLASS ((obj), PIDGIN_TYPE_ICON_THEME, PidginIconThemeClass))
+
+struct _PidginIconTheme
+{
+	PurpleTheme parent;
+	gpointer priv;
+};
+
+struct _PidginIconThemeClass
+{
+	PurpleThemeClass parent_class;
+};
+
+/**************************************************************************/
+/** @name Pidgin Icon Theme API                                          */
+/**************************************************************************/
+G_BEGIN_DECLS
+
+/**
+ * GObject foo.
+ * @internal.
+ */
+GType pidgin_icon_theme_get_type(void);
+
+/**
+ * Returns a copy of the filename for the icon event or NULL if it is not set
+ *
+ * @param event		the pidgin icon event to look up
+ *
+ * @returns the filename of the icon event
+ */
+const gchar *pidgin_icon_theme_get_icon(PidginIconTheme *theme,
+				  	const gchar *event);
+/**
+ * Sets the filename for a given icon id, setting the icon to NULL will remove the icon from the theme
+ *
+ * @param icon_id		a string representing what the icon is to be used for
+ * @param filename		the name of the file to be used for the given id
+ */
+void pidgin_icon_theme_set_icon(PidginIconTheme *theme,
+				const gchar *icon_id, 
+			    	const gchar *filename);
+
+G_END_DECLS
+#endif /* _PIDGIN_ICON_THEME_H_ */
--- a/pidgin/gtklog.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtklog.c	Thu Nov 27 21:15:43 2008 +0000
@@ -760,13 +760,19 @@
 		return;
 	}
 
-	for (child = contact->node.child ; child ; child = child->next) {
+	for (child = purple_blist_node_get_first_child((PurpleBlistNode*)contact) ;
+	     child != NULL ;
+	     child = purple_blist_node_get_sibling_next(child)) {
+		const char *buddy_name;
+		PurpleAccount *account;
+
 		if (!PURPLE_BLIST_NODE_IS_BUDDY(child))
 			continue;
 
-		logs = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, ((PurpleBuddy *)child)->name,
-						((PurpleBuddy *)child)->account), logs);
-		total_log_size += purple_log_get_total_size(PURPLE_LOG_IM, ((PurpleBuddy *)child)->name, ((PurpleBuddy *)child)->account);
+		buddy_name = purple_buddy_get_name((PurpleBuddy *)child);
+		account = purple_buddy_get_account((PurpleBuddy *)child);
+		logs = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, buddy_name, account), logs);
+		total_log_size += purple_log_get_total_size(PURPLE_LOG_IM, buddy_name, account);
 	}
 	logs = g_list_sort(logs, purple_log_compare);
 
--- a/pidgin/gtknotify.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtknotify.c	Thu Nov 27 21:15:43 2008 +0000
@@ -730,7 +730,6 @@
 	GtkListStore *model = data->model;
 	GtkTreeIter iter;
 	GdkPixbuf *pixbuf;
-	guint col_num;
 	GList *row, *column;
 	guint n;
 
@@ -738,9 +737,6 @@
 
 	pixbuf = pidgin_create_prpl_icon(purple_connection_get_account(gc), 0.5);
 
-	/* +1 is for the automagically created Status column. */
-	col_num = g_list_length(results->columns) + 1;
-
 	for (row = results->rows; row != NULL; row = row->next) {
 
 		gtk_list_store_append(model, &iter);
@@ -776,6 +772,7 @@
 	guint col_num;
 	GList *columniter;
 	guint i;
+	GList *l;
 
 	GtkWidget *vbox;
 	GtkWidget *label;
@@ -869,8 +866,8 @@
 		i++;
 	}
 
-	for (i = 0; i < g_list_length(results->buttons); i++) {
-		PurpleNotifySearchButton *b = g_list_nth_data(results->buttons, i);
+	for (l = results->buttons; l; l = l->next) {
+		PurpleNotifySearchButton *b = l->data;
 		GtkWidget *button = NULL;
 		switch (b->type) {
 			case PURPLE_NOTIFY_BUTTON_LABELED:
--- a/pidgin/gtkprefs.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtkprefs.c	Thu Nov 27 21:15:43 2008 +0000
@@ -35,6 +35,8 @@
 #include "request.h"
 #include "savedstatuses.h"
 #include "sound.h"
+#include "sound-theme.h"
+#include "theme-manager.h"
 #include "util.h"
 #include "network.h"
 
@@ -47,6 +49,7 @@
 #include "gtkprefs.h"
 #include "gtksavedstatuses.h"
 #include "gtksound.h"
+#include "gtkstatus-icon-theme.h"
 #include "gtkthemes.h"
 #include "gtkutils.h"
 #include "pidginstock.h"
@@ -56,6 +59,8 @@
 #define PROXYUSER 2
 #define PROXYPASS 3
 
+#define PREFS_OPTIMAL_ICON_SIZE 32
+
 static int sound_row_sel = 0;
 static GtkWidget *prefsnotebook;
 
@@ -69,6 +74,12 @@
 static int notebook_page = 0;
 static GtkTreeRowReference *previous_smiley_row = NULL;
 
+static gboolean prefs_themes_unsorted = TRUE;
+static GtkListStore *prefs_sound_themes;
+static GtkListStore *prefs_blist_themes;
+static GtkListStore *prefs_status_icon_themes;
+ 
+
 /*
  * PROTOTYPES
  */
@@ -546,6 +557,213 @@
 	gtk_drag_finish(dc, FALSE, FALSE, t);
 }
 
+/* Rebuild the markup for the sound theme selection for "(Custom)" themes */
+static void
+pref_sound_generate_markup()
+{	
+	gboolean print_custom, customized;
+	const gchar *name, *author, *description, *current_theme;
+	gchar *markup;
+	PurpleSoundTheme *theme;
+	GtkTreeIter iter;
+
+	customized = pidgin_sound_is_customized();
+	current_theme = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme");
+	
+	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(prefs_sound_themes), &iter)) {
+		do {
+			gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &iter, 2, &name, -1);
+
+			print_custom = customized && g_str_equal(current_theme, name);
+			
+			if (g_str_equal(name, ""))
+				markup = g_strdup_printf("<b>(Default)</b>%s%s - None\n<span foreground='dim grey'>The default Pidgin sound theme</span>",
+							 print_custom ? " " : "", print_custom ? "(Custom)" : ""); 
+			else {
+				theme = PURPLE_SOUND_THEME(purple_theme_manager_find_theme(name, "sound"));
+				author = purple_theme_get_author(PURPLE_THEME(theme));
+				description = purple_theme_get_description(PURPLE_THEME(theme));
+				
+				markup = g_strdup_printf("<b>%s</b>%s%s%s%s\n<span foreground='dim grey'>%s</span>",
+							 name, print_custom ? " " : "", print_custom ? "(Custom)" : "", 
+							 author != NULL ? " - " : "", author != NULL ? author : "", description != NULL ? description : ""); 
+			}
+
+			gtk_list_store_set(prefs_sound_themes, &iter, 1, markup, -1);
+
+			g_free(markup);
+
+		} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(prefs_sound_themes), &iter));
+	}
+}
+
+/* adds the themes to the theme list from the manager so they can be sisplayed in prefs */
+static void
+prefs_themes_sort(PurpleTheme *theme)
+{
+	GdkPixbuf *pixbuf = NULL;
+	GtkTreeIter iter;
+	gchar *image_full = NULL, *markup;
+	const gchar *name, *author, *description;
+	
+	if (PURPLE_IS_SOUND_THEME(theme)){
+		
+		image_full = purple_theme_get_image_full(theme);
+		if (image_full != NULL){
+			pixbuf = gdk_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
+			g_free(image_full);
+		} else pixbuf = NULL; 
+
+		gtk_list_store_append(prefs_sound_themes, &iter);
+		gtk_list_store_set(prefs_sound_themes, &iter, 0, pixbuf, 2, purple_theme_get_name(theme), -1);
+
+		if (pixbuf != NULL)
+			gdk_pixbuf_unref(pixbuf);
+
+	} else if (PIDGIN_IS_BLIST_THEME(theme) || PIDGIN_IS_STATUS_ICON_THEME(theme)){
+		GtkListStore *store;
+
+		if (PIDGIN_IS_BLIST_THEME(theme)) 
+			store = prefs_blist_themes;
+		else store = prefs_status_icon_themes;
+
+		image_full = purple_theme_get_image_full(theme);
+		if (image_full != NULL){
+			pixbuf = gdk_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
+			g_free(image_full);
+		} else pixbuf = NULL; 
+
+		name = purple_theme_get_name(theme);
+		author = purple_theme_get_author(theme);
+		description = purple_theme_get_description(theme);
+		
+		markup = g_strdup_printf("<b>%s</b>%s%s\n<span foreground='dim grey'>%s</span>", name, author != NULL ? " - " : "",
+					 author != NULL ? author : "", description != NULL ? description : "");
+
+		gtk_list_store_append(store, &iter);
+		gtk_list_store_set(store, &iter, 0, pixbuf, 1, markup, 2, name, -1);
+
+		g_free(markup);
+		if (pixbuf != NULL)
+			gdk_pixbuf_unref(pixbuf);
+	} 
+
+}
+
+/* init all the theme variables so that the themes can be sorted later and used by pref pages */
+static void
+prefs_themes_init()
+{
+	GdkPixbuf *pixbuf = NULL;
+	gchar *filename;
+	GtkTreeIter iter;
+
+	filename = g_build_filename(DATADIR, "icons", "hicolor", "32x32", "apps", "pidgin.png", NULL);
+	pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
+	g_free(filename);
+
+	/* sound themes */
+	prefs_sound_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+
+	gtk_list_store_append(prefs_sound_themes, &iter);
+	gtk_list_store_set(prefs_sound_themes, &iter, 0, pixbuf, 2, "", -1);
+
+	/* blist themes */
+	prefs_blist_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+
+	gtk_list_store_append(prefs_blist_themes, &iter);
+	gtk_list_store_set(prefs_blist_themes, &iter, 0, pixbuf, 1, "<b>(Default)</b> - None\n<span color='dim grey'>"
+								    "The default Pidgin buddy list theme</span>", 2, "", -1);
+
+	/* status icon themes */
+	prefs_status_icon_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+
+	gtk_list_store_append(prefs_status_icon_themes, &iter);
+	gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1, "<b>(Default)</b> - None\n<span color='dim grey'>"
+								    "The default Pidgin status icon theme</span>", 2, "", -1);
+
+	gdk_pixbuf_unref(pixbuf);
+}
+
+/* builds a theme combo box from a list store with colums: icon preview, markup, theme name */
+static GtkWidget *
+prefs_build_theme_combo_box(GtkListStore *store, const gchar *current_theme)
+{
+	GtkWidget *combo_box;
+	GtkCellRenderer *cell_rend;
+	GtkTreeIter iter;
+	gchar *theme = NULL;
+	gboolean unset = TRUE;
+
+	g_return_val_if_fail(store != NULL && current_theme != NULL, NULL);
+
+	combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
+
+	cell_rend = gtk_cell_renderer_pixbuf_new();
+	gtk_cell_renderer_set_fixed_size(cell_rend, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE);
+	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combo_box), cell_rend, FALSE);
+	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell_rend, "pixbuf", 0, NULL);
+	
+	cell_rend = gtk_cell_renderer_text_new();
+	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combo_box), cell_rend, FALSE);
+	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell_rend, "markup", 1, NULL);
+/*#if GTK_CHECK_VERSION(2,6,0)
+			g_object_set(cell_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+#endif*/
+	
+	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
+		do {
+			gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 2, &theme, -1);
+
+			if (g_str_equal(current_theme, theme)) {
+				gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter);
+				unset = FALSE;
+			}
+
+			g_free(theme);
+		} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
+	}
+
+	if (unset)
+		gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0);
+
+	return combo_box;
+}
+
+/* sets the current sound theme */
+static void
+prefs_set_sound_theme_cb(GtkComboBox *combo_box, gpointer user_data)
+{
+	gint i;
+	gchar *pref;
+	gchar *new_theme;
+	gboolean sucess;
+	GtkTreeIter new_iter;
+	
+
+	sucess = gtk_combo_box_get_active_iter(combo_box, &new_iter);
+	g_return_if_fail(sucess);
+
+	gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &new_iter, 2, &new_theme, -1);
+
+	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/sound/theme", new_theme);
+
+	/* New theme removes all customization */
+	for(i=0; i <  PURPLE_NUM_SOUNDS; i++){
+		pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
+					pidgin_sound_get_event_option(i));
+		purple_prefs_set_path(pref, "");
+		g_free(pref);
+	}
+
+	/* gets rid of the "(Custom)" from the last selection */
+	pref_sound_generate_markup();
+
+	gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)"));
+
+	g_free(new_theme);
+}
+
 /* Does same as normal sort, except "none" is sorted first */
 static gint pidgin_sort_smileys (GtkTreeModel	*model,
 						GtkTreeIter		*a,
@@ -922,6 +1140,40 @@
 	gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
 }
 
+/* sets the current buddy list theme */
+static void
+prefs_set_blist_theme_cb(GtkComboBox *combo_box, gpointer user_data)
+{
+	PidginBlistTheme *theme;
+	GtkTreeIter iter;
+	gchar *name = NULL;
+	
+	g_return_if_fail(gtk_combo_box_get_active_iter(combo_box, &iter));
+	gtk_tree_model_get(GTK_TREE_MODEL(prefs_blist_themes), &iter, 2, &name, -1);
+
+	theme = PIDGIN_BLIST_THEME(purple_theme_manager_find_theme(name, "blist"));
+	g_free(name);
+
+	pidgin_blist_set_theme(theme);
+}
+
+/* sets the current icon theme */
+static void
+prefs_set_status_icon_theme_cb(GtkComboBox *combo_box, gpointer user_data)
+{
+	PidginStatusIconTheme *theme;
+	GtkTreeIter iter;
+	gchar *name = NULL;
+	
+	g_return_if_fail(gtk_combo_box_get_active_iter(combo_box, &iter));
+	gtk_tree_model_get(GTK_TREE_MODEL(prefs_status_icon_themes), &iter, 2, &name, -1);
+
+	theme = PIDGIN_STATUS_ICON_THEME(purple_theme_manager_find_theme(name, "status-icon"));
+	g_free(name);
+
+	pidgin_stock_load_status_icon_theme(theme);
+}
+
 static GtkWidget *
 interface_page(void)
 {
@@ -929,6 +1181,7 @@
 	GtkWidget *vbox;
 	GtkWidget *vbox2;
 	GtkWidget *label;
+	GtkWidget *combo_box;
 	GtkSizeGroup *sg;
 	GList *names = NULL;
 
@@ -937,6 +1190,19 @@
 
 	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 
+	/* Buddy List Themes */
+	vbox = pidgin_make_frame(ret, _("Buddy List Theme"));
+
+	combo_box = prefs_build_theme_combo_box(prefs_blist_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"));
+	gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0);
+	g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_blist_theme_cb, NULL);
+
+	/* Status Icon Themes */
+	combo_box = prefs_build_theme_combo_box(prefs_status_icon_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme"));
+	gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0);
+	g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_status_icon_theme_cb, NULL);
+
+	/* System Tray */	
 	vbox = pidgin_make_frame(ret, _("System Tray Icon"));
 	label = pidgin_prefs_dropdown(vbox, _("_Show system tray icon:"), PURPLE_PREF_STRING,
 					PIDGIN_PREFS_ROOT "/docklet/show",
@@ -1736,6 +2002,8 @@
 	g_free(pref);
 
 	gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)"));
+
+	pref_sound_generate_markup();
 }
 
 static void
@@ -1758,6 +2026,8 @@
 	 */
 	if (sound == sound_row_sel)
 		gtk_entry_set_text(GTK_ENTRY(sound_entry), filename);
+
+	pref_sound_generate_markup();	
 }
 
 static void select_sound(GtkWidget *button, gpointer being_NULL_is_fun)
@@ -1826,6 +2096,8 @@
 	if (sound_entry)
 		gtk_entry_set_text(GTK_ENTRY(sound_entry), (file && *file != '\0') ? file : _("(default)"));
 	g_value_unset (&val);
+
+	pref_sound_generate_markup();
 }
 
 
@@ -1851,7 +2123,7 @@
 sound_page(void)
 {
 	GtkWidget *ret;
-	GtkWidget *vbox, *sw, *button;
+	GtkWidget *vbox, *sw, *button, *combo_box;
 	GtkSizeGroup *sg;
 	GtkTreeIter iter;
 	GtkWidget *event_view;
@@ -1945,7 +2217,6 @@
 	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/sound/method",
 								sound_changed2_cb, vbox);
 #endif
-
 	vbox = pidgin_make_frame(ret, _("Sound Events"));
 
 	/* The following is an ugly hack to make the frame expand so the
@@ -1957,6 +2228,14 @@
 	gtk_box_set_child_packing(GTK_BOX(vbox->parent->parent->parent),
 			vbox->parent->parent, TRUE, TRUE, 0, GTK_PACK_START);
 
+	/* SOUND THEMES */
+	combo_box = prefs_build_theme_combo_box(prefs_sound_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme"));
+	pref_sound_generate_markup();
+	gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0);
+
+	g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_sound_theme_cb, NULL);
+
+	/* SOUND SELECTION */
 	sw = gtk_scrolled_window_new(NULL,NULL);
 	gtk_widget_set_size_request(sw, -1, 100);
 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
@@ -2189,7 +2468,12 @@
 		gtk_window_present(GTK_WINDOW(prefs));
 		return;
 	}
-
+	
+	/* add everthing in the thmeme manager before the window is loaded */
+	if (prefs_themes_unsorted) {
+		purple_theme_manager_for_each_theme(prefs_themes_sort);
+		prefs_themes_unsorted = FALSE;
+	}
 	/* copy the preferences to tmp values...
 	 * I liked "take affect immediately" Oh well :-( */
 	/* (that should have been "effect," right?) */
@@ -2284,6 +2568,9 @@
 	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder", "");
 	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", "");
 
+	/* Themes */
+	prefs_themes_init();
+
 	/* Smiley Themes */
 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/smileys");
 	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/smileys/theme", "Default");
--- a/pidgin/gtkrequest.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtkrequest.c	Thu Nov 27 21:15:43 2008 +0000
@@ -680,15 +680,17 @@
 static void
 req_entry_field_changed_cb(GtkWidget *entry, PurpleRequestField *field)
 {
+	PurpleRequestFieldGroup *group;
 	PidginRequestData *req_data;
 	const char *text = gtk_entry_get_text(GTK_ENTRY(entry));
 
 	purple_request_field_string_set_value(field, (*text == '\0' ? NULL : text));
 
-	req_data = (PidginRequestData *)field->group->fields_list->ui_data;
+	group = purple_request_field_get_group(field);
+	req_data = (PidginRequestData *)group->fields_list->ui_data;
 
 	gtk_widget_set_sensitive(req_data->ok_button,
-		purple_request_fields_all_required_filled(field->group->fields_list));
+		purple_request_fields_all_required_filled(group->fields_list));
 }
 
 static void
@@ -709,7 +711,8 @@
 		if (purple_str_has_prefix(type_hint, "screenname"))
 		{
 			GtkWidget *optmenu = NULL;
-			GList *fields = field->group->fields;
+			PurpleRequestFieldGroup *group = purple_request_field_get_group(field);
+			GList *fields = group->fields;
 			while (fields)
 			{
 				PurpleRequestField *fld = fields->data;
@@ -720,9 +723,11 @@
 					const char *type_hint = purple_request_field_get_type_hint(fld);
 					if (type_hint != NULL && strcmp(type_hint, "account") == 0)
 					{
-						if (fld->ui_data == NULL)
-							fld->ui_data = create_account_field(fld);
-						optmenu = GTK_WIDGET(fld->ui_data);
+						optmenu = GTK_WIDGET(purple_request_field_get_ui_data(fld));
+						if (optmenu == NULL) {
+							optmenu = GTK_WIDGET(create_account_field(fld));
+							purple_request_field_set_ui_data(field, optmenu);
+						}
 						break;
 					}
 				}
@@ -853,12 +858,11 @@
 create_choice_field(PurpleRequestField *field)
 {
 	GtkWidget *widget;
-	GList *labels;
+	GList *labels = purple_request_field_choice_get_labels(field);
+	int num_labels = g_list_length(labels);
 	GList *l;
 
-	labels = purple_request_field_choice_get_labels(field);
-
-	if (g_list_length(labels) > 5)
+	if (num_labels > 5)
 	{
 		GtkWidget *menu;
 		GtkWidget *item;
@@ -892,7 +896,7 @@
 		GtkWidget *radio;
 		gint i;
 
-		if (g_list_length(labels) == 2)
+		if (num_labels == 2)
 			box = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
 		else
 			box = gtk_vbox_new(FALSE, 0);
@@ -1335,24 +1339,26 @@
 					gtk_widget_show(label);
 				}
 
-				if (field->ui_data != NULL)
-					widget = GTK_WIDGET(field->ui_data);
-				else if (type == PURPLE_REQUEST_FIELD_STRING)
-					widget = create_string_field(field);
-				else if (type == PURPLE_REQUEST_FIELD_INTEGER)
-					widget = create_int_field(field);
-				else if (type == PURPLE_REQUEST_FIELD_BOOLEAN)
-					widget = create_bool_field(field);
-				else if (type == PURPLE_REQUEST_FIELD_CHOICE)
-					widget = create_choice_field(field);
-				else if (type == PURPLE_REQUEST_FIELD_LIST)
-					widget = create_list_field(field);
-				else if (type == PURPLE_REQUEST_FIELD_IMAGE)
-					widget = create_image_field(field);
-				else if (type == PURPLE_REQUEST_FIELD_ACCOUNT)
-					widget = create_account_field(field);
-				else
-					continue;
+				widget = GTK_WIDGET(purple_request_field_get_ui_data(field));
+				if (widget == NULL)
+				{
+					if (type == PURPLE_REQUEST_FIELD_STRING)
+						widget = create_string_field(field);
+					else if (type == PURPLE_REQUEST_FIELD_INTEGER)
+						widget = create_int_field(field);
+					else if (type == PURPLE_REQUEST_FIELD_BOOLEAN)
+						widget = create_bool_field(field);
+					else if (type == PURPLE_REQUEST_FIELD_CHOICE)
+						widget = create_choice_field(field);
+					else if (type == PURPLE_REQUEST_FIELD_LIST)
+						widget = create_list_field(field);
+					else if (type == PURPLE_REQUEST_FIELD_IMAGE)
+						widget = create_image_field(field);
+					else if (type == PURPLE_REQUEST_FIELD_ACCOUNT)
+						widget = create_account_field(field);
+					else
+						continue;
+				}
 
 				if (label)
 					gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget);
@@ -1397,7 +1403,7 @@
 
 				gtk_widget_show(widget);
 
-				field->ui_data = widget;
+				purple_request_field_set_ui_data(field, widget);
 			}
 		}
 	}
--- a/pidgin/gtksavedstatuses.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtksavedstatuses.c	Thu Nov 27 21:15:43 2008 +0000
@@ -331,7 +331,8 @@
 	}
 	g_list_free(sel_paths);
 
-	if (g_list_length(sel_titles) == 1) {
+	g_return_if_fail(sel_titles != NULL);
+	if (!sel_titles->next) {
 		title = g_strdup_printf(_("Are you sure you want to delete %s?"),
 				(const gchar *)sel_titles->data);
 		handle = purple_savedstatus_find(sel_titles->data);
--- a/pidgin/gtksound.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtksound.c	Thu Nov 27 21:15:43 2008 +0000
@@ -40,6 +40,8 @@
 #include "notify.h"
 #include "prefs.h"
 #include "sound.h"
+#include "sound-theme.h"
+#include "theme-manager.h"
 #include "util.h"
 
 #include "gtkconv.h"
@@ -294,6 +296,7 @@
 	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/sound/file/nick_said", "");
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/sound/enabled/pounce_default", TRUE);
 	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/sound/file/pounce_default", "");
+	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/sound/theme", "");
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/sound/conv_focus", TRUE);
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/sound/mute", FALSE);
 	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/sound/command", "");
@@ -557,6 +560,8 @@
 {
 	char *enable_pref;
 	char *file_pref;
+	const char *theme_name;
+	PurpleSoundTheme *theme;
 
 	if ((event == PURPLE_SOUND_BUDDY_ARRIVE) && mute_login_sounds)
 		return;
@@ -570,16 +575,35 @@
 			sounds[event].pref);
 	file_pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s", sounds[event].pref);
 
+
+
 	/* check NULL for sounds that don't have an option, ie buddy pounce */
 	if (purple_prefs_get_bool(enable_pref)) {
 		char *filename = g_strdup(purple_prefs_get_path(file_pref));
-		if(!filename || !strlen(filename)) {
+		theme_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme");
+		
+		if (theme_name && strlen(theme_name) && (!filename || !strlen(filename))){ /* Use theme */
 			g_free(filename);
+
+			theme = PURPLE_SOUND_THEME(purple_theme_manager_find_theme(theme_name, "sound"));
+			filename = purple_sound_theme_get_file_full(theme, sounds[event].pref);
+
+			if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)){ /* Use Default sound in this case */
+				purple_debug_error("sound", "The file: (%s) %s\n from theme: %s, was not found or wasn't readable\n", 
+							sounds[event].pref, filename, theme_name);
+				g_free(filename);
+			}
+		}
+		
+		if (!filename || !strlen(filename)) {			    /* Use Default sounds */
+			g_free(filename);
+
 			/* XXX Consider creating a constant for "sounds/purple" to be shared with Finch */
 			filename = g_build_filename(DATADIR, "sounds", "purple", sounds[event].def, NULL);
 		}
 
 		purple_sound_play_file(filename, NULL);
+
 		g_free(filename);
 	}
 
@@ -587,6 +611,29 @@
 	g_free(file_pref);
 }
 
+gboolean 
+pidgin_sound_is_customized(void)
+{
+	gint i;	
+	gchar *path, *file;
+
+	for (i=0; i < PURPLE_NUM_SOUNDS; i++){
+		path = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s", sounds[i].pref);
+		file = g_strdup(purple_prefs_get_path(path));
+		g_free(path);
+
+		if (file && strlen(file)){
+			g_free(file);
+			return TRUE;
+		}
+
+		g_free(file);
+	}
+
+	return FALSE;
+
+}
+
 static PurpleSoundUiOps sound_ui_ops =
 {
 	pidgin_sound_init,
--- a/pidgin/gtksound.h	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/gtksound.h	Thu Nov 27 21:15:43 2008 +0000
@@ -63,6 +63,13 @@
  */
 void *pidgin_sound_get_handle(void);
 
+/**
+ * Returns true Pidgin is using customized sounds
+ *
+ * @return TRUE if non default sounds are used 
+ */
+gboolean pidgin_sound_is_customized(void);
+
 /*@}*/
 
 #endif /* _PIDGINSOUND_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkstatus-icon-theme.c	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,73 @@
+/*
+ * Status Icon Themes for Pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+#include "gtkstatus-icon-theme.h"
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * GObject Stuff                                                              
+ *****************************************************************************/
+
+static void 
+pidgin_status_icon_theme_finalize(GObject *obj)
+{
+	parent_class->finalize(obj);
+}
+
+static void
+pidgin_status_icon_theme_class_init(PidginStatusIconThemeClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	parent_class = g_type_class_peek_parent(klass);
+
+        obj_class->finalize = pidgin_status_icon_theme_finalize;
+}
+
+GType 
+pidgin_status_icon_theme_get_type(void)
+{
+  static GType type = 0;
+  if (type == 0) {
+    static const GTypeInfo info = {
+      sizeof (PidginStatusIconThemeClass),
+      NULL,   /* base_init */
+      NULL,   /* base_finalize */
+      (GClassInitFunc)pidgin_status_icon_theme_class_init,   /* class_init */
+      NULL,   /* class_finalize */
+      NULL,   /* class_data */
+      sizeof (PidginStatusIconTheme),
+      0,      /* n_preallocs */
+      NULL,
+      NULL,   /* value table */
+    };
+    type = g_type_register_static(PIDGIN_TYPE_ICON_THEME,
+                                   "PidginStatusIconTheme",
+                                   &info, 0);
+  }
+  return type;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkstatus-icon-theme.h	Thu Nov 27 21:15:43 2008 +0000
@@ -0,0 +1,71 @@
+/**
+ * @file status_icon-theme.h  Pidgin Icon Theme  Class API
+ */
+
+/* pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PIDGIN_STATUS_ICON_THEME_H_
+#define _PIDGIN_STATUS_ICON_THEME_H_
+
+#include <glib-object.h>
+#include "gtkicon-theme.h"
+
+/**
+ * extends PidginIconTheme (gtkicon-theme.h)
+ * A pidgin status icon theme.
+ * This object represents a Pidgin status icon theme.
+ *
+ * PidginStatusIconTheme is a PidginIconTheme Object.
+ */
+typedef struct _PidginStatusIconTheme        PidginStatusIconTheme;
+typedef struct _PidginStatusIconThemeClass   PidginStatusIconThemeClass;
+
+#define PIDGIN_TYPE_STATUS_ICON_THEME		  	(pidgin_status_icon_theme_get_type ())
+#define PIDGIN_STATUS_ICON_THEME(obj)		  	(G_TYPE_CHECK_INSTANCE_CAST ((obj), PIDGIN_TYPE_STATUS_ICON_THEME, PidginStatusIconTheme))
+#define PIDGIN_STATUS_ICON_THEME_CLASS(klass)	  	(G_TYPE_CHECK_CLASS_CAST ((klass), PIDGIN_TYPE_STATUS_ICON_THEME, PidginStatusIconThemeClass))
+#define PIDGIN_IS_STATUS_ICON_THEME(obj)	  	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIDGIN_TYPE_STATUS_ICON_THEME))
+#define PIDGIN_IS_STATUS_ICON_THEME_CLASS(klass) 	(G_TYPE_CHECK_CLASS_TYPE ((klass), PIDGIN_TYPE_STATUS_ICON_THEME))
+#define PIDGIN_STATUS_ICON_THEME_GET_CLASS(obj)  	(G_TYPE_INSTANCE_GET_CLASS ((obj), PIDGIN_TYPE_STATUS_ICON_THEME, PidginStatusIconThemeClass))
+
+struct _PidginStatusIconTheme
+{
+	PidginIconTheme parent;
+};
+
+struct _PidginStatusIconThemeClass
+{
+	PidginIconThemeClass parent_class;
+};
+
+/**************************************************************************/
+/** @name Pidgin Status Icon Theme API                                          */
+/**************************************************************************/
+G_BEGIN_DECLS
+
+/**
+ * GObject foo.
+ * @internal.
+ */
+GType pidgin_status_icon_theme_get_type(void);
+
+G_END_DECLS
+#endif /* _PIDGIN_STATUS_ICON_THEME_H_ */
--- a/pidgin/pidginstock.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/pidginstock.c	Thu Nov 27 21:15:43 2008 +0000
@@ -26,17 +26,32 @@
  */
 #include "internal.h"
 #include "pidgin.h"
+#include "prefs.h"
+
+#include "gtkicon-theme-loader.h"
+#include "theme-manager.h"
 
 #include "pidginstock.h"
 
+/**************************************************************************
+ * Globals
+ **************************************************************************/
+
+static gboolean stock_initted = FALSE;
+static GtkIconSize microscopic, extra_small, small, medium, large, huge;
+
+/**************************************************************************
+ * Structures
+ **************************************************************************/
+
 static struct StockIcon
 {
 	const char *name;
 	const char *dir;
 	const char *filename;
 
-} const stock_icons[] =
-{
+} const stock_icons[] = {
+
 	{ PIDGIN_STOCK_ACTION,          NULL,      GTK_STOCK_EXECUTE          },
 #if GTK_CHECK_VERSION(2,6,0)
 	{ PIDGIN_STOCK_ALIAS,           NULL,      GTK_STOCK_EDIT             },
@@ -98,7 +113,7 @@
 	{ PIDGIN_STOCK_EDIT,                N_("_Edit"),       0, 0, NULL }
 };
 
-static struct SizedStockIcon {
+typedef struct {
   const char *name;
   const char *dir;
   const char *filename;
@@ -110,18 +125,9 @@
   gboolean huge;
   gboolean rtl;
   const char *translucent_name;
-} const sized_stock_icons [] = {
-	{ PIDGIN_STOCK_STATUS_AVAILABLE,   "status", "available.png", 	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_AVAILABLE_I },
-	{ PIDGIN_STOCK_STATUS_AWAY, 	   "status", "away.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_AWAY_I },
-	{ PIDGIN_STOCK_STATUS_BUSY, 	"status", "busy.png", 		TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_BUSY_I },
-	{ PIDGIN_STOCK_STATUS_CHAT, 	"status", "chat.png",		TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL },
-	{ PIDGIN_STOCK_STATUS_INVISIBLE,"status", "invisible.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL },
-	{ PIDGIN_STOCK_STATUS_XA, 	"status", "extended-away.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, PIDGIN_STOCK_STATUS_XA_I },
-	{ PIDGIN_STOCK_STATUS_LOGIN, 	"status", "log-in.png",		TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
-	{ PIDGIN_STOCK_STATUS_LOGOUT, 	"status", "log-out.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
-	{ PIDGIN_STOCK_STATUS_OFFLINE, 	"status", "offline.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_OFFLINE_I  },
-	{ PIDGIN_STOCK_STATUS_PERSON, 	"status", "person.png",		TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_STATUS_MESSAGE, 	"toolbar", "message-new.png",   TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+} SizedStockIcon;
+
+const SizedStockIcon sized_stock_icons [] = {
 	
 	{ PIDGIN_STOCK_STATUS_IGNORED,	"emblems", "blocked.png",	FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
 	{ PIDGIN_STOCK_STATUS_FOUNDER,	"emblems", "founder.png",	FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
@@ -175,41 +181,55 @@
 	{ PIDGIN_STOCK_ANIMATION_TYPING4,  "animations", "typing4.png",FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
 	{ PIDGIN_STOCK_ANIMATION_TYPING5,  "animations", "typing5.png",FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
 
-	{ PIDGIN_STOCK_TOOLBAR_ACCOUNTS, "toolbar", "accounts.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_BGCOLOR, "toolbar", "change-bgcolor.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_BLOCK, "emblems", "blocked.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_FGCOLOR, "toolbar", "change-fgcolor.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_SMILEY, "toolbar", "emote-select.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_FONT_FACE, "toolbar", "font-face.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_TEXT_SMALLER, "toolbar", "font-size-down.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_TEXT_LARGER, "toolbar", "font-size-up.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_INSERT, "toolbar", "insert.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE, "toolbar", "insert-image.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_INSERT_LINK, "toolbar", "insert-link.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, "toolbar", "message-new.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_PENDING, "tray", "tray-new-im.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_PLUGINS, "toolbar", "plugins.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_TYPING, "toolbar", "typing.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_UNBLOCK, "toolbar", "unblock.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_SELECT_AVATAR, "toolbar", "select-avatar.png", FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_SEND_FILE, "toolbar", "send-file.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TOOLBAR_TRANSFER, "toolbar", "transfer.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
-
-	{ PIDGIN_STOCK_TRAY_AVAILABLE, "tray", "tray-online.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TRAY_INVISIBLE, "tray", "tray-invisible.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TRAY_AWAY, "tray", "tray-away.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TRAY_BUSY, "tray", "tray-busy.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TRAY_XA, "tray", "tray-extended-away.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TRAY_OFFLINE, "tray", "tray-offline.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TRAY_CONNECT, "tray", "tray-connecting.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TRAY_PENDING, "tray", "tray-new-im.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TRAY_EMAIL, "tray", "tray-message.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  }
+	{ PIDGIN_STOCK_TOOLBAR_ACCOUNTS,	"toolbar", "accounts.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_BGCOLOR,		"toolbar", "change-bgcolor.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_BLOCK,		"emblems", "blocked.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_FGCOLOR,		"toolbar", "change-fgcolor.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_SMILEY,		"toolbar", "emote-select.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_FONT_FACE,	"toolbar", "font-face.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_TEXT_SMALLER,	"toolbar", "font-size-down.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_TEXT_LARGER,	"toolbar", "font-size-up.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_INSERT,		"toolbar", "insert.png", 	 FALSE,	TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE,	"toolbar", "insert-image.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_INSERT_LINK,	"toolbar", "insert-link.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW,	"toolbar", "message-new.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_PENDING,		"toolbar", "message-new.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_PLUGINS,		"toolbar", "plugins.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_TYPING,		"toolbar", "typing.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_UNBLOCK,		"toolbar", "unblock.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_SELECT_AVATAR,	"toolbar", "select-avatar.png",	 FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_SEND_FILE,	"toolbar", "send-file.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TOOLBAR_TRANSFER,	"toolbar", "transfer.png",	 FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  }
 };
 
-static void
-add_sized_icon_common(GtkIconSet *iconset, GtkIconSize sizeid, const char *dir,
-	       gboolean rtl, const char *size, const char *file,
-		   gboolean translucent);
+const SizedStockIcon sized_status_icons [] = {
+
+	{ PIDGIN_STOCK_STATUS_AVAILABLE, "status", "available.png", 	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_AVAILABLE_I },
+	{ PIDGIN_STOCK_STATUS_AWAY, 	 "status", "away.png",		TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_AWAY_I },
+	{ PIDGIN_STOCK_STATUS_BUSY, 	 "status", "busy.png", 		TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_BUSY_I },
+	{ PIDGIN_STOCK_STATUS_CHAT, 	 "status", "chat.png",		TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL },
+	{ PIDGIN_STOCK_STATUS_INVISIBLE, "status", "invisible.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL },
+	{ PIDGIN_STOCK_STATUS_XA, 	 "status", "extended-away.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE,  PIDGIN_STOCK_STATUS_XA_I },
+	{ PIDGIN_STOCK_STATUS_LOGIN, 	 "status", "log-in.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE,  NULL },
+	{ PIDGIN_STOCK_STATUS_LOGOUT, 	 "status", "log-out.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE,  NULL },
+	{ PIDGIN_STOCK_STATUS_OFFLINE, 	 "status", "offline.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_OFFLINE_I  },
+	{ PIDGIN_STOCK_STATUS_PERSON, 	 "status", "person.png",	TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_STATUS_MESSAGE, 	 "toolbar", "message-new.png",  TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
+
+	{ PIDGIN_STOCK_TRAY_AVAILABLE,	"tray", "tray-online.png",	  FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TRAY_INVISIBLE,	"tray", "tray-invisible.png",	  FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TRAY_AWAY,	"tray", "tray-away.png",	  FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TRAY_BUSY,	"tray", "tray-busy.png", 	  FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TRAY_XA,		"tray", "tray-extended-away.png", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TRAY_OFFLINE,	"tray", "tray-offline.png",	  FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TRAY_CONNECT,	"tray", "tray-connecting.png",	  FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TRAY_PENDING,	"tray", "tray-new-im.png", 	  FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TRAY_EMAIL,	"tray", "tray-message.png",	  FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  }
+};
+
+/*****************************************************************************
+ * Private functions                                                      
+ *****************************************************************************/
 
 static gchar *
 find_file_common(const char *name)
@@ -259,16 +279,10 @@
 	return ret;
 }
 
-static void
-add_sized_icon(GtkIconSet *iconset, GtkIconSize sizeid, const char *dir,
-	       gboolean rtl, const char *size, const char *file)
-{
-	add_sized_icon_common(iconset, sizeid, dir, rtl, size, file, FALSE);
-}
 
 /* Altered from do_colorshift in gnome-panel */
 static void
-do_alphashift (GdkPixbuf *dest, GdkPixbuf *src)
+do_alphashift(GdkPixbuf *dest, GdkPixbuf *src)
 {
         gint i, j;
         gint width, height, has_alpha, srcrowstride, destrowstride;
@@ -302,28 +316,48 @@
         }
 }
 
-static void
-add_translucent_sized_icon(GtkIconSet *iconset, GtkIconSize sizeid, const char *dir,
-	       gboolean rtl, const char *size, const char *file)
+static gchar *
+find_icon_file(PidginStatusIconTheme *theme, const gchar *size, SizedStockIcon sized_icon, gboolean rtl)
 {
-	add_sized_icon_common(iconset, sizeid, dir, rtl, size, file, TRUE);
+	const gchar *file, *dir;
+	gchar *file_full = NULL;
+	gchar *tmp;
+
+	if (theme != NULL) {
+		file = pidgin_icon_theme_get_icon(PIDGIN_ICON_THEME(theme), sized_icon.name);
+		dir = purple_theme_get_dir(PURPLE_THEME(theme));
+
+		if (rtl)
+			file_full = g_build_filename(dir, size, "rtl", file, NULL);
+		else
+			file_full = g_build_filename(dir, size, file, NULL);
+
+		if (g_file_test(file_full, G_FILE_TEST_IS_REGULAR))			
+			return file_full;
+
+		g_free(file_full);
+	}
+
+	if (rtl)
+		tmp = g_build_filename("pixmaps", "pidgin", sized_icon.dir, size, "rtl", sized_icon.filename, NULL);
+	else
+		tmp = g_build_filename("pixmaps", "pidgin", sized_icon.dir, size, sized_icon.filename, NULL);
+
+	file_full = find_file_common(tmp);
+	g_free(tmp);
+	return file_full;
 }
 
 static void
-add_sized_icon_common(GtkIconSet *iconset, GtkIconSize sizeid, const char *dir,
-	       gboolean rtl, const char *size, const char *file,
-		   gboolean translucent)
+add_sized_icon(GtkIconSet *iconset, GtkIconSize sizeid, PidginStatusIconTheme *theme,
+		const char *size, SizedStockIcon sized_icon, gboolean translucent)
 {
-	char *filename, *subpath;
+	char *filename;
 	GtkIconSource *source;
 	GdkPixbuf *pixbuf;
 
-	subpath = g_build_filename("pixmaps", "pidgin", dir, size, file, NULL);
-	filename = find_file_common(subpath);
-	g_free(subpath);
-	if (!filename)
-		return;
-
+	filename = find_icon_file(theme, size, sized_icon, FALSE);
+	g_return_if_fail(filename != NULL);
 	pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
 	if (translucent)
 		do_alphashift(pixbuf, pixbuf);
@@ -331,7 +365,7 @@
 	source = gtk_icon_source_new();
 	gtk_icon_source_set_pixbuf(source, pixbuf);
 	gtk_icon_source_set_direction(source, GTK_TEXT_DIR_LTR);
-	gtk_icon_source_set_direction_wildcarded(source, !rtl);
+	gtk_icon_source_set_direction_wildcarded(source, !sized_icon.rtl);
 	gtk_icon_source_set_size(source, sizeid);
 	gtk_icon_source_set_size_wildcarded(source, FALSE);
 	gtk_icon_source_set_state_wildcarded(source, TRUE);
@@ -351,17 +385,16 @@
 	g_free(filename);
 	g_object_unref(pixbuf);
 
-	if (rtl) {
-		subpath = g_build_filename("pixmaps", "pidgin", dir, size, "rtl", file, NULL);
-		filename = find_file_common(subpath);
-		g_free(subpath);
-		if (!filename)
-			return;
+	if (sized_icon.rtl) {
+		filename = find_icon_file(theme, size, sized_icon, TRUE);
+		g_return_if_fail(filename != NULL);
 		pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
 		if (translucent)
 			do_alphashift(pixbuf, pixbuf);
+
 		source = gtk_icon_source_new();
 		gtk_icon_source_set_pixbuf(source, pixbuf);
+		gtk_icon_source_set_filename(source, filename);
 		gtk_icon_source_set_direction(source, GTK_TEXT_DIR_RTL);
 		gtk_icon_source_set_size(source, sizeid);
 		gtk_icon_source_set_size_wildcarded(source, FALSE);
@@ -373,20 +406,90 @@
 	}
 }
 
+/*****************************************************************************
+ * Public API functions                                                      
+ *****************************************************************************/
+
+void
+pidgin_stock_load_status_icon_theme(PidginStatusIconTheme *theme)
+{
+	GtkIconFactory *icon_factory;
+	gint i;
+	GtkIconSet *normal;
+	GtkIconSet *translucent = NULL;
+	GtkWidget *win;
+
+	if (theme != NULL) {
+		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/status/icon-theme", 
+				        purple_theme_get_name(PURPLE_THEME(theme)));
+		purple_prefs_set_path(PIDGIN_PREFS_ROOT "/status/icon-theme-dir", 
+				      purple_theme_get_dir(PURPLE_THEME(theme)));
+	}
+	else {
+		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/status/icon-theme", "");
+		purple_prefs_set_path(PIDGIN_PREFS_ROOT "/status/icon-theme-dir", "");
+	}
+	
+	icon_factory = gtk_icon_factory_new();
+
+	gtk_icon_factory_add_default(icon_factory);
+
+	win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_widget_realize(win);
+
+	for (i = 0; i < G_N_ELEMENTS(sized_status_icons); i++)
+	{
+		normal = gtk_icon_set_new();
+		if (sized_status_icons[i].translucent_name)
+			translucent = gtk_icon_set_new();
+
+#define ADD_SIZED_ICON(name, size) if (sized_status_icons[i].name) { \
+					add_sized_icon(normal, name, theme, size, sized_status_icons[i], FALSE); \
+					if (sized_status_icons[i].translucent_name) \
+						add_sized_icon(translucent, name, theme, size, sized_status_icons[i], TRUE); \
+				   }
+		ADD_SIZED_ICON(microscopic, "11");
+		ADD_SIZED_ICON(extra_small, "16");
+		ADD_SIZED_ICON(small, "22");
+		ADD_SIZED_ICON(medium, "32");
+		ADD_SIZED_ICON(large, "48");
+		ADD_SIZED_ICON(huge, "64");
+#undef ADD_SIZED_ICON
+
+		gtk_icon_factory_add(icon_factory, sized_status_icons[i].name, normal);
+		gtk_icon_set_unref(normal);
+
+		if (sized_status_icons[i].translucent_name) {
+			gtk_icon_factory_add(icon_factory, sized_status_icons[i].translucent_name, translucent);
+			gtk_icon_set_unref(translucent);
+		}
+	}
+
+
+	gtk_widget_destroy(win);
+	g_object_unref(G_OBJECT(icon_factory));
+}
+
 void
 pidgin_stock_init(void)
 {
-	static gboolean stock_initted = FALSE;
 	GtkIconFactory *icon_factory;
 	size_t i;
 	GtkWidget *win;
-	GtkIconSize microscopic, extra_small, small, medium, large, huge;
+	PidginIconThemeLoader *loader;
+	const gchar *path = NULL;
 
 	if (stock_initted)
 		return;
 
 	stock_initted = TRUE;
 
+	/* Setup the status icon theme */
+	loader = g_object_new(PIDGIN_TYPE_ICON_THEME_LOADER, "type", "status-icon", NULL);
+	purple_theme_manager_register_type(PURPLE_THEME_LOADER(loader));
+	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/status/icon-theme", "");
+	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/status/icon-theme-dir", "");
+
 	/* Setup the icon factory. */
 	icon_factory = gtk_icon_factory_new();
 
@@ -396,6 +499,7 @@
 	win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 	gtk_widget_realize(win);
 
+	/* All non-sized icons */
 	for (i = 0; i < G_N_ELEMENTS(stock_icons); i++)
 	{
 		GtkIconSource *source;
@@ -434,7 +538,6 @@
 	}
 
 	/* register custom icon sizes */
-
 	microscopic =  gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC, 11, 11);
 	extra_small =  gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL, 16, 16);
 	small =        gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_SMALL, 22, 22);
@@ -442,18 +545,13 @@
 	large =        gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_LARGE, 48, 48);
 	huge =         gtk_icon_size_register(PIDGIN_ICON_SIZE_TANGO_HUGE, 64, 64);
 
+	/* All non-status sized icons */
 	for (i = 0; i < G_N_ELEMENTS(sized_stock_icons); i++)
 	{
-		GtkIconSet *iconset;
-
-		iconset = gtk_icon_set_new();
+		GtkIconSet *iconset = gtk_icon_set_new();
 
-#define ADD_SIZED_ICON(name, size) do { \
-		if (sized_stock_icons[i].name)  \
-			add_sized_icon(iconset, name,  \
-					sized_stock_icons[i].dir, sized_stock_icons[i].rtl, \
-					size, sized_stock_icons[i].filename); \
-		} while (0)
+#define ADD_SIZED_ICON(name, size) if (sized_stock_icons[i].name) \
+					add_sized_icon(iconset, name, NULL, size, sized_stock_icons[i], FALSE);		
 		ADD_SIZED_ICON(microscopic, "11");
 		ADD_SIZED_ICON(extra_small, "16");
 		ADD_SIZED_ICON(small, "22");
@@ -464,32 +562,21 @@
 
 		gtk_icon_factory_add(icon_factory, sized_stock_icons[i].name, iconset);
 		gtk_icon_set_unref(iconset);
-
-		if (sized_stock_icons[i].translucent_name) {
-			iconset = gtk_icon_set_new();
-
-#define ADD_TRANS_ICON(name, size) do { \
-			if (sized_stock_icons[i].name) \
-				add_translucent_sized_icon(iconset, name, \
-						sized_stock_icons[i].dir, sized_stock_icons[i].rtl, \
-						size, sized_stock_icons[i].filename); \
-			} while (0)
-			ADD_TRANS_ICON(microscopic, "11");
-			ADD_TRANS_ICON(extra_small, "16");
-			ADD_TRANS_ICON(small, "22");
-			ADD_TRANS_ICON(medium, "32");
-			ADD_TRANS_ICON(large, "48");
-			ADD_TRANS_ICON(huge, "64");
-#undef ADD_TRANS_ICON
-
-			gtk_icon_factory_add(icon_factory, sized_stock_icons[i].translucent_name, iconset);
-			gtk_icon_set_unref(iconset);
-		}
 	}
 
 	gtk_widget_destroy(win);
 	g_object_unref(G_OBJECT(icon_factory));
 
+	/* Pre-load Status icon theme - this avoids a bug with displaying the correct icon in the tray, theme is destroyed after*/
+	if (purple_prefs_get_string(PIDGIN_PREFS_ROOT "/icon/status/theme") && 
+	   (path = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/status/icon-theme-dir"))) {
+		
+		PidginStatusIconTheme *theme = PIDGIN_STATUS_ICON_THEME(purple_theme_loader_build(PURPLE_THEME_LOADER(loader), path));
+		pidgin_stock_load_status_icon_theme(theme);
+		g_object_unref(G_OBJECT(theme));
+
+	} else pidgin_stock_load_status_icon_theme(NULL);
+
 	/* Register the stock items. */
 	gtk_stock_add_static(stock_items, G_N_ELEMENTS(stock_items));
 }
--- a/pidgin/pidginstock.h	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/pidginstock.h	Thu Nov 27 21:15:43 2008 +0000
@@ -24,6 +24,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 #include <gtk/gtkstock.h>
+#include "gtkstatus-icon-theme.h"
 
 #ifndef _PIDGIN_STOCK_H_
 #define _PIDGIN_STOCK_H_
@@ -177,6 +178,14 @@
 #define PIDGIN_ICON_SIZE_TANGO_MEDIUM         "pidgin-icon-size-tango-medium"
 #define PIDGIN_ICON_SIZE_TANGO_LARGE          "pidgin-icon-size-tango-large"
 #define PIDGIN_ICON_SIZE_TANGO_HUGE           "pidgin-icon-size-tango-huge"
+
+/**
+ * Loades all of the icons from the status icon theme into Pidgin stock
+ * 
+ * @param theme		the theme to load, or null to load all the default icons
+ */
+void pidgin_stock_load_status_icon_theme(PidginStatusIconTheme *theme);
+
 /**
  * Sets up the purple stock repository.
  */
--- a/pidgin/plugins/history.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/plugins/history.c	Thu Nov 27 21:15:43 2008 +0000
@@ -47,10 +47,11 @@
 
 	convtype = purple_conversation_get_type(c);
 	gtkconv = PIDGIN_CONVERSATION(c);
-	if (gtkconv == NULL)
-		return;
+	g_return_if_fail(gtkconv != NULL);
 
-	if (convtype == PURPLE_CONV_TYPE_IM && g_list_length(gtkconv->convs) < 2)
+	/* An IM which is the first active conversation. */
+	g_return_if_fail(gtkconv->convs != NULL);
+	if (convtype == PURPLE_CONV_TYPE_IM && !gtkconv->convs->next)
 	{
 		GSList *buddies;
 		GSList *cur;
@@ -70,16 +71,20 @@
 	        for (cur = buddies; cur != NULL; cur = cur->next)
 	        {
 	                PurpleBlistNode *node = cur->data;
-	                if ((node != NULL) && ((node->prev != NULL) || (node->next != NULL)))
+					PurpleBlistNode *prev = purple_blist_node_get_sibling_prev(node);
+					PurpleBlistNode *next = purple_blist_node_get_sibling_next(node);
+	                if ((node != NULL) && ((prev != NULL) || (next != NULL)))
 	                {
 				PurpleBlistNode *node2;
+				PurpleBlistNode *parent = purple_blist_node_get_parent(node);
+				PurpleBlistNode *child = purple_blist_node_get_first_child(parent);
 
 				alias = purple_buddy_get_contact_alias((PurpleBuddy *)node);
 
 				/* We've found a buddy that matches this conversation.  It's part of a
 				 * PurpleContact with more than one PurpleBuddy.  Loop through the PurpleBuddies
 				 * in the contact and get all the logs. */
-				for (node2 = node->parent->child ; node2 != NULL ; node2 = node2->next)
+				for (node2 = child ; node2 != NULL ; node2 = purple_blist_node_get_sibling_next(node2))
 				{
 					logs = g_list_concat(
 						purple_log_get_logs(PURPLE_LOG_IM,
--- a/pidgin/plugins/relnot.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/plugins/relnot.c	Thu Nov 27 21:15:43 2008 +0000
@@ -34,7 +34,10 @@
 #include "connection.h"
 #include "core.h"
 #include "debug.h"
+#include "gtkblist.h"
+#include "gtkutils.h"
 #include "notify.h"
+#include "pidginstock.h"
 #include "prefs.h"
 #include "util.h"
 #include "version.h"
@@ -45,12 +48,26 @@
 #define MIN_CHECK_INTERVAL 60 * 60 * 24
 
 static void
+release_hide()
+{
+	/* No-op.  We may use this method in the future to avoid showing
+	 * the popup twice */
+}
+
+static void
+release_show()
+{
+	purple_notify_uri(NULL, PURPLE_WEBSITE);
+}
+
+static void
 version_fetch_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
 		const gchar *response, size_t len, const gchar *error_message)
 {
-	gchar *cur_ver, *formatted;
+	gchar *cur_ver;
 	const char *tmp, *changelog;
 	char response_code[4];
+	GtkWidget *release_dialog;
 
 	GString *message;
 	int i = 0;
@@ -89,27 +106,21 @@
 		return;
 
 	cur_ver = g_strndup(changelog, i);
-	changelog += i;
-
-	while(*changelog == '\n') changelog++;
 
 	message = g_string_new("");
-	g_string_append_printf(message, _("You are using %s version %s.  The "
-			"current version is %s.  You can get it from "
-			"<a href=\"%s\">%s</a><hr>"),
-			PIDGIN_NAME, purple_core_get_version(), cur_ver,
-			PURPLE_WEBSITE, PURPLE_WEBSITE);
+	g_string_append_printf(message, _("You can upgrade to %s %s today."),
+			PIDGIN_NAME, cur_ver);
 
-	if(*changelog) {
-		formatted = purple_strdup_withhtml(changelog);
-		g_string_append_printf(message, _("<b>ChangeLog:</b><br>%s"),
-				formatted);
-		g_free(formatted);
-	}
+	release_dialog = pidgin_make_mini_dialog(
+		NULL, PIDGIN_STOCK_DIALOG_INFO,
+		_("New Version Available"),
+		message->str,
+		NULL,
+		_("Later"), PURPLE_CALLBACK(release_hide),
+		_("Download Now"), PURPLE_CALLBACK(release_show),
+		NULL);
 
-	purple_notify_formatted(NULL, _("New Version Available"),
-			_("New Version Available"), NULL, message->str,
-			NULL, NULL);
+	pidgin_blist_add_alert(release_dialog);
 
 	g_string_free(message, TRUE);
 	g_free(cur_ver);
--- a/pidgin/plugins/ticker/ticker.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/plugins/ticker/ticker.c	Thu Nov 27 21:15:43 2008 +0000
@@ -91,7 +91,9 @@
 	PurpleContact *contact = user_data;
 	PurpleBuddy *b = purple_contact_get_priority_buddy(contact);
 
-	purple_conversation_new(PURPLE_CONV_TYPE_IM, b->account, b->name);
+	purple_conversation_new(PURPLE_CONV_TYPE_IM,
+	                        purple_buddy_get_account(b),
+							purple_buddy_get_name(b));
 	return TRUE;
 }
 
@@ -217,20 +219,25 @@
 
 static void buddy_ticker_show(void)
 {
-	PurpleBuddyList *list = purple_get_blist();
 	PurpleBlistNode *gnode, *cnode, *bnode;
 	PurpleBuddy *b;
 
-	if(!list)
-		return;
-
-	for(gnode = list->root; gnode; gnode = gnode->next) {
+	for(gnode = purple_blist_get_root();
+	    gnode;
+	    gnode = purple_blist_node_get_sibling_next(gnode))
+	{
 		if(!PURPLE_BLIST_NODE_IS_GROUP(gnode))
 			continue;
-		for(cnode = gnode->child; cnode; cnode = cnode->next) {
+		for(cnode = purple_blist_node_get_first_child(gnode);
+		    cnode;
+		    cnode = purple_blist_node_get_sibling_next(cnode))
+		{
 			if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
 				continue;
-			for(bnode = cnode->child; bnode; bnode = bnode->next) {
+			for(bnode = purple_blist_node_get_first_child(cnode);
+			    bnode;
+			    bnode = purple_blist_node_get_sibling_next(bnode))
+			{
 				if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
 				b = (PurpleBuddy *)bnode;
--- a/pidgin/win32/winpidgin.c	Sun Nov 23 18:30:31 2008 +0000
+++ b/pidgin/win32/winpidgin.c	Thu Nov 27 21:15:43 2008 +0000
@@ -621,9 +621,22 @@
 	char *tmp;
 	int pidgin_argc = __argc;
 	char **pidgin_argv = __argv;
+	int i;
+	BOOL debug = FALSE, help = FALSE, version = FALSE, multiple = FALSE;
 
 	/* If debug or help or version flag used, create console for output */
-	if (strstr(lpszCmdLine, "-d") || strstr(lpszCmdLine, "-h") || strstr(lpszCmdLine, "-v")) {
+	for (i = 1; i < __argc; i++) {
+		if (strstr(__argv[i], "-d") || strstr(__argv[i], "--debug"))
+			debug = TRUE;
+		else if (strstr(__argv[i], "-h") || strstr(__argv[i], "--help"))
+			help = TRUE;
+		else if (strstr(__argv[i], "-v") || strstr(__argv[i], "--version"))
+			version = TRUE;
+		else if (strstr(__argv[i], "-m") || strstr(__argv[i], "--multiple"))
+			multiple = TRUE;
+	}
+
+	if (debug || help || version) {
 		/* If stdout hasn't been redirected to a file, alloc a console
 		 *  (_istty() doesn't work for stuff using the GUI subsystem) */
 		if (_fileno(stdout) == -1 || _fileno(stdout) == -2) {
@@ -710,8 +723,8 @@
 	winpidgin_add_stuff_to_path();
 
 	/* If help, version or multiple flag used, do not check Mutex */
-	if (!strstr(lpszCmdLine, "-h") && !strstr(lpszCmdLine, "-v"))
-		if (!winpidgin_set_running(getenv("PIDGIN_MULTI_INST") == NULL && strstr(lpszCmdLine, "-m") == NULL))
+	if (!help && !version)
+		if (!winpidgin_set_running(getenv("PIDGIN_MULTI_INST") == NULL && !multiple))
 			return 0;
 
 	/* Now we are ready for Pidgin .. */
--- a/po/POTFILES.in	Sun Nov 23 18:30:31 2008 +0000
+++ b/po/POTFILES.in	Thu Nov 27 21:15:43 2008 +0000
@@ -183,6 +183,7 @@
 libpurple/status.c
 libpurple/util.c
 libpurple/win32/libc_interface.c
+libpurple/xmlnode.c
 pidgin.desktop.in
 pidgin/eggtrayicon.c
 pidgin/gtkaccount.c
--- a/po/de.po	Sun Nov 23 18:30:31 2008 +0000
+++ b/po/de.po	Thu Nov 27 21:15:43 2008 +0000
@@ -11,7 +11,7 @@
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-10-28 17:46+0100\n"
+"POT-Creation-Date: 2008-11-25 22:03+0100\n"
 "PO-Revision-Date: 2008-10-28 17:46+0100\n"
 "Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
 "Language-Team: Deutsch <de@li.org>\n"
@@ -273,7 +273,6 @@
 msgid "Add Buddy Pounce"
 msgstr "Buddy-Alarm hinzufügen"
 
-#. if (q_bud && is_online(q_bud->status)) {
 msgid "Send File"
 msgstr "Datei versenden"
 
@@ -1340,7 +1339,7 @@
 #. PurpleStatusPrimitive
 #. id - use default
 #. name - use default
-#. savable
+#. saveable
 #. user_settable
 #. not independent
 #. Attributes - each status can have a message.
@@ -4977,7 +4976,7 @@
 #. primitive
 #. ID
 #. name - use default
-#. savable
+#. saveable
 #. should be user_settable some day
 #. independent
 msgid "Artist"
@@ -5190,8 +5189,7 @@
 #. *< id
 #. *< name
 #. *< version
-#. *  summary
-#. *  description
+#. *< summary
 msgid "Windows Live Messenger Protocol Plugin"
 msgstr "Windows Live Messenger Protokoll-Plugin"
 
@@ -6217,7 +6215,7 @@
 msgstr "Bewertung zum Client"
 
 msgid "Service unavailable"
-msgstr "Dienst nicht unerreichbar"
+msgstr "Dienst nicht verfügbar"
 
 msgid "Service not defined"
 msgstr "Dienst nicht definiert"
@@ -6425,6 +6423,7 @@
 "Leerzeichen enthalten oder nur aus Ziffern bestehen."
 
 #. Unregistered screen name
+#. uid is not exist
 msgid "Invalid username."
 msgstr "Ungültiger Benutzername."
 
@@ -6858,10 +6857,12 @@
 "beginnen und nur Buchstaben, Ziffern und Leerzeichen enthalten oder nur aus "
 "Ziffern bestehen."
 
-msgid "Unable To Add"
+#, fuzzy
+msgid "Unable to Add"
 msgstr "Kann nicht hinzufügen"
 
-msgid "Unable To Retrieve Buddy List"
+#, fuzzy
+msgid "Unable to Retrieve Buddy List"
 msgstr "Konnte Buddy-Liste nicht laden"
 
 msgid ""
@@ -7086,42 +7087,6 @@
 "ist notwendig für IM-Bilder. Da Ihre IP-Adresse verwendet wird, kann dies "
 "eine Verletzung der Privatsphäre bedeuten."
 
-msgid "Primary Information"
-msgstr "Primäre Informationen"
-
-msgid "Personal Introduction"
-msgstr "Persönliche Vorstellung"
-
-msgid "QQ Number"
-msgstr "QQ-Nummer"
-
-msgid "Country/Region"
-msgstr "Land/Region"
-
-msgid "Province/State"
-msgstr "Provinz/Staat"
-
-msgid "Horoscope Symbol"
-msgstr "Horoskopsymbol"
-
-msgid "Zodiac Sign"
-msgstr "Sternzeichen"
-
-msgid "Blood Type"
-msgstr "Blutgruppe"
-
-msgid "College"
-msgstr "College"
-
-msgid "Zipcode"
-msgstr "PLZ"
-
-msgid "Cellphone Number"
-msgstr "Handy-Telefonnummer"
-
-msgid "Phone Number"
-msgstr "Telefonnummer"
-
 msgid "Aquarius"
 msgstr "Wassermann"
 
@@ -7197,100 +7162,189 @@
 msgid "Other"
 msgstr "Andere"
 
-msgid "Modify information"
+#, fuzzy
+msgid "Visible"
+msgstr "Unsichtbar"
+
+msgid "Firend Only"
+msgstr ""
+
+#, fuzzy
+msgid "Private"
+msgstr "Privatsphäre"
+
+msgid "QQ Number"
+msgstr "QQ-Nummer"
+
+msgid "Country/Region"
+msgstr "Land/Region"
+
+msgid "Province/State"
+msgstr "Provinz/Staat"
+
+msgid "Zipcode"
+msgstr "PLZ"
+
+msgid "Phone Number"
+msgstr "Telefonnummer"
+
+#, fuzzy
+msgid "Authorize adding"
+msgstr "Buddy autorisieren?"
+
+msgid "Cellphone Number"
+msgstr "Handy-Telefonnummer"
+
+msgid "Personal Introduction"
+msgstr "Persönliche Vorstellung"
+
+#, fuzzy
+msgid "City/Area"
+msgstr "Stadt"
+
+#, fuzzy
+msgid "Publish Mobile"
+msgstr "Handy (privat)"
+
+#, fuzzy
+msgid "Publish Contact"
+msgstr "Kontakt-Alias"
+
+msgid "College"
+msgstr "College"
+
+#, fuzzy
+msgid "Horoscope"
+msgstr "Horoskopsymbol"
+
+#, fuzzy
+msgid "Zodiac"
+msgstr "Sternzeichen"
+
+#, fuzzy
+msgid "Blood"
+msgstr "Blockiert"
+
+#, fuzzy
+msgid "True"
+msgstr "Stier"
+
+#, fuzzy
+msgid "False"
+msgstr "Gescheitert"
+
+#, fuzzy
+msgid "Modify Contact"
+msgstr "Konto bearbeiten"
+
+#, fuzzy
+msgid "Modify Address"
+msgstr "Privatadresse"
+
+#, fuzzy
+msgid "Modify Extended Information"
 msgstr "Informationen bearbeiten"
 
-msgid "Update information"
-msgstr "Informationen aktualisieren"
-
-#. TODO: We don't really need to notify the user about this, do we?
-#. TODO: Does the user really need to be notified about this?
-msgid "QQ Buddy"
-msgstr "QQ-Buddy"
-
-msgid "Successed:"
-msgstr "Erfolgreich:"
-
-msgid "Change buddy information."
+#, fuzzy
+msgid "Modify Information"
+msgstr "Informationen bearbeiten"
+
+#, fuzzy
+msgid "Update"
+msgstr "Letzte Aktualisierung"
+
+#, fuzzy
+msgid "Could not change buddy information."
 msgstr "Buddy-Informationen bearbeiten"
 
 #, c-format
-msgid ""
-"Setting custom faces is not currently supported. Please choose an image from "
-"%s."
-msgstr ""
-"Das Setzen von benutzerdefinierten Gesichtern wird momentan nicht "
-"unterstützt. Bitte wählen Sie ein Bild von %s."
-
-msgid "Invalid QQ Face"
-msgstr "Ungültiges QQ-Gesicht"
-
-# c-format
-#, c-format
-msgid "You rejected %d's request"
-msgstr "Sie haben die Anfrage von %d abgelehnt"
-
-msgid "Reject request"
-msgstr "Anfrage ablehnen"
-
-#. title
-msgid "Sorry, you are not my style..."
+msgid "%d needs Q&A"
+msgstr ""
+
+#, fuzzy
+msgid "Add buddy Q&A"
+msgstr "Buddy hinzufügen"
+
+#, fuzzy
+msgid "Input answer here"
+msgstr "Anfrage hier eingeben"
+
+msgid "Send"
+msgstr "Senden"
+
+#, fuzzy
+msgid "Invalid answer."
+msgstr "Ungültiger Benutzername."
+
+msgid "Authorization denied message:"
+msgstr "Nachricht für die Ablehnung der Autorisierung:"
+
+#, fuzzy
+msgid "Sorry, You are not my style."
 msgstr "Tut mir Leid, du bist nicht mein Typ..."
 
-msgid "Add buddy with auth request failed"
-msgstr "Benutzer hinzufügen, wenn Autorisierungsanfrage fehlschlug"
-
-msgid "Failed:"
-msgstr "Gescheitert:"
-
-msgid "Remove buddy"
-msgstr "Buddy entfernen"
-
-msgid "Remove from other's buddy list"
-msgstr "Von der Liste des Buddys entfernen"
-
 #, c-format
 msgid "%d needs authentication"
 msgstr "%d benötigt Authentifizierung"
 
+#, fuzzy
+msgid "Add buddy authorize"
+msgstr "Benutzer zu Ihrer Buddy-Liste hinzufügen?"
+
 msgid "Input request here"
 msgstr "Anfrage hier eingeben"
 
-#. TODO: Awkward string to fix post string freeze - standardize auth dialogues? -evands
 msgid "Would you be my friend?"
 msgstr "Möchten Sie mein Freund sein?"
 
-#. multiline
-#. masked
-#. hint
-msgid "Send"
-msgstr "Senden"
-
-#, c-format
-msgid "Add into %d's buddy list"
-msgstr "Zu %ds Buddy-Liste hinzufügen"
-
-msgid "QQ Number Error"
-msgstr "Fehler in QQ-Nummer"
+msgid "QQ Buddy"
+msgstr "QQ-Buddy"
+
+#, fuzzy
+msgid "Add buddy"
+msgstr "Buddy hinzufügen"
 
 msgid "Invalid QQ Number"
 msgstr "Ungültige QQ-Nummer"
 
+#, fuzzy
+msgid "Failed sending authorize"
+msgstr "Bitte autorisiere mich!"
+
+#, fuzzy, c-format
+msgid "Failed removing buddy %d"
+msgstr "Kontakt konnte nicht entfernt werden"
+
+#, fuzzy, c-format
+msgid "Failed removing me from %d's buddy list"
+msgstr "Von der Liste des Buddys entfernen"
+
+#, fuzzy
+msgid "No reason given"
+msgstr "Kein Grund angegeben."
+
+#. only need to get value
+#, c-format
+msgid "You have been added by %s"
+msgstr "Sie wurden von %s hinzugefügt"
+
+msgid "Would you like to add him?"
+msgstr "Möchten Sie ihn hinzufügen?"
+
+#, fuzzy, c-format
+msgid "Rejected by %s"
+msgstr "Anfrage abgelehnt von %s"
+
+#, c-format
+msgid "Message: %s"
+msgstr "Nachricht: %s"
+
 msgid "ID: "
 msgstr "ID: "
 
 msgid "Group ID"
 msgstr "Gruppen-ID"
 
-msgid "Creator"
-msgstr "Ersteller"
-
-msgid "Group Description"
-msgstr "Gruppenbeschreibung"
-
-msgid "Auth"
-msgstr "Autorisieren"
-
 msgid "QQ Qun"
 msgstr "QQ-Qun"
 
@@ -7300,75 +7354,71 @@
 msgid "You can only search for permanent Qun\n"
 msgstr "Sie können nur nach permanenten Qun suchen\n"
 
-#, c-format
-msgid "%d request to join Qun %d"
-msgstr "%d möchte dem Qun %d beitreten"
-
-#, c-format
-msgid "Message: %s"
-msgstr "Nachricht: %s"
-
-msgid "QQ Qun Operation"
-msgstr "QQ-Qun-Operation"
-
-msgid "Approve"
-msgstr "Akzeptieren"
-
-#, c-format
-msgid "Failed to join Qun %d, operated by admin %d"
-msgstr "Dem Qun %d, moderiert von admin %d, konnte nicht beigetreten werden"
-
-#, c-format
-msgid "Successed to join Qun %d, operated by admin %d"
-msgstr "Erfolgreicher Beitritt in den Qun %d, moderiert vom Admin %d"
-
-#, c-format
-msgid "[%d] removed from Qun \"%d\""
-msgstr "[%d] vom Qun „%d“ entfernt"
-
-msgid "Notice:"
+#, fuzzy
+msgid "Not member"
+msgstr "Ich bin kein Mitglied"
+
+msgid "Member"
+msgstr "Mitglied"
+
+#, fuzzy
+msgid "Requesting"
+msgstr "Anfrage-Dialog"
+
+#, fuzzy
+msgid "Admin"
+msgstr "Adium"
+
+#, fuzzy
+msgid "Notice"
 msgstr "Bemerkung:"
 
-#, c-format
-msgid "[%d] added to Qun \"%d\""
-msgstr "[%d] zum Qun „%d“ hinzugefügt"
-
-msgid "I am not a member"
-msgstr "Ich bin kein Mitglied"
-
-msgid "I am a member"
-msgstr "Ich bin Mitglied"
-
-msgid "I am requesting"
-msgstr "Ich frage an"
-
-msgid "I am the admin"
-msgstr "Ich bin der Admin"
-
-msgid "Unknown status"
-msgstr "Unbekannter Status"
+#, fuzzy
+msgid "Detail"
+msgstr "Standard"
+
+msgid "Creator"
+msgstr "Ersteller"
+
+#, fuzzy
+msgid "About me"
+msgstr "Über %s"
+
+#, fuzzy
+msgid "Category"
+msgstr "Chatfehler"
 
 msgid "The Qun does not allow others to join"
 msgstr "Diesen Qun können andere nicht beitreten"
 
-msgid "Remove from Qun"
-msgstr "vom Qun entfernen"
-
-msgid "Join to Qun"
+#, fuzzy
+msgid "Join QQ Qun"
 msgstr "Qun betreten"
 
 #, c-format
+msgid "Successfully joined Qun %s (%d)"
+msgstr ""
+
+#, fuzzy
+msgid "Successfully joined Qun"
+msgstr "Sie haben einen Qun angelegt"
+
+#, c-format
 msgid "Qun %d denied to join"
 msgstr "Qun %d hat Ihren Beitritt abgelehnt"
 
+msgid "QQ Qun Operation"
+msgstr "QQ-Qun-Operation"
+
+msgid "Failed:"
+msgstr "Gescheitert:"
+
 msgid "Join Qun, Unknow Reply"
 msgstr "Qun-Beitritt, Unbekannte Antwort"
 
-msgid "You entered a group ID outside the acceptable range"
-msgstr "Sie haben eine Gruppen-ID außerhalb des erlaubten Bereichs angegeben"
-
-msgid "Are you sure you want to leave this Qun?"
-msgstr "Wollen Sie dieses Qun wirklich verlassen?"
+#, fuzzy
+msgid "Quit Qun"
+msgstr "QQ-Qun"
 
 msgid ""
 "Note, if you are the creator, \n"
@@ -7377,43 +7427,51 @@
 "Beachten Sie, dass diese Operation den Qun entfernen könnte, \n"
 "wenn Sie der Ersteller sind."
 
-#. we want to see window
-msgid "Do you want to approve the request?"
-msgstr "Wollen sie die Anfrage akzeptieren?"
-
-msgid "Change Qun member"
+#, fuzzy
+msgid "Sorry, you are not our style ..."
+msgstr "Tut mir Leid, du bist nicht mein Typ..."
+
+#, fuzzy
+msgid "Successfully changed Qun member"
 msgstr "Qun-Mitglied ändern"
 
-msgid "Change Qun information"
+#, fuzzy
+msgid "Successfully changed Qun information"
 msgstr "Qun-Informationen bearbeiten"
 
 msgid "You have successfully created a Qun"
 msgstr "Sie haben einen Qun angelegt"
 
-msgid "Would you like to set up the detail information now?"
+#, fuzzy
+msgid "Would you like to set detailed information now?"
 msgstr "Möchten Sie jetzt Detail-Informationen einstellen?"
 
 msgid "Setup"
 msgstr "Setup"
 
-#, c-format
-msgid ""
-"%s\n"
-"\n"
-"%s"
-msgstr ""
-"%s\n"
-"\n"
-"%s"
-
-msgid "QQ Server News"
-msgstr "QQ-Server-News"
-
-msgid "System Message"
-msgstr "Systemnachricht"
-
-msgid "Failed to send IM."
-msgstr "Senden der Nachricht fehlgeschlagen."
+#, fuzzy, c-format
+msgid "%d requested to join Qun %d for %s"
+msgstr "%d möchte dem Qun %d beitreten"
+
+#, c-format
+msgid "%d request to join Qun %d"
+msgstr "%d möchte dem Qun %d beitreten"
+
+#, c-format
+msgid "Failed to join Qun %d, operated by admin %d"
+msgstr "Dem Qun %d, moderiert von admin %d, konnte nicht beigetreten werden"
+
+#, c-format
+msgid "<b>Joining Qun %d is approved by admin %d for %s</b>"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "<b>Removed buddy %d.</b>"
+msgstr "Buddy entfernen"
+
+#, c-format
+msgid "<b>New buddy %d joined.</b>"
+msgstr ""
 
 #, c-format
 msgid "Unknown-%d"
@@ -7422,9 +7480,6 @@
 msgid "Level"
 msgstr "Stufe"
 
-msgid "Member"
-msgstr "Mitglied"
-
 msgid " VIP"
 msgstr " VIP"
 
@@ -7452,24 +7507,36 @@
 msgid "Invalid name"
 msgstr "QQ: Ungültiger Name"
 
-#, c-format
-msgid "<b>Current Online</b>: %d<br>\n"
+#, fuzzy
+msgid "Select icon..."
+msgstr "Ordner auswählen..."
+
+#, fuzzy, c-format
+msgid "<b>Login time</b>: %d-%d-%d, %d:%d:%d<br>\n"
+msgstr "<b>Anmeldezeit</b>: %s<br>\n"
+
+#, fuzzy, c-format
+msgid "<b>Total Online Buddies</b>: %d<br>\n"
 msgstr "<b>Aktuell online:</b> %d<br>\n"
 
-#, c-format
-msgid "<b>Last Refresh</b>: %s<br>\n"
+#, fuzzy, c-format
+msgid "<b>Last Refresh</b>: %d-%d-%d, %d:%d:%d<br>\n"
 msgstr "<b>Letzte Aktualisierung</b>: %s<br>\n"
 
 #, c-format
 msgid "<b>Server</b>: %s<br>\n"
 msgstr "<b>Server</b>: %s<br>\n"
 
+#, fuzzy, c-format
+msgid "<b>Client Tag</b>: %s<br>\n"
+msgstr "<b>Anmeldezeit</b>: %s<br>\n"
+
 #, c-format
 msgid "<b>Connection Mode</b>: %s<br>\n"
 msgstr "<b>Verbindungsmodus</b>: %s<br>\n"
 
-#, c-format
-msgid "<b>My Internet Address</b>: %s<br>\n"
+#, fuzzy, c-format
+msgid "<b>My Internet IP</b>: %s:%d<br>\n"
 msgstr "<b>Meine Internet-Adresse</b>: %s<br>\n"
 
 #, c-format
@@ -7492,23 +7559,44 @@
 msgid "<b>Received Duplicate</b>: %lu<br>\n"
 msgstr "<b>Duplikat empfangen</b>: %lu<br>\n"
 
-#, c-format
-msgid "<b>Login Time</b>: %s<br>\n"
+#, fuzzy, c-format
+msgid "<b>Time</b>: %d-%d-%d, %d:%d:%d<br>\n"
 msgstr "<b>Anmeldezeit</b>: %s<br>\n"
 
-#, c-format
-msgid "<b>Last Login IP</b>: %s<br>\n"
-msgstr "<b>Letzte Anmelde-IP</b>: %s<br>\n"
-
-#, c-format
-msgid "<b>Last Login Time</b>: %s\n"
-msgstr "<b>Letzte Anmeldezeit</b>: %s\n"
+#, fuzzy, c-format
+msgid "<b>IP</b>: %s<br>\n"
+msgstr "<b>Server</b>: %s<br>\n"
 
 msgid "Login Information"
 msgstr "Login-Informationen"
 
-msgid "Set My Information"
-msgstr "Meine Informationen festlegen"
+msgid "<p><b>Original Author</b>:<br>\n"
+msgstr ""
+
+msgid "<p><b>Code Contributors</b>:<br>\n"
+msgstr ""
+
+#, fuzzy
+msgid "<p><b>Lovely Patch Writers</b>:<br>\n"
+msgstr "<b>Letzte Aktualisierung</b>: %s<br>\n"
+
+#, fuzzy
+msgid "<p><b>Acknowledgement</b>:<br>\n"
+msgstr "<b>Gesendet</b>: %lu<br>\n"
+
+msgid "<p><i>And, all the boys in the backroom...</i><br>\n"
+msgstr ""
+
+msgid "<i>Feel free to join us!</i> :)"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "About OpenQ r%s"
+msgstr "Über %s"
+
+#, fuzzy
+msgid "Change Icon"
+msgstr "Icon speichern"
 
 msgid "Change Password"
 msgstr "Passwort ändern"
@@ -7516,11 +7604,12 @@
 msgid "Account Information"
 msgstr "Kontoinformationen"
 
-msgid "Leave the QQ Qun"
-msgstr "Diesen QQ-Qun verlassen"
-
-msgid "Block this buddy"
-msgstr "Diesen Buddy blockieren"
+msgid "Update all QQ Quns"
+msgstr ""
+
+#, fuzzy
+msgid "About OpenQ"
+msgstr "Über %s"
 
 #. *< type
 #. *< ui_requirement
@@ -7532,12 +7621,27 @@
 #. *< version
 #. *  summary
 #. *  description
-msgid "QQ Protocol\tPlugin"
+#, fuzzy
+msgid "QQ Protocol Plugin"
 msgstr "QQ-Protokoll-Plugin"
 
 msgid "Auto"
 msgstr "Auto"
 
+#, fuzzy
+msgid "Select Server"
+msgstr "Benutzer wählen"
+
+msgid "QQ2005"
+msgstr ""
+
+msgid "QQ2007"
+msgstr ""
+
+msgid "QQ2008"
+msgstr ""
+
+#. #endif
 msgid "Connect by TCP"
 msgstr "Über TCP verbinden"
 
@@ -7547,40 +7651,82 @@
 msgid "Show server news"
 msgstr "Server-News anzeigen"
 
-msgid "Keep alive interval(s)"
+#, fuzzy
+msgid "Keep alive interval (seconds)"
 msgstr "Intervall(e) zum Aufrechterhalten der Verbindung (Keep alive)"
 
-msgid "Update interval(s)"
+#, fuzzy
+msgid "Update interval (seconds)"
 msgstr "Aktualisierungsintervall(e)"
 
-#, c-format
-msgid "Invalid token reply code, 0x%02X"
-msgstr "Ungültiger Token-Antwort-Code, 0x%02X"
+#, fuzzy
+msgid "Can not decrypt server reply"
+msgstr "Kann die Antwort der Anmeldung nicht entschlüsseln"
+
+#, fuzzy
+msgid "Can not decrypt get server reply"
+msgstr "Kann die Antwort der Anmeldung nicht entschlüsseln"
+
+#, c-format
+msgid "Failed requesting token, 0x%02X"
+msgstr ""
 
 #, c-format
 msgid "Invalid token len, %d"
 msgstr "Ungültige Länge des Tokens, %d"
 
-msgid "Unable login for not support Redirect_EX now"
-msgstr "Anmeldung nicht möglich, Redirect_EX wird noch nicht unterstützt"
-
-#, c-format
-msgid "Error password: %s"
-msgstr "Passwort-Fehler: %s"
-
-#, c-format
-msgid "Need active: %s"
-msgstr "Brauche aktiv: %s"
-
-#, c-format
-msgid "Unable login for unknow reply code 0x%02X"
+#. extend redirect used in QQ2006
+msgid "Redirect_EX is not currently supported"
+msgstr ""
+
+#. need activation
+#. need activation
+#. need activation
+#, fuzzy
+msgid "Activation required"
+msgstr "Registrierung erforderlich"
+
+#, fuzzy, c-format
+msgid "Unknow reply code when login (0x%02X)"
 msgstr "Anmeldung nicht möglich, unbekannter Antwort-Code 0x%02X"
 
 msgid "Keep alive error"
 msgstr "Fehler beim Aufrechterhalten der Verbindung (Keep alive)"
 
-msgid "Failed to connect all servers"
-msgstr "Konnte nicht alle Server verbinden"
+#, fuzzy
+msgid "Requesting captcha ..."
+msgstr "Bitte um %ss Aufmerksamkeit..."
+
+msgid "Checking code of captcha ..."
+msgstr ""
+
+msgid "Failed captcha verify"
+msgstr ""
+
+#, fuzzy
+msgid "Captcha Image"
+msgstr "Bild speichern"
+
+#, fuzzy
+msgid "Enter code"
+msgstr "Geben Sie ein Passwort ein"
+
+msgid "QQ Captcha Verifing"
+msgstr ""
+
+#, fuzzy
+msgid "Enter the text from the image"
+msgstr "Bitte geben Sie den Namen der Gruppe ein"
+
+#, c-format
+msgid "Unknow reply code when checking password (0x%02X)"
+msgstr ""
+
+#, c-format
+msgid ""
+"Unknow reply code when login (0x%02X):\n"
+"%s"
+msgstr ""
 
 #. we didn't successfully connect. tdt->toc_fd is valid here
 msgid "Unable to connect."
@@ -7606,7 +7752,10 @@
 msgid "Connection lost"
 msgstr "Verbindung verloren"
 
-#. Update the login progress status display
+#, fuzzy
+msgid "Get server ..."
+msgstr "Benutzer-Info setzen..."
+
 msgid "Request token"
 msgstr "Anfragekürzel"
 
@@ -7616,13 +7765,34 @@
 msgid "Invalid server or port"
 msgstr "Ungültiger Server oder Port"
 
-#, c-format
-msgid "Connecting server %s, retries %d"
-msgstr "Verbinde zu Server %s, %d Wiederholungen"
+#, fuzzy
+msgid "Connecting server ..."
+msgstr "Verbindungsserver"
 
 msgid "QQ Error"
 msgstr "QQ-Fehler"
 
+msgid "Failed to send IM."
+msgstr "Senden der Nachricht fehlgeschlagen."
+
+#, fuzzy, c-format
+msgid ""
+"Server News:\n"
+"%s\n"
+"%s\n"
+"%s"
+msgstr "QQ-Server-News"
+
+#, c-format
+msgid "From %s:"
+msgstr "Von %s:"
+
+#, fuzzy, c-format
+msgid ""
+"Server notice From %s: \n"
+"%s"
+msgstr "Anleitung vom Server: %s"
+
 msgid "Unknow SERVER CMD"
 msgstr "Unbekanntes SERVER-CMD"
 
@@ -7637,16 +7807,21 @@
 msgid "QQ Qun Command"
 msgstr "QQ-Qun-Kommando"
 
-#, c-format
-msgid "You are not a member of QQ Qun \"%s\"\n"
+#, fuzzy, c-format
+msgid "Not a member of room \"%s\"\n"
 msgstr "Sie sind kein Mitglied des Qun „%s“\n"
 
 msgid "Can not decrypt login reply"
 msgstr "Kann die Antwort der Anmeldung nicht entschlüsseln"
 
-msgid "Unknow reply CMD"
+#, fuzzy
+msgid "Unknow LOGIN CMD"
 msgstr "Unbekanntes Antwort-CMD"
 
+#, fuzzy
+msgid "Unknow CLIENT CMD"
+msgstr "Unbekanntes SERVER-CMD"
+
 #, c-format
 msgid "%d has declined the file %s"
 msgstr "%d hat die Datei %s abgelehnt"
@@ -7658,58 +7833,6 @@
 msgid "%d canceled the transfer of %s"
 msgstr "%d hat die Übertragung von %s abgebrochen"
 
-msgid "Do you approve the requestion?"
-msgstr "Wollen sie die Anfrage akzeptieren?"
-
-msgid "Do you add the buddy?"
-msgstr "Möchten Sie diesen Buddy hinzufügen?"
-
-#. only need to get value
-#, c-format
-msgid "You have been added by %s"
-msgstr "Sie wurden von %s hinzugefügt"
-
-msgid "Would you like to add him?"
-msgstr "Möchten Sie ihn hinzufügen?"
-
-#, c-format
-msgid "%s added you [%s] to buddy list"
-msgstr "%s hat Sie [%s] zur Buddy-Liste hinzugefügt"
-
-msgid "QQ Budy"
-msgstr "QQ-Buddy"
-
-#, c-format
-msgid "Requestion rejected by %s"
-msgstr "Anfrage abgelehnt von %s"
-
-#, c-format
-msgid "Requestion approved by %s"
-msgstr "Anfrage akzeptiert von %s"
-
-#. TODO: this should go through purple_account_request_authorization()
-#, c-format
-msgid "%s wants to add you [%s] as a friend"
-msgstr "%s möchte Sie [%s] als Freund hinzufügen"
-
-#, c-format
-msgid "%s is not in buddy list"
-msgstr "%s ist nicht in der Buddy-Liste"
-
-msgid "Would you add?"
-msgstr "Möchten Sie ihn hinzufügen?"
-
-#, c-format
-msgid "From %s:"
-msgstr "Von %s:"
-
-#, c-format
-msgid "%s"
-msgstr "%s"
-
-msgid "QQ Server Notice"
-msgstr "QQ-Server-Nachricht"
-
 msgid "Connection closed (writing)"
 msgstr "Verbindung geschlossen (schreibend)"
 
@@ -9408,9 +9531,6 @@
 msgid "Yahoo! system message for %s:"
 msgstr "Yahoo!-Systemnachricht für %s:"
 
-msgid "Authorization denied message:"
-msgstr "Nachricht für die Ablehnung der Autorisierung:"
-
 #, c-format
 msgid ""
 "%s has (retroactively) denied your request to add them to your list for the "
@@ -10297,14 +10417,14 @@
 msgid "Protocol"
 msgstr "Protokoll"
 
-#, c-format
+#, fuzzy, c-format
 msgid ""
 "<span size='larger' weight='bold'>Welcome to %s!</span>\n"
 "\n"
 "You have no IM accounts configured. To start connecting with %s press the "
-"<b>Add</b> button below and configure your first account. If you want %s to "
-"connect to multiple IM accounts, press <b>Add</b> again to configure them "
-"all.\n"
+"<b>Add...</b> button below and configure your first account. If you want %s "
+"to connect to multiple IM accounts, press <b>Add...</b> again to configure "
+"them all.\n"
 "\n"
 "You can come back to this window to add, edit, or remove accounts from "
 "<b>Accounts->Manage Accounts</b> in the Buddy List window"
@@ -10745,7 +10865,8 @@
 msgid "Auto_join when account becomes online."
 msgstr "Automatisch _beitreten, wenn das Konto online geht."
 
-msgid "_Hide chat when the window is closed."
+#, fuzzy
+msgid "_Remain in chat after window is closed."
 msgstr "_Chat verstecken, wenn das Fenster geschlossen wird."
 
 msgid "Please enter the name of the group to be added."
@@ -12035,7 +12156,7 @@
 "                      nur das erste Konto aktiviert).\n"
 "  -v, --version       zeigt aktuelle Version und beendet das Programm\n"
 
-#, c-format
+#, fuzzy, c-format
 msgid ""
 "%s %s has segfaulted and attempted to dump a core file.\n"
 "This is a bug in the software and has happened through\n"
@@ -12049,11 +12170,6 @@
 "and post the backtrace from the core file.  If you do not know\n"
 "how to get the backtrace, please read the instructions at\n"
 "%swiki/GetABacktrace\n"
-"\n"
-"If you need further assistance, please IM either SeanEgn or \n"
-"LSchiere (via AIM).  Contact information for Sean and Luke \n"
-"on other protocols is at\n"
-"%swiki/DeveloperPages\n"
 msgstr ""
 "%s %s hat einen Speicherzugriffsfehler festgestellt und \n"
 "versucht, eine Core-Datei zu schreiben.  Dies ist ein \n"
@@ -12913,9 +13029,14 @@
 msgid "_Invite"
 msgstr "_Einladen"
 
-msgid "_Modify"
+#, fuzzy
+msgid "_Modify..."
 msgstr "_Bearbeiten"
 
+#, fuzzy
+msgid "_Add..."
+msgstr "_Hinzufügen"
+
 msgid "_Open Mail"
 msgstr "Mail ö_ffnen"
 
@@ -12937,6 +13058,13 @@
 msgid "none"
 msgstr "keine"
 
+#, fuzzy
+msgid "Small"
+msgstr "E-Mail"
+
+msgid "Smaller versions of the default smilies"
+msgstr ""
+
 msgid "Response Probability:"
 msgstr "Antwortwahrscheinlichkeit:"
 
@@ -13595,20 +13723,20 @@
 "Sie das Debug-Fenster."
 
 #, c-format
-msgid ""
-"You are using %s version %s.  The current version is %s.  You can get it "
-"from <a href=\"%s\">%s</a><hr>"
-msgstr ""
-"Sie verwenden gerade %s Version %s.  Die aktuelle Version ist %s.  Sie "
-"können Pidgin von <a href=\"%s\">%s</a> herunterladen.<hr>"
-
-#, c-format
-msgid "<b>ChangeLog:</b><br>%s"
-msgstr "<b>Änderungen:</b><br>%s"
+msgid "You can upgrade to %s %s today."
+msgstr ""
 
 msgid "New Version Available"
 msgstr "Neue Version verfügbar"
 
+#, fuzzy
+msgid "Later"
+msgstr "Datum"
+
+#, fuzzy
+msgid "Download Now"
+msgstr "Download %s: %s"
+
 #. *< type
 #. *< ui_requirement
 #. *< flags
@@ -13918,3 +14046,169 @@
 msgid "This plugin is useful for debbuging XMPP servers or clients."
 msgstr ""
 "Dieses Plugin ist nützlich zur Fehlersuche in XMPP-Servern oder -Clients."
+
+#~ msgid "Primary Information"
+#~ msgstr "Primäre Informationen"
+
+#~ msgid "Blood Type"
+#~ msgstr "Blutgruppe"
+
+#~ msgid "Update information"
+#~ msgstr "Informationen aktualisieren"
+
+#~ msgid "Successed:"
+#~ msgstr "Erfolgreich:"
+
+#~ msgid ""
+#~ "Setting custom faces is not currently supported. Please choose an image "
+#~ "from %s."
+#~ msgstr ""
+#~ "Das Setzen von benutzerdefinierten Gesichtern wird momentan nicht "
+#~ "unterstützt. Bitte wählen Sie ein Bild von %s."
+
+#~ msgid "Invalid QQ Face"
+#~ msgstr "Ungültiges QQ-Gesicht"
+
+# c-format
+#~ msgid "You rejected %d's request"
+#~ msgstr "Sie haben die Anfrage von %d abgelehnt"
+
+#~ msgid "Reject request"
+#~ msgstr "Anfrage ablehnen"
+
+#~ msgid "Add buddy with auth request failed"
+#~ msgstr "Benutzer hinzufügen, wenn Autorisierungsanfrage fehlschlug"
+
+#~ msgid "Add into %d's buddy list"
+#~ msgstr "Zu %ds Buddy-Liste hinzufügen"
+
+#~ msgid "QQ Number Error"
+#~ msgstr "Fehler in QQ-Nummer"
+
+#~ msgid "Group Description"
+#~ msgstr "Gruppenbeschreibung"
+
+#~ msgid "Auth"
+#~ msgstr "Autorisieren"
+
+#~ msgid "Approve"
+#~ msgstr "Akzeptieren"
+
+#~ msgid "Successed to join Qun %d, operated by admin %d"
+#~ msgstr "Erfolgreicher Beitritt in den Qun %d, moderiert vom Admin %d"
+
+#~ msgid "[%d] removed from Qun \"%d\""
+#~ msgstr "[%d] vom Qun „%d“ entfernt"
+
+#~ msgid "[%d] added to Qun \"%d\""
+#~ msgstr "[%d] zum Qun „%d“ hinzugefügt"
+
+#~ msgid "I am a member"
+#~ msgstr "Ich bin Mitglied"
+
+#~ msgid "I am requesting"
+#~ msgstr "Ich frage an"
+
+#~ msgid "I am the admin"
+#~ msgstr "Ich bin der Admin"
+
+#~ msgid "Unknown status"
+#~ msgstr "Unbekannter Status"
+
+#~ msgid "Remove from Qun"
+#~ msgstr "vom Qun entfernen"
+
+#~ msgid "You entered a group ID outside the acceptable range"
+#~ msgstr ""
+#~ "Sie haben eine Gruppen-ID außerhalb des erlaubten Bereichs angegeben"
+
+#~ msgid "Are you sure you want to leave this Qun?"
+#~ msgstr "Wollen Sie dieses Qun wirklich verlassen?"
+
+#~ msgid "Do you want to approve the request?"
+#~ msgstr "Wollen sie die Anfrage akzeptieren?"
+
+#~ msgid ""
+#~ "%s\n"
+#~ "\n"
+#~ "%s"
+#~ msgstr ""
+#~ "%s\n"
+#~ "\n"
+#~ "%s"
+
+#~ msgid "System Message"
+#~ msgstr "Systemnachricht"
+
+#~ msgid "<b>Last Login IP</b>: %s<br>\n"
+#~ msgstr "<b>Letzte Anmelde-IP</b>: %s<br>\n"
+
+#~ msgid "<b>Last Login Time</b>: %s\n"
+#~ msgstr "<b>Letzte Anmeldezeit</b>: %s\n"
+
+#~ msgid "Set My Information"
+#~ msgstr "Meine Informationen festlegen"
+
+#~ msgid "Leave the QQ Qun"
+#~ msgstr "Diesen QQ-Qun verlassen"
+
+#~ msgid "Block this buddy"
+#~ msgstr "Diesen Buddy blockieren"
+
+#~ msgid "Invalid token reply code, 0x%02X"
+#~ msgstr "Ungültiger Token-Antwort-Code, 0x%02X"
+
+#~ msgid "Unable login for not support Redirect_EX now"
+#~ msgstr "Anmeldung nicht möglich, Redirect_EX wird noch nicht unterstützt"
+
+#~ msgid "Error password: %s"
+#~ msgstr "Passwort-Fehler: %s"
+
+#~ msgid "Need active: %s"
+#~ msgstr "Brauche aktiv: %s"
+
+#~ msgid "Failed to connect all servers"
+#~ msgstr "Konnte nicht alle Server verbinden"
+
+#~ msgid "Connecting server %s, retries %d"
+#~ msgstr "Verbinde zu Server %s, %d Wiederholungen"
+
+#~ msgid "Do you approve the requestion?"
+#~ msgstr "Wollen sie die Anfrage akzeptieren?"
+
+#~ msgid "Do you add the buddy?"
+#~ msgstr "Möchten Sie diesen Buddy hinzufügen?"
+
+#~ msgid "%s added you [%s] to buddy list"
+#~ msgstr "%s hat Sie [%s] zur Buddy-Liste hinzugefügt"
+
+#~ msgid "QQ Budy"
+#~ msgstr "QQ-Buddy"
+
+#~ msgid "Requestion approved by %s"
+#~ msgstr "Anfrage akzeptiert von %s"
+
+#~ msgid "%s wants to add you [%s] as a friend"
+#~ msgstr "%s möchte Sie [%s] als Freund hinzufügen"
+
+#~ msgid "%s is not in buddy list"
+#~ msgstr "%s ist nicht in der Buddy-Liste"
+
+#~ msgid "Would you add?"
+#~ msgstr "Möchten Sie ihn hinzufügen?"
+
+#~ msgid "%s"
+#~ msgstr "%s"
+
+#~ msgid "QQ Server Notice"
+#~ msgstr "QQ-Server-Nachricht"
+
+#~ msgid ""
+#~ "You are using %s version %s.  The current version is %s.  You can get it "
+#~ "from <a href=\"%s\">%s</a><hr>"
+#~ msgstr ""
+#~ "Sie verwenden gerade %s Version %s.  Die aktuelle Version ist %s.  Sie "
+#~ "können Pidgin von <a href=\"%s\">%s</a> herunterladen.<hr>"
+
+#~ msgid "<b>ChangeLog:</b><br>%s"
+#~ msgstr "<b>Änderungen:</b><br>%s"
--- a/po/hu.po	Sun Nov 23 18:30:31 2008 +0000
+++ b/po/hu.po	Thu Nov 27 21:15:43 2008 +0000
@@ -9,8 +9,8 @@
 msgstr ""
 "Project-Id-Version: pidgin 2.5\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-10-16 00:55-0700\n"
-"PO-Revision-Date: 2008-10-02 18:55+0200\n"
+"POT-Creation-Date: 2008-11-23 21:15+0100\n"
+"PO-Revision-Date: 2008-11-23 21:16+0100\n"
 "Last-Translator: Gabor Kelemen <kelemeng@gnome.hu>\n"
 "Language-Team: Hungarian <gnome@fsf.hu>\n"
 "MIME-Version: 1.0\n"
@@ -73,7 +73,6 @@
 msgid "Remember password"
 msgstr "Emlékezzen a jelszóra"
 
-#, fuzzy
 msgid "There are no protocol plugins installed."
 msgstr "Nincsenek protokollbővítmények telepítve."
 
@@ -146,8 +145,7 @@
 
 #, c-format
 msgid "%s%s%s%s wants to add %s to his or her buddy list%s%s"
-msgstr ""
-"%s%s%s%s felhasználó szeretné %s partnert felvenni a partnerlistájára%s%s"
+msgstr "%s%s%s%s felhasználó szeretné %s partnert felvenni a partnerlistájára%s%s"
 
 msgid "Authorize buddy?"
 msgstr "Engedélyezi a partnert?"
@@ -242,9 +240,6 @@
 msgid "You must give a name for the group to add."
 msgstr "Meg kell adnia a felvenni kívánt csoport nevét."
 
-msgid "A group with the name already exists."
-msgstr "Ilyen nevű csoport már létezik."
-
 msgid "Add Group"
 msgstr "Csoport felvétele"
 
@@ -275,15 +270,14 @@
 msgid "Add Buddy Pounce"
 msgstr "Partnerfigyelmeztetés felvétele"
 
-#. if (q_bud && is_online(q_bud->status)) {
 msgid "Send File"
 msgstr "Fájl küldése"
 
 msgid "Blocked"
 msgstr "Tiltott"
 
-msgid "View Log"
-msgstr "Napló megtekintése"
+msgid "Show when offline"
+msgstr "Megjelenítés, ha elérhető"
 
 #, c-format
 msgid "Please enter the new name for %s"
@@ -302,8 +296,7 @@
 msgstr "A kapcsolat eltávolítása a kapcsolat partnereit is eltávolítja"
 
 msgid "Removing this group will also remove all the buddies in the group"
-msgstr ""
-"A csoport eltávolítása a csoportban található partnereket is eltávolítja"
+msgstr "A csoport eltávolítása a csoportban található partnereket is eltávolítja"
 
 #, c-format
 msgid "Are you sure you want to remove %s?"
@@ -326,6 +319,9 @@
 msgid "Toggle Tag"
 msgstr "Címke átváltása"
 
+msgid "View Log"
+msgstr "Napló megtekintése"
+
 #. General
 msgid "Nickname"
 msgstr "Becenév"
@@ -373,8 +369,7 @@
 msgstr "Új azonnali üzenet"
 
 msgid "Please enter the username or alias of the person you would like to IM."
-msgstr ""
-"Adja meg azon személy felhasználónevét vagy álnevét, akinek üzenni szeretne."
+msgstr "Adja meg azon személy felhasználónevét vagy álnevét, akinek üzenni szeretne."
 
 msgid "Channel"
 msgstr "Csatorna"
@@ -600,13 +595,10 @@
 msgstr "Elhagyta ezt a csevegést."
 
 msgid "Logging started. Future messages in this conversation will be logged."
-msgstr ""
-"A naplózás elkezdődött. A társalgás jövőbeli üzenetei naplózva lesznek."
-
-msgid ""
-"Logging stopped. Future messages in this conversation will not be logged."
-msgstr ""
-"A naplózás befejeződött. A társalgás jövőbeli üzenetei nem lesznek naplózva."
+msgstr "A naplózás elkezdődött. A társalgás jövőbeli üzenetei naplózva lesznek."
+
+msgid "Logging stopped. Future messages in this conversation will not be logged."
+msgstr "A naplózás befejeződött. A társalgás jövőbeli üzenetei nem lesznek naplózva."
 
 msgid "Send To"
 msgstr "Küldés ennek"
@@ -678,8 +670,7 @@
 
 #, c-format
 msgid "%s is not a valid color. See '/help msgcolor' for valid colors."
-msgstr ""
-"%s nem érvényes szín. Az érvényes színekért lásd a „help msgcolor” kimenetét."
+msgstr "%s nem érvényes szín. Az érvényes színekért lásd a „help msgcolor” kimenetét."
 
 msgid ""
 "say &lt;message&gt;:  Send a message normally as if you weren't using a "
@@ -852,8 +843,7 @@
 "Az azonnali üzenetek csak akkor lesznek naplózva, ha az „Összes azonnali "
 "üzenet naplózása” tulajdonság be van állítva."
 
-msgid ""
-"Chats will only be logged if the \"Log all chats\" preference is enabled."
+msgid "Chats will only be logged if the \"Log all chats\" preference is enabled."
 msgstr ""
 "A csevegések csak akkor lesznek naplózva, ha az „Összes csevegés naplózása” "
 "tulajdonság be van állítva."
@@ -959,8 +949,7 @@
 msgid "The selected file is not a valid plugin."
 msgstr "A kiválasztott fájl nem egy érvényes bővítmény."
 
-msgid ""
-"Please open the debug window and try again to see the exact error message."
+msgid "Please open the debug window and try again to see the exact error message."
 msgstr ""
 "Nyissa meg a hibakereső ablakot és próbálkozzon újra a pontos hibaüzenet "
 "megjelenítéséhez."
@@ -1332,7 +1321,7 @@
 #. PurpleStatusPrimitive
 #. id - use default
 #. name - use default
-#. savable
+#. saveable
 #. user_settable
 #. not independent
 #. Attributes - each status can have a message.
@@ -1393,8 +1382,7 @@
 msgstr "Az ablak nem található"
 
 msgid "This plugin cannot be loaded because it was not built with X11 support."
-msgstr ""
-"A bővítmény nem tölthető be, mivel X11 támogatás nélkül került lefordításra."
+msgstr "A bővítmény nem tölthető be, mivel X11 támogatás nélkül került lefordításra."
 
 msgid "GntClipboard"
 msgstr "GntClipboard"
@@ -1675,8 +1663,7 @@
 "ellenőrizhető."
 
 #. vrq will be completed by user_auth
-msgid ""
-"The root certificate this one claims to be issued by is unknown to Pidgin."
+msgid "The root certificate this one claims to be issued by is unknown to Pidgin."
 msgstr "A tanúsítványt kiadó gyökértanúsítványt a Pidgin nem ismeri."
 
 #, c-format
@@ -2087,8 +2074,7 @@
 msgstr "A megadott parancs kezelje-e az „ymsgr” URL címeket"
 
 msgid "<b><font color=\"red\">The logger has no read function</font></b>"
-msgstr ""
-"<b><font color=\"red\">A naplózónak nincsen olvasás funkciója</font></b>"
+msgstr "<b><font color=\"red\">A naplózónak nincsen olvasás funkciója</font></b>"
 
 msgid "HTML"
 msgstr "HTML"
@@ -2148,8 +2134,7 @@
 msgid "ABI version mismatch %d.%d.x (need %d.%d.x)"
 msgstr "Az ABI verziója nem egyezik: %d.%d.x (szükséges: %d.%d.x)"
 
-msgid ""
-"Plugin does not implement all required functions (list_icon, login and close)"
+msgid "Plugin does not implement all required functions (list_icon, login and close)"
 msgstr ""
 "A bővítmény nem valósítja meg az összes kívánt függvényt (list_icon, login "
 "és close)"
@@ -2158,8 +2143,7 @@
 msgid ""
 "The required plugin %s was not found. Please install this plugin and try "
 "again."
-msgstr ""
-"A szükséges %s bővítmény nem található. Kérem telepítse, majd próbálja újra."
+msgstr "A szükséges %s bővítmény nem található. Kérem telepítse, majd próbálja újra."
 
 msgid "Unable to load the plugin"
 msgstr "A bővítmény nem tölthető be"
@@ -2224,8 +2208,7 @@
 "(Teljes elérési utat adjon meg)"
 
 msgid "Automatically reject from users not in buddy list"
-msgstr ""
-"Automatikus visszautasítás a partnerlistán nem szereplő felhasználóktól"
+msgstr "Automatikus visszautasítás a partnerlistán nem szereplő felhasználóktól"
 
 msgid ""
 "Notify with a popup when an autoaccepted file transfer is complete\n"
@@ -2454,8 +2437,7 @@
 msgid ""
 "You are currently disconnected. Messages will not be received unless you are "
 "logged in."
-msgstr ""
-"Jelenleg nincs csatlakozva. Nem fogadhat üzeneteket, amíg nem jelentkezik be."
+msgstr "Jelenleg nincs csatlakozva. Nem fogadhat üzeneteket, amíg nem jelentkezik be."
 
 msgid "Message could not be sent because the maximum length was exceeded."
 msgstr "Az üzenet nem küldhető el, mivel a maximális hossz el lett érve."
@@ -2829,10 +2811,8 @@
 msgid "Unable to listen for incoming IM connections\n"
 msgstr "Nem lehetséges a bejövő azonnali üzenő kapcsolatokat figyelni\n"
 
-msgid ""
-"Unable to establish connection with the local mDNS server.  Is it running?"
-msgstr ""
-"Nem hozható létre kapcsolat a helyi mDNS kiszolgálóval. Egyáltalán fut?"
+msgid "Unable to establish connection with the local mDNS server.  Is it running?"
+msgstr "Nem hozható létre kapcsolat a helyi mDNS kiszolgálóval. Egyáltalán fut?"
 
 #. Creating the options for the protocol
 msgid "First name"
@@ -3499,8 +3479,7 @@
 msgstr "nickserv: parancs küldése a nickserv kiszolgálónak"
 
 msgid "notice &lt;target&lt;:  Send a notice to a user or channel."
-msgstr ""
-"notice &lt;cél&lt;:  Értesítés küldése egy felhasználónak vagy csatornának."
+msgstr "notice &lt;cél&lt;:  Értesítés küldése egy felhasználónak vagy csatornának."
 
 msgid ""
 "op &lt;nick1&gt; [nick2] ...:  Grant channel operator status to someone. You "
@@ -3584,8 +3563,7 @@
 "tudja."
 
 msgid "whois [server] &lt;nick&gt;:  Get information on a user."
-msgstr ""
-"whois [kiszolgáló] &lt;becenév&gt;:  Információk lekérése egy felhasználóról."
+msgstr "whois [kiszolgáló] &lt;becenév&gt;:  Információk lekérése egy felhasználóról."
 
 msgid "whowas &lt;nick&gt;: Get information on a user that has logged off."
 msgstr ""
@@ -3623,8 +3601,7 @@
 msgstr "Titkosítást kér, de a TLS/SSL támogatása nem található."
 
 msgid "Server requires plaintext authentication over an unencrypted stream"
-msgstr ""
-"A kiszolgáló szöveges hitelesítést követel meg egy nem titkosított csatornán"
+msgstr "A kiszolgáló szöveges hitelesítést követel meg egy nem titkosított csatornán"
 
 #, c-format
 msgid ""
@@ -3957,8 +3934,7 @@
 msgstr "Kiszolgálóutasítások: %s"
 
 msgid "Fill in one or more fields to search for any matching XMPP users."
-msgstr ""
-"Töltsön ki legalább egy mezőt a megfelelő XMPP felhasználók kereséséhez."
+msgstr "Töltsön ki legalább egy mezőt a megfelelő XMPP felhasználók kereséséhez."
 
 msgid "Email Address"
 msgstr "E-mail cím"
@@ -4116,8 +4092,7 @@
 msgid "Unregister"
 msgstr "Regisztráció megszüntetése"
 
-msgid ""
-"Please fill out the information below to change your account registration."
+msgid "Please fill out the information below to change your account registration."
 msgstr "Adja meg a következő információkat a regisztrált fiók módosításához."
 
 msgid "Please fill out the information below to register your new account."
@@ -4491,8 +4466,7 @@
 msgid "kick &lt;user&gt; [reason]:  Kick a user from the room."
 msgstr "kick &lt;felhasználó&gt; [ok]:  Felhasználó kirúgása a szobából."
 
-msgid ""
-"msg &lt;user&gt; &lt;message&gt;:  Send a private message to another user."
+msgid "msg &lt;user&gt; &lt;message&gt;:  Send a private message to another user."
 msgstr ""
 "msg &lt;felhasználó&gt; &lt;üzenet&gt;:  Magánüzenet küldése másik "
 "felhasználónak."
@@ -4543,7 +4517,6 @@
 
 #. this should probably be part of global smiley theme settings later on,
 #. shared with MSN
-#, fuzzy
 msgid "Show Custom Smileys"
 msgstr "Egyéni hangulatjelek megjelenítése"
 
@@ -4915,13 +4888,11 @@
 msgid "MSN Error: %s\n"
 msgstr "MSN hiba: %s\n"
 
-#, fuzzy
 msgid "Other Contacts"
-msgstr "Előnyben részesített kapcsolat"
-
-#, fuzzy
+msgstr "Egyéb partnerek"
+
 msgid "Non-IM Contacts"
-msgstr "Kapcsolat eltávolítása"
+msgstr "Nem azonnali üzenetváltási partnerek"
 
 msgid "Nudge"
 msgstr "Bökés"
@@ -4979,8 +4950,7 @@
 msgstr "Nincs tiltott szöveg ehhez a fiókhoz."
 
 #, c-format
-msgid ""
-"MSN servers are currently blocking the following regular expressions:<br/>%s"
+msgid "MSN servers are currently blocking the following regular expressions:<br/>%s"
 msgstr ""
 "Az MSN kiszolgálók jelenleg a következő reguláris kifejezéseket tiltják:<br/>"
 "%s"
@@ -5021,7 +4991,7 @@
 #. primitive
 #. ID
 #. name - use default
-#. savable
+#. saveable
 #. should be user_settable some day
 #. independent
 msgid "Artist"
@@ -5234,8 +5204,7 @@
 #. *< id
 #. *< name
 #. *< version
-#. *  summary
-#. *  description
+#. *< summary
 msgid "Windows Live Messenger Protocol Plugin"
 msgstr "Windows Live Messenger protokollbővítmény"
 
@@ -5272,6 +5241,7 @@
 msgid "%s just sent you a Nudge!"
 msgstr "%s megbökte!"
 
+#. char *adl = g_strndup(payload, len);
 #, c-format
 msgid "Unknown error (%d)"
 msgstr "Ismeretlen hiba (%d)"
@@ -5279,9 +5249,8 @@
 msgid "Unable to add user"
 msgstr "Nem vehető fel a felhasználó"
 
-#, fuzzy
 msgid "The following users are missing from your addressbook"
-msgstr "A keresés eredményei a következők"
+msgstr "A következő felhasználók hiányoznak a címjegyzékéből"
 
 #, c-format
 msgid "Unable to add user on %s (%s)"
@@ -5397,8 +5366,7 @@
 msgid "Unable to authenticate: %s"
 msgstr "Nem sikerült a hitelesítés: %s"
 
-msgid ""
-"Your MSN buddy list is temporarily unavailable. Please wait and try again."
+msgid "Your MSN buddy list is temporarily unavailable. Please wait and try again."
 msgstr ""
 "Az Ön MSN partnerlistája átmenetileg nem érhető el. Kérem várjon és próbálja "
 "újra később."
@@ -5431,8 +5399,7 @@
 msgstr "Ebédelni mentem"
 
 msgid "Message may have not been sent because a timeout occurred:"
-msgstr ""
-"Időtúllépés következett be, emiatt az üzenet lehet, hogy nem lett elküldve:"
+msgstr "Időtúllépés következett be, emiatt az üzenet lehet, hogy nem lett elküldve:"
 
 msgid "Message could not be sent, not allowed while invisible:"
 msgstr "Az üzenet nem küldhető el, láthatatlan módban nem engedélyezett:"
@@ -5454,8 +5421,7 @@
 "kiszolgálóval. Ez valószínűleg kiszolgálóhiba, pár perc múlva próbálkozzon "
 "újra:"
 
-msgid ""
-"Message could not be sent because an error with the switchboard occurred:"
+msgid "Message could not be sent because an error with the switchboard occurred:"
 msgstr "Az üzenet nem küldhető el, mivel hiba lépett fel a közvetítés közben:"
 
 msgid "Message may have not been sent because an unknown error occurred:"
@@ -5469,13 +5435,11 @@
 msgid "%s has removed you from his or her buddy list."
 msgstr "%s eltávolította Önt a partnerlistájáról."
 
-#, fuzzy
 msgid "Delete Buddy from Address Book?"
-msgstr "Hozzáadás a címjegyzékhez"
-
-#, fuzzy
+msgstr "Törli a partnert a címjegyzékből?"
+
 msgid "Do you want to delete this buddy from your address book as well?"
-msgstr "Fel kívánja venni ezt a partnert a listájára?"
+msgstr "Törölni kívánja a partnert a címjegyzékéből is?"
 
 #. only notify the user about problems adding to the friends list
 #. * maybe we should do something else for other lists, but it probably
@@ -5953,8 +5917,7 @@
 msgid ""
 "This evaluation version does not allow more than ten users to log in at one "
 "time"
-msgstr ""
-"Ez a próbaverzió nem engedélyezi tíznél több felhasználó egyidejű belépését"
+msgstr "Ez a próbaverzió nem engedélyezi tíznél több felhasználó egyidejű belépését"
 
 msgid "The user is either offline or you are blocked"
 msgstr "A felhasználó kilépett, vagy Ön le van tiltva"
@@ -5994,8 +5957,7 @@
 
 #, c-format
 msgid "Unable to send message. Could not create the conference (%s)."
-msgstr ""
-"Az üzenetet nem lehet elküldeni. Nem sikerült létrehozni a konferenciát (%s)."
+msgstr "Az üzenetet nem lehet elküldeni. Nem sikerült létrehozni a konferenciát (%s)."
 
 #, c-format
 msgid ""
@@ -6035,8 +5997,7 @@
 
 #, c-format
 msgid "Unable to change server side privacy settings (%s)."
-msgstr ""
-"Nem lehet megváltoztatni a kiszolgálóoldali magánszféra-beállításokat (%s)."
+msgstr "Nem lehet megváltoztatni a kiszolgálóoldali magánszféra-beállításokat (%s)."
 
 #, c-format
 msgid "Unable to create conference (%s)."
@@ -6100,12 +6061,10 @@
 msgstr "Szeretne csatlakozni a társalgáshoz?"
 
 msgid "You have been logged out because you logged in at another workstation."
-msgstr ""
-"Ki lett jelentkeztetve, mivel bejelentkezett egy másik munkaállomásról."
-
-#, c-format
-msgid ""
-"%s appears to be offline and did not receive the message that you just sent."
+msgstr "Ki lett jelentkeztetve, mivel bejelentkezett egy másik munkaállomásról."
+
+#, c-format
+msgid "%s appears to be offline and did not receive the message that you just sent."
 msgstr "Úgy tűnik, %s kilépett, és nem kapta meg az utoljára küldött üzenetet."
 
 msgid ""
@@ -6449,6 +6408,7 @@
 "tartalmazhatnak."
 
 #. Unregistered screen name
+#. uid is not exist
 msgid "Invalid username."
 msgstr "Érvénytelen felhasználónév."
 
@@ -6556,8 +6516,7 @@
 #. Someone has granted you authorization
 #, c-format
 msgid "The user %u has granted your request to add them to your buddy list."
-msgstr ""
-"%u felhasználó elfogadta a kérését, így felveheti őt a partnerlistájára."
+msgstr "%u felhasználó elfogadta a kérését, így felveheti őt a partnerlistájára."
 
 #, c-format
 msgid ""
@@ -6611,27 +6570,21 @@
 #, c-format
 msgid "You missed %hu message from %s because it was invalid."
 msgid_plural "You missed %hu messages from %s because they were invalid."
-msgstr[0] ""
-"Nem kapott meg %hu üzenetet a következőtől: %s, mert az érvénytelen volt."
-msgstr[1] ""
-"Nem kapott meg %hu üzenetet a következőtől: %s, mert az érvénytelen volt."
+msgstr[0] "Nem kapott meg %hu üzenetet a következőtől: %s, mert az érvénytelen volt."
+msgstr[1] "Nem kapott meg %hu üzenetet a következőtől: %s, mert az érvénytelen volt."
 
 #, c-format
 msgid "You missed %hu message from %s because it was too large."
 msgid_plural "You missed %hu messages from %s because they were too large."
-msgstr[0] ""
-"Nem kapott meg %hu üzenetet a következőtől: %s, mert az túl nagy volt."
-msgstr[1] ""
-"Nem kapott meg %hu üzenetet a következőtől: %s, mert az túl nagy volt."
+msgstr[0] "Nem kapott meg %hu üzenetet a következőtől: %s, mert az túl nagy volt."
+msgstr[1] "Nem kapott meg %hu üzenetet a következőtől: %s, mert az túl nagy volt."
 
 # #: ../src/protocols/oscar/oscar.c:1605
 # #, c-format
 # msgid "You missed %d message from %s because the rate limit has been exceeded."
 #, c-format
-msgid ""
-"You missed %hu message from %s because the rate limit has been exceeded."
-msgid_plural ""
-"You missed %hu messages from %s because the rate limit has been exceeded."
+msgid "You missed %hu message from %s because the rate limit has been exceeded."
+msgid_plural "You missed %hu messages from %s because the rate limit has been exceeded."
 msgstr[0] ""
 "Nem kapott meg %hu üzenetet a következőtől: %s, mert túllépte a küldés "
 "gyakoriságának a korlátját."
@@ -6640,10 +6593,8 @@
 "gyakoriságának a korlátját."
 
 #, c-format
-msgid ""
-"You missed %hu message from %s because his/her warning level is too high."
-msgid_plural ""
-"You missed %hu messages from %s because his/her warning level is too high."
+msgid "You missed %hu message from %s because his/her warning level is too high."
+msgid_plural "You missed %hu messages from %s because his/her warning level is too high."
 msgstr[0] ""
 "Nem kapott meg %hu üzenetet a következőtől: %s, mert a feladó "
 "figyelmeztetési szintje túl magas volt."
@@ -6653,8 +6604,7 @@
 
 #, c-format
 msgid "You missed %hu message from %s because your warning level is too high."
-msgid_plural ""
-"You missed %hu messages from %s because your warning level is too high."
+msgid_plural "You missed %hu messages from %s because your warning level is too high."
 msgstr[0] ""
 "Nem kapott meg %hu üzenetet a következőtől: %s, mert az Ön figyelmeztetési "
 "szintje túl magas."
@@ -6818,8 +6768,7 @@
 msgid "Account Info"
 msgstr "Fiókinformációk"
 
-msgid ""
-"Your IM Image was not sent. You must be Direct Connected to send IM Images."
+msgid "Your IM Image was not sent. You must be Direct Connected to send IM Images."
 msgstr ""
 "Az Ön IM képe nem lett elküldve. IM képek küldéséhez közvetlen kapcsolatban "
 "kell lennie."
@@ -6843,10 +6792,8 @@
 msgid_plural ""
 "The maximum profile length of %d bytes has been exceeded.  It has been "
 "truncated for you."
-msgstr[0] ""
-"A profil mérete túllépte a maximális %d bájtot. Ez csonkításra került."
-msgstr[1] ""
-"A profil mérete túllépte a maximális %d bájtot. Ez csonkításra került."
+msgstr[0] "A profil mérete túllépte a maximális %d bájtot. Ez csonkításra került."
+msgstr[1] "A profil mérete túllépte a maximális %d bájtot. Ez csonkításra került."
 
 msgid "Profile too long."
 msgstr "A profil túl hosszú."
@@ -6879,10 +6826,10 @@
 "kezdődniük, és betűket, számokat és szóközöket, vagy csak számokból "
 "állhatnak."
 
-msgid "Unable To Add"
+msgid "Unable to Add"
 msgstr "Nem sikerült felvenni"
 
-msgid "Unable To Retrieve Buddy List"
+msgid "Unable to Retrieve Buddy List"
 msgstr "Nem lehet lekérni a partnerek listáját"
 
 msgid ""
@@ -6948,8 +6895,7 @@
 msgstr "_Váltás:"
 
 msgid "Your IM Image was not sent. You cannot send IM Images in AIM chats."
-msgstr ""
-"Az Ön IM képe nem lett elküldve. Nem küldhet IM képeket AIM csevegésekbe."
+msgstr "Az Ön IM képe nem lett elküldve. Nem küldhet IM képeket AIM csevegésekbe."
 
 msgid "iTunes Music Store Link"
 msgstr "iTunes zenebolt hivatkozás"
@@ -7081,8 +7027,7 @@
 
 #, c-format
 msgid "Asking %s to connect to us at %s:%hu for Direct IM."
-msgstr ""
-"%s felkérése, hogy kapcsolódjon hozzánk ezen: %s:%hu közvetlen kapcsolattal."
+msgstr "%s felkérése, hogy kapcsolódjon hozzánk ezen: %s:%hu közvetlen kapcsolattal."
 
 #, c-format
 msgid "Attempting to connect to %s:%hu."
@@ -7105,42 +7050,6 @@
 "képekhez. Ezzel láthatóvá válik az IP címe, ami veszélyeztetheti a "
 "magánszférája biztonságát."
 
-msgid "Primary Information"
-msgstr "Elsődleges információk"
-
-msgid "Personal Introduction"
-msgstr "Személyes bemutatkozás"
-
-msgid "QQ Number"
-msgstr "QQ szám"
-
-msgid "Country/Region"
-msgstr "Ország/terület"
-
-msgid "Province/State"
-msgstr "Megye/állam"
-
-msgid "Horoscope Symbol"
-msgstr "Horoszkóp szimbólum"
-
-msgid "Zodiac Sign"
-msgstr "Zodiákus jel"
-
-msgid "Blood Type"
-msgstr "Vércsoport"
-
-msgid "College"
-msgstr "Főiskola"
-
-msgid "Zipcode"
-msgstr "Irányítószám"
-
-msgid "Cellphone Number"
-msgstr "Mobil telefonszám"
-
-msgid "Phone Number"
-msgstr "Telefonszám"
-
 msgid "Aquarius"
 msgstr "Vízöntő"
 
@@ -7216,186 +7125,228 @@
 msgid "Other"
 msgstr "Egyéb"
 
-#, fuzzy
-msgid "Modify information"
+msgid "Visible"
+msgstr "Látható"
+
+msgid "Firend Only"
+msgstr "Csak barát"
+
+msgid "Private"
+msgstr "Magánjellegű"
+
+msgid "QQ Number"
+msgstr "QQ szám"
+
+msgid "Country/Region"
+msgstr "Ország/terület"
+
+msgid "Province/State"
+msgstr "Megye/állam"
+
+msgid "Zipcode"
+msgstr "Irányítószám"
+
+msgid "Phone Number"
+msgstr "Telefonszám"
+
+msgid "Authorize adding"
+msgstr "Felvétel engedélyezése"
+
+msgid "Cellphone Number"
+msgstr "Mobil telefonszám"
+
+msgid "Personal Introduction"
+msgstr "Személyes bemutatkozás"
+
+msgid "City/Area"
+msgstr "Város/terület"
+
+msgid "Publish Mobile"
+msgstr "Mobil közzététele"
+
+msgid "Publish Contact"
+msgstr "Kapcsolat közzététele"
+
+msgid "College"
+msgstr "Főiskola"
+
+msgid "Horoscope"
+msgstr "Horoszkóp"
+
+msgid "Zodiac"
+msgstr "Zodiákus"
+
+msgid "Blood"
+msgstr "Vércsoport"
+
+msgid "True"
+msgstr "Igaz"
+
+msgid "False"
+msgstr "Hamis"
+
+msgid "Modify Contact"
+msgstr "Partner módosítása"
+
+msgid "Modify Address"
+msgstr "Cím módosítása"
+
+msgid "Modify Extended Information"
+msgstr "Bővített információk módosítása"
+
+msgid "Modify Information"
 msgstr "Információk módosítása"
 
-#, fuzzy
-msgid "Update information"
-msgstr "Információk frissítése"
-
-#. TODO: We don't really need to notify the user about this, do we?
-#. TODO: Does the user really need to be notified about this?
-msgid "QQ Buddy"
-msgstr "QQ partner"
-
-msgid "Successed:"
-msgstr "Sikeres:"
-
-msgid "Change buddy information."
-msgstr "Partnerinformációk módosítása."
-
-#, c-format
-msgid ""
-"Setting custom faces is not currently supported. Please choose an image from "
-"%s."
-msgstr ""
-"Az egyéni arcképek beállítása jelenleg nem támogatott. Válasszon egy képet "
-"innen: %s."
-
-msgid "Invalid QQ Face"
-msgstr "Érvénytelen QQ arckép"
-
-#, c-format
-msgid "You rejected %d's request"
-msgstr "Visszautasította %d kérését"
-
-msgid "Reject request"
-msgstr "Kérés visszautasítása"
-
-#. title
-#, fuzzy
-msgid "Sorry, you are not my style..."
+msgid "Update"
+msgstr "Frissítés"
+
+msgid "Could not change buddy information."
+msgstr "A partnerinformációk nem módosíthatók."
+
+#, c-format
+msgid "%d needs Q&A"
+msgstr "%d Q&A-t igényel"
+
+msgid "Add buddy Q&A"
+msgstr "Partner Q&A hozzáadása"
+
+msgid "Input answer here"
+msgstr "Írja be ide a válaszát"
+
+msgid "Send"
+msgstr "Küldés"
+
+msgid "Invalid answer."
+msgstr "Érvénytelen válasz."
+
+msgid "Authorization denied message:"
+msgstr "Hozzáférés elutasítva üzenet:"
+
+msgid "Sorry, You are not my style."
 msgstr "Bocs, nem vagy az esetem…"
 
-msgid "Add buddy with auth request failed"
-msgstr "A partner felvétele felhatalmazási kéréssel meghiúsult"
-
-msgid "Failed:"
-msgstr "Sikertelen:"
-
-msgid "Remove buddy"
-msgstr "Partner törlése"
-
-msgid "Remove from other's buddy list"
-msgstr "Eltávolítás mások partnerlistájáról"
-
-#, fuzzy, c-format
+#, c-format
 msgid "%d needs authentication"
 msgstr "A(z) %d felhasználó felhatalmazást kér"
 
+msgid "Add buddy authorize"
+msgstr "Partnerengedélyezés felvétele"
+
 msgid "Input request here"
 msgstr "Írja be ide kérését"
 
-#. TODO: Awkward string to fix post string freeze - standardize auth dialogues? -evands
 msgid "Would you be my friend?"
 msgstr "Leszünk barátok?"
 
-#. multiline
-#. masked
-#. hint
-msgid "Send"
-msgstr "Küldés"
-
-#, c-format
-msgid "Add into %d's buddy list"
-msgstr "Hozzáadás %d partnerlistájához"
-
-msgid "QQ Number Error"
-msgstr "QQ számhiba"
+msgid "QQ Buddy"
+msgstr "QQ partner"
+
+msgid "Add buddy"
+msgstr "Partner hozzáadása"
 
 msgid "Invalid QQ Number"
 msgstr "Érvénytelen QQ szám"
 
+msgid "Failed sending authorize"
+msgstr "Az engedély küldése meghiúsult"
+
+#, c-format
+msgid "Failed removing buddy %d"
+msgstr "A partner (%d) eltávolítása meghiúsult"
+
+#, c-format
+msgid "Failed removing me from %d's buddy list"
+msgstr "Az eltávolításom %d partnerlistájáról meghiúsult"
+
+msgid "No reason given"
+msgstr "Nincs ok megadva"
+
+#. only need to get value
+#, c-format
+msgid "You have been added by %s"
+msgstr "%s felvette"
+
+msgid "Would you like to add him?"
+msgstr "Szeretné felvenni?"
+
+#, c-format
+msgid "Rejected by %s"
+msgstr "%s visszautasította"
+
+#, c-format
+msgid "Message: %s"
+msgstr "Üzenet: %s"
+
 msgid "ID: "
 msgstr "Azonosító: "
 
 msgid "Group ID"
 msgstr "Csoportazonosító"
 
-msgid "Creator"
-msgstr "Létrehozó"
-
-msgid "Group Description"
-msgstr "Csoportleírás"
-
-msgid "Auth"
-msgstr "Engedélyezés"
-
 msgid "QQ Qun"
 msgstr "QQ Qun"
 
 msgid "Please enter Qun number"
 msgstr "Adja meg a Qun számot"
 
-#, fuzzy
 msgid "You can only search for permanent Qun\n"
 msgstr "Csak állandó Qun-t kereshet\n"
 
-#, fuzzy, c-format
-msgid "%d request to join Qun %d"
-msgstr "A(z) %d felhasználó csatlakozni szeretne a(z) %d Qun-hoz"
-
-#, c-format
-msgid "Message: %s"
-msgstr "Üzenet: %s"
+msgid "Not member"
+msgstr "Nem tag"
+
+msgid "Member"
+msgstr "Tag"
+
+msgid "Requesting"
+msgstr "Kérés"
+
+msgid "Admin"
+msgstr "Rendszergazda"
+
+msgid "Notice"
+msgstr "Megjegyzés"
+
+msgid "Detail"
+msgstr "Részletek"
+
+msgid "Creator"
+msgstr "Létrehozó"
+
+msgid "About me"
+msgstr "A névjegyem"
+
+msgid "Category"
+msgstr "Kategória"
+
+msgid "The Qun does not allow others to join"
+msgstr "Ez a Qun nem engedélyezi mások csatlakozását"
+
+msgid "Join QQ Qun"
+msgstr "Csatlakozás QQ Qun-hoz"
+
+#, c-format
+msgid "Successfully joined Qun %s (%d)"
+msgstr "Sikeresen csatlakozott a(z) %s Qun-hoz (%d)"
+
+msgid "Successfully joined Qun"
+msgstr "Sikeresen csatlakozott a Qun-hoz"
+
+#, c-format
+msgid "Qun %d denied to join"
+msgstr "A Qun (%d) megtagadta a csatlakozást"
 
 msgid "QQ Qun Operation"
 msgstr "QQ Qun művelet"
 
-msgid "Approve"
-msgstr "Jóváhagyás"
-
-#, fuzzy, c-format
-msgid "Failed to join Qun %d, operated by admin %d"
-msgstr "Partner csatlakoztatása a csevegéshez sikertelen"
-
-#, fuzzy, c-format
-msgid "Successed to join Qun %d, operated by admin %d"
-msgstr "Partner csatlakoztatása a csevegéshez sikertelen"
-
-#, fuzzy, c-format
-msgid "[%d] removed from Qun \"%d\""
-msgstr "Ön [%d] kilépett a következő csoportból: „%d”"
-
-#, fuzzy
-msgid "Notice:"
-msgstr "Megjegyzés"
-
-#, fuzzy, c-format
-msgid "[%d] added to Qun \"%d\""
-msgstr "Ön [%d] kilépett a következő csoportból: „%d”"
-
-msgid "I am not a member"
-msgstr "Nem vagyok tag"
-
-msgid "I am a member"
-msgstr "Tag vagyok"
-
-#, fuzzy
-msgid "I am requesting"
-msgstr "Hibás kérés"
-
-msgid "I am the admin"
-msgstr "Admin vagyok"
-
-msgid "Unknown status"
-msgstr "Ismeretlen állapot"
-
-#, fuzzy
-msgid "The Qun does not allow others to join"
-msgstr "Ez a csoport nem engedélyezi mások csatlakozását"
-
-#, fuzzy
-msgid "Remove from Qun"
-msgstr "Csoport törlése"
-
-#, fuzzy
-msgid "Join to Qun"
-msgstr "Csatlakozás csevegéshez"
-
-#, c-format
-msgid "Qun %d denied to join"
-msgstr ""
+msgid "Failed:"
+msgstr "Sikertelen:"
 
 msgid "Join Qun, Unknow Reply"
-msgstr ""
-
-msgid "You entered a group ID outside the acceptable range"
-msgstr "Az elfogadható tartományon kívüli csoportazonosítót adott meg"
-
-msgid "Are you sure you want to leave this Qun?"
-msgstr "Biztos, hogy el kívánja hagyni ezt a Qun-t?"
+msgstr "Csatlakozás Qun-hoz, ismeretlen válasz"
+
+msgid "Quit Qun"
+msgstr "Kilépés a Qun-ból"
 
 msgid ""
 "Note, if you are the creator, \n"
@@ -7404,44 +7355,47 @@
 "Ne feledje, ha Ön hozta létre,\n"
 "akkor ez a művelet törli a Qun-t."
 
-#. we want to see window
-msgid "Do you want to approve the request?"
-msgstr "Jóvá kívánja hagyni a kérést?"
-
-#, fuzzy
-msgid "Change Qun member"
-msgstr "Telefonszám"
-
-#, fuzzy
-msgid "Change Qun information"
-msgstr "Csatornainformációk"
+msgid "Sorry, you are not our style ..."
+msgstr "Bocs, nem vagy az esetünk…"
+
+msgid "Successfully changed Qun member"
+msgstr "Sikeresen módosított egy Qun tagot"
+
+msgid "Successfully changed Qun information"
+msgstr "Sikeresen módosította a Qun információkat"
 
 msgid "You have successfully created a Qun"
 msgstr "Sikeresen létrehozott egy Qun-t"
 
-#, fuzzy
-msgid "Would you like to set up the detail information now?"
-msgstr "Be kívánja állítani most a Qun részleteit?"
+msgid "Would you like to set detailed information now?"
+msgstr "Be kívánja állítani most a részletes információkat?"
 
 msgid "Setup"
 msgstr "Beállítás"
 
-#, fuzzy, c-format
-msgid ""
-"%s\n"
-"\n"
-"%s"
-msgstr "%s (%s)"
-
-#, fuzzy
-msgid "QQ Server News"
-msgstr "ICQ közvetítő kiszolgáló"
-
-msgid "System Message"
-msgstr "Rendszerüzenet"
-
-msgid "Failed to send IM."
-msgstr "Az azonnali üzenet küldése meghiúsult."
+#, c-format
+msgid "%d requested to join Qun %d for %s"
+msgstr "A(z) %d felhasználó csatlakozni szeretne a(z) %d Qun-hoz, ok: %s"
+
+#, c-format
+msgid "%d request to join Qun %d"
+msgstr "A(z) %d felhasználó csatlakozni szeretne a(z) %d Qun-hoz"
+
+#, c-format
+msgid "Failed to join Qun %d, operated by admin %d"
+msgstr "A csatlakozás sikertelen a(z) %d Qun-hoz, amelyet %d admin működtet"
+
+#, c-format
+msgid "<b>Joining Qun %d is approved by admin %d for %s</b>"
+msgstr "<b>A csatlakozást a Qun-hoz (%d) jóváhagyta %d admin %s számára</b>"
+
+#, c-format
+msgid "<b>Removed buddy %d.</b>"
+msgstr "<b>%d partner eltávolítva.</b>"
+
+#, c-format
+msgid "<b>New buddy %d joined.</b>"
+msgstr "<b>Új partner (%d) csatlakozott.</b>"
 
 #, c-format
 msgid "Unknown-%d"
@@ -7450,9 +7404,6 @@
 msgid "Level"
 msgstr "Szint"
 
-msgid "Member"
-msgstr "Tag"
-
 msgid " VIP"
 msgstr " VIP"
 
@@ -7468,9 +7419,8 @@
 msgid " Video"
 msgstr " Videó"
 
-#, fuzzy
 msgid " Zone"
-msgstr "Nincs"
+msgstr " zóna"
 
 msgid "Flag"
 msgstr "Jelző"
@@ -7481,77 +7431,104 @@
 msgid "Invalid name"
 msgstr "Érvénytelen név"
 
-#, c-format
-msgid "<b>Current Online</b>: %d<br>\n"
-msgstr "<b>Jelenleg elérhető</b>: %d<br>\n"
-
-#, c-format
-msgid "<b>Last Refresh</b>: %s<br>\n"
-msgstr "<b>Utolsó frissítés</b>: %s<br>\n"
-
-#, fuzzy, c-format
+msgid "Select icon..."
+msgstr "Válasszon ikont…"
+
+#, c-format
+msgid "<b>Login time</b>: %d-%d-%d, %d:%d:%d<br>\n"
+msgstr "<b>Bejelentkezés ideje</b>: %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
+msgid "<b>Total Online Buddies</b>: %d<br>\n"
+msgstr "<b>Elérhető partnerek összesen</b>: %d<br>\n"
+
+#, c-format
+msgid "<b>Last Refresh</b>: %d-%d-%d, %d:%d:%d<br>\n"
+msgstr "<b>Utolsó frissítés</b>: %d-%d-%d, %d:%d:%d<br><br>\n"
+
+#, c-format
 msgid "<b>Server</b>: %s<br>\n"
-msgstr "<b>Kiszolgáló</b>: %s: %d<br>\n"
+msgstr "<b>Kiszolgáló</b>: %s<br>\n"
+
+#, c-format
+msgid "<b>Client Tag</b>: %s<br>\n"
+msgstr "<b>Klienscímke</b>: %s<br>\n"
 
 #, c-format
 msgid "<b>Connection Mode</b>: %s<br>\n"
 msgstr "<b>Kapcsolat módja</b>: %s<br>\n"
 
-#, fuzzy, c-format
-msgid "<b>My Internet Address</b>: %s<br>\n"
-msgstr "<b>Kapcsolat módja</b>: %s<br>\n"
-
-#, fuzzy, c-format
+#, c-format
+msgid "<b>My Internet IP</b>: %s:%d<br>\n"
+msgstr "<b>IP-címem</b>: %s:%d<br>\n"
+
+#, c-format
 msgid "<b>Sent</b>: %lu<br>\n"
-msgstr "<b>Kiszolgáló</b>: %s: %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Elküldve</b>: %lu<br>\n"
+
+#, c-format
 msgid "<b>Resend</b>: %lu<br>\n"
-msgstr "<b>Kiszolgáló</b>: %s: %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Újraküldés</b>: %lu<br>\n"
+
+#, c-format
 msgid "<b>Lost</b>: %lu<br>\n"
-msgstr "<b>Utolsó frissítés</b>: %s<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Elveszett</b>: %lu<br>\n"
+
+#, c-format
 msgid "<b>Received</b>: %lu<br>\n"
-msgstr "<b>Kiszolgáló</b>: %s: %d<br>\n"
-
-#, fuzzy, c-format
+msgstr "<b>Fogadott</b>: %lu<br>\n"
+
+#, c-format
 msgid "<b>Received Duplicate</b>: %lu<br>\n"
-msgstr "<b>Nyilvános IP címem</b>: %s<br>\n"
-
-#, c-format
-msgid "<b>Login Time</b>: %s<br>\n"
-msgstr "<b>Bejelentkezés ideje</b>: %s<br>\n"
-
-#, c-format
-msgid "<b>Last Login IP</b>: %s<br>\n"
-msgstr "<b>Utolsó bejelentkezési IP</b>: %s<br>\n"
-
-#, c-format
-msgid "<b>Last Login Time</b>: %s\n"
-msgstr "<b>Utolsó bejelentkezés ideje</b>: %s\n"
+msgstr "<b>Másodpéldány érkezett</b>: %lu<br>\n"
+
+#, c-format
+msgid "<b>Time</b>: %d-%d-%d, %d:%d:%d<br>\n"
+msgstr "<b>Idő</b>: %d-%d-%d, %d:%d:%d<br>\n"
+
+#, c-format
+msgid "<b>IP</b>: %s<br>\n"
+msgstr "<b>IP</b>: %s<br>\n"
 
 msgid "Login Information"
 msgstr "Bejelentkezési információk"
 
-msgid "Set My Information"
-msgstr "Saját információk beállítása"
+msgid "<p><b>Original Author</b>:<br>\n"
+msgstr "<p><b>Eredeti szerző</b>:<br>\n"
+
+msgid "<p><b>Code Contributors</b>:<br>\n"
+msgstr "<p><b>Közreműködők</b>:<br>\n"
+
+msgid "<p><b>Lovely Patch Writers</b>:<br>\n"
+msgstr "<p><b>Javítások</b>:<br>\n"
+
+msgid "<p><b>Acknowledgement</b>:<br>\n"
+msgstr "<p><b>Köszönetnyilvánítás</b>:<br>\n"
+
+msgid "<p><i>And, all the boys in the backroom...</i><br>\n"
+msgstr "<p><i>és a háttéremberek...</i><br>\n"
+
+msgid "<i>Feel free to join us!</i> :)"
+msgstr "<i>csatlakozzon bátran</i> :)"
+
+#, c-format
+msgid "About OpenQ r%s"
+msgstr "Az OpenQ r%s névjegye"
+
+msgid "Change Icon"
+msgstr "Ikon módosítása"
 
 msgid "Change Password"
 msgstr "Jelszó módosítása"
 
-#, fuzzy
 msgid "Account Information"
-msgstr "Az azonosító jellemzői"
-
-#, fuzzy
-msgid "Leave the QQ Qun"
-msgstr "Kilépés ebből a QQ Qun-ből"
-
-msgid "Block this buddy"
-msgstr "A partner tiltása"
+msgstr "Fiókinformációk"
+
+msgid "Update all QQ Quns"
+msgstr "Minden QQ Qun frissítése"
+
+msgid "About OpenQ"
+msgstr "Az OpenQ névjegye"
 
 #. *< type
 #. *< ui_requirement
@@ -7563,60 +7540,103 @@
 #. *< version
 #. *  summary
 #. *  description
-msgid "QQ Protocol\tPlugin"
-msgstr "QQ protokoll\tbővítmény"
-
-#, fuzzy
+msgid "QQ Protocol Plugin"
+msgstr "QQ protokollbővítmény"
+
 msgid "Auto"
 msgstr "Auto"
 
-#, fuzzy
+msgid "Select Server"
+msgstr "Válassza ki a kiszolgálót"
+
+msgid "QQ2005"
+msgstr "QQ2005"
+
+msgid "QQ2007"
+msgstr "QQ2007"
+
+msgid "QQ2008"
+msgstr "QQ2008"
+
+#. #endif
 msgid "Connect by TCP"
 msgstr "Kapcsolódás TCP segítségével"
 
-#, fuzzy
 msgid "Show server notice"
-msgstr "Kiszolgáló portja"
-
-#, fuzzy
+msgstr "Kiszolgálómegjegyzés megjelenítése"
+
 msgid "Show server news"
-msgstr "Kiszolgáló címe"
-
-msgid "Keep alive interval(s)"
-msgstr "Kapcsolat-fenntartási időköz"
-
-msgid "Update interval(s)"
-msgstr "Frissítési időköz"
-
-#, c-format
-msgid "Invalid token reply code, 0x%02X"
-msgstr "Érvénytelen jelsorválaszkód, 0x%02X"
+msgstr "Kiszolgálóhírek megjelenítése"
+
+msgid "Keep alive interval (seconds)"
+msgstr "Kapcsolat-fenntartási időköz (mp)"
+
+msgid "Update interval (seconds)"
+msgstr "Frissítési időköz (mp)"
+
+msgid "Can not decrypt server reply"
+msgstr "Nem fejthető vissza a kiszolgáló válasza"
+
+msgid "Can not decrypt get server reply"
+msgstr "Nem fejthető vissza a kiszolgálólekérdezés válasza"
+
+#, c-format
+msgid "Failed requesting token, 0x%02X"
+msgstr "A jelsor lekérése meghiúsult: 0x%02X"
 
 #, c-format
 msgid "Invalid token len, %d"
 msgstr "Érvénytelen jelsorhossz: %d"
 
-msgid "Unable login for not support Redirect_EX now"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "Error password: %s"
-msgstr "Hiba a jelszó módosításakor"
-
-#, c-format
-msgid "Need active: %s"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "Unable login for unknow reply code 0x%02X"
-msgstr "Érvénytelen jelsorválaszkód, 0x%02X"
+#. extend redirect used in QQ2006
+msgid "Redirect_EX is not currently supported"
+msgstr "A Redirect_EX jelenleg nem támogatott"
+
+#. need activation
+#. need activation
+#. need activation
+msgid "Activation required"
+msgstr "Aktiválás szükséges"
+
+#, c-format
+msgid "Unknow reply code when login (0x%02X)"
+msgstr "Ismeretlen válaszkód bejelentkezéskor (0x%02X)"
 
 msgid "Keep alive error"
 msgstr "Kapcsolat-fenntartási hiba"
 
-#, fuzzy
-msgid "Failed to connect all servers"
-msgstr "Nem sikerült a kiszolgálóhoz kapcsolódni"
+msgid "Requesting captcha ..."
+msgstr "Captcha kérése…"
+
+msgid "Checking code of captcha ..."
+msgstr "A captcha kódjának ellenőrzése…"
+
+msgid "Failed captcha verify"
+msgstr "A captcha ellenőrzése meghiúsult"
+
+msgid "Captcha Image"
+msgstr "Captcha kép"
+
+msgid "Enter code"
+msgstr "Adja meg a kódot"
+
+msgid "QQ Captcha Verifing"
+msgstr "QQ captcha ellenőrzés"
+
+msgid "Enter the text from the image"
+msgstr "Adja meg a szöveget a képről"
+
+#, c-format
+msgid "Unknow reply code when checking password (0x%02X)"
+msgstr "Ismeretlen válaszkód a jelszó ellenőrzésekor (0x%02X)"
+
+#, c-format
+msgid ""
+"Unknow reply code when login (0x%02X):\n"
+"%s"
+msgstr ""
+"Ismeretlen válaszkód bejelentkezéskor (0x%02X):\n"
+"%s"
 
 #. we didn't successfully connect. tdt->toc_fd is valid here
 msgid "Unable to connect."
@@ -7642,54 +7662,77 @@
 msgid "Connection lost"
 msgstr "A kapcsolat elveszett"
 
-#. Update the login progress status display
-#, fuzzy, c-format
+msgid "Get server ..."
+msgstr "Kiszolgáló lekérdezése…"
+
 msgid "Request token"
-msgstr "Kérés elutasítva"
+msgstr "Jelsor kérése"
 
 msgid "Couldn't resolve host"
 msgstr "Nem sikerült a kiszolgáló feloldása"
 
-#, fuzzy
 msgid "Invalid server or port"
-msgstr "Érvénytelen hiba"
-
-#, c-format
-msgid "Connecting server %s, retries %d"
-msgstr "Kapcsolódási a(z) %s kiszolgálóhoz, újrapróbálkozás: %d"
-
-#, fuzzy
+msgstr "Érvénytelen kiszolgáló vagy port"
+
+msgid "Connecting server ..."
+msgstr "Kapcsolódás kiszolgálóhoz…"
+
 msgid "QQ Error"
-msgstr "QQid hiba"
-
-#, fuzzy
+msgstr "QQ hiba"
+
+msgid "Failed to send IM."
+msgstr "Az azonnali üzenet küldése meghiúsult."
+
+#, c-format
+msgid ""
+"Server News:\n"
+"%s\n"
+"%s\n"
+"%s"
+msgstr ""
+"Kiszolgáló hírei:\n"
+"%s\n"
+"%s\n"
+"%s"
+
+#, c-format
+msgid "From %s:"
+msgstr "Feladó: %s:"
+
+#, c-format
+msgid ""
+"Server notice From %s: \n"
+"%s"
+msgstr ""
+"Kiszolgálómegjegyzés ettől: %s\n"
+"%s"
+
 msgid "Unknow SERVER CMD"
-msgstr "Ismeretlen ok"
-
-#, fuzzy, c-format
+msgstr "Ismeretlen kiszolgálóparancs"
+
+#, c-format
 msgid ""
 "Error reply of %s(0x%02X)\n"
 "Room %d, reply 0x%02X"
 msgstr ""
-"Válasz: %s(0x%02X )\n"
-"Elküldve: %s(0x%02X )\n"
-"Szobaazonosító: %d, válasz: [0x%02X]: \n"
-"%s"
-
-#, fuzzy
+"Hiba %s(0x%02X) válaszában\n"
+"Szoba: %d, válasz: 0x%02X"
+
 msgid "QQ Qun Command"
-msgstr "Parancs"
-
-#, fuzzy, c-format
-msgid "You are not a member of QQ Qun \"%s\"\n"
-msgstr "Ön nem tagja a következő csoportnak: „%s”\n"
+msgstr "QQ Qun parancs"
+
+#, c-format
+msgid "Not a member of room \"%s\"\n"
+msgstr "Ön nem tagja a következő szobának: „%s”\n"
 
 msgid "Can not decrypt login reply"
 msgstr "Nem fejthető vissza a bejelentkezési válasz"
 
-#, fuzzy
-msgid "Unknow reply CMD"
-msgstr "Ismeretlen ok"
+msgid "Unknow LOGIN CMD"
+msgstr "Ismeretlen bejelentkezési parancs"
+
+msgid "Unknow CLIENT CMD"
+msgstr "Ismeretlen kliensparancs"
 
 #, c-format
 msgid "%d has declined the file %s"
@@ -7702,63 +7745,6 @@
 msgid "%d canceled the transfer of %s"
 msgstr "%d megszakította a(z) %s átvitelét"
 
-#, fuzzy
-msgid "Do you approve the requestion?"
-msgstr "Jóvá kívánja hagyni a kérést?"
-
-#, fuzzy
-msgid "Do you add the buddy?"
-msgstr "Fel kívánja venni ezt a partnert?"
-
-#. only need to get value
-#, c-format
-msgid "You have been added by %s"
-msgstr "%s felvette"
-
-msgid "Would you like to add him?"
-msgstr "Szeretné felvenni?"
-
-#, fuzzy, c-format
-msgid "%s added you [%s] to buddy list"
-msgstr "%s felvette Önt a partnerlistájára."
-
-#, fuzzy
-msgid "QQ Budy"
-msgstr "Partner"
-
-#, c-format
-msgid "Requestion rejected by %s"
-msgstr ""
-
-#, c-format
-msgid "Requestion approved by %s"
-msgstr ""
-
-#. TODO: this should go through purple_account_request_authorization()
-#, c-format
-msgid "%s wants to add you [%s] as a friend"
-msgstr "%s fel kívánja venni Önt [%s] barátként"
-
-#, fuzzy, c-format
-msgid "%s is not in buddy list"
-msgstr "%s nincs a partnerlistáján"
-
-#, fuzzy
-msgid "Would you add?"
-msgstr "Szeretné felvenni?"
-
-#, fuzzy, c-format
-msgid "From %s:"
-msgstr "Feladó %s:"
-
-#, c-format
-msgid "%s"
-msgstr "%s"
-
-#, fuzzy
-msgid "QQ Server Notice"
-msgstr "Kiszolgáló portja"
-
 msgid "Connection closed (writing)"
 msgstr "Kapcsolat lezárva (írás)"
 
@@ -7808,8 +7794,7 @@
 msgstr "Szolgáltatások indítása"
 
 #, c-format
-msgid ""
-"A Sametime administrator has issued the following announcement on server %s"
+msgid "A Sametime administrator has issued the following announcement on server %s"
 msgstr ""
 "Egy Sametime adminisztrátor a következő bejelentést adta ki a(z) %s "
 "kiszolgálón"
@@ -8460,8 +8445,7 @@
 msgstr "Titkos csatorna beállítása"
 
 #, c-format
-msgid ""
-"You have to join the %s channel before you are able to join the private group"
+msgid "You have to join the %s channel before you are able to join the private group"
 msgstr ""
 "Mielőtt csatlakozhatna a magáncsoporthoz, csatlakoznia kell a(z) %s "
 "csatornához"
@@ -8529,8 +8513,7 @@
 
 #, c-format
 msgid "<I>%s</I> set channel <I>%s</I> modes to: %s"
-msgstr ""
-"<I>%s</I> átállította a(z) <I>%s</I> csatorna üzemmódjait a következőkre: %s"
+msgstr "<I>%s</I> átállította a(z) <I>%s</I> csatorna üzemmódjait a következőkre: %s"
 
 #, c-format
 msgid "<I>%s</I> removed all channel <I>%s</I> modes"
@@ -8713,8 +8696,7 @@
 
 #, c-format
 msgid "Received %s's public key. Would you like to accept this public key?"
-msgstr ""
-"%s nyilvános kulcsa megérkezett. El kívánja fogadni ezt a nyilvános kulcsot?"
+msgstr "%s nyilvános kulcsa megérkezett. El kívánja fogadni ezt a nyilvános kulcsot?"
 
 #, c-format
 msgid ""
@@ -8746,8 +8728,7 @@
 msgid "Key Exchange failed"
 msgstr "Kulcscsere sikertelen"
 
-msgid ""
-"Resuming detached session failed. Press Reconnect to create new connection."
+msgid "Resuming detached session failed. Press Reconnect to create new connection."
 msgstr ""
 "A leválasztott folyamat folytatása sikertelen. Kattintson az Újrakapcsolódás "
 "gombra egy új kapcsolat létrehozásához."
@@ -8930,8 +8911,7 @@
 msgstr "whois &lt;becenév&gt;:  A becenévhez tartozó információk megjelenítése"
 
 msgid "msg &lt;nick&gt; &lt;message&gt;:  Send a private message to a user"
-msgstr ""
-"msg &lt;becenév&gt; &lt;message&gt;:  Magánüzenet küldése a felhasználónak"
+msgstr "msg &lt;becenév&gt; &lt;message&gt;:  Magánüzenet küldése a felhasználónak"
 
 msgid "query &lt;nick&gt; [&lt;message&gt;]:  Send a private message to a user"
 msgstr ""
@@ -9000,12 +8980,10 @@
 "csatornáról"
 
 msgid "info [server]:  View server administrative details"
-msgstr ""
-"info [kiszolgáló]:  A kiszolgáló adminisztrációs részleteinek megjelenítése"
+msgstr "info [kiszolgáló]:  A kiszolgáló adminisztrációs részleteinek megjelenítése"
 
 msgid "ban [&lt;channel&gt; +|-&lt;nick&gt;]:  Ban client from channel"
-msgstr ""
-"ban [&lt;csatorna&gt; +|-&lt;becenév&gt;]:  Kliens kitiltása a csatornáról"
+msgstr "ban [&lt;csatorna&gt; +|-&lt;becenév&gt;]:  Kliens kitiltása a csatornáról"
 
 msgid "getkey &lt;nick|server&gt;:  Retrieve client's or server's public key"
 msgstr ""
@@ -9182,8 +9160,7 @@
 
 #, c-format
 msgid "Failure: Remote does not trust/support your public key"
-msgstr ""
-"Hiba: A távoli fél nem bízik meg vagy nem támogatja az Ön nyilvános kulcsát"
+msgstr "Hiba: A távoli fél nem bízik meg vagy nem támogatja az Ön nyilvános kulcsát"
 
 #, c-format
 msgid "Failure: Remote does not support proposed KE group"
@@ -9314,8 +9291,7 @@
 
 #, c-format
 msgid "A message has been dropped, you are exceeding the server speed limit."
-msgstr ""
-"Egy üzenet el lett dobva, Ön túllépte a kiszolgáló átviteli sebességhatárát."
+msgstr "Egy üzenet el lett dobva, Ön túllépte a kiszolgáló átviteli sebességhatárát."
 
 #, c-format
 msgid "Chat in %s is not available."
@@ -9477,9 +9453,6 @@
 msgid "Yahoo! system message for %s:"
 msgstr "Yahoo! rendszerüzenet %s számára:"
 
-msgid "Authorization denied message:"
-msgstr "Hozzáférés elutasítva üzenet:"
-
 #, c-format
 msgid ""
 "%s has (retroactively) denied your request to add them to your list for the "
@@ -9777,8 +9750,7 @@
 
 #, c-format
 msgid "%s declined your conference invitation to room \"%s\" because \"%s\"."
-msgstr ""
-"%s visszalépett az Ön meghívásától a(z) „%s” konferenciaszobába, mivel: „%s”."
+msgstr "%s visszalépett az Ön meghívásától a(z) „%s” konferenciaszobába, mivel: „%s”."
 
 msgid "Invitation Rejected"
 msgstr "Meghívás visszautasítva"
@@ -9895,8 +9867,7 @@
 "sub &lt;osztály&gt; &lt;példány&gt; &lt;címzett&gt;: Csatlakozás új "
 "csevegéshez"
 
-msgid ""
-"zi &lt;instance&gt;: Send a message to &lt;message,<i>instance</i>,*&gt;"
+msgid "zi &lt;instance&gt;: Send a message to &lt;message,<i>instance</i>,*&gt;"
 msgstr ""
 "zi &lt;példány&gt;: Üzenet küldése a következőnek: &lt;üzenet,<i>példány</i>,"
 "*&gt;"
@@ -10373,9 +10344,9 @@
 "<span size='larger' weight='bold'>Welcome to %s!</span>\n"
 "\n"
 "You have no IM accounts configured. To start connecting with %s press the "
-"<b>Add</b> button below and configure your first account. If you want %s to "
-"connect to multiple IM accounts, press <b>Add</b> again to configure them "
-"all.\n"
+"<b>Add...</b> button below and configure your first account. If you want %s "
+"to connect to multiple IM accounts, press <b>Add...</b> again to configure "
+"them all.\n"
 "\n"
 "You can come back to this window to add, edit, or remove accounts from "
 "<b>Accounts->Manage Accounts</b> in the Buddy List window"
@@ -10385,7 +10356,7 @@
 "Nincsenek beállítva azonnaliüzenő-fiókjai. A %s használatának megkezdéséhez "
 "kattintson az alábbi <b>Hozzáadás</b> gombra és állítsa be első fiókját. Ha "
 "azt szeretné hogy a %s több fiókhoz csatlakozzon, kattintson újra a "
-"<b>Hozzáadás</b> gombra és állítsa be mindet.\n"
+"<b>Hozzáadás…</b> gombra és állítsa be mindet.\n"
 "\n"
 "A Partnerlista ablak <b>Fiókok -> Fiókok kezelése</b> menüpontja "
 "segítségével visszatérhet ehhez az ablakhoz fiókok hozzáadásához, "
@@ -10393,8 +10364,7 @@
 
 #, c-format
 msgid "You have %d contact named %s. Would you like to merge them?"
-msgid_plural ""
-"You currently have %d contacts named %s. Would you like to merge them?"
+msgid_plural "You currently have %d contacts named %s. Would you like to merge them?"
 msgstr[0] "Jelenleg %d %s nevű partnere van. Össze kívánja vonni ezeket?"
 msgstr[1] "Jelenleg %d %s nevű partnere van. Össze kívánja vonni ezeket?"
 
@@ -10450,9 +10420,6 @@
 msgid "Hide when offline"
 msgstr "Elrejtés, ha nem érhető el"
 
-msgid "Show when offline"
-msgstr "Megjelenítés, ha elérhető"
-
 msgid "_Alias..."
 msgstr "Ál_név…"
 
@@ -10499,8 +10466,7 @@
 msgid "/Tools/Mute Sounds"
 msgstr "/Eszközök/Hangok némítása"
 
-msgid ""
-"You are not currently signed on with an account that can add that buddy."
+msgid "You are not currently signed on with an account that can add that buddy."
 msgstr ""
 "Jelenleg nincs bejelentkezve olyan hálózatra, amelyen felvehetné ezt a "
 "partnert."
@@ -10728,8 +10694,7 @@
 
 #, c-format
 msgid "%d account was disabled because you signed on from another location:"
-msgid_plural ""
-"%d accounts were disabled because you signed on from another location:"
+msgid_plural "%d accounts were disabled because you signed on from another location:"
 msgstr[0] "%d fiók letiltva, mivel bejelentkezett egy másik helyről:"
 msgstr[1] "%d fiók letiltva, mivel bejelentkezett egy másik helyről:"
 
@@ -10814,8 +10779,8 @@
 msgid "Auto_join when account becomes online."
 msgstr "Automatikus _csatlakozás a fiók elérhetővé válásakor."
 
-msgid "_Hide chat when the window is closed."
-msgstr "Cse_vegés elrejtése az ablak bezárásakor."
+msgid "_Remain in chat after window is closed."
+msgstr "Csevegésben mara_dás az ablak bezárásakor."
 
 msgid "Please enter the name of the group to be added."
 msgstr "Adja meg a felvenni kívánt csoport nevét."
@@ -10848,18 +10813,13 @@
 msgid "SSL Servers"
 msgstr "SSL kiszolgálók"
 
-#, fuzzy
-msgid "Network disconnected"
-msgstr "A távoli fél bontotta a kapcsolatot"
-
 msgid "Unknown command."
 msgstr "Ismeretlen parancs."
 
 msgid "That buddy is not on the same protocol as this chat."
 msgstr "A partner nem ugyanazt a protokollt használja, mint ez a csevegés."
 
-msgid ""
-"You are not currently signed on with an account that can invite that buddy."
+msgid "You are not currently signed on with an account that can invite that buddy."
 msgstr ""
 "Jelenleg nincs bejelentkezve olyan fiókkal, mellyel meghívhatná ezt a "
 "partnert."
@@ -11193,8 +11153,12 @@
 msgid "Fatal Error"
 msgstr "Végzetes hiba"
 
-msgid "developer"
-msgstr "fejlesztő"
+# fixme: jobb ötlet?
+msgid "bug master"
+msgstr "hibaritkító"
+
+msgid "artist"
+msgstr "grafikus"
 
 #. feel free to not translate this
 msgid "Ka-Hing Cheung"
@@ -11203,11 +11167,8 @@
 msgid "support"
 msgstr "támogató"
 
-msgid "support/QA"
-msgstr "támogató/QA"
-
-msgid "developer & webmaster"
-msgstr "fejlesztő és webmester"
+msgid "webmaster"
+msgstr "webmester"
 
 msgid "Senior Contributor/QA"
 msgstr "Veterán közreműködő/QA"
@@ -11225,8 +11186,11 @@
 msgid "hacker and designated driver [lazy bum]"
 msgstr "hacker és kijelölt vezető"
 
-msgid "XMPP developer"
-msgstr "XMPP fejlesztő"
+msgid "support/QA"
+msgstr "támogató/QA"
+
+msgid "XMPP"
+msgstr "XMPP"
 
 msgid "original author"
 msgstr "eredeti szerző"
@@ -11475,8 +11439,7 @@
 
 #, c-format
 msgid "<FONT SIZE=\"4\">IRC:</FONT> #pidgin on irc.freenode.net<BR><BR>"
-msgstr ""
-"<FONT SIZE=\"4\">IRC:</FONT> #pidgin az irc.freenode.net hálózaton<BR><BR>"
+msgstr "<FONT SIZE=\"4\">IRC:</FONT> #pidgin az irc.freenode.net hálózaton<BR><BR>"
 
 msgid "Current Developers"
 msgstr "Jelenlegi fejlesztők"
@@ -11490,9 +11453,6 @@
 msgid "Retired Crazy Patch Writers"
 msgstr "Visszavonult őrült patch szerzők"
 
-msgid "Artists"
-msgstr "Grafikusok"
-
 msgid "Current Translators"
 msgstr "Jelenlegi fordítók"
 
@@ -11589,8 +11549,7 @@
 msgstr "_Csoport eltávolítása"
 
 #, c-format
-msgid ""
-"You are about to remove %s from your buddy list.  Do you want to continue?"
+msgid "You are about to remove %s from your buddy list.  Do you want to continue?"
 msgstr "%s eltávolítására készül a partnerlistájáról. Folytatni akarja?"
 
 msgid "Remove Buddy"
@@ -11603,8 +11562,7 @@
 msgid ""
 "You are about to remove the chat %s from your buddy list.  Do you want to "
 "continue?"
-msgstr ""
-"%s csevegés eltávolítására készül a partnerlistájáról. Folytatni akarja?"
+msgstr "%s csevegés eltávolítására készül a partnerlistájáról. Folytatni akarja?"
 
 msgid "Remove Chat"
 msgstr "Csevegés eltávolítása"
@@ -11736,8 +11694,7 @@
 msgstr "Hiperhivatkozás előfényszíne"
 
 msgid "Color to draw hyperlinks when mouse is over them."
-msgstr ""
-"Hiperhivatkozások rajzolásához használt szín, amikor az egér rájuk mutat."
+msgstr "Hiperhivatkozások rajzolásához használt szín, amikor az egér rájuk mutat."
 
 msgid "Sent Message Name Color"
 msgstr "Elküldött üzenet névszíne"
@@ -11860,8 +11817,7 @@
 msgid ""
 "Please enter the URL and description of the link that you want to insert. "
 "The description is optional."
-msgstr ""
-"Adja meg a beszúrandó hivatkozás URL címét és leírását. A leírás opcionális."
+msgstr "Adja meg a beszúrandó hivatkozás URL címét és leírását. A leírás opcionális."
 
 msgid "Please enter the URL of the link that you want to insert."
 msgstr "Adja meg a beszúrandó hivatkozás URL címét."
@@ -12013,8 +11969,7 @@
 msgid ""
 "Are you sure you want to permanently delete the system log which started at %"
 "s?"
-msgstr ""
-"Biztos, hogy törölni akarja a(z) %s időpontban kezdődött rendszernaplót?"
+msgstr "Biztos, hogy törölni akarja a(z) %s időpontban kezdődött rendszernaplót?"
 
 msgid "Delete Log?"
 msgstr "Törli a naplót?"
@@ -12028,8 +11983,7 @@
 
 #, c-format
 msgid "<span size='larger' weight='bold'>Conversation with %s on %s</span>"
-msgstr ""
-"<span size='larger' weight='bold'>Társalgás ezzel: %s, ekkor: %s</span>"
+msgstr "<span size='larger' weight='bold'>Társalgás ezzel: %s, ekkor: %s</span>"
 
 #. Steal the "HELP" response and use it to trigger browsing to the logs folder
 msgid "_Browse logs folder"
@@ -12109,11 +12063,6 @@
 "and post the backtrace from the core file.  If you do not know\n"
 "how to get the backtrace, please read the instructions at\n"
 "%swiki/GetABacktrace\n"
-"\n"
-"If you need further assistance, please IM either SeanEgn or \n"
-"LSchiere (via AIM).  Contact information for Sean and Luke \n"
-"on other protocols is at\n"
-"%swiki/DeveloperPages\n"
 msgstr ""
 "A %s %s összeomlott és megpróbált kiírni egy magfájlt.\n"
 "Ez a szoftver és nem az Ön hibája miatt történt.\n"
@@ -12127,12 +12076,6 @@
 "szerezze be a visszakövetést, akkor olvassa el a következő címen található\n"
 "utasításokat:\n"
 "%swiki/GetABacktrace\n"
-"\n"
-"Ha további segítségre van szüksége, akkor küldjön azonnali üzenetet (AIM "
-"protokollon, angolul)\n"
-"SeanEgn-nak vagy LSchiere-nek. Sean és Luke kapcsolatinformációi más\n"
-"protokollokhoz elérhetők a következő oldalon:\n"
-"%swiki/DeveloperPages\n"
 
 #. Translators may want to transliterate the name.
 #. It is not to be translated.
@@ -12168,8 +12111,7 @@
 msgid "Error launching \"%s\": %s"
 msgstr "Hiba „%s” indításakor: %s"
 
-msgid ""
-"The 'Manual' browser command has been chosen, but no command has been set."
+msgid "The 'Manual' browser command has been chosen, but no command has been set."
 msgstr "A „Kézi” böngészőparancsot választotta, de nem adott meg parancsot."
 
 msgid "The following plugins will be unloaded."
@@ -12604,11 +12546,9 @@
 msgid "Sounds when conversation has _focus"
 msgstr "Hangok lejátszása, ha a társalgás ablaka a_ktív"
 
-#, fuzzy
 msgid "_Enable sounds:"
 msgstr "Hangok _engedélyezése:"
 
-#, fuzzy
 msgid "V_olume:"
 msgstr "H_angerő:"
 
@@ -12833,13 +12773,11 @@
 msgid "Custom Smiley Manager"
 msgstr "Egyénihangulatjel-kezelő"
 
-#, fuzzy
 msgid "Click to change your buddyicon for this account."
-msgstr "Ezen _partnerikon használata a fiókhoz:"
-
-#, fuzzy
+msgstr "Kattintson a fiók partnerikonjának módosításához."
+
 msgid "Click to change your buddyicon for all accounts."
-msgstr "Ezen _partnerikon használata a fiókhoz:"
+msgstr "Kattintson az összes fiók partnerikonjának módosításához."
 
 msgid "Waiting for network connection"
 msgstr "Várakozás a hálózati kapcsolatra"
@@ -12938,8 +12876,7 @@
 
 #, c-format
 msgid "The file '%s' is too large for %s.  Please try a smaller image.\n"
-msgstr ""
-"A(z) „%s” fájl túl nagy a következőhöz: %s. Próbálkozzon kisebb képpel.\n"
+msgstr "A(z) „%s” fájl túl nagy a következőhöz: %s. Próbálkozzon kisebb képpel.\n"
 
 msgid "Icon Error"
 msgstr "Ikonhiba"
@@ -12952,8 +12889,7 @@
 msgstr "Nem sikerült megnyitni a(z) „%s” fájlt: %s"
 
 #, c-format
-msgid ""
-"Failed to load image '%s': reason not known, probably a corrupt image file"
+msgid "Failed to load image '%s': reason not known, probably a corrupt image file"
 msgstr ""
 "A(z) „%s” kép betöltése sikertelen: az ok nem ismert, valószínűleg sérült a "
 "képfájl"
@@ -12976,8 +12912,11 @@
 msgid "_Invite"
 msgstr "Meg_hívás"
 
-msgid "_Modify"
-msgstr "_Módosítás"
+msgid "_Modify..."
+msgstr "_Módosítás…"
+
+msgid "_Add..."
+msgstr "Hozzá_adás…"
 
 msgid "_Open Mail"
 msgstr "_Levél megnyitása"
@@ -13000,6 +12939,12 @@
 msgid "none"
 msgstr "nincs"
 
+msgid "Small"
+msgstr "Kicsi"
+
+msgid "Smaller versions of the default smilies"
+msgstr "Az alapértelmezett hangulatjelek kisebb változatai"
+
 msgid "Response Probability:"
 msgstr "Válasz valószínűsége:"
 
@@ -13083,8 +13028,7 @@
 #. *< name
 #. *< version
 #. *< summary
-msgid ""
-"Allows for controlling the values associated with different buddy states."
+msgid "Allows for controlling the values associated with different buddy states."
 msgstr ""
 "Lehetővé teszi a partnerek különböző állapotaihoz rendelt értékek "
 "beállítását."
@@ -13149,8 +13093,7 @@
 msgstr "Társalgások száma ablakonként"
 
 msgid "Separate IM and Chat windows when placing by number"
-msgstr ""
-"Azonnali üzenő- és csevegőablakok elkülönítése szám szerinti elhelyezésnél"
+msgstr "Azonnali üzenő- és csevegőablakok elkülönítése szám szerinti elhelyezésnél"
 
 #. *< type
 #. *< ui_requirement
@@ -13359,8 +13302,7 @@
 #. *  summary
 #. *  description
 msgid "Iconifies the buddy list and your conversations when you go away."
-msgstr ""
-"Ikonállapotba helyezi a partnerlistát és a társalgásokat, amikor távol van."
+msgstr "Ikonállapotba helyezi a partnerlistát és a társalgásokat, amikor távol van."
 
 msgid "Mail Checker"
 msgstr "Levélfigyelő"
@@ -13369,8 +13311,7 @@
 msgstr "Új helyi levél érkezését ellenőrzi."
 
 msgid "Adds a small box to the buddy list that shows if you have new mail."
-msgstr ""
-"Kis dobozt ad a partnerlistához, amely megjelenik új levél érkezésekor."
+msgstr "Kis dobozt ad a partnerlistához, amely megjelenik új levél érkezésekor."
 
 msgid "Markerline"
 msgstr "Jelölő vonal"
@@ -13470,6 +13411,9 @@
 msgid "Set window manager \"_URGENT\" hint"
 msgstr "„_SÜRGŐS” tipp beállítása az ablakkezelő számára"
 
+msgid "_Flash window"
+msgstr "_Ablak villogtatása"
+
 #. Raise window method button
 msgid "R_aise conversation window"
 msgstr "_Társalgási ablak előtérbe hozása"
@@ -13516,8 +13460,7 @@
 #. *  summary
 #. *  description
 msgid "Provides a variety of ways of notifying you of unread messages."
-msgstr ""
-"Különböző lehetőségeket nyújt az olvasatlan üzenetekre figyelmeztetésre."
+msgstr "Különböző lehetőségeket nyújt az olvasatlan üzenetekre figyelmeztetésre."
 
 #. *< type
 #. *< ui_requirement
@@ -13934,8 +13877,7 @@
 msgid "Options specific to Pidgin for Windows."
 msgstr "A windowsos Pidginre jellemző beállítások."
 
-msgid ""
-"Provides options specific to Pidgin for Windows , such as buddy list docking."
+msgid "Provides options specific to Pidgin for Windows , such as buddy list docking."
 msgstr ""
 "A windowsos Pidginre jellemző beállításokat biztosít, mint például a "
 "partnerlista dokkolása."
@@ -13979,122 +13921,3 @@
 "Ez a bővítmény XMPP kiszolgálókban vagy kliensekben végzett hibakereséshez "
 "hasznos."
 
-#, fuzzy
-#~ msgid "EOF while reading from resolver process"
-#~ msgstr ""
-#~ "Hiba a feloldó folyamatból olvasás közben:\n"
-#~ "%s"
-
-#, fuzzy
-#~ msgid "Your information has been updated"
-#~ msgstr "A jelszava meg lett változtatva."
-
-#, fuzzy
-#~ msgid "You have successfully removed a buddy"
-#~ msgstr "Sikeresen létrehozott egy Qun-t"
-
-#, fuzzy
-#~ msgid "You have successfully removed yourself from your friend's buddy list"
-#~ msgstr "%s eltávolította Önt a partnerlistájáról."
-
-#, fuzzy
-#~ msgid "You have added %d to buddy list"
-#~ msgstr "%s felvette Önt [%s] a partnerlistájára"
-
-#, fuzzy
-#~ msgid "Invalid QQid"
-#~ msgstr "Érvénytelen authzid"
-
-#, fuzzy
-#~ msgid "Please enter external group ID"
-#~ msgstr "Adja meg %s új nevét"
-
-#, fuzzy
-#~ msgid "Reason: %s"
-#~ msgstr "Verzió: \t%s\n"
-
-#, fuzzy
-#~ msgid "Your request to join group %d has been rejected by admin %d"
-#~ msgstr ""
-#~ "A csatlakozási kérelmét a(z) %d csoporthoz %d admin visszautasította"
-
-#, fuzzy
-#~ msgid "Your request to join group %d has been approved by admin %d"
-#~ msgstr ""
-#~ "A csatlakozási kérelmét a(z) %d csoporthoz %d admin visszautasította"
-
-#, fuzzy
-#~ msgid "You [%d] have left group \"%d\""
-#~ msgstr "Ön [%d] fel lett véve a következő csoportba: „%d”"
-
-#, fuzzy
-#~ msgid "You [%d] have been added to group \"%d\""
-#~ msgstr "%s felvette"
-
-#, fuzzy
-#~ msgid "This group has been added to your buddy list"
-#~ msgstr "%s felvette Önt a partnerlistájára."
-
-#, fuzzy
-#~ msgid "You have successfully left the group"
-#~ msgstr "Sikeresen létrehozott egy Qun-t"
-
-#, fuzzy
-#~ msgid "Enter your reason:"
-#~ msgstr "Írja be alább a jegyzetet…"
-
-#, fuzzy
-#~ msgid "You have successfully modified Qun member"
-#~ msgstr "Sikeresen létrehozott egy Qun-t"
-
-#, fuzzy
-#~ msgid "You have successfully modified Qun information"
-#~ msgstr "Sikeresen létrehozott egy Qun-t"
-
-#, fuzzy
-#~ msgid " Space"
-#~ msgstr "MySpace"
-
-#, fuzzy
-#~ msgid "<b>Real hostname</b>: %s: %d<br>\n"
-#~ msgstr "<b>Utolsó frissítés</b>: %s<br>\n"
-
-#, fuzzy
-#~ msgid "<b>My Public IP</b>: %s<br>\n"
-#~ msgstr "<b>Utolsó bejelentkezési IP</b>: %s<br>\n"
-
-#, fuzzy
-#~ msgid "Show Login Information"
-#~ msgstr "Bejelentkezési információk"
-
-#, fuzzy
-#~ msgid "resend interval(s)"
-#~ msgstr "Frissítési időköz"
-
-#, fuzzy
-#~ msgid "Failed to connect server"
-#~ msgstr "Nem sikerült a kiszolgálóhoz kapcsolódni."
-
-#, fuzzy
-#~ msgid "Unable to login. Check debug log."
-#~ msgstr "A bővítmény nem tölthető be"
-
-#, fuzzy
-#~ msgid "Unable to login"
-#~ msgstr "A bővítmény nem tölthető be"
-
-#, fuzzy
-#~ msgid "Failed room reply"
-#~ msgstr "A partner eltávolítása sikertelen"
-
-#, fuzzy
-#~ msgid "User %s rejected your request"
-#~ msgstr "Visszautasította %d kérését"
-
-#, fuzzy
-#~ msgid "User %s approved your request"
-#~ msgstr "Jóvá kívánja hagyni a kérést?"
-
-#, fuzzy
-#~ msgid "Notice from: %s"
-#~ msgstr "Megjegyzés"