changeset 25432:8c8948b9f602

propagate from branch 'im.pidgin.pidgin' (head 8ae2fca06a3be4b99cc677c8f880d9521a35ec8b) to branch 'im.pidgin.pidgin.next.minor' (head 3725318168b46a11998066b36f9311e26d51885b)
author Mark Doliner <mark@kingant.net>
date Wed, 28 Jan 2009 10:23:37 +0000
parents 9bff90dfb2e5 (diff) 29f953732186 (current diff)
children e0572c12265a
files .todo COPYRIGHT ChangeLog libpurple/certificate.c libpurple/core.c libpurple/protocols/oscar/oscar.c libpurple/protocols/oscar/oscar.h libpurple/protocols/oscar/peer.c libpurple/status.c pidgin/gtkimhtml.c
diffstat 236 files changed, 9525 insertions(+), 3668 deletions(-) [+]
line wrap: on
line diff
--- a/.mtn-ignore	Wed Jan 28 04:27:01 2009 +0000
+++ b/.mtn-ignore	Wed Jan 28 10:23:37 2009 +0000
@@ -10,6 +10,7 @@
 .*\.def$
 .*\.dll$
 .*\.exe$
+.*\.loT$
 intltool-.*
 Doxyfile(\.mingw)?$
 aclocal.m4
--- a/.todo	Wed Jan 28 04:27:01 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-<todo version="0.1.19">
-    <title>
-        Gaim TODO List
-    </title>
-    <link filename="./libpurple/protocols/oscar/.todo" priority="medium" time="0"/>
-    <link filename="./libpurple/protocols/jabber/.todo" priority="medium" time="1176995038"/>
-</todo>
--- a/COPYRIGHT	Wed Jan 28 04:27:01 2009 +0000
+++ b/COPYRIGHT	Wed Jan 28 10:23:37 2009 +0000
@@ -85,6 +85,7 @@
 Lorenzo Colitti
 Collabora Ltd.
 Jeff Connelly
+Chris Connett
 Nathan Conrad
 Felipe Contreras
 Alex Converse
--- a/ChangeLog	Wed Jan 28 04:27:01 2009 +0000
+++ b/ChangeLog	Wed Jan 28 10:23:37 2009 +0000
@@ -1,5 +1,20 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.6.0 (??/??/????):
+	General:
+	* Theme support in libpurple thanks to Justin Rodriguez's summer of code
+	  project.  With some minor additions and clean ups from Paul Aurich.
+
+	Pidgin:
+	* Added -f command line option to tell Pidgin to ignore NetworkManager
+	  and assume it has a valid network connection.
+	* Allow plugins to specify custom link types to the GtkIMHtml widget.
+	* The status message input box at the bottom of the buddy list expands
+	  correctly when starting a new line of text.
+	* Pressing the Enter key in the message entry box of the New Status
+	  dialog and various other dialogs now causes the cursor to move to
+	  the next line.
+
 version 2.5.5 (??/??/????):
 	libpurple:
 	* Fix transfer of buddy icons, custom smileys and files from the
@@ -609,13 +624,13 @@
 version 2.2.0 (09/13/2007):
 	http://developer.pidgin.im/query?status=closed&milestone=2.2.0
 
-	Libpurple:
+	libpurple:
 	* New protocol plugin: MySpaceIM (Jeff Connelly, Google Summer of
 	  Code)
 	* XMPP enhancements. See
-	  http://www.adiumx.com/blog/2007/07/soc-xmpp-update.php (Andreas 
+	  http://www.adiumx.com/blog/2007/07/soc-xmpp-update.php (Andreas
 	  Monitzer, Google Summer of Code for Adium)
-	* Certificate management. Libpurple will validate certificates on
+	* Certificate management. libpurple will validate certificates on
 	  SSL-encrypted protocols (William Ehlhardt, Google Summer of Code)
 	* Some adjustments were made to fix sending messages when using
 	  the MSN HTTP method. (Laszlo Pandy)
--- a/ChangeLog.API	Wed Jan 28 04:27:01 2009 +0000
+++ b/ChangeLog.API	Wed Jan 28 10:23:37 2009 +0000
@@ -1,5 +1,73 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.6.0 (??/??/????):
+	libpurple:
+		Added:
+		* PURPLE_BLIST_NODE
+		* PURPLE_GROUP
+		* PURPLE_CONTACT
+		* PURPLE_BUDDY
+		* PURPLE_CHAT
+		* purple_buddy_get_protocol_data
+		* purple_buddy_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_connection_get_protocol_data
+		* purple_connection_set_protocol_data
+		* purple_global_proxy_set_info
+		* purple_log_get_activity_score
+		* purple_network_force_online
+		* purple_request_field_get_group
+		* purple_request_field_get_ui_data
+		* purple_request_field_set_ui_data
+		* purple_strequal
+		* xmlnode_from_file
+
+		Deprecated:
+		* purple_buddy_get_local_alias
+		* purple_notify_user_info_remove_entry
+		* purple_status_type_set_primary_attr
+		* purple_status_type_add_attr
+		* purple_status_type_add_attrs
+		* purple_status_type_add_attrs_vargs
+		* purple_status_type_get_primary_attr
+		* purple_status_set_attr_boolean
+		* purple_status_set_attr_int
+		* purple_status_set_attr_string
+		* purple_presence_add_status
+		* purple_presence_add_list
+
+	pidgin:
+		Added:
+		* gtk_imhtml_class_register_protocol
+		* gtk_imhtml_link_get_url, gtk_imhtml_link_get_text_tag,
+		  gtk_imhtml_link_activate functions to process GtkIMHtmlLink
+		  objects from GtkIMHtml protocol callbacks.
+		* gtk_imhtml_set_return_inserts_newline
+		* pidgin_blist_set_theme
+		* pidgin_blist_get_theme
+		* pidgin_sound_is_customized
+		* pidgin_utils_init, pidgin_utils_uninit
+
+	perl:
+		Changed:
+		* Made a bunch of functions act more perl-like. Call the new()
+		  functions as Class->new(...) instead of Class::new(...):
+			* Purple::Request::Fields::new
+			* Purple::Request::Field::new
+			* Purple::Request::Field::account_new
+			* Purple::Request::Field::bool_new
+			* Purple::Request::Field::choice_new
+			* Purple::Request::Field::int_new
+			* Purple::Request::Field::label_new
+			* Purple::Request::Field::list_new
+			* Purple::Request::Field::string_new
+			* Purple::Request::Field::group_new
+
 version 2.5.5 (??/??/2009):
 	libpurple:
 		Changed:
--- a/Makefile.am	Wed Jan 28 04:27:01 2009 +0000
+++ b/Makefile.am	Wed Jan 28 10:23:37 2009 +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 \
--- a/Makefile.mingw	Wed Jan 28 04:27:01 2009 +0000
+++ b/Makefile.mingw	Wed Jan 28 10:23:37 2009 +0000
@@ -2,7 +2,7 @@
 #
 # Author: hermanator12002@yahoo.com
 # Date 9/11/02
-# Description: Top Makefile for win32 (mingw) port of Pidgin and LibPurple
+# Description: Top Makefile for win32 (mingw) port of Pidgin and libpurple
 #
 
 PIDGIN_TREE_TOP := .
--- a/configure.ac	Wed Jan 28 04:27:01 2009 +0000
+++ b/configure.ac	Wed Jan 28 10:23:37 2009 +0000
@@ -1103,6 +1103,7 @@
 		msnp9)		dynamic_msn=yes ;;
 		myspace)	dynamic_myspace=yes ;;
 		novell)		dynamic_novell=yes ;;
+		null)		dynamic_null=yes ;;
 		oscar)		dynamic_oscar=yes ;;
 		aim)		dynamic_oscar=yes ;;
 		icq)		dynamic_oscar=yes ;;
@@ -1117,21 +1118,6 @@
 		*)			echo "Invalid dynamic protocol $i!!" ; exit ;;
 	esac
 done
-AM_CONDITIONAL(DYNAMIC_BONJOUR, test "x$dynamic_bonjour" = "xyes"  -a [ "x$avahiincludes" = "xyes" -a "x$avahilibs " = "xyes" ] )
-AM_CONDITIONAL(DYNAMIC_GG, test "x$dynamic_gg" = "xyes")
-AM_CONDITIONAL(DYNAMIC_IRC, test "x$dynamic_irc" = "xyes")
-AM_CONDITIONAL(DYNAMIC_JABBER, test "x$dynamic_jabber" = "xyes")
-AM_CONDITIONAL(DYNAMIC_MSN, test "x$dynamic_msn" = "xyes")
-AM_CONDITIONAL(DYNAMIC_MYSPACE, test "x$dynamic_myspace" = "xyes")
-AM_CONDITIONAL(DYNAMIC_NOVELL, test "x$dynamic_novell" = "xyes")
-AM_CONDITIONAL(DYNAMIC_OSCAR, test "x$dynamic_oscar" = "xyes")
-AM_CONDITIONAL(DYNAMIC_QQ, test "x$dynamic_qq" = "xyes")
-AM_CONDITIONAL(DYNAMIC_SAMETIME, test "x$dynamic_sametime" = "xyes" -a "x$have_meanwhile" = "xyes")
-AM_CONDITIONAL(DYNAMIC_SILC, test "x$dynamic_silc" = "xyes" -a "x$have_silc" = "xyes")
-AM_CONDITIONAL(DYNAMIC_SIMPLE, test "x$dynamic_simple" = "xyes")
-AM_CONDITIONAL(DYNAMIC_TOC, test "x$dynamic_toc" = "xyes")
-AM_CONDITIONAL(DYNAMIC_YAHOO, test "x$dynamic_yahoo" = "xyes")
-AM_CONDITIONAL(DYNAMIC_ZEPHYR, test "x$dynamic_zephyr" = "xyes")
 
 AC_ARG_ENABLE(plugins, [AC_HELP_STRING([--disable-plugins], [compile without plugin support])], , enable_plugins=yes)
 AC_ARG_WITH(krb4, [AC_HELP_STRING([--with-krb4=PREFIX], [compile Zephyr plugin with Kerberos 4 support])], kerberos="$withval", kerberos="no")
--- a/doc/TCL-HOWTO.dox	Wed Jan 28 04:27:01 2009 +0000
+++ b/doc/TCL-HOWTO.dox	Wed Jan 28 10:23:37 2009 +0000
@@ -332,7 +332,7 @@
 callbacks will live in the namespace @c event underneath that
 namespace.  To briefly illustrate, the signal @c receiving-im-msg is
 provided with three arguments; the account on which the IM was
-received, the screen name of the user sending the IM, and the text of
+received, the name of the buddy sending the IM, and the text of
 the IM.  These arguments live in the variables @c event::account,
 @c event::sender, and @c event::buffer, respectively.  Therefore a callback
 which notifies the user of an incoming IM containing the word 'shizzle'
--- a/doc/notify-signals.dox	Wed Jan 28 04:27:01 2009 +0000
+++ b/doc/notify-signals.dox	Wed Jan 28 10:23:37 2009 +0000
@@ -18,7 +18,7 @@
   @note
     If adding a PurpleNotifyUserInfoEntry, be sure not to free it -- PurpleNotifyUserInfo assumes responsibility for its objects.
   @param account   The account on which the info was obtained.
-  @param who       The screen name of the user whose info is to be displayed.
+  @param who       The name of the buddy whose info is to be displayed.
   @param user_info The information to be displayed, as PurpleNotifyUserInfoEntry objects
  @endsignaldef
 
--- a/doc/pidgin.1.in	Wed Jan 28 04:27:01 2009 +0000
+++ b/doc/pidgin.1.in	Wed Jan 28 10:23:37 2009 +0000
@@ -128,11 +128,11 @@
 .TP
 .B Alias
 Create an alias for this buddy.  This will show an editable text field where
-the buddy's screen name was displayed.  In this field one can give this
+the buddy's name was displayed.  In this field one can give this
 buddy an alternate, more friendly name to appear on the buddy list and in
 conversations.
 
-For example, if a buddy's name screen name was jsmith1281xx and his real
+For example, if a buddy's name was jsmith1281xx and his real
 name was 'John Q. Smith,' one could create an alias as to identify the
 buddy by his common name.
 .LP
@@ -150,7 +150,7 @@
 Clicking \fIDelete\fR will delete the currently selected account.
 Clicking \fIAdd\fR or \fIModify\fR will invoke a \fBModify Account\fR
 window.  Here, the user  can add or alter account information.  When creating
-a new account, the user will submit a screen name and password.  The user will
+a new account, the user will submit a username and password.  The user will
 also choose the protocol for the account.
 
 If \fIRemember Password\fR is chosen, the password will be saved in
@@ -545,7 +545,7 @@
 .br
   \fI~/.purple/status.xml\fR: stores the user's away messages.
 .br
-  \fI~/.purple/logs/PROTOCOL/ACCOUNT/SCREENNAME/DATE.{html,txt}\fR: conversation logs.
+  \fI~/.purple/logs/PROTOCOL/ACCOUNT/BUDDYNAME/DATE.{html,txt}\fR: conversation logs.
 
 .SH DIRECTORIES
   \fI@prefix@/lib/pidgin/\fR: Pidgin's plugins directory.
--- a/finch/gntaccount.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/finch/gntaccount.c	Wed Jan 28 10:23:37 2009 +0000
@@ -65,7 +65,7 @@
 	GntWidget *window;
 
 	GntWidget *protocol;
-	GntWidget *screenname;
+	GntWidget *username;
 	GntWidget *password;
 	GntWidget *alias;
 
@@ -118,8 +118,8 @@
 	plugin = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol));
 	prplinfo = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
 
-	/* Screenname && user-splits */
-	value = gnt_entry_get_text(GNT_ENTRY(dialog->screenname));
+	/* Username && user-splits */
+	value = gnt_entry_get_text(GNT_ENTRY(dialog->username));
 
 	if (value == NULL || *value == '\0')
 	{
@@ -326,7 +326,7 @@
 	}
 
 	if (username != NULL)
-		gnt_entry_set_text(GNT_ENTRY(dialog->screenname), username);
+		gnt_entry_set_text(GNT_ENTRY(dialog->username), username);
 
 	g_free(username);
 }
@@ -546,7 +546,7 @@
 	gnt_box_set_pad(GNT_BOX(hbox), 0);
 	gnt_box_add_widget(GNT_BOX(window), hbox);
 
-	dialog->screenname = entry = gnt_entry_new(NULL);
+	dialog->username = entry = gnt_entry_new(NULL);
 	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Username:")));
 	gnt_box_add_widget(GNT_BOX(hbox), entry);
 
--- a/finch/gntblist.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/finch/gntblist.c	Wed Jan 28 10:23:37 2009 +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)) {
@@ -2415,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/finch/gntconv.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/finch/gntlog.c	Wed Jan 28 10:23:37 2009 +0000
@@ -49,7 +49,7 @@
 
 struct log_viewer_hash_t {
 	PurpleLogType type;
-	char *screenname;
+	char *username;
 	PurpleAccount *account;
 	PurpleContact *contact;
 };
@@ -62,7 +62,7 @@
 		return g_direct_hash(viewer->contact);
 
 	if (viewer->account) {
-		return g_str_hash(viewer->screenname) +
+		return g_str_hash(viewer->username) +
 			g_str_hash(purple_account_get_username(viewer->account));
 	}
 
@@ -88,10 +88,10 @@
 			return FALSE;
 	}
 
-	if (a->screenname && b->screenname) {
-		normal = g_strdup(purple_normalize(a->account, a->screenname));
+	if (a->username && b->username) {
+		normal = g_strdup(purple_normalize(a->account, a->username));
 		ret = (a->account == b->account) &&
-			!strcmp(normal, purple_normalize(b->account, b->screenname));
+			!strcmp(normal, purple_normalize(b->account, b->username));
 		g_free(normal);
 	} else {
 		ret = (a == b);
@@ -155,7 +155,7 @@
 		lv = g_hash_table_lookup(log_viewers, ht);
 		g_hash_table_remove(log_viewers, ht);
 
-		g_free(ht->screenname);
+		g_free(ht->username);
 		g_free(ht);
 	} else
 		syslog_viewer = NULL;
@@ -284,7 +284,7 @@
 				if (!purple_prefs_get_bool("/purple/logging/log_chats"))
 					log_preferences = _("Chats will only be logged if the \"Log all chats\" preference is enabled.");
 			}
-			g_free(ht->screenname);
+			g_free(ht->username);
 			g_free(ht);
 		}
 
@@ -365,31 +365,31 @@
 	*list = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, set->name, set->account), *list);
 }
 
-void finch_log_show(PurpleLogType type, const char *screenname, PurpleAccount *account)
+void finch_log_show(PurpleLogType type, const char *username, PurpleAccount *account)
 {
 	struct log_viewer_hash_t *ht;
 	FinchLogViewer *lv = NULL;
-	const char *name = screenname;
+	const char *name = username;
 	char *title;
 	GList *logs = NULL;
 	int size = 0;
 
 	if (type != PURPLE_LOG_IM) {
 		g_return_if_fail(account != NULL);
-		g_return_if_fail(screenname != NULL);
+		g_return_if_fail(username != NULL);
 	}
 
 	ht = g_new0(struct log_viewer_hash_t, 1);
 
 	ht->type = type;
-	ht->screenname = g_strdup(screenname);
+	ht->username = g_strdup(username);
 	ht->account = account;
 
 	if (log_viewers == NULL) {
 		log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal);
 	} else if ((lv = g_hash_table_lookup(log_viewers, ht))) {
 		gnt_window_present(lv->window);
-		g_free(ht->screenname);
+		g_free(ht->username);
 		g_free(ht);
 		return;
 	}
@@ -397,7 +397,7 @@
 	if (type == PURPLE_LOG_CHAT) {
 		PurpleChat *chat;
 
-		chat = purple_blist_find_chat(account, screenname);
+		chat = purple_blist_find_chat(account, username);
 		if (chat != NULL)
 			name = purple_chat_get_name(chat);
 
@@ -405,8 +405,8 @@
 	} else {
 		PurpleBuddy *buddy;
 
-		if (screenname) {
-			buddy = purple_find_buddy(account, screenname);
+		if (username) {
+			buddy = purple_find_buddy(account, username);
 			if (buddy != NULL)
 				name = purple_buddy_get_contact_alias(buddy);
 			title = g_strdup_printf(_("Conversations with %s"), name);
@@ -415,9 +415,9 @@
 		}
 	}
 
-	if (screenname) {
-		logs = purple_log_get_logs(type, screenname, account);
-		size = purple_log_get_total_size(type, screenname, account);
+	if (username) {
+		logs = purple_log_get_logs(type, username, account);
+		size = purple_log_get_total_size(type, username, account);
 	} else {
 		/* This will happen only for IMs */
 		GHashTable *table = purple_log_get_log_sets();
@@ -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/gntlog.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/finch/gntlog.h	Wed Jan 28 10:23:37 2009 +0000
@@ -50,7 +50,7 @@
 
 
 
-void finch_log_show(PurpleLogType type, const char *screenname, PurpleAccount *account);
+void finch_log_show(PurpleLogType type, const char *username, PurpleAccount *account);
 void finch_log_show_contact(PurpleContact *contact);
 
 void finch_syslog_show(void);
--- a/finch/gntrequest.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/finch/gntrequest.c	Wed Jan 28 10:23:37 2009 +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;
@@ -393,11 +399,11 @@
 }
 
 static void
-update_selected_account(GntEntry *screenname, const char *start, const char *end,
+update_selected_account(GntEntry *username, const char *start, const char *end,
 		GntComboBox *accountlist)
 {
 	GList *accounts = gnt_tree_get_rows(GNT_TREE(accountlist->dropdown));
-	const char *name = gnt_entry_get_text(screenname);
+	const char *name = gnt_entry_get_text(username);
 	while (accounts) {
 		if (purple_find_buddy(accounts->data, name)) {
 			gnt_combo_box_set_selected(accountlist, accounts->data);
@@ -419,7 +425,7 @@
 }
 
 static GntWidget*
-create_string_field(PurpleRequestField *field, GntWidget **screenname)
+create_string_field(PurpleRequestField *field, GntWidget **username)
 {
 	const char *hint = purple_request_field_get_type_hint(field);
 	GntWidget *entry = gnt_entry_new(
@@ -435,8 +441,8 @@
 			gnt_entry_add_suggest(GNT_ENTRY(entry), purple_buddy_get_name((PurpleBuddy*)node));
 		}
 		gnt_entry_set_always_suggest(GNT_ENTRY(entry), TRUE);
-		if (screenname)
-			*screenname = entry;
+		if (username)
+			*username = entry;
 	} else if (hint && !strcmp(hint, "group")) {
 		PurpleBlistNode *node;
 		for (node = purple_blist_get_root(); node;
@@ -569,7 +575,7 @@
 {
 	GntWidget *window, *box;
 	GList *grlist;
-	GntWidget *screenname = NULL, *accountlist = NULL;
+	GntWidget *username = NULL, *accountlist = NULL;
 
 	window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_FIELDS);
 
@@ -617,7 +623,7 @@
 			}
 			else if (type == PURPLE_REQUEST_FIELD_STRING)
 			{
-				FINCH_SET_DATA(field, create_string_field(field, &screenname));
+				FINCH_SET_DATA(field, create_string_field(field, &username));
 			}
 			else if (type == PURPLE_REQUEST_FIELD_INTEGER)
 			{
@@ -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
 			{
@@ -655,8 +662,8 @@
 	setup_default_callback(window, cancel_cb, userdata);
 	gnt_widget_show(window);
 
-	if (screenname && accountlist) {
-		g_signal_connect(screenname, "completion", G_CALLBACK(update_selected_account), accountlist);
+	if (username && accountlist) {
+		g_signal_connect(username, "completion", G_CALLBACK(update_selected_account), accountlist);
 	}
 
 	g_object_set_data(G_OBJECT(window), "fields", allfields);
--- a/finch/plugins/grouping.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/finch/plugins/grouping.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/Makefile.am	Wed Jan 28 10:23:37 2009 +0000
@@ -75,7 +75,12 @@
 	stringref.c \
 	stun.c \
 	sound.c \
+	sound-theme.c \
+	sound-theme-loader.c \
 	sslconn.c \
+	theme.c \
+	theme-loader.c \
+	theme-manager.c \
 	upnp.c \
 	util.c \
 	value.c \
@@ -128,7 +133,12 @@
 	stringref.h \
 	stun.h \
 	sound.h \
+	sound-theme.h \
+	sound-theme-loader.h \
 	sslconn.h \
+	theme.h \
+	theme-loader.h \
+	theme-manager.h \
 	upnp.h \
 	util.h \
 	value.h \
--- a/libpurple/Makefile.mingw	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/Makefile.mingw	Wed Jan 28 10:23:37 2009 +0000
@@ -1,7 +1,7 @@
 #
 # Makefile.mingw
 #
-# Description: Makefile for win32 (mingw) version of LibPurple
+# Description: Makefile for win32 (mingw) version of libpurple
 #
 
 PIDGIN_TREE_TOP := ..
@@ -67,10 +67,15 @@
 			signals.c \
 			smiley.c \
 			sound.c \
+			sound-theme.c \
+			sound-theme-loader.c \
 			sslconn.c \
 			status.c \
 			stringref.c \
 			stun.c \
+			theme.c \
+			theme-loader.c \
+			theme-manager.c \
 			upnp.c \
 			util.c \
 			value.c \
--- a/libpurple/account.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/account.c	Wed Jan 28 10:23:37 2009 +0000
@@ -178,9 +178,7 @@
 	{
 		const char *string_value = purple_value_get_string(attr_value);
 		const char *default_string_value = purple_value_get_string(default_value);
-		if (((string_value == NULL) && (default_string_value == NULL)) ||
-			((string_value != NULL) && (default_string_value != NULL) &&
-			 !strcmp(string_value, default_string_value)))
+		if (purple_strequal(string_value, default_string_value))
 			return NULL;
 		value = g_strdup(purple_value_get_string(attr_value));
 	}
@@ -511,11 +509,11 @@
 			/* Ignore this setting */
 			continue;
 
-		if (!strcmp(str_type, "string"))
+		if (purple_strequal(str_type, "string"))
 			type = PURPLE_PREF_STRING;
-		else if (!strcmp(str_type, "int"))
+		else if (purple_strequal(str_type, "int"))
 			type = PURPLE_PREF_INT;
-		else if (!strcmp(str_type, "bool"))
+		else if (purple_strequal(str_type, "bool"))
 			type = PURPLE_PREF_BOOLEAN;
 		else
 			/* Ignore this setting */
@@ -660,17 +658,17 @@
 	child = xmlnode_get_child(node, "type");
 	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
 	{
-		if (!strcmp(data, "global"))
+		if (purple_strequal(data, "global"))
 			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_GLOBAL);
-		else if (!strcmp(data, "none"))
+		else if (purple_strequal(data, "none"))
 			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_NONE);
-		else if (!strcmp(data, "http"))
+		else if (purple_strequal(data, "http"))
 			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_HTTP);
-		else if (!strcmp(data, "socks4"))
+		else if (purple_strequal(data, "socks4"))
 			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_SOCKS4);
-		else if (!strcmp(data, "socks5"))
+		else if (purple_strequal(data, "socks5"))
 			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_SOCKS5);
-		else if (!strcmp(data, "envvar"))
+		else if (purple_strequal(data, "envvar"))
 			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_ENVVAR);
 		else
 		{
@@ -2027,7 +2025,7 @@
 	{
 		PurpleStatusType *status_type = (PurpleStatusType *)l->data;
 
-		if (!strcmp(purple_status_type_get_id(status_type), id))
+		if (purple_strequal(purple_status_type_get_id(status_type), id))
 			return status_type;
 	}
 
@@ -2238,9 +2236,9 @@
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleConnection *gc = purple_account_get_connection(account);
 	PurplePlugin *prpl = NULL;
-	
+
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);      
+	        prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
@@ -2255,20 +2253,20 @@
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleConnection *gc = purple_account_get_connection(account);
 	PurplePlugin *prpl = NULL;
-	
+
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);      
+	        prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-		
+
 	if (prpl_info) {
 		GList *cur, *groups = NULL;
 
 		/* 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)
@@ -2294,13 +2292,13 @@
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleConnection *gc = purple_account_get_connection(account);
 	PurplePlugin *prpl = NULL;
-	
+
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);      
+	        prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-		
+
 	if (prpl_info && prpl_info->remove_buddy)
 		prpl_info->remove_buddy(gc, buddy, group);
 }
@@ -2311,13 +2309,13 @@
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleConnection *gc = purple_account_get_connection(account);
 	PurplePlugin *prpl = NULL;
-	
+
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);      
+	        prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-		
+
 	if (prpl_info) {
 		if (prpl_info->remove_buddies)
 			prpl_info->remove_buddies(gc, buddies, groups);
@@ -2339,9 +2337,9 @@
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleConnection *gc = purple_account_get_connection(account);
 	PurplePlugin *prpl = NULL;
-	
+
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);      
+	        prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
@@ -2357,11 +2355,11 @@
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleConnection *gc = purple_account_get_connection(account);
 	PurplePlugin *prpl = NULL;
-	
+
 	purple_account_set_password(account, new_pw);
-	
+
 	if (gc != NULL)
-	        prpl = purple_connection_get_prpl(gc);      
+	        prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
@@ -2375,15 +2373,15 @@
 	PurpleConnection *gc;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurplePlugin *prpl = NULL;
-	
+
 	g_return_val_if_fail(account, FALSE);
 	g_return_val_if_fail(buddy, FALSE);
 
 	gc = purple_account_get_connection(account);
 	if (gc == NULL)
 		return FALSE;
-	
-	prpl = purple_connection_get_prpl(gc);      
+
+	prpl = purple_connection_get_prpl(gc);
 
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
@@ -2518,23 +2516,26 @@
 	purple_accounts_remove(account);
 
 	/* Remove this account's buddies */
-	for (gnode = purple_blist_get_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;
@@ -2542,7 +2543,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;
@@ -2633,11 +2634,11 @@
 
 	for (l = purple_accounts_get_all(); l != NULL; l = l->next) {
 		account = (PurpleAccount *)l->data;
-		if (protocol_id && strcmp(account->protocol_id, protocol_id))
+		if (protocol_id && !purple_strequal(account->protocol_id, protocol_id))
 		  continue;
 
 		who = g_strdup(purple_normalize(account, name));
-		if (!strcmp(purple_normalize(account, purple_account_get_username(account)), who)) {
+		if (purple_strequal(purple_normalize(account, purple_account_get_username(account)), who)) {
 			g_free(who);
 			return account;
 		}
--- a/libpurple/account.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/account.h	Wed Jan 28 10:23:37 2009 +0000
@@ -253,7 +253,7 @@
  * Notifies the user that a remote user has wants to add the local user
  * to his or her buddy list and requires authorization to do so.
  *
- * This will present a dialog informing the user of this and ask if the 
+ * This will present a dialog informing the user of this and ask if the
  * user authorizes or denies the remote user from adding him.
  *
  * @param account      The account that was added
--- a/libpurple/blist.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/blist.c	Wed Jan 28 10:23:37 2009 +0000
@@ -82,7 +82,7 @@
 
 static guint _purple_blist_hbuddy_equal(struct _purple_hbuddy *hb1, struct _purple_hbuddy *hb2)
 {
-	return ((!strcmp(hb1->name, hb2->name)) && hb1->account == hb2->account && hb1->group == hb2->group);
+	return (purple_strequal(hb1->name, hb2->name) && hb1->account == hb2->account && hb1->group == hb2->group);
 }
 
 static void _purple_blist_hbuddy_free_key(struct _purple_hbuddy *hb)
@@ -382,11 +382,11 @@
 	if (!value)
 		return;
 
-	if (!type || !strcmp(type, "string"))
+	if (!type || purple_strequal(type, "string"))
 		purple_blist_node_set_string(node, name, value);
-	else if (!strcmp(type, "bool"))
+	else if (purple_strequal(type, "bool"))
 		purple_blist_node_set_bool(node, name, atoi(value));
-	else if (!strcmp(type, "int"))
+	else if (purple_strequal(type, "int"))
 		purple_blist_node_set_int(node, name, atoi(value));
 
 	g_free(value);
@@ -453,9 +453,9 @@
 	for (x = cnode->child; x; x = x->next) {
 		if (x->type != XMLNODE_TYPE_TAG)
 			continue;
-		if (!strcmp(x->name, "buddy"))
+		if (purple_strequal(x->name, "buddy"))
 			parse_buddy(group, contact, x);
-		else if (!strcmp(x->name, "setting"))
+		else if (purple_strequal(x->name, "setting"))
 			parse_setting((PurpleBlistNode*)contact, x);
 	}
 
@@ -528,12 +528,12 @@
 	for (cnode = groupnode->child; cnode; cnode = cnode->next) {
 		if (cnode->type != XMLNODE_TYPE_TAG)
 			continue;
-		if (!strcmp(cnode->name, "setting"))
+		if (purple_strequal(cnode->name, "setting"))
 			parse_setting((PurpleBlistNode*)group, cnode);
-		else if (!strcmp(cnode->name, "contact") ||
-				!strcmp(cnode->name, "person"))
+		else if (purple_strequal(cnode->name, "contact") ||
+				purple_strequal(cnode->name, "person"))
 			parse_contact(group, cnode);
-		else if (!strcmp(cnode->name, "chat"))
+		else if (purple_strequal(cnode->name, "chat"))
 			parse_chat(group, cnode);
 	}
 }
@@ -590,11 +590,11 @@
 				if (x->type != XMLNODE_TYPE_TAG)
 					continue;
 
-				if (!strcmp(x->name, "permit")) {
+				if (purple_strequal(x->name, "permit")) {
 					name = xmlnode_get_data(x);
 					purple_privacy_permit_add(account, name, TRUE);
 					g_free(name);
-				} else if (!strcmp(x->name, "block")) {
+				} else if (purple_strequal(x->name, "block")) {
 					name = xmlnode_get_data(x);
 					purple_privacy_deny_add(account, name, TRUE);
 					g_free(name);
@@ -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,
@@ -1025,7 +1061,7 @@
 	g_return_if_fail(source != NULL);
 	g_return_if_fail(new_name != NULL);
 
-	if (*new_name == '\0' || !strcmp(new_name, source->name))
+	if (*new_name == '\0' || purple_strequal(new_name, source->name))
 		return;
 
 	dest = purple_find_group(new_name);
@@ -1092,7 +1128,7 @@
 
 	/* Notify all PRPLs */
 	/* TODO: Is this condition needed?  Seems like it would always be TRUE */
-	if(old_name && source && strcmp(source->name, old_name)) {
+	if(old_name && purple_strequal(source->name, old_name)) {
 		for (accts = purple_group_get_accounts(source); accts; accts = g_slist_remove(accts, accts->data)) {
 			PurpleAccount *account = accts->data;
 			PurpleConnection *gc = NULL;
@@ -1101,7 +1137,7 @@
 			GList *l = NULL, *buddies = NULL;
 
 			gc = purple_account_get_connection(account);
-			
+
 			if(gc)
 				prpl = purple_connection_get_prpl(gc);
 
@@ -1166,17 +1202,17 @@
 	return chat;
 }
 
-PurpleBuddy *purple_buddy_new(PurpleAccount *account, const char *screenname, const char *alias)
+PurpleBuddy *purple_buddy_new(PurpleAccount *account, const char *name, const char *alias)
 {
 	PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
 	PurpleBuddy *buddy;
 
 	g_return_val_if_fail(account != NULL, FALSE);
-	g_return_val_if_fail(screenname != NULL, FALSE);
+	g_return_val_if_fail(name != NULL, FALSE);
 
 	buddy = g_new0(PurpleBuddy, 1);
 	buddy->account  = account;
-	buddy->name     = g_strdup(screenname);
+	buddy->name     = g_strdup(name);
 	buddy->alias    = g_strdup(alias);
 	buddy->presence = purple_presence_new_for_buddy(buddy);
 	((PurpleBlistNode *)buddy)->type = PURPLE_BLIST_BUDDY_NODE;
@@ -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) ||
@@ -2056,6 +2107,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);
@@ -2300,7 +2357,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/blist.h	Wed Jan 28 10:23:37 2009 +0000
@@ -75,12 +75,37 @@
 
 } PurpleBlistNodeFlags;
 
+/**
+ * @since 2.6.0
+ */
+#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)
 
+/**
+ * @since 2.6.0
+ */
+#define PURPLE_GROUP(obj) ((PurpleGroup *)(obj))
+
+/**
+ * @since 2.6.0
+ */
+#define PURPLE_CONTACT(obj) ((PurpleContact *)(obj))
+
+/**
+ * @since 2.6.0
+ */
+#define PURPLE_BUDDY(obj) ((PurpleBuddy *)(obj))
+
+/**
+ * @since 2.6.0
+ */
+#define PURPLE_CHAT(obj) ((PurpleChat *)(obj))
+
 #include "account.h"
 #include "buddyicon.h"
 #include "status.h"
@@ -111,7 +136,7 @@
  */
 struct _PurpleBuddy {
 	PurpleBlistNode node;                     /**< The node that this buddy inherits from */
-	char *name;                             /**< The screenname of the buddy. */
+	char *name;                             /**< The name of the buddy. */
 	char *alias;                            /**< The user-set alias of the buddy */
 	char *server_alias;                     /**< The server-specified alias of the buddy.  (i.e. MSN "Friendly Names") */
 	void *proto_data;                       /**< This allows the prpl to associate whatever data it wants with a buddy */
@@ -156,9 +181,6 @@
 	PurpleAccount *account; /**< The account this chat is attached to */
 };
 
-#endif /* PURPLE_HIDE_STRUCTS && PURPLE_BLIST_STRUCTS */
-
-
 /**
  * The Buddy List
  */
@@ -168,6 +190,8 @@
 	void *ui_data;                /**< UI-specific data. */
 };
 
+#endif /* PURPLE_HIDE_STRUCTS && PURPLE_BLIST_STRUCTS */
+
 /**
  * Buddy list UI operations.
  *
@@ -236,6 +260,33 @@
 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 +353,25 @@
 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);
@@ -331,6 +401,7 @@
  * Updates a node's custom icon.
  *
  * @param node  The PurpleBlistNode whose custom icon has changed.
+ *
  * @since 2.5.0
  */
 void purple_blist_update_node_icon(PurpleBlistNode *node);
@@ -423,11 +494,11 @@
  * Creates a new buddy
  *
  * @param account    The account this buddy will get added to
- * @param screenname The screenname of the new buddy
+ * @param name       The name of the new buddy
  * @param alias      The alias of the new buddy (or NULL if unaliased)
  * @return           A newly allocated buddy
  */
-PurpleBuddy *purple_buddy_new(PurpleAccount *account, const char *screenname, const char *alias);
+PurpleBuddy *purple_buddy_new(PurpleAccount *account, const char *name, const char *alias);
 
 /**
  * Sets a buddy's icon.
@@ -470,6 +541,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,15 +756,18 @@
  */
 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
  * contact alias; buddy's user name.
- * 
+ *
  * @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 +780,16 @@
 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.
@@ -688,19 +798,19 @@
 const char *purple_chat_get_name(PurpleChat *chat);
 
 /**
- * Finds the buddy struct given a screenname and an account
+ * Finds the buddy struct given a name and an account
  *
  * @param account The account this buddy belongs to
- * @param name    The buddy's screenname
+ * @param name    The buddy's name
  * @return        The buddy or NULL if the buddy does not exist
  */
 PurpleBuddy *purple_find_buddy(PurpleAccount *account, const char *name);
 
 /**
- * Finds the buddy struct given a screenname, an account, and a group
+ * Finds the buddy struct given a name, an account, and a group
  *
  * @param account The account this buddy belongs to
- * @param name    The buddy's screenname
+ * @param name    The buddy's name
  * @param group   The group to look in
  * @return        The buddy or NULL if the buddy does not exist in the group
  */
@@ -708,10 +818,10 @@
 		PurpleGroup *group);
 
 /**
- * Finds all PurpleBuddy structs given a screenname and an account
+ * Finds all PurpleBuddy structs given a name and an account
  *
  * @param account The account this buddy belongs to
- * @param name    The buddy's screenname (or NULL to return all buddies in the account)
+ * @param name    The buddy's name (or NULL to return all buddies in the account)
  *
  * @return        A GSList of buddies (which must be freed), or NULL if the buddy doesn't exist
  */
@@ -751,6 +861,7 @@
  * @param chat  The chat.
  *
  * @return  The account the chat belongs to.
+ *
  * @since 2.4.0
  */
 PurpleAccount *purple_chat_get_account(PurpleChat *chat);
@@ -761,6 +872,7 @@
  * @param chat  The chat.
  *
  * @constreturn  The hashtable.
+ *
  * @since 2.4.0
  */
 GHashTable *purple_chat_get_components(PurpleChat *chat);
@@ -979,6 +1091,7 @@
  * @param node The node.
  *
  * @return The type of the node.
+ *
  * @since 2.1.0
  */
 PurpleBlistNodeType purple_blist_node_get_type(PurpleBlistNode *node);
--- a/libpurple/buddyicon.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/buddyicon.c	Wed Jan 28 10:23:37 2009 +0000
@@ -153,7 +153,7 @@
 {
 	const char *dirname;
 	char *path;
-	
+
 	g_return_if_fail(img != NULL);
 
 	if (!purple_buddy_icons_is_caching())
@@ -175,7 +175,7 @@
 	}
 
 	purple_util_write_data_to_file_absolute(path, purple_imgstore_get_data(img),
-											purple_imgstore_get_size(img));	
+											purple_imgstore_get_size(img));
 	g_free(path);
 }
 
@@ -453,7 +453,7 @@
 
 	if (conv != NULL)
 		purple_conv_im_set_icon(PURPLE_CONV_IM(conv), icon_to_set);
-	
+
 	/* icon's refcount was incremented above */
 	if (icon) purple_buddy_icon_unref(icon);
 }
@@ -757,7 +757,7 @@
 		g_hash_table_insert(pointer_icon_cache, account, img);
 	else
 		g_hash_table_remove(pointer_icon_cache, account);
-	
+
 	if (purple_account_is_connected(account))
 	{
 		PurpleConnection *gc;
@@ -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;
@@ -986,7 +988,7 @@
 {
 	purple_blist_node_remove_setting(node, setting_name);
 
-	if (!strcmp(setting_name, "buddy_icon"))
+	if (purple_strequal(setting_name, "buddy_icon"))
 	{
 		purple_blist_node_remove_setting(node, "avatar_hash");
 		purple_blist_node_remove_setting(node, "icon_checksum");
@@ -1083,7 +1085,7 @@
 
 		g_free(new_filename);
 
-		if (!strcmp(setting_name, "buddy_icon"))
+		if (purple_strequal(setting_name, "buddy_icon"))
 		{
 			const char *hash;
 
@@ -1098,7 +1100,7 @@
 				PurpleAccount *account = purple_buddy_get_account((PurpleBuddy *)node);
 				const char *prpl_id = purple_account_get_protocol_id(account);
 
-				if (!strcmp(prpl_id, "prpl-yahoo"))
+				if (purple_strequal(prpl_id, "prpl-yahoo"))
 				{
 					int checksum = purple_blist_node_get_int(node, "icon_checksum");
 					if (checksum != 0)
--- a/libpurple/certificate.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/certificate.c	Wed Jan 28 10:23:37 2009 +0000
@@ -51,7 +51,7 @@
 {
 	PurpleCertificateVerificationRequest *vrq;
 	PurpleCertificateScheme *scheme;
-	
+
 	g_return_if_fail(subject_name != NULL);
 	/* If you don't have a cert to check, why are you requesting that it
 	   be verified? */
@@ -97,10 +97,10 @@
 				  "Failed to verify certificate for %s\n",
 				  vrq->subject_name);
 	}
-		
-		
-		
-	
+
+
+
+
 	/* Pass the results on to the request's callback */
 	(vrq->cb)(st, vrq->cb_data);
 
@@ -154,7 +154,7 @@
 purple_certificate_destroy (PurpleCertificate *crt)
 {
 	PurpleCertificateScheme *scheme;
-	
+
 	if (NULL == crt) return;
 
 	scheme = crt->scheme;
@@ -206,7 +206,7 @@
 			  "Checking signature chain for uid=%s\n",
 			  uid);
 	g_free(uid);
-	
+
 	/* If this is a single-certificate chain, say that it is valid */
 	if (chain->next == NULL) {
 		purple_debug_info("certificate",
@@ -218,9 +218,9 @@
 	crt = (PurpleCertificate *)(chain->data);
 	/* And start with the second certificate in the chain */
 	for ( cur = chain->next; cur; cur = cur->next ) {
-		
+
 		issuer = (PurpleCertificate *)(cur->data);
-		
+
 		/* Check the signature for this link */
 		if (! purple_certificate_signed_by(crt, issuer) ) {
 			uid = purple_certificate_get_unique_id(issuer);
@@ -228,7 +228,7 @@
 					  "...Bad or missing signature by %s\nChain is INVALID\n",
 					  uid);
 			g_free(uid);
-		
+
 			return FALSE;
 		}
 
@@ -237,7 +237,7 @@
 				  "...Good signature by %s\n",
 				  uid);
 		g_free(uid);
-		
+
 		/* The issuer is now the next crt whose signature is to be
 		   checked */
 		crt = issuer;
@@ -283,7 +283,7 @@
 	g_return_val_if_fail(crt->scheme, NULL);
 
 	scheme = crt->scheme;
-	
+
 	g_return_val_if_fail(scheme->get_fingerprint_sha1, NULL);
 
 	fpr = (scheme->get_fingerprint_sha1)(crt);
@@ -354,7 +354,7 @@
 	g_return_val_if_fail(crt, FALSE);
 
 	scheme = crt->scheme;
-	
+
 	g_return_val_if_fail(scheme, FALSE);
 
 	/* If both provided references are NULL, what are you doing calling
@@ -371,7 +371,7 @@
 {
 	gchar *path;
 	gchar *esc_scheme_name, *esc_name, *esc_id;
-	
+
 	g_return_val_if_fail(pool, NULL);
 	g_return_val_if_fail(pool->scheme_name, NULL);
 	g_return_val_if_fail(pool->name, NULL);
@@ -380,7 +380,7 @@
 	esc_scheme_name = pool ? g_strdup(purple_escape_filename(pool->scheme_name)) : NULL;
 	esc_name = pool ? g_strdup(purple_escape_filename(pool->name)) : NULL;
 	esc_id = id ? g_strdup(purple_escape_filename(id)) : NULL;
-	
+
 	path = g_build_filename(purple_user_dir(),
 				"certificates", /* TODO: constantize this? */
 				esc_scheme_name,
@@ -404,7 +404,7 @@
 	if (purple_certificate_find_scheme(pool->scheme_name) == NULL) {
 		return FALSE;
 	}
-	
+
 	return TRUE;
 }
 
@@ -441,7 +441,7 @@
 purple_certificate_pool_store(PurpleCertificatePool *pool, const gchar *id, PurpleCertificate *crt)
 {
 	gboolean ret = FALSE;
-	
+
 	g_return_val_if_fail(pool, FALSE);
 	g_return_val_if_fail(id, FALSE);
 	g_return_val_if_fail(pool->put_cert, FALSE);
@@ -461,13 +461,13 @@
 	}
 
 	return ret;
-}	
+}
 
 gboolean
 purple_certificate_pool_delete(PurpleCertificatePool *pool, const gchar *id)
 {
 	gboolean ret = FALSE;
-	
+
 	g_return_val_if_fail(pool, FALSE);
 	g_return_val_if_fail(id, FALSE);
 	g_return_val_if_fail(pool->delete_cert, FALSE);
@@ -496,7 +496,7 @@
 purple_certificate_pool_destroy_idlist(GList *idlist)
 {
 	GList *l;
-	
+
 	/* Iterate through and free them strings */
 	for ( l = idlist; l; l = l->next ) {
 		g_free(l->data);
@@ -520,7 +520,7 @@
 			  vrq->subject_name, id);
 
 	/* Signal what happened back to the caller */
-	if (1 == id) {		
+	if (1 == id) {
 		/* Accepted! */
 		purple_certificate_verify_complete(vrq,
 						   PURPLE_CERTIFICATE_VALID);
@@ -557,11 +557,11 @@
 	} else {
 		cn_match = _("(DOES NOT MATCH)");
 	}
-	
+
 	/* Make messages */
 	primary = g_strdup_printf(_("%s has presented the following certificate for just-this-once use:"), vrq->subject_name);
 	secondary = g_strdup_printf(_("Common name: %s %s\nFingerprint (SHA1): %s"), cn, cn_match, sha_asc);
-	
+
 	/* Make a semi-pretty display */
 	purple_request_accept_cancel(
 		vrq->cb_data, /* TODO: Find what the handle ought to be */
@@ -575,7 +575,7 @@
 		vrq,
 		x509_singleuse_verify_cb,
 		x509_singleuse_verify_cb );
-	
+
 	/* Cleanup */
 	g_free(primary);
 	g_free(secondary);
@@ -644,13 +644,13 @@
 
 	/* lazy_init calls this function, so calling lazy_init here is a
 	   Bad Thing */
-	
+
 	g_return_val_if_fail(crt, FALSE);
 	g_return_val_if_fail(crt->scheme, FALSE);
 	/* Make sure that this is some kind of X.509 certificate */
 	/* TODO: Perhaps just check crt->scheme->name instead? */
 	g_return_val_if_fail(crt->scheme == purple_certificate_find_scheme(x509_ca.scheme_name), FALSE);
-	
+
 	el = g_new0(x509_ca_element, 1);
 	el->dn = purple_certificate_get_unique_id(crt);
 	el->crt = purple_certificate_copy(crt);
@@ -675,7 +675,7 @@
 	const gchar *entry;
 	GPatternSpec *pempat;
 	GList *iter = NULL;
-	
+
 	if (x509_ca_initialized) return TRUE;
 
 	/* Check that X.509 is registered */
@@ -791,7 +791,7 @@
 
 	for (cur = lst; cur; cur = cur->next) {
 		x509_ca_element *el = cur->data;
-		if (el->dn && !strcmp(dn, el->dn)) {
+		if (purple_strequal(dn, el->dn)) {
 			return el;
 		}
 	}
@@ -832,7 +832,7 @@
 	} else {
 		crt = NULL;
 	}
-	
+
 	return crt;
 }
 
@@ -840,7 +840,7 @@
 x509_ca_put_cert(const gchar *id, PurpleCertificate *crt)
 {
 	gboolean ret = FALSE;
-	
+
 	g_return_val_if_fail(x509_ca_lazy_init(), FALSE);
 
 	/* TODO: This is a quick way of doing this. At some point the change
@@ -854,7 +854,7 @@
 x509_ca_delete_cert(const gchar *id)
 {
 	x509_ca_element *el;
-	
+
 	g_return_val_if_fail(x509_ca_lazy_init(), FALSE);
 	g_return_val_if_fail(id, FALSE);
 
@@ -870,7 +870,7 @@
 	/* Unlink it from the memory cache and destroy it */
 	x509_ca_certs = g_list_remove(x509_ca_certs, el);
 	x509_ca_element_free(el);
-	
+
 	return TRUE;
 }
 
@@ -878,7 +878,7 @@
 x509_ca_get_idlist(void)
 {
 	GList *l, *idlist;
-	
+
 	g_return_val_if_fail(x509_ca_lazy_init(), NULL);
 
 	idlist = NULL;
@@ -886,7 +886,7 @@
 		x509_ca_element *el = l->data;
 		idlist = g_list_prepend(idlist, g_strdup(el->dn));
 	}
-	
+
 	return idlist;
 }
 
@@ -921,7 +921,7 @@
 {
 	gchar *poolpath;
 	int ret;
-	
+
 	/* Set up key cache here if it isn't already done */
 	poolpath = purple_certificate_pool_mkpath(&x509_tls_peers, NULL);
 	ret = purple_build_dir(poolpath, 0700); /* Make it this user only */
@@ -937,13 +937,13 @@
 {
 	gchar *keypath;
 	gboolean ret = FALSE;
-	
+
 	g_return_val_if_fail(id, FALSE);
 
 	keypath = purple_certificate_pool_mkpath(&x509_tls_peers, id);
 
 	ret = g_file_test(keypath, G_FILE_TEST_IS_REGULAR);
-	
+
 	g_free(keypath);
 	return ret;
 }
@@ -954,14 +954,14 @@
 	PurpleCertificateScheme *x509;
 	PurpleCertificate *crt;
 	gchar *keypath;
-	
+
 	g_return_val_if_fail(id, NULL);
 
 	/* Is it in the pool? */
 	if ( !x509_tls_peers_cert_in_pool(id) ) {
 		return NULL;
 	}
-	
+
 	/* Look up the X.509 scheme */
 	x509 = purple_certificate_find_scheme("x509");
 	g_return_val_if_fail(x509, NULL);
@@ -990,7 +990,7 @@
 	/* Work out the filename and export */
 	keypath = purple_certificate_pool_mkpath(&x509_tls_peers, id);
 	ret = purple_certificate_export(keypath, crt);
-	
+
 	g_free(keypath);
 	return ret;
 }
@@ -1012,7 +1012,7 @@
 	}
 
 	/* OK, so work out the keypath and delete the thing */
-	keypath = purple_certificate_pool_mkpath(&x509_tls_peers, id);	
+	keypath = purple_certificate_pool_mkpath(&x509_tls_peers, id);
 	if ( unlink(keypath) != 0 ) {
 		purple_debug_error("certificate/tls_peers",
 				   "Unlink of %s failed!\n",
@@ -1047,7 +1047,7 @@
 	while ( (entry = g_dir_read_name(dir)) != NULL ) {
 		/* Unescape the filename */
 		const char *unescaped = purple_unescape_filename(entry);
-		
+
 		/* Copy the entry name into our list (GLib owns the original
 		   string) */
 		idlist = g_list_prepend(idlist, g_strdup(unescaped));
@@ -1055,7 +1055,7 @@
 
 	/* Release the directory */
 	g_dir_close(dir);
-	
+
 	return idlist;
 }
 
@@ -1143,7 +1143,7 @@
 
 	g_return_if_fail(c);
 	g_return_if_fail(c->vrq);
-	
+
 	vrq = c->vrq;
 
 	x509_tls_cached_ua_ctx_free(c);
@@ -1155,7 +1155,7 @@
 		purple_debug_info("certificate/x509/tls_cached",
 				  "User ACCEPTED cert\nCaching first in chain for future use as %s...\n",
 				  cache_id);
-		
+
 		purple_certificate_pool_store(tls_peers, cache_id,
 					      vrq->cert_chain->data);
 
@@ -1195,7 +1195,7 @@
 	/* Make messages */
 	primary = g_strdup_printf(_("Accept certificate for %s?"),
 				  vrq->subject_name);
-		
+
 	/* Make a semi-pretty display */
 	purple_request_action(
 		vrq->cb_data, /* TODO: Find what the handle ought to be */
@@ -1211,7 +1211,7 @@
 		_("Accept"), x509_tls_cached_user_auth_accept_cb,
 		_("Reject"),  x509_tls_cached_user_auth_reject_cb,
 		_("_View Certificate..."), x509_tls_cached_show_cert);
-	
+
 	/* Cleanup */
 	g_free(primary);
 }
@@ -1225,7 +1225,7 @@
 			  "Certificate for %s does not match cached. "
 			  "Auto-rejecting!\n",
 			  vrq->subject_name);
-	
+
 	purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID);
 	return;
 }
@@ -1245,7 +1245,7 @@
 	/* The peer's certificate should be the first in the list */
 	PurpleCertificate *peer_crt =
 		(PurpleCertificate *) vrq->cert_chain->data;
-	
+
 	PurpleCertificate *cached_crt;
 	GByteArray *peer_fpr, *cached_fpr;
 
@@ -1278,7 +1278,7 @@
 		/* vrq now becomes the problem of the user */
 		x509_tls_cached_unknown_peer(vrq);
 	}
-	
+
 	purple_certificate_destroy(cached_crt);
 	g_byte_array_free(peer_fpr, TRUE);
 	g_byte_array_free(cached_fpr, TRUE);
@@ -1305,7 +1305,7 @@
 	   "not self-signed" */
 	if ( purple_certificate_signed_by(peer_crt, peer_crt) ) {
 		gchar *msg;
-		
+
 		purple_debug_info("certificate/x509/tls_cached",
 				  "Certificate for %s is self-signed.\n",
 				  vrq->subject_name);
@@ -1316,13 +1316,13 @@
 					"is self-signed. It cannot be "
 					"automatically checked."),
 				      vrq->subject_name);
-				      
+
 		x509_tls_cached_user_auth(vrq,msg);
 
 		g_free(msg);
 		return;
 	} /* if (self signed) */
-	
+
 	/* Next, check that the certificate chain is valid */
 	if ( ! purple_certificate_check_signature_chain(chain) ) {
 		/* TODO: Tell the user where the chain broke? */
@@ -1390,7 +1390,7 @@
 	}
 
 	g_free(ca_id);
-	
+
 	/* Check the signature */
 	if ( !purple_certificate_signed_by(end_crt, ca_crt) ) {
 		/* TODO: If signed_by ever returns a reason, maybe mention
@@ -1406,7 +1406,7 @@
 					  "Authority from which it claims to "
 					  "have a signature."),
 					vrq->subject_name);
-		
+
 		purple_notify_error(NULL, /* TODO: Probably wrong */
 				    _("SSL Certificate Error"),
 				    _("Invalid certificate authority"
@@ -1425,7 +1425,7 @@
 						     vrq->subject_name) ) {
 		gchar *sn = purple_certificate_get_subject_name(peer_crt);
 		gchar *msg;
-		
+
 		purple_debug_info("certificate/x509/tls_cached",
 				  "Name mismatch: Certificate given for %s "
 				  "has a name of %s\n",
@@ -1441,7 +1441,7 @@
 					"connecting to the service you "
 					"believe you are."),
 				      vrq->subject_name, sn);
-				      
+
 		x509_tls_cached_user_auth(vrq,msg);
 
 		g_free(sn);
@@ -1465,7 +1465,7 @@
 				   "Unable to locate tls_peers certificate "
 				   "cache.\n");
 	}
-	
+
 	/* Whew! Done! */
 	purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_VALID);
 }
@@ -1481,7 +1481,7 @@
 	purple_debug_info("certificate/x509/tls_cached",
 			  "Starting verify for %s\n",
 			  vrq->subject_name);
-	
+
 	tls_peers = purple_certificate_find_pool(x509_tls_cached.scheme_name,tls_peers_name);
 
 	if (!tls_peers) {
@@ -1494,7 +1494,7 @@
 		x509_tls_cached_unknown_peer(vrq);
 		return;
 	}
-	
+
 	/* Check if the peer has a certificate cached already */
 	purple_debug_info("certificate/x509/tls_cached",
 			  "Checking for cached cert...\n");
@@ -1583,7 +1583,7 @@
 			     name);
 
 	/* TODO: Signalling and such? */
-	
+
 	return NULL;
 }
 
@@ -1611,7 +1611,7 @@
 	purple_debug_info("certificate",
 			  "CertificateScheme %s registered\n",
 			  scheme->name);
-	
+
 	return TRUE;
 }
 
@@ -1664,7 +1664,7 @@
 			     scheme_name, ver_name);
 
 	/* TODO: Signalling and such? */
-	
+
 	return NULL;
 }
 
@@ -1742,7 +1742,7 @@
 			     scheme_name, pool_name);
 
 	/* TODO: Signalling and such? */
-	
+
 	return NULL;
 
 }
@@ -1830,11 +1830,11 @@
 	}
 
 	cert_pools = g_list_remove(cert_pools, pool);
-	
+
 	/* TODO: Signalling? */
 	purple_signal_unregister(pool, "certificate-stored");
 	purple_signal_unregister(pool, "certificate-deleted");
-		
+
 	purple_debug_info("certificate",
 			  "CertificatePool %s unregistered\n",
 			  pool->name);
--- a/libpurple/certificate.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/certificate.h	Wed Jan 28 10:23:37 2009 +0000
@@ -60,7 +60,7 @@
 typedef void (*PurpleCertificateVerifiedCallback)
 		(PurpleCertificateVerificationStatus st,
 		 gpointer userdata);
-							  
+
 /** A certificate instance
  *
  *  An opaque data structure representing a single certificate under some
@@ -96,7 +96,7 @@
 
 	/** Internal pool data */
 	gpointer data;
-	
+
 	/**
 	 * Set up the Pool's internal state
 	 *
@@ -249,7 +249,7 @@
 
 	/** Retrieve the certificate activation/expiration times */
 	gboolean (* get_times)(PurpleCertificate *crt, time_t *activation, time_t *expiration);
-	
+
 	void (*_purple_reserved1)(void);
 	void (*_purple_reserved2)(void);
 	void (*_purple_reserved3)(void);
@@ -276,7 +276,7 @@
 
 	/** Name of the Verifier - case insensitive */
 	gchar *name;
-	
+
 	/**
 	 * Start the verification process
 	 *
@@ -326,14 +326,14 @@
 	 * For X.509 certificates, this is the Common Name
 	 */
 	gchar *subject_name;
-	
+
 	/** List of certificates in the chain to be verified (such as that returned by purple_ssl_get_peer_certificates )
 	 *
 	 * This is most relevant for X.509 certificates used in SSL sessions.
 	 * The list order should be: certificate, issuer, issuer's issuer, etc.
 	 */
 	GList *cert_chain;
-	
+
 	/** Internal data used by the Verifier code */
 	gpointer data;
 
@@ -437,7 +437,7 @@
  *
  * @return TRUE if 'crt' has a valid signature made by 'issuer',
  *         otherwise FALSE
- * @todo Find a way to give the reason (bad signature, not the issuer, etc.) 
+ * @todo Find a way to give the reason (bad signature, not the issuer, etc.)
  */
 gboolean
 purple_certificate_signed_by(PurpleCertificate *crt, PurpleCertificate *issuer);
@@ -523,7 +523,7 @@
 /**
  * Check the subject name against that on the certificate
  * @param crt   Certificate instance
- * @param name  Name to check. 
+ * @param name  Name to check.
  * @return TRUE if it is a match, else FALSE
  */
 gboolean
--- a/libpurple/cipher.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/cipher.c	Wed Jan 28 10:23:37 2009 +0000
@@ -512,7 +512,7 @@
 }
 
 static void
-md4_append(PurpleCipherContext *context, const guchar *data, size_t len) 
+md4_append(PurpleCipherContext *context, const guchar *data, size_t len)
 {
 	struct MD4_Context *mctx = purple_cipher_context_get_data(context);
 	const guint32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
@@ -551,7 +551,7 @@
 	char *p = (char *)mctx->block + offset;
 	int padding = 56 - (offset + 1);
 
-	
+
 	if(in_len<16) return FALSE;
 	if(out_len) *out_len = 16;
 	*p++ = 0x80;
@@ -659,7 +659,7 @@
 
 	hctx = purple_cipher_context_get_data(context);
 
-	if (!strcmp(name, "hash")) {
+	if (purple_strequal(name, "hash")) {
 		g_free(hctx->name);
 		if (hctx->hash)
 			purple_cipher_context_destroy(hctx->hash);
@@ -676,7 +676,7 @@
 
 	hctx = purple_cipher_context_get_data(context);
 
-	if (!strcmp(name, "hash")) {
+	if (purple_strequal(name, "hash")) {
 		return hctx->name;
 	}
 
@@ -684,7 +684,7 @@
 }
 
 static void
-hmac_append(PurpleCipherContext *context, const guchar *data, size_t len) 
+hmac_append(PurpleCipherContext *context, const guchar *data, size_t len)
 {
 	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
 
@@ -778,7 +778,7 @@
 	hmac_set_key_with_len(context, key, strlen((char *)key));
 }
 
-static size_t 
+static size_t
 hmac_get_block_size(PurpleCipherContext *context)
 {
 	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
@@ -1022,11 +1022,11 @@
  *			  16 encryption rounds.
  *			  To calculate subkeys for decryption the caller
  *    			  have to reorder the generated subkeys.
- *     
+ *
  *        rawkey:	    8 Bytes of key data
  *        subkey:	    Array of at least 32 guint32s. Will be filled
  *    		    with calculated subkeys.
- *     
+ *
  **/
 static void
 des_key_schedule (const guint8 * rawkey, guint32 * subkey)
@@ -1186,7 +1186,7 @@
 				buf,
 				output+offset,
 				0);
-	}	
+	}
 	return 0;
 }
 
@@ -1216,7 +1216,7 @@
 				buf,
 				output+offset,
 				1);
-	}	
+	}
 	return 0;
 }
 
@@ -1692,11 +1692,11 @@
 
 	ctx = purple_cipher_context_get_data(context);
 
-	if(!strcmp(name, "sizeHi")) {
+	if(purple_strequal(name, "sizeHi")) {
 		ctx->sizeHi = GPOINTER_TO_INT(value);
-	} else if(!strcmp(name, "sizeLo")) {
+	} else if(purple_strequal(name, "sizeLo")) {
 		ctx->sizeLo = GPOINTER_TO_INT(value);
-	} else if(!strcmp(name, "lenW")) {
+	} else if(purple_strequal(name, "lenW")) {
 		ctx->lenW = GPOINTER_TO_INT(value);
 	}
 }
@@ -1707,11 +1707,11 @@
 
 	ctx = purple_cipher_context_get_data(context);
 
-	if(!strcmp(name, "sizeHi")) {
+	if(purple_strequal(name, "sizeHi")) {
 		return GINT_TO_POINTER(ctx->sizeHi);
-	} else if(!strcmp(name, "sizeLo")) {
+	} else if(purple_strequal(name, "sizeLo")) {
 		return GINT_TO_POINTER(ctx->sizeLo);
-	} else if(!strcmp(name, "lenW")) {
+	} else if(purple_strequal(name, "lenW")) {
 		return GINT_TO_POINTER(ctx->lenW);
 	}
 
@@ -1942,12 +1942,12 @@
 
 	ctx = purple_cipher_context_get_data(context);
 
-	if(!strcmp(name, "key_len")) {
+	if(purple_strequal(name, "key_len")) {
 		ctx->key_len = GPOINTER_TO_INT(value);
 	}
 }
 
-static size_t 
+static size_t
 rc4_get_key_size (PurpleCipherContext *context)
 {
 	struct RC4Context *ctx;
@@ -1967,7 +1967,7 @@
 
 	ctx = purple_cipher_context_get_data(context);
 
-	if(!strcmp(name, "key_len")) {
+	if(purple_strequal(name, "key_len")) {
 		return GINT_TO_POINTER(ctx->key_len);
 	}
 
--- a/libpurple/cipher.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/cipher.h	Wed Jan 28 10:23:37 2009 +0000
@@ -422,7 +422,7 @@
 size_t purple_cipher_context_get_block_size(PurpleCipherContext *context);
 
 /**
- * Sets the key with a given length on a context 
+ * Sets the key with a given length on a context
  *
  * @param context The context whose key to set
  * @param key     The key
--- a/libpurple/circbuffer.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/circbuffer.c	Wed Jan 28 10:23:37 2009 +0000
@@ -44,7 +44,7 @@
 static void grow_circ_buffer(PurpleCircBuffer *buf, gsize len) {
 	int in_offset = 0, out_offset = 0;
 	int start_buflen;
-	
+
 	g_return_if_fail(buf != NULL);
 
 	start_buflen = buf->buflen;
@@ -94,7 +94,7 @@
 	int len_stored;
 
 	g_return_if_fail(buf != NULL);
-	
+
 	/* Grow the buffer, if necessary */
 	if ((buf->buflen - buf->bufused) < len)
 		grow_circ_buffer(buf, len);
--- a/libpurple/cmds.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/cmds.c	Wed Jan 28 10:23:37 2009 +0000
@@ -236,7 +236,7 @@
 	for (l = cmds; l; l = l->next) {
 		c = l->data;
 
-		if (strcmp(c->cmd, cmd) != 0)
+		if (!purple_strequal(c->cmd, cmd))
 			continue;
 
 		found = TRUE;
@@ -250,8 +250,8 @@
 
 		right_type = TRUE;
 
-		if ((c->flags & PURPLE_CMD_FLAG_PRPL_ONLY) && c->prpl_id &&
-		    (strcmp(c->prpl_id, prpl_id) != 0))
+		if ((c->flags & PURPLE_CMD_FLAG_PRPL_ONLY) &&
+		    !purple_strequal(c->prpl_id, prpl_id))
 			continue;
 
 		right_prpl = TRUE;
@@ -320,8 +320,8 @@
 			if (!(c->flags & PURPLE_CMD_FLAG_CHAT))
 				continue;
 
-		if (conv && (c->flags & PURPLE_CMD_FLAG_PRPL_ONLY) && c->prpl_id &&
-		    (strcmp(c->prpl_id, purple_account_get_protocol_id(purple_conversation_get_account(conv))) != 0))
+		if (conv && (c->flags & PURPLE_CMD_FLAG_PRPL_ONLY) &&
+		    !purple_strequal(c->prpl_id, purple_account_get_protocol_id(purple_conversation_get_account(conv))))
 			continue;
 
 		ret = g_list_append(ret, c->cmd);
@@ -342,7 +342,7 @@
 	for (l = cmds; l; l = l->next) {
 		c = l->data;
 
-		if (cmd && (strcmp(cmd, c->cmd) != 0))
+		if (cmd && !purple_strequal(cmd, c->cmd))
 			continue;
 
 		if (conv && (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM))
@@ -352,8 +352,8 @@
 			if (!(c->flags & PURPLE_CMD_FLAG_CHAT))
 				continue;
 
-		if (conv && (c->flags & PURPLE_CMD_FLAG_PRPL_ONLY) && c->prpl_id &&
-		    (strcmp(c->prpl_id, purple_account_get_protocol_id(purple_conversation_get_account(conv))) != 0))
+		if (conv && (c->flags & PURPLE_CMD_FLAG_PRPL_ONLY) &&
+		    !purple_strequal(c->prpl_id, purple_account_get_protocol_id(purple_conversation_get_account(conv))))
 			continue;
 
 		ret = g_list_append(ret, c->help);
--- a/libpurple/connection.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/connection.c	Wed Jan 28 10:23:37 2009 +0000
@@ -191,16 +191,16 @@
 	PurpleConnection *gc;
 	PurplePlugin *prpl;
 	PurplePluginProtocolInfo *prpl_info;
-	
+
 	g_return_if_fail(account != NULL);
-		
+
 	prpl = purple_find_prpl(purple_account_get_protocol_id(account));
-	
+
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 	else {
 		gchar *message;
-		
+
 		message = g_strdup_printf(_("Missing protocol plugin for %s"),
 								  purple_account_get_username(account));
 		purple_notify_error(NULL, _("Unregistration Error"), message, NULL);
@@ -212,7 +212,7 @@
 		prpl_info->unregister_user(account, cb, user_data);
 		return;
 	}
-	
+
 	if (((password == NULL) || (*password == '\0')) &&
 		!(prpl_info->options & OPT_PROTO_NO_PASSWORD) &&
 		!(prpl_info->options & OPT_PROTO_PASSWORD_OPTIONAL))
@@ -221,10 +221,10 @@
 						   "a password.\n", purple_account_get_username(account));
 		return;
 	}
-	
+
 	gc = g_new0(PurpleConnection, 1);
 	PURPLE_DBUS_REGISTER_POINTER(gc, PurpleConnection);
-	
+
 	gc->prpl = prpl;
 	if ((password != NULL) && (*password != '\0'))
 		gc->password = g_strdup(password);
@@ -232,11 +232,11 @@
 	purple_connection_set_state(gc, PURPLE_CONNECTING);
 	connections = g_list_append(connections, gc);
 	purple_account_set_connection(account, gc);
-	
+
 	purple_signal_emit(purple_connections_get_handle(), "signing-on", gc);
-	
+
 	purple_debug_info("connection", "Unregistering.  gc = %p\n", gc);
-	
+
 	prpl_info->unregister_user(account, cb, user_data);
 }
 
@@ -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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/connection.h	Wed Jan 28 10:23:37 2009 +0000
@@ -42,7 +42,7 @@
 	PURPLE_CONNECTION_FORMATTING_WBFO = 0x0008, /**< The text buffer must be formatted as a whole */
 	PURPLE_CONNECTION_NO_NEWLINES = 0x0010, /**< No new lines are allowed in outgoing messages */
 	PURPLE_CONNECTION_NO_FONTSIZE = 0x0020, /**< Connection does not send/receive font sizes */
-	PURPLE_CONNECTION_NO_URLDESC = 0x0040,  /**< Connection does not support descriptions with links */ 
+	PURPLE_CONNECTION_NO_URLDESC = 0x0040,  /**< Connection does not support descriptions with links */
 	PURPLE_CONNECTION_NO_IMAGES = 0x0080,  /**< Connection does not support sending of images */
 	PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY = 0x0100 /**< Connection supports sending and receiving custom smileys */
 
@@ -56,7 +56,9 @@
 
 } PurpleConnectionState;
 
-/** Possible errors that can cause a connection to be closed.
+/**
+ * Possible errors that can cause a connection to be closed.
+ *
  *  @since 2.3.0
  */
 typedef enum
@@ -92,7 +94,7 @@
 	PURPLE_CONNECTION_ERROR_NAME_IN_USE = 6,
 
 	/** The username/server/other preference for the account isn't valid.
-	 *  For instance, on IRC the screen name cannot contain white space.
+	 *  For instance, on IRC the username cannot contain white space.
 	 *  This reason should not be used for incorrect passwords etc: use
 	 *  #PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED for that.
 	 *
@@ -148,71 +150,84 @@
 #include "status.h"
 #include "sslconn.h"
 
-/** Connection UI operations.  Used to notify the user of changes to
- *  connections, such as being disconnected, and to respond to the
- *  underlying network connection appearing and disappearing.  UIs should
- *  call #purple_connections_set_ui_ops() with an instance of this struct.
+/**
+ * Connection UI operations.  Used to notify the user of changes to
+ * connections, such as being disconnected, and to respond to the
+ * underlying network connection appearing and disappearing.  UIs should
+ * call #purple_connections_set_ui_ops() with an instance of this struct.
  *
- *  @see @ref ui-ops
+ * @see @ref ui-ops
  */
 typedef struct
 {
-	/** When an account is connecting, this operation is called to notify
-	 *  the UI of what is happening, as well as which @a step out of @a
-	 *  step_count has been reached (which might be displayed as a progress
-	 *  bar).
-	 *  @see #purple_connection_update_progress
+	/**
+	 * When an account is connecting, this operation is called to notify
+	 * the UI of what is happening, as well as which @a step out of @a
+	 * step_count has been reached (which might be displayed as a progress
+	 * bar).
+	 * @see #purple_connection_update_progress
 	 */
 	void (*connect_progress)(PurpleConnection *gc,
 	                         const char *text,
 	                         size_t step,
 	                         size_t step_count);
 
-	/** Called when a connection is established (just before the
-	 *  @ref signed-on signal).
+	/**
+	 * Called when a connection is established (just before the
+	 * @ref signed-on signal).
 	 */
 	void (*connected)(PurpleConnection *gc);
-	/** Called when a connection is ended (between the @ref signing-off
-	 *  and @ref signed-off signals).
+
+	/**
+	 * Called when a connection is ended (between the @ref signing-off
+	 * and @ref signed-off signals).
 	 */
 	void (*disconnected)(PurpleConnection *gc);
 
-	/** Used to display connection-specific notices.  (Pidgin's Gtk user
-	 *  interface implements this as a no-op; #purple_connection_notice(),
-	 *  which uses this operation, is not used by any of the protocols
-	 *  shipped with libpurple.)
+	/**
+	 * Used to display connection-specific notices.  (Pidgin's Gtk user
+	 * interface implements this as a no-op; #purple_connection_notice(),
+	 * which uses this operation, is not used by any of the protocols
+	 * shipped with libpurple.)
 	 */
 	void (*notice)(PurpleConnection *gc, const char *text);
 
-	/** Called when an error causes a connection to be disconnected.
-	 *  Called before #disconnected.
-	 *  @param text  a localized error message.
-	 *  @see #purple_connection_error
-	 *  @deprecated in favour of
-	 *              #PurpleConnectionUiOps.report_disconnect_reason.
+	/**
+	 * Called when an error causes a connection to be disconnected.
+	 * Called before #disconnected.
+	 * @param text  a localized error message.
+	 * @see #purple_connection_error
+	 * @deprecated in favour of
+	 *             #PurpleConnectionUiOps.report_disconnect_reason.
 	 */
 	void (*report_disconnect)(PurpleConnection *gc, const char *text);
 
-	/** Called when libpurple discovers that the computer's network
-	 *  connection is active.  On Linux, this uses Network Manager if
-	 *  available; on Windows, it uses Win32's network change notification
-	 *  infrastructure.
+	/**
+	 * Called when libpurple discovers that the computer's network
+	 * connection is active.  On Linux, this uses Network Manager if
+	 * available; on Windows, it uses Win32's network change notification
+	 * infrastructure.
 	 */
 	void (*network_connected)(void);
-	/** Called when libpurple discovers that the computer's network
-	 *  connection has gone away.
+
+	/**
+	 * Called when libpurple discovers that the computer's network
+	 * connection has gone away.
 	 */
 	void (*network_disconnected)(void);
 
-	/** Called when an error causes a connection to be disconnected.
+	/**
+	 * Called when an error causes a connection to be disconnected.
 	 *  Called before #disconnected.  This op is intended to replace
 	 *  #report_disconnect.  If both are implemented, this will be called
 	 *  first; however, there's no real reason to implement both.
+	 *
 	 *  @param reason  why the connection ended, if known, or
 	 *                 #PURPLE_CONNECTION_ERROR_OTHER_ERROR, if not.
 	 *  @param text  a localized message describing the disconnection
 	 *               in more detail to the user.
 	 *  @see #purple_connection_error_reason
+	 *
 	 *  @since 2.3.0
 	 */
 	void (*report_disconnect_reason)(PurpleConnection *gc,
@@ -354,6 +369,16 @@
 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.
@@ -385,6 +410,7 @@
  * @param gc The connection.
  *
  * @return The protocol plugin.
+ *
  * @since 2.4.0
  */
 PurplePlugin * purple_connection_get_prpl(const PurpleConnection *gc);
@@ -408,6 +434,17 @@
 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.
@@ -450,6 +487,7 @@
  * @param gc          the connection which is closing.
  * @param reason      why the connection is closing.
  * @param description a non-@c NULL localized description of the error.
+ *
  * @since 2.3.0
  */
 void
@@ -461,6 +499,7 @@
  * Closes a connection due to an SSL error; this is basically a shortcut to
  * turning the #PurpleSslErrorType into a #PurpleConnectionError and a
  * human-readable string and then calling purple_connection_error_reason().
+ *
  * @since 2.3.0
  */
 void
@@ -484,6 +523,7 @@
  *
  * @return @c TRUE if the account should not be automatically reconnected, and
  *         @c FALSE otherwise.
+ *
  * @since 2.3.0
  */
 gboolean
--- a/libpurple/conversation.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/conversation.c	Wed Jan 28 10:23:37 2009 +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 && !purple_strequal(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);
@@ -1480,7 +1480,7 @@
 
 		str = g_strdup(purple_normalize(account, who));
 
-		if (!strcmp(str, purple_normalize(account, chat->nick))) {
+		if (purple_strequal(str, purple_normalize(account, chat->nick))) {
 			flags |= PURPLE_MESSAGE_SEND;
 		} else {
 			flags |= PURPLE_MESSAGE_RECV;
@@ -1601,7 +1601,7 @@
 		const char *extra_msg = (extra_msgs ? extra_msgs->data : NULL);
 
 		if(!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
-			if (!strcmp(chat->nick, purple_normalize(conv->account, user))) {
+			if (purple_strequal(chat->nick, purple_normalize(conv->account, user))) {
 				const char *alias2 = purple_account_get_alias(conv->account);
 				if (alias2 != NULL)
 					alias = alias2;
@@ -1692,7 +1692,7 @@
 	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
 	g_return_if_fail(prpl_info != NULL);
 
-	if (!strcmp(chat->nick, purple_normalize(conv->account, old_user))) {
+	if (purple_strequal(chat->nick, purple_normalize(conv->account, old_user))) {
 		const char *alias;
 
 		/* Note this for later. */
--- a/libpurple/conversation.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/conversation.h	Wed Jan 28 10:23:37 2009 +0000
@@ -1350,7 +1350,7 @@
  * Retrieves the extended menu items for the conversation.
  *
  * @param conv The conversation.
- * 
+ *
  * @return  A list of PurpleMenuAction items, harvested by the
  *          chat-extended-menu signal. The list and the menuaction
  *          items should be freed by the caller.
--- a/libpurple/core.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/core.c	Wed Jan 28 10:23:37 2009 +0000
@@ -46,9 +46,11 @@
 #include "signals.h"
 #include "smiley.h"
 #include "sound.h"
+#include "sound-theme-loader.h"
 #include "sslconn.h"
 #include "status.h"
 #include "stun.h"
+#include "theme-manager.h"
 #include "util.h"
 
 #ifdef HAVE_DBUS
@@ -143,6 +145,8 @@
 
 	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 +175,7 @@
 	purple_xfers_init();
 	purple_idle_init();
 	purple_smileys_init();
-
+	purple_theme_manager_init();
 	/*
 	 * Call this early on to try to auto-detect our IP address and
 	 * hopefully save some time later.
@@ -181,6 +185,9 @@
 	if (ops != NULL && ops->ui_init != NULL)
 		ops->ui_init();
 
+	/* The UI may have registered some theme types, so refresh them */
+	purple_theme_manager_refresh();
+
 	return TRUE;
 }
 
@@ -233,6 +240,7 @@
 	purple_savedstatuses_uninit();
 	purple_status_uninit();
 	purple_sound_uninit();
+	purple_theme_manager_uninit();
 	purple_xfers_uninit();
 	purple_proxy_uninit();
 	purple_dnsquery_uninit();
@@ -350,15 +358,7 @@
 			const char *user_dir = purple_user_dir();
 			char *dbus_owner_user_dir = purple_dbus_owner_user_dir();
 
-			if (NULL == user_dir && NULL != dbus_owner_user_dir)
-				is_single_instance = TRUE;
-			else if (NULL != user_dir && NULL == dbus_owner_user_dir)
-				is_single_instance = TRUE;
-			else if (NULL == user_dir && NULL == dbus_owner_user_dir)
-				is_single_instance = FALSE;
-			else
-				is_single_instance = strcmp(dbus_owner_user_dir, user_dir);
-
+			is_single_instance = !purple_strequal(dbus_owner_user_dir, user_dir);
 			g_free(dbus_owner_user_dir);
 		}
 	}
@@ -489,7 +489,7 @@
 		if (g_file_test(name, G_FILE_TEST_IS_SYMLINK))
 		{
 			/* We're only going to duplicate a logs symlink. */
-			if (!strcmp(entry, "logs"))
+			if (purple_strequal(entry, "logs"))
 			{
 				char *link;
 #if GLIB_CHECK_VERSION(2,4,0)
@@ -532,7 +532,8 @@
 
 				logs_dir = g_build_filename(user_dir, "logs", NULL);
 
-				if (!strcmp(link, "../.purple/logs") || !strcmp(link, logs_dir))
+				if (purple_strequal(link, "../.purple/logs") ||
+				    purple_strequal(link, logs_dir))
 				{
 					/* If the symlink points to the new directory, we're
 					 * likely just trying again after a failed migration,
@@ -577,7 +578,7 @@
 		/* Deal with directories... */
 		if (g_file_test(name, G_FILE_TEST_IS_DIR))
 		{
-			if (!strcmp(entry, "icons"))
+			if (purple_strequal(entry, "icons"))
 			{
 				/* This is a special case for the Album plugin, which
 				 * stores data in the icons folder.  We're not copying
@@ -646,7 +647,7 @@
 
 				g_dir_close(icons_dir);
 			}
-			else if (!strcmp(entry, "plugins"))
+			else if (purple_strequal(entry, "plugins"))
 			{
 				/* Do nothing, because we broke plugin compatibility.
 				 * This means that the plugins directory gets left behind. */
--- a/libpurple/core.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/core.h	Wed Jan 28 10:23:37 2009 +0000
@@ -90,17 +90,17 @@
 
 /**
  * <p>
- * Calls purple_core_quit().  This can be used as the function 
- * passed to purple_timeout_add() when you want to shutdown Purple 
- * in a specified amount of time.  When shutting down Purple 
+ * Calls purple_core_quit().  This can be used as the function
+ * passed to purple_timeout_add() when you want to shutdown Purple
+ * in a specified amount of time.  When shutting down Purple
  * from a plugin, you must use this instead of purple_core_quit();
- * for an immediate exit, use a timeout value of 0: 
+ * for an immediate exit, use a timeout value of 0:
  * </p>
  *
  * <code>purple_timeout_add(0, purple_core_quitcb, NULL);</code>
  *
  * <p>
- * This is ensures that code from your plugin is not being 
+ * This is ensures that code from your plugin is not being
  * executed when purple_core_quit() is called.  If the plugin
  * called purple_core_quit() directly, you would get a core dump
  * after purple_core_quit() executes and control returns to your
--- a/libpurple/dbus-bindings.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/dbus-bindings.h	Wed Jan 28 10:23:37 2009 +0000
@@ -84,7 +84,7 @@
 					int              first_arg_type,
 					va_list          var_args);
 
-dbus_int32_t* purple_dbusify_GList(GList *list, gboolean free_memory, 
+dbus_int32_t* purple_dbusify_GList(GList *list, gboolean free_memory,
 				 dbus_int32_t *len);
 dbus_int32_t* purple_dbusify_GSList(GSList *list, gboolean free_memory,
 				  dbus_int32_t *len);
--- a/libpurple/dbus-server.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/dbus-server.h	Wed Jan 28 10:23:37 2009 +0000
@@ -173,7 +173,7 @@
 
 /**
  * Determines whether this instance owns the DBus service name
- * 
+ *
  * @since 2.1.0
  */
 gboolean purple_dbus_is_owner(void);
--- a/libpurple/desktopitem.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/desktopitem.c	Wed Jan 28 10:23:37 2009 +0000
@@ -41,12 +41,12 @@
  * modify it under the terms of the GNU Library General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
- * 
+ *
  * The Gnome Library 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
  * Library General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Library General Public
  * License along with the Gnome Library; see the file COPYING.LIB.  If not,
  * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
@@ -67,7 +67,7 @@
 	GList *languages;
 
 	PurpleDesktopItemType type;
-	
+
 	/* `modified' means that the ditem has been
 	 * modified since the last save. */
 	gboolean modified;
@@ -108,30 +108,30 @@
 
 	switch (type [0]) {
 	case 'A':
-		if (!strcmp (type, "Application"))
+		if (purple_strequal (type, "Application"))
 			return PURPLE_DESKTOP_ITEM_TYPE_APPLICATION;
 		break;
 	case 'L':
-		if (!strcmp (type, "Link"))
+		if (purple_strequal (type, "Link"))
 			return PURPLE_DESKTOP_ITEM_TYPE_LINK;
 		break;
 	case 'F':
-		if (!strcmp (type, "FSDevice"))
+		if (purple_strequal (type, "FSDevice"))
 			return PURPLE_DESKTOP_ITEM_TYPE_FSDEVICE;
 		break;
 	case 'M':
-		if (!strcmp (type, "MimeType"))
+		if (purple_strequal (type, "MimeType"))
 			return PURPLE_DESKTOP_ITEM_TYPE_MIME_TYPE;
 		break;
 	case 'D':
-		if (!strcmp (type, "Directory"))
+		if (purple_strequal (type, "Directory"))
 			return PURPLE_DESKTOP_ITEM_TYPE_DIRECTORY;
 		break;
 	case 'S':
-		if (!strcmp (type, "Service"))
+		if (purple_strequal (type, "Service"))
 			return PURPLE_DESKTOP_ITEM_TYPE_SERVICE;
 
-		else if (!strcmp (type, "ServiceType"))
+		else if (purple_strequal (type, "ServiceType"))
 			return PURPLE_DESKTOP_ITEM_TYPE_SERVICE_TYPE;
 		break;
 	default:
@@ -149,12 +149,12 @@
 
 	if (section == NULL)
 		return NULL;
-	if (strcmp (section, "Desktop Entry") == 0)
+	if (purple_strequal (section, "Desktop Entry"))
 		return NULL;
 
 	for (li = item->sections; li != NULL; li = li->next) {
 		sec = li->data;
-		if (strcmp (sec->name, section) == 0)
+		if (purple_strequal (sec->name, section))
 			return sec;
 	}
 
@@ -235,7 +235,7 @@
 				item->keys = g_list_append (item->keys,
 							    g_strdup (key));
 
-			g_hash_table_replace (item->main_hash, 
+			g_hash_table_replace (item->main_hash,
 					      g_strdup (key),
 					      g_strdup (value));
 		} else {
@@ -264,7 +264,7 @@
 
 	set (item, attr, value);
 
-	if (strcmp (attr, PURPLE_DESKTOP_ITEM_TYPE) == 0)
+	if (purple_strequal (attr, PURPLE_DESKTOP_ITEM_TYPE))
 		item->type = type_from_string (value);
 }
 
@@ -280,7 +280,7 @@
 	retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
 						   (GDestroyNotify) g_free,
 						   (GDestroyNotify) g_free);
-	
+
 	/* These are guaranteed to be set */
 	_purple_desktop_item_set_string (retval,
 				       PURPLE_DESKTOP_ITEM_NAME,
@@ -354,16 +354,16 @@
 			p++;
 			if (*p == ' ')
 				p++;
-			if (strcmp (p, "UTF-8") == 0) {
+			if (purple_strequal (p, "UTF-8")) {
 				return ENCODING_UTF8;
-			} else if (strcmp (p, "Legacy-Mixed") == 0) {
+			} else if (purple_strequal (p, "Legacy-Mixed")) {
 				return ENCODING_LEGACY_MIXED;
 			} else {
 				/* According to the spec we're not supposed
 				 * to read a file like this */
 				return ENCODING_UNKNOWN;
 			}
-		} else if (strcmp ("[KDE Desktop Entry]", buf) == 0) {
+		} else if (purple_strequal ("[KDE Desktop Entry]", buf)) {
 			old_kde = TRUE;
 			/* don't break yet, we still want to support
 			 * Encoding even here */
@@ -557,7 +557,7 @@
 		char *utf8_string;
 		if (char_encoding == NULL)
 			return NULL;
-		if (strcmp (char_encoding, "ASCII") == 0) {
+		if (purple_strequal (char_encoding, "ASCII")) {
 			return decode_string_and_dup (value);
 		}
 		utf8_string = g_convert (value, -1, "UTF-8", char_encoding,
@@ -673,7 +673,7 @@
 	char *val;
 	/* we always store everything in UTF-8 */
 	if (cur_section == NULL &&
-	    strcmp (key, PURPLE_DESKTOP_ITEM_ENCODING) == 0) {
+	    purple_strequal (key, PURPLE_DESKTOP_ITEM_ENCODING)) {
 		k = g_strdup (key);
 		val = g_strdup ("UTF-8");
 	} else {
@@ -690,14 +690,14 @@
 			g_free (locale);
 			return;
 		}
-		
+
 		g_strchomp (val);
 
 		/* For old KDE entries, we can also split by a comma
 		 * on sort order, so convert to semicolons */
 		if (old_kde &&
 		    cur_section == NULL &&
-		    strcmp (key, PURPLE_DESKTOP_ITEM_SORT_ORDER) == 0 &&
+		    purple_strequal (key, PURPLE_DESKTOP_ITEM_SORT_ORDER) &&
 		    strchr (val, ';') == NULL) {
 			int i;
 			for (i = 0; val[i] != '\0'; i++) {
@@ -720,7 +720,7 @@
 
 		/* Take care of the language part */
 		if (locale != NULL &&
-		    strcmp (locale, "C") == 0) {
+		    purple_strequal (locale, "C")) {
 			char *p;
 			/* Whack C locale */
 			p = strchr (k, '[');
@@ -791,11 +791,10 @@
 						PURPLE_DESKTOP_ITEM_TYPE);
 	if (type == NULL && uri != NULL) {
 		char *base = g_path_get_basename (uri);
-		if (base != NULL &&
-		    strcmp (base, ".directory") == 0) {
+		if (purple_strequal(base, ".directory")) {
 			/* This gotta be a directory */
 			g_hash_table_replace (item->main_hash,
-					      g_strdup (PURPLE_DESKTOP_ITEM_TYPE), 
+					      g_strdup (PURPLE_DESKTOP_ITEM_TYPE),
 					      g_strdup ("Directory"));
 			item->keys = g_list_prepend
 				(item->keys, g_strdup (PURPLE_DESKTOP_ITEM_TYPE));
@@ -813,7 +812,7 @@
 lookup_locale (const PurpleDesktopItem *item, const char *key, const char *locale)
 {
 	if (locale == NULL ||
-	    strcmp (locale, "C") == 0) {
+	    purple_strequal (locale, "C")) {
 		return lookup (item, key);
 	} else {
 		const char *ret;
@@ -857,7 +856,7 @@
 	type = lookup (item, PURPLE_DESKTOP_ITEM_TYPE);
 
 	/* understand old gnome style url exec thingies */
-	if (type != NULL && strcmp (type, "URL") == 0) {
+	if (purple_strequal(type, "URL")) {
 		const char *exec = lookup (item, PURPLE_DESKTOP_ITEM_EXEC);
 		set (item, PURPLE_DESKTOP_ITEM_TYPE, "Link");
 		if (exec != NULL) {
@@ -877,7 +876,7 @@
 		if (name == NULL)
 			name = g_strdup (_("No name"));
 		g_hash_table_replace (item->main_hash,
-				      g_strdup (PURPLE_DESKTOP_ITEM_NAME), 
+				      g_strdup (PURPLE_DESKTOP_ITEM_NAME),
 				      name);
 		item->keys = g_list_prepend
 			(item->keys, g_strdup (PURPLE_DESKTOP_ITEM_NAME));
@@ -885,7 +884,7 @@
 	if (lookup (item, PURPLE_DESKTOP_ITEM_ENCODING) == NULL) {
 		/* We store everything in UTF-8 so write that down */
 		g_hash_table_replace (item->main_hash,
-				      g_strdup (PURPLE_DESKTOP_ITEM_ENCODING), 
+				      g_strdup (PURPLE_DESKTOP_ITEM_ENCODING),
 				      g_strdup ("UTF-8"));
 		item->keys = g_list_prepend
 			(item->keys, g_strdup (PURPLE_DESKTOP_ITEM_ENCODING));
@@ -893,7 +892,7 @@
 	if (lookup (item, PURPLE_DESKTOP_ITEM_VERSION) == NULL) {
 		/* this is the version that we follow, so write it down */
 		g_hash_table_replace (item->main_hash,
-				      g_strdup (PURPLE_DESKTOP_ITEM_VERSION), 
+				      g_strdup (PURPLE_DESKTOP_ITEM_VERSION),
 				      g_strdup ("1.0"));
 		item->keys = g_list_prepend
 			(item->keys, g_strdup (PURPLE_DESKTOP_ITEM_VERSION));
@@ -954,7 +953,7 @@
 	while ((c = getc (df)) != EOF) {
 		if (c == '\r')		/* Ignore Carriage Return */
 			continue;
-		
+
 		switch (state) {
 
 		case OnSecHeader:
@@ -968,13 +967,11 @@
 					cur_section->keys = g_list_reverse
 						(cur_section->keys);
 				}
-				if (strcmp (CharBuffer,
-					    "KDE Desktop Entry") == 0) {
+				if (purple_strequal (CharBuffer, "KDE Desktop Entry")) {
 					/* Main section */
 					cur_section = NULL;
 					old_kde = TRUE;
-				} else if (strcmp (CharBuffer,
-						   "Desktop Entry") == 0) {
+				} else if (purple_strequal(CharBuffer, "Desktop Entry")) {
 					/* Main section */
 					cur_section = NULL;
 				} else {
@@ -1025,16 +1022,16 @@
 			/* On first pass, don't allow dangling keys */
 			if (state == FirstBrace)
 				break;
-	    
+
 			if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
 				break;
-	    
+
 			if (c == '\n' || PURPLE_DESKTOP_ITEM_OVERFLOW) { /* Abort Definition */
 				next = CharBuffer;
 				state = KeyDef;
 				break;
 			}
-	    
+
 			if (c == '=' || PURPLE_DESKTOP_ITEM_OVERFLOW){
 				*next = '\0';
 
@@ -1067,7 +1064,7 @@
 			break;
 
 		} /* switch */
-	
+
 	} /* while ((c = getc_unlocked (f)) != EOF) */
 	if (c == EOF && state == KeyValue) {
 		*next = '\0';
@@ -1158,7 +1155,7 @@
 		printf ("Can't open %s: %s", filename, g_strerror(errno));
 		return NULL;
 	}
-	
+
 	retval = ditem_load(dfile, FALSE, filename);
 
 	return retval;
@@ -1203,7 +1200,7 @@
 	/* Languages */
 	retval->languages = g_list_copy (item->languages);
 	for (li = retval->languages; li != NULL; li = li->next)
-		li->data = g_strdup (li->data);	
+		li->data = g_strdup (li->data);
 
 	/* Keys */
 	retval->keys = g_list_copy (item->keys);
--- a/libpurple/desktopitem.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/desktopitem.h	Wed Jan 28 10:23:37 2009 +0000
@@ -41,12 +41,12 @@
  * modify it under the terms of the GNU Library General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
- * 
+ *
  * The Gnome Library 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
  * Library General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Library General Public
  * License along with the Gnome Library; see the file COPYING.LIB.  If not,
  * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
@@ -155,7 +155,7 @@
  *
  * @param item The item to be copied
  *
- * @return The new copy 
+ * @return The new copy
  */
 PurpleDesktopItem *purple_desktop_item_copy (const PurpleDesktopItem *item);
 
--- a/libpurple/eventloop.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/eventloop.h	Wed Jan 28 10:23:37 2009 +0000
@@ -119,8 +119,8 @@
 	 * @see purple_input_remove
 	 */
 	gboolean (*input_remove)(guint handle);
-	
-	
+
+
 	/**
 	 * If implemented, should get the current error status for an input.
 	 *
@@ -161,7 +161,7 @@
 /*@{*/
 /**
  * Creates a callback timer.
- * 
+ *
  * The timer will repeat until the function returns @c FALSE. The
  * first call will be at the end of the first interval.
  *
@@ -185,12 +185,12 @@
  *
  * This function allows UIs to group timers for better power efficiency.  For
  * this reason, @a interval may be rounded by up to a second.
- * 
+ *
  * @param interval	The time between calls of the function, in
  *                      seconds.
  * @param function	The function to call.
  * @param data		data to pass to @a function.
- * @return A handle to the timer which can be passed to 
+ * @return A handle to the timer which can be passed to
  *         purple_timeout_remove() to remove the timer.
  *
  * @since 2.1.0
--- a/libpurple/idle.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/idle.c	Wed Jan 28 10:23:37 2009 +0000
@@ -126,14 +126,14 @@
 	idle_reporting = purple_prefs_get_string("/purple/away/idle_reporting");
 	auto_away = purple_prefs_get_bool("/purple/away/away_when_idle");
 
-	if (!strcmp(idle_reporting, "system") &&
+	if (purple_strequal(idle_reporting, "system") &&
 		(idle_ui_ops != NULL) && (idle_ui_ops->get_time_idle != NULL))
 	{
 		/* Use system idle time (mouse or keyboard movement, etc.) */
 		time_idle = idle_ui_ops->get_time_idle();
 		idle_recheck_interval = 1;
 	}
-	else if (!strcmp(idle_reporting, "purple"))
+	else if (purple_strequal(idle_reporting, "purple"))
 	{
 		/* Use 'Purple idle' */
 		time_idle = time(NULL) - last_active_time;
@@ -214,7 +214,7 @@
 
 
 /*
- * Check idle and set the timer to fire at the next idle-worth event 
+ * Check idle and set the timer to fire at the next idle-worth event
  */
 static gboolean
 check_idleness_timer(void)
--- a/libpurple/internal.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/internal.h	Wed Jan 28 10:23:37 2009 +0000
@@ -102,7 +102,7 @@
 #include <gmodule.h>
 
 #ifdef PURPLE_PLUGINS
-# ifdef HAVE_DLFCN_H 
+# ifdef HAVE_DLFCN_H
 #  include <dlfcn.h>
 # endif
 #endif
--- a/libpurple/log.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/log.c	Wed Jan 28 10:23:37 2009 +0000
@@ -34,6 +34,7 @@
 #include "util.h"
 #include "stringref.h"
 #include "imgstore.h"
+#include "time.h"
 
 static GSList *loggers = NULL;
 
@@ -46,6 +47,7 @@
 	PurpleAccount *account;
 };
 static GHashTable *logsize_users = NULL;
+static GHashTable *logsize_users_decayed = NULL;
 
 static void log_get_log_sets_common(GHashTable *sets);
 
@@ -161,14 +163,27 @@
 	lu->account = log->account;
 
 	if(g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize)) {
+		char *tmp = lu->name;
+
 		total = GPOINTER_TO_INT(ptrsize);
 		total += written;
 		g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(total));
+
+		/* The hash table takes ownership of lu, so create a new one
+		 * for the logsize_users_decayed check below. */
+		lu = g_new(struct _purple_logsize_user, 1);
+		lu->name = g_strdup(tmp);
+		lu->account = log->account;
+	}
+
+	if(g_hash_table_lookup_extended(logsize_users_decayed, lu, NULL, &ptrsize)) {
+		total = GPOINTER_TO_INT(ptrsize);
+		total += written;
+		g_hash_table_replace(logsize_users_decayed, lu, GINT_TO_POINTER(total));
 	} else {
 		g_free(lu->name);
 		g_free(lu);
 	}
-
 }
 
 char *purple_log_read(PurpleLog *log, PurpleLogReadFlags *flags)
@@ -200,7 +215,7 @@
 static guint _purple_logsize_user_equal(struct _purple_logsize_user *lu1,
 		struct _purple_logsize_user *lu2)
 {
-	return (lu1->account == lu2->account && (!strcmp(lu1->name, lu2->name)));
+	return (lu1->account == lu2->account && purple_strequal(lu1->name, lu2->name));
 }
 
 static void _purple_logsize_user_free_key(struct _purple_logsize_user *lu)
@@ -250,6 +265,49 @@
 	return size;
 }
 
+gint purple_log_get_activity_score(PurpleLogType type, const char *name, PurpleAccount *account)
+{
+	gpointer ptrscore;
+	int score;
+	GSList *n;
+	struct _purple_logsize_user *lu;
+	time_t now;
+	time(&now);
+
+	lu = g_new(struct _purple_logsize_user, 1);
+	lu->name = g_strdup(purple_normalize(account, name));
+	lu->account = account;
+
+	if(g_hash_table_lookup_extended(logsize_users_decayed, lu, NULL, &ptrscore)) {
+		score = GPOINTER_TO_INT(ptrscore);
+		g_free(lu->name);
+		g_free(lu);
+	} else {
+		double score_double = 0.0;
+		for (n = loggers; n; n = n->next) {
+			PurpleLogLogger *logger = n->data;
+
+			if(logger->list) {
+				GList *logs = (logger->list)(type, name, account);
+
+				while (logs) {
+					PurpleLog *log = (PurpleLog*)(logs->data);
+					/* Activity score counts bytes in the log, exponentially
+					   decayed with a half-life of 14 days. */
+					score_double += purple_log_get_size(log) *
+						pow(0.5, difftime(now, log->time)/1209600.0);
+					purple_log_free(log);
+					logs = g_list_delete_link(logs, logs);
+				}
+			}
+		}
+
+		score = (gint)score_double;
+		g_hash_table_replace(logsize_users_decayed, lu, GINT_TO_POINTER(score));
+	}
+	return score;
+}
+
 gboolean purple_log_is_deletable(PurpleLog *log)
 {
 	g_return_val_if_fail(log != NULL, FALSE);
@@ -324,7 +382,7 @@
 	GSList *l = loggers;
 	while (l) {
 		logger = l->data;
-		if (!strcmp(logger->id, value)) {
+		if (purple_strequal(logger->id, value)) {
 			purple_log_logger_set(logger);
 			return;
 		}
@@ -406,7 +464,7 @@
 	if (g_slist_find(loggers, logger))
 		return;
 	loggers = g_slist_append(loggers, logger);
-	if (strcmp(purple_prefs_get_string("/purple/logging/format"), logger->id) == 0) {
+	if (purple_strequal(purple_prefs_get_string("/purple/logging/format"), logger->id)) {
 		purple_prefs_trigger_callback("/purple/logging/format");
 	}
 }
@@ -588,11 +646,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,
@@ -661,6 +719,9 @@
 	logsize_users = g_hash_table_new_full((GHashFunc)_purple_logsize_user_hash,
 			(GEqualFunc)_purple_logsize_user_equal,
 			(GDestroyNotify)_purple_logsize_user_free_key, NULL);
+	logsize_users_decayed = g_hash_table_new_full((GHashFunc)_purple_logsize_user_hash,
+				(GEqualFunc)_purple_logsize_user_equal,
+				(GDestroyNotify)_purple_logsize_user_free_key, NULL);
 }
 
 void
@@ -679,6 +740,9 @@
 	purple_log_logger_remove(old_logger);
 	purple_log_logger_free(old_logger);
 	old_logger = NULL;
+
+	g_hash_table_destroy(logsize_users);
+	g_hash_table_destroy(logsize_users_decayed);
 }
 
 /****************************************************************************
@@ -1019,7 +1083,7 @@
 				continue;
 			prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
-			if (!strcmp(protocol_unescaped, prpl_info->list_icon((PurpleAccount *)account_iter->data, NULL)))
+			if (purple_strequal(protocol_unescaped, prpl_info->list_icon((PurpleAccount *)account_iter->data, NULL)))
 				accounts = g_list_prepend(accounts, account_iter->data);
 		}
 		g_free(protocol_unescaped);
@@ -1039,7 +1103,7 @@
 			/* Find the account for username in the list of accounts for protocol. */
 			username_unescaped = purple_unescape_filename(username);
 			for (account_iter = g_list_first(accounts) ; account_iter != NULL ; account_iter = account_iter->next) {
-				if (!strcmp(((PurpleAccount *)account_iter->data)->username, username_unescaped)) {
+				if (purple_strequal(((PurpleAccount *)account_iter->data)->username, username_unescaped)) {
 					account = account_iter->data;
 					break;
 				}
@@ -1068,14 +1132,14 @@
 				/* Chat for .chat or .system at the end of the name to determine the type. */
 				if (len >= 7) {
 					gchar *tmp = &name[len - 7];
-					if (!strcmp(tmp, ".system")) {
+					if (purple_strequal(tmp, ".system")) {
 						set->type = PURPLE_LOG_SYSTEM;
 						*tmp = '\0';
 					}
 				}
 				if (len > 5) {
 					gchar *tmp = &name[len - 5];
-					if (!strcmp(tmp, ".chat")) {
+					if (purple_strequal(tmp, ".chat")) {
 						set->type = PURPLE_LOG_CHAT;
 						*tmp = '\0';
 					}
@@ -1773,29 +1837,29 @@
 			sscanf(convostart, "%*s %s %d %d:%d:%d %d",
 			       month, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &tm.tm_year);
 			/* Ugly hack, in case current locale is not English */
-			if (strcmp(month, "Jan") == 0) {
+			if (purple_strequal(month, "Jan")) {
 				tm.tm_mon= 0;
-			} else if (strcmp(month, "Feb") == 0) {
+			} else if (purple_strequal(month, "Feb")) {
 				tm.tm_mon = 1;
-			} else if (strcmp(month, "Mar") == 0) {
+			} else if (purple_strequal(month, "Mar")) {
 				tm.tm_mon = 2;
-			} else if (strcmp(month, "Apr") == 0) {
+			} else if (purple_strequal(month, "Apr")) {
 				tm.tm_mon = 3;
-			} else if (strcmp(month, "May") == 0) {
+			} else if (purple_strequal(month, "May")) {
 				tm.tm_mon = 4;
-			} else if (strcmp(month, "Jun") == 0) {
+			} else if (purple_strequal(month, "Jun")) {
 				tm.tm_mon = 5;
-			} else if (strcmp(month, "Jul") == 0) {
+			} else if (purple_strequal(month, "Jul")) {
 				tm.tm_mon = 6;
-			} else if (strcmp(month, "Aug") == 0) {
+			} else if (purple_strequal(month, "Aug")) {
 				tm.tm_mon = 7;
-			} else if (strcmp(month, "Sep") == 0) {
+			} else if (purple_strequal(month, "Sep")) {
 				tm.tm_mon = 8;
-			} else if (strcmp(month, "Oct") == 0) {
+			} else if (purple_strequal(month, "Oct")) {
 				tm.tm_mon = 9;
-			} else if (strcmp(month, "Nov") == 0) {
+			} else if (purple_strequal(month, "Nov")) {
 				tm.tm_mon = 10;
-			} else if (strcmp(month, "Dec") == 0) {
+			} else if (purple_strequal(month, "Dec")) {
 				tm.tm_mon = 11;
 			}
 			tm.tm_year -= 1900;
@@ -1930,7 +1994,7 @@
 
 		/* Make sure we're dealing with a log file. */
 		ext = &name[len - 4];
-		if (strcmp(ext, ".log")) {
+		if (!purple_strequal(ext, ".log")) {
 			g_free(name);
 			continue;
 		}
@@ -1943,7 +2007,7 @@
 		set->type = PURPLE_LOG_IM;
 		if (len > 9) {
 			char *tmp = &name[len - 9];
-			if (!strcmp(tmp, ".chat")) {
+			if (purple_strequal(tmp, ".chat")) {
 				set->type = PURPLE_LOG_CHAT;
 				*tmp = '\0';
 			}
@@ -1952,22 +2016,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 (purple_strequal(purple_buddy_get_name(buddy), name)) {
+						set->account = purple_buddy_get_account(buddy);
 						set->buddy = TRUE;
 						found = TRUE;
 					}
--- a/libpurple/log.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/log.h	Wed Jan 28 10:23:37 2009 +0000
@@ -194,7 +194,7 @@
  * Creates a new log
  *
  * @param type        The type of log this is.
- * @param name        The name of this conversation (screenname, chat name,
+ * @param name        The name of this conversation (buddy name, chat name,
  *                    etc.)
  * @param account     The account the conversation is occurring on
  * @param conv        The conversation being logged
@@ -294,6 +294,19 @@
 int purple_log_get_total_size(PurpleLogType type, const char *name, PurpleAccount *account);
 
 /**
+ * Returns the activity score of a log, based on total size in bytes,
+ * which is then decayed based on age
+ *
+ * @param type                The type of the log
+ * @param name                The name of the log
+ * @param account             The account
+ * @return                    The activity score
+ *
+ * @since 2.6.0
+ */
+int purple_log_get_activity_score(PurpleLogType type, const char *name, PurpleAccount *account);
+
+/**
  * Tests whether a log is deletable
  *
  * A return value of @c FALSE indicates that purple_log_delete() will fail on this
--- a/libpurple/nat-pmp.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/nat-pmp.c	Wed Jan 28 10:23:37 2009 +0000
@@ -126,7 +126,7 @@
 
 	for (i = 0; i < RTAX_MAX; i++)
 	{
-		if (bitmask & (1 << i)) 
+		if (bitmask & (1 << i))
 		{
 			addrs[i] = sa;
 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
@@ -139,7 +139,7 @@
 				sa = (struct sockaddr*)(sizeof(struct sockaddr_in6) + (char *)sa);
 #endif
 #endif
-		} 
+		}
 		else
 		{
 			addrs[i] = NULL;
@@ -192,7 +192,7 @@
     mib[5] = 0;
 
 	/* Determine the buffer side needed to get the full routing table */
-    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 
+    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
 	{
 		purple_debug_warning("nat-pmp", "sysctl: net.route.0.0.dump estimate\n");
 		return NULL;
@@ -205,7 +205,7 @@
     }
 
 	/* Read the routing table into buf */
-    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 
+    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
 	{
 		purple_debug_warning("nat-pmp", "sysctl: net.route.0.0.dump\n");
 		return NULL;
@@ -213,12 +213,12 @@
 
     lim = buf + needed;
 
-    for (next = buf; next < lim; next += rtm->rtm_msglen) 
+    for (next = buf; next < lim; next += rtm->rtm_msglen)
 	{
 		rtm = (struct rt_msghdr *)next;
 		sa = (struct sockaddr *)(rtm + 1);
-		
-		if (sa->sa_family == AF_INET) 
+
+		if (sa->sa_family == AF_INET)
 		{
 			sin = (struct sockaddr_in*) sa;
 
@@ -240,7 +240,7 @@
 					memcpy(&mask, rti_info[RTAX_NETMASK], sizeof(mask));
 
 				if (rtm->rtm_addrs & RTA_GATEWAY &&
-					is_default_route(&addr, &mask)) 
+					is_default_route(&addr, &mask))
 				{
 					if (rti_info[RTAX_GATEWAY]) {
 						struct sockaddr_in *rti_sin = (struct sockaddr_in *)rti_info[RTAX_GATEWAY];
@@ -263,7 +263,7 @@
 }
 
 /*!
- *	purple_pmp_get_public_ip() will return the publicly facing IP address of the 
+ *	purple_pmp_get_public_ip() will return the publicly facing IP address of the
  *	default NAT gateway. The function will return NULL if:
  *		- The gateway doesn't support NAT-PMP
  *		- The gateway errors in some other spectacular fashion
@@ -278,10 +278,10 @@
 	PurplePmpIpRequest req;
 	PurplePmpIpResponse resp;
 	int sendfd;
-	
+
 	if (pmp_info.status == PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER)
 		return NULL;
-	
+
 	if ((pmp_info.status == PURPLE_PMP_STATUS_DISCOVERED) && (pmp_info.publicip != NULL))
 	{
 #ifdef PMP_DEBUG
@@ -318,7 +318,7 @@
 	/* The NAT-PMP spec says we should attempt to contact the gateway 9 times, doubling the time we wait each time.
 	 * Even starting with a timeout of 0.1 seconds, that means that we have a total waiting of 204.6 seconds.
 	 * With the recommended timeout of 0.25 seconds, we're talking 511.5 seconds (8.5 minutes).
-	 * 
+	 *
 	 * This seems really silly... if this were nonblocking, a couple retries might be in order, but it's not at present.
 	 */
 #ifdef PMP_DEBUG
@@ -327,7 +327,7 @@
 #endif
 
 	/* TODO: Non-blocking! */
-	
+
 	if (sendto(sendfd, &req, sizeof(req), 0, (struct sockaddr *)(gateway), sizeof(struct sockaddr)) < 0)
 	{
 		purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP public IP request! (%s)\n", g_strerror(errno));
@@ -370,7 +370,7 @@
 
 	if (!publicsockaddr) {
 		g_free(gateway);
-		
+
 		pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER;
 		return NULL;
 	}
@@ -437,7 +437,7 @@
 	/* The NAT-PMP spec says we should attempt to contact the gateway 9 times, doubling the time we wait each time.
 	 * Even starting with a timeout of 0.1 seconds, that means that we have a total waiting of 204.6 seconds.
 	 * With the recommended timeout of 0.25 seconds, we're talking 511.5 seconds (8.5 minutes).
-	 * 
+	 *
 	 * This seems really silly... if this were nonblocking, a couple retries might be in order, but it's not at present.
 	 * XXX Make this nonblocking.
 	 * XXX This code looks like the pmp_get_public_ip() code. Can it be consolidated?
--- a/libpurple/network.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/network.c	Wed Jan 28 10:23:37 2009 +0000
@@ -92,6 +92,10 @@
 static NMState nm_get_network_state(void);
 #endif
 
+#if defined(HAVE_NETWORKMANAGER) || defined(_WIN32)
+static gboolean force_online;
+#endif
+
 const unsigned char *
 purple_network_ip_atoi(const char *ip)
 {
@@ -648,6 +652,9 @@
 purple_network_is_available(void)
 {
 #ifdef HAVE_NETWORKMANAGER
+	if (force_online)
+		return TRUE;
+
 	if (!have_nm_state)
 	{
 		have_nm_state = TRUE;
@@ -662,12 +669,20 @@
 	return FALSE;
 
 #elif defined _WIN32
-	return (current_network_count > 0);
+	return (current_network_count > 0 || force_online);
 #else
 	return TRUE;
 #endif
 }
 
+void
+purple_network_force_online()
+{
+#if defined(HAVE_NETWORKMANAGER) || defined(_WIN32)
+	force_online = TRUE;
+#endif
+}
+
 #ifdef HAVE_NETWORKMANAGER
 static void
 nm_update_state(NMState state)
--- a/libpurple/network.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/network.h	Wed Jan 28 10:23:37 2009 +0000
@@ -208,6 +208,17 @@
 gboolean purple_network_is_available(void);
 
 /**
+ * Makes purple_network_is_available() always return @c TRUE.
+ *
+ * This is what backs the --force-online command line argument in Pidgin,
+ * for example.  This is useful for offline testing, especially when
+ * combined with nullprpl.
+ *
+ * @since 2.6.0
+ */
+void purple_network_force_online(void);
+
+/**
  * Get the handle for the network system
  *
  * @return the handle to the network system
--- a/libpurple/notify.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/notify.c	Wed Jan 28 10:23:37 2009 +0000
@@ -444,7 +444,7 @@
 purple_notify_user_info_entry_new(const char *label, const char *value)
 {
 	PurpleNotifyUserInfoEntry *user_info_entry;
-	
+
 	user_info_entry = g_new0(PurpleNotifyUserInfoEntry, 1);
 	PURPLE_DBUS_REGISTER_POINTER(user_info_entry, PurpleNotifyUserInfoEntry);
 	user_info_entry->label = g_strdup(label);
@@ -458,7 +458,7 @@
 purple_notify_user_info_entry_destroy(PurpleNotifyUserInfoEntry *user_info_entry)
 {
 	g_return_if_fail(user_info_entry != NULL);
-	
+
 	g_free(user_info_entry->label);
 	g_free(user_info_entry->value);
 	PURPLE_DBUS_UNREGISTER_POINTER(user_info_entry);
@@ -469,11 +469,11 @@
 purple_notify_user_info_new()
 {
 	PurpleNotifyUserInfo *user_info;
-	
+
 	user_info = g_new0(PurpleNotifyUserInfo, 1);
 	PURPLE_DBUS_REGISTER_POINTER(user_info, PurpleNotifyUserInfo);
 	user_info->user_info_entries = NULL;
-	
+
 	return user_info;
 }
 
@@ -484,10 +484,10 @@
 
 	for (l = user_info->user_info_entries; l != NULL; l = l->next) {
 		PurpleNotifyUserInfoEntry *user_info_entry = l->data;
-		
+
 		purple_notify_user_info_entry_destroy(user_info_entry);
 	}
-	
+
 	g_list_free(user_info->user_info_entries);
 	PURPLE_DBUS_UNREGISTER_POINTER(user_info);
 	g_free(user_info);
@@ -506,7 +506,7 @@
 {
 	GList *l;
 	GString *text;
-	
+
 	text = g_string_new("");
 
 	for (l = user_info->user_info_entries; l != NULL; l = l->next) {
@@ -532,7 +532,7 @@
 		if ((user_info_entry->type != PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK) &&
 			(l->next && ((((PurpleNotifyUserInfoEntry *)(l->next->data))->type != PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK))))
 			g_string_append(text, newline);
-		
+
 		/* Add an extra newline after a section header */
 		if (user_info_entry->type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER)
 			g_string_append(text, newline);
@@ -563,7 +563,7 @@
 purple_notify_user_info_entry_get_value(PurpleNotifyUserInfoEntry *user_info_entry)
 {
 	g_return_val_if_fail(user_info_entry != NULL, NULL);
-	
+
 	return user_info_entry->value;
 }
 
@@ -596,7 +596,7 @@
 purple_notify_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value)
 {
 	PurpleNotifyUserInfoEntry *entry;
-	
+
 	entry = purple_notify_user_info_entry_new(label, value);
 	user_info->user_info_entries = g_list_append(user_info->user_info_entries, entry);
 }
@@ -623,7 +623,7 @@
 purple_notify_user_info_add_section_header(PurpleNotifyUserInfo *user_info, const char *label)
 {
 	PurpleNotifyUserInfoEntry *entry;
-	
+
 	entry = purple_notify_user_info_entry_new(label, NULL);
 	entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER;
 
@@ -634,10 +634,10 @@
 purple_notify_user_info_prepend_section_header(PurpleNotifyUserInfo *user_info, const char *label)
 {
 	PurpleNotifyUserInfoEntry *entry;
-	
+
 	entry = purple_notify_user_info_entry_new(label, NULL);
 	entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER;
-	
+
 	user_info->user_info_entries = g_list_prepend(user_info->user_info_entries, entry);
 }
 
@@ -645,7 +645,7 @@
 purple_notify_user_info_add_section_break(PurpleNotifyUserInfo *user_info)
 {
 	PurpleNotifyUserInfoEntry *entry;
-	
+
 	entry = purple_notify_user_info_entry_new(NULL, NULL);
 	entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK;
 
@@ -656,10 +656,10 @@
 purple_notify_user_info_prepend_section_break(PurpleNotifyUserInfo *user_info)
 {
 	PurpleNotifyUserInfoEntry *entry;
-	
+
 	entry = purple_notify_user_info_entry_new(NULL, NULL);
 	entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK;
-	
+
 	user_info->user_info_entries = g_list_prepend(user_info->user_info_entries, entry);
 }
 
--- a/libpurple/notify.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/notify.h	Wed Jan 28 10:23:37 2009 +0000
@@ -291,6 +291,7 @@
  */
 void purple_notify_searchresults_row_add(PurpleNotifySearchResults *results,
 									   GList *row);
+
 #if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_NOTIFY_C_)
 /**
  * Returns a number of the rows in the search results object.
@@ -558,14 +559,21 @@
  */
 void purple_notify_user_info_prepend_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value);
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_NOTIFY_C_)
 /**
  * Remove a PurpleNotifyUserInfoEntry from a PurpleNotifyUserInfo object
  * without freeing the entry.
  *
  * @param user_info        The PurpleNotifyUserInfo
  * @param user_info_entry  The PurpleNotifyUserInfoEntry
+ *
+ * @deprecated Nothing is using this function and it should be removed
+ *             in 3.0.0.  Or, if we decide we want to keep it in 3.0.0
+ *             then we should make purple_notify_user_info_entry_destroy
+ *             public so that entries can be free'd after they're removed.
  */
 void purple_notify_user_info_remove_entry(PurpleNotifyUserInfo *user_info, PurpleNotifyUserInfoEntry *user_info_entry);
+#endif
 
 /**
  * Create a new PurpleNotifyUserInfoEntry
--- a/libpurple/ntlm.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/ntlm.h	Wed Jan 28 10:23:37 2009 +0000
@@ -46,7 +46,7 @@
  *
  * @param type2 String containing the base64 encoded type2 message
  * @param flags If not @c NULL, this will store the flags for the message
- * 
+ *
  * @return The nonce for use in message type3.  This is a statically
  *         allocated 8 byte binary string.
  */
--- a/libpurple/plugin.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/plugin.c	Wed Jan 28 10:23:37 2009 +0000
@@ -218,7 +218,7 @@
 	g_free(basename);
 	if (plugin != NULL)
 	{
-		if (!strcmp(filename, plugin->path))
+		if (purple_strequal(filename, plugin->path))
 			return plugin;
 		else if (!purple_plugin_is_unloadable(plugin))
 		{
@@ -357,7 +357,7 @@
 		return NULL;
 	}
 	else if (plugin->info->ui_requirement &&
-			strcmp(plugin->info->ui_requirement, purple_core_get_ui()))
+			!purple_strequal(plugin->info->ui_requirement, purple_core_get_ui()))
 	{
 		plugin->error = g_strdup_printf(_("You are using %s, but this plugin requires %s."),
 					purple_core_get_ui(), plugin->info->ui_requirement);
@@ -1538,7 +1538,7 @@
 	for (l = plugins; l != NULL; l = l->next) {
 		plugin = l->data;
 
-		if (!strcmp(plugin->info->name, name))
+		if (purple_strequal(plugin->info->name, name))
 			return plugin;
 	}
 
@@ -1554,7 +1554,7 @@
 	for (l = plugins; l != NULL; l = l->next) {
 		plugin = l->data;
 
-		if (plugin->path != NULL && !strcmp(plugin->path, filename))
+		if (purple_strequal(plugin->path, filename))
 			return plugin;
 	}
 
@@ -1577,7 +1577,7 @@
 
 		if (plugin->path != NULL) {
 			tmp = purple_plugin_get_basename(plugin->path);
-			if (!strcmp(tmp, basename))
+			if (purple_strequal(tmp, basename))
 			{
 				g_free(tmp);
 				return plugin;
@@ -1603,7 +1603,7 @@
 	{
 		plugin = l->data;
 
-		if (plugin->info->id != NULL && !strcmp(plugin->info->id, id))
+		if (purple_strequal(plugin->info->id, id))
 			return plugin;
 	}
 
--- a/libpurple/plugin.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/plugin.h	Wed Jan 28 10:23:37 2009 +0000
@@ -183,7 +183,7 @@
 	/** NULL for plugin actions menu, set to the PurpleConnection for
 	    account actions menu */
 	gpointer context;
-	
+
 	gpointer user_data;
 };
 
@@ -358,7 +358,7 @@
  * Returns a plugin's name.
  *
  * @param plugin The plugin.
- * 
+ *
  * @return THe name of the plugin, or @c NULL.
  */
 const gchar *purple_plugin_get_name(const PurplePlugin *plugin);
--- a/libpurple/plugins/Makefile.mingw	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/plugins/Makefile.mingw	Wed Jan 28 10:23:37 2009 +0000
@@ -1,7 +1,7 @@
 #
 # Makefile.mingw
 #
-# Description: Makefile for win32 (mingw) version of LibPurple Plugins 
+# Description: Makefile for win32 (mingw) version of libpurple Plugins
 #
 
 PIDGIN_TREE_TOP := ../..
--- a/libpurple/plugins/autoaccept.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/plugins/autoaccept.c	Wed Jan 28 10:23:37 2009 +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/perl/common/BuddyList.xs	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/plugins/perl/common/BuddyList.xs	Wed Jan 28 10:23:37 2009 +0000
@@ -363,9 +363,9 @@
 PROTOTYPES: ENABLE
 
 Purple::BuddyList::Buddy
-purple_buddy_new(account, screenname, alias)
+purple_buddy_new(account, name, alias)
 	Purple::Account account
-	const char *screenname
+	const char *name
 	const char *alias
 
 const char *
--- a/libpurple/plugins/perl/common/Request.xs	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/plugins/perl/common/Request.xs	Wed Jan 28 10:23:37 2009 +0000
@@ -211,10 +211,11 @@
 PROTOTYPES: ENABLE
 
 Purple::Request::Field
-purple_request_field_account_new(id, text, account = NULL)
+purple_request_field_account_new(class, id, text, account = NULL)
 	const char *id
 	const char *text
 	Purple::Account account
+	C_ARGS: id, text, account
 
 Purple::Account
 purple_request_field_account_get_default_value(field)
@@ -255,10 +256,11 @@
 PROTOTYPES: ENABLE
 
 Purple::Request::Field
-purple_request_field_bool_new(id, text, default_value = TRUE)
+purple_request_field_bool_new(class, id, text, default_value = TRUE)
 	const char *id
 	const char *text
 	gboolean default_value
+	C_ARGS: id, text, default_value
 
 gboolean
 purple_request_field_bool_get_default_value(field)
@@ -282,10 +284,11 @@
 PROTOTYPES: ENABLE
 
 Purple::Request::Field
-purple_request_field_choice_new(id, text, default_value = 0)
+purple_request_field_choice_new(class, id, text, default_value = 0)
 	const char *id
 	const char *text
 	int default_value
+	C_ARGS: id, text, default_value
 
 void
 purple_request_field_choice_add(field, label)
@@ -324,10 +327,11 @@
 PROTOTYPES: ENABLE
 
 Purple::Request::Field
-purple_request_field_int_new(id, text, default_value = 0)
+purple_request_field_int_new(clas, id, text, default_value = 0)
 	const char *id
 	const char *text
 	int default_value
+	C_ARGS: id, text, default_value
 
 int
 purple_request_field_int_get_default_value(field)
@@ -355,17 +359,19 @@
 PROTOTYPES: ENABLE
 
 Purple::Request::Field
-purple_request_field_label_new(id, text)
+purple_request_field_label_new(class, id, text)
 	const char *id
 	const char *text
+	C_ARGS: id, text
 
 MODULE = Purple::Request  PACKAGE = Purple::Request::Field  PREFIX = purple_request_field_
 PROTOTYPES: ENABLE
 
 Purple::Request::Field
-purple_request_field_list_new(id, text)
+purple_request_field_list_new(class, id, text)
 	const char *id
 	const char *text
+	C_ARGS: id, text
 
 void
 purple_request_field_list_add(field, item, data)
@@ -425,10 +431,11 @@
 PROTOTYPES: ENABLE
 
 Purple::Request::Field
-purple_request_field_new(id, text, type)
+purple_request_field_new(class, id, text, type)
 	const char *id
 	const char *text
 	Purple::RequestFieldType type
+	C_ARGS: id, text, type
 
 void
 purple_request_field_set_label(field, label)
@@ -454,11 +461,12 @@
 PROTOTYPES: ENABLE
 
 Purple::Request::Field
-purple_request_field_string_new(id, text, default_value, multiline)
+purple_request_field_string_new(class, id, text, default_value, multiline)
 	const char *id
 	const char *text
 	const char *default_value
 	gboolean multiline
+	C_ARGS: id, text, default_value, multiline
 
 const char *
 purple_request_field_string_get_default_value(field)
@@ -527,8 +535,9 @@
 	Purple::Request::Field::Group group
 
 Purple::Request::Field::Group
-purple_request_field_group_new(title)
+purple_request_field_group_new(class, title)
 	const char *title
+	C_ARGS: title
 
 MODULE = Purple::Request  PACKAGE = Purple::Request::Field  PREFIX = purple_request_field_
 PROTOTYPES: ENABLE
@@ -561,7 +570,8 @@
 PROTOTYPES: ENABLE
 
 Purple::Request::Fields
-purple_request_fields_new()
+purple_request_fields_new(class)
+	C_ARGS: /* void */
 
 void
 purple_request_fields_add_group(fields, group)
--- a/libpurple/plugins/statenotify.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/plugins/statenotify.c	Wed Jan 28 10:23:37 2009 +0000
@@ -33,7 +33,7 @@
 	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))
+	if (buddy != purple_find_buddy(account, buddy_name))
 		return;
 
 	who = purple_buddy_get_alias(buddy);
--- a/libpurple/plugins/tcl/tcl_cmds.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/plugins/tcl/tcl_cmds.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/pounce.c	Wed Jan 28 10:23:37 2009 +0000
@@ -326,7 +326,7 @@
 		data->buffer = NULL;
 	}
 
-	if (!strcmp(element_name, "pounce")) {
+	if (purple_strequal(element_name, "pounce")) {
 		const char *ui = g_hash_table_lookup(atts, "ui");
 
 		if (ui == NULL) {
@@ -338,7 +338,7 @@
 
 		data->events = 0;
 	}
-	else if (!strcmp(element_name, "account")) {
+	else if (purple_strequal(element_name, "account")) {
 		const char *protocol_id = g_hash_table_lookup(atts, "protocol");
 
 		if (protocol_id == NULL) {
@@ -348,7 +348,7 @@
 		else
 			data->protocol_id = g_strdup(protocol_id);
 	}
-	else if (!strcmp(element_name, "option")) {
+	else if (purple_strequal(element_name, "option")) {
 		const char *type = g_hash_table_lookup(atts, "type");
 
 		if (type == NULL) {
@@ -358,7 +358,7 @@
 		else
 			data->option_type = g_strdup(type);
 	}
-	else if (!strcmp(element_name, "event")) {
+	else if (purple_strequal(element_name, "event")) {
 		const char *type = g_hash_table_lookup(atts, "type");
 
 		if (type == NULL) {
@@ -368,7 +368,7 @@
 		else
 			data->event_type = g_strdup(type);
 	}
-	else if (!strcmp(element_name, "action")) {
+	else if (purple_strequal(element_name, "action")) {
 		const char *type = g_hash_table_lookup(atts, "type");
 
 		if (type == NULL) {
@@ -378,7 +378,7 @@
 		else
 			data->action_name = g_strdup(type);
 	}
-	else if (!strcmp(element_name, "param")) {
+	else if (purple_strequal(element_name, "param")) {
 		const char *param_name = g_hash_table_lookup(atts, "name");
 
 		if (param_name == NULL) {
@@ -404,7 +404,7 @@
 		data->buffer = NULL;
 	}
 
-	if (!strcmp(element_name, "account")) {
+	if (purple_strequal(element_name, "account")) {
 		char *tmp;
 		g_free(data->account_name);
 		data->account_name = g_strdup(buffer);
@@ -412,43 +412,43 @@
 		data->protocol_id = g_strdup(_purple_oscar_convert(buffer, tmp));
 		g_free(tmp);
 	}
-	else if (!strcmp(element_name, "pouncee")) {
+	else if (purple_strequal(element_name, "pouncee")) {
 		g_free(data->pouncee);
 		data->pouncee = g_strdup(buffer);
 	}
-	else if (!strcmp(element_name, "option")) {
-		if (!strcmp(data->option_type, "on-away"))
+	else if (purple_strequal(element_name, "option")) {
+		if (purple_strequal(data->option_type, "on-away"))
 			data->options |= PURPLE_POUNCE_OPTION_AWAY;
 
 		g_free(data->option_type);
 		data->option_type = NULL;
 	}
-	else if (!strcmp(element_name, "event")) {
-		if (!strcmp(data->event_type, "sign-on"))
+	else if (purple_strequal(element_name, "event")) {
+		if (purple_strequal(data->event_type, "sign-on"))
 			data->events |= PURPLE_POUNCE_SIGNON;
-		else if (!strcmp(data->event_type, "sign-off"))
+		else if (purple_strequal(data->event_type, "sign-off"))
 			data->events |= PURPLE_POUNCE_SIGNOFF;
-		else if (!strcmp(data->event_type, "away"))
+		else if (purple_strequal(data->event_type, "away"))
 			data->events |= PURPLE_POUNCE_AWAY;
-		else if (!strcmp(data->event_type, "return-from-away"))
+		else if (purple_strequal(data->event_type, "return-from-away"))
 			data->events |= PURPLE_POUNCE_AWAY_RETURN;
-		else if (!strcmp(data->event_type, "idle"))
+		else if (purple_strequal(data->event_type, "idle"))
 			data->events |= PURPLE_POUNCE_IDLE;
-		else if (!strcmp(data->event_type, "return-from-idle"))
+		else if (purple_strequal(data->event_type, "return-from-idle"))
 			data->events |= PURPLE_POUNCE_IDLE_RETURN;
-		else if (!strcmp(data->event_type, "start-typing"))
+		else if (purple_strequal(data->event_type, "start-typing"))
 			data->events |= PURPLE_POUNCE_TYPING;
-		else if (!strcmp(data->event_type, "typed"))
+		else if (purple_strequal(data->event_type, "typed"))
 			data->events |= PURPLE_POUNCE_TYPED;
-		else if (!strcmp(data->event_type, "stop-typing"))
+		else if (purple_strequal(data->event_type, "stop-typing"))
 			data->events |= PURPLE_POUNCE_TYPING_STOPPED;
-		else if (!strcmp(data->event_type, "message-received"))
+		else if (purple_strequal(data->event_type, "message-received"))
 			data->events |= PURPLE_POUNCE_MESSAGE_RECEIVED;
 
 		g_free(data->event_type);
 		data->event_type = NULL;
 	}
-	else if (!strcmp(element_name, "action")) {
+	else if (purple_strequal(element_name, "action")) {
 		if (data->pounce != NULL) {
 			purple_pounce_action_register(data->pounce, data->action_name);
 			purple_pounce_action_set_enabled(data->pounce, data->action_name, TRUE);
@@ -457,7 +457,7 @@
 		g_free(data->action_name);
 		data->action_name = NULL;
 	}
-	else if (!strcmp(element_name, "param")) {
+	else if (purple_strequal(element_name, "param")) {
 		if (data->pounce != NULL) {
 			purple_pounce_action_set_attribute(data->pounce, data->action_name,
 											 data->param_name, buffer);
@@ -466,7 +466,7 @@
 		g_free(data->param_name);
 		data->param_name = NULL;
 	}
-	else if (!strcmp(element_name, "events")) {
+	else if (purple_strequal(element_name, "events")) {
 		PurpleAccount *account;
 
 		account = purple_accounts_find(data->account_name, data->protocol_id);
@@ -499,11 +499,11 @@
 		g_free(data->pouncee);
 		data->pouncee = NULL;
 	}
-	else if (!strcmp(element_name, "save")) {
+	else if (purple_strequal(element_name, "save")) {
 		if (data->pounce != NULL)
 			purple_pounce_set_save(data->pounce, TRUE);
 	}
-	else if (!strcmp(element_name, "pounce")) {
+	else if (purple_strequal(element_name, "pounce")) {
 		data->pounce  = NULL;
 		data->events  = 0;
 		data->options = 0;
@@ -1023,7 +1023,7 @@
 
 	for (iter = pounces; iter; iter = iter->next) {
 		PurplePounce *pounce = iter->data;
-		if (pounce->ui_type && strcmp(pounce->ui_type, ui) == 0)
+		if (purple_strequal(pounce->ui_type, ui))
 			list = g_list_prepend(list, pounce);
 	}
 	list = g_list_reverse(list);
@@ -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/prefs.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/prefs.c	Wed Jan 28 10:23:37 2009 +0000
@@ -250,33 +250,34 @@
 	GString *pref_name_full;
 	GList *tmp;
 
-	if(strcmp(element_name, "pref") && strcmp(element_name, "item"))
+	if(!purple_strequal(element_name, "pref") &&
+	   !purple_strequal(element_name, "item"))
 		return;
 
 	for(i = 0; attribute_names[i]; i++) {
-		if(!strcmp(attribute_names[i], "name")) {
+		if(purple_strequal(attribute_names[i], "name")) {
 			pref_name = attribute_values[i];
-		} else if(!strcmp(attribute_names[i], "type")) {
-			if(!strcmp(attribute_values[i], "bool"))
+		} else if(purple_strequal(attribute_names[i], "type")) {
+			if(purple_strequal(attribute_values[i], "bool"))
 				pref_type = PURPLE_PREF_BOOLEAN;
-			else if(!strcmp(attribute_values[i], "int"))
+			else if(purple_strequal(attribute_values[i], "int"))
 				pref_type = PURPLE_PREF_INT;
-			else if(!strcmp(attribute_values[i], "string"))
+			else if(purple_strequal(attribute_values[i], "string"))
 				pref_type = PURPLE_PREF_STRING;
-			else if(!strcmp(attribute_values[i], "stringlist"))
+			else if(purple_strequal(attribute_values[i], "stringlist"))
 				pref_type = PURPLE_PREF_STRING_LIST;
-			else if(!strcmp(attribute_values[i], "path"))
+			else if(purple_strequal(attribute_values[i], "path"))
 				pref_type = PURPLE_PREF_PATH;
-			else if(!strcmp(attribute_values[i], "pathlist"))
+			else if(purple_strequal(attribute_values[i], "pathlist"))
 				pref_type = PURPLE_PREF_PATH_LIST;
 			else
 				return;
-		} else if(!strcmp(attribute_names[i], "value")) {
+		} else if(purple_strequal(attribute_names[i], "value")) {
 			pref_value = attribute_values[i];
 		}
 	}
 
-	if(!strcmp(element_name, "item")) {
+	if(purple_strequal(element_name, "item")) {
 		struct purple_pref *pref;
 
 		pref_name_full = g_string_new("");
@@ -301,7 +302,7 @@
 	} else {
 		char *decoded;
 
-		if(!pref_name || !strcmp(pref_name, "/"))
+		if(!pref_name || purple_strequal(pref_name, "/"))
 			return;
 
 		pref_name_full = g_string_new(pref_name);
@@ -352,7 +353,7 @@
 						  const gchar *element_name,
 						  gpointer user_data, GError **error)
 {
-	if(prefs_stack && !strcmp(element_name, "pref")) {
+	if(prefs_stack && purple_strequal(element_name, "pref")) {
 		g_free(prefs_stack->data);
 		prefs_stack = g_list_delete_link(prefs_stack, prefs_stack);
 	}
@@ -521,7 +522,7 @@
 	char *parent_name = get_path_dirname(name);
 	struct purple_pref *ret = &prefs;
 
-	if(strcmp(parent_name, "/")) {
+	if(!purple_strequal(parent_name, "/")) {
 		ret = find_pref(parent_name);
 	}
 
@@ -571,7 +572,7 @@
 	my_name = get_path_basename(name);
 
 	for(sibling = parent->first_child; sibling; sibling = sibling->sibling) {
-		if(!strcmp(sibling->name, my_name)) {
+		if(purple_strequal(sibling->name, my_name)) {
 			g_free(my_name);
 			return NULL;
 		}
@@ -849,10 +850,7 @@
 			return;
 		}
 
-		if((value && !pref->value.string) ||
-				(!value && pref->value.string) ||
-				(value && pref->value.string &&
-				 strcmp(pref->value.string, value))) {
+		if (!purple_strequal(pref->value.string, value)) {
 			g_free(pref->value.string);
 			pref->value.string = g_strdup(value);
 			do_callbacks(name, pref);
@@ -909,10 +907,7 @@
 			return;
 		}
 
-		if((value && !pref->value.string) ||
-				(!value && pref->value.string) ||
-				(value && pref->value.string &&
-				 strcmp(pref->value.string, value))) {
+		if (!purple_strequal(pref->value.string, value)) {
 			g_free(pref->value.string);
 			pref->value.string = g_strdup(value);
 			do_callbacks(name, pref);
@@ -1106,7 +1101,7 @@
 		next = child->sibling;
 		for(newchild = newpref->first_child; newchild != NULL; newchild = newchild->sibling)
 		{
-			if(!strcmp(child->name, newchild->name))
+			if(purple_strequal(child->name, newchild->name))
 			{
 				purple_prefs_rename_node(child, newchild);
 				break;
--- a/libpurple/prefs.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/prefs.h	Wed Jan 28 10:23:37 2009 +0000
@@ -67,8 +67,8 @@
 #endif
 
 /**************************************************************************/
-/** @name Prefs API                                                       
-    Preferences are named according to a directory-like structure.        
+/** @name Prefs API
+    Preferences are named according to a directory-like structure.
     Example: "/plugins/core/potato/is_from_idaho" (probably a boolean)    */
 /**************************************************************************/
 /*@{*/
--- a/libpurple/privacy.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/privacy.c	Wed Jan 28 10:23:37 2009 +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);
 	}
 }
@@ -259,7 +261,7 @@
 				for (list = account->permit; list != NULL;) {
 					char *person = list->data;
 					list = list->next;
-					if (strcmp(norm, person) != 0)
+					if (!purple_strequal(norm, person))
 						purple_privacy_permit_remove(account, person, local);
 				}
 			}
@@ -303,7 +305,7 @@
 				for (list = account->deny; list != NULL; ) {
 					char *person = list->data;
 					list = list->next;
-					if (strcmp(norm, person) != 0)
+					if (!purple_strequal(norm, person))
 						purple_privacy_deny_remove(account, person, local);
 				}
 			}
--- a/libpurple/privacy.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/privacy.h	Wed Jan 28 10:23:37 2009 +0000
@@ -125,7 +125,7 @@
  *									changed to PURPLE_PRIVACY_ALLOW_USERS, all the
  *									buddies are added to the allow-list, and the
  *									user is also added to the allow-list.
- * 
+ *
  * @param account	The account.
  * @param who		The name of the user.
  * @param local		Whether the change is local-only.
--- a/libpurple/protocols/Makefile.mingw	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/Makefile.mingw	Wed Jan 28 10:23:37 2009 +0000
@@ -2,7 +2,7 @@
 #
 # Author: hermanator12002@yahoo.com
 # Date 9/11/02
-# Description: Protocols Makefile for win32 (mingw) port of LibPurple
+# Description: Protocols Makefile for win32 (mingw) port of libpurple
 #
 
 PIDGIN_TREE_TOP := ../..
--- a/libpurple/protocols/bonjour/bonjour.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/bonjour/bonjour_ft.c	Wed Jan 28 10:23:37 2009 +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;
 
 	g_return_if_fail(pc != NULL);
 	g_return_if_fail(packet != NULL);
@@ -421,6 +421,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) {
@@ -448,31 +450,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");
@@ -501,7 +506,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")) {
@@ -841,8 +846,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;
@@ -856,7 +863,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/bonjour/buddy.c	Wed Jan 28 10:23:37 2009 +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 && *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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Wed Jan 28 10:23:37 2009 +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 */
@@ -329,12 +336,15 @@
 		ret = 0;
 	else if (ret <= 0) {
 		PurpleConversation *conv;
+		PurpleAccount *account;
 		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."),
@@ -373,11 +383,12 @@
 
 	/* Inform the user that the conversation has been closed */
 	BonjourBuddy *bb = NULL;
+	const gchar *name = bconv->pb ? purple_buddy_get_name(bconv->pb) : "(unknown)";
 
-	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);
 
 	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;
@@ -411,9 +422,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.
@@ -421,7 +434,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 {
@@ -465,7 +479,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);
 		}
 
@@ -644,7 +658,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");
@@ -743,17 +757,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."),
@@ -766,12 +783,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."),
@@ -791,14 +811,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;
 
@@ -848,7 +868,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) {
@@ -856,7 +876,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);
@@ -896,12 +916,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)
 	{
@@ -948,7 +966,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;
@@ -956,8 +974,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));
@@ -1007,7 +1023,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;
 	}
@@ -1036,7 +1052,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);
@@ -1095,7 +1111,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;
@@ -1158,15 +1174,20 @@
 check_if_blocked(PurpleBuddy *pb)
 {
 	gboolean blocked = FALSE;
-	GSList *l;
+	GSList *l = NULL;
 	PurpleAccount *acc = purple_buddy_get_account(pb);
 
 	if(acc == NULL)
 		return FALSE;
 
+	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;
 		}
@@ -1178,16 +1199,19 @@
 xep_iq_parse(xmlnode *packet, PurpleBuddy *pb)
 {
 	xmlnode *child;
+	PurpleAccount *account;
+	PurpleConnection *gc;
 
 	if(check_if_blocked(pb))
 		return;
 
+		account = purple_buddy_get_account(pb);
+		gc = purple_account_get_connection(account);
+
 	if ((child = xmlnode_get_child(packet, "si")) || (child = xmlnode_get_child(packet, "error")))
-		xep_si_parse(purple_account_get_connection(pb->account),
-			packet, pb);
+		xep_si_parse(gc, packet, pb);
 	else
-		xep_bytestreams_parse(purple_account_get_connection(pb->account),
-			packet, pb);
+		xep_bytestreams_parse(gc, packet, pb);
 }
 
 int
--- a/libpurple/protocols/bonjour/mdns_avahi.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/bonjour/mdns_avahi.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/gg/buddylist.c	Wed Jan 28 10:23:37 2009 +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, ret = 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,41 +230,46 @@
 /* char *ggp_buddylist_dump(PurpleAccount *account) {{{ */
 char *ggp_buddylist_dump(PurpleAccount *account)
 {
-	PurpleBuddyList *blist;
 	PurpleBlistNode *gnode, *cnode, *bnode;
 	PurpleGroup *group;
 	PurpleBuddy *buddy;
-	GString *buddylist;
+	GString *buddylist = g_string_sized_new(1024);
 	char *ptr;
 
-	if ((blist = purple_get_blist()) == NULL)
-		return NULL;
-
-	buddylist = g_string_sized_new(1024);
-
-	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 *name, *alias, *gname;
+			for (bnode = purple_blist_node_get_first_child(cnode);
+			     bnode != NULL;
+			     bnode = purple_blist_node_get_sibling_next(bnode))
+			{
+				const gchar *name, *alias, *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);
 
 				g_string_append_printf(buddylist,
 						"%s;%s;%s;%s;%s;%s;%s;%s%s\r\n",
--- a/libpurple/protocols/gg/gg.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/gg/gg.c	Wed Jan 28 10:23:37 2009 +0000
@@ -2052,11 +2052,12 @@
 {
 	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);
 	}
 }
@@ -2066,7 +2067,7 @@
 {
 	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)
--- a/libpurple/protocols/irc/irc.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/irc/irc.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/irc/msgs.c	Wed Jan 28 10:23:37 2009 +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);
 				}
 			}
--- a/libpurple/protocols/jabber/adhoccommands.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/jabber/adhoccommands.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Wed Jan 28 10:23:37 2009 +0000
@@ -422,7 +422,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) {
 			/*
@@ -558,7 +558,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");
@@ -584,7 +584,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 {
@@ -1780,7 +1780,7 @@
 
 void jabber_buddy_get_info(PurpleConnection *gc, const char *who)
 {
-	JabberStream *js = gc->proto_data;
+	JabberStream *js = purple_connection_get_protocol_data(gc);
 	JabberID *jid = jabber_id_new(who);
 
 	if (!jid)
@@ -1840,10 +1840,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)
@@ -1855,10 +1855,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,
@@ -1871,11 +1871,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)
@@ -1887,10 +1887,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");
 }
 
 
@@ -1903,18 +1903,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);
@@ -1928,7 +1928,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);
@@ -1939,12 +1939,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);
@@ -1953,9 +1954,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;
@@ -2010,7 +2012,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);
@@ -2478,7 +2480,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/jabber/google.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Wed Jan 28 10:23:37 2009 +0000
@@ -1620,13 +1620,14 @@
 {
 	JabberStream *js;
 	JabberBuddy *jb = NULL;
-
-	if(!b->account->gc)
+	PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(b));
+
+	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 ||
@@ -1640,9 +1641,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"));
@@ -1671,14 +1674,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);
-
-	jb = jabber_buddy_find(b->account->gc->proto_data, b->name,
-			FALSE);
+
+	account = purple_buddy_get_account(b);
+	g_return_if_fail(account != NULL);
+
+	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;
@@ -2014,19 +2022,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/roster.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/jabber/roster.c	Wed Jan 28 10:23:37 2009 +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/msn/directconn.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/msn/directconn.c	Wed Jan 28 10:23:37 2009 +0000
@@ -201,24 +201,6 @@
 
 	g_free(buffer);
 
-#if 0
-	/* Let's write the length of the data. */
-	ret = write(directconn->fd, &len, sizeof(len));
-
-	/* Let's write the data. */
-	ret = write(directconn->fd, data, len);
-
-	char *str;
-	str = g_strdup_printf("/home/revo/msntest/w%.4d.bin", directconn->c);
-
-	FILE *tf = g_fopen(str, "w");
-	fwrite(&len, 1, sizeof(len), tf);
-	fwrite(data, 1, len, tf);
-	fclose(tf);
-
-	g_free(str);
-#endif
-
 	directconn->c++;
 
 	return ret;
@@ -341,7 +323,7 @@
 		MsnMessage *msg;
 
 #ifdef DEBUG_DC
-		str = g_strdup_printf("/home/revo/msntest/r%.4d.bin", directconn->c);
+		str = g_strdup_printf("%s/msntest/r%.4d.bin", g_get_home_dir(), directconn->c);
 
 		FILE *tf = g_fopen(str, "w");
 		fwrite(body, 1, len, tf);
--- a/libpurple/protocols/msn/msn.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/msn/msn.c	Wed Jan 28 10:23:37 2009 +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)
@@ -694,7 +700,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))
 	{
@@ -937,7 +943,7 @@
 
 	g_return_val_if_fail(buddy != NULL, NULL);
 
-	user = buddy->proto_data;
+	user = purple_buddy_get_protocol_data(buddy);
 
 	if (user != NULL)
 	{
@@ -950,8 +956,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),
@@ -1419,14 +1425,15 @@
 {
 	MsnSession *session;
 	MsnUserList *userlist;
-	const char *who;
+	const char *who, *gname;
 	MsnUser *user;
 
 	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
@@ -1453,10 +1460,10 @@
 	if ((user != NULL) && (user->networkid != MSN_NETWORK_UNKNOWN)) {
 		/* We already know this buddy and their network. This function knows
 		   what to do with users already in the list and stuff... */
-		msn_userlist_add_buddy(userlist, who, group ? group->name : NULL);
+		msn_userlist_add_buddy(userlist, who, gname);
 	} else {
 		/* We need to check the network for this buddy first */
-		msn_userlist_save_pending_buddy(userlist, who, group ? group->name : NULL);
+		msn_userlist_save_pending_buddy(userlist, who, gname);
 		msn_notification_send_fqy(session, who);
 	}
 }
@@ -1474,7 +1481,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
@@ -1727,20 +1734,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);
 	}
 }
 
@@ -1800,20 +1809,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);
 }
 
 /**
@@ -1830,17 +1841,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>", nicktext);
 			purple_notify_user_info_add_pair(user_info, _("Nickname"), tmp);
 			g_free(tmp);
--- a/libpurple/protocols/msn/session.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/msn/session.c	Wed Jan 28 10:23:37 2009 +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/user.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/msn/user.c	Wed Jan 28 10:23:37 2009 +0000
@@ -289,9 +289,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/msn/userlist.c	Wed Jan 28 10:23:37 2009 +0000
@@ -930,31 +930,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/myspace/README	Wed Jan 28 10:23:37 2009 +0000
@@ -1,9 +1,8 @@
-MySpaceIM Protocol Plugin for Libpurple     by Jeff Connelly 20070807
-
+MySpaceIM Protocol Plugin for libpurple by Jeff Connelly 2007-08-07
 
 Greetings. This package contains a plugin for libpurple (as used in
-Pidgin, formerly Gaim) to connect to the new MySpaceIM instant messaging 
-network and send/receive messages. Functionality is only basic as of yet, 
+Pidgin, formerly Gaim) to connect to the new MySpaceIM instant messaging
+network and send/receive messages. Functionality is only basic as of yet,
 and this code should be considered alpha quality.
 
 This code was initially developed under Google Summer of Code 2007.
@@ -15,10 +14,10 @@
 Login using your _email address_ you use to login to myspace.com. You can't
 login using your numeric ID or alias.
 
-To test it out, send a message to yourself (by your username or numeric 
-uid (email not yet supported)) or tom (6221). In either case you should 
-get a reply. You should also be able to talk to other MySpaceIM users if 
-you desire. Replies will always be shown as coming from a user's username, 
+To test it out, send a message to yourself (by your username or numeric
+uid (email not yet supported)) or tom (6221). In either case you should
+get a reply. You should also be able to talk to other MySpaceIM users if
+you desire. Replies will always be shown as coming from a user's username,
 even if you IM by email or userid.
 
 Feedback welcome. You can IM my test account at "msimprpl" if you feel like it.
@@ -26,4 +25,3 @@
 Enjoy,
 -Jeff Connelly
 msimprpl@xyzzy.cjb.net
-
--- a/libpurple/protocols/myspace/myspace.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Wed Jan 28 10:23:37 2009 +0000
@@ -202,7 +202,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(PURPLE_BLIST_NODE(buddy), "UserID");
 		} else {
 			uid = 0;
 		}
@@ -311,7 +311,7 @@
 		/* See finch/gnthistory.c */
 		buddy = cur->data;
 
-		uid = purple_blist_node_get_int(&buddy->node, "UserID");
+		uid = purple_blist_node_get_int(PURPLE_BLIST_NODE(buddy), "UserID");
 		name = purple_buddy_get_name(buddy);
 
 		if (uid == wanted_uid)
@@ -383,12 +383,17 @@
 	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;
@@ -435,8 +440,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));
 
@@ -1036,11 +1043,11 @@
 		 * of numbers in the buddy list.
 		 */
 		if (display_name != NULL) {
-			purple_blist_node_set_string(&buddy->node, "DisplayName", display_name);
+			purple_blist_node_set_string(PURPLE_BLIST_NODE(buddy), "DisplayName", display_name);
 			serv_got_alias(session->gc, username, display_name);
 		} else {
 			serv_got_alias(session->gc, username,
-					purple_blist_node_get_string(&buddy->node, "DisplayName"));
+					purple_blist_node_get_string(PURPLE_BLIST_NODE(buddy), "DisplayName"));
 		}
 	}
 	g_free(display_name);
@@ -1050,7 +1057,7 @@
 
 	user->id = uid;
 	/* Keep track of the user ID across sessions */
-	purple_blist_node_set_int(&buddy->node, "UserID", uid);
+	purple_blist_node_set_int(PURPLE_BLIST_NODE(buddy), "UserID", uid);
 
 	/* Stores a few fields in the MsimUser, relevant to the buddy itself.
 	 * AvatarURL, Headline, ContactID. */
@@ -1376,7 +1383,7 @@
 		user->id = msim_msg_get_integer(msg, "f");
 
 		/* Keep track of the user ID across sessions */
-		purple_blist_node_set_int(&buddy->node, "UserID", user->id);
+		purple_blist_node_set_int(PURPLE_BLIST_NODE(buddy), "UserID", user->id);
 
 		msim_store_user_info(session, msg, NULL);
 	} else {
@@ -2630,10 +2637,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,
@@ -2642,7 +2653,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;
@@ -2654,7 +2665,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(""),
@@ -2675,7 +2686,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);
@@ -2684,7 +2695,14 @@
 	msim_msg_free(msg_persist);
 
 	/* Add to allow list, remove from block list */
-	msim_update_blocklist_for_buddy(session, buddy->name, TRUE, FALSE);
+	msim_update_blocklist_for_buddy(session, name, TRUE, FALSE);
+}
+
+static void
+msim_buddy_free(PurpleBuddy *buddy)
+{
+	msim_user_free(purple_buddy_get_protocol_data(buddy));
+	purple_buddy_set_protocol_data(buddy, NULL);
 }
 
 /**
@@ -2696,8 +2714,10 @@
 	MsimSession *session;
 	MsimMessage *delbuddy_msg;
 	MsimMessage *persist_msg;
+	const char *name;
 
 	session = (MsimSession *)gc->proto_data;
+	name = purple_buddy_get_name(buddy);
 
 	delbuddy_msg = msim_msg_new(
 				"delbuddy", MSIM_TYPE_BOOLEAN, TRUE,
@@ -2705,7 +2725,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;
@@ -2724,7 +2744,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;
@@ -2736,15 +2756,12 @@
 	 * doesn't seem like it would be necessary, but the official client
 	 * does it)
 	 */
-	if (!msim_update_blocklist_for_buddy(session, buddy->name, FALSE, FALSE)) {
+	if (!msim_update_blocklist_for_buddy(session, name, FALSE, FALSE)) {
 		purple_notify_error(NULL, NULL,
 				_("Failed to remove buddy"), _("blocklist command failed"));
 		return;
 	}
-	if (buddy->proto_data) {
-		msim_user_free(buddy->proto_data);
-		buddy->proto_data = NULL;
-	}
+	msim_buddy_free(buddy);
 }
 
 /**
@@ -2834,13 +2851,6 @@
 	msim_update_blocklist_for_buddy(session, name, FALSE, FALSE);
 }
 
-static void
-msim_buddy_free(PurpleBuddy *buddy)
-{
-	msim_user_free(buddy->proto_data);
-	buddy->proto_data = NULL;
-}
-
 /**
  * Returns a string of a username in canonical form. Basically removes all the
  * spaces, lowercases the string, and looks up user IDs to usernames.
--- a/libpurple/protocols/myspace/user.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/myspace/user.c	Wed Jan 28 10:23:37 2009 +0000
@@ -52,17 +52,14 @@
 		return NULL;
 	}
 
-	if (!buddy->proto_data) {
+	if (!(user = purple_buddy_get_protocol_data(buddy))) {
 		/* No MsimUser for this buddy; make one. */
 
 		user = g_new0(MsimUser, 1);
 		user->buddy = buddy;
-		user->id = purple_blist_node_get_int((PurpleBlistNode*)buddy, "UserID");
-		buddy->proto_data = (gpointer)user;
+		purple_buddy_set_protocol_data(buddy, user);
 	}
 
-	user = (MsimUser *)(buddy->proto_data);
-
 	return user;
 }
 
@@ -111,6 +108,7 @@
 {
 	PurplePresence *presence;
 	gchar *str;
+	guint uid;
 	guint cv;
 
 	/* Useful to identify the account the tooltip refers to.
@@ -119,6 +117,8 @@
 		purple_notify_user_info_add_pair(user_info, _("User"), user->username);
 	}
 
+	uid = purple_blist_node_get_int((PurpleBlistNode *)user->buddy, "UserID");
+
 	/* a/s/l...the vitals */
 	if (user->age) {
 		char age[16];
@@ -209,9 +209,9 @@
 		gsize len,
 		const gchar *error_message)
 {
-	MsimUser *user;
-
-	user = (MsimUser *)user_data;
+	MsimUser *user = (MsimUser *)user_data;
+	const char *name = purple_buddy_get_name(user->buddy);
+	PurpleAccount *account;
 
 	purple_debug_info("msim_downloaded_buddy_icon",
 			"Downloaded %" G_GSIZE_FORMAT " bytes\n", len);
@@ -219,12 +219,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,
+	account = purple_buddy_get_account(user->buddy);
+	purple_buddy_icons_set_for_user(account, name,
 			g_memdup((gchar *)url_text, len), len,
 			/* Use URL itself as buddy icon "checksum" (TODO: ETag) */
 			user->image_url);		/* checksum */
@@ -247,7 +247,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;
 
 	if (user->buddy == NULL)
 		/* User not on buddy list so nothing to do */
@@ -261,8 +263,11 @@
 	if (new_title && !*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;
 	}
 
@@ -282,7 +287,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);
@@ -299,14 +304,16 @@
 static 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(). */
 		user->id = atol(value_str);
 		g_free(value_str);
 		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", user->id);
+			purple_debug_info("msim", "associating uid %s with username %s\n", key_str, name);
+			purple_blist_node_set_int(PURPLE_BLIST_NODE(user->buddy), "UserID", user->id);
 		}
 		/* Need to store in MsimUser, too? What if not on blist? */
 	} else if (g_str_equal(key_str, "Age")) {
@@ -359,9 +366,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;
 		}
 
--- a/libpurple/protocols/myspace/zap.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/myspace/zap.c	Wed Jan 28 10:23:37 2009 +0000
@@ -173,13 +173,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/novell/novell.c	Wed Jan 28 10:23:37 2009 +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/null/README	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/null/README	Wed Jan 28 10:23:37 2009 +0000
@@ -28,11 +28,10 @@
 -----------------------
 
 To build, just run ./configure as usual in the root directory of the pidgin
-source distribution. Then cd libpurple/protocols/null and type make. To
-install, copy libnull.la and .libs/libnull.so into your ~/.purple/plugins
-directory. Then run Pidgin.
+source distribution. Then cd libpurple/protocols/null and then make.  To
+install, run make install.  Then run Pidgin.
 
-To build nullprpl on Windows (with Cygwin/MinGW), use Makefile.mingw.
+To build nullprpl on Windows (with Cygwin/MinGW), use: make -f Makefile.mingw
 
 -----
 USAGE
--- a/libpurple/protocols/null/nullprpl.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/null/nullprpl.c	Wed Jan 28 10:23:37 2009 +0000
@@ -220,25 +220,7 @@
  */
 static const char *nullprpl_list_icon(PurpleAccount *acct, PurpleBuddy *buddy)
 {
-  /* shamelessly steal (er, borrow) the meanwhile protocol icon. it's cute! */
-  return "meanwhile";
-}
-
-static const char *nullprpl_list_emblem(PurpleBuddy *buddy)
-{
-  const char* emblem;
-
-  if (get_nullprpl_gc(buddy->name)) {
-    PurplePresence *presence = purple_buddy_get_presence(buddy);
-    PurpleStatus *status = purple_presence_get_active_status(presence);
-    emblem = purple_status_get_name(status);
-  } else {
-    emblem = "offline";
-  }
-
-  purple_debug_info("nullprpl", "using emblem %s for %s's buddy %s\n",
-                    emblem, buddy->account->username, buddy->name);
-  return emblem;
+  return "null";
 }
 
 static char *nullprpl_status_text(PurpleBuddy *buddy) {
@@ -304,22 +286,22 @@
                     acct->username,
                     NULL_STATUS_ONLINE, NULL_STATUS_AWAY, NULL_STATUS_OFFLINE);
 
-  type = purple_status_type_new(PURPLE_STATUS_AVAILABLE, NULL_STATUS_ONLINE,
-                                NULL_STATUS_ONLINE, TRUE);
-  purple_status_type_add_attr(type, "message", _("Online"),
-                              purple_value_new(PURPLE_TYPE_STRING));
+  type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
+      NULL_STATUS_ONLINE, NULL, TRUE, TRUE, FALSE,
+      "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+      NULL);
   types = g_list_prepend(types, type);
 
-  type = purple_status_type_new(PURPLE_STATUS_AWAY, NULL_STATUS_AWAY,
-                                NULL_STATUS_AWAY, TRUE);
-  purple_status_type_add_attr(type, "message", _("Away"),
-                              purple_value_new(PURPLE_TYPE_STRING));
+  type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY,
+      NULL_STATUS_AWAY, NULL, TRUE, TRUE, FALSE,
+      "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+      NULL);
   types = g_list_prepend(types, type);
-  
-  type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL_STATUS_OFFLINE,
-                                NULL_STATUS_OFFLINE, TRUE);
-  purple_status_type_add_attr(type, "message", _("Offline"),
-                              purple_value_new(PURPLE_TYPE_STRING));
+
+  type = purple_status_type_new_with_attrs(PURPLE_STATUS_OFFLINE,
+      NULL_STATUS_OFFLINE, NULL, TRUE, TRUE, FALSE,
+      "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+      NULL);
   types = g_list_prepend(types, type);
 
   return g_list_reverse(types);
@@ -1073,7 +1055,7 @@
       PURPLE_ICON_SCALE_DISPLAY,       /* scale_rules */
   },
   nullprpl_list_icon,                  /* list_icon */
-  nullprpl_list_emblem,                /* list_emblem */
+  NULL,                                /* list_emblem */
   nullprpl_status_text,                /* status_text */
   nullprpl_tooltip_text,               /* tooltip_text */
   nullprpl_status_types,               /* status_types */
@@ -1130,24 +1112,24 @@
   NULL,                                /* whiteboard_prpl_ops */
   NULL,                                /* send_raw */
   NULL,                                /* roomlist_room_serialize */
-  NULL,                                /* padding... */
-  NULL,
-  NULL,
-	sizeof(PurplePluginProtocolInfo),    /* struct_size */
-  NULL
+  NULL,	                               /* unregister_user */
+  NULL,                                /* send_attention */
+  NULL,                                /* attention_types */
+  sizeof(PurplePluginProtocolInfo),    /* struct_size */
+  NULL,                                /* get_account_text_table */
 };
 
 static void nullprpl_init(PurplePlugin *plugin)
 {
   /* see accountopt.h for information about user splits and protocol options */
   PurpleAccountUserSplit *split = purple_account_user_split_new(
-    _("Example user split (unused)"),  /* text shown to user */
-    "default",                         /* default value */
-    '@');                              /* field separator */
+    _("Example user split"),  /* text shown to user */
+    "default",                /* default value */
+    '@');                     /* field separator */
   PurpleAccountOption *option = purple_account_option_string_new(
-    _("Example option (unused)"),      /* text shown to user */
-    "example",                         /* pref name */
-    "default");                        /* default value */
+    _("Example option"),      /* text shown to user */
+    "example",                /* pref name */
+    "default");               /* default value */
 
   purple_debug_info("nullprpl", "starting up\n");
 
@@ -1156,13 +1138,13 @@
 
   /* register whisper chat command, /msg */
   purple_cmd_register("msg",
-                    "ws",                /* args: recipient and message */
+                    "ws",                  /* args: recipient and message */
                     PURPLE_CMD_P_DEFAULT,  /* priority */
                     PURPLE_CMD_FLAG_CHAT,
                     "prpl-null",
                     send_whisper,
                     "msg &lt;username&gt; &lt;message&gt;: send a private message, aka a whisper",
-                    NULL);               /* userdata */
+                    NULL);                 /* userdata */
 
   /* get ready to store offline messages */
   goffline_messages = g_hash_table_new_full(g_str_hash,  /* hash fn */
@@ -1189,12 +1171,12 @@
   NULL,                                                    /* dependencies */
   PURPLE_PRIORITY_DEFAULT,                                 /* priority */
   NULLPRPL_ID,                                             /* id */
-  "Nullprpl",                                              /* name */
-  "0.3",                                                   /* version */
-  "Null Protocol Plugin",                                  /* summary */
-  "Null Protocol Plugin",                                  /* description */
-  "Ryan Barrett <nullprpl@ryanb.org>",                     /* author */
-  "http://snarfed.org/space/pidgin+null+protocol+plugin",  /* homepage */
+  "Null - Testing Plugin",                                 /* name */
+  DISPLAY_VERSION,                                         /* version */
+  N_("Null Protocol Plugin"),                              /* summary */
+  N_("Null Protocol Plugin"),                              /* description */
+  NULL,                                                    /* author */
+  PURPLE_WEBSITE,                                          /* homepage */
   NULL,                                                    /* load */
   NULL,                                                    /* unload */
   nullprpl_destroy,                                        /* destroy */
--- a/libpurple/protocols/oscar/family_admin.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/family_admin.c	Wed Jan 28 10:23:37 2009 +0000
@@ -21,9 +21,8 @@
 /*
  * Family 0x0007 - Account Administration.
  *
- * Used for stuff like changing the formating of your screen name, changing your
+ * Used for stuff like changing the formating of your username, changing your
  * email address, requesting an account confirmation email, getting account info,
- *
  */
 
 #include "oscar.h"
@@ -32,7 +31,7 @@
  * Subtype 0x0002 - Request a bit of account info.
  *
  * Info should be one of the following:
- * 0x0001 - Screen name formatting
+ * 0x0001 - Username formatting
  * 0x0011 - Email address
  * 0x0013 - Unknown
  */
@@ -111,7 +110,7 @@
 }
 
 /**
- * Subtype 0x0004 - Set screenname formatting.
+ * Subtype 0x0004 - Set the formatting of username (change spaces and capitalization).
  */
 void
 aim_admin_setnick(OscarData *od, FlapConnection *conn, const char *newnick)
--- a/libpurple/protocols/oscar/family_alert.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/family_alert.c	Wed Jan 28 10:23:37 2009 +0000
@@ -22,10 +22,10 @@
  * Family 0x0018 - Email notification
  *
  * Used for being alerted when the email address(es) associated with
- * your screen name get new electronic-m.  For normal AIM accounts, you
- * get the email address screenname@netscape.net.  AOL accounts have
- * screenname@aol.com, and can also activate a netscape.net account.
- *
+ * your username get new electronic-m.  For normal AIM accounts, you
+ * get the email address username@netscape.net.  AOL accounts have
+ * username@aol.com, and can also activate a netscape.net account.
+ * Note: This information might be out of date.
  */
 
 #include "oscar.h"
@@ -88,7 +88,7 @@
  * but this is coded so it will handle that, and handle it well.
  * This tells you if you have unread mail or not, the URL you
  * should use to access that mail, and the domain name for the
- * email account (screenname@domainname.com).  If this is the
+ * email account (username@domainname.com).  If this is the
  * first 0x0007 SNAC you've received since you signed on, or if
  * this is just a periodic status update, this will also contain
  * the number of unread emails that you have.
--- a/libpurple/protocols/oscar/family_auth.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/family_auth.c	Wed Jan 28 10:23:37 2009 +0000
@@ -229,7 +229,7 @@
 
 	/* Truncate ICQ and AOL passwords, if necessary */
 	password_len = strlen(password);
-	if (aim_snvalid_icq(sn) && (password_len > MAXICQPASSLEN))
+	if (oscar_util_valid_name_icq(sn) && (password_len > MAXICQPASSLEN))
 		password_len = MAXICQPASSLEN;
 	else if (truncate_pass && password_len > 8)
 		password_len = 8;
@@ -293,11 +293,11 @@
 	tlvlist = aim_tlvlist_read(bs);
 
 	/*
-	 * No matter what, we should have a screen name.
+	 * No matter what, we should have a username.
 	 */
 	if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) {
-		info->sn = aim_tlv_getstr(tlvlist, 0x0001, 1);
-		purple_connection_set_display_name(od->gc, info->sn);
+		info->bn = aim_tlv_getstr(tlvlist, 0x0001, 1);
+		purple_connection_set_display_name(od->gc, info->bn);
 	}
 
 	/*
@@ -394,7 +394,7 @@
 
 #if 0
 	/*
-	 * Unknown.  Seen on an @mac.com screen name with value of 0x003f
+	 * Unknown.  Seen on an @mac.com username with value of 0x003f
 	 */
 	if (aim_tlv_gettlv(tlvlist, 0x0055, 1)) {
 		/* Unhandled */
@@ -421,7 +421,7 @@
  *   - connect
  *   - server sends flap version
  *   - client sends flap version
- *   - client sends screen name (17/6)
+ *   - client sends username (17/6)
  *   - server sends hash key (17/7)
  *   - client sends auth request (17/2 -- aim_send_login)
  *   - server yells
@@ -460,7 +460,7 @@
  * Subtype 0x0006
  *
  * In AIM 3.5 protocol, the first stage of login is to request login from the
- * Authorizer, passing it the screen name for verification.  If the name is
+ * Authorizer, passing it the username for verification.  If the name is
  * invalid, a 0017/0003 is spit back, with the standard error contents.  If
  * valid, a 0017/0007 comes back, which is the signal to send it the main
  * login command (0017/0002).
@@ -527,7 +527,7 @@
 	/*
 	 * If the truncate_pass TLV exists then we should truncate the
 	 * user's password to 8 characters.  This flag is sent to us
-	 * when logging in with an AOL user's screen name.
+	 * when logging in with an AOL user's username.
 	 */
 	truncate_pass = aim_tlv_gettlv(tlvlist, 0x0026, 1) != NULL;
 
@@ -597,7 +597,7 @@
 {
 	if (od->authinfo != NULL)
 	{
-		g_free(od->authinfo->sn);
+		g_free(od->authinfo->bn);
 		g_free(od->authinfo->bosip);
 		g_free(od->authinfo->errorurl);
 		g_free(od->authinfo->email);
--- a/libpurple/protocols/oscar/family_bart.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/family_bart.c	Wed Jan 28 10:23:37 2009 +0000
@@ -90,26 +90,26 @@
  * Subtype 0x0004 - Request someone's icon.
  *
  * @param od The oscar session.
- * @param sn The screen name of the person who's icon you are requesting.
+ * @param bn The name of the buddy whose icon you are requesting.
  * @param iconcsum The MD5 checksum of the icon you are requesting.
  * @param iconcsumlen Length of the MD5 checksum given above.  Should be 10 bytes.
  * @return Return 0 if no errors, otherwise return the error number.
  */
 int
-aim_bart_request(OscarData *od, const char *sn, guint8 iconcsumtype, const guint8 *iconcsum, guint16 iconcsumlen)
+aim_bart_request(OscarData *od, const char *bn, guint8 iconcsumtype, const guint8 *iconcsum, guint16 iconcsumlen)
 {
 	FlapConnection *conn;
 	ByteStream bs;
 	aim_snacid_t snacid;
 
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_BART)) || !sn || !strlen(sn) || !iconcsum || !iconcsumlen)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_BART)) || !bn || !strlen(bn) || !iconcsum || !iconcsumlen)
 		return -EINVAL;
 
-	byte_stream_new(&bs, 1+strlen(sn) + 4 + 1+iconcsumlen);
+	byte_stream_new(&bs, 1+strlen(bn) + 4 + 1+iconcsumlen);
 
-	/* Screen name */
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
+	/* Buddy name */
+	byte_stream_put8(&bs, strlen(bn));
+	byte_stream_putstr(&bs, bn);
 
 	/* Some numbers.  You like numbers, right? */
 	byte_stream_put8(&bs, 0x01);
@@ -138,11 +138,11 @@
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
-	char *sn;
+	char *bn;
 	guint16 flags, iconlen;
 	guint8 iconcsumtype, iconcsumlen, *iconcsum, *icon;
 
-	sn = byte_stream_getstr(bs, byte_stream_get8(bs));
+	bn = byte_stream_getstr(bs, byte_stream_get8(bs));
 	flags = byte_stream_get16(bs);
 	iconcsumtype = byte_stream_get8(bs);
 	iconcsumlen = byte_stream_get8(bs);
@@ -151,9 +151,9 @@
 	icon = byte_stream_getraw(bs, iconlen);
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, sn, iconcsumtype, iconcsum, iconcsumlen, icon, iconlen);
+		ret = userfunc(od, conn, frame, bn, iconcsumtype, iconcsum, iconcsumlen, icon, iconlen);
 
-	g_free(sn);
+	g_free(bn);
 	g_free(iconcsum);
 	g_free(icon);
 
--- a/libpurple/protocols/oscar/family_bos.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/family_bos.c	Wed Jan 28 10:23:37 2009 +0000
@@ -94,8 +94,7 @@
  *  AIM_VISIBILITYCHANGE_DENYADD: Hides you from provided list of names
  *  AIM_VISIBILITYCHANGE_DENYREMOVE: Lets list see you again
  *
- * list should be a list of
- * screen names in the form "Screen Name One&ScreenNameTwo&" etc.
+ * list should be a list of "Buddy Name One&BuddyNameTwo&" etc.
  *
  * Equivelents to options in WinAIM:
  *   - Allow all users to contact me: Send an AIM_VISIBILITYCHANGE_DENYADD
--- a/libpurple/protocols/oscar/family_buddy.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/family_buddy.c	Wed Jan 28 10:23:37 2009 +0000
@@ -121,7 +121,7 @@
  *
  * This just builds the "set buddy list" command then queues it.
  *
- * buddy_list = "Screen Name One&ScreenNameTwo&";
+ * buddy_list = "Buddy Name One&BuddyNameTwo&";
  *
  * XXX Clean this up.
  *
@@ -222,7 +222,7 @@
 		ret = userfunc(od, conn, frame, &userinfo);
 
 	if (snac->subtype == SNAC_SUBTYPE_BUDDY_ONCOMING && userinfo.flags & AIM_FLAG_AWAY)
-		aim_locate_autofetch_away_message(od, userinfo.sn);
+		aim_locate_autofetch_away_message(od, userinfo.bn);
 
 	aim_info_free(&userinfo);
 
--- a/libpurple/protocols/oscar/family_feedbag.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/family_feedbag.c	Wed Jan 28 10:23:37 2009 +0000
@@ -243,7 +243,7 @@
 	if (!cur1->name && cur2->name)
 		return 6;
 
-	if (cur1->name && cur2->name && aim_sncmp(cur1->name, cur2->name))
+	if (cur1->name && cur2->name && oscar_util_name_compare(cur1->name, cur2->name))
 		return 7;
 
 	if (cur1->gid != cur2->gid)
@@ -285,8 +285,8 @@
 }
 
 /**
- * Locally find an item given a group name, screen name, and type.  If group name
- * and screen name are null, then just return the first item of the given type.
+ * Locally find an item given a group name, buddy name, and type.  If group name
+ * and buddy name are null, then just return the first item of the given type.
  *
  * @param list A pointer to the current list of items.
  * @param gn The group name of the desired item.
@@ -294,31 +294,31 @@
  * @param type The type of the desired item.
  * @return Return a pointer to the item if found, else return NULL.
  */
-struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, guint16 type)
+struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *bn, guint16 type)
 {
 	struct aim_ssi_item *cur;
 	if (!list)
 		return NULL;
 
-	if (gn && sn) { /* For finding buddies in groups */
+	if (gn && bn) { /* For finding buddies in groups */
 		for (cur=list; cur; cur=cur->next)
-			if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) {
+			if ((cur->type == type) && (cur->name) && !(oscar_util_name_compare(cur->name, bn))) {
 				struct aim_ssi_item *curg;
 				for (curg=list; curg; curg=curg->next)
-					if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(aim_sncmp(curg->name, gn)))
+					if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(oscar_util_name_compare(curg->name, gn)))
 						return cur;
 			}
 
 	} else if (gn) { /* For finding groups */
 		for (cur=list; cur; cur=cur->next) {
-			if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(aim_sncmp(cur->name, gn))) {
+			if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(oscar_util_name_compare(cur->name, gn))) {
 				return cur;
 			}
 		}
 
-	} else if (sn) { /* For finding permits, denies, and ignores */
+	} else if (bn) { /* For finding permits, denies, and ignores */
 		for (cur=list; cur; cur=cur->next) {
-			if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) {
+			if ((cur->type == type) && (cur->name) && !(oscar_util_name_compare(cur->name, bn))) {
 				return cur;
 			}
 		}
@@ -336,14 +336,14 @@
  * Check if the given buddy exists in any group in the buddy list.
  *
  * @param list A pointer to the current list of items.
- * @param sn The group name of the desired item.
+ * @param bn The group name of the desired item.
  * @return Return a pointer to the name of the item if found, else return NULL;
  */
-struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn)
+struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *bn)
 {
-	if (!sn)
+	if (!bn)
 		return NULL;
-	return aim_ssi_itemlist_finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY);
+	return aim_ssi_itemlist_finditem(list, NULL, bn, AIM_SSI_TYPE_BUDDY);
 }
 
 /**
@@ -353,12 +353,12 @@
  * @param bn The buddy name of the desired item.
  * @return Return a pointer to the name of the item if found, else return NULL;
  */
-char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn)
+char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *bn)
 {
 	struct aim_ssi_item *cur, *curg;
-	if (!list || !sn)
+	if (!list || !bn)
 		return NULL;
-	if (!(cur = aim_ssi_itemlist_exists(list, sn)))
+	if (!(cur = aim_ssi_itemlist_exists(list, bn)))
 		return NULL;
 	if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000)))
 		return NULL;
@@ -406,14 +406,14 @@
  *
  * @param list A pointer to the current list of items.
  * @param gn The group of the buddy.
- * @param sn The name of the buddy.
+ * @param bn The name of the buddy.
  * @return A pointer to a NULL terminated string that is the buddy's
  *         alias, or NULL if the buddy has no alias.  You should free
  *         this returned value!
  */
-char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn)
+char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *bn)
 {
-	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
+	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY);
 	if (cur) {
 		aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x0131, 1);
 		if (tlv && tlv->length)
@@ -427,14 +427,14 @@
  *
  * @param list A pointer to the current list of items.
  * @param gn The group of the buddy.
- * @param sn The name of the buddy.
+ * @param bn The name of the buddy.
  * @return A pointer to a NULL terminated string that is the buddy's
  *         comment, or NULL if the buddy has no comment.  You should free
  *         this returned value!
  */
-char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *sn)
+char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *bn)
 {
-	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
+	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY);
 	if (cur) {
 		aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x013c, 1);
 		if (tlv && tlv->length) {
@@ -449,12 +449,12 @@
  *
  * @param list A pointer to the current list of items.
  * @param gn The group of the buddy.
- * @param sn The name of the buddy.
+ * @param bn The name of the buddy.
  * @return 1 if you are waiting for authorization; 0 if you are not
  */
-gboolean aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn)
+gboolean aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *bn)
 {
-	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
+	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY);
 	if (cur) {
 		if (aim_tlv_gettlv(cur->data, 0x0066, 1))
 			return TRUE;
@@ -678,7 +678,7 @@
 			cur2 = cur->next;
 			while (cur2) {
 				next2 = cur2->next;
-				if ((cur->type == cur2->type) && (cur->gid == cur2->gid) && (cur->name != NULL) && (cur2->name != NULL) && (!aim_sncmp(cur->name, cur2->name))) {
+				if ((cur->type == cur2->type) && (cur->gid == cur2->gid) && (cur->name != NULL) && (cur2->name != NULL) && (!oscar_util_name_compare(cur->name, cur2->name))) {
 					aim_ssi_itemlist_del(&od->ssi.local, cur2);
 				}
 				cur2 = next2;
@@ -916,16 +916,16 @@
  * @param od The oscar odion.
  * @param oldgn The group that the buddy is currently in.
  * @param newgn The group that the buddy should be moved in to.
- * @param sn The name of the buddy to be moved.
+ * @param bn The name of the buddy to be moved.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *sn)
+int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *bn)
 {
 	struct aim_ssi_item *buddy;
 	GSList *data;
 
 	/* Find the buddy */
-	buddy = aim_ssi_itemlist_finditem(od->ssi.local, oldgn, sn, AIM_SSI_TYPE_BUDDY);
+	buddy = aim_ssi_itemlist_finditem(od->ssi.local, oldgn, bn, AIM_SSI_TYPE_BUDDY);
 	if (buddy == NULL)
 		return -EINVAL;
 
@@ -933,10 +933,10 @@
 	data = aim_tlvlist_copy(buddy->data);
 
 	/* Delete the old item */
-	aim_ssi_delbuddy(od, sn, oldgn);
+	aim_ssi_delbuddy(od, bn, oldgn);
 
 	/* Add the new item using the EXACT SAME TLV list */
-	aim_ssi_addbuddy(od, sn, newgn, data, NULL, NULL, NULL, FALSE);
+	aim_ssi_addbuddy(od, bn, newgn, data, NULL, NULL, NULL, FALSE);
 
 	return 0;
 }
@@ -946,19 +946,19 @@
  *
  * @param od The oscar odion.
  * @param gn The group that the buddy is currently in.
- * @param sn The screen name of the buddy.
+ * @param bn The name of the buddy.
  * @param alias The new alias for the buddy, or NULL if you want to remove
  *        a buddy's comment.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-int aim_ssi_aliasbuddy(OscarData *od, const char *gn, const char *sn, const char *alias)
+int aim_ssi_aliasbuddy(OscarData *od, const char *gn, const char *bn, const char *alias)
 {
 	struct aim_ssi_item *tmp;
 
-	if (!od || !gn || !sn)
+	if (!od || !gn || !bn)
 		return -EINVAL;
 
-	if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY)))
+	if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY)))
 		return -EINVAL;
 
 	/* Either add or remove the 0x0131 TLV from the TLV chain */
@@ -976,19 +976,19 @@
  *
  * @param od The oscar odion.
  * @param gn The group that the buddy is currently in.
- * @param sn The screen name of the buddy.
+ * @param bn The name of the buddy.
  * @param alias The new comment for the buddy, or NULL if you want to remove
  *        a buddy's comment.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-int aim_ssi_editcomment(OscarData *od, const char *gn, const char *sn, const char *comment)
+int aim_ssi_editcomment(OscarData *od, const char *gn, const char *bn, const char *comment)
 {
 	struct aim_ssi_item *tmp;
 
-	if (!od || !gn || !sn)
+	if (!od || !gn || !bn)
 		return -EINVAL;
 
-	if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY)))
+	if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY)))
 		return -EINVAL;
 
 	/* Either add or remove the 0x0131 TLV from the TLV chain */
@@ -1681,20 +1681,20 @@
  * Authorizes a contact so they can add you to their contact list.
  *
  */
-int aim_ssi_sendauth(OscarData *od, char *sn, char *msg)
+int aim_ssi_sendauth(OscarData *od, char *bn, char *msg)
 {
 	FlapConnection *conn;
 	ByteStream bs;
 	aim_snacid_t snacid;
 
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !bn)
 		return -EINVAL;
 
-	byte_stream_new(&bs, 1+strlen(sn) + 2+(msg ? strlen(msg)+1 : 0) + 2);
+	byte_stream_new(&bs, 1+strlen(bn) + 2+(msg ? strlen(msg)+1 : 0) + 2);
 
-	/* Screen name */
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
+	/* Username */
+	byte_stream_put8(&bs, strlen(bn));
+	byte_stream_putstr(&bs, bn);
 
 	/* Message (null terminated) */
 	byte_stream_put16(&bs, msg ? strlen(msg) : 0);
@@ -1722,13 +1722,13 @@
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 tmp;
-	char *sn, *msg;
+	char *bn, *msg;
 
-	/* Read screen name */
+	/* Read buddy name */
 	if ((tmp = byte_stream_get8(bs)))
-		sn = byte_stream_getstr(bs, tmp);
+		bn = byte_stream_getstr(bs, tmp);
 	else
-		sn = NULL;
+		bn = NULL;
 
 	/* Read message (null terminated) */
 	if ((tmp = byte_stream_get16(bs)))
@@ -1740,9 +1740,9 @@
 	tmp = byte_stream_get16(bs);
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, sn, msg);
+		ret = userfunc(od, conn, frame, bn, msg);
 
-	g_free(sn);
+	g_free(bn);
 	g_free(msg);
 
 	return ret;
@@ -1755,20 +1755,20 @@
  * granted, denied, or dropped.
  *
  */
-int aim_ssi_sendauthrequest(OscarData *od, char *sn, const char *msg)
+int aim_ssi_sendauthrequest(OscarData *od, char *bn, const char *msg)
 {
 	FlapConnection *conn;
 	ByteStream bs;
 	aim_snacid_t snacid;
 
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !bn)
 		return -EINVAL;
 
-	byte_stream_new(&bs, 1+strlen(sn) + 2+(msg ? strlen(msg)+1 : 0) + 2);
+	byte_stream_new(&bs, 1+strlen(bn) + 2+(msg ? strlen(msg)+1 : 0) + 2);
 
-	/* Screen name */
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
+	/* Username */
+	byte_stream_put8(&bs, strlen(bn));
+	byte_stream_putstr(&bs, bn);
 
 	/* Message (null terminated) */
 	byte_stream_put16(&bs, msg ? strlen(msg) : 0);
@@ -1796,13 +1796,13 @@
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 tmp;
-	char *sn, *msg;
+	char *bn, *msg;
 
-	/* Read screen name */
+	/* Read buddy name */
 	if ((tmp = byte_stream_get8(bs)))
-		sn = byte_stream_getstr(bs, tmp);
+		bn = byte_stream_getstr(bs, tmp);
 	else
-		sn = NULL;
+		bn = NULL;
 
 	/* Read message (null terminated) */
 	if ((tmp = byte_stream_get16(bs)))
@@ -1814,9 +1814,9 @@
 	tmp = byte_stream_get16(bs);
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, sn, msg);
+		ret = userfunc(od, conn, frame, bn, msg);
 
-	g_free(sn);
+	g_free(bn);
 	g_free(msg);
 
 	return ret;
@@ -1832,20 +1832,20 @@
  * if reply=0x01 then grant
  *
  */
-int aim_ssi_sendauthreply(OscarData *od, char *sn, guint8 reply, const char *msg)
+int aim_ssi_sendauthreply(OscarData *od, char *bn, guint8 reply, const char *msg)
 {
 	FlapConnection *conn;
 	ByteStream bs;
 	aim_snacid_t snacid;
 
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !bn)
 		return -EINVAL;
 
-	byte_stream_new(&bs, 1+strlen(sn) + 1 + 2+(msg ? (strlen(msg)+1) : 0) + 2);
+	byte_stream_new(&bs, 1+strlen(bn) + 1 + 2+(msg ? (strlen(msg)+1) : 0) + 2);
 
-	/* Screen name */
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
+	/* Username */
+	byte_stream_put8(&bs, strlen(bn));
+	byte_stream_putstr(&bs, bn);
 
 	/* Grant or deny */
 	byte_stream_put8(&bs, reply);
@@ -1880,13 +1880,13 @@
 	aim_rxcallback_t userfunc;
 	guint16 tmp;
 	guint8 reply;
-	char *sn, *msg;
+	char *bn, *msg;
 
-	/* Read screen name */
+	/* Read buddy name */
 	if ((tmp = byte_stream_get8(bs)))
-		sn = byte_stream_getstr(bs, tmp);
+		bn = byte_stream_getstr(bs, tmp);
 	else
-		sn = NULL;
+		bn = NULL;
 
 	/* Read reply */
 	reply = byte_stream_get8(bs);
@@ -1901,9 +1901,9 @@
 	tmp = byte_stream_get16(bs);
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, sn, reply, msg);
+		ret = userfunc(od, conn, frame, bn, reply, msg);
 
-	g_free(sn);
+	g_free(bn);
 	g_free(msg);
 
 	return ret;
@@ -1917,18 +1917,18 @@
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 tmp;
-	char *sn;
+	char *bn;
 
-	/* Read screen name */
+	/* Read buddy name */
 	if ((tmp = byte_stream_get8(bs)))
-		sn = byte_stream_getstr(bs, tmp);
+		bn = byte_stream_getstr(bs, tmp);
 	else
-		sn = NULL;
+		bn = NULL;
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, sn);
+		ret = userfunc(od, conn, frame, bn);
 
-	g_free(sn);
+	g_free(bn);
 
 	return ret;
 }
--- a/libpurple/protocols/oscar/family_icbm.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/family_icbm.c	Wed Jan 28 10:23:37 2009 +0000
@@ -61,16 +61,16 @@
  * @param bs The bstream to write the ICBM header to.
  * @param c c is for cookie, and cookie is for me.
  * @param channel The ICBM channel (1 through 4).
- * @param sn Null-terminated scrizeen nizame.
+ * @param bn Null-terminated scrizeen nizame.
  * @return The number of bytes written.  It's really not useful.
  */
-static int aim_im_puticbm(ByteStream *bs, const guchar *c, guint16 channel, const char *sn)
+static int aim_im_puticbm(ByteStream *bs, const guchar *c, guint16 channel, const char *bn)
 {
 	byte_stream_putraw(bs, c, 8);
 	byte_stream_put16(bs, channel);
-	byte_stream_put8(bs, strlen(sn));
-	byte_stream_putstr(bs, sn);
-	return 8+2+1+strlen(sn);
+	byte_stream_put8(bs, strlen(bn));
+	byte_stream_putstr(bs, bn);
+	return 8+2+1+strlen(bn);
 }
 
 /**
@@ -324,7 +324,7 @@
 	aim_icbm_makecookie(cookie);
 
 	/* ICBM header */
-	aim_im_puticbm(&data, cookie, 0x0001, args->destsn);
+	aim_im_puticbm(&data, cookie, 0x0001, args->destbn);
 
 	/* Message TLV (type 0x0002) */
 	byte_stream_put16(&data, 0x0002);
@@ -410,7 +410,7 @@
 	}
 
 	/* XXX - should be optional */
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, args->destbn, strlen(args->destbn)+1);
 
 	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &data);
 	byte_stream_destroy(&data);
@@ -431,11 +431,11 @@
  * that requires an explicit message length.  Use aim_im_sendch1_ext().
  *
  */
-int aim_im_sendch1(OscarData *od, const char *sn, guint16 flags, const char *msg)
+int aim_im_sendch1(OscarData *od, const char *bn, guint16 flags, const char *msg)
 {
 	struct aim_sendimext_args args;
 
-	args.destsn = sn;
+	args.destbn = bn;
 	args.flags = flags;
 	args.msg = msg;
 	args.msglen = strlen(msg);
@@ -451,7 +451,7 @@
 /*
  * Subtype 0x0006 - Send a chat invitation.
  */
-int aim_im_sendch2_chatinvite(OscarData *od, const char *sn, const char *msg, guint16 exchange, const char *roomname, guint16 instance)
+int aim_im_sendch2_chatinvite(OscarData *od, const char *bn, const char *msg, guint16 exchange, const char *roomname, guint16 instance)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -465,18 +465,18 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
 		return -EINVAL;
 
-	if (!sn || !msg || !roomname)
+	if (!bn || !msg || !roomname)
 		return -EINVAL;
 
 	aim_icbm_makecookie(cookie);
 
-	byte_stream_new(&bs, 1142+strlen(sn)+strlen(roomname)+strlen(msg));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, sn, strlen(sn)+1);
+	byte_stream_new(&bs, 1142+strlen(bn)+strlen(roomname)+strlen(msg));
+
+	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, bn, strlen(bn)+1);
 
 	/* XXX should be uncached by an unwritten 'invite accept' handler */
 	priv = g_malloc(sizeof(struct aim_invite_priv));
-	priv->sn = g_strdup(sn);
+	priv->bn = g_strdup(bn);
 	priv->roomname = g_strdup(roomname);
 	priv->exchange = exchange;
 	priv->instance = instance;
@@ -487,7 +487,7 @@
 		g_free(priv);
 
 	/* ICBM Header */
-	aim_im_puticbm(&bs, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, bn);
 
 	/*
 	 * TLV t(0005)
@@ -532,7 +532,7 @@
  * This is also performance sensitive. (If you can believe it...)
  *
  */
-int aim_im_sendch2_icon(OscarData *od, const char *sn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum)
+int aim_im_sendch2_icon(OscarData *od, const char *bn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -542,17 +542,17 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
 		return -EINVAL;
 
-	if (!sn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN))
+	if (!bn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN))
 		return -EINVAL;
 
 	aim_icbm_makecookie(cookie);
 
-	byte_stream_new(&bs, 8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2);
+	byte_stream_new(&bs, 8+2+1+strlen(bn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
 
 	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, bn);
 
 	/*
 	 * TLV t(0005)
@@ -623,7 +623,7 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
 		return -EINVAL;
 
-	if (!args || !args->destsn || !args->rtfmsg)
+	if (!args || !args->destbn || !args->rtfmsg)
 		return -EINVAL;
 
 	servdatalen = 2+2+16+2+4+1+2  +  2+2+4+4+4  +  2+4+2+strlen(args->rtfmsg)+1  +  4+4+4+strlen(rtfcap)+1;
@@ -635,7 +635,7 @@
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
 
 	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, args->destsn);
+	aim_im_puticbm(&bs, cookie, 0x0002, args->destbn);
 
 	/* TLV t(0005) - Encompasses everything below. */
 	byte_stream_put16(&bs, 0x0005);
@@ -708,12 +708,12 @@
 	if (conn == NULL)
 		return;
 
-	byte_stream_new(&bs, 118+strlen(peer_conn->sn));
+	byte_stream_new(&bs, 118+strlen(peer_conn->bn));
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
 
 	/* ICBM header */
-	aim_im_puticbm(&bs, peer_conn->cookie, 0x0002, peer_conn->sn);
+	aim_im_puticbm(&bs, peer_conn->cookie, 0x0002, peer_conn->bn);
 
 	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
 
@@ -757,12 +757,12 @@
 	if (conn == NULL)
 		return;
 
-	byte_stream_new(&bs, 11+strlen(peer_conn->sn) + 4+2+8+16);
+	byte_stream_new(&bs, 11+strlen(peer_conn->bn) + 4+2+8+16);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
 
 	/* ICBM header */
-	aim_im_puticbm(&bs, peer_conn->cookie, 0x0002, peer_conn->sn);
+	aim_im_puticbm(&bs, peer_conn->cookie, 0x0002, peer_conn->bn);
 
 	byte_stream_put16(&bs, 0x0005);
 	byte_stream_put16(&bs, 0x001a);
@@ -783,7 +783,7 @@
  * "I want to connect through a proxy server"
  */
 void
-aim_im_sendch2_odc_requestdirect(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 port, guint16 requestnumber)
+aim_im_sendch2_odc_requestdirect(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 port, guint16 requestnumber)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -795,12 +795,12 @@
 	if (conn == NULL)
 		return;
 
-	byte_stream_new(&bs, 246+strlen(sn));
+	byte_stream_new(&bs, 246+strlen(bn));
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
 
 	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, bn);
 
 	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
 
@@ -835,7 +835,7 @@
  * remote user to connect to us via a proxy server.
  */
 void
-aim_im_sendch2_odc_requestproxy(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 pin, guint16 requestnumber)
+aim_im_sendch2_odc_requestproxy(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 pin, guint16 requestnumber)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -848,12 +848,12 @@
 	if (conn == NULL)
 		return;
 
-	byte_stream_new(&bs, 246+strlen(sn));
+	byte_stream_new(&bs, 246+strlen(bn));
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
 
 	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, bn);
 
 	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
 
@@ -898,7 +898,7 @@
  *
  */
 void
-aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles)
+aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -915,7 +915,7 @@
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
 
 	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, bn);
 
 	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
 
@@ -981,7 +981,7 @@
  * remote user to connect to us via a proxy server.
  */
 void
-aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles)
+aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -999,7 +999,7 @@
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
 
 	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, bn);
 
 	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
 
@@ -1073,29 +1073,29 @@
  * Subtype 0x0006 - Request the status message of the given ICQ user.
  *
  * @param od The oscar session.
- * @param sn The UIN of the user of whom you wish to request info.
+ * @param bn The UIN of the user of whom you wish to request info.
  * @param type The type of info you wish to request.  This should be the current
  *        state of the user, as one of the AIM_ICQ_STATE_* defines.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-int aim_im_sendch2_geticqaway(OscarData *od, const char *sn, int type)
+int aim_im_sendch2_geticqaway(OscarData *od, const char *bn, int type)
 {
 	FlapConnection *conn;
 	ByteStream bs;
 	aim_snacid_t snacid;
 	guchar cookie[8];
 
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)) || !bn)
 		return -EINVAL;
 
 	aim_icbm_makecookie(cookie);
 
-	byte_stream_new(&bs, 8+2+1+strlen(sn) + 4+0x5e + 4);
+	byte_stream_new(&bs, 8+2+1+strlen(bn) + 4+0x5e + 4);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
 
 	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, bn);
 
 	/* TLV t(0005) - Encompasses almost everything below. */
 	byte_stream_put16(&bs, 0x0005); /* T */
@@ -1176,12 +1176,12 @@
  * but thats ok, because it gives me time to try to figure out what kind of drugs the AOL people
  * were taking when they merged the two protocols.
  *
- * @param sn The destination screen name.
+ * @param bn The destination buddy name.
  * @param type The type of message.  0x0007 for authorization denied.  0x0008 for authorization granted.
  * @param message The message you want to send, it should be null terminated.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-int aim_im_sendch4(OscarData *od, const char *sn, guint16 type, const char *message)
+int aim_im_sendch4(OscarData *od, const char *bn, guint16 type, const char *message)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -1191,17 +1191,17 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
 		return -EINVAL;
 
-	if (!sn || !type || !message)
+	if (!bn || !type || !message)
 		return -EINVAL;
 
-	byte_stream_new(&bs, 8+3+strlen(sn)+12+strlen(message)+1+4);
+	byte_stream_new(&bs, 8+3+strlen(bn)+12+strlen(message)+1+4);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
 
 	aim_icbm_makecookie(cookie);
 
 	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0004, sn);
+	aim_im_puticbm(&bs, cookie, 0x0004, bn);
 
 	/*
 	 * TLV t(0005)
@@ -1246,8 +1246,8 @@
 	guchar cookie[8];
 	guint16 channel;
 	GSList *tlvlist;
-	char *sn;
-	int snlen;
+	char *bn;
+	int bnlen;
 	guint16 icbmflags = 0;
 	guint8 flag1 = 0, flag2 = 0;
 	gchar *msg = NULL;
@@ -1264,8 +1264,8 @@
 		return 0;
 	}
 
-	snlen = byte_stream_get8(bs);
-	sn = byte_stream_getstr(bs, snlen);
+	bnlen = byte_stream_get8(bs);
+	bn = byte_stream_getstr(bs, bnlen);
 
 	tlvlist = aim_tlvlist_read(bs);
 
@@ -1296,9 +1296,9 @@
 	}
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, channel, sn, msg, icbmflags, flag1, flag2);
-
-	g_free(sn);
+		ret = userfunc(od, conn, frame, channel, bn, msg, icbmflags, flag1, flag2);
+
+	g_free(bn);
 	g_free(msg);
 	aim_tlvlist_free(tlvlist);
 
@@ -1480,7 +1480,7 @@
 		msglen = byte_stream_get16(&mbs);
 		if (msglen > byte_stream_empty(&mbs))
 		{
-			purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->sn);
+			purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->bn);
 			break;
 		}
 
@@ -1588,7 +1588,7 @@
 
 		if (length > byte_stream_empty(bs))
 		{
-			purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->sn);
+			purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->bn);
 			break;
 		}
 
@@ -1611,7 +1611,7 @@
 			args.featureslen = byte_stream_get16(bs);
 			if (args.featureslen > byte_stream_empty(bs))
 			{
-				purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->sn);
+				purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->bn);
 				break;
 			}
 			if (args.featureslen == 0)
@@ -1686,7 +1686,7 @@
 
 			if (length > byte_stream_empty(bs))
 			{
-				purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->sn);
+				purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->bn);
 				break;
 			}
 			g_free(args.extdata);
@@ -1761,7 +1761,7 @@
 			bnlen = byte_stream_get16(servdata);
 			bn = byte_stream_getstr(servdata, bnlen);
 
-			purple_debug_misc("oscar", "got a buddy list from %s: group %s, buddy %s\n", userinfo->sn, gn, bn);
+			purple_debug_misc("oscar", "got a buddy list from %s: group %s, buddy %s\n", userinfo->bn, gn, bn);
 
 			g_free(bn);
 		}
@@ -2250,7 +2250,7 @@
 }
 
 /*
- * Subtype 0x0008 - Send a warning to sn.
+ * Subtype 0x0008 - Send a warning to bn.
  *
  * Flags:
  *  AIM_WARN_ANON  Send as an anonymous (doesn't count as much)
@@ -2258,21 +2258,21 @@
  * returns -1 on error (couldn't alloc packet), 0 on success.
  *
  */
-int aim_im_warn(OscarData *od, FlapConnection *conn, const char *sn, guint32 flags)
+int aim_im_warn(OscarData *od, FlapConnection *conn, const char *bn, guint32 flags)
 {
 	ByteStream bs;
 	aim_snacid_t snacid;
 
-	if (!od || !conn || !sn)
+	if (!od || !conn || !bn)
 		return -EINVAL;
 
-	byte_stream_new(&bs, strlen(sn)+3);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0008, 0x0000, sn, strlen(sn)+1);
+	byte_stream_new(&bs, strlen(bn)+3);
+
+	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0008, 0x0000, bn, strlen(bn)+1);
 
 	byte_stream_put16(&bs, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000);
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
+	byte_stream_put8(&bs, strlen(bn));
+	byte_stream_putstr(&bs, bn);
 
 	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0008, 0x0000, snacid, &bs);
 
@@ -2314,7 +2314,7 @@
  *    AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers"
  *
  */
-int aim_im_denytransfer(OscarData *od, const char *sn, const guchar *cookie, guint16 code)
+int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, guint16 code)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -2324,15 +2324,15 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
 		return -EINVAL;
 
-	byte_stream_new(&bs, 8+2+1+strlen(sn)+6);
+	byte_stream_new(&bs, 8+2+1+strlen(bn)+6);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x000b, 0x0000, NULL, 0);
 
 	byte_stream_putraw(&bs, cookie, 8);
 
 	byte_stream_put16(&bs, 0x0002); /* channel */
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
+	byte_stream_put8(&bs, strlen(bn));
+	byte_stream_putstr(&bs, bn);
 
 	aim_tlvlist_add_16(&tlvlist, 0x0003, code);
 	aim_tlvlist_write(&bs, &tlvlist);
@@ -2345,7 +2345,7 @@
 	return 0;
 }
 
-static void parse_status_note_text(OscarData *od, guchar *cookie, char *sn, ByteStream *bs)
+static void parse_status_note_text(OscarData *od, guchar *cookie, char *bn, ByteStream *bs)
 {
 	struct aim_icq_info *info;
 	struct aim_icq_info *prev_info;
@@ -2499,10 +2499,10 @@
 	g_free(status_note_text);
 	g_free(stripped_status_note_text);
 
-	buddy = purple_find_buddy(account, sn);
+	buddy = purple_find_buddy(account, bn);
 	if (buddy == NULL)
 	{
-		purple_debug_misc("oscar", "clientautoresp: buddy %s was not found.\n", sn);
+		purple_debug_misc("oscar", "clientautoresp: buddy %s was not found.\n", bn);
 		g_free(status_note);
 		return;
 	}
@@ -2513,7 +2513,7 @@
 	presence = purple_buddy_get_presence(buddy);
 	status = purple_presence_get_active_status(presence);
 
-	purple_prpl_got_user_status(account, sn,
+	purple_prpl_got_user_status(account, bn,
 			purple_status_get_id(status),
 			"message", status_note, NULL);
 
@@ -2530,26 +2530,26 @@
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 channel, reason;
-	char *sn;
+	char *bn;
 	guchar *cookie;
-	guint8 snlen;
+	guint8 bnlen;
 
 	cookie = byte_stream_getraw(bs, 8);
 	channel = byte_stream_get16(bs);
-	snlen = byte_stream_get8(bs);
-	sn = byte_stream_getstr(bs, snlen);
+	bnlen = byte_stream_get8(bs);
+	bn = byte_stream_getstr(bs, bnlen);
 	reason = byte_stream_get16(bs);
 
 	if (channel == 0x0002)
 	{
 		if (reason == 0x0003) /* channel-specific */
 			/* parse status note text */
-			parse_status_note_text(od, cookie, sn, bs);
+			parse_status_note_text(od, cookie, bn, bs);
 
 		byte_stream_get16(bs); /* Unknown */
 		byte_stream_get16(bs); /* Unknown */
 		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-			ret = userfunc(od, conn, frame, channel, sn, reason, cookie);
+			ret = userfunc(od, conn, frame, channel, bn, reason, cookie);
 
 	} else if (channel == 0x0004) { /* ICQ message */
 		switch (reason) {
@@ -2594,20 +2594,20 @@
 				msg = byte_stream_getraw(bs, len);
 
 				if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-					ret = userfunc(od, conn, frame, channel, sn, reason, state, msg);
+					ret = userfunc(od, conn, frame, channel, bn, reason, state, msg);
 
 				g_free(msg);
 			} break;
 
 			default: {
 				if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-					ret = userfunc(od, conn, frame, channel, sn, reason);
+					ret = userfunc(od, conn, frame, channel, bn, reason);
 			} break;
 		} /* end switch */
 	}
 
 	g_free(cookie);
-	g_free(sn);
+	g_free(bn);
 
 	return ret;
 }
@@ -2625,17 +2625,17 @@
 	aim_rxcallback_t userfunc;
 	guint16 ch;
 	guchar *cookie;
-	char *sn;
+	char *bn;
 	int ret = 0;
 
 	cookie = byte_stream_getraw(bs, 8);
 	ch = byte_stream_get16(bs);
-	sn = byte_stream_getstr(bs, byte_stream_get8(bs));
+	bn = byte_stream_getstr(bs, byte_stream_get8(bs));
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, ch, sn);
-
-	g_free(sn);
+		ret = userfunc(od, conn, frame, ch, bn);
+
+	g_free(bn);
 	g_free(cookie);
 
 	return ret;
@@ -2672,7 +2672,7 @@
  * and Purple 0.60 and newer.
  *
  */
-int aim_im_sendmtn(OscarData *od, guint16 type1, const char *sn, guint16 type2)
+int aim_im_sendmtn(OscarData *od, guint16 type1, const char *bn, guint16 type2)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -2681,10 +2681,10 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
 		return -EINVAL;
 
-	if (!sn)
+	if (!bn)
 		return -EINVAL;
 
-	byte_stream_new(&bs, 11+strlen(sn)+2);
+	byte_stream_new(&bs, 11+strlen(bn)+2);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0014, 0x0000, NULL, 0);
 
@@ -2703,10 +2703,10 @@
 	byte_stream_put16(&bs, type1);
 
 	/*
-	 * Dest sn
+	 * Dest buddy name
 	 */
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
+	byte_stream_put8(&bs, strlen(bn));
+	byte_stream_putstr(&bs, bn);
 
 	/*
 	 * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn)
@@ -2731,20 +2731,20 @@
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
-	char *sn;
-	guint8 snlen;
+	char *bn;
+	guint8 bnlen;
 	guint16 type1, type2;
 
 	byte_stream_advance(bs, 8); /* Unknown - All 0's */
 	type1 = byte_stream_get16(bs);
-	snlen = byte_stream_get8(bs);
-	sn = byte_stream_getstr(bs, snlen);
+	bnlen = byte_stream_get8(bs);
+	bn = byte_stream_getstr(bs, bnlen);
 	type2 = byte_stream_get16(bs);
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, type1, sn, type2);
-
-	g_free(sn);
+		ret = userfunc(od, conn, frame, type1, bn, type2);
+
+	g_free(bn);
 
 	return ret;
 }
--- a/libpurple/protocols/oscar/family_locate.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/family_locate.c	Wed Jan 28 10:23:37 2009 +0000
@@ -100,7 +100,7 @@
 	  0x82, 0x22, 0x44, 0x45, 0x45, 0x53, 0x54, 0x00}},
 
 	/* Supports "new status message features" (Who advertises this one?) */
-	/* OSCAR_CAPABILITY_HOST_STATUS_TEXT_AWARE */ 
+	/* OSCAR_CAPABILITY_HOST_STATUS_TEXT_AWARE */
 	{OSCAR_CAPABILITY_GENERICUNKNOWN,
 	 {0x09, 0x46, 0x01, 0x0a, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
@@ -112,7 +112,7 @@
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
 	/* Client only asserts caps for services in which it is participating */
-	/* OSCAR_CAPABILITY_SMARTCAPS */ 
+	/* OSCAR_CAPABILITY_SMARTCAPS */
 	{OSCAR_CAPABILITY_GENERICUNKNOWN,
 	 {0x09, 0x46, 0x01, 0xff, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
@@ -253,11 +253,11 @@
 	FlapConnection *conn;
 	aim_rxcallback_t userfunc;
 
-	cur = aim_locate_finduserinfo(od, userinfo->sn);
+	cur = aim_locate_finduserinfo(od, userinfo->bn);
 
 	if (cur == NULL) {
 		cur = (aim_userinfo_t *)g_new0(aim_userinfo_t, 1);
-		cur->sn = g_strdup(userinfo->sn);
+		cur->bn = g_strdup(userinfo->bn);
 		cur->next = od->locate.userinfo;
 		od->locate.userinfo = cur;
 	}
@@ -366,35 +366,35 @@
 }
 
 /**
- * Remove this screen name from our queue.  If this info was requested
+ * Remove this buddy name from our queue.  If this info was requested
  * by our info request queue, then pop the next element off of the queue.
  *
  * @param od The aim session.
- * @param sn Screen name of the info we just received.
+ * @param bn Buddy name of the info we just received.
  * @return True if the request was explicit (client requested the info),
  *         false if the request was implicit (libfaim request the info).
  */
 static int
-aim_locate_gotuserinfo(OscarData *od, FlapConnection *conn, const char *sn)
+aim_locate_gotuserinfo(OscarData *od, FlapConnection *conn, const char *bn)
 {
 	struct userinfo_node *cur, *del;
 	int was_explicit = TRUE;
 
-	while ((od->locate.requested != NULL) && (aim_sncmp(sn, od->locate.requested->sn) == 0)) {
+	while ((od->locate.requested != NULL) && (oscar_util_name_compare(bn, od->locate.requested->bn) == 0)) {
 		del = od->locate.requested;
 		od->locate.requested = del->next;
 		was_explicit = FALSE;
-		g_free(del->sn);
+		g_free(del->bn);
 		g_free(del);
 	}
 
 	cur = od->locate.requested;
 	while ((cur != NULL) && (cur->next != NULL)) {
-		if (aim_sncmp(sn, cur->next->sn) == 0) {
+		if (oscar_util_name_compare(bn, cur->next->bn) == 0) {
 			del = cur->next;
 			cur->next = del->next;
 			was_explicit = FALSE;
-			g_free(del->sn);
+			g_free(del->bn);
 			g_free(del);
 		} else
 			cur = cur->next;
@@ -404,34 +404,34 @@
 }
 
 void
-aim_locate_autofetch_away_message(OscarData *od, const char *sn)
+aim_locate_autofetch_away_message(OscarData *od, const char *bn)
 {
 	struct userinfo_node *cur;
 
 	/* Make sure we haven't already made an info request for this buddy */
 	for (cur = od->locate.requested; cur != NULL; cur = cur->next)
-		if (aim_sncmp(sn, cur->sn) == 0)
+		if (oscar_util_name_compare(bn, cur->bn) == 0)
 			return;
 
 	/* Add a new node to our request queue */
 	cur = (struct userinfo_node *)g_malloc(sizeof(struct userinfo_node));
-	cur->sn = g_strdup(sn);
+	cur->bn = g_strdup(bn);
 	cur->next = od->locate.requested;
 	od->locate.requested = cur;
 
-	aim_locate_getinfoshort(od, cur->sn, 0x00000002);
+	aim_locate_getinfoshort(od, cur->bn, 0x00000002);
 }
 
-aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *sn) {
+aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *bn) {
 	aim_userinfo_t *cur = NULL;
 
-	if (sn == NULL)
+	if (bn == NULL)
 		return NULL;
 
 	cur = od->locate.userinfo;
 
 	while (cur != NULL) {
-		if (aim_sncmp(cur->sn, sn) == 0)
+		if (oscar_util_name_compare(cur->bn, bn) == 0)
 			return cur;
 		cur = cur->next;
 	}
@@ -552,7 +552,7 @@
 void
 aim_info_free(aim_userinfo_t *info)
 {
-	g_free(info->sn);
+	g_free(info->bn);
 	g_free(info->iconcsum);
 	g_free(info->info);
 	g_free(info->info_encoding);
@@ -572,7 +572,7 @@
 aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *outinfo)
 {
 	int curtlv, tlvcnt;
-	guint8 snlen;
+	guint8 bnlen;
 
 	if (!bs || !outinfo)
 		return -EINVAL;
@@ -581,11 +581,11 @@
 	memset(outinfo, 0x00, sizeof(aim_userinfo_t));
 
 	/*
-	 * Screen name.  Stored as an unterminated string prepended with a
+	 * Username.  Stored as an unterminated string prepended with a
 	 * byte containing its length.
 	 */
-	snlen = byte_stream_get8(bs);
-	outinfo->sn = byte_stream_getstr(bs, snlen);
+	bnlen = byte_stream_get8(bs);
+	outinfo->bn = byte_stream_getstr(bs, bnlen);
 
 	/*
 	 * Warning Level.  Stored as an unsigned short.
@@ -881,7 +881,7 @@
 			 */
 #ifdef LOG_UNKNOWN_TLV
 			purple_debug_misc("oscar", "userinfo: **warning: unexpected TLV:\n");
-			purple_debug_misc("oscar", "userinfo:   sn    =%s\n", outinfo->sn);
+			purple_debug_misc("oscar", "userinfo:   bn    =%s\n", outinfo->bn);
 			dumptlv(od, type, bs, length);
 #endif
 		}
@@ -906,8 +906,8 @@
 	if (!bs || !info)
 		return -EINVAL;
 
-	byte_stream_put8(bs, strlen(info->sn));
-	byte_stream_putstr(bs, info->sn);
+	byte_stream_put8(bs, strlen(info->bn));
+	byte_stream_putstr(bs, info->bn);
 
 	byte_stream_put16(bs, info->warnlevel);
 
@@ -922,7 +922,7 @@
 
 /* XXX - So, ICQ_OSCAR_SUPPORT is never defined anywhere... */
 #ifdef ICQ_OSCAR_SUPPORT
-	if (atoi(info->sn) != 0) {
+	if (atoi(info->bn) != 0) {
 		if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS)
 			aim_tlvlist_add_16(&tlvlist, 0x0006, info->icqinfo.status);
 		if (info->present & AIM_USERINFO_PRESENT_ICQIPADDR)
@@ -953,35 +953,35 @@
 	aim_rxcallback_t userfunc;
 	aim_snac_t *snac2;
 	guint16 reason;
-	char *sn;
+	char *bn;
 	int was_explicit;
 
 	if (!(snac2 = aim_remsnac(od, snac->id))) {
-		purple_debug_misc("oscar", "faim: locate.c, error(): received response from unknown request!\n");
+		purple_debug_misc("oscar", "locate error: received response from unknown request!\n");
 		return 0;
 	}
 
 	if ((snac2->family != SNAC_FAMILY_LOCATE) && (snac2->type != 0x0015)) {
-		purple_debug_misc("oscar", "faim: locate.c, error(): received response from invalid request! %d\n", snac2->family);
+		purple_debug_misc("oscar", "locate error: received response from invalid request! %d\n", snac2->family);
 		return 0;
 	}
 
-	if (!(sn = snac2->data)) {
-		purple_debug_misc("oscar", "faim: locate.c, error(): received response from request without a screen name!\n");
+	if (!(bn = snac2->data)) {
+		purple_debug_misc("oscar", "locate error: received response from request without a buddy name!\n");
 		return 0;
 	}
 
 	reason = byte_stream_get16(bs);
 
 	/*
-	 * Remove this screen name from our queue.  If the client requested
+	 * Remove this buddy name from our queue.  If the client requested
 	 * this buddy's info explicitly, then notify them that we do not have
 	 * info for this buddy.
 	 */
-	was_explicit = aim_locate_gotuserinfo(od, conn, sn);
+	was_explicit = aim_locate_gotuserinfo(od, conn, bn);
 	if (was_explicit == TRUE)
 		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-			ret = userfunc(od, conn, frame, reason, sn);
+			ret = userfunc(od, conn, frame, reason, bn);
 
 	if (snac2)
 		g_free(snac2->data);
@@ -1157,29 +1157,29 @@
 /*
  * Subtype 0x0005 - Request info of another AIM user.
  *
- * @param sn The screenname whose info you wish to request.
+ * @param bn The buddy name whose info you wish to request.
  * @param infotype The type of info you wish to request.
  *        0x0001 - Info/profile
  *        0x0003 - Away message
  *        0x0004 - Capabilities
  */
 int
-aim_locate_getinfo(OscarData *od, const char *sn, guint16 infotype)
+aim_locate_getinfo(OscarData *od, const char *bn, guint16 infotype)
 {
 	FlapConnection *conn;
 	ByteStream bs;
 	aim_snacid_t snacid;
 
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn)
 		return -EINVAL;
 
-	byte_stream_new(&bs, 2+1+strlen(sn));
+	byte_stream_new(&bs, 2+1+strlen(bn));
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0005, 0x0000, NULL, 0);
 
 	byte_stream_put16(&bs, infotype);
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
+	byte_stream_put8(&bs, strlen(bn));
+	byte_stream_putstr(&bs, bn);
 
 	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0005, 0x0000, snacid, &bs);
 
@@ -1229,18 +1229,18 @@
 	aim_tlvlist_free(tlvlist);
 
 	aim_locate_adduserinfo(od, userinfo);
-	userinfo2 = aim_locate_finduserinfo(od, userinfo->sn);
+	userinfo2 = aim_locate_finduserinfo(od, userinfo->bn);
 	aim_info_free(userinfo);
 	g_free(userinfo);
 
 	/*
-	 * Remove this screen name from our queue.  If the client requested
+	 * Remove this buddy name from our queue.  If the client requested
 	 * this buddy's info explicitly, then notify them that we have info
 	 * for this buddy.
 	 */
 	if (userinfo2 != NULL)
 	{
-		was_explicit = aim_locate_gotuserinfo(od, conn, userinfo2->sn);
+		was_explicit = aim_locate_gotuserinfo(od, conn, userinfo2->bn);
 		if (was_explicit == TRUE)
 			if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
 				ret = userfunc(od, conn, frame, userinfo2);
@@ -1307,7 +1307,7 @@
 /*
  * Subtype 0x000b - Huh? What is this?
  */
-int aim_locate_000b(OscarData *od, const char *sn)
+int aim_locate_000b(OscarData *od, const char *bn)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -1315,15 +1315,15 @@
 
 		return -EINVAL;
 
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn)
 		return -EINVAL;
 
-	byte_stream_new(&bs, 1+strlen(sn));
+	byte_stream_new(&bs, 1+strlen(bn));
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, NULL, 0);
 
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
+	byte_stream_put8(&bs, strlen(bn));
+	byte_stream_putstr(&bs, bn);
 
 	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, snacid, &bs);
 
@@ -1380,7 +1380,7 @@
  * Subtype 0x0015 - Request the info of a user using the short method.  This is
  * what iChat uses.  It normally is VERY leniently rate limited.
  *
- * @param sn The screen name whose info you wish to request.
+ * @param bn The buddy name whose info you wish to request.
  * @param flags The bitmask which specifies the type of info you wish to request.
  *        0x00000001 - Info/profile.
  *        0x00000002 - Away message.
@@ -1389,21 +1389,21 @@
  * @return Return 0 if no errors, otherwise return the error number.
  */
 int
-aim_locate_getinfoshort(OscarData *od, const char *sn, guint32 flags)
+aim_locate_getinfoshort(OscarData *od, const char *bn, guint32 flags)
 {
 	FlapConnection *conn;
 	ByteStream bs;
 	aim_snacid_t snacid;
 
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn)
 		return -EINVAL;
 
-	byte_stream_new(&bs, 4 + 1 + strlen(sn));
+	byte_stream_new(&bs, 4 + 1 + strlen(bn));
 	byte_stream_put32(&bs, flags);
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
+	byte_stream_put8(&bs, strlen(bn));
+	byte_stream_putstr(&bs, bn);
 
-	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, sn, strlen(sn)+1);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, bn, strlen(bn)+1);
 	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, snacid, &bs, FALSE);
 
 	byte_stream_destroy(&bs);
--- a/libpurple/protocols/oscar/family_odir.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/family_odir.c	Wed Jan 28 10:23:37 2009 +0000
@@ -31,7 +31,7 @@
 /**
  * Subtype 0x0002 - Submit a User Search Request
  *
- * Search for an AIM screen name based on their email address.
+ * Search for an AIM buddy based on their email address.
  *
  * @param od The oscar session.
  * @param region Should be "us-ascii" unless you know what you're doing.
@@ -70,7 +70,7 @@
 /**
  * Subtype 0x0002 - Submit a User Search Request
  *
- * Search for an AIM screen name based on various info
+ * Search for an AIM buddy based on various info
  * about the person.
  *
  * @param od The oscar session.
@@ -202,7 +202,7 @@
 		new->country = aim_tlv_getstr(tlvlist, 0x0006, 1);
 		new->state = aim_tlv_getstr(tlvlist, 0x0007, 1);
 		new->city = aim_tlv_getstr(tlvlist, 0x0008, 1);
-		new->sn = aim_tlv_getstr(tlvlist, 0x0009, 1);
+		new->bn = aim_tlv_getstr(tlvlist, 0x0009, 1);
 		new->interest = aim_tlv_getstr(tlvlist, 0x000b, 1);
 		new->nick = aim_tlv_getstr(tlvlist, 0x000c, 1);
 		new->zip = aim_tlv_getstr(tlvlist, 0x000d, 1);
@@ -228,7 +228,7 @@
 		g_free(del->country);
 		g_free(del->state);
 		g_free(del->city);
-		g_free(del->sn);
+		g_free(del->bn);
 		g_free(del->interest);
 		g_free(del->nick);
 		g_free(del->zip);
--- a/libpurple/protocols/oscar/odc.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/odc.c	Wed Jan 28 10:23:37 2009 +0000
@@ -62,7 +62,7 @@
 		PurpleConversation *conv;
 
 		account = purple_connection_get_account(conn->od->gc);
-		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn);
+		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->bn);
 		purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
 		g_free(tmp);
 	}
@@ -90,11 +90,11 @@
 
 	purple_debug_info("oscar", "Outgoing ODC frame to %s with "
 		"type=0x%04x, flags=0x%04x, payload length=%u\n",
-		conn->sn, frame->type, frame->flags, frame->payload.len);
+		conn->bn, frame->type, frame->flags, frame->payload.len);
 
 	account = purple_connection_get_account(conn->od->gc);
 	username = purple_account_get_username(account);
-	memcpy(frame->sn, username, strlen(username));
+	memcpy(frame->bn, username, strlen(username));
 	memcpy(frame->cookie, conn->cookie, 8);
 
 	length = 76;
@@ -116,7 +116,7 @@
 	byte_stream_put16(&bs, frame->flags);
 	byte_stream_put16(&bs, 0x0000);
 	byte_stream_put16(&bs, 0x0000);
-	byte_stream_putraw(&bs, frame->sn, 32);
+	byte_stream_putraw(&bs, frame->bn, 32);
 	byte_stream_putraw(&bs, frame->payload.data, frame->payload.len);
 
 	peer_connection_send(conn, &bs);
@@ -366,7 +366,7 @@
 		g_datalist_clear(&attributes);
 
 		/* Append the message up to the tag */
-		utf8 = purple_plugin_oscar_decode_im_part(account, conn->sn,
+		utf8 = purple_plugin_oscar_decode_im_part(account, conn->bn,
 				encoding, 0x0000, tmp, start - tmp);
 		if (utf8 != NULL) {
 			g_string_append(newmsg, utf8);
@@ -386,7 +386,7 @@
 	/* Append any remaining message data */
 	if (tmp <= msgend)
 	{
-		utf8 = purple_plugin_oscar_decode_im_part(account, conn->sn,
+		utf8 = purple_plugin_oscar_decode_im_part(account, conn->bn,
 				encoding, 0x0000, tmp, msgend - tmp);
 		if (utf8 != NULL) {
 			g_string_append(newmsg, utf8);
@@ -400,7 +400,7 @@
 		imflags |= PURPLE_MESSAGE_IMAGES;
 	if (autoreply)
 		imflags |= PURPLE_MESSAGE_AUTO_RESP;
-	serv_got_im(gc, conn->sn, newmsg->str, imflags, time(NULL));
+	serv_got_im(gc, conn->bn, newmsg->str, imflags, time(NULL));
 	g_string_free(newmsg, TRUE);
 
 	/* unref any images we allocated */
@@ -503,11 +503,11 @@
 	byte_stream_advance(bs, 4);
 	frame->flags = byte_stream_get16(bs);
 	byte_stream_advance(bs, 4);
-	byte_stream_getrawbuf(bs, frame->sn, 32);
+	byte_stream_getrawbuf(bs, frame->bn, 32);
 
 	purple_debug_info("oscar", "Incoming ODC frame from %s with "
 			"type=0x%04x, flags=0x%04x, payload length=%u\n",
-			frame->sn, frame->type, frame->flags, frame->payload.len);
+			frame->bn, frame->type, frame->flags, frame->payload.len);
 
 	if (!conn->ready)
 	{
@@ -558,7 +558,7 @@
 
 		/* Tell the local user that we are connected */
 		account = purple_connection_get_account(gc);
-		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn);
+		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->bn);
 		purple_conversation_write(conv, NULL, _("Direct IM established"),
 				PURPLE_MESSAGE_SYSTEM, time(NULL));
 	}
@@ -576,16 +576,16 @@
 		/* I had to leave this. It's just too funny. It reminds me of my sister. */
 		purple_debug_info("oscar", "ohmigod! %s has started typing "
 			"(DirectIM). He's going to send you a message! "
-			"*squeal*\n", conn->sn);
-		serv_got_typing(gc, conn->sn, 0, PURPLE_TYPING);
+			"*squeal*\n", conn->bn);
+		serv_got_typing(gc, conn->bn, 0, PURPLE_TYPING);
 	}
 	else if (frame->flags & 0x0004)
 	{
-		serv_got_typing(gc, conn->sn, 0, PURPLE_TYPED);
+		serv_got_typing(gc, conn->bn, 0, PURPLE_TYPED);
 	}
 	else
 	{
-		serv_got_typing_stopped(gc, conn->sn);
+		serv_got_typing_stopped(gc, conn->bn);
 	}
 
 	if (frame->payload.len > 0)
@@ -598,12 +598,12 @@
 
 			size1 = purple_str_size_to_units(frame->payload.len);
 			size2 = purple_str_size_to_units(DIRECTIM_MAX_FILESIZE);
-			tmp = g_strdup_printf(_("%s tried to send you a %s file, but we only allow files up to %s over Direct IM.  Try using file transfer instead.\n"), conn->sn, size1, size2);
+			tmp = g_strdup_printf(_("%s tried to send you a %s file, but we only allow files up to %s over Direct IM.  Try using file transfer instead.\n"), conn->bn, size1, size2);
 			g_free(size1);
 			g_free(size2);
 
 			account = purple_connection_get_account(conn->od->gc);
-			conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn);
+			conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->bn);
 			purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
 			g_free(tmp);
 
--- a/libpurple/protocols/oscar/oft.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/oft.c	Wed Jan 28 10:23:37 2009 +0000
@@ -544,7 +544,7 @@
 	frame.name = byte_stream_getraw(bs, frame.name_length);
 
 	purple_debug_info("oscar", "Incoming OFT frame from %s with "
-			"type=0x%04x\n", conn->sn, frame.type);
+			"type=0x%04x\n", conn->bn, frame.type);
 
 	/* TODOFT: peer_oft_dirconvert_fromstupid(frame->name); */
 
--- a/libpurple/protocols/oscar/oscar.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Wed Jan 28 10:23:37 2009 +0000
@@ -204,7 +204,7 @@
 void oscar_set_info(PurpleConnection *gc, const char *info);
 static void oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo, gboolean setstatus, PurpleStatus *status);
 static void oscar_set_extendedstatus(PurpleConnection *gc);
-static void oscar_format_screenname(PurpleConnection *gc, const char *nick);
+static void oscar_format_username(PurpleConnection *gc, const char *nick);
 static gboolean purple_ssi_rerequestdata(gpointer data);
 
 static void oscar_free_name_data(struct name_data *data) {
@@ -362,7 +362,7 @@
 	const char *charset = NULL;
 	char *ret = NULL;
 
-	if(aim_snvalid_icq(purple_account_get_username(account)))
+	if(oscar_util_valid_name_icq(purple_account_get_username(account)))
 		charset = purple_account_get_string(account, "encoding", NULL);
 
 	if(charset && *charset)
@@ -414,7 +414,7 @@
  * charsetstr1 is always set to what the correct encoding should be.
  */
 gchar *
-purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcesn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen)
+purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcebn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen)
 {
 	gchar *ret = NULL;
 	const gchar *charsetstr1, *charsetstr2;
@@ -428,7 +428,7 @@
 		charsetstr1 = "UTF-16BE";
 		charsetstr2 = "UTF-8";
 	} else if (charset == AIM_CHARSET_CUSTOM) {
-		if ((sourcesn != NULL) && aim_snvalid_icq(sourcesn))
+		if ((sourcebn != NULL) && oscar_util_valid_name_icq(sourcebn))
 			charsetstr1 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
 		else
 			charsetstr1 = "ISO-8859-1";
@@ -458,7 +458,7 @@
 		str[datalen] = '\0';
 		salvage = purple_utf8_salvage(str);
 		tmp = g_strdup_printf(_("(There was an error receiving this message.  Either you and %s have different encodings selected, or %s has a buggy client.)"),
-					  sourcesn, sourcesn);
+					  sourcebn, sourcebn);
 		ret = g_strdup_printf("%s %s", salvage, tmp);
 		g_free(tmp);
 		g_free(str);
@@ -473,11 +473,11 @@
  */
 static void
 purple_plugin_oscar_convert_to_best_encoding(PurpleConnection *gc,
-				const char *destsn, const gchar *from,
+				const char *destbn, const gchar *from,
 				gchar **msg, int *msglen_int,
 				guint16 *charset, guint16 *charsubset)
 {
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	PurpleAccount *account = purple_connection_get_account(gc);
 	GError *err = NULL;
 	aim_userinfo_t *userinfo = NULL;
@@ -499,13 +499,13 @@
 	 * capability, and they are online, then attempt to send
 	 * as UTF-16BE.
 	 */
-	if ((destsn != NULL) && aim_snvalid_icq(destsn))
-		userinfo = aim_locate_finduserinfo(od, destsn);
+	if ((destbn != NULL) && oscar_util_valid_name_icq(destbn))
+		userinfo = aim_locate_finduserinfo(od, destbn);
 
 	if ((userinfo != NULL) && (userinfo->capabilities & OSCAR_CAPABILITY_UNICODE))
 	{
 		PurpleBuddy *b;
-		b = purple_find_buddy(account, destsn);
+		b = purple_find_buddy(account, destbn);
 		if ((b != NULL) && (PURPLE_BUDDY_IS_ONLINE(b)))
 		{
 			*msg = g_convert(from, -1, "UTF-16BE", "UTF-8", NULL, &msglen, &err);
@@ -529,7 +529,7 @@
 	 * ICQ then attempt to send as the user specified character encoding.
 	 */
 	charsetstr = "ISO-8859-1";
-	if ((destsn != NULL) && aim_snvalid_icq(destsn))
+	if ((destbn != NULL) && oscar_util_valid_name_icq(destbn))
 		charsetstr = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
 
 	/*
@@ -808,16 +808,16 @@
 	gchar *message = NULL, *itmsurl = NULL, *tmp;
 	gboolean is_away;
 
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 
 	if (userinfo == NULL)
-		userinfo = aim_locate_finduserinfo(od, b->name);
+		userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
 
 	if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL)))
 		return;
 
 	if (b == NULL)
-		b = purple_find_buddy(purple_connection_get_account(gc), userinfo->sn);
+		b = purple_find_buddy(purple_connection_get_account(gc), userinfo->bn);
 
 	if (b) {
 		presence = purple_buddy_get_presence(b);
@@ -884,7 +884,7 @@
 
 	if (b) {
 		if (purple_presence_is_online(presence)) {
-			if (aim_snvalid_icq(b->name) || is_away || !message || !(*message)) {
+			if (oscar_util_valid_name_icq(purple_buddy_get_name(b)) || 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);
@@ -899,21 +899,20 @@
 				message = tmp;
 			}
 
+		} else if (aim_ssi_waitingforauth(od->ssi.local,
+			aim_ssi_itemlist_findparentname(od->ssi.local, purple_buddy_get_name(b)),
+			purple_buddy_get_name(b)))
+		{
+			/* Note if an offline buddy is not authorized */
+			tmp = g_strdup_printf("%s%s%s",
+					_("Not Authorized"),
+					(message && *message) ? ": " : "",
+					(message && *message) ? message : "");
+			g_free(message);
+			message = tmp;
 		} else {
-			if (aim_ssi_waitingforauth(od->ssi.local,
-									   aim_ssi_itemlist_findparentname(od->ssi.local, b->name),
-									   b->name)) {
-				/* Note if an offline buddy is not authorized */
-				tmp = g_strdup_printf("%s%s%s",
-									  _("Not Authorized"),
-									  (message && *message) ? ": " : "",
-									  (message && *message) ? message : "");
-				g_free(message);
-				message = tmp;
-			} else {
-				g_free(message);
-				message = g_strdup(_("Offline"));
-			}
+			g_free(message);
+			message = g_strdup(_("Offline"));
 		}
 
 	}
@@ -931,27 +930,30 @@
 	PurpleGroup *g = NULL;
 	struct buddyinfo *bi = NULL;
 	char *tmp;
-
-	od = gc->proto_data;
+	const char *bname, *gname = NULL;
+
+	od = purple_connection_get_protocol_data(gc);
 	account = purple_connection_get_account(gc);
 
 	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);
+		b = purple_find_buddy(account, userinfo->bn);
 
 	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);
 	}
 
 	if (userinfo != NULL)
-		bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->sn));
+		bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn));
 
 	if ((bi != NULL) && (bi->ipaddr != 0)) {
 		tmp =  g_strdup_printf("%hhu.%hhu.%hhu.%hhu",
@@ -969,8 +971,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);
@@ -1017,7 +1019,7 @@
 static struct chat_connection *
 find_oscar_chat(PurpleConnection *gc, int id)
 {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	GSList *cur;
 	struct chat_connection *cc;
 
@@ -1034,7 +1036,7 @@
 static struct chat_connection *
 find_oscar_chat_by_conn(PurpleConnection *gc, FlapConnection *conn)
 {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	GSList *cur;
 	struct chat_connection *cc;
 
@@ -1051,7 +1053,7 @@
 static struct chat_connection *
 find_oscar_chat_by_conv(PurpleConnection *gc, PurpleConversation *conv)
 {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	GSList *cur;
 	struct chat_connection *cc;
 
@@ -1076,7 +1078,7 @@
 static void
 oscar_chat_kill(PurpleConnection *gc, struct chat_connection *cc)
 {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	/* Notify the conversation window that we've left the chat */
 	serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(cc->conv)));
@@ -1292,10 +1294,10 @@
 		od->chpass = FALSE;
 	}
 	if (od->setnick) {
-		purple_debug_info("oscar", "formatting screen name\n");
-		aim_admin_setnick(od, conn, od->newsn);
-		g_free(od->newsn);
-		od->newsn = NULL;
+		purple_debug_info("oscar", "formatting username\n");
+		aim_admin_setnick(od, conn, od->newformatting);
+		g_free(od->newformatting);
+		od->newformatting = NULL;
 		od->setnick = FALSE;
 	}
 	if (od->conf) {
@@ -1391,7 +1393,7 @@
 	guint32 presence;
 
 	gc = data;
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	report_idle = strcmp((const char *)value, "none") != 0;
 	presence = aim_ssi_getpresence(od->ssi.local);
 
@@ -1414,7 +1416,7 @@
 	guint32 presence;
 
 	gc = data;
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	presence = aim_ssi_getpresence(od->ssi.local);
 
 	if (value)
@@ -1431,8 +1433,9 @@
 	FlapConnection *newconn;
 
 	gc = purple_account_get_connection(account);
-	od = gc->proto_data = oscar_data_new();
+	od = oscar_data_new();
 	od->gc = gc;
+	purple_connection_set_protocol_data(gc, od);
 
 	oscar_data_addhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, purple_connerr, 0);
 	oscar_data_addhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, flap_connection_established, 0);
@@ -1499,7 +1502,7 @@
 
 	purple_debug_misc("oscar", "oscar_login: gc = %p\n", gc);
 
-	if (!aim_snvalid(purple_account_get_username(account))) {
+	if (!oscar_util_valid_name(purple_account_get_username(account))) {
 		gchar *buf;
 		buf = g_strdup_printf(_("Unable to login: Could not sign on as %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."), purple_account_get_username(account));
 		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, buf);
@@ -1507,7 +1510,7 @@
 		return;
 	}
 
-	if (aim_snvalid_icq((purple_account_get_username(account)))) {
+	if (oscar_util_valid_name_icq((purple_account_get_username(account)))) {
 		od->icq = TRUE;
 	} else {
 		gc->flags |= PURPLE_CONNECTION_HTML;
@@ -1578,7 +1581,7 @@
 {
 	OscarData *od;
 
-	od = (OscarData *)gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 
 	while (od->oscar_chats)
 	{
@@ -1594,7 +1597,7 @@
 		g_free(cr);
 	}
 	oscar_data_destroy(od);
-	gc->proto_data = NULL;
+	purple_connection_set_protocol_data(gc, NULL);
 
 	purple_prefs_disconnect_by_handle(gc);
 
@@ -1605,7 +1608,7 @@
 purple_parse_auth_resp(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
 	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = gc->account;
+	PurpleAccount *account = purple_connection_get_account(gc);
 	char *host; int port;
 	int i;
 	FlapConnection *newconn;
@@ -1619,13 +1622,13 @@
 	va_end(ap);
 
 	purple_debug_info("oscar",
-			   "inside auth_resp (Username: %s)\n", info->sn);
+			   "inside auth_resp (Username: %s)\n", info->bn);
 
 	if (info->errorcode || !info->bosip || !info->cookielen || !info->cookie) {
 		char buf[256];
 		switch (info->errorcode) {
 		case 0x01:
-			/* Unregistered screen name */
+			/* Unregistered username */
 			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_USERNAME, _("Invalid username."));
 			break;
 		case 0x05:
@@ -1644,7 +1647,7 @@
 			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("The AOL Instant Messenger service is temporarily unavailable."));
 			break;
 		case 0x18:
-			/* screen name connecting too frequently */
+			/* username connecting too frequently */
 			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
 			break;
 		case 0x1c:
@@ -1722,7 +1725,7 @@
 purple_parse_auth_securid_request_yes_cb(gpointer user_data, const char *msg)
 {
 	PurpleConnection *gc = user_data;
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	aim_auth_securid_send(od, msg);
 }
@@ -1774,7 +1777,7 @@
 static void damn_you(gpointer data, gint source, PurpleInputCondition c)
 {
 	struct pieceofcrap *pos = data;
-	OscarData *od = pos->gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(pos->gc);
 	char in = '\0';
 	int x = 0;
 	unsigned char m[17];
@@ -1840,7 +1843,7 @@
 	pos->fd = source;
 
 	if (source < 0) {
-		GHashTable *ui_info = purple_core_get_ui_info();				
+		GHashTable *ui_info = purple_core_get_ui_info();
 		buf = g_strdup_printf(_("You may be disconnected shortly.  "
 				"Check %s for updates."),
 				((ui_info && g_hash_table_lookup(ui_info, "website")) ? (char *)g_hash_table_lookup(ui_info, "website") : PURPLE_WEBSITE));
@@ -2077,28 +2080,28 @@
 static gboolean purple_requesticqstatusnote(gpointer data)
 {
 	PurpleConnection *gc = data;
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	while (od->statusnotes_queue != NULL)
 	{
-		char *sn;
+		char *bn;
 		struct aim_ssi_item *ssi_item;
 		aim_tlv_t *note_hash;
 
-		sn = od->statusnotes_queue->data;
+		bn = od->statusnotes_queue->data;
 
 		ssi_item = aim_ssi_itemlist_finditem(od->ssi.local,
-											 NULL, sn, AIM_SSI_TYPE_BUDDY);
+											 NULL, bn, AIM_SSI_TYPE_BUDDY);
 		if (ssi_item != NULL)
 		{
 			note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1);
 			if (note_hash != NULL) {
-				aim_icq_getstatusnote(od, sn, note_hash->value, note_hash->length);
+				aim_icq_getstatusnote(od, bn, note_hash->value, note_hash->length);
 			}
 		}
 
-		od->statusnotes_queue = g_slist_remove(od->statusnotes_queue, sn);
-		g_free(sn);
+		od->statusnotes_queue = g_slist_remove(od->statusnotes_queue, bn);
+		g_free(bn);
 	}
 
 	od->statusnotes_queue_timer = 0;
@@ -2126,7 +2129,7 @@
 	va_end(ap);
 
 	g_return_val_if_fail(info != NULL, 1);
-	g_return_val_if_fail(info->sn != NULL, 1);
+	g_return_val_if_fail(info->bn != NULL, 1);
 
 	if (info->present & AIM_USERINFO_PRESENT_FLAGS) {
 		if (info->flags & AIM_FLAG_AWAY)
@@ -2140,7 +2143,7 @@
 		}
 	}
 
-	if (aim_snvalid_icq(info->sn)) {
+	if (oscar_util_valid_name_icq(info->bn)) {
 		if (type & AIM_ICQ_STATE_CHAT)
 			status_id = OSCAR_STATUS_ID_FREE4CHAT;
 		else if (type & AIM_ICQ_STATE_DND)
@@ -2166,9 +2169,9 @@
 
 	if (info->flags & AIM_FLAG_WIRELESS)
 	{
-		purple_prpl_got_user_status(account, info->sn, OSCAR_STATUS_ID_MOBILE, NULL);
+		purple_prpl_got_user_status(account, info->bn, OSCAR_STATUS_ID_MOBILE, NULL);
 	} else {
-		purple_prpl_got_user_status_deactive(account, info->sn, OSCAR_STATUS_ID_MOBILE);
+		purple_prpl_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE);
 	}
 
 	if (strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) == 0)
@@ -2193,7 +2196,7 @@
 		if (tmp2 == NULL && itmsurl != NULL)
 			tmp2 = "";
 
-		purple_prpl_got_user_status(account, info->sn, status_id,
+		purple_prpl_got_user_status(account, info->bn, status_id,
 				"message", tmp2, "itmsurl", itmsurl, NULL);
 		g_free(tmp);
 
@@ -2202,17 +2205,17 @@
 	}
 	else
 	{
-		PurpleBuddy *b = purple_find_buddy(account, info->sn);
+		PurpleBuddy *b = purple_find_buddy(account, info->bn);
 		PurplePresence *presence = purple_buddy_get_presence(b);
 		PurpleStatus *old_status = purple_presence_get_active_status(presence);
 		PurpleStatus *new_status = purple_presence_get_status(presence, status_id);
-		
+
 		/* If our status_id would change with this update, pass it to the core.
 		 * However, if our status_id would not change, do nothing, as we would clear out any existing
 		 * attributes on the status prematurely. purple_got_infoblock() will update the message as needed.
 		 */
 		if (old_status != new_status)
-			purple_prpl_got_user_status(account, info->sn, status_id, NULL);
+			purple_prpl_got_user_status(account, info->bn, status_id, NULL);
 	}
 
 	/* Login time stuff */
@@ -2220,7 +2223,7 @@
 		signon = info->onlinesince;
 	else if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
 		signon = time(NULL) - info->sessionlen;
-	purple_prpl_got_user_login_time(account, info->sn, signon);
+	purple_prpl_got_user_login_time(account, info->bn, signon);
 
 	/* Idle time stuff */
 	/* info->idletime is the number of minutes that this user has been idle */
@@ -2228,15 +2231,15 @@
 		time_idle = time(NULL) - info->idletime * 60;
 
 	if (time_idle > 0)
-		purple_prpl_got_user_idle(account, info->sn, TRUE, time_idle);
+		purple_prpl_got_user_idle(account, info->bn, TRUE, time_idle);
 	else
-		purple_prpl_got_user_idle(account, info->sn, FALSE, 0);
+		purple_prpl_got_user_idle(account, info->bn, FALSE, 0);
 
 	/* Server stored icon stuff */
-	bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, info->sn));
+	bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, info->bn));
 	if (!bi) {
 		bi = g_new0(struct buddyinfo, 1);
-		g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, info->sn)), bi);
+		g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, info->bn)), bi);
 	}
 	bi->typingnot = FALSE;
 	bi->ico_informed = FALSE;
@@ -2248,20 +2251,20 @@
 		PurpleBuddy *b = NULL;
 
 		b16 = purple_base16_encode(info->iconcsum, info->iconcsumlen);
-		b = purple_find_buddy(account, info->sn);
+		b = purple_find_buddy(account, info->bn);
 		if (b != NULL)
 			saved_b16 = purple_buddy_icons_get_checksum_for_user(b);
 
 		if (!b16 || !saved_b16 || strcmp(b16, saved_b16)) {
 			/* Invalidate the old icon for this user */
-			purple_buddy_icons_set_for_user(account, info->sn, NULL, 0, NULL);
+			purple_buddy_icons_set_for_user(account, info->bn, NULL, 0, NULL);
 
 			/* Fetch the new icon (if we're not already doing so) */
-			if (g_slist_find_custom(od->requesticon, info->sn,
-					(GCompareFunc)aim_sncmp) == NULL)
+			if (g_slist_find_custom(od->requesticon, info->bn,
+					(GCompareFunc)oscar_util_name_compare) == NULL)
 			{
 				od->requesticon = g_slist_prepend(od->requesticon,
-						g_strdup(purple_normalize(account, info->sn)));
+						g_strdup(purple_normalize(account, info->bn)));
 				purple_icons_fetch(gc);
 			}
 		}
@@ -2284,7 +2287,7 @@
 		aim_tlv_t *note_hash;
 
 		ssi_item = aim_ssi_itemlist_finditem(od->ssi.local,
-				NULL, info->sn, AIM_SSI_TYPE_BUDDY);
+				NULL, info->bn, AIM_SSI_TYPE_BUDDY);
 		if (ssi_item != NULL)
 		{
 			note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1);
@@ -2299,10 +2302,10 @@
 				 * buddy.
 				 */
 				if (od->statusnotes_queue == NULL ||
-					g_slist_find_custom(od->statusnotes_queue, info->sn, (GCompareFunc)strcmp) == NULL)
+					g_slist_find_custom(od->statusnotes_queue, info->bn, (GCompareFunc)strcmp) == NULL)
 				{
 					od->statusnotes_queue = g_slist_prepend(od->statusnotes_queue,
-							g_strdup(info->sn));
+							g_strdup(info->bn));
 
 					if (od->statusnotes_queue_timer > 0)
 						purple_timeout_remove(od->statusnotes_queue_timer);
@@ -2333,9 +2336,9 @@
 	info = va_arg(ap, aim_userinfo_t *);
 	va_end(ap);
 
-	purple_prpl_got_user_status(account, info->sn, OSCAR_STATUS_ID_OFFLINE, NULL);
-	purple_prpl_got_user_status_deactive(account, info->sn, OSCAR_STATUS_ID_MOBILE);
-	g_hash_table_remove(od->buddyinfo, purple_normalize(gc->account, info->sn));
+	purple_prpl_got_user_status(account, info->bn, OSCAR_STATUS_ID_OFFLINE, NULL);
+	purple_prpl_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE);
+	g_hash_table_remove(od->buddyinfo, purple_normalize(gc->account, info->bn));
 
 	return 1;
 }
@@ -2353,15 +2356,15 @@
 	GData *attribs;
 
 	purple_debug_misc("oscar", "Received IM from %s with %d parts\n",
-					userinfo->sn, args->mpmsg.numparts);
+					userinfo->bn, args->mpmsg.numparts);
 
 	if (args->mpmsg.numparts == 0)
 		return 1;
 
-	bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->sn));
+	bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn));
 	if (!bi) {
 		bi = g_new0(struct buddyinfo, 1);
-		g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, userinfo->sn)), bi);
+		g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, userinfo->bn)), bi);
 	}
 
 	if (args->icbmflags & AIM_IMFLAGS_AWAY)
@@ -2373,7 +2376,7 @@
 		bi->typingnot = FALSE;
 
 	if ((args->icbmflags & AIM_IMFLAGS_HASICON) && (args->iconlen) && (args->iconsum) && (args->iconstamp)) {
-		purple_debug_misc("oscar", "%s has an icon\n", userinfo->sn);
+		purple_debug_misc("oscar", "%s has an icon\n", userinfo->bn);
 		if ((args->iconlen != bi->ico_len) || (args->iconsum != bi->ico_csum) || (args->iconstamp != bi->ico_time)) {
 			bi->ico_need = TRUE;
 			bi->ico_len = args->iconlen;
@@ -2389,8 +2392,8 @@
 		size_t len = purple_imgstore_get_size(img);
 		purple_debug_info("oscar",
 				"Sending buddy icon to %s (%" G_GSIZE_FORMAT " bytes)\n",
-				userinfo->sn, len);
-		aim_im_sendch2_icon(od, userinfo->sn, data, len,
+				userinfo->bn, len);
+		aim_im_sendch2_icon(od, userinfo->bn, data, len,
 			purple_buddy_icons_get_account_icon_timestamp(account),
 			aimutil_iconsum(data, len));
 	}
@@ -2399,7 +2402,7 @@
 	message = g_string_new("");
 	curpart = args->mpmsg.parts;
 	while (curpart != NULL) {
-		tmp = purple_plugin_oscar_decode_im_part(account, userinfo->sn, curpart->charset,
+		tmp = purple_plugin_oscar_decode_im_part(account, userinfo->bn, curpart->charset,
 				curpart->charsubset, curpart->data, curpart->datalen);
 		if (tmp != NULL) {
 			g_string_append(message, tmp);
@@ -2419,7 +2422,7 @@
 	 * Note: There *may* be some clients which send messages as HTML formatted -
 	 *       they need to be special-cased somehow.
 	 */
-	if (aim_snvalid_icq(purple_account_get_username(account)) && aim_snvalid_icq(userinfo->sn)) {
+	if (oscar_util_valid_name_icq(purple_account_get_username(account)) && oscar_util_valid_name_icq(userinfo->bn)) {
 		/* being recevied by ICQ from ICQ - escape HTML so it is displayed as sent */
 		gchar *tmp2 = g_markup_escape_text(tmp, -1);
 		g_free(tmp);
@@ -2457,7 +2460,7 @@
 		g_datalist_clear(&attribs);
 	}
 
-	serv_got_im(gc, userinfo->sn, tmp, flags,
+	serv_got_im(gc, userinfo->bn, tmp, flags,
 			(args->icbmflags & AIM_IMFLAGS_OFFLINE) ? args->timestamp : time(NULL));
 	g_free(tmp);
 
@@ -2476,13 +2479,13 @@
 
 	gc = od->gc;
 	account = purple_connection_get_account(gc);
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 
 	if (args == NULL)
 		return 0;
 
 	purple_debug_misc("oscar", "Incoming rendezvous message of type %u, "
-			"user %s, status %hu\n", args->type, userinfo->sn, args->status);
+			"user %s, status %hu\n", args->type, userinfo->bn, args->status);
 
 	if (args->msg != NULL)
 	{
@@ -2528,7 +2531,7 @@
 				g_strdup_printf("%d", args->info.chat.roominfo.exchange));
 		serv_got_chat_invite(gc,
 				     utf8name,
-				     userinfo->sn,
+				     userinfo->bn,
 				     message,
 				     components);
 	}
@@ -2538,14 +2541,14 @@
 	{
 		if (args->status == AIM_RENDEZVOUS_PROPOSE)
 		{
-			peer_connection_got_proposition(od, userinfo->sn, message, args);
+			peer_connection_got_proposition(od, userinfo->bn, message, args);
 		}
 		else if (args->status == AIM_RENDEZVOUS_CANCEL)
 		{
 			/* The other user canceled a peer request */
 			PeerConnection *conn;
 
-			conn = peer_connection_find_by_cookie(od, userinfo->sn, args->cookie);
+			conn = peer_connection_find_by_cookie(od, userinfo->bn, args->cookie);
 			/*
 			 * If conn is NULL it means we haven't tried to create
 			 * a connection with that user.  They may be trying to
@@ -2576,7 +2579,7 @@
 
 	else if (args->type & OSCAR_CAPABILITY_BUDDYICON)
 	{
-		purple_buddy_icons_set_for_user(account, userinfo->sn,
+		purple_buddy_icons_set_for_user(account, userinfo->bn,
 									  g_memdup(args->info.icon.icon, args->info.icon.length),
 									  args->info.icon.length,
 									  NULL);
@@ -2613,9 +2616,10 @@
 	PurpleAccount *account;
 	PurpleBuddy *buddy;
 	PurpleGroup *group;
+	const char *bname, *gname;
 
 	gc = data->gc;
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	account = purple_connection_get_account(gc);
 	buddy = purple_find_buddy(account, data->name);
 	if (buddy != NULL)
@@ -2625,15 +2629,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);
@@ -2673,8 +2679,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 */
@@ -2683,7 +2689,7 @@
 {
 	struct name_data *data = cbdata;
 	PurpleConnection *gc = data->gc;
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	aim_ssi_sendauthreply(od, data->name, 0x01, NULL);
 
@@ -2695,7 +2701,7 @@
 purple_auth_dontgrant(struct name_data *data, char *msg)
 {
 	PurpleConnection *gc = data->gc;
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	aim_ssi_sendauthreply(od, data->name, 0x00, msg ? msg : _("No reason given."));
 }
@@ -2809,21 +2815,21 @@
 		case 0x06: { /* Someone requested authorization */
 			if (i >= 6) {
 				struct name_data *data = g_new(struct name_data, 1);
-				gchar *sn = g_strdup_printf("%u", args->uin);
+				gchar *bn = g_strdup_printf("%u", args->uin);
 				gchar *reason = NULL;
 
 				if (msg2[5] != NULL)
-					reason = purple_plugin_oscar_decode_im_part(account, sn, AIM_CHARSET_CUSTOM, 0x0000, msg2[5], strlen(msg2[5]));
+					reason = purple_plugin_oscar_decode_im_part(account, bn, AIM_CHARSET_CUSTOM, 0x0000, msg2[5], strlen(msg2[5]));
 
 				purple_debug_info("oscar",
 						   "Received an authorization request from UIN %u\n",
 						   args->uin);
 				data->gc = gc;
-				data->name = sn;
+				data->name = bn;
 				data->nick = NULL;
 
-				purple_account_request_authorization(account, sn, NULL, NULL,
-						reason, purple_find_buddy(account, sn) != NULL,
+				purple_account_request_authorization(account, bn, NULL, NULL,
+						reason, purple_find_buddy(account, bn) != NULL,
 						purple_auth_grant,
 						purple_auth_dontgrant_msgprompt, data);
 				g_free(reason);
@@ -3025,7 +3031,7 @@
 				   "You missed %hu messages from %s because they were invalid.",
 				   nummissed),
 				   nummissed,
-				   userinfo->sn);
+				   userinfo->bn);
 			break;
 		case 1: /* Message too large */
 			buf = g_strdup_printf(
@@ -3034,7 +3040,7 @@
 				   "You missed %hu messages from %s because they were too large.",
 				   nummissed),
 				   nummissed,
-				   userinfo->sn);
+				   userinfo->bn);
 			break;
 		case 2: /* Rate exceeded */
 			buf = g_strdup_printf(
@@ -3043,7 +3049,7 @@
 				   "You missed %hu messages from %s because the rate limit has been exceeded.",
 				   nummissed),
 				   nummissed,
-				   userinfo->sn);
+				   userinfo->bn);
 			break;
 		case 3: /* Evil Sender */
 			buf = g_strdup_printf(
@@ -3052,7 +3058,7 @@
 				   "You missed %hu messages from %s because his/her warning level is too high.",
 				   nummissed),
 				   nummissed,
-				   userinfo->sn);
+				   userinfo->bn);
 			break;
 		case 4: /* Evil Receiver */
 			buf = g_strdup_printf(
@@ -3061,7 +3067,7 @@
 				   "You missed %hu messages from %s because your warning level is too high.",
 				   nummissed),
 				   nummissed,
-				   userinfo->sn);
+				   userinfo->bn);
 			break;
 		default:
 			buf = g_strdup_printf(
@@ -3070,11 +3076,11 @@
 				   "You missed %hu messages from %s for an unknown reason.",
 				   nummissed),
 				   nummissed,
-				   userinfo->sn);
+				   userinfo->bn);
 			break;
 	}
 
-	if (!purple_conv_present_error(userinfo->sn, account, buf))
+	if (!purple_conv_present_error(userinfo->bn, account, buf))
 		purple_notify_error(od->gc, NULL, buf, NULL);
 	g_free(buf);
 
@@ -3192,7 +3198,7 @@
 static int purple_parse_msgerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	PurpleConnection *gc = od->gc;
 #ifdef TODOFT
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	PurpleXfer *xfer;
 #endif
 	va_list ap;
@@ -3220,7 +3226,7 @@
 	}
 #endif
 
-	/* Data is assumed to be the destination sn */
+	/* Data is assumed to be the destination bn */
 	buf = g_strdup_printf(_("Unable to send message: %s"), (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason."));
 	if (!purple_conv_present_error(data, purple_connection_get_account(gc), buf)) {
 		g_free(buf);
@@ -3237,25 +3243,25 @@
 	PurpleConnection *gc = od->gc;
 	va_list ap;
 	guint16 type1, type2;
-	char *sn;
+	char *bn;
 
 	va_start(ap, fr);
 	type1 = (guint16) va_arg(ap, unsigned int);
-	sn = va_arg(ap, char *);
+	bn = va_arg(ap, char *);
 	type2 = (guint16) va_arg(ap, unsigned int);
 	va_end(ap);
 
 	switch (type2) {
 		case 0x0000: { /* Text has been cleared */
-			serv_got_typing_stopped(gc, sn);
+			serv_got_typing_stopped(gc, bn);
 		} break;
 
 		case 0x0001: { /* Paused typing */
-			serv_got_typing(gc, sn, 0, PURPLE_TYPED);
+			serv_got_typing(gc, bn, 0, PURPLE_TYPED);
 		} break;
 
 		case 0x0002: { /* Typing */
-			serv_got_typing(gc, sn, 0, PURPLE_TYPING);
+			serv_got_typing(gc, bn, 0, PURPLE_TYPING);
 		} break;
 
 		default: {
@@ -3263,7 +3269,7 @@
 			 * It looks like iChat sometimes sends typing notification
 			 * with type1=0x0001 and type2=0x000f.  Not sure why.
 			 */
-			purple_debug_info("oscar", "Received unknown typing notification message from %s.  Type1 is 0x%04x and type2 is 0x%04hx.\n", sn, type1, type2);
+			purple_debug_info("oscar", "Received unknown typing notification message from %s.  Type1 is 0x%04x and type2 is 0x%04hx.\n", bn, type1, type2);
 		} break;
 	}
 
@@ -3324,7 +3330,7 @@
 
 	oscar_user_info_append_extra_info(gc, user_info, NULL, userinfo);
 
-	if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !aim_snvalid_sms(userinfo->sn)) {
+	if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !oscar_util_valid_name_sms(userinfo->bn)) {
 		/* An SMS contact is always online; its Online Since valid is not useful */
 		time_t t = userinfo->onlinesince;
 		oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t)));
@@ -3358,11 +3364,11 @@
 
 	purple_notify_user_info_add_section_break(user_info);
 	tmp = g_strdup_printf("<a href=\"http://profiles.aim.com/%s\">%s</a>",
-			purple_normalize(account, userinfo->sn), _("View web profile"));
+			purple_normalize(account, userinfo->bn), _("View web profile"));
 	purple_notify_user_info_add_pair(user_info, NULL, tmp);
 	g_free(tmp);
 
-	purple_notify_userinfo(gc, userinfo->sn, user_info, NULL, NULL);
+	purple_notify_userinfo(gc, userinfo->bn, user_info, NULL, NULL);
 	purple_notify_user_info_destroy(user_info);
 
 	return 1;
@@ -3384,14 +3390,14 @@
 	userinfo = va_arg(ap, aim_userinfo_t *);
 	va_end(ap);
 
-	b = purple_find_buddy(account, userinfo->sn);
+	b = purple_find_buddy(account, userinfo->bn);
 	if (b == NULL)
 		return 1;
 
-	if (!aim_snvalid_icq(userinfo->sn))
+	if (!oscar_util_valid_name_icq(userinfo->bn))
 	{
-		if (strcmp(purple_buddy_get_name(b), userinfo->sn) != 0)
-			serv_got_alias(gc, purple_buddy_get_name(b), userinfo->sn);
+		if (strcmp(purple_buddy_get_name(b), userinfo->bn) != 0)
+			serv_got_alias(gc, purple_buddy_get_name(b), userinfo->bn);
 		else
 			serv_got_alias(gc, purple_buddy_get_name(b), NULL);
 	}
@@ -3408,7 +3414,7 @@
 		                                 userinfo->away,
 		                                 userinfo->away_len);
 		g_free(charset);
-		purple_prpl_got_user_status(account, userinfo->sn,
+		purple_prpl_got_user_status(account, userinfo->bn,
 				purple_status_get_id(status),
 				"message", message, NULL);
 		g_free(message);
@@ -3529,7 +3535,7 @@
 		return 1;
 
 	for (i = 0; i < count; i++)
-		purple_conv_chat_add_user(PURPLE_CONV_CHAT(c->conv), info[i].sn, NULL, PURPLE_CBFLAGS_NONE, TRUE);
+		purple_conv_chat_add_user(PURPLE_CONV_CHAT(c->conv), info[i].bn, NULL, PURPLE_CBFLAGS_NONE, TRUE);
 
 	return 1;
 }
@@ -3552,7 +3558,7 @@
 		return 1;
 
 	for (i = 0; i < count; i++)
-		purple_conv_chat_remove_user(PURPLE_CONV_CHAT(c->conv), info[i].sn, NULL);
+		purple_conv_chat_remove_user(PURPLE_CONV_CHAT(c->conv), info[i].bn, NULL);
 
 	return 1;
 }
@@ -3621,7 +3627,7 @@
 	if (utf8 == NULL)
 		/* The conversion failed! */
 		utf8 = g_strdup(_("[Unable to display a message from this user because it contained invalid characters.]"));
-	serv_got_chat_in(gc, ccon->id, info->sn, 0, utf8, time((time_t)NULL));
+	serv_got_chat_in(gc, ccon->id, info->bn, 0, utf8, time((time_t)NULL));
 	g_free(utf8);
 
 	return 1;
@@ -3629,11 +3635,15 @@
 
 static int purple_email_parseupdate(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
-	PurpleConnection *gc = od->gc;
+	PurpleConnection *gc;
+	PurpleAccount *account;
 	struct aim_emailinfo *emailinfo;
 	int havenewmail;
 	char *alertitle, *alerturl;
 
+	gc = od->gc;
+	account = purple_connection_get_account(gc);
+
 	va_start(ap, fr);
 	emailinfo = va_arg(ap, struct aim_emailinfo *);
 	havenewmail = va_arg(ap, int);
@@ -3641,12 +3651,13 @@
 	alerturl  = va_arg(ap, char *);
 	va_end(ap);
 
-	if ((emailinfo != NULL) && purple_account_get_check_mail(gc->account)) {
-		gchar *to = g_strdup_printf("%s%s%s", purple_account_get_username(purple_connection_get_account(gc)),
-									emailinfo->domain ? "@" : "",
-									emailinfo->domain ? emailinfo->domain : "");
-		if (emailinfo->unread && havenewmail)
-			purple_notify_emails(gc, emailinfo->nummsgs, FALSE, NULL, NULL, (const char **)&to, (const char **)&emailinfo->url, NULL, NULL);
+	if (account != NULL && emailinfo != NULL && emailinfo->unread && havenewmail) {
+		gchar *to = g_strdup_printf("%s%s%s",
+				purple_account_get_username(account),
+				emailinfo->domain ? "@" : "",
+				emailinfo->domain ? emailinfo->domain : "");
+		purple_notify_emails(gc, emailinfo->nummsgs, FALSE, NULL, NULL,
+				(const char **)&to, (const char **)&emailinfo->url, NULL, NULL);
 		g_free(to);
 	}
 
@@ -3659,12 +3670,12 @@
 static int purple_icon_parseicon(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	PurpleConnection *gc = od->gc;
 	va_list ap;
-	char *sn;
+	char *bn;
 	guint8 iconcsumtype, *iconcsum, *icon;
 	guint16 iconcsumlen, iconlen;
 
 	va_start(ap, fr);
-	sn = va_arg(ap, char *);
+	bn = va_arg(ap, char *);
 	iconcsumtype = va_arg(ap, int);
 	iconcsum = va_arg(ap, guint8 *);
 	iconcsumlen = va_arg(ap, int);
@@ -3679,7 +3690,7 @@
 	if ((iconlen > 0) && (iconlen != 90)) {
 		char *b16 = purple_base16_encode(iconcsum, iconcsumlen);
 		purple_buddy_icons_set_for_user(purple_connection_get_account(gc),
-									  sn, g_memdup(icon, iconlen), iconlen, b16);
+									  bn, g_memdup(icon, iconlen), iconlen, b16);
 		g_free(b16);
 	}
 
@@ -3689,7 +3700,7 @@
 static void
 purple_icons_fetch(PurpleConnection *gc)
 {
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	aim_userinfo_t *userinfo;
 	FlapConnection *conn;
 
@@ -3736,14 +3747,14 @@
 static int purple_parse_msgack(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	guint16 type;
-	char *sn;
+	char *bn;
 
 	va_start(ap, fr);
 	type = (guint16) va_arg(ap, unsigned int);
-	sn = va_arg(ap, char *);
+	bn = va_arg(ap, char *);
 	va_end(ap);
 
-	purple_debug_info("oscar", "Sent message to %s.\n", sn);
+	purple_debug_info("oscar", "Sent message to %s.\n", bn);
 
 	return 1;
 }
@@ -3803,7 +3814,7 @@
 	userinfo = va_arg(ap, aim_userinfo_t *);
 	va_end(ap);
 
-	purple_prpl_got_account_warning_level(account, (userinfo && userinfo->sn) ? userinfo->sn : NULL, (newevil/10.0) + 0.5);
+	purple_prpl_got_account_warning_level(account, (userinfo && userinfo->bn) ? userinfo->bn : NULL, (newevil/10.0) + 0.5);
 #endif
 
 	return 1;
@@ -3818,7 +3829,7 @@
 	info = va_arg(ap, aim_userinfo_t *);
 	va_end(ap);
 
-	purple_connection_set_display_name(od->gc, info->sn);
+	purple_connection_set_display_name(od->gc, info->bn);
 
 	/*
 	 * What's with the + 0.5?
@@ -3927,13 +3938,13 @@
 	PurpleAccount *account;
 	PurpleStatus *status;
 	PurplePresence *presence;
-	const char *message, *itmsurl;
+	const char *username, *message, *itmsurl;
 	char *tmp;
 	va_list ap;
 	guint16 maxpermits, maxdenies;
 
 	gc = od->gc;
-	od = (OscarData *)gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	account = purple_connection_get_account(gc);
 
 	va_start(ap, fr);
@@ -3956,12 +3967,13 @@
 	if (purple_account_get_user_info(account) != NULL)
 		serv_set_info(gc, purple_account_get_user_info(account));
 
-	if (!od->icq && strcmp(purple_account_get_username(account), purple_connection_get_display_name(gc)) != 0)
+	username = purple_account_get_username(account);
+	if (!od->icq && strcmp(username, purple_connection_get_display_name(gc)) != 0)
 		/*
-		 * Format the screen name for AIM accounts if it's different
+		 * Format the username for AIM accounts if it's different
 		 * than what's currently set.
 		 */
-		oscar_format_screenname(gc, account->username);
+		oscar_format_username(gc, username);
 
 	/* Set our available message based on the current status */
 	status = purple_account_get_active_status(account);
@@ -3995,13 +4007,13 @@
 	/*
 	 * The "if" statement here is a pathetic attempt to not attempt to
 	 * connect to the alerts servce (aka email notification) if this
-	 * screen name does not support it.  I think mail notification
+	 * username does not support it.  I think mail notification
 	 * works for @mac.com accounts but does not work for the newer
 	 * @anythingelse.com accounts.  If that's true then this change
 	 * breaks mail notification for @mac.com accounts, but it gets rid
 	 * of an annoying error at signon for @anythingelse.com accounts.
 	 */
-	if ((od->authinfo->email != NULL) && ((strchr(gc->account->username, '@') == NULL)))
+	if (od->authinfo->email != NULL && strchr(username, '@') == NULL)
 		aim_srv_requestnew(od, SNAC_FAMILY_ALERT);
 
 	return 1;
@@ -4065,9 +4077,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;
 
@@ -4084,7 +4096,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);
@@ -4093,7 +4105,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);
@@ -4128,7 +4140,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);
@@ -4164,7 +4176,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);
@@ -4198,7 +4210,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);
@@ -4328,7 +4340,7 @@
 	PurpleConnection *gc = od->gc;
 	va_list ap;
 	guint16 perms, err;
-	char *url, *sn, *email;
+	char *url, *bn, *email;
 	int change;
 
 	va_start(ap, fr);
@@ -4336,15 +4348,15 @@
 	perms = (guint16) va_arg(ap, unsigned int);
 	err = (guint16) va_arg(ap, unsigned int);
 	url = va_arg(ap, char *);
-	sn = va_arg(ap, char *);
+	bn = va_arg(ap, char *);
 	email = va_arg(ap, char *);
 	va_end(ap);
 
 	purple_debug_misc("oscar",
-					"account info: because of %s, perms=0x%04x, err=0x%04x, url=%s, sn=%s, email=%s\n",
+					"account info: because of %s, perms=0x%04x, err=0x%04x, url=%s, bn=%s, email=%s\n",
 					change ? "change" : "request", perms, err,
 					(url != NULL) ? url : "(null)",
-					(sn != NULL) ? sn : "(null)",
+					(bn != NULL) ? bn : "(null)",
 					(email != NULL) ? email : "(null)");
 
 	if ((err > 0) && (url != NULL)) {
@@ -4386,7 +4398,7 @@
 	OscarData *od;
 	FlapConnection *conn;
 
-	od = (OscarData *)gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	conn = flap_connection_getbytype(od, SNAC_FAMILY_LOCATE);
 	if (conn != NULL)
 		flap_connection_send_keepalive(od, conn);
@@ -4398,7 +4410,7 @@
 	OscarData *od;
 	PeerConnection *conn;
 
-	od = (OscarData *)gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM);
 
 	if ((conn != NULL) && (conn->ready))
@@ -4408,7 +4420,7 @@
 	else {
 		/* Don't send if this turkey is in our deny list */
 		GSList *list;
-		for (list=gc->account->deny; (list && aim_sncmp(name, list->data)); list=list->next);
+		for (list=gc->account->deny; (list && oscar_util_name_compare(name, list->data)); list=list->next);
 		if (!list) {
 			struct buddyinfo *bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(gc->account, name));
 			if (bi && bi->typingnot) {
@@ -4494,7 +4506,7 @@
 
 	/* Convert the message to a good encoding */
 	purple_plugin_oscar_convert_to_best_encoding(conn->od->gc,
-			conn->sn, msg->str, &tmp, &tmplen, &charset, &charsubset);
+			conn->bn, msg->str, &tmp, &tmplen, &charset, &charsubset);
 	g_string_free(msg, TRUE);
 	msg = g_string_new_len(tmp, tmplen);
 	g_free(tmp);
@@ -4520,11 +4532,11 @@
 	char *tmp1, *tmp2;
 	gboolean is_sms, is_html;
 
-	od = (OscarData *)gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	account = purple_connection_get_account(gc);
 	ret = 0;
 
-	is_sms = aim_snvalid_sms(name);
+	is_sms = oscar_util_valid_name_sms(name);
 
 	if (od->icq && is_sms) {
 		/*
@@ -4562,7 +4574,7 @@
 			                        "You must be Direct Connected to send IM Images."),
 			                        PURPLE_MESSAGE_ERROR, time(NULL));
 
-		buddy = purple_find_buddy(gc->account, name);
+		buddy = purple_find_buddy(account, name);
 
 		bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, name));
 		if (!bi) {
@@ -4637,17 +4649,17 @@
 			purple_imgstore_unref(img);
 		}
 
-		args.destsn = name;
+		args.destbn = name;
 
 		/*
 		 * If we're IMing an SMS user or an ICQ user from an ICQ account, then strip HTML.
 		 */
-		if (aim_snvalid_sms(name)) {
+		if (oscar_util_valid_name_sms(name)) {
 			/* Messaging an SMS (mobile) user */
 			tmp2 = purple_markup_strip_html(tmp1);
 			is_html = FALSE;
-		} else if (aim_snvalid_icq(purple_account_get_username(account))) {
-			if (aim_snvalid_icq(name)) {
+		} else if (oscar_util_valid_name_icq(purple_account_get_username(account))) {
+			if (oscar_util_valid_name_icq(name)) {
 				/* From ICQ to ICQ */
 				tmp2 = purple_markup_strip_html(tmp1);
 				is_html = FALSE;
@@ -4707,9 +4719,9 @@
  * AIM users can only request AIM info.
  */
 void oscar_get_info(PurpleConnection *gc, const char *name) {
-	OscarData *od = (OscarData *)gc->proto_data;
-
-	if (od->icq && aim_snvalid_icq(name))
+	OscarData *od = purple_connection_get_protocol_data(gc);
+
+	if (od->icq && oscar_util_valid_name_icq(name))
 		aim_icq_getallinfo(od, name);
 	else
 		aim_locate_getinfoshort(od, name, 0x00000003);
@@ -4719,14 +4731,14 @@
 static void oscar_set_dir(PurpleConnection *gc, const char *first, const char *middle, const char *last,
 			  const char *maiden, const char *city, const char *state, const char *country, int web) {
 	/* XXX - some of these things are wrong, but i'm lazy */
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	aim_locate_setdirinfo(od, first, middle, last,
 				maiden, NULL, NULL, city, state, NULL, 0, web);
 }
 #endif
 
 void oscar_set_idle(PurpleConnection *gc, int time) {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	aim_srv_setidle(od, time);
 }
 
@@ -4772,7 +4784,7 @@
 	const gchar *status_id;
 	guint32 data = 0x00000000;
 
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	account = purple_connection_get_account(gc);
 	status = purple_account_get_active_status(account);
 	status_id = purple_status_get_id(status);
@@ -4806,7 +4818,7 @@
 						  gboolean setstatus, PurpleStatus *status)
 {
 	PurpleConnection *gc = purple_account_get_connection(account);
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	PurpleStatusType *status_type;
 	PurpleStatusPrimitive primitive;
 
@@ -4919,7 +4931,7 @@
 	OscarData *od = NULL;
 
 	if (gc)
-		od = (OscarData *)gc->proto_data;
+		od = purple_connection_get_protocol_data(gc);
 	if (!od)
 		return;
 
@@ -4949,14 +4961,14 @@
 	oscar_set_info_and_status(account, FALSE, NULL, TRUE, status);
 
 	/* Set the ICQ status for ICQ accounts only */
-	if (aim_snvalid_icq(purple_account_get_username(account)))
+	if (oscar_util_valid_name_icq(purple_account_get_username(account)))
 		oscar_set_status_icq(account, status);
 }
 
 #ifdef CRAZY_WARN
 void
 oscar_warn(PurpleConnection *gc, const char *name, gboolean anonymous) {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	aim_im_warn(od, od->conn, name, anonymous ? AIM_WARN_ANON : 0);
 }
 #endif
@@ -4965,14 +4977,17 @@
 oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
 	OscarData *od;
 	PurpleAccount *account;
-
-	od = (OscarData *)gc->proto_data;
+	const char *bname, *gname;
+
+	od = purple_connection_get_protocol_data(gc);
 	account = purple_connection_get_account(gc);
-
-	if (!aim_snvalid(buddy->name)) {
+	bname = purple_buddy_get_name(buddy);
+	gname = purple_group_get_name(group);
+
+	if (!oscar_util_valid_name(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);
 
@@ -4982,39 +4997,40 @@
 		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;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	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);
 	}
 }
 
 void oscar_move_buddy(PurpleConnection *gc, const char *name, const char *old_group, const char *new_group) {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
+
 	if (od->ssi.received_data && strcmp(old_group, new_group)) {
 		purple_debug_info("oscar",
 				   "ssi: moving buddy %s from group %s to group %s\n", name, old_group, new_group);
@@ -5023,7 +5039,8 @@
 }
 
 void oscar_alias_buddy(PurpleConnection *gc, const char *name, const char *alias) {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
+
 	if (od->ssi.received_data) {
 		char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, name);
 		if (gname) {
@@ -5038,10 +5055,11 @@
  * FYI, the OSCAR SSI code removes empty groups automatically.
  */
 void oscar_rename_group(PurpleConnection *gc, const char *old_name, PurpleGroup *group, GList *moved_buddies) {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	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);
 
@@ -5051,25 +5069,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(purple_connection_get_protocol_data(gc), purple_group_get_name(group));
 }
 
 static gboolean purple_ssi_rerequestdata(gpointer data) {
@@ -5150,7 +5168,7 @@
 	guint32 timestamp;
 
 	gc = od->gc;
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	account = purple_connection_get_account(gc);
 
 	va_start(ap, fr);
@@ -5178,33 +5196,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);
 							}
@@ -5221,8 +5250,8 @@
 		}
 
 		/* Permit list */
-		if (gc->account->permit) {
-			next = gc->account->permit;
+		if (account->permit) {
+			next = account->permit;
 			while (next != NULL) {
 				cur = next;
 				next = next->next;
@@ -5235,8 +5264,8 @@
 		}
 
 		/* Deny list */
-		if (gc->account->deny) {
-			next = gc->account->deny;
+		if (account->deny) {
+			next = account->deny;
 			while (next != NULL) {
 				cur = next;
 				next = next->next;
@@ -5280,7 +5309,7 @@
 						if (g_utf8_validate(gname, -1, NULL))
 							gname_utf8 = g_strdup(gname);
 						else
-							gname_utf8 = oscar_utf8_try_convert(gc->account, gname);
+							gname_utf8 = oscar_utf8_try_convert(account, gname);
 					} else
 						gname_utf8 = NULL;
 
@@ -5300,18 +5329,18 @@
 					} 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)) {
+					if (!oscar_util_name_compare(curitem->name, purple_account_get_username(account))) {
 						char *comment = aim_ssi_getcomment(od->ssi.local, gname, curitem->name);
 						if (comment != NULL)
 						{
@@ -5321,7 +5350,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);
@@ -5344,7 +5373,7 @@
 					if (g_utf8_validate(gname, -1, NULL))
 						gname_utf8 = g_strdup(gname);
 					else
-						gname_utf8 = oscar_utf8_try_convert(gc->account, gname);
+						gname_utf8 = oscar_utf8_try_convert(account, gname);
 				} else
 					gname_utf8 = NULL;
 
@@ -5359,7 +5388,7 @@
 				if (curitem->name) {
 					/* if (!find_permdeny_by_name(gc->permit, curitem->name)) { AAA */
 					GSList *list;
-					for (list=account->permit; (list && aim_sncmp(curitem->name, list->data)); list=list->next);
+					for (list=account->permit; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next);
 					if (!list) {
 						purple_debug_info("oscar",
 								   "ssi: adding permit buddy %s to local list\n", curitem->name);
@@ -5371,7 +5400,7 @@
 			case 0x0003: { /* Deny buddy */
 				if (curitem->name) {
 					GSList *list;
-					for (list=account->deny; (list && aim_sncmp(curitem->name, list->data)); list=list->next);
+					for (list=account->deny; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next);
 					if (!list) {
 						purple_debug_info("oscar",
 								   "ssi: adding deny buddy %s to local list\n", curitem->name);
@@ -5388,7 +5417,7 @@
 								   "ssi: changing permdeny from %d to %hhu\n", account->perm_deny, permdeny);
 						account->perm_deny = permdeny;
 						if (od->icq && account->perm_deny == PURPLE_PRIVACY_ALLOW_USERS) {
-							purple_presence_set_status_active(account->presence, OSCAR_STATUS_ID_INVISIBLE, TRUE);
+							purple_presence_set_status_active(purple_account_get_presence(account), OSCAR_STATUS_ID_INVISIBLE, TRUE);
 						}
 					}
 				}
@@ -5535,13 +5564,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);
 		}
 
 	}
@@ -5570,36 +5597,36 @@
 static int purple_ssi_authgiven(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	PurpleConnection *gc = od->gc;
 	va_list ap;
-	char *sn, *msg;
+	char *bn, *msg;
 	gchar *dialog_msg, *nombre;
 	struct name_data *data;
 	PurpleBuddy *buddy;
 
 	va_start(ap, fr);
-	sn = va_arg(ap, char *);
+	bn = va_arg(ap, char *);
 	msg = va_arg(ap, char *);
 	va_end(ap);
 
 	purple_debug_info("oscar",
-			   "ssi: %s has given you permission to add him to your buddy list\n", sn);
-
-	buddy = purple_find_buddy(gc->account, sn);
+			   "ssi: %s has given you permission to add him to your buddy list\n", bn);
+
+	buddy = purple_find_buddy(purple_connection_get_account(gc), bn);
 	if (buddy && (purple_buddy_get_alias_only(buddy)))
-		nombre = g_strdup_printf("%s (%s)", sn, purple_buddy_get_alias_only(buddy));
+		nombre = g_strdup_printf("%s (%s)", bn, purple_buddy_get_alias_only(buddy));
 	else
-		nombre = g_strdup(sn);
+		nombre = g_strdup(bn);
 
 	dialog_msg = g_strdup_printf(_("The user %s has given you permission to add him or her to your buddy list.  Do you want to add this user?"), nombre);
 	g_free(nombre);
 
 	data = g_new(struct name_data, 1);
 	data->gc = gc;
-	data->name = g_strdup(sn);
+	data->name = g_strdup(bn);
 	data->nick = (buddy ? g_strdup(purple_buddy_get_alias_only(buddy)) : NULL);
 
 	purple_request_yes_no(gc, NULL, _("Authorization Given"), dialog_msg,
 						PURPLE_DEFAULT_ACTION_NONE,
-						purple_connection_get_account(gc), sn, NULL,
+						purple_connection_get_account(gc), bn, NULL,
 						data,
 						G_CALLBACK(purple_icq_buddyadd),
 						G_CALLBACK(oscar_free_name_data));
@@ -5611,7 +5638,7 @@
 static int purple_ssi_authrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	PurpleConnection *gc = od->gc;
 	va_list ap;
-	char *sn;
+	char *bn;
 	char *msg;
 	PurpleAccount *account = purple_connection_get_account(gc);
 	gchar *reason = NULL;
@@ -5619,24 +5646,24 @@
 	PurpleBuddy *buddy;
 
 	va_start(ap, fr);
-	sn = va_arg(ap, char *);
+	bn = va_arg(ap, char *);
 	msg = va_arg(ap, char *);
 	va_end(ap);
 
 	purple_debug_info("oscar",
-			   "ssi: received authorization request from %s\n", sn);
-
-	buddy = purple_find_buddy(account, sn);
+			   "ssi: received authorization request from %s\n", bn);
+
+	buddy = purple_find_buddy(account, bn);
 
 	if (msg != NULL)
-		reason = purple_plugin_oscar_decode_im_part(account, sn, AIM_CHARSET_CUSTOM, 0x0000, msg, strlen(msg));
+		reason = purple_plugin_oscar_decode_im_part(account, bn, AIM_CHARSET_CUSTOM, 0x0000, msg, strlen(msg));
 
 	data = g_new(struct name_data, 1);
 	data->gc = gc;
-	data->name = g_strdup(sn);
+	data->name = g_strdup(bn);
 	data->nick = (buddy ? g_strdup(purple_buddy_get_alias_only(buddy)) : NULL);
 
-	purple_account_request_authorization(account, sn, NULL,
+	purple_account_request_authorization(account, bn, NULL,
 			(buddy ? purple_buddy_get_alias_only(buddy) : NULL),
 			reason, buddy != NULL, purple_auth_grant,
 			purple_auth_dontgrant_msgprompt, data);
@@ -5648,25 +5675,25 @@
 static int purple_ssi_authreply(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	PurpleConnection *gc = od->gc;
 	va_list ap;
-	char *sn, *msg;
+	char *bn, *msg;
 	gchar *dialog_msg, *nombre;
 	guint8 reply;
 	PurpleBuddy *buddy;
 
 	va_start(ap, fr);
-	sn = va_arg(ap, char *);
+	bn = va_arg(ap, char *);
 	reply = (guint8)va_arg(ap, int);
 	msg = va_arg(ap, char *);
 	va_end(ap);
 
 	purple_debug_info("oscar",
-			   "ssi: received authorization reply from %s.  Reply is 0x%04hhx\n", sn, reply);
-
-	buddy = purple_find_buddy(gc->account, sn);
+			   "ssi: received authorization reply from %s.  Reply is 0x%04hhx\n", bn, reply);
+
+	buddy = purple_find_buddy(purple_connection_get_account(gc), bn);
 	if (buddy && (purple_buddy_get_alias_only(buddy)))
-		nombre = g_strdup_printf("%s (%s)", sn, purple_buddy_get_alias_only(buddy));
+		nombre = g_strdup_printf("%s (%s)", bn, purple_buddy_get_alias_only(buddy));
 	else
-		nombre = g_strdup(sn);
+		nombre = g_strdup(bn);
 
 	if (reply) {
 		/* Granted */
@@ -5685,17 +5712,19 @@
 
 static int purple_ssi_gotadded(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	PurpleConnection *gc = od->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
 	va_list ap;
-	char *sn;
+	char *bn;
 	PurpleBuddy *buddy;
 
 	va_start(ap, fr);
-	sn = va_arg(ap, char *);
+	bn = va_arg(ap, char *);
 	va_end(ap);
 
-	buddy = purple_find_buddy(gc->account, sn);
-	purple_debug_info("oscar", "ssi: %s added you to their buddy list\n", sn);
-	purple_account_notify_added(gc->account, sn, NULL, (buddy ? purple_buddy_get_alias_only(buddy) : NULL), NULL);
+	buddy = purple_find_buddy(account, bn);
+	purple_debug_info("oscar", "ssi: %s added you to their buddy list\n", bn);
+	purple_account_notify_added(account, bn, NULL,
+			(buddy ? purple_buddy_get_alias_only(buddy) : NULL), NULL);
 
 	return 1;
 }
@@ -5744,7 +5773,7 @@
 void
 oscar_join_chat(PurpleConnection *gc, GHashTable *data)
 {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	FlapConnection *conn;
 	char *name, *exchange;
 	int exchange_int;
@@ -5779,7 +5808,7 @@
 void
 oscar_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name)
 {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	struct chat_connection *ccon = find_oscar_chat(gc, id);
 
 	if (ccon == NULL)
@@ -5799,14 +5828,16 @@
 
 	g_return_if_fail(conv != NULL);
 
-	purple_debug_info("oscar", "Leaving chat room %s\n", conv->name);
+	purple_debug_info("oscar", "Leaving chat room %s\n",
+			purple_conversation_get_name(conv));
 
 	cc = find_oscar_chat(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)));
 	oscar_chat_kill(gc, cc);
 }
 
-int oscar_send_chat(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags) {
-	OscarData *od = (OscarData *)gc->proto_data;
+int oscar_send_chat(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags)
+{
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	PurpleConversation *conv = NULL;
 	struct chat_connection *c = NULL;
 	char *buf, *buf2, *buf3;
@@ -5873,30 +5904,32 @@
 
 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) || oscar_util_valid_name_sms(name))
 	{
-		if (a == NULL || aim_snvalid_icq(purple_account_get_username(a)))
+		if (a == NULL || oscar_util_valid_name_icq(purple_account_get_username(a)))
 			return "icq";
 		else
 			return "aim";
 	}
 
-	if (aim_snvalid_icq(b->name))
+	if (oscar_util_valid_name_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) || oscar_util_valid_name_sms(name))
 	{
-		if (a != NULL && aim_snvalid_icq(purple_account_get_username(a)))
+		if (a != NULL && oscar_util_valid_name_icq(purple_account_get_username(a)))
 			return "icq";
 		else
 			return "aim";
 	}
 
-	if (aim_snvalid_icq(b->name))
+	if (oscar_util_valid_name_icq(name))
 		return "icq";
 	return "aim";
 }
@@ -5910,14 +5943,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;
+		od = purple_connection_get_protocol_data(gc);
 	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);
@@ -5925,9 +5960,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";
 		}
 	}
@@ -5950,15 +5985,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;
-	od = gc->proto_data;
-	userinfo = aim_locate_finduserinfo(od, b->name);
+	account = purple_buddy_get_account(b);
+	gc = purple_account_get_connection(account);
+	od = purple_connection_get_protocol_data(gc);
+	userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
 
 	oscar_user_info_append_status(gc, user_info, b, userinfo, /* strip_html_tags */ TRUE);
 
@@ -5979,15 +6016,16 @@
 
 	gc = purple_account_get_connection(purple_buddy_get_account(b));
 	account = purple_connection_get_account(gc);
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	presence = purple_buddy_get_presence(b);
 	status = purple_presence_get_active_status(presence);
 	id = purple_status_get_id(status);
 
 	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"));
@@ -6087,7 +6125,7 @@
 
 void oscar_set_permit_deny(PurpleConnection *gc) {
 	PurpleAccount *account = purple_connection_get_account(gc);
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	if (od->ssi.received_data) {
 		switch (account->perm_deny) {
@@ -6114,28 +6152,28 @@
 }
 
 void oscar_add_permit(PurpleConnection *gc, const char *who) {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	purple_debug_info("oscar", "ssi: About to add a permit\n");
 	if (od->ssi.received_data)
 		aim_ssi_addpermit(od, who);
 }
 
 void oscar_add_deny(PurpleConnection *gc, const char *who) {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	purple_debug_info("oscar", "ssi: About to add a deny\n");
 	if (od->ssi.received_data)
 		aim_ssi_adddeny(od, who);
 }
 
 void oscar_rem_permit(PurpleConnection *gc, const char *who) {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	purple_debug_info("oscar", "ssi: About to delete a permit\n");
 	if (od->ssi.received_data)
 		aim_ssi_delpermit(od, who);
 }
 
 void oscar_rem_deny(PurpleConnection *gc, const char *who) {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	purple_debug_info("oscar", "ssi: About to delete a deny\n");
 	if (od->ssi.received_data)
 		aim_ssi_deldeny(od, who);
@@ -6151,7 +6189,7 @@
 	g_return_val_if_fail(account != NULL, NULL);
 
 	/* Used to flag some statuses as "user settable" or not */
-	is_icq = aim_snvalid_icq(purple_account_get_username(account));
+	is_icq = oscar_util_valid_name_icq(purple_account_get_username(account));
 
 	/* Common status types */
 	/* Really the available message should only be settable for AIM accounts */
@@ -6217,24 +6255,33 @@
 }
 
 static void oscar_ssi_editcomment(struct name_data *data, const char *text) {
-	PurpleConnection *gc = data->gc;
-	OscarData *od = gc->proto_data;
+	PurpleConnection *gc;
+	PurpleAccount *account;
+	OscarData *od;
 	PurpleBuddy *b;
 	PurpleGroup *g;
-
-	if (!(b = purple_find_buddy(purple_connection_get_account(data->gc), data->name))) {
+	const char *username;
+
+	gc = data->gc;
+	od = purple_connection_get_protocol_data(gc);
+	account = purple_connection_get_account(gc);
+
+	b = purple_find_buddy(account, data->name);
+	if (b == NULL) {
 		oscar_free_name_data(data);
 		return;
 	}
 
-	if (!(g = purple_buddy_get_group(b))) {
+	g = purple_buddy_get_group(b);
+	if (g == NULL) {
 		oscar_free_name_data(data);
 		return;
 	}
 
-	aim_ssi_editcomment(od, g->name, data->name, text);
-
-	if (!aim_sncmp(data->name, gc->account->username))
+	aim_ssi_editcomment(od, purple_group_get_name(g), data->name, text);
+
+	username = purple_account_get_username(account);
+	if (!oscar_util_name_compare(data->name, username))
 		purple_check_comment(od, text);
 
 	oscar_free_name_data(data);
@@ -6250,23 +6297,27 @@
 	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);
-	od = gc->proto_data;
+	name = purple_buddy_get_name(buddy);
+	account = purple_buddy_get_account(buddy);
+	gc = purple_account_get_connection(account);
+	od = purple_connection_get_protocol_data(gc);
 
 	if (!(g = purple_buddy_get_group(buddy)))
 		return;
 
 	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);
@@ -6274,7 +6325,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);
 
@@ -6306,26 +6357,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->od = gc->proto_data;
+	data->who = g_strdup(purple_buddy_get_name(buddy));
+	data->od = purple_connection_get_protocol_data(gc);
 	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));
@@ -6341,9 +6394,10 @@
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *)node;
-	gc = purple_account_get_connection(buddy->account);
-
-	aim_locate_getinfoshort(gc->proto_data, purple_buddy_get_name(buddy), 0x00000003);
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+
+	aim_locate_getinfoshort(purple_connection_get_protocol_data(gc),
+			purple_buddy_get_name(buddy), 0x00000003);
 }
 
 static GList *
@@ -6354,13 +6408,16 @@
 	GList *menu;
 	PurpleMenuAction *act;
 	aim_userinfo_t *userinfo;
-
-	gc = purple_account_get_connection(buddy->account);
-	od = gc->proto_data;
-	userinfo = aim_locate_finduserinfo(od, buddy->name);
+	PurpleAccount *account;
+	const char *bname = purple_buddy_get_name(buddy);
+
+	account = purple_buddy_get_account(buddy);
+	gc = purple_account_get_connection(account);
+	od = purple_connection_get_protocol_data(gc);
+	userinfo = aim_locate_finduserinfo(od, bname);
 	menu = NULL;
 
-	if (od->icq && aim_snvalid_icq(purple_buddy_get_name(buddy)))
+	if (od->icq && oscar_util_valid_name_icq(bname))
 	{
 		act = purple_menu_action_new(_("Get AIM Info"),
 								   PURPLE_CALLBACK(oscar_get_aim_info_cb),
@@ -6388,7 +6445,7 @@
 #endif
 
 	if (userinfo &&
-		aim_sncmp(purple_account_get_username(buddy->account), buddy->name) &&
+		oscar_util_name_compare(purple_account_get_username(account), bname) &&
 		PURPLE_BUDDY_IS_ONLINE(buddy))
 	{
 		if (userinfo->capabilities & OSCAR_CAPABILITY_DIRECTIM)
@@ -6412,8 +6469,8 @@
 	if (od->ssi.received_data && purple_buddy_get_group(buddy) != NULL)
 	{
 		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),
@@ -6439,7 +6496,7 @@
 static void
 oscar_icq_privacy_opts(PurpleConnection *gc, PurpleRequestFields *fields)
 {
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	PurpleAccount *account = purple_connection_get_account(gc);
 	PurpleRequestField *f;
 	gboolean auth, web_aware;
@@ -6490,13 +6547,13 @@
 						gc);
 }
 
-static void oscar_format_screenname(PurpleConnection *gc, const char *nick) {
-	OscarData *od = gc->proto_data;
-	if (!aim_sncmp(purple_account_get_username(purple_connection_get_account(gc)), nick)) {
+static void oscar_format_username(PurpleConnection *gc, const char *nick) {
+	OscarData *od = purple_connection_get_protocol_data(gc);
+	if (!oscar_util_name_compare(purple_account_get_username(purple_connection_get_account(gc)), nick)) {
 		if (!flap_connection_getbytype(od, SNAC_FAMILY_ADMIN)) {
 			od->setnick = TRUE;
-			g_free(od->newsn);
-			od->newsn = g_strdup(nick);
+			g_free(od->newformatting);
+			od->newformatting = g_strdup(nick);
 			aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
 		} else {
 			aim_admin_setnick(od, flap_connection_getbytype(od, SNAC_FAMILY_ADMIN), nick);
@@ -6514,7 +6571,7 @@
 	FlapConnection *conn;
 
 	gc = (PurpleConnection *)action->context;
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 
 	conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
 	if (conn != NULL) {
@@ -6528,7 +6585,7 @@
 static void oscar_show_email(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *) action->context;
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	FlapConnection *conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
 
 	if (conn) {
@@ -6541,7 +6598,7 @@
 
 static void oscar_change_email(PurpleConnection *gc, const char *email)
 {
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	FlapConnection *conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
 
 	if (conn) {
@@ -6567,29 +6624,40 @@
 static void oscar_show_awaitingauth(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *) action->context;
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	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;
@@ -6615,7 +6683,7 @@
 
 static void search_by_email_cb(PurpleConnection *gc, const char *email)
 {
-	OscarData *od = (OscarData *)gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	aim_search_address(od, email);
 }
@@ -6655,7 +6723,7 @@
 static void oscar_show_chpassurl(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *) action->context;
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	gchar *substituted = purple_strreplace(od->authinfo->chpassurl, "%s", purple_account_get_username(purple_connection_get_account(gc)));
 	purple_notify_uri(gc, substituted);
 	g_free(substituted);
@@ -6669,7 +6737,7 @@
 
 void oscar_set_icon(PurpleConnection *gc, PurpleStoredImage *img)
 {
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	if (img == NULL) {
 		aim_ssi_delicon(od);
@@ -6698,7 +6766,7 @@
 	OscarData *od;
 	PurpleAccount *account;
 
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	account = purple_connection_get_account(gc);
 
 	if (od != NULL)
@@ -6712,7 +6780,7 @@
 		 */
 		if (((userinfo == NULL) ||
 			(userinfo->capabilities & OSCAR_CAPABILITY_SENDFILE)) &&
-			aim_sncmp(who, purple_account_get_username(account)))
+			oscar_util_name_compare(who, purple_account_get_username(account)))
 		{
 			return TRUE;
 		}
@@ -6729,7 +6797,7 @@
 	PurpleAccount *account;
 	PeerConnection *conn;
 
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	account = purple_connection_get_account(gc);
 
 	xfer = purple_xfer_new(account, PURPLE_XFER_SEND, who);
@@ -6773,7 +6841,7 @@
 oscar_actions(PurplePlugin *plugin, gpointer context)
 {
 	PurpleConnection *gc = (PurpleConnection *) context;
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 	GList *menu = NULL;
 	PurplePluginAction *act;
 
@@ -6853,7 +6921,7 @@
 
 void oscar_change_passwd(PurpleConnection *gc, const char *old, const char *new)
 {
-	OscarData *od = gc->proto_data;
+	OscarData *od = purple_connection_get_protocol_data(gc);
 
 	if (od->icq) {
 		aim_icq_changepasswd(od, new);
@@ -6877,7 +6945,7 @@
 	OscarData *od;
 	PeerConnection *conn;
 
-	od = gc->proto_data;
+	od = purple_connection_get_protocol_data(gc);
 	conn = peer_connection_find_by_type(od, who, OSCAR_CAPABILITY_DIRECTIM);
 
 	if (conn != NULL)
@@ -6968,14 +7036,14 @@
 
 	/* aim:GoIM?screenname=SCREENNAME&message=MESSAGE */
 	if (!g_ascii_strcasecmp(cmd, "GoIM")) {
-		char *sname = g_hash_table_lookup(params, "screenname");
-		if (sname) {
+		char *bname = g_hash_table_lookup(params, "screenname");
+		if (bname) {
 			char *message = g_hash_table_lookup(params, "message");
 
 			PurpleConversation *conv = purple_find_conversation_with_account(
-				PURPLE_CONV_TYPE_IM, sname, acct);
+				PURPLE_CONV_TYPE_IM, bname, acct);
 			if (conv == NULL)
-				conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, sname);
+				conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, bname);
 			purple_conversation_present(conv);
 
 			if (message) {
@@ -7008,9 +7076,9 @@
 	}
 	/* aim:AddBuddy?screenname=SCREENNAME&groupname=GROUPNAME*/
 	else if (!g_ascii_strcasecmp(cmd, "AddBuddy")) {
-		char *sname = g_hash_table_lookup(params, "screenname");
+		char *bname = g_hash_table_lookup(params, "screenname");
 		char *gname = g_hash_table_lookup(params, "groupname");
-		purple_blist_request_add_buddy(acct, sname, gname, NULL);
+		purple_blist_request_add_buddy(acct, bname, gname, NULL);
 		return TRUE;
 	}
 
@@ -7040,7 +7108,7 @@
 	option = purple_account_option_bool_new(_("Allow multiple simultaneous logins"), "allow_multiple_logins",
 											OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS);
 	prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
-	
+
 	if (init)
 		return;
 	init = TRUE;
--- a/libpurple/protocols/oscar/oscar.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Wed Jan 28 10:23:37 2009 +0000
@@ -75,7 +75,7 @@
 #define FAIM_SNAC_HASH_SIZE 16
 
 /*
- * Current Maximum Length for Screen Names (not including NULL)
+ * Current Maximum Length for usernames (not including NULL)
  *
  * Currently only names up to 16 characters can be registered
  * however it is apparently legal for them to be larger.
@@ -470,7 +470,7 @@
 	gboolean setemail;
 	char *email;
 	gboolean setnick;
-	char *newsn;
+	char *newformatting;
 	gboolean chpass;
 	char *oldp;
 	char *newp;
@@ -577,7 +577,7 @@
 
 struct aim_authresp_info
 {
-	char *sn;
+	char *bn;
 	guint16 errorcode;
 	char *errorurl;
 	guint16 regstatus;
@@ -606,8 +606,8 @@
 	} chat;
 };
 
-int aim_request_login(OscarData *od, FlapConnection *conn, const char *sn);
-int aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key, gboolean allow_multiple_logins);
+int aim_request_login(OscarData *od, FlapConnection *conn, const char *bn);
+int aim_send_login(OscarData *od, FlapConnection *conn, const char *bn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key, gboolean allow_multiple_logins);
 /* 0x000b */ int aim_auth_securid_send(OscarData *od, const char *securid);
 
 void oscar_data_addhandler(OscarData *od, guint16 family, guint16 subtype, aim_rxcallback_t newhandler, guint16 flags);
@@ -806,7 +806,7 @@
 {
 
 	/* These are _required_ */
-	const char *destsn;
+	const char *destbn;
 	guint32 flags; /* often 0 */
 
 	/* Only required if not using multipart messages */
@@ -835,7 +835,7 @@
  */
 struct aim_sendrtfmsg_args
 {
-	const char *destsn;
+	const char *destbn;
 	guint32 fgcolor;
 	guint32 bgcolor;
 	const char *rtfmsg; /* must be in RTF */
@@ -949,28 +949,28 @@
 /* 0x0002 */ int aim_im_setparams(OscarData *od, struct aim_icbmparameters *params);
 /* 0x0004 */ int aim_im_reqparams(OscarData *od);
 /* 0x0006 */ int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args);
-/* 0x0006 */ int aim_im_sendch1(OscarData *, const char *destsn, guint16 flags, const char *msg);
-/* 0x0006 */ int aim_im_sendch2_chatinvite(OscarData *od, const char *sn, const char *msg, guint16 exchange, const char *roomname, guint16 instance);
-/* 0x0006 */ int aim_im_sendch2_icon(OscarData *od, const char *sn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum);
+/* 0x0006 */ int aim_im_sendch1(OscarData *, const char *destbn, guint16 flags, const char *msg);
+/* 0x0006 */ int aim_im_sendch2_chatinvite(OscarData *od, const char *bn, const char *msg, guint16 exchange, const char *roomname, guint16 instance);
+/* 0x0006 */ int aim_im_sendch2_icon(OscarData *od, const char *bn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum);
 /* 0x0006 */ int aim_im_sendch2_rtfmsg(OscarData *od, struct aim_sendrtfmsg_args *args);
 
 /* 0x0006 */ void aim_im_sendch2_cancel(PeerConnection *peer_conn);
 /* 0x0006 */ void aim_im_sendch2_connected(PeerConnection *peer_conn);
-/* 0x0006 */ void aim_im_sendch2_odc_requestdirect(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 port, guint16 requestnumber);
-/* 0x0006 */ void aim_im_sendch2_odc_requestproxy(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 pin, guint16 requestnumber);
-/* 0x0006 */ void aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles);
-/* 0x0006 */ void aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles);
+/* 0x0006 */ void aim_im_sendch2_odc_requestdirect(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 port, guint16 requestnumber);
+/* 0x0006 */ void aim_im_sendch2_odc_requestproxy(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 pin, guint16 requestnumber);
+/* 0x0006 */ void aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles);
+/* 0x0006 */ void aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles);
 
-/* 0x0006 */ int aim_im_sendch2_geticqaway(OscarData *od, const char *sn, int type);
-/* 0x0006 */ int aim_im_sendch4(OscarData *od, const char *sn, guint16 type, const char *message);
-/* 0x0008 */ int aim_im_warn(OscarData *od, FlapConnection *conn, const char *destsn, guint32 flags);
-/* 0x000b */ int aim_im_denytransfer(OscarData *od, const char *sn, const guchar *cookie, guint16 code);
+/* 0x0006 */ int aim_im_sendch2_geticqaway(OscarData *od, const char *bn, int type);
+/* 0x0006 */ int aim_im_sendch4(OscarData *od, const char *bn, guint16 type, const char *message);
+/* 0x0008 */ int aim_im_warn(OscarData *od, FlapConnection *conn, const char *destbn, guint32 flags);
+/* 0x000b */ int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, guint16 code);
 /* 0x0010 */ int aim_im_reqofflinemsgs(OscarData *od);
-/* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 type1, const char *sn, guint16 type2);
+/* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 type1, const char *bn, guint16 type2);
 void aim_icbm_makecookie(guchar* cookie);
 gchar *oscar_encoding_extract(const char *encoding);
 gchar *oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen);
-gchar *purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcesn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen);
+gchar *purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcebn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen);
 
 
 /* 0x0002 - family_locate.c */
@@ -1005,13 +1005,13 @@
 
 struct userinfo_node
 {
-	char *sn;
+	char *bn;
 	struct userinfo_node *next;
 };
 
 typedef struct aim_userinfo_s
 {
-	char *sn;
+	char *bn;
 	guint16 warnlevel; /* evil percent * 10 (999 = 99.9%) */
 	guint16 idletime; /* in seconds */
 	guint16 flags;
@@ -1057,7 +1057,7 @@
 
 struct aim_invite_priv
 {
-	char *sn;
+	char *bn;
 	char *roomname;
 	guint16 exchange;
 	guint16 instance;
@@ -1080,7 +1080,7 @@
 #define AIM_COOKIETYPE_OFTIMAGE 0x14
 #define AIM_COOKIETYPE_OFTICON  0x15
 
-aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *sn);
+aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *bn);
 void aim_locate_dorequest(OscarData *od);
 
 /* 0x0002 */ int aim_locate_reqrights(OscarData *od);
@@ -1088,11 +1088,11 @@
 /* 0x0004 */ int aim_locate_setprofile(OscarData *od, const char *profile_encoding, const gchar *profile, const int profile_len, const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len);
 /* 0x0005 */ int aim_locate_getinfo(OscarData *od, const char *, guint16);
 /* 0x0009 */ int aim_locate_setdirinfo(OscarData *od, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, guint16 privacy);
-/* 0x000b */ int aim_locate_000b(OscarData *od, const char *sn);
+/* 0x000b */ int aim_locate_000b(OscarData *od, const char *bn);
 /* 0x000f */ int aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy);
-/* 0x0015 */ int aim_locate_getinfoshort(OscarData *od, const char *sn, guint32 flags);
+/* 0x0015 */ int aim_locate_getinfoshort(OscarData *od, const char *bn, guint32 flags);
 
-void aim_locate_autofetch_away_message(OscarData *od, const char *sn);
+void aim_locate_autofetch_away_message(OscarData *od, const char *bn);
 guint32 aim_locate_getcaps(OscarData *od, ByteStream *bs, int len);
 guint32 aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len);
 void aim_info_free(aim_userinfo_t *);
@@ -1159,7 +1159,7 @@
 	char *country;
 	char *state;
 	char *city;
-	char *sn;
+	char *bn;
 	char *interest;
 	char *nick;
 	char *zip;
@@ -1176,7 +1176,7 @@
 
 /* 0x0010 - family_bart.c */
 int aim_bart_upload(OscarData *od, const guint8 *icon, guint16 iconlen);
-int aim_bart_request(OscarData *od, const char *sn, guint8 iconcsumtype, const guint8 *iconstr, guint16 iconstrlen);
+int aim_bart_request(OscarData *od, const char *bn, guint8 iconcsumtype, const guint8 *iconstr, guint16 iconstrlen);
 
 
 
@@ -1226,20 +1226,20 @@
 /* 0x0007 */ int aim_ssi_enable(OscarData *od);
 /* 0x0011 */ int aim_ssi_modbegin(OscarData *od);
 /* 0x0012 */ int aim_ssi_modend(OscarData *od);
-/* 0x0014 */ int aim_ssi_sendauth(OscarData *od, char *sn, char *msg);
-/* 0x0018 */ int aim_ssi_sendauthrequest(OscarData *od, char *sn, const char *msg);
-/* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, char *sn, guint8 reply, const char *msg);
+/* 0x0014 */ int aim_ssi_sendauth(OscarData *od, char *bn, char *msg);
+/* 0x0018 */ int aim_ssi_sendauthrequest(OscarData *od, char *bn, const char *msg);
+/* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, char *bn, guint8 reply, const char *msg);
 
 /* Client functions for retrieving SSI data */
 struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid);
-struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, guint16 type);
-struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn);
-char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn);
+struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *bn, guint16 type);
+struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *bn);
+char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *bn);
 int aim_ssi_getpermdeny(struct aim_ssi_item *list);
 guint32 aim_ssi_getpresence(struct aim_ssi_item *list);
-char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn);
-char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *sn);
-gboolean aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn);
+char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *bn);
+char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *bn);
+gboolean aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *bn);
 
 /* Client functions for changing SSI data */
 int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, GSList *tlvlist, const char *alias, const char *comment, const char *smsnum, gboolean needauth);
@@ -1249,9 +1249,9 @@
 int aim_ssi_delgroup(OscarData *od, const char *group);
 int aim_ssi_delpermit(OscarData *od, const char *name);
 int aim_ssi_deldeny(OscarData *od, const char *name);
-int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *sn);
-int aim_ssi_aliasbuddy(OscarData *od, const char *gn, const char *sn, const char *alias);
-int aim_ssi_editcomment(OscarData *od, const char *gn, const char *sn, const char *alias);
+int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *bn);
+int aim_ssi_aliasbuddy(OscarData *od, const char *gn, const char *bn, const char *alias);
+int aim_ssi_editcomment(OscarData *od, const char *gn, const char *bn, const char *alias);
 int aim_ssi_rename_group(OscarData *od, const char *oldgn, const char *newgn);
 int aim_ssi_cleanlist(OscarData *od);
 int aim_ssi_deletelist(OscarData *od);
@@ -1497,11 +1497,10 @@
 int aimutil_itemcnt(char *toSearch, char dl);
 char *aimutil_itemindex(char *toSearch, int theindex, char dl);
 
-gboolean aim_snvalid(const char *sn);
-gboolean aim_snvalid_icq(const char *sn);
-gboolean aim_snvalid_sms(const char *sn);
-int aim_snlen(const char *sn);
-int aim_sncmp(const char *sn1, const char *sn2);
+gboolean oscar_util_valid_name(const char *bn);
+gboolean oscar_util_valid_name_icq(const char *bn);
+gboolean oscar_util_valid_name_sms(const char *bn);
+int oscar_util_name_compare(const char *bn1, const char *bn2);
 
 
 
--- a/libpurple/protocols/oscar/peer.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/peer.c	Wed Jan 28 10:23:37 2009 +0000
@@ -69,7 +69,7 @@
 #endif
 
 PeerConnection *
-peer_connection_find_by_type(OscarData *od, const char *sn, OscarCapability type)
+peer_connection_find_by_type(OscarData *od, const char *bn, OscarCapability type)
 {
 	GSList *cur;
 	PeerConnection *conn;
@@ -77,7 +77,7 @@
 	for (cur = od->peer_connections; cur != NULL; cur = cur->next)
 	{
 		conn = cur->data;
-		if ((conn->type == type) && !aim_sncmp(conn->sn, sn))
+		if ((conn->type == type) && !oscar_util_name_compare(conn->bn, bn))
 			return conn;
 	}
 
@@ -88,7 +88,7 @@
  * @param cookie This must be exactly 8 characters.
  */
 PeerConnection *
-peer_connection_find_by_cookie(OscarData *od, const char *sn, const guchar *cookie)
+peer_connection_find_by_cookie(OscarData *od, const char *bn, const guchar *cookie)
 {
 	GSList *cur;
 	PeerConnection *conn;
@@ -96,7 +96,7 @@
 	for (cur = od->peer_connections; cur != NULL; cur = cur->next)
 	{
 		conn = cur->data;
-		if (!memcmp(conn->cookie, cookie, 8) && !aim_sncmp(conn->sn, sn))
+		if (!memcmp(conn->cookie, cookie, 8) && !oscar_util_name_compare(conn->bn, bn))
 			return conn;
 	}
 
@@ -104,7 +104,7 @@
 }
 
 PeerConnection *
-peer_connection_new(OscarData *od, OscarCapability type, const char *sn)
+peer_connection_new(OscarData *od, OscarCapability type, const char *bn)
 {
 	PeerConnection *conn;
 	PurpleAccount *account;
@@ -114,7 +114,7 @@
 	conn = g_new0(PeerConnection, 1);
 	conn->od = od;
 	conn->type = type;
-	conn->sn = g_strdup(sn);
+	conn->bn = g_strdup(bn);
 	conn->buffer_outgoing = purple_circ_buffer_new(0);
 	conn->listenerfd = -1;
 	conn->fd = -1;
@@ -228,7 +228,7 @@
 		conn->xfer = NULL;
 	}
 
-	g_free(conn->sn);
+	g_free(conn->bn);
 	g_free(conn->error_message);
 	g_free(conn->proxyip);
 	g_free(conn->clientip);
@@ -698,20 +698,20 @@
 	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
 	{
 		aim_im_sendch2_odc_requestdirect(od,
-				conn->cookie, conn->sn, purple_network_ip_atoi(listener_ip),
+				conn->cookie, conn->bn, purple_network_ip_atoi(listener_ip),
 				listener_port, ++conn->lastrequestnumber);
 
 		/* Print a message to a local conversation window */
-		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn);
+		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->bn);
 		tmp = g_strdup_printf(_("Asking %s to connect to us at %s:%hu for "
-				"Direct IM."), conn->sn, listener_ip, listener_port);
+				"Direct IM."), conn->bn, listener_ip, listener_port);
 		purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
 		g_free(tmp);
 	}
 	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
 	{
 		aim_im_sendch2_sendfile_requestdirect(od,
-				conn->cookie, conn->sn,
+				conn->cookie, conn->bn,
 				purple_network_ip_atoi(listener_ip),
 				listener_port, ++conn->lastrequestnumber,
 				(const gchar *)conn->xferdata.name,
@@ -790,7 +790,7 @@
 			PurpleConversation *conv;
 			tmp = g_strdup_printf(_("Attempting to connect to %s:%hu."),
 					conn->verifiedip, conn->port);
-			conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn);
+			conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->bn);
 			purple_conversation_write(conv, NULL, tmp,
 					PURPLE_MESSAGE_SYSTEM, time(NULL));
 			g_free(tmp);
@@ -863,7 +863,7 @@
 			gchar *tmp;
 			PurpleConversation *conv;
 			tmp = g_strdup(_("Attempting to connect via proxy server."));
-			conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn);
+			conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->bn);
 			purple_conversation_write(conv, NULL, tmp,
 					PURPLE_MESSAGE_SYSTEM, time(NULL));
 			g_free(tmp);
@@ -888,13 +888,13 @@
  * Initiate a peer connection with someone.
  */
 void
-peer_connection_propose(OscarData *od, OscarCapability type, const char *sn)
+peer_connection_propose(OscarData *od, OscarCapability type, const char *bn)
 {
 	PeerConnection *conn;
 
 	if (type == OSCAR_CAPABILITY_DIRECTIM)
 	{
-		conn = peer_connection_find_by_type(od, sn, type);
+		conn = peer_connection_find_by_type(od, bn, type);
 		if (conn != NULL)
 		{
 			if (conn->ready)
@@ -903,10 +903,10 @@
 				PurpleConversation *conv;
 
 				purple_debug_info("oscar", "Already have a direct IM "
-						"session with %s.\n", sn);
+						"session with %s.\n", bn);
 				account = purple_connection_get_account(od->gc);
 				conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
-						sn, account);
+						bn, account);
 				if (conv != NULL)
 					purple_conversation_present(conv);
 				return;
@@ -917,7 +917,7 @@
 		}
 	}
 
-	conn = peer_connection_new(od, type, sn);
+	conn = peer_connection_new(od, type, bn);
 	conn->flags |= PEER_CONNECTION_FLAG_INITIATED_BY_ME;
 	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
 	aim_icbm_makecookie(conn->cookie);
@@ -954,7 +954,7 @@
 
 	conn = data;
 
-	aim_im_denytransfer(conn->od, conn->sn, conn->cookie,
+	aim_im_denytransfer(conn->od, conn->bn, conn->cookie,
 			AIM_TRANSFER_DENY_DECLINE);
 	peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
 }
@@ -963,7 +963,7 @@
  * Someone else wants to establish a peer connection with us.
  */
 void
-peer_connection_got_proposition(OscarData *od, const gchar *sn, const gchar *message, IcbmArgsCh2 *args)
+peer_connection_got_proposition(OscarData *od, const gchar *bn, const gchar *message, IcbmArgsCh2 *args)
 {
 	PurpleConnection *gc;
 	PurpleAccount *account;
@@ -979,7 +979,7 @@
 	 * and we should try connecting to them, instead.  Or they want
 	 * to go through a proxy.
 	 */
-	conn = peer_connection_find_by_cookie(od, sn, args->cookie);
+	conn = peer_connection_find_by_cookie(od, bn, args->cookie);
 	if ((conn != NULL) && (conn->type == args->type))
 	{
 		purple_debug_info("oscar", "Remote user wants to try a "
@@ -1003,12 +1003,12 @@
 	/* If this is a direct IM, then close any existing session */
 	if (args->type == OSCAR_CAPABILITY_DIRECTIM)
 	{
-		conn = peer_connection_find_by_type(od, sn, args->type);
+		conn = peer_connection_find_by_type(od, bn, args->type);
 		if (conn != NULL)
 		{
 			/* Close the old direct IM and start a new one */
 			purple_debug_info("oscar", "Received new direct IM request "
-				"from %s.  Destroying old connection.\n", sn);
+				"from %s.  Destroying old connection.\n", bn);
 			peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
 		}
 	}
@@ -1022,12 +1022,12 @@
 		{
 			purple_debug_warning("oscar",
 					"%s tried to send you a file with incomplete "
-					"information.\n", sn);
+					"information.\n", bn);
 			return;
 		}
 	}
 
-	conn = peer_connection_new(od, args->type, sn);
+	conn = peer_connection_new(od, args->type, bn);
 	memcpy(conn->cookie, args->cookie, 8);
 	if (args->use_proxy)
 		conn->proxyip = g_strdup(args->proxyip);
@@ -1040,7 +1040,7 @@
 	if (args->type == OSCAR_CAPABILITY_DIRECTIM)
 	{
 		buf = g_strdup_printf(_("%s has just asked to directly connect to %s"),
-				sn, purple_account_get_username(account));
+				bn, purple_account_get_username(account));
 
 		purple_request_action(conn, NULL, buf,
 						_("This requires a direct connection between "
@@ -1049,7 +1049,7 @@
 						  "revealed, this may be considered a privacy "
 						  "risk."),
 						PURPLE_DEFAULT_ACTION_NONE,
-						account, sn, NULL,
+						account, bn, NULL,
 						conn, 2,
 						_("C_onnect"), G_CALLBACK(peer_connection_got_proposition_yes_cb),
 						_("Cancel"), G_CALLBACK(peer_connection_got_proposition_no_cb));
@@ -1058,7 +1058,7 @@
 	{
 		gchar *filename;
 
-		conn->xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE, sn);
+		conn->xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE, bn);
 		if (conn->xfer)
 		{
 			conn->xfer->data = conn;
--- a/libpurple/protocols/oscar/peer.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/peer.h	Wed Jan 28 10:23:37 2009 +0000
@@ -83,7 +83,7 @@
 	/* Unknown */
 	guint16 flags;                /* 38 */
 	/* Unknown */
-	guchar sn[32];                /* 44 */
+	guchar bn[32];                /* 44 */
 	/* Unknown */
 	ByteStream payload;           /* 76 */
 };
@@ -137,7 +137,7 @@
 {
 	OscarData *od;
 	OscarCapability type;
-	char *sn;
+	char *bn;
 	guchar magic[4];
 	guchar cookie[8];
 	guint16 lastrequestnumber;
@@ -228,12 +228,12 @@
  * @param type The type of the peer connection.  One of
  *        OSCAR_CAPABILITY_DIRECTIM or OSCAR_CAPABILITY_SENDFILE.
  */
-PeerConnection *peer_connection_new(OscarData *od, OscarCapability type, const char *sn);
+PeerConnection *peer_connection_new(OscarData *od, OscarCapability type, const char *bn);
 
 void peer_connection_destroy(PeerConnection *conn, OscarDisconnectReason reason, const gchar *error_message);
 void peer_connection_schedule_destroy(PeerConnection *conn, OscarDisconnectReason reason, const gchar *error_message);
-PeerConnection *peer_connection_find_by_type(OscarData *od, const char *sn, OscarCapability type);
-PeerConnection *peer_connection_find_by_cookie(OscarData *od, const char *sn, const guchar *cookie);
+PeerConnection *peer_connection_find_by_type(OscarData *od, const char *bn, OscarCapability type);
+PeerConnection *peer_connection_find_by_cookie(OscarData *od, const char *bn, const guchar *cookie);
 
 void peer_connection_listen_cb(gpointer data, gint source, PurpleInputCondition cond);
 void peer_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond);
@@ -241,8 +241,8 @@
 
 void peer_connection_trynext(PeerConnection *conn);
 void peer_connection_finalize_connection(PeerConnection *conn);
-void peer_connection_propose(OscarData *od, OscarCapability type, const char *sn);
-void peer_connection_got_proposition(OscarData *od, const gchar *sn, const gchar *message, IcbmArgsCh2 *args);
+void peer_connection_propose(OscarData *od, OscarCapability type, const char *bn);
+void peer_connection_got_proposition(OscarData *od, const gchar *bn, const gchar *message, IcbmArgsCh2 *args);
 
 /*
  * For ODC
--- a/libpurple/protocols/oscar/peer_proxy.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/peer_proxy.c	Wed Jan 28 10:23:37 2009 +0000
@@ -63,19 +63,19 @@
 {
 	ProxyFrame frame;
 	PurpleAccount *account;
-	const gchar *sn;
-	guint8 sn_length;
+	const gchar *bn;
+	guint8 bn_length;
 
 	memset(&frame, 0, sizeof(ProxyFrame));
 	frame.type = PEER_PROXY_TYPE_CREATE;
 	frame.flags = 0x0000;
 
 	account = purple_connection_get_account(conn->od->gc);
-	sn = purple_account_get_username(account);
-	sn_length = strlen(sn);
-	byte_stream_new(&frame.payload, 1 + sn_length + 8 + 20);
-	byte_stream_put8(&frame.payload, sn_length);
-	byte_stream_putraw(&frame.payload, (const guint8 *)sn, sn_length);
+	bn = purple_account_get_username(account);
+	bn_length = strlen(bn);
+	byte_stream_new(&frame.payload, 1 + bn_length + 8 + 20);
+	byte_stream_put8(&frame.payload, bn_length);
+	byte_stream_putraw(&frame.payload, (const guint8 *)bn, bn_length);
 	byte_stream_putraw(&frame.payload, conn->cookie, 8);
 
 	byte_stream_put16(&frame.payload, 0x0001); /* Type */
@@ -99,19 +99,19 @@
 {
 	ProxyFrame frame;
 	PurpleAccount *account;
-	const gchar *sn;
-	guint8 sn_length;
+	const gchar *bn;
+	guint8 bn_length;
 
 	memset(&frame, 0, sizeof(ProxyFrame));
 	frame.type = PEER_PROXY_TYPE_JOIN;
 	frame.flags = 0x0000;
 
 	account = purple_connection_get_account(conn->od->gc);
-	sn = purple_account_get_username(account);
-	sn_length = strlen(sn);
-	byte_stream_new(&frame.payload, 1 + sn_length + 2 + 8 + 20);
-	byte_stream_put8(&frame.payload, sn_length);
-	byte_stream_putraw(&frame.payload, (const guint8 *)sn, sn_length);
+	bn = purple_account_get_username(account);
+	bn_length = strlen(bn);
+	byte_stream_new(&frame.payload, 1 + bn_length + 2 + 8 + 20);
+	byte_stream_put8(&frame.payload, bn_length);
+	byte_stream_putraw(&frame.payload, (const guint8 *)bn, bn_length);
 	byte_stream_put16(&frame.payload, pin);
 	byte_stream_putraw(&frame.payload, conn->cookie, 8);
 
@@ -149,11 +149,11 @@
 		if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
 			aim_im_sendch2_odc_requestproxy(conn->od,
 					conn->cookie,
-					conn->sn, ip, pin, ++conn->lastrequestnumber);
+					conn->bn, ip, pin, ++conn->lastrequestnumber);
 		else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
 		{
 			aim_im_sendch2_sendfile_requestproxy(conn->od,
-					conn->cookie, conn->sn,
+					conn->cookie, conn->bn,
 					ip, pin, ++conn->lastrequestnumber,
 					(const gchar *)conn->xferdata.name,
 					conn->xferdata.size, conn->xferdata.totfiles);
--- a/libpurple/protocols/oscar/snactypes.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/snactypes.h	Wed Jan 28 10:23:37 2009 +0000
@@ -252,7 +252,6 @@
  * SNAC Family: Authorizer
  *
  * Used only in protocol versions three and above.
- *
  */
 #define SNAC_SUBTYPE_AUTH_ERROR 0x0001
 #define SNAC_SUBTYPE_AUTH_LOGINREQEST 0x0002
@@ -266,8 +265,7 @@
  * SNAC Family: Email
  *
  * Used for getting information on the email address
- * associated with your screen name.
- *
+ * associated with your username.
  */
 #define SNAC_SUBTYPE_ALERT_ERROR 0x0001
 #define SNAC_SUBTYPE_ALERT_SENDCOOKIES 0x0006
@@ -280,7 +278,6 @@
  * This isn't truly a SNAC family either, but using
  * these, we can integrated non-SNAC services into
  * the SNAC-centered libfaim callback structure.
- *
  */
 #define AIM_CB_SPECIAL_CONNERR 0x0003
 #define AIM_CB_SPECIAL_CONNINITDONE 0x0006
--- a/libpurple/protocols/oscar/util.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/oscar/util.c	Wed Jan 28 10:23:37 2009 +0000
@@ -136,27 +136,27 @@
 }
 
 /**
- * Check if the given screen name is a valid AIM screen name.
+ * Check if the given name is a valid AIM username.
  * Example: BobDole
  * Example: Henry_Ford@mac.com
  * Example: 1KrazyKat@example.com
  *
- * @return TRUE if the screen name is valid, FALSE if not.
+ * @return TRUE if the name is valid, FALSE if not.
  */
 static gboolean
-aim_snvalid_aim(const char *sn)
+oscar_util_valid_name_aim(const char *name)
 {
 	int i;
 
-	if (purple_email_is_valid(sn))
+	if (purple_email_is_valid(name))
 		return TRUE;
 
-	/* Normal AIM screen names can't start with a number */
-	if (isdigit(sn[0]))
+	/* Normal AIM usernames can't start with a number */
+	if (isdigit(name[0]))
 		return FALSE;
 
-	for (i = 0; sn[i] != '\0'; i++) {
-		if (!isalnum(sn[i]) && (sn[i] != ' '))
+	for (i = 0; name[i] != '\0'; i++) {
+		if (!isalnum(name[i]) && (name[i] != ' '))
 			return FALSE;
 	}
 
@@ -164,18 +164,18 @@
 }
 
 /**
- * Check if the given screen name is a valid ICQ screen name.
+ * Check if the given name is a valid ICQ username.
  * Example: 1234567
  *
- * @return TRUE if the screen name is valid, FALSE if not.
+ * @return TRUE if the name is valid, FALSE if not.
  */
 gboolean
-aim_snvalid_icq(const char *sn)
+oscar_util_valid_name_icq(const char *name)
 {
 	int i;
 
-	for (i = 0; sn[i] != '\0'; i++) {
-		if (!isdigit(sn[i]))
+	for (i = 0; name[i] != '\0'; i++) {
+		if (!isdigit(name[i]))
 			return FALSE;
 	}
 
@@ -183,21 +183,21 @@
 }
 
 /**
- * Check if the given screen name is a valid SMS screen name.
+ * Check if the given name is a valid SMS username.
  * Example: +19195551234
  *
- * @return TRUE if the screen name is valid, FALSE if not.
+ * @return TRUE if the name is valid, FALSE if not.
  */
 gboolean
-aim_snvalid_sms(const char *sn)
+oscar_util_valid_name_sms(const char *name)
 {
 	int i;
 
-	if (sn[0] != '+')
+	if (name[0] != '+')
 		return FALSE;
 
-	for (i = 1; sn[i] != '\0'; i++) {
-		if (!isdigit(sn[i]))
+	for (i = 1; name[i] != '\0'; i++) {
+		if (!isdigit(name[i]))
 			return FALSE;
 	}
 
@@ -205,44 +205,46 @@
 }
 
 /**
- * Check if the given screen name is a valid oscar screen name.
+ * Check if the given name is a valid oscar username.
  *
- * @return TRUE if the screen name is valid, FALSE if not.
+ * @return TRUE if the name is valid, FALSE if not.
  */
 gboolean
-aim_snvalid(const char *sn)
+oscar_util_valid_name(const char *name)
 {
-	if ((sn == NULL) || (*sn == '\0'))
+	if ((name == NULL) || (*name == '\0'))
 		return FALSE;
 
-	return aim_snvalid_icq(sn) || aim_snvalid_sms(sn) || aim_snvalid_aim(sn);
+	return oscar_util_valid_name_icq(name)
+			|| oscar_util_valid_name_sms(name)
+			|| oscar_util_valid_name_aim(name);
 }
 
 /**
- * This takes two screen names and compares them using the rules
- * on screen names for AIM/AOL.  Mainly, this means case and space
+ * This takes two names and compares them using the rules
+ * on usernames for AIM/AOL.  Mainly, this means case and space
  * insensitivity (all case differences and spacing differences are
- * ignored, with the exception that screen names can not start with
+ * ignored, with the exception that usernames can not start with
  * a space).
  *
  * @return 0 if equal, non-0 if different
  */
 /* TODO: Do something different for email addresses. */
 int
-aim_sncmp(const char *sn1, const char *sn2)
+oscar_util_name_compare(const char *name1, const char *name2)
 {
 
-	if ((sn1 == NULL) || (sn2 == NULL))
+	if ((name1 == NULL) || (name2 == NULL))
 		return -1;
 
 	do {
-		while (*sn2 == ' ')
-			sn2++;
-		while (*sn1 == ' ')
-			sn1++;
-		if (toupper(*sn1) != toupper(*sn2))
+		while (*name2 == ' ')
+			name2++;
+		while (*name1 == ' ')
+			name1++;
+		if (toupper(*name1) != toupper(*name2))
 			return 1;
-	} while ((*sn1 != '\0') && sn1++ && sn2++);
+	} while ((*name1 != '\0') && name1++ && name2++);
 
 	return 0;
 }
--- a/libpurple/protocols/qq/buddy_info.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/qq/buddy_info.c	Wed Jan 28 10:23:37 2009 +0000
@@ -612,7 +612,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 = strtoul(segments[QQ_INFO_UID], NULL, 10);
 	who = uid_to_purple_name(uid);
@@ -631,15 +631,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);
@@ -768,8 +769,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/qq/buddy_list.c	Wed Jan 28 10:23:37 2009 +0000
@@ -232,7 +232,7 @@
 			/* create no-auth buddy */
 			buddy = qq_buddy_new(gc, bs.uid);
 		}
-		bd = (buddy == NULL) ? NULL : (qq_buddy_data *)buddy->proto_data;
+		bd = (buddy == NULL) ? NULL : (qq_buddy_data *)purple_buddy_get_protocol_data(buddy);
 		if (bd == NULL) {
 			purple_debug_error("QQ",
 					"Got an online buddy %u, but not in my buddy list\n", bs.uid);
@@ -334,7 +334,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;
 		}
@@ -342,7 +342,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);
 		*/
@@ -567,7 +567,7 @@
 		/* create no-auth buddy */
 		buddy = qq_buddy_new(gc, bs.uid);
 	}
-	bd = (buddy == NULL) ? NULL : (qq_buddy_data *) buddy->proto_data;
+	bd = (buddy == NULL) ? NULL : (qq_buddy_data *)purple_buddy_get_protocol_data(buddy);
 	if (bd == NULL) {
 		purple_debug_warning("QQ", "Got status of no-auth buddy %u\n", bs.uid);
 		return;
@@ -659,9 +659,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;
@@ -681,16 +682,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/qq/buddy_opt.c	Wed Jan 28 10:23:37 2009 +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 %u\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 %u\n", uid);
 		return NULL;
 	}
-	return (qq_buddy_data *)buddy->proto_data;
+	return bd;
 }
 
 void qq_buddy_data_free(qq_buddy_data *bd)
@@ -149,7 +151,7 @@
 	purple_debug_info("QQ", "Add new purple buddy: [%u]\n", uid);
 	who = uid_to_purple_name(uid);
 	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);
 
@@ -162,11 +164,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);
 }
 
@@ -186,6 +191,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);
 
@@ -197,11 +203,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/qq/group_internal.c	Wed Jan 28 10:23:37 2009 +0000
@@ -103,16 +103,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("%u", rmd->id));
-	g_hash_table_replace(chat->components,
+	g_hash_table_replace(components,
 		     g_strdup(QQ_ROOM_KEY_EXTERNAL_ID),
 		     g_strdup_printf("%u", 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));
 }
 
@@ -251,11 +256,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);
 	}
@@ -384,16 +391,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/qq/im.c	Wed Jan 28 10:23:37 2009 +0000
@@ -788,7 +788,7 @@
 		/* create no-auth buddy */
 		buddy = qq_buddy_new(gc, im_header->uid_from);
 	}
-	bd = (buddy == NULL) ? NULL : (qq_buddy_data *) buddy->proto_data;
+	bd = (buddy == NULL) ? NULL : purple_buddy_get_protocol_data(buddy);
 	if (bd != NULL) {
 		bd->client_tag = im_header->version_from;
 		bd->face = im_text.sender_icon;
@@ -889,7 +889,7 @@
 		/* create no-auth buddy */
 		buddy = qq_buddy_new(gc, im_header->uid_from);
 	}
-	bd = (buddy == NULL) ? NULL : (qq_buddy_data *) buddy->proto_data;
+	bd = (buddy == NULL) ? NULL : purple_buddy_get_protocol_data(buddy);
 	if (bd != NULL) {
 		bd->client_tag = im_header->version_from;
 		bd->face = im_text.sender_icon;
--- a/libpurple/protocols/qq/qq.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/qq/qq.c	Wed Jan 28 10:23:37 2009 +0000
@@ -246,7 +246,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;
 
@@ -289,7 +289,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;
 
@@ -380,11 +380,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";
 	}
@@ -693,8 +694,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;
 
@@ -712,8 +714,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;
 
@@ -800,7 +803,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);
 }
@@ -813,7 +816,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/send_file.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/qq/send_file.c	Wed Jan 28 10:23:37 2009 +0000
@@ -808,7 +808,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/sametime/sametime.c	Wed Jan 28 10:23:37 2009 +0000
@@ -663,7 +663,6 @@
   */
 
   PurpleAccount *acct;
-  PurpleBuddyList *blist;
   PurpleBlistNode *gn, *cn, *bn;
   PurpleGroup *grp;
   PurpleBuddy *bdy;
@@ -674,10 +673,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;
@@ -702,13 +699,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
@@ -716,27 +713,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));
 	}
       }
     }
@@ -816,7 +817,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 ");
 }
 
 
@@ -825,7 +826,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;
@@ -890,7 +891,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);
@@ -926,7 +927,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);
@@ -1006,23 +1008,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);
       }
     }
@@ -1059,7 +1065,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);
@@ -1078,18 +1084,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);
       }
     }
@@ -1145,7 +1155,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;
@@ -1164,12 +1175,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 {
@@ -1284,6 +1295,7 @@
 
   GString *str;
   char *tmp;
+  const char *gname;
 
   g_return_if_fail(pd != NULL);
 
@@ -1295,11 +1307,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);
@@ -1356,19 +1369,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);
 	}
       }
@@ -1388,7 +1406,6 @@
   PurpleConnection *gc;
   PurpleAccount *acct;
   struct mwStorageUnit *unit;
-  PurpleBuddyList *blist;
   PurpleBlistNode *l;
 
   gc = pd->gc;
@@ -1399,8 +1416,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;
@@ -3239,10 +3256,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);
 
@@ -3299,13 +3316,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);
 
@@ -3321,7 +3338,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);
@@ -3333,34 +3350,34 @@
   }
 }
 
-
-static GList *mw_prpl_status_types(PurpleAccount *acct) {
-  GList *types = NULL;
-  PurpleStatusType *type;
-
-  type = purple_status_type_new(PURPLE_STATUS_AVAILABLE, MW_STATE_ACTIVE,
-			      NULL, TRUE);
-  purple_status_type_add_attr(type, MW_STATE_MESSAGE, _("Message"),
-			    purple_value_new(PURPLE_TYPE_STRING));
-  types = g_list_append(types, type);
-
-  type = purple_status_type_new(PURPLE_STATUS_AWAY, MW_STATE_AWAY,
-			      NULL, TRUE);
-  purple_status_type_add_attr(type, MW_STATE_MESSAGE, _("Message"),
-			    purple_value_new(PURPLE_TYPE_STRING));
-  types = g_list_append(types, type);
-  
-  type = purple_status_type_new(PURPLE_STATUS_UNAVAILABLE, MW_STATE_BUSY,
-			      _("Do Not Disturb"), TRUE);
-  purple_status_type_add_attr(type, MW_STATE_MESSAGE, _("Message"),
-			    purple_value_new(PURPLE_TYPE_STRING));
-  types = g_list_append(types, type);
-  
-  type = purple_status_type_new(PURPLE_STATUS_OFFLINE, MW_STATE_OFFLINE,
-			      NULL, TRUE);
-  types = g_list_append(types, type);
-
-  return types;
+static GList *mw_prpl_status_types(PurpleAccount *acct)
+{
+	GList *types = NULL;
+	PurpleStatusType *type;
+
+	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
+			MW_STATE_ACTIVE, NULL, TRUE, TRUE, FALSE,
+			MW_STATE_MESSAGE, _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
+	types = g_list_append(types, type);
+
+	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY,
+			MW_STATE_AWAY, NULL, TRUE, TRUE, FALSE,
+			MW_STATE_MESSAGE, _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
+	types = g_list_append(types, type);
+
+	type = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE,
+			MW_STATE_BUSY, _("Do Not Disturb"), TRUE, TRUE, FALSE,
+			MW_STATE_MESSAGE, _("Message"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
+	types = g_list_append(types, type);
+
+	type = purple_status_type_new_full(PURPLE_STATUS_OFFLINE,
+			MW_STATE_OFFLINE, NULL, TRUE, TRUE, FALSE);
+	types = g_list_append(types, type);
+
+	return types;
 }
 
 
@@ -3383,7 +3400,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;
@@ -3397,7 +3414,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);
 }
 
@@ -3417,7 +3434,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);
@@ -3437,7 +3454,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,
@@ -3474,7 +3491,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);
     }
   }
@@ -3495,7 +3512,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);
@@ -3523,7 +3540,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,
@@ -3545,7 +3562,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);
@@ -4186,8 +4203,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);
@@ -4329,10 +4346,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),
@@ -4414,7 +4431,7 @@
 
   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)
@@ -4515,7 +4532,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,
@@ -4568,7 +4585,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 */
@@ -4593,7 +4610,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/silc/buddy.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/silc/chat.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/silc/ops.c	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/simple/simple.c	Wed Jan 28 10:23:37 2009 +0000
@@ -196,33 +196,41 @@
 {
 	struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data;
 	struct simple_buddy *b;
-	if(strcmp("sip:", buddy->name)) {
-		gchar *buf = g_strdup_printf("sip:%s", buddy->name);
+	const char *name = purple_buddy_get_name(buddy);
+	if(strcmp("sip:", name)) {
+		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);
--- a/libpurple/protocols/yahoo/yahoo.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Wed Jan 28 10:23:37 2009 +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) {
@@ -3128,11 +3131,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";
 	}
@@ -3192,7 +3196,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;
 
@@ -3204,7 +3208,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) {
@@ -3213,9 +3217,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) {
@@ -3233,10 +3237,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;
 
@@ -3258,8 +3262,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"));
 
@@ -3288,8 +3294,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 {
@@ -3340,7 +3348,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);
 }
@@ -3354,9 +3362,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) {
@@ -3400,9 +3408,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)
@@ -3410,12 +3419,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"),
@@ -3942,19 +3951,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";
 
@@ -3967,7 +3977,7 @@
 	                  1, purple_connection_get_display_name(gc),
 	                  302, "319",
 	                  300, "319",
-	                  7, buddy->name,
+	                  7, bname,
 	                  334, "0",
 	                  301, "319",
 	                  303, "319"
@@ -3981,19 +3991,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;
 		}
@@ -4002,12 +4015,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);
 }
@@ -4116,7 +4129,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);
@@ -4271,7 +4284,7 @@
 }
 
 /* This may not be the best way to do this, but we find the first key w/o a value
- * and assume it is the screenname */
+ * and assume it is the buddy name */
 static void yahoo_find_uri_novalue_param(gpointer key, gpointer value, gpointer user_data)
 {
 	char **retval = user_data;
--- a/libpurple/protocols/yahoo/yahoo_picture.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/yahoo/yahoo_picture.c	Wed Jan 28 10:23:37 2009 +0000
@@ -569,7 +569,7 @@
 		checksum &= ~g;
 	}
 
-	purple_debug_misc("yahoo", "Calculated buddy icon checksum: %d", checksum);
+	purple_debug_misc("yahoo", "Calculated buddy icon checksum: %d\n", checksum);
 
 	return checksum;
 } 
--- a/libpurple/protocols/yahoo/yahoo_profile.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/yahoo/yahoo_profile.c	Wed Jan 28 10:23:37 2009 +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);
@@ -1213,7 +1214,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));
 			}
 			str = f ? _("Could not retrieve the user's profile. "
 					  "This most likely is a temporary server-side problem. "
--- a/libpurple/protocols/yahoo/yahoochat.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/yahoo/yahoochat.c	Wed Jan 28 10:23:37 2009 +0000
@@ -519,7 +519,7 @@
 		GList *l;
 		GList *flags = NULL;
 		for (l = members; l; l = l->next)
-			flags = g_list_append(flags, GINT_TO_POINTER(PURPLE_CBFLAGS_NONE));
+			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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/protocols/zephyr/zephyr.c	Wed Jan 28 10:23:37 2009 +0000
@@ -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);
@@ -1141,6 +1147,7 @@
 				/* XXX fix */
 				char *user; 
 				PurpleBuddy *b;
+				const char *bname;
 				int nlocs = 0;
 				parse_tree *locations;
 				gchar *locval;
@@ -1160,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 {
@@ -1179,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)) {
@@ -1246,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
@@ -1288,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;
@@ -1295,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)) {
@@ -1323,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
@@ -1936,6 +1959,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");
@@ -1944,18 +1968,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);
 				}
@@ -2498,26 +2529,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;
--- a/libpurple/proxy.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/proxy.c	Wed Jan 28 10:23:37 2009 +0000
@@ -207,6 +207,16 @@
 	return global_proxy_info;
 }
 
+void
+purple_global_proxy_set_info(PurpleProxyInfo *info)
+{
+	g_return_if_fail(info != NULL);
+
+	purple_proxy_info_destroy(global_proxy_info);
+
+	global_proxy_info = info;
+}
+
 static PurpleProxyInfo *
 purple_gnome_proxy_get_info(void)
 {
@@ -228,13 +238,13 @@
 	g_free(err);
 	err = NULL;
 
-	if (!strcmp(tmp, "none\n")) {
+	if (purple_strequal(tmp, "none\n")) {
 		info.type = PURPLE_PROXY_NONE;
 		g_free(tmp);
 		return &info;
 	}
 
-	if (strcmp(tmp, "manual\n")) {
+	if (purple_strequal(tmp, "manual\n")) {
 		/* Unknown setting.  Fallback to using our global proxy settings. */
 		g_free(tmp);
 		return purple_global_proxy_get_info();
@@ -263,7 +273,7 @@
 	g_free(err);
 	err = NULL;
 
-	if (!strcmp(tmp, "true\n"))
+	if (purple_strequal(tmp, "true\n"))
 		use_same_proxy = TRUE;
 	g_free(tmp);
 	tmp = NULL;
@@ -1697,7 +1707,7 @@
 			return;
 
 		msg_ret = s5_parse_chap_msg(connect_data);
-	
+
 		if (msg_ret < 0)
 			return;
 
@@ -2242,31 +2252,31 @@
 {
 	PurpleProxyInfo *info = purple_global_proxy_get_info();
 
-	if (!strcmp(name, "/purple/proxy/type")) {
+	if (purple_strequal(name, "/purple/proxy/type")) {
 		int proxytype;
 		const char *type = value;
 
-		if (!strcmp(type, "none"))
+		if (purple_strequal(type, "none"))
 			proxytype = PURPLE_PROXY_NONE;
-		else if (!strcmp(type, "http"))
+		else if (purple_strequal(type, "http"))
 			proxytype = PURPLE_PROXY_HTTP;
-		else if (!strcmp(type, "socks4"))
+		else if (purple_strequal(type, "socks4"))
 			proxytype = PURPLE_PROXY_SOCKS4;
-		else if (!strcmp(type, "socks5"))
+		else if (purple_strequal(type, "socks5"))
 			proxytype = PURPLE_PROXY_SOCKS5;
-		else if (!strcmp(type, "envvar"))
+		else if (purple_strequal(type, "envvar"))
 			proxytype = PURPLE_PROXY_USE_ENVVAR;
 		else
 			proxytype = -1;
 
 		purple_proxy_info_set_type(info, proxytype);
-	} else if (!strcmp(name, "/purple/proxy/host"))
+	} else if (purple_strequal(name, "/purple/proxy/host"))
 		purple_proxy_info_set_host(info, value);
-	else if (!strcmp(name, "/purple/proxy/port"))
+	else if (purple_strequal(name, "/purple/proxy/port"))
 		purple_proxy_info_set_port(info, GPOINTER_TO_INT(value));
-	else if (!strcmp(name, "/purple/proxy/username"))
+	else if (purple_strequal(name, "/purple/proxy/username"))
 		purple_proxy_info_set_username(info, value);
-	else if (!strcmp(name, "/purple/proxy/password"))
+	else if (purple_strequal(name, "/purple/proxy/password"))
 		purple_proxy_info_set_password(info, value);
 }
 
--- a/libpurple/proxy.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/proxy.h	Wed Jan 28 10:23:37 2009 +0000
@@ -186,6 +186,14 @@
  */
 PurpleProxyInfo *purple_global_proxy_get_info(void);
 
+/**
+ * Set purple's global proxy information.
+ *
+ * @param info     The proxy information.
+ * @since 2.6.0
+ */
+void purple_global_proxy_set_info(PurpleProxyInfo *info);
+
 /*@}*/
 
 /**************************************************************************/
--- a/libpurple/prpl.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/prpl.c	Wed Jan 28 10:23:37 2009 +0000
@@ -75,7 +75,7 @@
 purple_attention_type_set_icon_name(PurpleAttentionType *type, const char *name)
 {
 	g_return_if_fail(type != NULL);
-	
+
 	type->icon_name = name;
 }
 
@@ -400,7 +400,7 @@
 	PurpleConversation *conv;
 	gboolean (*send_attention)(PurpleConnection *, const char *, guint);
 	PurpleBuddy *buddy;
-	const char *alias;	
+	const char *alias;
 	gchar *description;
 	time_t mtime;
 
@@ -425,7 +425,7 @@
 	} else {
 		description = g_strdup_printf(_("Requesting %s's attention..."), alias);
 	}
-	
+
 	flags = PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_NOTIFY | PURPLE_MESSAGE_SYSTEM;
 
 	purple_debug_info("server", "serv_send_attention: sending '%s' to %s\n",
@@ -511,7 +511,7 @@
 	for (l = purple_plugins_get_protocols(); l != NULL; l = l->next) {
 		plugin = (PurplePlugin *)l->data;
 
-		if (!strcmp(plugin->info->id, id))
+		if (purple_strequal(plugin->info->id, id))
 			return plugin;
 	}
 
--- a/libpurple/prpl.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/prpl.h	Wed Jan 28 10:23:37 2009 +0000
@@ -178,9 +178,11 @@
 	OPT_PROTO_USE_POINTSIZE = 0x00000100,
 
 	/**
-	 * Set the Register button active when screenname is not given.
+	 * Set the Register button active even when the username has not
+	 * been specified.
 	 *
-	 * Gadu-Gadu doesn't need a screenname to register new account.
+	 * Gadu-Gadu doesn't need a username to register new account (because
+	 * usernames are assigned by the server).
 	 */
 	OPT_PROTO_REGISTER_NOSCREENNAME = 0x00000200,
 
@@ -211,7 +213,7 @@
 
 	/**
 	 * Returns the base icon name for the given buddy and account.
-	 * If buddy is NULL and the account is non-NULL, it will return the 
+	 * If buddy is NULL and the account is non-NULL, it will return the
 	 * name to use for the account's icon. If both are NULL, it will
 	 * return the name to use for the protocol's icon.
 	 *
@@ -413,7 +415,7 @@
 	 * reasons.
 	 */
 	void (*unregister_user)(PurpleAccount *, PurpleAccountUnregistrationCb cb, void *user_data);
-	
+
 	/* Attention API for sending & receiving zaps/nudges/buzzes etc. */
 	gboolean (*send_attention)(PurpleConnection *gc, const char *username, guint type);
 	GList *(*get_attention_types)(PurpleAccount *acct);
@@ -594,7 +596,7 @@
 /*@{*/
 
 /**
- * Notifies Purple that an account's idle state and time have changed.
+ * Notifies Purple that our account's idle state and time have changed.
  *
  * This is meant to be called from protocol plugins.
  *
@@ -606,7 +608,7 @@
 								time_t idle_time);
 
 /**
- * Notifies Purple of an account's log-in time.
+ * Notifies Purple of our account's log-in time.
  *
  * This is meant to be called from protocol plugins.
  *
@@ -616,7 +618,7 @@
 void purple_prpl_got_account_login_time(PurpleAccount *account, time_t login_time);
 
 /**
- * Notifies Purple that an account's status has changed.
+ * Notifies Purple that our account's status has changed.
  *
  * This is meant to be called from protocol plugins.
  *
@@ -627,13 +629,14 @@
  */
 void purple_prpl_got_account_status(PurpleAccount *account,
 								  const char *status_id, ...) G_GNUC_NULL_TERMINATED;
+
 /**
- * Notifies Purple that a user's idle state and time have changed.
+ * Notifies Purple that a buddy's idle state and time have changed.
  *
  * This is meant to be called from protocol plugins.
  *
  * @param account   The account the user is on.
- * @param name      The screen name of the user.
+ * @param name      The name of the buddy.
  * @param idle      The user's idle state.
  * @param idle_time The user's idle time.  This is the time at
  *                  which the user became idle, in seconds since
@@ -644,24 +647,24 @@
 							 gboolean idle, time_t idle_time);
 
 /**
- * Notifies Purple of a user's log-in time.
+ * Notifies Purple of a buddy's log-in time.
  *
  * This is meant to be called from protocol plugins.
  *
  * @param account    The account the user is on.
- * @param name       The screen name of the user.
+ * @param name       The name of the buddy.
  * @param login_time The user's log-in time.
  */
 void purple_prpl_got_user_login_time(PurpleAccount *account, const char *name,
 								   time_t login_time);
 
 /**
- * Notifies Purple that a user's status has been activated.
+ * Notifies Purple that a buddy's status has been activated.
  *
  * This is meant to be called from protocol plugins.
  *
  * @param account   The account the user is on.
- * @param name      The screen name of the user.
+ * @param name      The name of the buddy.
  * @param status_id The status ID.
  * @param ...       A NULL-terminated list of attribute IDs and values,
  *                  beginning with the value for @a attr_id.
@@ -670,19 +673,19 @@
 							   const char *status_id, ...) G_GNUC_NULL_TERMINATED;
 
 /**
- * Notifies libpurple that a user's status has been deactivated
+ * Notifies libpurple that a buddy's status has been deactivated
  *
  * This is meant to be called from protocol plugins.
  *
  * @param account   The account the user is on.
- * @param name      The screen name of the user.
+ * @param name      The name of the buddy.
  * @param status_id The status ID.
  */
 void purple_prpl_got_user_status_deactive(PurpleAccount *account, const char *name,
 					const char *status_id);
- 
+
 /**
- * Informs the server that an account's status changed.
+ * Informs the server that our account's status changed.
  *
  * @param account    The account the user is on.
  * @param old_status The previous status.
@@ -703,37 +706,43 @@
  */
 GList *purple_prpl_get_statuses(PurpleAccount *account, PurplePresence *presence);
 
-/** Send an attention request message.
+/**
+ * Send an attention request message.
  *
  * @param gc The connection to send the message on.
  * @param who Whose attention to request.
  * @param type_code An index into the prpl's attention_types list determining the type
- * 	of the attention request command to send. 0 if prpl only defines one
- * 	(for example, Yahoo and MSN), but some protocols define more (MySpaceIM).
+ *        of the attention request command to send. 0 if prpl only defines one
+ *        (for example, Yahoo and MSN), but some protocols define more (MySpaceIM).
  *
  * Note that you can't send arbitrary PurpleAttentionType's, because there is
  * only a fixed set of attention commands.
+ *
  * @since 2.5.0
  */
 void purple_prpl_send_attention(PurpleConnection *gc, const char *who, guint type_code);
 
-/** Process an incoming attention message. 
+/**
+ * Process an incoming attention message.
  *
  * @param gc The connection that received the attention message.
  * @param who Who requested your attention.
  * @param type_code An index into the prpl's attention_types list determining the type
- * 	of the attention request command to send.
+ *        of the attention request command to send.
+ *
  * @since 2.5.0
  */
 void purple_prpl_got_attention(PurpleConnection *gc, const char *who, guint type_code);
 
-/** Process an incoming attention message in a chat. 
+/**
+ * Process an incoming attention message in a chat.
  *
  * @param gc The connection that received the attention message.
  * @param id The chat id.
  * @param who Who requested your attention.
  * @param type_code An index into the prpl's attention_types list determining the type
- * 	of the attention request command to send. 
+ *        of the attention request command to send.
+ *
  * @since 2.5.0
  */
 void purple_prpl_got_attention_in_chat(PurpleConnection *gc, int id, const char *who, guint type_code);
--- a/libpurple/purple-send-async	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/purple-send-async	Wed Jan 28 10:23:37 2009 +0000
@@ -2,18 +2,18 @@
 
 METHOD_NAME=$1
 
-if test -z "$METHOD_NAME" 
+if test -z "$METHOD_NAME"
 then
-    cat <<EOF 
-This program calls purple API functions using DBus.  As opposed to purple-send, 
+    cat <<EOF
+This program calls purple API functions using DBus.  As opposed to purple-send,
 it does not print the return value.
 
 Usage:
 
    $0 method-name type1:parameter1 type2:parameter2 ...
 
-This shell script just invokes dbus-send, see man dbus-send for how 
-to specify the parameters.  
+This shell script just invokes dbus-send, see man dbus-send for how
+to specify the parameters.
 
 Examples:
 
@@ -27,4 +27,4 @@
 shift
 dbus-send --dest=im.pidgin.purple.PurpleService --type=method_call /im/pidgin/purple/PurpleObject im.pidgin.purple.PurpleInterface.$METHOD_NAME "$@"
 
-echo 
+echo
--- a/libpurple/request.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/request.c	Wed Jan 28 10:23:37 2009 +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)
 {
--- a/libpurple/request.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/request.h	Wed Jan 28 10:23:37 2009 +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,17 @@
 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 +581,30 @@
  */
 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/savedstatuses.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/savedstatuses.c	Wed Jan 28 10:23:37 2009 +0000
@@ -461,7 +461,7 @@
 	ret = g_new0(PurpleSavedStatus, 1);
 
 	attrib = xmlnode_get_attrib(status, "transient");
-	if ((attrib == NULL) || (strcmp(attrib, "true")))
+	if (!purple_strequal(attrib, "true"))
 	{
 		/* Read the title */
 		attrib = xmlnode_get_attrib(status, "name");
@@ -940,7 +940,7 @@
 	for (iter = saved_statuses; iter != NULL; iter = iter->next)
 	{
 		status = (PurpleSavedStatus *)iter->data;
-		if ((status->title != NULL) && !strcmp(status->title, title))
+		if (purple_strequal(status->title, title))
 			return status;
 	}
 
@@ -975,8 +975,7 @@
 		status = (PurpleSavedStatus *)iter->data;
 		if ((status->type == type) && purple_savedstatus_is_transient(status) &&
 			!purple_savedstatus_has_substatuses(status) &&
-			(((status->message == NULL) && (message == NULL)) ||
-			((status->message != NULL) && (message != NULL) && !strcmp(status->message, message))))
+			purple_strequal(status->message, message))
 		{
 			return status;
 		}
--- a/libpurple/server.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/server.c	Wed Jan 28 10:23:37 2009 +0000
@@ -152,7 +152,7 @@
 	auto_reply_pref = purple_prefs_get_string("/purple/away/auto_reply");
 	if((gc->flags & PURPLE_CONNECTION_AUTO_RESP) &&
 			!purple_presence_is_available(presence) &&
-			strcmp(auto_reply_pref, "never")) {
+			!purple_strequal(auto_reply_pref, "never")) {
 
 		struct last_auto_response *lar;
 		lar = get_last_auto_response(gc, name);
@@ -172,7 +172,7 @@
 
 	if(gc)
 		prpl = purple_connection_get_prpl(gc);
-	
+
 	if(prpl)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
@@ -188,7 +188,7 @@
 
 	if(gc)
 		prpl = purple_connection_get_prpl(gc);
-	
+
 	if(prpl)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
@@ -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,20 +247,20 @@
 
 	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 (purple_strequal(server_alias, alias))
 			continue;
-		}
 
 		purple_blist_server_alias_buddy(b, alias);
 
-		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, b->name, account);
-		if(conv != NULL && alias != NULL &&
-		   who != NULL && strcmp(alias, who))
+		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, purple_buddy_get_name(b), account);
+		if (conv != NULL && alias != NULL && purple_strequal(alias, who))
 		{
 			char *escaped = g_markup_escape_text(who, -1);
 			char *escaped2 = g_markup_escape_text(alias, -1);
@@ -289,11 +289,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 (purple_strequal(balias, alias))
 			continue;
 
 		purple_blist_alias_buddy(b, alias);
@@ -367,7 +369,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));
 		}
 	}
 }
@@ -666,8 +670,8 @@
 		if ((primitive == PURPLE_STATUS_AVAILABLE) ||
 			(primitive == PURPLE_STATUS_INVISIBLE) ||
 			mobile ||
-		    !strcmp(auto_reply_pref, "never") ||
-		    (!purple_presence_is_idle(presence) && !strcmp(auto_reply_pref, "awayidle")))
+		    purple_strequal(auto_reply_pref, "never") ||
+		    (!purple_presence_is_idle(presence) && purple_strequal(auto_reply_pref, "awayidle")))
 		{
 			g_free(name);
 			return;
--- a/libpurple/server.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/server.h	Wed Jan 28 10:23:37 2009 +0000
@@ -55,8 +55,8 @@
 void serv_move_buddy(PurpleBuddy *, PurpleGroup *, PurpleGroup *);
 int  serv_send_im(PurpleConnection *, const char *, const char *, PurpleMessageFlags flags);
 
-/** Get information about an account's attention commands, from the prpl. 
- * 
+/** Get information about an account's attention commands, from the prpl.
+ *
  * @return The attention command numbered 'code' from the prpl's attention_types, or NULL.
  */
 PurpleAttentionType *purple_get_attention_type_from_code(PurpleAccount *account, guint type_code);
@@ -76,14 +76,14 @@
  */
 void serv_send_attention(PurpleConnection *gc, const char *who, guint type_code);
 
-/** Process an incoming attention message. 
+/** Process an incoming attention message.
  *
  * @deprecated Use purple_prpl_got_attention() instead.
  *
  * @param gc The connection that received the attention message.
  * @param who Who requested your attention.
  * @param type_code An index into the prpl's attention_types list determining the type
- * 	of the attention request command to send. 
+ * 	of the attention request command to send.
  */
 void serv_got_attention(PurpleConnection *gc, const char *who, guint type_code);
 
@@ -108,7 +108,7 @@
  * aliases are the aliases or display names that buddies set for themselves.
  *
  * @param gc The connection on which the alias was received.
- * @param who The screen name of the buddy whose alias was received.
+ * @param who The name of the buddy whose alias was received.
  * @param alias The alias that was received.
  */
 void purple_serv_got_private_alias(PurpleConnection *gc, const char *who, const char *alias);
@@ -180,7 +180,7 @@
  *                function should be g_str_equal().
  */
 void purple_serv_got_join_chat_failed(PurpleConnection *gc, GHashTable *data);
-	
+
 void serv_got_chat_left(PurpleConnection *g, int id);
 void serv_got_chat_in(PurpleConnection *g, int id, const char *who,
 					  PurpleMessageFlags flags, const char *message, time_t mtime);
--- a/libpurple/signals.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/signals.c	Wed Jan 28 10:23:37 2009 +0000
@@ -487,7 +487,7 @@
 	}
 
 #ifdef HAVE_DBUS
-	purple_dbus_signal_emit_purple(signal, signal_data->num_values, 
+	purple_dbus_signal_emit_purple(signal, signal_data->num_values,
 				   signal_data->values, args);
 #endif	/* HAVE_DBUS */
 
@@ -539,7 +539,7 @@
 
 #ifdef HAVE_DBUS
 	G_VA_COPY(tmp, args);
-	purple_dbus_signal_emit_purple(signal, signal_data->num_values, 
+	purple_dbus_signal_emit_purple(signal, signal_data->num_values,
 				   signal_data->values, tmp);
 	va_end(tmp);
 #endif	/* HAVE_DBUS */
--- a/libpurple/signals.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/signals.h	Wed Jan 28 10:23:37 2009 +0000
@@ -137,7 +137,7 @@
 /**
  * Connects a signal handler to a signal for a particular object.
  * (Its priority defaults to 0, aka #PURPLE_SIGNAL_PRIORITY_DEFAULT.)
- * 
+ *
  * Take care not to register a handler function twice. Purple will
  * not correct any mistakes for you in this area.
  *
--- a/libpurple/smiley.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/smiley.c	Wed Jan 28 10:23:37 2009 +0000
@@ -722,7 +722,7 @@
 		smiley = purple_smiley_new_from_stream(shortcut, smiley_data,
 				smiley_data_len);
 	}
-	
+
 	return smiley;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/sound-theme-loader.c	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,111 @@
+/*
+ * 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 "internal.h"
+#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-theme-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	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,71 @@
+/**
+ * @file sound-theme-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	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,158 @@
+/*
+ * 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 "internal.h"
+#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	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,105 @@
+/**
+ * @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.  This is
+ *          a newly allocated string that should be freed with g_free.
+ */
+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	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/sound.c	Wed Jan 28 10:23:37 2009 +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/sslconn.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/sslconn.c	Wed Jan 28 10:23:37 2009 +0000
@@ -216,7 +216,7 @@
 	/* TODO: Move this elsewhere */
 	gsc->verifier = purple_certificate_find_verifier("x509","tls_cached");
 
-    
+
 	ops = purple_ssl_get_ops();
 	ops->connectfunc(gsc);
 
--- a/libpurple/sslconn.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/sslconn.h	Wed Jan 28 10:23:37 2009 +0000
@@ -65,7 +65,7 @@
 
 	/** File descriptor used to refer to the socket */
 	int fd;
-	/** Glib event source ID; used to refer to the received data callback 
+	/** Glib event source ID; used to refer to the received data callback
 	 * in the glib eventloop */
 	guint inpa;
 	/** Data related to the underlying TCP connection */
@@ -133,7 +133,7 @@
 	 *              list can be guaranteed.
 	 */
 	GList * (* get_peer_certificates)(PurpleSslConnection * gsc);
-	
+
 	void (*_purple_reserved2)(void);
 	void (*_purple_reserved3)(void);
 	void (*_purple_reserved4)(void);
--- a/libpurple/status.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/status.c	Wed Jan 28 10:23:37 2009 +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_STATUS_C_
+
 #include "internal.h"
 
 #include "blist.h"
@@ -203,7 +205,7 @@
 
     for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
     {
-        if (!strcmp(id, status_primitive_map[i].id))
+		if (purple_strequal(id, status_primitive_map[i].id))
             return status_primitive_map[i].type;
     }
 
@@ -451,7 +453,7 @@
 	{
 		PurpleStatusAttr *attr = (PurpleStatusAttr *)l->data;
 
-		if (!strcmp(purple_status_attr_get_id(attr), id))
+		if (purple_strequal(purple_status_attr_get_id(attr), id))
 			return attr;
 	}
 
@@ -477,7 +479,7 @@
 	{
 		status_type = status_types->data;
 
-		if (!strcmp(id, status_type->id))
+		if (purple_strequal(id, status_type->id))
 			return status_type;
 
 		status_types = status_types->next;
@@ -612,7 +614,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 +626,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,
@@ -779,12 +784,8 @@
 		{
 			const gchar *string_data = l->data;
 			l = l->next;
-			if (((string_data == NULL) && (value->data.string_data == NULL)) ||
-				((string_data != NULL) && (value->data.string_data != NULL) &&
-				!strcmp(string_data, value->data.string_data)))
-			{
+			if (purple_strequal(string_data, value->data.string_data))
 				continue;
-			}
 			purple_status_set_attr_string(status, id, string_data);
 			changed = TRUE;
 		}
@@ -1146,13 +1147,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;
 
@@ -1248,12 +1249,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)
 			{
@@ -1273,7 +1275,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)
 			{
@@ -1461,7 +1463,7 @@
 		{
 			PurpleStatus *temp_status = l->data;
 
-			if (!strcmp(status_id, purple_status_get_id(temp_status)))
+			if (purple_strequal(status_id, purple_status_get_id(temp_status)))
 				status = temp_status;
 		}
 
--- a/libpurple/status.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/status.h	Wed Jan 28 10:23:37 2009 +0000
@@ -252,6 +252,7 @@
  */
 void purple_status_type_destroy(PurpleStatusType *status_type);
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_STATUS_C_)
 /**
  * Sets a status type's primary attribute.
  *
@@ -261,10 +262,14 @@
  *
  * @param status_type The status type.
  * @param attr_id     The ID of the primary attribute.
+ *
+ * @deprecated This function isn't used and should be removed in 3.0.0.
  */
 void purple_status_type_set_primary_attr(PurpleStatusType *status_type,
 									   const char *attr_id);
+#endif
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_STATUS_C_)
 /**
  * Adds an attribute to a status type.
  *
@@ -272,10 +277,16 @@
  * @param id          The ID of the attribute.
  * @param name        The name presented to the user.
  * @param value       The value type of this attribute.
+ *
+ * @deprecated This function isn't needed and should be removed in 3.0.0.
+ *             Status type attributes should be set when the status type
+ *             is created, in the call to purple_status_type_new_with_attrs.
  */
 void purple_status_type_add_attr(PurpleStatusType *status_type, const char *id,
 							   const char *name, PurpleValue *value);
+#endif
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_STATUS_C_)
 /**
  * Adds multiple attributes to a status type.
  *
@@ -284,18 +295,29 @@
  * @param name        The description of the first attribute.
  * @param value       The value type of the first attribute attribute.
  * @param ...         Additional attribute information.
+ *
+ * @deprecated This function isn't needed and should be removed in 3.0.0.
+ *             Status type attributes should be set when the status type
+ *             is created, in the call to purple_status_type_new_with_attrs.
  */
 void purple_status_type_add_attrs(PurpleStatusType *status_type, const char *id,
 								const char *name, PurpleValue *value, ...) G_GNUC_NULL_TERMINATED;
+#endif
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_STATUS_C_)
 /**
  * Adds multiple attributes to a status type using a va_list.
  *
  * @param status_type The status type to add the attribute to.
  * @param args        The va_list of attributes.
+ *
+ * @deprecated This function isn't needed and should be removed in 3.0.0.
+ *             Status type attributes should be set when the status type
+ *             is created, in the call to purple_status_type_new_with_attrs.
  */
 void purple_status_type_add_attrs_vargs(PurpleStatusType *status_type,
 									  va_list args);
+#endif
 
 /**
  * Returns the primitive type of a status type.
@@ -378,14 +400,18 @@
  */
 gboolean purple_status_type_is_available(const PurpleStatusType *status_type);
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_STATUS_C_)
 /**
  * Returns a status type's primary attribute ID.
  *
  * @param type The status type.
  *
  * @return The primary attribute's ID.
+ *
+ * @deprecated This function isn't used and should be removed in 3.0.0.
  */
 const char *purple_status_type_get_primary_attr(const PurpleStatusType *type);
+#endif
 
 /**
  * Returns the attribute with the specified ID.
@@ -537,35 +563,50 @@
 void purple_status_set_active_with_attrs_list(PurpleStatus *status, gboolean active,
 											GList *attrs);
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_STATUS_C_)
 /**
  * Sets the boolean value of an attribute in a status with the specified ID.
  *
  * @param status The status.
  * @param id     The attribute ID.
  * @param value  The boolean value.
+ *
+ * @deprecated This function is only used by status.c and should be made
+ *             static in 3.0.0.
  */
 void purple_status_set_attr_boolean(PurpleStatus *status, const char *id,
 								  gboolean value);
+#endif
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_STATUS_C_)
 /**
  * Sets the integer value of an attribute in a status with the specified ID.
  *
  * @param status The status.
  * @param id     The attribute ID.
  * @param value  The integer value.
+ *
+ * @deprecated This function is only used by status.c and should be made
+ *             static in 3.0.0.
  */
 void purple_status_set_attr_int(PurpleStatus *status, const char *id,
 							  int value);
+#endif
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_STATUS_C_)
 /**
  * Sets the string value of an attribute in a status with the specified ID.
  *
  * @param status The status.
  * @param id     The attribute ID.
  * @param value  The string value.
+ *
+ * @deprecated This function is only used by status.c and should be made
+ *             static in 3.0.0.
  */
 void purple_status_set_attr_string(PurpleStatus *status, const char *id,
 								 const char *value);
+#endif
 
 /**
  * Returns the status's type.
@@ -773,22 +814,31 @@
  */
 void purple_presence_destroy(PurplePresence *presence);
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_STATUS_C_)
 /**
  * Adds a status to a presence.
  *
  * @param presence The presence.
  * @param status   The status to add.
+ *
+ * @deprecated This function is only used by purple_presence_add_list,
+ *             and both should be removed in 3.0.0.
  */
 void purple_presence_add_status(PurplePresence *presence, PurpleStatus *status);
+#endif
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_STATUS_C_)
 /**
  * Adds a list of statuses to the presence.
  *
  * @param presence    The presence.
  * @param source_list The source list of statuses to add, which is not
  *                    modified or freed by this function.
+ *
+ * @deprecated This function isn't used and should be removed in 3.0.0.
  */
 void purple_presence_add_list(PurplePresence *presence, GList *source_list);
+#endif
 
 /**
  * Sets the active state of a status in a presence.
--- a/libpurple/stun.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/stun.c	Wed Jan 28 10:23:37 2009 +0000
@@ -388,9 +388,7 @@
 		/** Deal with the server name having changed since we did the
 		    lookup */
 		if (servername && strlen(servername) > 1
-				&& ((nattype.servername
-					&& strcmp(servername, nattype.servername))
-				|| !nattype.servername)) {
+				&& !purple_strequal(servername, nattype.servername)) {
 			use_cached_result = FALSE;
 		}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/theme-loader.c	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,183 @@
+/*
+ * 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 "internal.h"
+#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	Wed Jan 28 10:23:37 2009 +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 A 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	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,295 @@
+/*
+ * 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 <glib.h>
+#include <string.h>
+
+#include "internal.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 && *name, NULL);
+	g_return_val_if_fail(type && *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);
+
+	if (!rdir)
+		return;
+
+	/* 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(void)
+{
+	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(void)
+{
+	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	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,131 @@
+/**
+ * @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 and 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 exists
+ * then this function 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);
+
+/**
+ * Adds 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);
+
+/**
+ * Calls 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	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,408 @@
+/*
+ * 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 <glib.h>
+#include <string.h>
+
+#include "internal.h"
+#include "theme.h"
+#include "util.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, -1);
+	g_strdelimit(clean_text, "\n", ' ');
+	purple_str_strip_char(clean_text, '\r');
+	return clean_text;
+}
+
+/*****************************************************************************
+ * Public API function
+ *****************************************************************************/
+
+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	Wed Jan 28 10:23:37 2009 +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/upnp.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/upnp.c	Wed Jan 28 10:23:37 2009 +0000
@@ -715,7 +715,7 @@
 
 	g_free(totalSendMessage);
 	g_free(addressOfControl);
-	
+
 	return gfud;
 }
 
@@ -1048,7 +1048,7 @@
 purple_upnp_get_handle(void)
 {
 	static int handle;
-	
+
 	return &handle;
 }
 
--- a/libpurple/util.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/util.c	Wed Jan 28 10:23:37 2009 +0000
@@ -98,7 +98,7 @@
 void
 purple_util_init(void)
 {
-	/* This does nothing right now.  It exists for symmetry with 
+	/* This does nothing right now.  It exists for symmetry with
 	 * purple_util_uninit() and forwards compatibility. */
 }
 
@@ -1409,7 +1409,7 @@
 						struct purple_parse_tag *pt = tags->data;
 						if(xhtml)
 							g_string_append_printf(xhtml, "</%s>", pt->dest_tag);
-						if(plain && !strcmp(pt->src_tag, "a")) {
+						if(plain && purple_strequal(pt->src_tag, "a")) {
 							/* if this is a link, we have to add the url to the plaintext, too */
 							if (cdata && url &&
 									(!g_string_equal(cdata, url) && (g_ascii_strncasecmp(url->str, "mailto:", 7) != 0 ||
@@ -2693,7 +2693,7 @@
 		return FALSE;
 	}
 #endif
-    
+
 	/* Close file */
 	if (fclose(file) != 0)
 	{
@@ -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");
 }
 
 /*
@@ -3012,7 +2949,7 @@
 	g_free(tmp);
 
 	session = g_getenv("KDE_FULL_SESSION");
-	if (session != NULL && !strcmp(session, "true"))
+	if (purple_strequal(session, "true"))
 		return TRUE;
 
 	/* If you run Purple from Konsole under !KDE, this will provide a
@@ -3053,6 +2990,17 @@
 /**************************************************************************
  * String Functions
  **************************************************************************/
+gboolean
+purple_strequal(const gchar *left, const gchar *right)
+{
+#if GLIB_CHECK_VERSION(2,16,0)
+	return (g_strcmp0(left, right) == 0);
+#else
+	return ((left == NULL && right == NULL) ||
+	        (left != NULL && right != NULL && strcmp(left, right) == 0));
+#endif
+}
+
 const char *
 purple_normalize(const PurpleAccount *account, const char *str)
 {
@@ -3167,7 +3115,7 @@
 	g_return_val_if_fail(x != NULL, FALSE);
 
 	off = strlen(s) - strlen(x);
-	return (off >= 0 && !strcmp(s + off, x));
+	return (off >= 0 && purple_strequal(s + off, x));
 #endif
 }
 
@@ -4764,7 +4712,7 @@
 
 const char *_purple_oscar_convert(const char *act, const char *protocol)
 {
-	if (protocol && act && strcmp(protocol, "prpl-oscar") == 0) {
+	if (act && purple_strequal(protocol, "prpl-oscar")) {
 		int i;
 		for (i = 0; act[i] != '\0'; i++)
 			if (!isdigit(act[i]))
--- a/libpurple/util.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/util.h	Wed Jan 28 10:23:37 2009 +0000
@@ -775,6 +775,21 @@
 /*@{*/
 
 /**
+ * Tests two strings for equality.
+ *
+ * Unlike strcmp(), this function will not crash if one or both of the
+ * strings are @c NULL.
+ *
+ * @param left	A string
+ * @param right A string to compare with left
+ *
+ * @return @c TRUE if the strings are the same, else @c FALSE.
+ *
+ * @since 2.6.0
+ */
+gboolean purple_strequal(const gchar *left, const gchar *right);
+
+/**
  * Normalizes a string, so that it is suitable for comparison.
  *
  * The returned string will point to a static buffer, so if the
--- a/libpurple/whiteboard.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/whiteboard.c	Wed Jan 28 10:23:37 2009 +0000
@@ -115,7 +115,7 @@
 	{
 		wb = l->data;
 
-		if(wb->account == account && !strcmp(wb->who, who))
+		if(wb->account == account && purple_strequal(wb->who, who))
 			return wb;
 
 		l = l->next;
--- a/libpurple/xmlnode.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/xmlnode.c	Wed Jan 28 10:23:37 2009 +0000
@@ -129,7 +129,7 @@
 	for(attr_node = node->child; attr_node; attr_node = attr_node->next)
 	{
 		if(attr_node->type == XMLNODE_TYPE_ATTRIB &&
-				!strcmp(attr_node->name, attr))
+				purple_strequal(attr_node->name, attr))
 		{
 			if(sibling == NULL) {
 				node->child = attr_node->next;
@@ -146,20 +146,6 @@
 	}
 }
 
-/* Compare two nullable xmlns strings.
- * They are considered equal if they're both NULL or the strings are equal
- */
-static gboolean _xmlnode_compare_xmlns(const char *xmlns1, const char *xmlns2) {
-	gboolean equal = FALSE;
-
-	if (xmlns1 == NULL && xmlns2 == NULL)
-		equal = TRUE;
-	else if (xmlns1 != NULL && xmlns2 != NULL && !strcmp(xmlns1, xmlns2))
-		equal = TRUE;
-
-	return equal;
-}
-
 void
 xmlnode_remove_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns)
 {
@@ -171,8 +157,8 @@
 	for(attr_node = node->child; attr_node; attr_node = attr_node->next)
 	{
 		if(attr_node->type == XMLNODE_TYPE_ATTRIB &&
-		   !strcmp(attr_node->name, attr) &&
-		   _xmlnode_compare_xmlns(xmlns, attr_node->xmlns))
+		   purple_strequal(attr,  attr_node->name) &&
+		   purple_strequal(xmlns, attr_node->xmlns))
 		{
 			if(sibling == NULL) {
 				node->child = attr_node->next;
@@ -252,7 +238,7 @@
 	g_return_val_if_fail(attr != NULL, NULL);
 
 	for(x = node->child; x; x = x->next) {
-		if(x->type == XMLNODE_TYPE_ATTRIB && !strcmp(attr, x->name)) {
+		if(x->type == XMLNODE_TYPE_ATTRIB && purple_strequal(attr, x->name)) {
 			return x->data;
 		}
 	}
@@ -270,8 +256,8 @@
 
 	for(x = node->child; x; x = x->next) {
 		if(x->type == XMLNODE_TYPE_ATTRIB &&
-		   !strcmp(attr, x->name) &&
-		   _xmlnode_compare_xmlns(xmlns, x->xmlns)) {
+		   purple_strequal(attr,  x->name) &&
+		   purple_strequal(xmlns, x->xmlns)) {
 			return x->data;
 		}
 	}
@@ -382,8 +368,8 @@
 		if(ns)
 			xmlns = xmlnode_get_namespace(x);
 
-		if(x->type == XMLNODE_TYPE_TAG && name && !strcmp(parent_name, x->name)
-				&& (!ns || (xmlns && !strcmp(ns, xmlns)))) {
+		if(x->type == XMLNODE_TYPE_TAG && purple_strequal(parent_name, x->name)
+				&& purple_strequal(ns, xmlns)) {
 			ret = x;
 			break;
 		}
@@ -471,7 +457,7 @@
 		g_hash_table_foreach(node->namespace_map,
 			(GHFunc)xmlnode_to_str_foreach_append_ns, text);
 	} else if (node->xmlns) {
-		if(!node->parent || !node->parent->xmlns || strcmp(node->xmlns, node->parent->xmlns))
+		if(!node->parent || !purple_strequal(node->xmlns, node->parent->xmlns))
 		{
 			char *xmlns = g_markup_escape_text(node->xmlns, -1);
 			g_string_append_printf(text, " xmlns='%s'", xmlns);
@@ -642,7 +628,7 @@
 
 	if(!xpd->current || xpd->error)
 		return;
-	
+
 	if(!text || !text_len)
 		return;
 
@@ -730,6 +716,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)
 {
@@ -794,8 +852,8 @@
 		if(ns)
 			xmlns = xmlnode_get_namespace(sibling);
 
-		if(sibling->type == XMLNODE_TYPE_TAG && !strcmp(node->name, sibling->name) &&
-				(!ns || (xmlns && !strcmp(ns, xmlns))))
+		if(sibling->type == XMLNODE_TYPE_TAG && purple_strequal(node->name, sibling->name) &&
+				purple_strequal(ns, xmlns))
 			return sibling;
 	}
 
--- a/libpurple/xmlnode.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/libpurple/xmlnode.h	Wed Jan 28 10:23:37 2009 +0000
@@ -26,6 +26,8 @@
 #ifndef _PURPLE_XMLNODE_H_
 #define _PURPLE_XMLNODE_H_
 
+#include <glib.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -297,6 +299,22 @@
  */
 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.
+ *
+ * @since 2.6.0
+ */
+xmlnode *xmlnode_from_file(const char *dir, const char *filename,
+			   const char *description, const char *process);
+
 #ifdef __cplusplus
 }
 #endif
--- a/pidgin/Makefile.am	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/Makefile.am	Wed Jan 28 10:23:37 2009 +0000
@@ -78,6 +78,8 @@
 	pidginstock.c \
 	gtkaccount.c \
 	gtkblist.c \
+	gtkblist-theme.c \
+	gtkblist-theme-loader.c \
 	gtkcelllayout.c \
 	gtkcellrendererexpander.c \
 	gtkcellrendererprogress.c \
@@ -94,6 +96,8 @@
 	gtkeventloop.c \
 	gtkexpander.c \
 	gtkft.c \
+	gtkicon-theme.c \
+	gtkicon-theme-loader.c \
 	gtkidle.c \
 	gtkimhtml.c \
 	gtkimhtmltoolbar.c \
@@ -116,6 +120,7 @@
 	gtksourceiter.c \
 	gtksourceundomanager.c \
 	gtksourceview-marshal.c \
+	gtkstatus-icon-theme.c \
 	gtkstatusbox.c \
 	gtkthemes.c \
 	gtkutils.c \
@@ -127,6 +132,8 @@
 	eggtrayicon.h \
 	gtkaccount.h \
 	gtkblist.h \
+	gtkblist-theme.h \
+	gtkblist-theme-loader.h \
 	gtkcelllayout.h \
 	gtkcellrendererexpander.h \
 	gtkcellrendererprogress.h \
@@ -146,6 +153,8 @@
 	gtkeventloop.h \
 	gtkexpander.h \
 	gtkft.h \
+	gtkicon-theme.h \
+	gtkicon-theme-loader.h \
 	gtkidle.h \
 	gtkgaim-compat.h \
 	gtkimhtml.h \
@@ -169,6 +178,7 @@
 	gtksourceiter.h \
 	gtksourceundomanager.h \
 	gtksourceview-marshal.h \
+	gtkstatus-icon-theme.h \
 	gtkstatusbox.h \
 	pidginstock.h \
 	gtkthemes.h \
--- a/pidgin/Makefile.mingw	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/Makefile.mingw	Wed Jan 28 10:23:37 2009 +0000
@@ -56,6 +56,8 @@
 PIDGIN_C_SRC =	\
 			gtkaccount.c \
 			gtkblist.c \
+			gtkblist-theme.c \
+			gtkblist-theme-loader.c \
 			gtkcertmgr.c \
 			gtkcellrendererexpander.c \
 			gtkcellrendererprogress.c \
@@ -68,6 +70,8 @@
 			gtkeventloop.c \
 			gtkexpander.c \
 			gtkft.c \
+			gtkicon-theme.c \
+			gtkicon-theme-loader.c \
 			gtkidle.c \
 			gtkimhtml.c \
 			gtkimhtmltoolbar.c \
@@ -88,6 +92,7 @@
 			gtksound.c \
 			gtksourceiter.c \
 			gtksourceundomanager.c \
+			gtkstatus-icon-theme.c \
 			gtkstatusbox.c \
 			gtkthemes.c \
 			gtkutils.c \
--- a/pidgin/eggtrayicon.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/eggtrayicon.c	Wed Jan 28 10:23:37 2009 +0000
@@ -39,7 +39,7 @@
   PROP_0,
   PROP_ORIENTATION
 };
-         
+
 static GtkPlugClass *parent_class = NULL;
 
 static void egg_tray_icon_init (EggTrayIcon *icon);
@@ -102,7 +102,7 @@
 {
   icon->stamp = 1;
   icon->orientation = GTK_ORIENTATION_HORIZONTAL;
-  
+
   gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
 }
 
@@ -250,7 +250,7 @@
 	  egg_tray_icon_manager_window_destroyed (icon);
 	}
     }
-  
+
   return GDK_FILTER_CONTINUE;
 }
 
@@ -296,7 +296,7 @@
 {
   XClientMessageEvent ev;
   Display *display;
-  
+
   ev.type = ClientMessage;
   ev.window = window;
   ev.message_type = icon->system_tray_opcode_atom;
@@ -335,7 +335,7 @@
 				     gboolean     dock_if_realized)
 {
   Display *xdisplay;
-  
+
   if (icon->manager_window != None)
     return;
 
@@ -345,7 +345,7 @@
     return;
 
   XGrabServer (xdisplay);
-  
+
   icon->manager_window = XGetSelectionOwner (xdisplay,
 					     icon->selection_atom);
 
@@ -355,7 +355,7 @@
 
   XUngrabServer (xdisplay);
   XFlush (xdisplay);
-  
+
   if (icon->manager_window != None)
     {
       GdkWindow *gdkwin;
@@ -380,7 +380,7 @@
 egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon)
 {
   GdkWindow *gdkwin;
-  
+
   g_return_if_fail (icon->manager_window != None);
 
 #if GTK_CHECK_VERSION(2,1,0)
@@ -458,9 +458,9 @@
 	      screen);
 
   icon->selection_atom = XInternAtom (xdisplay, buffer, False);
-  
+
   icon->manager_atom = XInternAtom (xdisplay, "MANAGER", False);
-  
+
   icon->system_tray_opcode_atom = XInternAtom (xdisplay,
 						   "_NET_SYSTEM_TRAY_OPCODE",
 						   False);
@@ -514,11 +514,11 @@
 			    gint         len)
 {
   guint stamp;
-  
+
   g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
   g_return_val_if_fail (timeout >= 0, 0);
   g_return_val_if_fail (message != NULL, 0);
-		     
+
   if (icon->manager_window == None)
     return 0;
 
@@ -526,7 +526,7 @@
     len = strlen (message);
 
   stamp = icon->stamp++;
-  
+
   /* Get ready to send the message */
   egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
 				      (Window)gtk_plug_get_id (GTK_PLUG (icon)),
@@ -576,7 +576,7 @@
 {
   g_return_if_fail (EGG_IS_TRAY_ICON (icon));
   g_return_if_fail (id > 0);
-  
+
   egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
 				      (Window)gtk_plug_get_id (GTK_PLUG (icon)),
 				      id, 0, 0);
--- a/pidgin/eggtrayicon.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/eggtrayicon.h	Wed Jan 28 10:23:37 2009 +0000
@@ -33,7 +33,7 @@
 #define EGG_IS_TRAY_ICON(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TRAY_ICON))
 #define EGG_IS_TRAY_ICON_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_ICON))
 #define EGG_TRAY_ICON_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
-	
+
 typedef struct _EggTrayIcon	  EggTrayIcon;
 typedef struct _EggTrayIconClass  EggTrayIconClass;
 
@@ -42,7 +42,7 @@
   GtkPlug parent_instance;
 
   guint stamp;
-  
+
   Atom selection_atom;
   Atom manager_atom;
   Atom system_tray_opcode_atom;
@@ -74,7 +74,7 @@
 					   guint        id);
 
 GtkOrientation egg_tray_icon_get_orientation (EggTrayIcon *icon);
-					    
+
 G_END_DECLS
 
 #endif /* __EGG_TRAY_ICON_H__ */
--- a/pidgin/getopt.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/getopt.c	Wed Jan 28 10:23:37 2009 +0000
@@ -178,7 +178,7 @@
 {
   REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
 } ordering;
-
+
 #ifdef	__GNU_LIBRARY__
 /* We want to avoid inclusion of string.h with non-GNU libraries
    because there are many ways it can cause trouble.
@@ -219,7 +219,7 @@
     to[i] = from[i];
 }
 #endif				/* GNU C library.  */
-
+
 /* Handle permutation of arguments.  */
 
 /* Describe the part of ARGV that contains non-options that have
@@ -259,7 +259,7 @@
   first_nonopt += (optind - last_nonopt);
   last_nonopt = optind;
 }
-
+
 /* Scan elements of ARGV (whose length is ARGC) for option characters
    given in OPTSTRING.
 
@@ -663,7 +663,7 @@
 }
 
 #endif	/* _LIBC or not __GNU_LIBRARY__.  */
-
+
 #ifdef TEST
 
 /* Compile with -DTEST to make an executable for use in testing
--- a/pidgin/getopt1.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/getopt1.c	Wed Jan 28 10:23:37 2009 +0000
@@ -81,7 +81,7 @@
 
 
 #endif	/* _LIBC or not __GNU_LIBRARY__.  */
-
+
 #ifdef TEST
 
 #include <stdio.h>
--- a/pidgin/gtkaccount.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkaccount.c	Wed Jan 28 10:23:37 2009 +0000
@@ -51,7 +51,7 @@
 {
 	COLUMN_ICON,
 	COLUMN_BUDDYICON,
-	COLUMN_SCREENNAME,
+	COLUMN_USERNAME,
 	COLUMN_ENABLED,
 	COLUMN_PROTOCOL,
 	COLUMN_DATA,
@@ -78,7 +78,7 @@
 	GtkListStore *model;
 	GtkTreeIter drag_iter;
 
-	GtkTreeViewColumn *screenname_col;
+	GtkTreeViewColumn *username_col;
 
 } AccountsWindow;
 
@@ -115,7 +115,7 @@
 	GtkWidget *login_frame;
 	GtkWidget *protocol_menu;
 	GtkWidget *password_box;
-	GtkWidget *screenname_entry;
+	GtkWidget *username_entry;
 	GtkWidget *password_entry;
 	GtkWidget *alias_entry;
 	GtkWidget *remember_pass_check;
@@ -256,7 +256,7 @@
 }
 
 static gboolean
-screenname_focus_cb(GtkWidget *widget, GdkEventFocus *event, AccountPrefsDialog *dialog)
+username_focus_cb(GtkWidget *widget, GdkEventFocus *event, AccountPrefsDialog *dialog)
 {
 	GHashTable *table;
 	const char *label;
@@ -275,7 +275,7 @@
 }
 
 static void
-screenname_changed_cb(GtkEntry *entry, AccountPrefsDialog *dialog)
+username_changed_cb(GtkEntry *entry, AccountPrefsDialog *dialog)
 {
 	if (dialog->ok_button)
 		gtk_widget_set_sensitive(dialog->ok_button,
@@ -290,7 +290,7 @@
 }
 
 static gboolean
-screenname_nofocus_cb(GtkWidget *widget, GdkEventFocus *event, AccountPrefsDialog *dialog)
+username_nofocus_cb(GtkWidget *widget, GdkEventFocus *event, AccountPrefsDialog *dialog)
 {
 	GdkColor color = {0, 34952, 35466, 34181};
 	GHashTable *table = NULL;
@@ -301,13 +301,13 @@
 		label = g_hash_table_lookup(table, "login_label");
 
 		if (*gtk_entry_get_text(GTK_ENTRY(widget)) == '\0') {
-			/* We have to avoid hitting the screenname_changed_cb function 
+			/* We have to avoid hitting the username_changed_cb function
 			 * because it enables buttons we don't want enabled yet ;)
 			 */
-			g_signal_handlers_block_by_func(widget, G_CALLBACK(screenname_changed_cb), dialog);
+			g_signal_handlers_block_by_func(widget, G_CALLBACK(username_changed_cb), dialog);
 			gtk_entry_set_text(GTK_ENTRY(widget), label);
 			/* Make sure we can hit it again */
-			g_signal_handlers_unblock_by_func(widget, G_CALLBACK(screenname_changed_cb), dialog);
+			g_signal_handlers_unblock_by_func(widget, G_CALLBACK(username_changed_cb), dialog);
 			gtk_widget_modify_text(widget, GTK_STATE_NORMAL, &color);
 		}
 
@@ -393,7 +393,7 @@
 
 	set = !(purple_account_is_connected(dialog->account) || purple_account_is_connecting(dialog->account));
 	gtk_widget_set_sensitive(dialog->protocol_menu, set);
-	gtk_widget_set_sensitive(dialog->screenname_entry, set);
+	gtk_widget_set_sensitive(dialog->username_entry, set);
 
 	for (l = dialog->user_split_entries ; l != NULL ; l = l->next)
 		gtk_widget_set_sensitive((GtkWidget *)l->data, set);
@@ -449,13 +449,13 @@
 
 	gtk_widget_unref(dialog->protocol_menu);
 
-	/* Screen name */
-	dialog->screenname_entry = gtk_entry_new();
+	/* Username */
+	dialog->username_entry = gtk_entry_new();
 #if GTK_CHECK_VERSION(2,10,0)
-	g_object_set(G_OBJECT(dialog->screenname_entry), "truncate-multiline", TRUE, NULL);
+	g_object_set(G_OBJECT(dialog->username_entry), "truncate-multiline", TRUE, NULL);
 #endif
 
-	add_pref_box(dialog, vbox, _("_Username:"), dialog->screenname_entry);
+	add_pref_box(dialog, vbox, _("_Username:"), dialog->username_entry);
 
 	if (dialog->account != NULL)
 		username = g_strdup(purple_account_get_username(dialog->account));
@@ -468,17 +468,17 @@
 		table = dialog->prpl_info->get_account_text_table(NULL);
 		label = g_hash_table_lookup(table, "login_label");
 
-		gtk_entry_set_text(GTK_ENTRY(dialog->screenname_entry), label);
-		g_signal_connect(G_OBJECT(dialog->screenname_entry), "focus-in-event",
-				G_CALLBACK(screenname_focus_cb), dialog);
-		g_signal_connect(G_OBJECT(dialog->screenname_entry), "focus-out-event",
-				G_CALLBACK(screenname_nofocus_cb), dialog);
-		gtk_widget_modify_text(dialog->screenname_entry, GTK_STATE_NORMAL, &color);
+		gtk_entry_set_text(GTK_ENTRY(dialog->username_entry), label);
+		g_signal_connect(G_OBJECT(dialog->username_entry), "focus-in-event",
+				G_CALLBACK(username_focus_cb), dialog);
+		g_signal_connect(G_OBJECT(dialog->username_entry), "focus-out-event",
+				G_CALLBACK(username_nofocus_cb), dialog);
+		gtk_widget_modify_text(dialog->username_entry, GTK_STATE_NORMAL, &color);
 		g_hash_table_destroy(table);
 	}
 
-	g_signal_connect(G_OBJECT(dialog->screenname_entry), "changed",
-					 G_CALLBACK(screenname_changed_cb), dialog);
+	g_signal_connect(G_OBJECT(dialog->username_entry), "changed",
+					 G_CALLBACK(username_changed_cb), dialog);
 
 	/* Do the user split thang */
 	if (dialog->prpl_info == NULL)
@@ -547,7 +547,7 @@
 	}
 
 	if (username != NULL)
-		gtk_entry_set_text(GTK_ENTRY(dialog->screenname_entry), username);
+		gtk_entry_set_text(GTK_ENTRY(dialog->username_entry), username);
 
 	g_free(username);
 
@@ -590,7 +590,7 @@
 		gtk_widget_hide(dialog->remember_pass_check);
 	}
 
-	/* Do not let the user change the protocol/screenname while connected. */
+	/* Do not let the user change the protocol/username while connected. */
 	update_editable(NULL, dialog);
 	purple_signal_connect(purple_connections_get_handle(), "signing-on", dialog,
 					G_CALLBACK(update_editable), dialog);
@@ -1193,7 +1193,7 @@
 	PurpleAccount *account;
 
 	/* Build the username string. */
-	username = g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->screenname_entry)));
+	username = g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->username_entry)));
 
 	if (dialog->prpl_info != NULL)
 	{
@@ -1933,7 +1933,7 @@
 	gtk_tree_view_column_set_resizable(column, FALSE);
 	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 
-	/* Screen Name column */
+	/* Username column */
 	column = gtk_tree_view_column_new();
 	gtk_tree_view_column_set_title(column, _("Username"));
 	gtk_tree_view_column_set_resizable(column, TRUE);
@@ -1945,12 +1945,12 @@
 	gtk_tree_view_column_add_attribute(column, renderer,
 					   "pixbuf", COLUMN_BUDDYICON);
 
-	/* Screen Name */
+	/* Username */
 	renderer = gtk_cell_renderer_text_new();
 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
 	gtk_tree_view_column_add_attribute(column, renderer,
-					   "text", COLUMN_SCREENNAME);
-	dialog->screenname_col = column;
+					   "text", COLUMN_USERNAME);
+	dialog->username_col = column;
 
 
 	/* Protocol name */
@@ -2012,7 +2012,7 @@
 	gtk_list_store_set(store, iter,
 			COLUMN_ICON, pixbuf,
 			COLUMN_BUDDYICON, buddyicon,
-			COLUMN_SCREENNAME, purple_account_get_username(account),
+			COLUMN_USERNAME, purple_account_get_username(account),
 			COLUMN_ENABLED, purple_account_get_enabled(account, PIDGIN_UI),
 			COLUMN_PROTOCOL, purple_account_get_protocol_name(account),
 			COLUMN_DATA, account,
@@ -2186,7 +2186,7 @@
 	dialog->model = gtk_list_store_new(NUM_COLUMNS,
 					GDK_TYPE_PIXBUF,   /* COLUMN_ICON */
 					GDK_TYPE_PIXBUF,   /* COLUMN_BUDDYICON */
-					G_TYPE_STRING,     /* COLUMN_SCREENNAME */
+					G_TYPE_STRING,     /* COLUMN_USERNAME */
 					G_TYPE_BOOLEAN,    /* COLUMN_ENABLED */
 					G_TYPE_STRING,     /* COLUMN_PROTOCOL */
 					G_TYPE_POINTER     /* COLUMN_DATA */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkblist-theme-loader.c	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,279 @@
+/*
+ * 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 success = TRUE;
+	GdkColor *bgcolor, *expanded_bgcolor, *collapsed_bgcolor, *contact_color;
+	GdkColor color;
+	FontColorPair *expanded, *collapsed, *contact, *online, *away, *offline, *idle, *message, *message_nick_said, *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);
+	message_nick_said = g_new0(FontColorPair, 1);
+	status = g_new0(FontColorPair, 1);
+
+	/* <blist> */
+	if ((success = (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 ((success = (success && (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 ((success = (success && 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 ((success = (success && (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 ((success = (success && 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 ((success = (success && 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 ((success = (success && 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 ((success = (success && 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 ((success = (success && 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 ((success = (success && 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 ((success = (success && 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 ((success = (success && sub_node != NULL && (sub_sub_node = xmlnode_get_child(sub_node, "message_nick_said_text")) != NULL))) {
+		message_nick_said->font = g_strdup(xmlnode_get_attrib(sub_sub_node, "font"));
+		if(gdk_color_parse(temp = xmlnode_get_attrib(sub_sub_node, "color"), &color))
+			message_nick_said->color = g_strdup(temp);
+		else message_nick_said->color = g_strdup(DEFAULT_TEXT_COLOR);
+	}
+
+	if ((success = (success && 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 */
+	success = (success && 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,
+			"message_nick_said", message_nick_said,
+			"status", status, NULL);
+
+	xmlnode_free(root_node);
+	g_free(data);
+
+	/* malformed xml file - also frees all partial data*/
+	if (!success) {
+		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	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,784 @@
+/*
+ * 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 *message_nick_said;
+
+	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_MESSAGE_NICK_SAID,
+	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_MESSAGE_NICK_SAID:
+			g_value_set_pointer(value, pidgin_blist_theme_get_unread_message_nick_said_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_MESSAGE_NICK_SAID:
+			pidgin_blist_theme_set_unread_message_nick_said_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->message_nick_said);
+	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 has an unread message",
+			G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_MESSAGE, pspec);
+
+	pspec = g_param_spec_pointer("message_nick_said", "Message (Nick Said) Text",
+			"The text information for when a chat has an unread message that mentions your nick",
+			G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_MESSAGE_NICK_SAID, 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_unread_message_nick_said_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_nick_said;
+}
+
+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_unread_message_nick_said_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_nick_said);
+	priv->message_nick_said = 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	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,332 @@
+/**
+ * @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"
+
+/**
+ * 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 chats with unread messages
+ * that mention your nick.
+ *
+ * @returns A font and color pair.
+ */
+ FontColorPair *pidgin_blist_theme_get_unread_message_nick_said_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 unread messages.
+ *
+ * @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 a chat with unread messages
+ * that mention your nick.
+ *
+ * @param pair The new text font at color pair.
+ */
+void pidgin_blist_theme_set_unread_message_nick_said_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	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkblist.c	Wed Jan 28 10:23:37 2009 +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.h"
+#include "gtkblist-theme-loader.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) \
@@ -142,7 +149,7 @@
 #if GTK_CHECK_VERSION(2,2,1)
 static void sort_method_alphabetical(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
 static void sort_method_status(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
-static void sort_method_log(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
+static void sort_method_log_activity(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
 #endif
 static PidginBuddyList *gtkblist = NULL;
 
@@ -164,7 +171,8 @@
 static void set_urgent(void);
 
 typedef enum {
-	PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE    =  1 << 0,  /* Whether there's pending message in a conversation */
+	PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE            =  1 << 0,  /* Whether there's pending message in a conversation */
+	PIDGIN_BLIST_CHAT_HAS_PENDING_MESSAGE_WITH_NICK	 =  1 << 1,  /* Whether there's a pending message in a chat that mentions our nick */
 } PidginBlistNodeFlags;
 
 typedef struct _pidgin_blist_node {
@@ -179,17 +187,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 +326,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 +368,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 +378,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 +401,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 +443,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 +479,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 +509,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 +532,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 +548,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 +597,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 && purple_utf8_strcasecmp(arg2, ((PurpleGroup*) node)->name)) {
-				pidgin_dialogs_merge_groups((PurpleGroup*) node, arg2);
-			} else
-				purple_blist_rename_group((PurpleGroup*)node, arg2);
+			if (dest != NULL && purple_utf8_strcasecmp(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 +722,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 +745,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 +760,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 {
@@ -757,10 +785,10 @@
 
 	if (name && account) {
 		pidgin_log_show(type, name, account);
-		g_free(name);
-
 		pidgin_clear_cursor(gtkblist->window);
 	}
+
+	g_free(name);
 }
 
 static void gtk_blist_menu_showoffline_cb(GtkWidget *w, PurpleBlistNode *node)
@@ -777,7 +805,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 +817,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 +937,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
@@ -1032,7 +1070,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);
@@ -1452,7 +1490,7 @@
 	pidgin_new_item_from_stock(menu, _("Add Buddy _Pounce..."), NULL,
 			G_CALLBACK(gtk_blist_menu_bp_cb), buddy, 0, 0, NULL);
 
-	if (node->parent && node->parent->child->next && 
+	if (node->parent && node->parent->child->next &&
 	      !sub && !contact_expanded) {
 		pidgin_new_item_from_stock(menu, _("View _Log"), NULL,
 				G_CALLBACK(gtk_blist_menu_showlog_cb),
@@ -1474,7 +1512,7 @@
 	if (!contact_expanded && contact != NULL)
 		pidgin_append_blist_node_move_to_menu(menu, (PurpleBlistNode *)contact);
 
-	if (node->parent && node->parent->child->next && 
+	if (node->parent && node->parent->child->next &&
               !sub && !contact_expanded) {
 		pidgin_separator(menu);
 		pidgin_append_blist_node_privacy_menu(menu, node);
@@ -1792,7 +1830,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;
@@ -2496,7 +2535,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 {
@@ -2720,7 +2759,7 @@
  *
  *
  */
-#define STATUS_SIZE 16 
+#define STATUS_SIZE 16
 #define TOOLTIP_BORDER 12
 #define SMALL_SPACE 6
 #define LARGE_SPACE 12
@@ -2982,18 +3021,18 @@
 }
 
 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) 
+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); 
+			pango_layout_set_alignment(td->name_layout, PANGO_ALIGN_RIGHT);
 		g_free(layout_name);
-		pango_layout_set_alignment(td->layout, PANGO_ALIGN_RIGHT); 
+		pango_layout_set_alignment(td->layout, PANGO_ALIGN_RIGHT);
 	}
 }
 
@@ -3082,7 +3121,7 @@
 	GValue val;
 	struct _pidgin_blist_node *gtknode;
 
-	if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), gtkblist->tip_rect.x, gtkblist->tip_rect.y + (gtkblist->tip_rect.height/2), 
+	if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), gtkblist->tip_rect.x, gtkblist->tip_rect.y + (gtkblist->tip_rect.height/2),
 		&path, NULL, NULL, NULL))
 		return FALSE;
 	gtk_tree_model_get_iter(GTK_TREE_MODEL(gtkblist->treemodel), &iter, path);
@@ -3168,7 +3207,7 @@
 	if (y < rect.y + (rect.height / 3) ||
 	    y > rect.y + (2 * (rect.height /3)))
 		return FALSE;
-	
+
 	rect.height = rect.height / 3;
 	rect.y += rect.height;
 
@@ -3287,10 +3326,10 @@
 	{ N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL },
 	{ N_("/Tools/Buddy _Pounces"), NULL, pidgin_pounces_manager_show, 1, "<Item>", NULL },
 	{ N_("/Tools/_Certificates"), NULL, pidgin_certmgr_show, 0, "<Item>", NULL },
+	{ N_("/Tools/Custom Smile_ys"), "<CTL>Y", pidgin_smiley_manager_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SMILEY },
 	{ N_("/Tools/Plu_gins"), "<CTL>U", pidgin_plugin_dialog_show, 2, "<StockItem>", PIDGIN_STOCK_TOOLBAR_PLUGINS },
 	{ N_("/Tools/Pr_eferences"), "<CTL>P", pidgin_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES },
 	{ N_("/Tools/Pr_ivacy"), NULL, pidgin_privacy_dialog_show, 0, "<Item>", NULL },
-	{ N_("/Tools/Smile_y"), "<CTL>Y", pidgin_smiley_manager_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SMILEY },
 	{ "/Tools/sep2", NULL, NULL, 0, "<Separator>", NULL },
 	{ N_("/Tools/_File Transfers"), "<CTL>T", pidgin_xfer_dialog_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_TRANSFER },
 	{ N_("/Tools/R_oom List"), NULL, pidgin_roomlist_dialog_show, 0, "<Item>", NULL },
@@ -3815,19 +3854,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 = NULL;
+	PidginBlistTheme *theme;
 
 	if (conv != NULL) {
 		PidginBlistNode *ui = b->node.ui_data;
@@ -3841,178 +3883,171 @@
 	}
 
 	/* 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
+
+			} 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 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 :  "");
-	}
-
+	}
+
+	/* choose the colors of the text */
+	theme = pidgin_blist_get_theme();
+
+	if (purple_presence_is_idle(presence)) {
+		if (theme)
+			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)) {
+		if (theme)
+			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 : "";
+
+		if (theme)
+			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 if (purple_presence_is_available(presence)) {
+		if (theme)
+			pair = pidgin_blist_theme_get_online_text_info(theme);
+		name_color = (pair != NULL && pair->color != NULL) ? pair->color : "black";
+		name_font = (pair != NULL && pair->font != NULL) ? pair->font : "";
+
+		if (theme)
+			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 {
+		if (theme)
+			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 : "";
+
+		if (theme)
+			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);
+	g_free(statustext);
 	g_free(idletime);
-	g_free(statustext);
-	g_free(esc);
 
 	if (hidden_conv) {
 		char *tmp = text;
@@ -4062,7 +4097,7 @@
 	PurpleBlistNode *gnode, *cnode;
 
 	if (gtk_blist_visibility == GDK_VISIBILITY_FULLY_OBSCURED
-			|| !GTK_WIDGET_VISIBLE(gtkblist->window)) 
+			|| !GTK_WIDGET_VISIBLE(gtkblist->window))
 		return TRUE;
 
 	for(gnode = list->root; gnode; gnode = gnode->next) {
@@ -4331,6 +4366,10 @@
 			!(flag & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)))
 		return;
 	ui->conv.flags |= PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE;
+	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT
+			&& (flag & PURPLE_MESSAGE_NICK))
+		ui->conv.flags |= PIDGIN_BLIST_CHAT_HAS_PENDING_MESSAGE_WITH_NICK;
+
 	ui->conv.last_message = time(NULL);    /* XXX: for lack of better data */
 	pidgin_blist_update(purple_get_blist(), node);
 }
@@ -4341,7 +4380,8 @@
 	PidginBlistNode *ui = node->ui_data;
 	if (ui->conv.conv != gtkconv->active_conv)
 		return;
-	ui->conv.flags &= ~PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE;
+	ui->conv.flags &= ~(PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE |
+	                    PIDGIN_BLIST_CHAT_HAS_PENDING_MESSAGE_WITH_NICK);
 	pidgin_blist_update(purple_get_blist(), node);
 }
 
@@ -4450,7 +4490,7 @@
 #if GTK_CHECK_VERSION(2,2,1)
 	pidgin_blist_sort_method_reg("alphabetical", _("Alphabetically"), sort_method_alphabetical);
 	pidgin_blist_sort_method_reg("status", _("By status"), sort_method_status);
-	pidgin_blist_sort_method_reg("log_size", _("By log size"), sort_method_log);
+	pidgin_blist_sort_method_reg("log_size", _("By recent log activity"), sort_method_log_activity);
 #endif
 	pidgin_blist_sort_method_set(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/sort_type"));
 }
@@ -5258,11 +5298,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;
@@ -5288,6 +5461,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);
 
@@ -5320,8 +5495,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);
@@ -5464,105 +5639,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);
@@ -5955,7 +6041,7 @@
 
 	if (editing_blist)
 		return;
-	
+
 	if (PURPLE_BLIST_NODE_IS_GROUP(node))
 		gnode = node;
 	else if (PURPLE_BLIST_NODE_IS_BUDDY(node))
@@ -5989,13 +6075,19 @@
 		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);
@@ -6013,7 +6105,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,
@@ -6036,6 +6128,9 @@
 	char *mark, *esc;
 	PurpleBlistNode *selected_node = NULL;
 	GtkTreeIter iter;
+	FontColorPair *pair;
+	gchar *text_color, *text_font;
+	PidginBlistTheme *theme;
 
 	group = (PurpleGroup*)gnode;
 
@@ -6051,8 +6146,21 @@
 		           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;
@@ -6060,14 +6168,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;
@@ -6091,35 +6200,39 @@
 	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,
@@ -6132,7 +6245,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,
@@ -6190,19 +6303,41 @@
 
 		if(gtknode->contact_expanded) {
 			GdkPixbuf *status;
-			char *mark;
+			gchar *mark, *tmp;
+			const gchar *fg_color, *font;
+			GdkColor *color = NULL;
+			PidginBlistTheme *theme = pidgin_blist_get_theme();
+			FontColorPair *pair;
+			gboolean selected = (gtkblist->selected_node == cnode);
+
+			mark = g_markup_escape_text(purple_contact_get_alias(contact), -1);
+
+			theme = pidgin_blist_get_theme();
+			if (theme == NULL)
+				pair = NULL;
+			else {
+				pair = pidgin_blist_theme_get_contact_text_info(theme);
+				color = pidgin_blist_theme_get_contact_color(theme);
+			}
+
+			font = (pair == NULL || pair->font == NULL) ? "" : pair->font;
+			fg_color = (selected || pair == NULL || pair->color == NULL) ? "black" : pair->color;
+
+			tmp = g_strdup_printf("<span font_desc='%s' color='%s'>%s</span>",
+						font, fg_color, mark);
+			g_free(mark);
+			mark = tmp;
 
 			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,
@@ -6270,20 +6405,28 @@
 	if(purple_account_is_connected(chat->account)) {
 		GtkTreeIter iter;
 		GdkPixbuf *status, *avatar, *emblem, *prpl_icon;
-		char *mark;
+		const gchar *color, *font;
+		gchar *mark, *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);
+		gboolean nick_said = FALSE;
 
 		if (!insert_node(list, node, &iter))
 			return;
 
 		ui = node->ui_data;
 		conv = ui->conv.conv;
-		hidden = (conv && (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE) &&
-				pidgin_conv_is_hidden(PIDGIN_CONVERSATION(conv)));
+		if (conv && pidgin_conv_is_hidden(PIDGIN_CONVERSATION(conv))) {
+			hidden = (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE);
+			nick_said = (ui->conv.flags & PIDGIN_BLIST_CHAT_HAS_PENDING_MESSAGE_WITH_NICK);
+		}
 
 		status = pidgin_blist_get_status_icon(node,
 				 biglist ? PIDGIN_STATUS_ICON_LARGE : PIDGIN_STATUS_ICON_SMALL);
@@ -6296,14 +6439,36 @@
 			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;
-		}
+
+		theme = pidgin_blist_get_theme();
+
+		if (theme == NULL)
+			pair = NULL;
+		else if (nick_said)
+			pair = pidgin_blist_theme_get_unread_message_nick_said_text_info(theme);
+		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) ? "" : pair->font;
+		if (selected || pair == NULL || pair->color == NULL)
+			/* nick_said color is the same as gtkconv:tab-label-attention */
+			color = (nick_said ? "#006aff" : "black");
+		else
+			color = 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,
 				STATUS_ICON_VISIBLE_COLUMN, TRUE,
@@ -6314,6 +6479,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);
 
@@ -6326,6 +6492,7 @@
 			g_object_unref(avatar);
 		if(prpl_icon)
 			g_object_unref(prpl_icon);
+
 	} else {
 		pidgin_blist_hide_node(list, node, TRUE);
 	}
@@ -6983,7 +7150,7 @@
 
 	data->group_combo = pidgin_text_combo_box_entry_new(group ? group->name : NULL, groups_tree());
 	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Group:"), data->sg, data->group_combo, TRUE, NULL);
-	
+
 	data->autojoin = gtk_check_button_new_with_mnemonic(_("Auto_join when account becomes online."));
 	data->persistent = gtk_check_button_new_with_mnemonic(_("_Remain in chat after window is closed."));
 	gtk_box_pack_start(GTK_BOX(vbox), data->autojoin, FALSE, FALSE, 0);
@@ -7187,6 +7354,34 @@
 			(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();
@@ -7215,6 +7410,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",
@@ -7489,11 +7687,11 @@
 	}
 }
 
-static void sort_method_log(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter)
+static void sort_method_log_activity(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter)
 {
 	GtkTreeIter more_z;
 
-	int log_size = 0, this_log_size = 0;
+	int activity_score = 0, this_log_activity_score = 0;
 	const char *buddy_name, *this_buddy_name;
 
 	if(cur && (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(gtkblist->treemodel), &groupiter) == 1)) {
@@ -7503,8 +7701,11 @@
 
 	if(PURPLE_BLIST_NODE_IS_CONTACT(node)) {
 		PurpleBlistNode *n;
-		for (n = node->child; n; n = n->next)
-			log_size += purple_log_get_total_size(PURPLE_LOG_IM, ((PurpleBuddy*)(n))->name, ((PurpleBuddy*)(n))->account);
+		PurpleBuddy *buddy;
+		for (n = node->child; n; n = n->next) {
+			buddy = (PurpleBuddy*)n;
+			activity_score += purple_log_get_activity_score(PURPLE_LOG_IM, buddy->name, buddy->account);
+		}
 		buddy_name = purple_contact_get_alias((PurpleContact*)node);
 	} else if(PURPLE_BLIST_NODE_IS_CHAT(node)) {
 		/* we don't have a reliable way of getting the log filename
@@ -7531,16 +7732,19 @@
 		GValue val;
 		PurpleBlistNode *n;
 		PurpleBlistNode *n2;
+		PurpleBuddy *buddy;
 		int cmp;
 
 		val.g_type = 0;
 		gtk_tree_model_get_value (GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &val);
 		n = g_value_get_pointer(&val);
-		this_log_size = 0;
+		this_log_activity_score = 0;
 
 		if(PURPLE_BLIST_NODE_IS_CONTACT(n)) {
-			for (n2 = n->child; n2; n2 = n2->next)
-				this_log_size += purple_log_get_total_size(PURPLE_LOG_IM, ((PurpleBuddy*)(n2))->name, ((PurpleBuddy*)(n2))->account);
+			for (n2 = n->child; n2; n2 = n2->next) {
+                        	buddy = (PurpleBuddy*)n2;
+				this_log_activity_score += purple_log_get_activity_score(PURPLE_LOG_IM, buddy->name, buddy->account);
+			}
 			this_buddy_name = purple_contact_get_alias((PurpleContact*)n);
 		} else {
 			this_buddy_name = NULL;
@@ -7548,8 +7752,8 @@
 
 		cmp = purple_utf8_strcasecmp(buddy_name, this_buddy_name);
 
-		if (!PURPLE_BLIST_NODE_IS_CONTACT(n) || log_size > this_log_size ||
-				((log_size == this_log_size) &&
+		if (!PURPLE_BLIST_NODE_IS_CONTACT(n) || activity_score > this_log_activity_score ||
+				((activity_score == this_log_activity_score) &&
 				 (cmp < 0 || (cmp == 0 && node < n)))) {
 			if (cur != NULL) {
 				gtk_tree_store_move_before(gtkblist->treemodel, cur, &more_z);
--- a/pidgin/gtkblist.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkblist.h	Wed Jan 28 10:23:37 2009 +0000
@@ -59,6 +59,7 @@
 
 #include "pidgin.h"
 #include "blist.h"
+#include "gtkblist-theme.h"
 
 /**************************************************************************
  * @name Structures
@@ -250,6 +251,23 @@
  */
 void pidgin_blist_add_alert(GtkWidget *widget);
 
+/**
+ * Sets the current theme for Pidgin to use
+ *
+ * @param theme	the new theme to use
+ *
+ * @since 2.6.0
+ */
+void pidgin_blist_set_theme(PidginBlistTheme *theme);
+
+/**
+ * Gets Pidgin's current buddy list theme
+ *
+ * @returns	the current theme
+ *
+ * @since 2.6.0
+ */
+PidginBlistTheme *pidgin_blist_get_theme(void);
 
 /**************************************************************************
  * @name GTK+ Buddy List sorting functions
@@ -381,7 +399,7 @@
  *
  * @param buddy The buddy to return markup from
  * @param selected  Whether this buddy is selected. If TRUE, the markup will not change the color.
- * @param aliased  TRUE to return the appropriate alias of this buddy, FALSE to return its screenname and status information
+ * @param aliased  TRUE to return the appropriate alias of this buddy, FALSE to return its username and status information
  * @return The markup for this buddy
  *
  * @since 2.1.0
--- a/pidgin/gtkcellrendererexpander.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkcellrendererexpander.c	Wed Jan 28 10:23:37 2009 +0000
@@ -18,14 +18,14 @@
  * 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
  *
  */
 
-/* This is taken largely from GtkCellRenderer[Text|Pixbuf|Toggle] by 
+/* This is taken largely from GtkCellRenderer[Text|Pixbuf|Toggle] by
  * Jonathon Blandford <jrb@redhat.com> for RedHat, Inc.
  */
 
@@ -74,14 +74,14 @@
 	PROP_0,
 	PROP_IS_EXPANDER
 };
-     
+
 static gpointer parent_class;
 /* static guint expander_cell_renderer_signals [LAST_SIGNAL]; */
 
 GType  pidgin_cell_renderer_expander_get_type (void)
 {
 	static GType cell_expander_type = 0;
-	
+
 	if (!cell_expander_type)
 		{
 			static const GTypeInfo cell_expander_info =
@@ -97,13 +97,13 @@
 					(GInstanceInitFunc) pidgin_cell_renderer_expander_init,
 					NULL		/* value_table */
 				};
-			
+
 			cell_expander_type =
 				g_type_register_static (GTK_TYPE_CELL_RENDERER,
 										"PidginCellRendererExpander",
 										&cell_expander_info, 0);
 		}
-	
+
 	return cell_expander_type;
 }
 
@@ -118,17 +118,17 @@
 {
 	GObjectClass *object_class = G_OBJECT_CLASS(class);
 	GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(class);
-	
+
 	parent_class = g_type_class_peek_parent (class);
 	object_class->finalize = pidgin_cell_renderer_expander_finalize;
 
 	object_class->get_property = pidgin_cell_renderer_expander_get_property;
 	object_class->set_property = pidgin_cell_renderer_expander_set_property;
-	
+
 	cell_class->get_size = pidgin_cell_renderer_expander_get_size;
 	cell_class->render   = pidgin_cell_renderer_expander_render;
 	cell_class->activate = pidgin_cell_renderer_expander_activate;
-	
+
 	g_object_class_install_property (object_class,
 					 PROP_IS_EXPANDER,
 					 g_param_spec_boolean ("expander-visible",
@@ -162,7 +162,7 @@
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, psec);
 			break;
-			
+
 		}
 }
 
@@ -199,19 +199,19 @@
 {
 	gint calc_width;
 	gint calc_height;
-	gint expander_size; 
-	
+	gint expander_size;
+
 	gtk_widget_style_get(widget, "expander-size", &expander_size, NULL);
-	
+
 	calc_width = (gint) cell->xpad * 2 + expander_size;
 	calc_height = (gint) cell->ypad * 2 + expander_size;
-	
+
 	if (width)
 		*width = calc_width;
-	
+
 	if (height)
 		*height = calc_height;
-	
+
 	if (cell_area)
 		{
 			if (x_offset)
@@ -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;
 
@@ -246,7 +246,7 @@
 
 	width = cell_area->width;
 	height = cell_area->height;
-	
+
 #if GTK_CHECK_VERSION(2,6,0)
 	if (!cell->sensitive)
 		state = GTK_STATE_INSENSITIVE;
@@ -270,8 +270,11 @@
 			    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)
-		gtk_paint_hline (widget->style, window, state, NULL, widget, NULL, 0, 
+
+	/* 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/gtkcellrendererexpander.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkcellrendererexpander.h	Wed Jan 28 10:23:37 2009 +0000
@@ -12,7 +12,7 @@
  * 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
--- a/pidgin/gtkcellrendererprogress.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkcellrendererprogress.c	Wed Jan 28 10:23:37 2009 +0000
@@ -18,14 +18,14 @@
  * 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
  *
  */
 
-/* This is taken largely from GtkCellRenderer[Text|Pixbuf|Toggle] by 
+/* This is taken largely from GtkCellRenderer[Text|Pixbuf|Toggle] by
  * Jonathon Blandford <jrb@redhat.com> for RedHat, Inc.
  */
 
@@ -76,14 +76,14 @@
 	PROP_TEXT,
 	PROP_SHOW_TEXT
 };
-     
+
 static gpointer parent_class;
 /* static guint progress_cell_renderer_signals [LAST_SIGNAL]; */
 
 GType  pidgin_cell_renderer_progress_get_type (void)
 {
 	static GType cell_progress_type = 0;
-	
+
 	if (!cell_progress_type)
 		{
 			static const GTypeInfo cell_progress_info =
@@ -99,13 +99,13 @@
 					(GInstanceInitFunc) pidgin_cell_renderer_progress_init,
 					NULL		/* value_table */
 				};
-			
+
 			cell_progress_type =
 				g_type_register_static (GTK_TYPE_CELL_RENDERER,
 										"PidginCellRendererProgress",
 										&cell_progress_info, 0);
 		}
-	
+
 	return cell_progress_type;
 }
 
@@ -120,16 +120,16 @@
 {
 	GObjectClass *object_class = G_OBJECT_CLASS(class);
 	GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(class);
-	
+
 	parent_class = g_type_class_peek_parent (class);
 	object_class->finalize = pidgin_cell_renderer_progress_finalize;
 
 	object_class->get_property = pidgin_cell_renderer_progress_get_property;
 	object_class->set_property = pidgin_cell_renderer_progress_set_property;
-	
+
 	cell_class->get_size = pidgin_cell_renderer_progress_get_size;
 	cell_class->render   = pidgin_cell_renderer_progress_render;
-	
+
 	g_object_class_install_property (object_class,
 					 PROP_PERCENTAGE,
 					 g_param_spec_double ("percentage",
@@ -228,16 +228,16 @@
 {
 	gint calc_width;
 	gint calc_height;
-	
+
 	calc_width = (gint) cell->xpad * 2 + 50;
 	calc_height = (gint) cell->ypad * 2 + 12;
-	
+
 	if (width)
 		*width = calc_width;
-	
+
 	if (height)
 		*height = calc_height;
-	
+
 	if (cell_area)
 		{
 			if (x_offset)
@@ -263,13 +263,13 @@
 					       guint            flags)
 {
 	PidginCellRendererProgress *cellprogress = (PidginCellRendererProgress *) cell;
-	
+
 	gint width, height;
 	GtkStateType state;
 
 	width = cell_area->width;
 	height = cell_area->height;
-	
+
 	if (GTK_WIDGET_HAS_FOCUS (widget))
 		state = GTK_STATE_ACTIVE;
 	else
@@ -280,7 +280,7 @@
 
 	gtk_paint_box (widget->style,
 		       window,
-		       GTK_STATE_NORMAL, GTK_SHADOW_IN, 
+		       GTK_STATE_NORMAL, GTK_SHADOW_IN,
 		       NULL, widget, "trough",
 		       cell_area->x + cell->xpad,
 		       cell_area->y + cell->ypad,
--- a/pidgin/gtkcellrendererprogress.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkcellrendererprogress.h	Wed Jan 28 10:23:37 2009 +0000
@@ -12,7 +12,7 @@
  * 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
--- a/pidgin/gtkcellview.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkcellview.c	Wed Jan 28 10:23:37 2009 +0000
@@ -463,14 +463,14 @@
   area = widget->allocation;
 
   /* we draw on our very own window, initialize x and y to zero */
-  area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0); 
+  area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0);
   area.y = widget->allocation.y;
 
   if (GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT)
     state = GTK_CELL_RENDERER_PRELIT;
   else
     state = 0;
-      
+
   /* PACK_START */
   for (i = cellview->priv->cell_list; i; i = i->next)
     {
@@ -483,7 +483,7 @@
         continue;
 
       area.width = info->real_width;
-      if (rtl)                                             
+      if (rtl)
          area.x -= area.width;
 
       gtk_cell_renderer_render (info->cell,
@@ -492,11 +492,11 @@
                                 /* FIXME! */
                                 &area, &area, &event->area, state);
 
-      if (!rtl)                                           
+      if (!rtl)
          area.x += info->real_width;
     }
 
-   area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width);  
+   area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width);
 
   /* PACK_END */
   for (i = cellview->priv->cell_list; i; i = i->next)
@@ -511,7 +511,7 @@
 
       area.width = info->real_width;
       if (!rtl)
-         area.x -= area.width;   
+         area.x -= area.width;
 
       gtk_cell_renderer_render (info->cell,
                                 widget->window,
@@ -550,7 +550,7 @@
   GtkTreePath *path;
 
   g_return_if_fail (cellview->priv->displayed_row != NULL);
-  
+
   path = gtk_tree_row_reference_get_path (cellview->priv->displayed_row);
   gtk_tree_model_get_iter (cellview->priv->model, &iter, path);
   gtk_tree_path_free (path);
@@ -666,7 +666,7 @@
       gtk_cell_view_cell_layout_clear_attributes (layout, info->cell);
       g_object_unref (G_OBJECT (info->cell));
       g_free (info);
-      cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, 
+      cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list,
 						      cellview->priv->cell_list);
     }
 }
@@ -719,7 +719,7 @@
 	  g_free (list->data);
 	  list = list->next->next;
 	}
-      
+
       g_slist_free (info->attributes);
       info->attributes = NULL;
     }
@@ -905,7 +905,7 @@
  * gtk_cell_view_set_displayed_row:
  * @cell_view: a #GtkCellView
  * @path: a #GtkTreePath or %NULL to unset.
- * 
+ *
  * Sets the row of the model that is currently displayed
  * by the #GtkCellView. If the path is unset, then the
  * contents of the cellview "stick" at their last value;
--- a/pidgin/gtkconv.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkconv.c	Wed Jan 28 10:23:37 2009 +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;
@@ -1395,7 +1395,7 @@
 
 	if (logging == purple_conversation_is_logging(conv))
 		return;
-	
+
 	node = get_conversation_blist_node(conv);
 
 	if (logging)
@@ -1835,7 +1835,7 @@
 	gtk_tree_selection_select_path(GTK_TREE_SELECTION(
 			gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkchat->list))), path);
 	gtk_tree_view_set_cursor(GTK_TREE_VIEW(gtkchat->list),
-							 path, NULL, FALSE); 
+							 path, NULL, FALSE);
 	gtk_widget_grab_focus(GTK_WIDGET(gtkchat->list));
 
 	gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
@@ -1867,7 +1867,7 @@
 	GtkTreeIter iter;
 	GtkTreeModel *model;
 	gchar *who;
-	
+
 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
 
 	gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
@@ -2058,7 +2058,7 @@
 	gtkconv  = (PidginConversation *)data;
 	conv     = gtkconv->active_conv;
 	win      = gtkconv->win;
-	
+
 	if (conv_keypress_common(gtkconv, event))
 		return TRUE;
 
@@ -2516,7 +2516,7 @@
 			if (ops && ops->update)
 				ops->update(NULL, (PurpleBlistNode*)b);
 
-			/* XXX Seanegan: We really need a util function to return a pixbuf for a Presence to avoid all this switching */	
+			/* XXX Seanegan: We really need a util function to return a pixbuf for a Presence to avoid all this switching */
 			if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AWAY))
 				status = pidgin_create_status_icon(PURPLE_STATUS_AWAY, parent, icon_size);
 			else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_EXTENDED_AWAY))
@@ -2542,7 +2542,7 @@
 			status = gtk_widget_render_icon (parent, PIDGIN_STOCK_STATUS_CHAT,
 					size, "GtkWidget");
 		}
-	}	
+	}
 	return status;
 }
 
@@ -2585,11 +2585,11 @@
 	gtk_image_set_from_pixbuf(GTK_IMAGE(gtkconv->icon), status);
 	gtk_image_set_from_pixbuf(GTK_IMAGE(gtkconv->menu_icon), status);
 
-	gtk_list_store_set(GTK_LIST_STORE(gtkconv->infopane_model), 
+	gtk_list_store_set(GTK_LIST_STORE(gtkconv->infopane_model),
 			&(gtkconv->infopane_iter),
 			CONV_ICON_COLUMN, infopane_status, -1);
 
-	gtk_list_store_set(GTK_LIST_STORE(gtkconv->infopane_model), 
+	gtk_list_store_set(GTK_LIST_STORE(gtkconv->infopane_model),
 			&(gtkconv->infopane_iter),
 			CONV_EMBLEM_COLUMN, emblem, -1);
 	if (emblem)
@@ -3850,7 +3850,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)
 				{
@@ -4799,7 +4799,7 @@
 
 	gtkconv->infopane = gtk_cell_view_new();
 	gtkconv->infopane_model = gtk_list_store_new(CONV_NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF);
-	gtk_cell_view_set_model(GTK_CELL_VIEW(gtkconv->infopane), 
+	gtk_cell_view_set_model(GTK_CELL_VIEW(gtkconv->infopane),
 				GTK_TREE_MODEL(gtkconv->infopane_model));
 	g_object_unref(gtkconv->infopane_model);
 	gtk_list_store_append(gtkconv->infopane_model, &(gtkconv->infopane_iter));
@@ -5033,9 +5033,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;
@@ -5043,8 +5043,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)
@@ -5494,7 +5495,7 @@
 	gtkconv->newday = mktime(tm);
 }
 
-/* Detect string direction and encapsulate the string in RLE/LRE/PDF unicode characters 
+/* Detect string direction and encapsulate the string in RLE/LRE/PDF unicode characters
    str - pointer to string (string is re-allocated and the pointer updated) */
 static void
 str_embed_direction_chars(char **str)
@@ -5531,14 +5532,14 @@
 }
 
 /* Returns true if the given HTML contains RTL text */
-static gboolean 
+static gboolean
 html_is_rtl(const char *html)
 {
 	GData *attributes;
 	const gchar *start, *end;
 	gboolean res = FALSE;
 
-	if (purple_markup_find_tag("span", html, &start, &end, &attributes)) 
+	if (purple_markup_find_tag("span", html, &start, &end, &attributes))
 	{
 		/* tmp is a member of attributes and is free with g_datalist_clear call */
 		const char *tmp = g_datalist_get_data(&attributes, "dir");
@@ -6462,10 +6463,10 @@
 			PurpleBuddy *buddy = purple_find_buddy(conv->account, conv->name);
 			window_icon =
 				gdk_pixbuf_animation_get_static_image(gtkconv->u.im->anim);
-		
+
 			if (buddy &&  !PURPLE_BUDDY_IS_ONLINE(buddy))
 				gdk_pixbuf_saturate_and_pixelate(window_icon, window_icon, 0.0, FALSE);
-			
+
 			g_object_ref(window_icon);
 			l = g_list_append(l, window_icon);
 		} else {
@@ -6658,7 +6659,7 @@
 			pango_attr_list_unref(list);
 		} else
 			gtk_label_set_attributes(GTK_LABEL(gtkconv->tab_label), NULL);
-		
+
 		if (pidgin_conv_window_is_active_conversation(conv))
 			update_typing_icon(gtkconv);
 
@@ -7230,7 +7231,7 @@
 		PurpleConversation *conv = l->data;
 		if (!PIDGIN_CONVERSATION(conv))
 			continue;
-		if (GPOINTER_TO_INT(value)) 
+		if (GPOINTER_TO_INT(value))
 			gtk_widget_show(PIDGIN_CONVERSATION(conv)->infopane_hbox);
 		else
 			gtk_widget_hide(PIDGIN_CONVERSATION(conv)->infopane_hbox);
@@ -7640,7 +7641,7 @@
 	list = purple_conversation_get_message_history(conv);
 	if (list) {
 		switch (purple_conversation_get_type(conv)) {
-			case PURPLE_CONV_TYPE_IM: 
+			case PURPLE_CONV_TYPE_IM:
 			{
 				GList *convs;
 				list = g_list_copy(list);
@@ -8406,7 +8407,7 @@
 								    G_CALLBACK(notebook_leave_cb), gtkconv->win);
 		return FALSE;
 	}
-	
+
 	if (e->button == 3) {
 		/* Right click was pressed. Popup the context menu. */
 		GtkWidget *menu = gtk_menu_new(), *sub;
@@ -8432,7 +8433,7 @@
 	}
 	return FALSE;
 }
- 
+
 static gboolean
 notebook_press_cb(GtkWidget *widget, GdkEventButton *e, PidginWindow *win)
 {
@@ -9012,7 +9013,7 @@
 
 static gboolean gtk_conv_configure_cb(GtkWidget *w, GdkEventConfigure *event, gpointer data) {
 	int x, y;
-	
+
 	if (GTK_WIDGET_VISIBLE(w))
 		gtk_window_get_position(GTK_WINDOW(w), &x, &y);
 	else
@@ -9022,7 +9023,7 @@
 	* when the window is being maximized */
 	if (gdk_window_get_state(w->window) & GDK_WINDOW_STATE_MAXIMIZED)
 		return FALSE;
-	
+
 	/* don't save off-screen positioning */
 	if (x + event->width < 0 ||
 	    y + event->height < 0 ||
@@ -9038,7 +9039,7 @@
 
 	/* continue to handle event normally */
 	return FALSE;
-						
+
 }
 
 static void
@@ -9119,7 +9120,7 @@
 	/* Intercept keystrokes from the menu items */
 	g_signal_connect(G_OBJECT(win->window), "key_press_event",
 					 G_CALLBACK(window_keypress_cb), win);
-	
+
 
 	/* Create the notebook. */
 	win->notebook = gtk_notebook_new();
@@ -9281,7 +9282,7 @@
 	win->gtkconvs = g_list_append(win->gtkconvs, gtkconv);
 	gtkconv->win = win;
 
-	if (win->gtkconvs && win->gtkconvs->next && win->gtkconvs->next->next == NULL) 
+	if (win->gtkconvs && win->gtkconvs->next && win->gtkconvs->next->next == NULL)
 		pidgin_conv_tab_pack(win, ((PidginConversation*)win->gtkconvs->data));
 
 
@@ -9440,11 +9441,11 @@
 		gtk_notebook_set_tab_label(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont, ebox);
 	}
 
-	gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont, 
-					   !tabs_side && !angle, 
+	gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont,
+					   !tabs_side && !angle,
 					   TRUE, GTK_PACK_START);
 
-	if (pidgin_conv_window_get_gtkconv_count(win) == 1) 
+	if (pidgin_conv_window_get_gtkconv_count(win) == 1)
 		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook),
 					   purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/tabs") &&
                                            (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons") ||
@@ -9655,7 +9656,7 @@
 	if (win == NULL) {
 		win = pidgin_conv_window_new();
 
-		g_signal_connect(G_OBJECT(win->window), "configure_event", 
+		g_signal_connect(G_OBJECT(win->window), "configure_event",
 				G_CALLBACK(gtk_conv_configure_cb), NULL);
 
 		pidgin_conv_window_add_gtkconv(win, conv);
@@ -9670,7 +9671,7 @@
 conv_placement_last_created_win_type_configured_cb(GtkWidget *w,
 		GdkEventConfigure *event, PidginConversation *conv)
 {
-	int x, y;	
+	int x, y;
 	PurpleConversationType type = purple_conversation_get_type(conv->active_conv);
 	GList *all;
 
@@ -9683,7 +9684,7 @@
 	* when the window is being maximized */
 	if (gdk_window_get_state(w->window) & GDK_WINDOW_STATE_MAXIMIZED)
 		return FALSE;
-	
+
 	/* don't save off-screen positioning */
 	if (x + event->width < 0 ||
 	    y + event->height < 0 ||
@@ -9737,11 +9738,11 @@
 				purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/width"),
 				purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/height"));
 		}
-				
+
 		pidgin_conv_window_add_gtkconv(win, conv);
 		pidgin_conv_window_show(win);
 
-		g_signal_connect(G_OBJECT(win->window), "configure_event", 
+		g_signal_connect(G_OBJECT(win->window), "configure_event",
 				G_CALLBACK(conv_placement_last_created_win_type_configured_cb), conv);
 	} else
 		pidgin_conv_window_add_gtkconv(win, conv);
@@ -9755,7 +9756,7 @@
 
 	win = pidgin_conv_window_new();
 
-	g_signal_connect(G_OBJECT(win->window), "configure_event", 
+	g_signal_connect(G_OBJECT(win->window), "configure_event",
 			G_CALLBACK(gtk_conv_configure_cb), NULL);
 
 	pidgin_conv_window_add_gtkconv(win, conv);
--- a/pidgin/gtkdebug.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkdebug.c	Wed Jan 28 10:23:37 2009 +0000
@@ -769,7 +769,7 @@
 		win->filter =
 			gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
 									   GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
-									   NULL, _("Filter"), _("Filter"), 
+									   NULL, _("Filter"), _("Filter"),
 									   NULL, NULL,
 									   G_CALLBACK(regex_filter_toggled_cb),
 									   win);
@@ -821,7 +821,7 @@
 		                           GTK_TOOLBAR_CHILD_WIDGET, gtk_label_new(_("Level ")),
 		                           NULL, _("Select the debug filter level."),
 		                           NULL, NULL, NULL, NULL);
-		
+
 		win->filterlevel = gtk_combo_box_new_text();
 		gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
 		                           GTK_TOOLBAR_CHILD_WIDGET, win->filterlevel,
--- a/pidgin/gtkdialogs.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkdialogs.c	Wed Jan 28 10:23:37 2009 +0000
@@ -349,7 +349,7 @@
 }
 
 #if 0
-/* This function puts the version number onto the pixmap we use in the 'about' 
+/* This function puts the version number onto the pixmap we use in the 'about'
  * screen in Pidgin. */
 static void
 pidgin_logo_versionize(GdkPixbuf **original, GtkWidget *widget) {
@@ -487,7 +487,7 @@
 						   _("Retired Crazy Patch Writers"));
 	add_developers(str, retired_patch_writers);
 	g_string_append(str, "<BR/>");
-			
+
 	/* Current Translators */
 	g_string_append_printf(str, "<FONT SIZE=\"4\">%s:</FONT><BR/>",
 						   _("Current Translators"));
@@ -1061,8 +1061,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;
@@ -1116,7 +1116,7 @@
 	ggp = g_new(struct _PidginGroupMergeObject, 1);
 	ggp->parent = source;
 	ggp->new_name = g_strdup(new_name);
-	
+
 	purple_request_action(source, NULL, _("Merge Groups"), text, 0,
 			NULL, NULL, NULL,
 			ggp, 2,
--- a/pidgin/gtkdnd-hints.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkdnd-hints.c	Wed Jan 28 10:23:37 2009 +0000
@@ -46,7 +46,7 @@
 /**
  * Info about each hint widget. See DndHintWindowId enum.
  */
-static HintWindowInfo hint_windows[] = { 
+static HintWindowInfo hint_windows[] = {
 	{ NULL, "arrow-up.xpm",   -13/2,     0 },
 	{ NULL, "arrow-down.xpm", -13/2,   -16 },
 	{ NULL, "arrow-left.xpm",     0, -13/2 },
@@ -139,7 +139,7 @@
 		dnd_hints_hide(i);
 }
 
-void 
+void
 dnd_hints_hide(DndHintWindowId i)
 {
 	GtkWidget *w = hint_windows[i].widget;
@@ -148,7 +148,7 @@
 		gtk_widget_hide(w);
 }
 
-void 
+void
 dnd_hints_show(DndHintWindowId id, gint x, gint y)
 {
 	GtkWidget *w;
@@ -165,7 +165,7 @@
 	}
 }
 
-void 
+void
 dnd_hints_show_relative(DndHintWindowId id, GtkWidget *widget,
 						DndHintPosition horiz, DndHintPosition vert)
 {
--- a/pidgin/gtkdocklet-x11.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkdocklet-x11.c	Wed Jan 28 10:23:37 2009 +0000
@@ -5,7 +5,7 @@
  * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
  * Inspired by a similar plugin by:
  *  John (J5) Palmieri <johnp@martianrock.com>
- * 
+ *
  * 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
@@ -15,7 +15,7 @@
  * 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
@@ -59,7 +59,7 @@
 docklet_x11_embedded_cb(GtkWidget *widget, void *data)
 {
 	purple_debug(PURPLE_DEBUG_INFO, "docklet", "embedded\n");
-	
+
 	g_source_remove(embed_timeout);
 	embed_timeout = 0;
 	pidgin_docklet_embedded();
@@ -211,9 +211,9 @@
 
 	if (embed_timeout)
 		g_source_remove(embed_timeout);
-	
+
 	pidgin_docklet_remove();
-	
+
 	g_signal_handlers_disconnect_by_func(G_OBJECT(docklet), G_CALLBACK(docklet_x11_destroyed_cb), NULL);
 	gtk_widget_destroy(GTK_WIDGET(docklet));
 
@@ -239,7 +239,7 @@
 	 */
 	purple_debug_info("docklet", "failed to embed within timeout\n");
 	pidgin_docklet_remove();
-	
+
 	return FALSE;
 }
 
--- a/pidgin/gtkdocklet.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkdocklet.h	Wed Jan 28 10:23:37 2009 +0000
@@ -1,11 +1,11 @@
-/* 
+/*
  * System tray icon (aka docklet) plugin for Purple
- * 
+ *
  * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
  * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
  * Inspired by a similar plugin by:
  *  John (J5) Palmieri <johnp@martianrock.com>
- * 
+ *
  * 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
@@ -15,7 +15,7 @@
  * 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
--- a/pidgin/gtkexpander.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkexpander.c	Wed Jan 28 10:23:37 2009 +0000
@@ -63,7 +63,7 @@
 
   guint             expanded : 1;
   guint             use_underline : 1;
-  guint             use_markup : 1; 
+  guint             use_markup : 1;
   guint             button_down : 1;
   guint             prelight : 1;
 };
@@ -129,7 +129,7 @@
 gtk_expander_get_type (void)
 {
   static GType expander_type = 0;
-  
+
   if (!expander_type)
     {
       static const GTypeInfo expander_info =
@@ -144,12 +144,12 @@
 	0,		/* n_preallocs */
 	(GInstanceInitFunc) gtk_expander_init,
       };
-      
+
       expander_type = g_type_register_static (GTK_TYPE_BIN,
 					      "GtkExpander",
 					      &expander_info, 0);
     }
-  
+
   return expander_type;
 }
 
@@ -314,7 +314,7 @@
 			   GParamSpec   *pspec)
 {
   GtkExpander *expander = GTK_EXPANDER (object);
-                                                                                                             
+
   switch (prop_id)
     {
     case PROP_EXPANDED:
@@ -382,7 +382,7 @@
 gtk_expander_destroy (GtkObject *object)
 {
   GtkExpanderPrivate *priv = GTK_EXPANDER (object)->priv;
-  
+
   if (priv->animation_timeout)
     {
       g_source_remove (priv->animation_timeout);
@@ -407,7 +407,7 @@
   border_width = GTK_CONTAINER (widget)->border_width;
 
   get_expander_bounds (GTK_EXPANDER (widget), &expander_rect);
-  
+
   attributes.window_type = GDK_WINDOW_CHILD;
   attributes.x = widget->allocation.x + border_width;
   attributes.y = expander_rect.y;
@@ -831,7 +831,7 @@
 			NULL);
 
   ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-  
+
   x = widget->allocation.x + border_width;
   y = widget->allocation.y + border_width;
 
@@ -853,7 +853,7 @@
       width += expander_size + 2 * expander_spacing;
       height = MAX (height, expander_size + 2 * expander_spacing);
     }
-      
+
   width  += 2 * focus_pad + 2 * focus_width;
   height += 2 * focus_pad + 2 * focus_width;
 
@@ -1115,16 +1115,16 @@
 		    GtkDirectionType  direction)
 {
   GtkExpander *expander = GTK_EXPANDER (widget);
-  
+
   if (!focus_current_site (expander, direction))
     {
       GtkWidget *old_focus_child;
       gboolean widget_is_focus;
       FocusSite site = FOCUS_NONE;
-      
+
       widget_is_focus = gtk_widget_is_focus (widget);
       old_focus_child = GTK_CONTAINER (widget)->focus_child;
-      
+
       if (old_focus_child && old_focus_child == expander->priv->label_widget)
 	site = FOCUS_LABEL;
       else if (old_focus_child)
@@ -1192,9 +1192,9 @@
 /**
  * gtk_expander_new:
  * @label: the text of the label
- * 
+ *
  * Creates a new expander using @label as the text of the label.
- * 
+ *
  * Return value: a new #GtkExpander widget.
  *
  * Since: 2.4
@@ -1209,14 +1209,14 @@
  * gtk_expander_new_with_mnemonic:
  * @label: the text of the label with an underscore in front of the
  *         mnemonic character
- * 
+ *
  * Creates a new expander using @label as the text of the label.
  * If characters in @label are preceded by an underscore, they are underlined.
- * If you need a literal underscore character in a label, use '__' (two 
- * underscores). The first underlined character represents a keyboard 
+ * If you need a literal underscore character in a label, use '__' (two
+ * underscores). The first underlined character represents a keyboard
  * accelerator called a mnemonic.
  * Pressing Alt and that key activates the button.
- * 
+ *
  * Return value: a new #GtkExpander widget.
  *
  * Since: 2.4
@@ -1328,7 +1328,7 @@
 	{
 	  gtk_expander_start_animation (expander);
 	}
-      else 
+      else
 	{
 	  priv->expander_style = expanded ? GTK_EXPANDER_EXPANDED :
 					    GTK_EXPANDER_COLLAPSED;
@@ -1643,7 +1643,7 @@
  * gtk_expander_set_label_widget().
  *
  * Return value: the label widget, or %NULL if there is none.
- * 
+ *
  * Since: 2.4
  **/
 GtkWidget *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkicon-theme-loader.c	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,111 @@
+/*
+ * 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-theme-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	Wed Jan 28 10:23:37 2009 +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	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,142 @@
+/*
+ * 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	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,93 @@
+/**
+ * @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/gtkimhtml.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkimhtml.c	Wed Jan 28 10:23:37 2009 +0000
@@ -88,6 +88,22 @@
 	GtkTextMark *mark;
 };
 
+struct _GtkIMHtmlLink
+{
+	GtkIMHtml *imhtml;
+	gchar *url;
+	GtkTextTag *tag;
+};
+
+typedef struct _GtkIMHtmlProtocol
+{
+	char *name;
+	int length;
+
+	gboolean (*activate)(GtkIMHtml *imhtml, GtkIMHtmlLink *link);
+	gboolean (*context_menu)(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu);
+} GtkIMHtmlProtocol;
+
 static gboolean
 gtk_text_view_drag_motion (GtkWidget        *widget,
                            GdkDragContext   *context,
@@ -115,6 +131,9 @@
 static void imhtml_font_grow(GtkIMHtml *imhtml);
 static void imhtml_font_shrink(GtkIMHtml *imhtml);
 static void imhtml_clear_formatting(GtkIMHtml *imhtml);
+static int gtk_imhtml_is_protocol(const char *text);
+static void gtk_imhtml_activate_tag(GtkIMHtml *imhtml, GtkTextTag *tag);
+static void gtk_imhtml_link_destroy(GtkIMHtmlLink *link);
 
 /* POINT_SIZE converts from AIM font sizes to a point size scale factor. */
 #define MAX_FONT_SIZE 7
@@ -349,7 +368,7 @@
 			g_string_free (t->values, TRUE);
 			g_free (t->children);
 		}
-		
+
 		g_free (t);
 	}
 }
@@ -819,7 +838,7 @@
 			                                      &tag_area.x,
 			                                      &tag_area.y);
 
-		
+
 			rect.height = tag_area.y + tag_area.height - rect.y
 				+ gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(widget))
 				+ gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(widget));
@@ -1106,8 +1125,8 @@
 	GtkTextIter iter;
 	GtkIMHtmlOptions flags = plaintext ? GTK_IMHTML_NO_SMILEY : (GTK_IMHTML_NO_NEWLINE | GTK_IMHTML_NO_COMMENTS);
 
-	if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL))
-		gtk_text_buffer_delete_selection(imhtml->text_buffer, TRUE, TRUE);
+	/* Delete any currently selected text */
+	gtk_text_buffer_delete_selection(imhtml->text_buffer, TRUE, TRUE);
 
 	gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, gtk_text_buffer_get_insert(imhtml->text_buffer));
 	if (!imhtml->wbfo && !plaintext)
@@ -1391,6 +1410,38 @@
 
 }
 
+static GtkIMHtmlProtocol *
+imhtml_find_protocol(const char *url, gboolean reverse)
+{
+	GtkIMHtmlClass *klass;
+	GList *iter;
+	GtkIMHtmlProtocol *proto = NULL;
+	int length = reverse ? strlen(url) : -1;
+
+	klass = g_type_class_ref(GTK_TYPE_IMHTML);
+	for (iter = klass->protocols; iter; iter = iter->next) {
+		proto = iter->data;
+		if (g_ascii_strncasecmp(url, proto->name, reverse ? MIN(length, proto->length) : proto->length) == 0) {
+			return proto;
+		}
+	}
+	return NULL;
+}
+
+static void
+imhtml_url_clicked(GtkIMHtml *imhtml, const char *url)
+{
+	GtkIMHtmlProtocol *proto = imhtml_find_protocol(url, FALSE);
+	GtkIMHtmlLink *link;
+	if (!proto)
+		return;
+	link = g_new0(GtkIMHtmlLink, 1);
+	link->imhtml = g_object_ref(imhtml);
+	link->url = g_strdup(url);
+	proto->activate(imhtml, link);   /* XXX: Do something with the return value? */
+	gtk_imhtml_link_destroy(link);
+}
+
 /* Boring GTK+ stuff */
 static void gtk_imhtml_class_init (GtkIMHtmlClass *klass)
 {
@@ -1475,6 +1526,7 @@
 	klass->toggle_format = imhtml_toggle_format;
 	klass->message_send = imhtml_message_send;
 	klass->clear_format = imhtml_clear_formatting;
+	klass->url_clicked = imhtml_url_clicked;
 	klass->undo = gtk_imhtml_undo;
 	klass->redo = gtk_imhtml_redo;
 
@@ -1688,37 +1740,14 @@
 	return imhtml_type;
 }
 
-struct url_data {
-	GObject *object;
-	gchar *url;
-	GtkTextTag *tag;
-};
-
-static void url_data_destroy(gpointer mydata)
-{
-	struct url_data *data = mydata;
-	g_object_unref(data->object);
-	g_object_unref(data->tag);
-	g_free(data->url);
-	g_free(data);
-}
-
-static void url_open(GtkWidget *w, struct url_data *data)
-{
-	if(!data) return;
-	g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url);
-	g_object_set_data(G_OBJECT(data->tag), "visited", GINT_TO_POINTER(TRUE));
-	gtk_imhtml_set_link_color(GTK_IMHTML(data->object), data->tag);
-}
-
-static void url_copy(GtkWidget *w, gchar *url) {
-	GtkClipboard *clipboard;
-
-	clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_PRIMARY);
-	gtk_clipboard_set_text(clipboard, url, -1);
-
-	clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_CLIPBOARD);
-	gtk_clipboard_set_text(clipboard, url, -1);
+static void gtk_imhtml_link_destroy(GtkIMHtmlLink *link)
+{
+	if (link->imhtml)
+		g_object_unref(link->imhtml);
+	if (link->tag)
+		g_object_unref(link->tag);
+	g_free(link->url);
+	g_free(link);
 }
 
 /* The callback for an event on a link tag. */
@@ -1734,21 +1763,16 @@
 			if (gtk_text_buffer_get_selection_bounds(
 						gtk_text_iter_get_buffer(arg2),	&start, &end))
 				return FALSE;
-
-			/* A link was clicked--we emit the "url_clicked" signal
-			 * with the URL as the argument */
-			g_object_ref(G_OBJECT(tag));
-			g_signal_emit(imhtml, signals[URL_CLICKED], 0, g_object_get_data(G_OBJECT(tag), "link_url"));
-			g_object_unref(G_OBJECT(tag));
-			g_object_set_data(G_OBJECT(tag), "visited", GINT_TO_POINTER(TRUE));
-			gtk_imhtml_set_link_color(GTK_IMHTML(imhtml), tag);
+			gtk_imhtml_activate_tag(GTK_IMHTML(imhtml), tag);
 			return FALSE;
 		} else if(event_button->button == 3) {
-			GtkWidget *img, *item, *menu;
-			struct url_data *tempdata = g_new(struct url_data, 1);
-			tempdata->object = g_object_ref(imhtml);
-			tempdata->url = g_strdup(g_object_get_data(G_OBJECT(tag), "link_url"));
-			tempdata->tag = g_object_ref(tag);
+			GList *children;
+			GtkWidget *menu;
+			GtkIMHtmlProtocol *proto;
+			GtkIMHtmlLink *link = g_new(GtkIMHtmlLink, 1);
+			link->imhtml = g_object_ref(imhtml);
+			link->url = g_strdup(g_object_get_data(G_OBJECT(tag), "link_url"));
+			link->tag = g_object_ref(tag);
 
 			/* Don't want the tooltip around if user right-clicked on link */
 			if (GTK_IMHTML(imhtml)->tip_window) {
@@ -1764,43 +1788,23 @@
 			else
 				gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor);
 			menu = gtk_menu_new();
-			g_object_set_data_full(G_OBJECT(menu), "x-imhtml-url-data", tempdata, url_data_destroy);
-
-			/* buttons and such */
-
-			if (!strncmp(tempdata->url, "mailto:", 7))
-			{
-				/* Copy Email Address */
-				img = gtk_image_new_from_stock(GTK_STOCK_COPY,
-											   GTK_ICON_SIZE_MENU);
-				item = gtk_image_menu_item_new_with_mnemonic(
-					_("_Copy Email Address"));
-				gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
-				g_signal_connect(G_OBJECT(item), "activate",
-								 G_CALLBACK(url_copy), tempdata->url + 7);
-				gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+			g_object_set_data_full(G_OBJECT(menu), "x-imhtml-url-data", link,
+					(GDestroyNotify)gtk_imhtml_link_destroy);
+
+			proto = imhtml_find_protocol(link->url, FALSE);
+
+			if (proto && proto->context_menu) {
+				proto->context_menu(GTK_IMHTML(link->imhtml), link, menu);
 			}
-			else
-			{
-				/* Open Link in Browser */
-				img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO,
-											   GTK_ICON_SIZE_MENU);
-				item = gtk_image_menu_item_new_with_mnemonic(
-					_("_Open Link in Browser"));
-				gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
-				g_signal_connect(G_OBJECT(item), "activate",
-								 G_CALLBACK(url_open), tempdata);
+
+			children = gtk_container_get_children(GTK_CONTAINER(menu));
+			if (!children) {
+				GtkWidget *item = gtk_menu_item_new_with_label(_("No actions available"));
+				gtk_widget_show(item);
+				gtk_widget_set_sensitive(item, FALSE);
 				gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-
-				/* Copy Link Location */
-				img = gtk_image_new_from_stock(GTK_STOCK_COPY,
-											   GTK_ICON_SIZE_MENU);
-				item = gtk_image_menu_item_new_with_mnemonic(
-					_("_Copy Link Location"));
-				gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
-				g_signal_connect(G_OBJECT(item), "activate",
-								 G_CALLBACK(url_copy), tempdata->url);
-				gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+			} else {
+				g_list_free(children);
 			}
 
 
@@ -1884,10 +1888,7 @@
 
 			links = g_strsplit((char *)sd->data, "\n", 0);
 			while((link = links[i]) != NULL){
-				if(purple_str_has_prefix(link, "http://") ||
-				   purple_str_has_prefix(link, "https://") ||
-				   purple_str_has_prefix(link, "ftp://"))
-				{
+				if (gtk_imhtml_is_protocol(link)) {
 					gchar *label;
 
 					if(links[i + 1])
@@ -1896,7 +1897,7 @@
 					label = links[i];
 
 					gtk_imhtml_insert_link(imhtml, mark, link, label);
-				} else if (link=='\0') {
+				} else if (*link == '\0') {
 					/* Ignore blank lines */
 				} else {
 					/* Special reasons, aka images being put in via other tag, etc. */
@@ -2067,7 +2068,7 @@
 {
 	if (smiley->imhtml) {
 		gtk_smiley_tree_remove(smiley->imhtml->default_smilies, smiley);
-		g_hash_table_foreach(smiley->imhtml->smiley_data, 
+		g_hash_table_foreach(smiley->imhtml->smiley_data,
 			gtk_imhtml_disassociate_smiley_foreach, smiley);
 		g_signal_handlers_disconnect_matched(smiley->imhtml, G_SIGNAL_MATCH_DATA,
 			0, 0, NULL, NULL, smiley);
@@ -2096,13 +2097,13 @@
 		g_signal_handlers_disconnect_matched(smiley->imhtml, G_SIGNAL_MATCH_DATA,
 			0, 0, NULL, NULL, smiley);
 	}
-	
+
 	smiley->imhtml = imhtml;
 
 	gtk_smiley_tree_insert (tree, smiley);
-	
+
 	/* connect destroy signal for the imhtml */
-	g_signal_connect(imhtml, "destroy", G_CALLBACK(gtk_imhtml_disconnect_smiley), 
+	g_signal_connect(imhtml, "destroy", G_CALLBACK(gtk_imhtml_disconnect_smiley),
 		smiley);
 }
 
@@ -2198,14 +2199,17 @@
 	return gtk_smiley_get_image(smiley);
 }
 
-#define VALID_TAG(x)	if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) {	\
-				*tag = g_strndup (string, strlen (x));		\
-				*len = strlen (x) + 1;				\
+#define VALID_TAG(x)	do { \
+			if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) {	\
+				if (tag) *tag = g_strndup (string, strlen (x));		\
+				if (len) *len = strlen (x) + 1;				\
 				return TRUE;					\
 			}							\
-			(*type)++
-
-#define VALID_OPT_TAG(x)	if (!g_ascii_strncasecmp (string, x " ", strlen (x " "))) {	\
+			if (type) (*type)++; \
+		} while (0)
+
+#define VALID_OPT_TAG(x)	do { \
+				if (!g_ascii_strncasecmp (string, x " ", strlen (x " "))) {	\
 					const gchar *c = string + strlen (x " ");	\
 					gchar e = '"';					\
 					gboolean quote = FALSE;				\
@@ -2222,12 +2226,13 @@
 						c++;					\
 					}						\
 					if (*c) {					\
-						*tag = g_strndup (string, c - string);	\
-						*len = c - string + 1;			\
+						if (tag) *tag = g_strndup (string, c - string);	\
+						if (len) *len = c - string + 1;			\
 						return TRUE;				\
 					}						\
 				}							\
-				(*type)++
+				if (type) (*type)++; \
+			} while (0)
 
 
 static gboolean
@@ -2237,8 +2242,8 @@
 		   gint        *type)
 {
 	char *close;
-	*type = 1;
-
+	if (type)
+		*type = 1;
 
 	if (!(close = strchr (string, '>')))
 		return FALSE;
@@ -2311,15 +2316,20 @@
 	if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) {
 		gchar *e = strstr (string + strlen("!--"), "-->");
 		if (e) {
-			*len = e - string + strlen ("-->");
-			*tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->"));
+			if (len)
+				*len = e - string + strlen ("-->");
+			if (tag)
+				*tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->"));
 			return TRUE;
 		}
 	}
 
-	*type = -1;
-	*len = close - string + 1;
-	*tag = g_strndup(string, *len - 1);
+	if (type)
+		*type = -1;
+	if (len)
+		*len = close - string + 1;
+	if (tag)
+		*tag = g_strndup(string, *len - 1);
 	return TRUE;
 }
 
@@ -2382,26 +2392,12 @@
 	return g_string_free(ret, FALSE);
 }
 
-static const char *accepted_protocols[] = {
-	"http://",
-	"https://",
-	"ftp://"
-};
-
-static const int accepted_protocols_size = 3;
-
 /* returns if the beginning of the text is a protocol. If it is the protocol, returns the length so
    the caller knows how long the protocol string is. */
 static int gtk_imhtml_is_protocol(const char *text)
 {
-	gint i;
-
-	for(i=0; i<accepted_protocols_size; i++){
-		if( g_ascii_strncasecmp(text, accepted_protocols[i], strlen(accepted_protocols[i])) == 0  ){
-			return strlen(accepted_protocols[i]);
-		}
-	}
-	return 0;
+	GtkIMHtmlProtocol *proto = imhtml_find_protocol(text, FALSE);
+	return proto ? proto->length : 0;
 }
 
 /*
@@ -2606,7 +2602,7 @@
 
 			count++;
 		}
-		
+
 		g_free(in_color);
 		return g_strdup_printf("#%02X%02X%02X", rgbval[0], rgbval[1], rgbval[2]);
 	}
@@ -2655,7 +2651,7 @@
 	c = text;
 	len = strlen(text);
 	ws = g_malloc(len + 1);
-	ws[0] = 0;
+	ws[0] = '\0';
 
 	gtk_text_buffer_begin_user_action(imhtml->text_buffer);
 	while (pos < len) {
@@ -3307,8 +3303,7 @@
 				ws[wpos] = '\n';
 				wpos++;
 				gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
-				ws[0] = '\0';
-				wpos = 0;
+				ws[0] = '\0'; wpos = 0;
 				/* NEW_BIT (NEW_TEXT_BIT); */
 			} else if (!br) {  /* Don't insert a space immediately after an HTML break */
 				/* A newline is defined by HTML as whitespace, which means we have to replace it with a word boundary.
@@ -3319,19 +3314,42 @@
 				ws[wpos] = ' ';
 				wpos++;
 				gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
-				ws[0] = '\0';
-				wpos = 0;
+				ws[0] = '\0'; wpos = 0;
 			}
 			c++;
 			pos++;
-		} else if ((len_protocol = gtk_imhtml_is_protocol(c)) > 0){
+		} else if ((pos == 0 || wpos == 0 || isspace(*(c - 1))) &&
+		           (len_protocol = gtk_imhtml_is_protocol(c)) > 0) {
 			br = FALSE;
-			while(len_protocol--){
-				/* Skip the next len_protocol characters, but make sure they're
-				   copied into the ws array.
-				*/
-				 ws [wpos++] = *c++;
-				 pos++;
+			if (wpos > 0) {
+				gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
+				ws[0] = '\0'; wpos = 0;
+			}
+			while (len_protocol--) {
+				/* Skip the next len_protocol characters, but
+				 * make sure they're copied into the ws array.
+				 */
+				ws [wpos++] = *c++;
+				pos++;
+			}
+			if (!imhtml->edit.link && (imhtml->format_functions & GTK_IMHTML_LINK)) {
+				while (*c && !isspace((int)*c) &&
+						(*c != '<' || !gtk_imhtml_is_tag(c + 1, NULL, NULL, NULL))) {
+					if (*c == '&' && (amp = purple_markup_unescape_entity(c, &tlen))) {
+						while (*amp)
+							ws[wpos++] = *amp++;
+						c += tlen;
+						pos += tlen;
+					} else {
+						ws [wpos++] = *c++;
+						pos++;
+					}
+				}
+				ws[wpos] = '\0';
+				gtk_imhtml_toggle_link(imhtml, ws);
+				gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
+				ws[0] = '\0'; wpos = 0;
+				gtk_imhtml_toggle_link(imhtml, NULL);
 			}
 		} else if (*c) {
 			br = FALSE;
@@ -3355,7 +3373,7 @@
 		ws[wpos++]  = 0xE2;
 		ws[wpos++]  = 0x80;
 		ws[wpos++]  = 0x8F;
-    
+
 		if (!rtl_direction)
 		{
 			/* insert LRM character to set direction */
@@ -3368,8 +3386,7 @@
 		ws[wpos]  = '\0';
 		gtk_text_buffer_insert(imhtml->text_buffer, &line_iter, ws, wpos);
 		gtk_text_buffer_get_end_iter(gtk_text_iter_get_buffer(&line_iter), iter);
-		ws[0] = '\0';
-		wpos = 0;
+		ws[0] = '\0'; wpos = 0;
 	}
 
 	while (fonts) {
@@ -4885,8 +4902,8 @@
 {
 	GtkTextIter iter;
 
-	if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL))
-		gtk_text_buffer_delete_selection(imhtml->text_buffer, TRUE, TRUE);
+	/* Delete any currently selected text */
+	gtk_text_buffer_delete_selection(imhtml->text_buffer, TRUE, TRUE);
 
 	gtk_imhtml_toggle_link(imhtml, url);
 	gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark);
@@ -4899,8 +4916,8 @@
 	GtkTextMark *mark;
 	GtkTextIter iter;
 
-	if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL))
-		gtk_text_buffer_delete_selection(imhtml->text_buffer, TRUE, TRUE);
+	/* Delete any currently selected text */
+	gtk_text_buffer_delete_selection(imhtml->text_buffer, TRUE, TRUE);
 
 	mark = gtk_text_buffer_get_insert(imhtml->text_buffer);
 
@@ -5753,3 +5770,104 @@
 	g_free(smiley);
 }
 
+gboolean gtk_imhtml_class_register_protocol(const char *name,
+		gboolean (*activate)(GtkIMHtml *imhtml, GtkIMHtmlLink *link),
+		gboolean (*context_menu)(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu))
+{
+	GtkIMHtmlClass *klass;
+	GtkIMHtmlProtocol *proto;
+
+	g_return_val_if_fail(name, FALSE);
+
+	klass = g_type_class_ref(GTK_TYPE_IMHTML);
+	g_return_val_if_fail(klass, FALSE);
+
+	if ((proto = imhtml_find_protocol(name, TRUE))) {
+		if (activate) {
+			return FALSE;
+		}
+		g_free(proto->name);
+		g_free(proto);
+		klass->protocols = g_list_remove(klass->protocols, proto);
+		return TRUE;
+	} else if (!activate) {
+		return FALSE;
+	}
+
+	proto = g_new0(GtkIMHtmlProtocol, 1);
+	proto->name = g_strdup(name);
+	proto->length = strlen(name);
+	proto->activate = activate;
+	proto->context_menu = context_menu;
+	klass->protocols = g_list_prepend(klass->protocols, proto);
+
+	return TRUE;
+}
+
+static void
+gtk_imhtml_activate_tag(GtkIMHtml *imhtml, GtkTextTag *tag)
+{
+	/* A link was clicked--we emit the "url_clicked" signal
+	 * with the URL as the argument */
+	g_object_ref(G_OBJECT(tag));
+	g_signal_emit(imhtml, signals[URL_CLICKED], 0, g_object_get_data(G_OBJECT(tag), "link_url"));
+	g_object_unref(G_OBJECT(tag));
+	g_object_set_data(G_OBJECT(tag), "visited", GINT_TO_POINTER(TRUE));
+	gtk_imhtml_set_link_color(GTK_IMHTML(imhtml), tag);
+}
+
+gboolean gtk_imhtml_link_activate(GtkIMHtmlLink *link)
+{
+	g_return_val_if_fail(link, FALSE);
+
+	if (link->tag) {
+		gtk_imhtml_activate_tag(link->imhtml, link->tag);
+	} else if (link->url) {
+		g_signal_emit(link->imhtml, signals[URL_CLICKED], 0, link->url);
+	} else
+		return FALSE;
+	return TRUE;
+}
+
+const char *gtk_imhtml_link_get_url(GtkIMHtmlLink *link)
+{
+	return link->url;
+}
+
+const GtkTextTag * gtk_imhtml_link_get_text_tag(GtkIMHtmlLink *link)
+{
+	return link->tag;
+}
+
+static gboolean return_add_newline_cb(GtkWidget *widget, gpointer data)
+{
+	GtkTextBuffer *buffer;
+	GtkTextMark *mark;
+	GtkTextIter iter;
+
+	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
+
+	/* Delete any currently selected text */
+	gtk_text_buffer_delete_selection(buffer, TRUE, TRUE);
+
+	/* Insert a newline at the current cursor position */
+	mark = gtk_text_buffer_get_insert(buffer);
+	gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
+	gtk_imhtml_insert_html_at_iter(GTK_IMHTML(widget), "\n", 0, &iter);
+
+	/*
+	 * If we just newlined ourselves past the end of the visible area
+	 * then scroll down so the cursor is in view.
+	 */
+	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(widget),
+			gtk_text_buffer_get_insert(buffer),
+			0, FALSE, 0.0, 0.0);
+
+	return TRUE;
+}
+
+void gtk_imhtml_set_return_inserts_newline(GtkIMHtml *imhtml)
+{
+	g_signal_connect(G_OBJECT(imhtml), "message_send",
+		G_CALLBACK(return_add_newline_cb), NULL);
+}
--- a/pidgin/gtkimhtml.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkimhtml.h	Wed Jan 28 10:23:37 2009 +0000
@@ -61,6 +61,11 @@
 typedef struct _GtkIMHtmlHr			GtkIMHtmlHr;
 typedef struct _GtkIMHtmlFuncs		GtkIMHtmlFuncs;
 
+/**
+ * @since 2.6.0
+ */
+typedef struct _GtkIMHtmlLink       GtkIMHtmlLink;
+
 typedef enum {
 	GTK_IMHTML_BOLD =       1 << 0,
 	GTK_IMHTML_ITALIC =     1 << 1,
@@ -156,6 +161,7 @@
 	gboolean (*message_send)(GtkIMHtml *);
 	void (*undo)(GtkIMHtml *);
 	void (*redo)(GtkIMHtml *);
+	GList *protocols; /* List of GtkIMHtmlProtocol's */
 };
 
 struct _GtkIMHtmlFontDetail {
@@ -885,6 +891,74 @@
  * @since 2.5.0
  */
 void gtk_imhtml_smiley_destroy(GtkIMHtmlSmiley *smiley);
+
+/**
+ * Register a protocol with the GtkIMHtml widget. Registering a protocol would
+ * allow certain text to be clickable.
+ *
+ * @param name      The name of the protocol (e.g. http://)
+ * @param activate  The callback to trigger when the protocol text is clicked.
+ *                  Removes any current protocol definition if @c NULL. The
+ *                  callback should return @c TRUE if the link was activated
+ *                  properly, @c FALSE otherwise.
+ * @param context_menu  The callback to trigger when the context menu is popped
+ *                      up on the protocol text. The callback should return
+ *                      @c TRUE if the request for context menu was processed
+ *                      successfully, @c FALSE otherwise.
+ *
+ * @return  @c TRUE if the protocol was successfully registered (or unregistered, when #activate is @c NULL)
+ *
+ * @since 2.6.0
+ */
+gboolean gtk_imhtml_class_register_protocol(const char *name,
+		gboolean (*activate)(GtkIMHtml *imhtml, GtkIMHtmlLink *link),
+		gboolean (*context_menu)(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu));
+
+/**
+ * Get the URL associated with a link. This should be used by the IMHtml protocol-callbacks.
+ *
+ * @param link   The GtkIMHtmlLink object sent to the callback functions
+ *
+ * @return  The URL
+ *
+ * @since 2.6.0
+ */
+const char *gtk_imhtml_link_get_url(GtkIMHtmlLink *link);
+
+/**
+ * Get the GtkTextTag object (if any) associated with a particular link.
+ *
+ * @param link   The GtkIMHtmlLink object sent to the callback functions
+ *
+ * @return  The GtkTextTag object, or @c NULL
+ *
+ * @since 2.6.0
+ */
+const GtkTextTag *gtk_imhtml_link_get_text_tag(GtkIMHtmlLink *link);
+
+/**
+ * Activates a GtkIMHtmlLink object. This triggers the 'url-clicked' signal, marks the
+ * link as visited (when possible).
+ *
+ * @param link   The GtkIMHtmlLink object sent to the callback functions
+ *
+ * @return  @c TRUE if 'url-clicked' signal was emitted, @c FALSE otherwise.
+ *
+ * @since 2.6.0
+ */
+gboolean gtk_imhtml_link_activate(GtkIMHtmlLink *link);
+
+/**
+ * By default this widget intercepts presses of the "return" key and
+ * emits the "message_send" signal instead.  If you don't want this
+ * behavior, and you want the standard GtkTextView behavior of
+ * inserting a newline into the buffer, then call this function.
+ *
+ * @param imhtml The GtkIMHtml where you want the "return" key to add
+ *        newline and not emit the "message_send" signal.
+ */
+void gtk_imhtml_set_return_inserts_newline(GtkIMHtml *imhtml);
+
 /*@}*/
 
 #ifdef __cplusplus
--- a/pidgin/gtkimhtmltoolbar.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Wed Jan 28 10:23:37 2009 +0000
@@ -680,7 +680,7 @@
 	  is custom smiley-enabled */
 	if (supports_custom && psmiley && !(smiley->flags & GTK_IMHTML_SMILEY_CUSTOM)) {
 		gchar tip[128];
-		g_snprintf(tip, sizeof(tip), 
+		g_snprintf(tip, sizeof(tip),
 			_("This smiley is disabled because a custom smiley exists for this shortcut:\n %s"),
 			face);
 		gtk_tooltips_set_tip(toolbar->tooltips, button, tip, NULL);
@@ -808,7 +808,7 @@
 			unique_smileys = g_slist_prepend(unique_smileys, smiley);
 		}
 	}
-	
+
 	/* we need to reverse the list to get the smileys in the correct order */
 	unique_smileys = g_slist_reverse(unique_smileys);
 
@@ -1413,13 +1413,13 @@
 	menuitem = gtk_menu_item_new_with_mnemonic(_("_Horizontal rule"));
 	g_signal_connect(G_OBJECT(menuitem), "activate"	, G_CALLBACK(insert_hr_cb), toolbar);
 	gtk_menu_shell_append(GTK_MENU_SHELL(insert_menu), menuitem);
-	toolbar->insert_hr = menuitem;	
+	toolbar->insert_hr = menuitem;
 
 	g_signal_connect_swapped(G_OBJECT(insert_button), "button-press-event", G_CALLBACK(gtk_widget_activate), insert_button);
 	g_signal_connect(G_OBJECT(insert_button), "activate", G_CALLBACK(pidgin_menu_clicked), insert_menu);
 	g_signal_connect(G_OBJECT(insert_menu), "deactivate", G_CALLBACK(pidgin_menu_deactivate), insert_button);
 	toolbar->sml = NULL;
-	
+
 	/* Sep */
 	sep = gtk_vseparator_new();
 	gtk_box_pack_start(GTK_BOX(box), sep, FALSE, FALSE, 0);
--- a/pidgin/gtklog.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtklog.c	Wed Jan 28 10:23:37 2009 +0000
@@ -45,7 +45,7 @@
 
 struct log_viewer_hash_t {
 	PurpleLogType type;
-	char *screenname;
+	char *buddyname;
 	PurpleAccount *account;
 	PurpleContact *contact;
 };
@@ -57,7 +57,7 @@
 	if (viewer->contact != NULL)
 		return g_direct_hash(viewer->contact);
 
-	return g_str_hash(viewer->screenname) +
+	return g_str_hash(viewer->buddyname) +
 		g_str_hash(purple_account_get_username(viewer->account));
 }
 
@@ -80,9 +80,9 @@
 			return FALSE;
 	}
 
-	normal = g_strdup(purple_normalize(a->account, a->screenname));
+	normal = g_strdup(purple_normalize(a->account, a->buddyname));
 	ret = (a->account == b->account) &&
-		!strcmp(normal, purple_normalize(b->account, b->screenname));
+		!strcmp(normal, purple_normalize(b->account, b->buddyname));
 	g_free(normal);
 
 	return ret;
@@ -209,7 +209,7 @@
 		lv = g_hash_table_lookup(log_viewers, ht);
 		g_hash_table_remove(log_viewers, ht);
 
-		g_free(ht->screenname);
+		g_free(ht->buddyname);
 		g_free(ht);
 	} else
 		syslog_viewer = NULL;
@@ -556,7 +556,7 @@
 				if (!purple_prefs_get_bool("/purple/logging/log_chats"))
 					log_preferences = _("Chats will only be logged if the \"Log all chats\" preference is enabled.");
 			}
-			g_free(ht->screenname);
+			g_free(ht->buddyname);
 			g_free(ht);
 		}
 
@@ -681,27 +681,27 @@
 	return lv;
 }
 
-void pidgin_log_show(PurpleLogType type, const char *screenname, PurpleAccount *account) {
+void pidgin_log_show(PurpleLogType type, const char *buddyname, PurpleAccount *account) {
 	struct log_viewer_hash_t *ht;
 	PidginLogViewer *lv = NULL;
-	const char *name = screenname;
+	const char *name = buddyname;
 	char *title;
 	GdkPixbuf *prpl_icon;
 
 	g_return_if_fail(account != NULL);
-	g_return_if_fail(screenname != NULL);
+	g_return_if_fail(buddyname != NULL);
 
 	ht = g_new0(struct log_viewer_hash_t, 1);
 
 	ht->type = type;
-	ht->screenname = g_strdup(screenname);
+	ht->buddyname = g_strdup(buddyname);
 	ht->account = account;
 
 	if (log_viewers == NULL) {
 		log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal);
 	} else if ((lv = g_hash_table_lookup(log_viewers, ht))) {
 		gtk_window_present(GTK_WINDOW(lv->window));
-		g_free(ht->screenname);
+		g_free(ht->buddyname);
 		g_free(ht);
 		return;
 	}
@@ -709,7 +709,7 @@
 	if (type == PURPLE_LOG_CHAT) {
 		PurpleChat *chat;
 
-		chat = purple_blist_find_chat(account, screenname);
+		chat = purple_blist_find_chat(account, buddyname);
 		if (chat != NULL)
 			name = purple_chat_get_name(chat);
 
@@ -717,7 +717,7 @@
 	} else {
 		PurpleBuddy *buddy;
 
-		buddy = purple_find_buddy(account, screenname);
+		buddy = purple_find_buddy(account, buddyname);
 		if (buddy != NULL)
 			name = purple_buddy_get_contact_alias(buddy);
 
@@ -726,9 +726,9 @@
 
 	prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM);
 
-	display_log_viewer(ht, purple_log_get_logs(type, screenname, account),
+	display_log_viewer(ht, purple_log_get_logs(type, buddyname, account),
 			title, gtk_image_new_from_pixbuf(prpl_icon),
-			purple_log_get_total_size(type, screenname, account));
+			purple_log_get_total_size(type, buddyname, account));
 
 	if (prpl_icon)
 		g_object_unref(prpl_icon);
@@ -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/gtklog.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtklog.h	Wed Jan 28 10:23:37 2009 +0000
@@ -9,7 +9,7 @@
  * 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
@@ -53,7 +53,7 @@
 
 
 
-void pidgin_log_show(PurpleLogType type, const char *screenname, PurpleAccount *account);
+void pidgin_log_show(PurpleLogType type, const char *buddyname, PurpleAccount *account);
 void pidgin_log_show_contact(PurpleContact *contact);
 
 void pidgin_syslog_show(void);
--- a/pidgin/gtkmain.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkmain.c	Wed Jan 28 10:23:37 2009 +0000
@@ -310,6 +310,7 @@
 	pidgin_log_init();
 	pidgin_docklet_init();
 	pidgin_smileys_init();
+	pidgin_utils_init();
 }
 
 static GHashTable *ui_info = NULL;
@@ -323,6 +324,7 @@
 #endif
 
 	/* Uninit */
+	pidgin_utils_uninit();
 	pidgin_smileys_uninit();
 	pidgin_conversations_uninit();
 	pidgin_status_uninit();
@@ -385,6 +387,7 @@
 		       "Usage: %s [OPTION]...\n\n"
 		       "  -c, --config=DIR    use DIR for config files\n"
 		       "  -d, --debug         print debugging messages to stdout\n"
+		       "  -f, --force-online  force online, regardless of network status\n"
 		       "  -h, --help          display this help and exit\n"
 		       "  -m, --multiple      do not ensure single instance\n"
 		       "  -n, --nologin       don't automatically login\n"
@@ -398,6 +401,7 @@
 		       "Usage: %s [OPTION]...\n\n"
 		       "  -c, --config=DIR    use DIR for config files\n"
 		       "  -d, --debug         print debugging messages to stdout\n"
+		       "  -f, --force-online  force online, regardless of network status\n"
 		       "  -h, --help          display this help and exit\n"
 		       "  -m, --multiple      do not ensure single instance\n"
 		       "  -n, --nologin       don't automatically login\n"
@@ -457,10 +461,10 @@
 int main(int argc, char *argv[])
 #endif
 {
+	gboolean opt_force_online = FALSE;
 	gboolean opt_help = FALSE;
 	gboolean opt_login = FALSE;
 	gboolean opt_nologin = FALSE;
-	gboolean opt_nocrash = FALSE;
 	gboolean opt_version = FALSE;
 	gboolean opt_si = TRUE;     /* Check for single instance? */
 	char *opt_config_dir_arg = NULL;
@@ -485,17 +489,17 @@
 	GList *active_accounts;
 
 	struct option long_options[] = {
-		{"config",   required_argument, NULL, 'c'},
-		{"debug",    no_argument,       NULL, 'd'},
-		{"help",     no_argument,       NULL, 'h'},
-		{"login",    optional_argument, NULL, 'l'},
-		{"multiple", no_argument,       NULL, 'm'},
-		{"nologin",  no_argument,       NULL, 'n'},
-		{"nocrash",  no_argument,       NULL, 'x'},
-		{"session",  required_argument, NULL, 's'},
-		{"version",  no_argument,       NULL, 'v'},
-		{"display",  required_argument, NULL, 'D'},
-		{"sync",     no_argument,       NULL, 'S'},
+		{"config",       required_argument, NULL, 'c'},
+		{"debug",        no_argument,       NULL, 'd'},
+		{"force-online", no_argument,       NULL, 'd'},
+		{"help",         no_argument,       NULL, 'h'},
+		{"login",        optional_argument, NULL, 'l'},
+		{"multiple",     no_argument,       NULL, 'm'},
+		{"nologin",      no_argument,       NULL, 'n'},
+		{"session",      required_argument, NULL, 's'},
+		{"version",      no_argument,       NULL, 'v'},
+		{"display",      required_argument, NULL, 'D'},
+		{"sync",         no_argument,       NULL, 'S'},
 		{0, 0, 0, 0}
 	};
 
@@ -602,9 +606,9 @@
 	opterr = 1;
 	while ((opt = getopt_long(argc, argv,
 #ifndef _WIN32
-				  "c:dhmnl::s:v",
+				  "c:dfhmnl::s:v",
 #else
-				  "c:dhmnl::v",
+				  "c:dfhmnl::v",
 #endif
 				  long_options, NULL)) != -1) {
 		switch (opt) {
@@ -615,6 +619,9 @@
 		case 'd':	/* debug */
 			debug_enabled = TRUE;
 			break;
+		case 'f':	/* force-online */
+			opt_force_online = TRUE;
+			break;
 		case 'h':	/* help */
 			opt_help = TRUE;
 			break;
@@ -637,9 +644,6 @@
 		case 'm':   /* do not ensure single instance. */
 			opt_si = FALSE;
 			break;
-		case 'x':   /* --nocrash */
-			opt_nocrash = TRUE;
-			break;
 		case 'D':   /* --display */
 		case 'S':   /* --sync */
 			/* handled by gtk_init_check below */
@@ -816,6 +820,11 @@
 		opt_config_dir_arg = NULL;
 	}
 
+	/* This needs to be before purple_blist_show() so the
+	 * statusbox gets the forced online status. */
+	if (opt_force_online)
+		purple_network_force_online();
+
 	/*
 	 * We want to show the blist early in the init process so the
 	 * user feels warm and fuzzy (not cold and prickley).
--- a/pidgin/gtkpluginpref.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkpluginpref.c	Wed Jan 28 10:23:37 2009 +0000
@@ -93,7 +93,7 @@
 		case PURPLE_PLUGIN_PREF_NONE:
 		default:
 			if (format == PURPLE_STRING_FORMAT_TYPE_NONE)
-			{				
+			{
 				entry = gtk_entry_new();
 				gtk_entry_set_text(GTK_ENTRY(entry), purple_prefs_get_string(pref_name));
 				gtk_entry_set_max_length(GTK_ENTRY(entry),
--- a/pidgin/gtkpounce.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkpounce.c	Wed Jan 28 10:23:37 2009 +0000
@@ -535,7 +535,7 @@
 
 	/* Create the window. */
 	dialog->window = window = gtk_dialog_new();
-	gtk_window_set_title(GTK_WINDOW(window), (cur_pounce == NULL ? _("New Buddy Pounce") : _("Edit Buddy Pounce")));
+	gtk_window_set_title(GTK_WINDOW(window), (cur_pounce == NULL ? _("Add Buddy Pounce") : _("Modify Buddy Pounce")));
 	gtk_window_set_role(GTK_WINDOW(window), "buddy_pounce");
 	gtk_container_set_border_width(GTK_CONTAINER(dialog->window), PIDGIN_HIG_BORDER);
 
--- a/pidgin/gtkpounce.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkpounce.h	Wed Jan 28 10:23:37 2009 +0000
@@ -8,7 +8,7 @@
  * 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
--- a/pidgin/gtkprefs.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkprefs.c	Wed Jan 28 10:23:37 2009 +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,212 @@
 	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 success;
+	GtkTreeIter new_iter;
+
+	success = gtk_combo_box_get_active_iter(combo_box, &new_iter);
+	g_return_if_fail(success);
+
+	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 +1139,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 +1180,7 @@
 	GtkWidget *vbox;
 	GtkWidget *vbox2;
 	GtkWidget *label;
+	GtkWidget *combo_box;
 	GtkSizeGroup *sg;
 	GList *names = NULL;
 
@@ -937,6 +1189,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",
@@ -1738,6 +2003,8 @@
 	g_free(pref);
 
 	gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)"));
+
+	pref_sound_generate_markup();
 }
 
 static void
@@ -1760,6 +2027,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)
@@ -1828,6 +2097,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();
 }
 
 
@@ -1853,7 +2124,7 @@
 sound_page(void)
 {
 	GtkWidget *ret;
-	GtkWidget *vbox, *sw, *button;
+	GtkWidget *vbox, *sw, *button, *combo_box;
 	GtkSizeGroup *sg;
 	GtkTreeIter iter;
 	GtkWidget *event_view;
@@ -1947,7 +2218,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
@@ -1959,6 +2229,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);
@@ -2192,6 +2470,14 @@
 		return;
 	}
 
+	/* Refresh the list of themes before showing the preferences window */
+	purple_theme_manager_refresh();
+
+	/* add everything in the theme 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?) */
@@ -2286,6 +2572,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/gtkprefs.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkprefs.h	Wed Jan 28 10:23:37 2009 +0000
@@ -59,7 +59,7 @@
  * @param max   The maximum value of the spin button
  * @param sg    If not NULL, the size group to which the spin button will be added
  * @return      An hbox containing both the label and the spinner.  Can be
- *              used to set the widgets to sensitive or insensitive based on the 
+ *              used to set the widgets to sensitive or insensitive based on the
  *              value of a checkbox.
  */
 GtkWidget *pidgin_prefs_labeled_spin_button(GtkWidget *page,
--- a/pidgin/gtkrequest.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkrequest.c	Wed Jan 28 10:23:37 2009 +0000
@@ -384,6 +384,8 @@
 			gtk_imhtml_append_text(GTK_IMHTML(entry), default_value, GTK_IMHTML_NO_SCROLL);
 		gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
 		gtk_widget_show(frame);
+
+		gtk_imhtml_set_return_inserts_newline(GTK_IMHTML(entry));
 	}
 	else {
 		if (multiline) {
@@ -682,15 +684,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
@@ -711,7 +715,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;
@@ -722,9 +727,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;
 					}
 				}
@@ -1338,24 +1345,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);
@@ -1400,7 +1409,7 @@
 
 				gtk_widget_show(widget);
 
-				field->ui_data = widget;
+				purple_request_field_set_ui_data(field, widget);
 			}
 		}
 	}
--- a/pidgin/gtksavedstatuses.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtksavedstatuses.c	Wed Jan 28 10:23:37 2009 +0000
@@ -76,7 +76,7 @@
 	STATUS_EDITOR_COLUMN_WINDOW,
 	STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS,
 	STATUS_EDITOR_COLUMN_ICON,
-	STATUS_EDITOR_COLUMN_SCREENNAME,
+	STATUS_EDITOR_COLUMN_USERNAME,
 	/** A hidden column containing the ID of this PurpleStatusType. */
 	STATUS_EDITOR_COLUMN_STATUS_ID,
 	STATUS_EDITOR_COLUMN_STATUS_NAME,
@@ -1007,7 +1007,7 @@
 	g_signal_connect(G_OBJECT(renderer), "toggled",
 			 G_CALLBACK(status_editor_substatus_cb), dialog);
 
-	/* Screen Name column */
+	/* Username column */
 	column = gtk_tree_view_column_new();
 	gtk_tree_view_column_set_resizable(column, TRUE);
 	gtk_tree_view_column_set_title(column, _("Username"));
@@ -1020,11 +1020,11 @@
 	gtk_tree_view_column_add_attribute(column, renderer, "pixbuf",
 									   STATUS_EDITOR_COLUMN_ICON);
 
-	/* Screen Name */
+	/* Username */
 	renderer = gtk_cell_renderer_text_new();
 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
 	gtk_tree_view_column_add_attribute(column, renderer, "text",
-									   STATUS_EDITOR_COLUMN_SCREENNAME);
+									   STATUS_EDITOR_COLUMN_USERNAME);
 
 	/* Status column */
 	column = gtk_tree_view_column_new();
@@ -1086,7 +1086,7 @@
 			STATUS_EDITOR_COLUMN_ACCOUNT, account,
 			STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, (substatus != NULL),
 			STATUS_EDITOR_COLUMN_ICON, pixbuf,
-			STATUS_EDITOR_COLUMN_SCREENNAME, purple_account_get_username(account),
+			STATUS_EDITOR_COLUMN_USERNAME, purple_account_get_username(account),
 			STATUS_EDITOR_COLUMN_STATUS_ID, id,
 			STATUS_EDITOR_COLUMN_STATUS_NAME, name,
 			STATUS_EDITOR_COLUMN_STATUS_MESSAGE, message,
@@ -1218,6 +1218,8 @@
 	gtk_container_set_focus_chain(GTK_CONTAINER(hbox), focus_chain);
 	g_list_free(focus_chain);
 
+	gtk_imhtml_set_return_inserts_newline(dialog->message);
+
 	if ((saved_status != NULL) && (purple_savedstatus_get_message(saved_status) != NULL))
 		gtk_imhtml_append_text(GTK_IMHTML(text),
 							   purple_savedstatus_get_message(saved_status), 0);
@@ -1547,7 +1549,7 @@
 	/* Seed the input widgets with the current values */
 
 	/* Only look at the saved status if we can't find it in the parent status dialog's substatuses model */
-	gtk_tree_model_get(GTK_TREE_MODEL(status_editor->model), &iter, 
+	gtk_tree_model_get(GTK_TREE_MODEL(status_editor->model), &iter,
 		STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, &parent_dialog_has_substatus, -1);
 	if (parent_dialog_has_substatus) {
 		gtk_tree_model_get(GTK_TREE_MODEL(status_editor->model), &iter,
@@ -1656,7 +1658,7 @@
 	 * And whether or not that emblem is visible
 	 */
 	SS_MENU_EMBLEM_VISIBLE_COLUMN,
-	
+
 	SS_MENU_NUM_COLUMNS
 };
 
--- a/pidgin/gtkscrollbook.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkscrollbook.h	Wed Jan 28 10:23:37 2009 +0000
@@ -51,7 +51,7 @@
 	GtkWidget *left_arrow;
 	GtkWidget *right_arrow;
 	GList *children;
-	
+
 	/* Padding for future expansion */
 	void (*_gtk_reserved1) (void);
 	void (*_gtk_reserved2) (void);
--- a/pidgin/gtksession.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtksession.c	Wed Jan 28 10:23:37 2009 +0000
@@ -108,7 +108,7 @@
 	purple_debug(PURPLE_DEBUG_INFO, NULL, "done.\n");
 }
 
-/* We call any handler installed before (or after) ice_init but 
+/* We call any handler installed before (or after) ice_init but
  * avoid calling the default libICE handler which does an exit().
  *
  * This means we do nothing by default, which is probably correct,
--- a/pidgin/gtksmiley.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtksmiley.c	Wed Jan 28 10:23:37 2009 +0000
@@ -225,6 +225,12 @@
 
 	entry = gtk_entry_get_text(GTK_ENTRY(s->smile));
 	if (!entry || !*entry) {
+		/*
+		 * TODO: We should enable/disable the add button based on
+		 *       whether the user has entered all required data.  That
+		 *       would eliminate the need for this check and provide a
+		 *       better user experience.
+		 */
 		purple_notify_error(s->parent, _("Custom Smiley"),
 				_("More Data needed"),
 				_("Please provide a shortcut to associate with the smiley."));
@@ -233,9 +239,12 @@
 
 	emoticon = purple_smileys_find_by_shortcut(entry);
 	if (emoticon && emoticon != s->smiley) {
+		gchar *msg;
+		msg = g_strdup_printf(_("A custom smiley for '%s' already exists.  "
+				"Please use a different shortcut."), entry);
 		purple_notify_error(s->parent, _("Custom Smiley"),
-				_("Duplicate Shortcut"),
-				_("A custom smiley for the selected shortcut already exists. Please specify a different shortcut."));
+				_("Duplicate Shortcut"), msg);
+		g_free(msg);
 		return;
 	}
 
@@ -273,7 +282,7 @@
 			gsize size = 0;
 			gchar *filename;
 			const gchar *dirname = purple_smileys_get_storing_dir();
-			
+
 			/* since this may be called before purple_smiley_new_* has ever been
 			 called, we create the storing dir, if it doesn't exist yet, to be
 			 able to save the pixbuf before adding the smiley */
@@ -286,7 +295,7 @@
 			                   dirname, g_strerror(errno));
 				}
 			}
-			
+
 			gdk_pixbuf_save_to_buffer(s->custom_pixbuf, &buffer, &size,
 				"png", NULL, "compression", "9", NULL, NULL);
 			filename = purple_util_get_image_filename(buffer, size);
@@ -385,7 +394,7 @@
 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
 	gtk_container_add(GTK_CONTAINER(GTK_VBOX(vbox)), hbox);
 
-	label = gtk_label_new_with_mnemonic(_("Smiley _Image"));
+	label = gtk_label_new_with_mnemonic(_("_Image:"));
 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
 	gtk_widget_show(label);
 
@@ -415,8 +424,8 @@
 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
 	gtk_container_add(GTK_CONTAINER(GTK_VBOX(vbox)),hbox);
 
-	/* Smiley shortcut */
-	label = gtk_label_new_with_mnemonic(_("Smiley S_hortcut"));
+	/* Shortcut text */
+	label = gtk_label_new_with_mnemonic(_("S_hortcut text:"));
 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
 	gtk_widget_show(label);
 
@@ -520,9 +529,9 @@
 	gtk_tree_view_column_pack_start(column, rend, FALSE);
 	gtk_tree_view_column_add_attribute(column, rend, "pixbuf", ICON);
 
-	/* Shortcut */
+	/* Shortcut Text */
 	column = gtk_tree_view_column_new();
-	gtk_tree_view_column_set_title(column, _("Shortcut"));
+	gtk_tree_view_column_set_title(column, _("Shortcut Text"));
 	gtk_tree_view_column_set_resizable(column, TRUE);
 	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 
@@ -712,7 +721,7 @@
 			_("Custom Smiley Manager"),
 			NULL,
 			GTK_DIALOG_DESTROY_WITH_PARENT,
-			GTK_STOCK_ADD, GTK_RESPONSE_YES,
+			PIDGIN_STOCK_ADD, GTK_RESPONSE_YES,
 			PIDGIN_STOCK_MODIFY, PIDGIN_RESPONSE_MODIFY,
 			GTK_STOCK_DELETE, GTK_RESPONSE_NO,
 			GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
@@ -740,4 +749,3 @@
 
 	gtk_widget_show(win);
 }
-
--- a/pidgin/gtksmiley.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtksmiley.h	Wed Jan 28 10:23:37 2009 +0000
@@ -25,8 +25,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#ifndef _PIDGIN_GTKSMILEY_H_
-#define _PIDGIN_GTKSMILEY_H_
+#ifndef PIDGIN_GTKSMILEY_H
+#define PIDGIN_GTKSMILEY_H
 
 #include "smiley.h"
 
@@ -62,7 +62,7 @@
  *
  * @constreturn A GtkIMHmlSmiley list
  */
-GSList* pidgin_smileys_get_all(void);
+GSList *pidgin_smileys_get_all(void);
 
 /******************************************************************************
  * Smiley Manager
@@ -100,4 +100,4 @@
  */
 void pidgin_smiley_editor_set_image(PidginSmiley *editor, GdkPixbuf *image);
 
-#endif /* _PIDGIN_GTKSMILEY_H_*/
+#endif /* PIDGIN_GTKSMILEY_H */
--- a/pidgin/gtksound.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtksound.c	Wed Jan 28 10:23:37 2009 +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;
@@ -573,13 +578,31 @@
 	/* 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 && *theme_name && (!filename || !*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 +610,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 && file[0] != '\0'){
+			g_free(file);
+			return TRUE;
+		}
+
+		g_free(file);
+	}
+
+	return FALSE;
+
+}
+
 static PurpleSoundUiOps sound_ui_ops =
 {
 	pidgin_sound_init,
--- a/pidgin/gtksound.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtksound.h	Wed Jan 28 10:23:37 2009 +0000
@@ -63,6 +63,15 @@
  */
 void *pidgin_sound_get_handle(void);
 
+/**
+ * Returns true Pidgin is using customized sounds
+ *
+ * @return TRUE if non default sounds are used.
+ *
+ * @since 2.6.0
+ */
+gboolean pidgin_sound_is_customized(void);
+
 /*@}*/
 
 #endif /* _PIDGINSOUND_H_ */
--- a/pidgin/gtksourceiter.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtksourceiter.c	Wed Jan 28 10:23:37 2009 +0000
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *  gtksourceiter.c
  *
  *  Pidgin is the legal property of its developers, whose names are too numerous
@@ -7,7 +7,7 @@
  *
  *  The following copyright notice applies to this file:
  *
- *  Copyright (C) 2000 - 2005 Paolo Maggi 
+ *  Copyright (C) 2000 - 2005 Paolo Maggi
  *  Copyright (C) 2002, 2003 Jeroen Zwartepoorte
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -206,7 +206,7 @@
 
 finally_2:
 	g_free (normalized_s1);
-	g_free (normalized_s2);	
+	g_free (normalized_s2);
 
 	return ret;
 }
@@ -247,7 +247,7 @@
 		{
 			/* being UTF8 correct sucks; this accounts for extra
 			   offsets coming from canonical decompositions of
-			   UTF8 characters (e.g. accented characters) which 
+			   UTF8 characters (e.g. accented characters) which
 			   g_utf8_normalize() performs */
 			gchar *normal;
 			gchar buffer[6];
@@ -530,14 +530,14 @@
  * @match_start: return location for start of match, or %%NULL.
  * @match_end: return location for end of match, or %%NULL.
  * @limit: bound for the search, or %%NULL for the end of the buffer.
- * 
- * Searches forward for @str. Any match is returned by setting 
- * @match_start to the first character of the match and @match_end to the 
+ *
+ * Searches forward for @str. Any match is returned by setting
+ * @match_start to the first character of the match and @match_end to the
  * first character after the match. The search will not continue past
  * @limit. Note that a search is a linear or O(n) operation, so you
  * may wish to use @limit to avoid locking up your UI on large
  * buffers.
- * 
+ *
  * If the #GTK_SOURCE_SEARCH_VISIBLE_ONLY flag is present, the match may
  * have invisible text interspersed in @str. i.e. @str will be a
  * possibly-noncontiguous subsequence of the matched range. similarly,
@@ -550,7 +550,7 @@
  *
  * Same as gtk_text_iter_forward_search(), but supports case insensitive
  * searching.
- * 
+ *
  * Return value: whether a match was found.
  **/
 gboolean
@@ -574,7 +574,7 @@
 	if ((flags & GTK_SOURCE_SEARCH_CASE_INSENSITIVE) == 0)
 		return gtk_text_iter_forward_search (iter, str, flags,
 						     match_start, match_end,
-						     limit); 
+						     limit);
 
 	if (limit && gtk_text_iter_compare (iter, limit) >= 0)
 		return FALSE;
@@ -650,10 +650,10 @@
  * @match_start: return location for start of match, or %%NULL.
  * @match_end: return location for end of match, or %%NULL.
  * @limit: location of last possible @match_start, or %%NULL for start of buffer.
- * 
+ *
  * Same as gtk_text_iter_backward_search(), but supports case insensitive
  * searching.
- * 
+ *
  * Return value: whether a match was found.
  **/
 gboolean
@@ -677,7 +677,7 @@
 	if ((flags & GTK_SOURCE_SEARCH_CASE_INSENSITIVE) == 0)
 		return gtk_text_iter_backward_search (iter, str, flags,
 						      match_start, match_end,
-						      limit); 
+						      limit);
 
 	if (limit && gtk_text_iter_compare (iter, limit) <= 0)
 		return FALSE;
--- a/pidgin/gtksourceiter.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtksourceiter.h	Wed Jan 28 10:23:37 2009 +0000
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *  gtksourceiter.h
  *
  *  Pidgin is the legal property of its developers, whose names are too numerous
@@ -7,7 +7,7 @@
  *
  *  The following copyright notice applies to this file:
  *
- *  Copyright (C) 2000 - 2005 Paolo Maggi 
+ *  Copyright (C) 2000 - 2005 Paolo Maggi
  *  Copyright (C) 2002, 2003 Jeroen Zwartepoorte
  *
  *  This program is free software; you can redistribute it and/or modify
--- a/pidgin/gtksourceundomanager.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtksourceundomanager.c	Wed Jan 28 10:23:37 2009 +0000
@@ -4,8 +4,8 @@
  * This file is part of GtkSourceView
  *
  * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
- * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi 
- * Copyright (C) 2002-2005  Paolo Maggi 
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005  Paolo Maggi
  *
  * 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
@@ -19,7 +19,7 @@
  *
  * 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, 
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02111-1301, USA.
  */
 
@@ -49,14 +49,14 @@
 	GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR,
 } GtkSourceUndoActionType;
 
-/* 
+/*
  * We use offsets instead of GtkTextIters because the last ones
  * require to much memory in this context without giving us any advantage.
- */ 
+ */
 
 struct _GtkSourceUndoInsertAction
 {
-	gint   pos; 
+	gint   pos;
 	gchar *text;
 	gint   length;
 	gint   chars;
@@ -79,7 +79,7 @@
 struct _GtkSourceUndoAction
 {
 	GtkSourceUndoActionType action_type;
-	
+
 	union {
 		GtkSourceUndoInsertAction  insert;
 		GtkSourceUndoDeleteAction  delete;
@@ -92,7 +92,7 @@
 	guint mergeable : 1;
 
 	/* It is TRUE whether the action is marked as "modified".
-	 * An action is marked as "modified" if it changed the 
+	 * An action is marked as "modified" if it changed the
 	 * state of the buffer from "not modified" to "modified". Only the first
 	 * action of a group can be marked as modified.
 	 * There can be a single action marked as "modified" in the actions list.
@@ -106,29 +106,29 @@
 struct _GtkSourceUndoManagerPrivate
 {
 	GtkTextBuffer	*document;
-	
+
 	GList*		 actions;
-	gint 		 next_redo;	
+	gint 		 next_redo;
 
 	gint 		 actions_in_current_group;
-	
+
 	gint		 running_not_undoable_actions;
 
 	gint		 num_of_groups;
 
 	gint		 max_undo_levels;
-	
+
 	guint	 	 can_undo : 1;
 	guint		 can_redo : 1;
-	
+
 	/* It is TRUE whether, while undoing an action of the current group (with order_in_group > 1),
 	 * the state of the buffer changed from "not modified" to "modified".
 	 */
-	guint	 	 modified_undoing_group : 1;	
+	guint	 	 modified_undoing_group : 1;
 
 	/* Pointer to the action (in the action list) marked as "modified".
-	 * It is NULL when no action is marked as "modified". 
-	 * It is INVALID when the action marked as "modified" has been removed 
+	 * It is NULL when no action is marked as "modified".
+	 * It is INVALID when the action marked as "modified" has been removed
 	 * from the action list (freeing the list or resizing it) */
 	GtkSourceUndoAction *modified_action;
 };
@@ -143,33 +143,33 @@
 static void gtk_source_undo_manager_init 			(GtkSourceUndoManager 		*um);
 static void gtk_source_undo_manager_finalize 			(GObject 			*object);
 
-static void gtk_source_undo_manager_insert_text_handler 	(GtkTextBuffer 			*buffer, 
+static void gtk_source_undo_manager_insert_text_handler 	(GtkTextBuffer 			*buffer,
 							 	 GtkTextIter 			*pos,
-		                             		 	 const 	gchar 			*text, 
-							 	 gint 				 length, 
+		                             		 	 const 	gchar 			*text,
+							 	 gint 				 length,
 							 	 GtkSourceUndoManager 		*um);
 static void gtk_source_undo_manager_insert_anchor_handler (GtkTextBuffer *buffer,
 			                   GtkTextIter            *pos,
 			                   GtkTextChildAnchor     *anchor,
 			                   GtkSourceUndoManager   *um);
-static void gtk_source_undo_manager_delete_range_handler 	(GtkTextBuffer 			*buffer, 
+static void gtk_source_undo_manager_delete_range_handler 	(GtkTextBuffer 			*buffer,
 							 	 GtkTextIter 			*start,
                         		      		 	 GtkTextIter 			*end,
 							 	 GtkSourceUndoManager 		*um);
-static void gtk_source_undo_manager_begin_user_action_handler 	(GtkTextBuffer 			*buffer, 
+static void gtk_source_undo_manager_begin_user_action_handler 	(GtkTextBuffer 			*buffer,
 								 GtkSourceUndoManager 		*um);
 static void gtk_source_undo_manager_modified_changed_handler	(GtkTextBuffer                  *buffer,
 								 GtkSourceUndoManager           *um);
 
 static void gtk_source_undo_manager_free_action_list 		(GtkSourceUndoManager 		*um);
 
-static void gtk_source_undo_manager_add_action 			(GtkSourceUndoManager 		*um, 
+static void gtk_source_undo_manager_add_action 			(GtkSourceUndoManager 		*um,
 		                                         	 const GtkSourceUndoAction 	*undo_action);
-static void gtk_source_undo_manager_free_first_n_actions 	(GtkSourceUndoManager 		*um, 
+static void gtk_source_undo_manager_free_first_n_actions 	(GtkSourceUndoManager 		*um,
 								 gint 				 n);
 static void gtk_source_undo_manager_check_list_size 		(GtkSourceUndoManager 		*um);
 
-static gboolean gtk_source_undo_manager_merge_action 		(GtkSourceUndoManager 		*um, 
+static gboolean gtk_source_undo_manager_merge_action 		(GtkSourceUndoManager 		*um,
 		                                        	 const GtkSourceUndoAction 	*undo_action);
 
 static GObjectClass 	*parent_class 				= NULL;
@@ -216,7 +216,7 @@
 
         klass->can_undo 	= NULL;
 	klass->can_redo 	= NULL;
-	
+
 	undo_manager_signals[CAN_UNDO] =
    		g_signal_new ("can_undo",
 			      G_OBJECT_CLASS_TYPE (object_class),
@@ -269,7 +269,7 @@
 
 	g_return_if_fail (object != NULL);
 	g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (object));
-	
+
    	um = GTK_SOURCE_UNDO_MANAGER (object);
 
 	g_return_if_fail (um->priv != NULL);
@@ -280,19 +280,19 @@
 	}
 
 	g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
-			  G_CALLBACK (gtk_source_undo_manager_delete_range_handler), 
+			  G_CALLBACK (gtk_source_undo_manager_delete_range_handler),
 			  um);
 
 	g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
-			  G_CALLBACK (gtk_source_undo_manager_insert_text_handler), 
+			  G_CALLBACK (gtk_source_undo_manager_insert_text_handler),
 			  um);
-	
+
 	g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
-			  G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler), 
+			  G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler),
 			  um);
-	
+
 	g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
-			  G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler), 
+			  G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler),
 			  um);
 
 	g_free (um->priv);
@@ -311,19 +311,19 @@
   	um->priv->document = buffer;
 
 	g_signal_connect (G_OBJECT (buffer), "insert_text",
-			  G_CALLBACK (gtk_source_undo_manager_insert_text_handler), 
+			  G_CALLBACK (gtk_source_undo_manager_insert_text_handler),
 			  um);
 
 	g_signal_connect (G_OBJECT (buffer), "insert_child_anchor",
-			  G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler), 
+			  G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler),
 			  um);
 
 	g_signal_connect (G_OBJECT (buffer), "delete_range",
-			  G_CALLBACK (gtk_source_undo_manager_delete_range_handler), 
+			  G_CALLBACK (gtk_source_undo_manager_delete_range_handler),
 			  um);
 
 	g_signal_connect (G_OBJECT (buffer), "begin_user_action",
-			  G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler), 
+			  G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler),
 			  um);
 
 	g_signal_connect (G_OBJECT (buffer), "modified_changed",
@@ -332,7 +332,7 @@
 	return um;
 }
 
-void 
+void
 gtk_source_undo_manager_begin_not_undoable_action (GtkSourceUndoManager *um)
 {
 	g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
@@ -341,18 +341,18 @@
 	++um->priv->running_not_undoable_actions;
 }
 
-static void 
+static void
 gtk_source_undo_manager_end_not_undoable_action_internal (GtkSourceUndoManager *um)
 {
 	g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
 	g_return_if_fail (um->priv != NULL);
 
 	g_return_if_fail (um->priv->running_not_undoable_actions > 0);
-	
+
 	--um->priv->running_not_undoable_actions;
 }
 
-void 
+void
 gtk_source_undo_manager_end_not_undoable_action (GtkSourceUndoManager *um)
 {
 	g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
@@ -361,26 +361,26 @@
 	gtk_source_undo_manager_end_not_undoable_action_internal (um);
 
 	if (um->priv->running_not_undoable_actions == 0)
-	{	
+	{
 		gtk_source_undo_manager_free_action_list (um);
-	
-		um->priv->next_redo = -1;	
+
+		um->priv->next_redo = -1;
 
 		if (um->priv->can_undo)
 		{
 			um->priv->can_undo = FALSE;
-			g_signal_emit (G_OBJECT (um), 
-				       undo_manager_signals [CAN_UNDO], 
-				       0, 
+			g_signal_emit (G_OBJECT (um),
+				       undo_manager_signals [CAN_UNDO],
+				       0,
 				       FALSE);
 		}
 
 		if (um->priv->can_redo)
 		{
 			um->priv->can_redo = FALSE;
-			g_signal_emit (G_OBJECT (um), 
-				       undo_manager_signals [CAN_REDO], 
-				       0, 
+			g_signal_emit (G_OBJECT (um),
+				       undo_manager_signals [CAN_REDO],
+				       0,
 				       FALSE);
 		}
 	}
@@ -395,7 +395,7 @@
 	return um->priv->can_undo;
 }
 
-gboolean 
+gboolean
 gtk_source_undo_manager_can_redo (const GtkSourceUndoManager *um)
 {
 	g_return_val_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um), FALSE);
@@ -408,31 +408,31 @@
 set_cursor (GtkTextBuffer *buffer, gint cursor)
 {
 	GtkTextIter iter;
-	
+
 	/* Place the cursor at the requested position */
 	gtk_text_buffer_get_iter_at_offset (buffer, &iter, cursor);
 	gtk_text_buffer_place_cursor (buffer, &iter);
 }
 
-static void 
+static void
 insert_text (GtkTextBuffer *buffer, gint pos, const gchar *text, gint len)
 {
 	GtkTextIter iter;
-	
+
 	gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos);
 	gtk_text_buffer_insert (buffer, &iter, text, len);
 }
 
-static void 
+static void
 insert_anchor (GtkTextBuffer *buffer, gint pos, GtkTextChildAnchor *anchor)
 {
 	GtkTextIter iter;
-	
+
 	gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos);
 	gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
 }
 
-static void 
+static void
 delete_text (GtkTextBuffer *buffer, gint start, gint end)
 {
 	GtkTextIter start_iter;
@@ -464,7 +464,7 @@
 	return gtk_text_buffer_get_slice (buffer, &start_iter, &end_iter, TRUE);
 }
 
-void 
+void
 gtk_source_undo_manager_undo (GtkSourceUndoManager *um)
 {
 	GtkSourceUndoAction *undo_action;
@@ -473,13 +473,13 @@
 	g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
 	g_return_if_fail (um->priv != NULL);
 	g_return_if_fail (um->priv->can_undo);
-	
+
 	um->priv->modified_undoing_group = FALSE;
 
 	gtk_source_undo_manager_begin_not_undoable_action (um);
 
 	do
-	{	
+	{
 		undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo + 1);
 		g_return_if_fail (undo_action != NULL);
 
@@ -490,7 +490,7 @@
 		if (undo_action->order_in_group <= 1)
 		{
 			/* Set modified to TRUE only if the buffer did not change its state from
-			 * "not modified" to "modified" undoing an action (with order_in_group > 1) 
+			 * "not modified" to "modified" undoing an action (with order_in_group > 1)
 			 * in current group. */
 			modified = (undo_action->modified && !um->priv->modified_undoing_group);
 		}
@@ -499,31 +499,31 @@
 		{
 			case GTK_SOURCE_UNDO_ACTION_DELETE:
 				insert_text (
-					um->priv->document, 
-					undo_action->action.delete.start, 
+					um->priv->document,
+					undo_action->action.delete.start,
 					undo_action->action.delete.text,
 					strlen (undo_action->action.delete.text));
 
 				if (undo_action->action.delete.forward)
 					set_cursor (
-						um->priv->document, 
+						um->priv->document,
 						undo_action->action.delete.start);
 				else
 					set_cursor (
-						um->priv->document, 
+						um->priv->document,
 						undo_action->action.delete.end);
 
 				break;
-				
+
 			case GTK_SOURCE_UNDO_ACTION_INSERT:
 				delete_text (
-					um->priv->document, 
-					undo_action->action.insert.pos, 
-					undo_action->action.insert.pos + 
-						undo_action->action.insert.chars); 
+					um->priv->document,
+					undo_action->action.insert.pos,
+					undo_action->action.insert.pos +
+						undo_action->action.insert.chars);
 
 				set_cursor (
-					um->priv->document, 
+					um->priv->document,
 					undo_action->action.insert.pos);
 				break;
 
@@ -551,29 +551,29 @@
 	}
 
 	gtk_source_undo_manager_end_not_undoable_action_internal (um);
-	
+
 	um->priv->modified_undoing_group = FALSE;
 
 	if (!um->priv->can_redo)
 	{
 		um->priv->can_redo = TRUE;
-		g_signal_emit (G_OBJECT (um), 
-			       undo_manager_signals [CAN_REDO], 
-			       0, 
+		g_signal_emit (G_OBJECT (um),
+			       undo_manager_signals [CAN_REDO],
+			       0,
 			       TRUE);
 	}
 
 	if (um->priv->next_redo >= (gint)(g_list_length (um->priv->actions) - 1))
 	{
 		um->priv->can_undo = FALSE;
-		g_signal_emit (G_OBJECT (um), 
-			       undo_manager_signals [CAN_UNDO], 
-			       0, 
+		g_signal_emit (G_OBJECT (um),
+			       undo_manager_signals [CAN_UNDO],
+			       0,
 			       FALSE);
 	}
 }
 
-void 
+void
 gtk_source_undo_manager_redo (GtkSourceUndoManager *um)
 {
 	GtkSourceUndoAction *undo_action;
@@ -582,7 +582,7 @@
 	g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
 	g_return_if_fail (um->priv != NULL);
 	g_return_if_fail (um->priv->can_redo);
-	
+
 	undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo);
 	g_return_if_fail (undo_action != NULL);
 
@@ -597,29 +597,29 @@
 		}
 
 		--um->priv->next_redo;
-	
+
 		switch (undo_action->action_type)
 		{
 			case GTK_SOURCE_UNDO_ACTION_DELETE:
 				delete_text (
-					um->priv->document, 
-					undo_action->action.delete.start, 
-					undo_action->action.delete.end); 
+					um->priv->document,
+					undo_action->action.delete.start,
+					undo_action->action.delete.end);
 
 				set_cursor (
 					um->priv->document,
 					undo_action->action.delete.start);
 
 				break;
-				
+
 			case GTK_SOURCE_UNDO_ACTION_INSERT:
 				set_cursor (
 					um->priv->document,
 					undo_action->action.insert.pos);
 
 				insert_text (
-					um->priv->document, 
-					undo_action->action.insert.pos, 
+					um->priv->document,
+					undo_action->action.insert.pos,
 					undo_action->action.insert.text,
 					undo_action->action.insert.length);
 
@@ -646,7 +646,7 @@
 			undo_action = NULL;
 		else
 			undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo);
-			
+
 	} while ((undo_action != NULL) && (undo_action->order_in_group > 1));
 
 	if (modified)
@@ -689,7 +689,7 @@
 	g_free (action);
 }
 
-static void 
+static void
 gtk_source_undo_manager_free_action_list (GtkSourceUndoManager *um)
 {
 	GList *l;
@@ -712,18 +712,18 @@
 	}
 
 	g_list_free (um->priv->actions);
-	um->priv->actions = NULL;	
+	um->priv->actions = NULL;
 }
 
-static void 
-gtk_source_undo_manager_insert_text_handler (GtkTextBuffer 		*buffer, 
+static void
+gtk_source_undo_manager_insert_text_handler (GtkTextBuffer 		*buffer,
 					     GtkTextIter 		*pos,
-		                             const gchar 		*text, 
-					     gint 			 length, 
+		                             const gchar 		*text,
+					     gint 			 length,
 					     GtkSourceUndoManager 	*um)
 {
 	GtkSourceUndoAction undo_action;
-	
+
 	if (um->priv->running_not_undoable_actions > 0)
 		return;
 
@@ -766,15 +766,15 @@
 	gtk_source_undo_manager_add_action (um, &undo_action);
 }
 
-static void 
-gtk_source_undo_manager_delete_range_handler (GtkTextBuffer 		*buffer, 
+static void
+gtk_source_undo_manager_delete_range_handler (GtkTextBuffer 		*buffer,
 					      GtkTextIter 		*start,
-                        		      GtkTextIter 		*end, 
+                        		      GtkTextIter 		*end,
 					      GtkSourceUndoManager 	*um)
 {
 	GtkSourceUndoAction undo_action;
 	GtkTextIter insert_iter;
-	
+
 	if (um->priv->running_not_undoable_actions > 0)
 		return;
 
@@ -805,14 +805,14 @@
 		undo_action.mergeable = TRUE;
 
 	undo_action.modified = FALSE;
-	
+
 	gtk_source_undo_manager_add_action (um, &undo_action);
 
 	g_free (undo_action.action.delete.text);
 
 }
 
-static void 
+static void
 gtk_source_undo_manager_begin_user_action_handler (GtkTextBuffer *buffer, GtkSourceUndoManager *um)
 {
 	g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
@@ -825,11 +825,11 @@
 }
 
 static void
-gtk_source_undo_manager_add_action (GtkSourceUndoManager 	*um, 
+gtk_source_undo_manager_add_action (GtkSourceUndoManager 	*um,
 				    const GtkSourceUndoAction 	*undo_action)
 {
 	GtkSourceUndoAction* action;
-	
+
 	if (um->priv->next_redo >= 0)
 	{
 		gtk_source_undo_manager_free_first_n_actions (um, um->priv->next_redo + 1);
@@ -845,7 +845,7 @@
 		if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
 			action->action.insert.text = g_strndup (undo_action->action.insert.text, undo_action->action.insert.length);
 		else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
-			action->action.delete.text = g_strdup (undo_action->action.delete.text); 
+			action->action.delete.text = g_strdup (undo_action->action.delete.text);
 		else if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR)
 		{
 			/* Nothing needs to be done */
@@ -855,16 +855,16 @@
 			g_free (action);
 			g_return_if_reached ();
 		}
-		
+
 		++um->priv->actions_in_current_group;
 		action->order_in_group = um->priv->actions_in_current_group;
 
 		if (action->order_in_group == 1)
 			++um->priv->num_of_groups;
-	
+
 		um->priv->actions = g_list_prepend (um->priv->actions, action);
 	}
-	
+
 	gtk_source_undo_manager_check_list_size (um);
 
 	if (!um->priv->can_undo)
@@ -880,8 +880,8 @@
 	}
 }
 
-static void 
-gtk_source_undo_manager_free_first_n_actions (GtkSourceUndoManager	*um, 
+static void
+gtk_source_undo_manager_free_first_n_actions (GtkSourceUndoManager	*um,
 					      gint 			 n)
 {
 	gint i;
@@ -904,21 +904,21 @@
 		um->priv->actions = g_list_delete_link (um->priv->actions,
 							um->priv->actions);
 
-		if (um->priv->actions == NULL) 
+		if (um->priv->actions == NULL)
 			return;
 	}
 }
 
-static void 
+static void
 gtk_source_undo_manager_check_list_size (GtkSourceUndoManager *um)
 {
 	gint undo_levels;
-	
+
 	g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
 	g_return_if_fail (um->priv != NULL);
-	
+
 	undo_levels = gtk_source_undo_manager_get_max_undo_levels (um);
-	
+
 	if (undo_levels < 1)
 		return;
 
@@ -926,14 +926,14 @@
 	{
 		GtkSourceUndoAction *undo_action;
 		GList *last;
-		
+
 		last = g_list_last (um->priv->actions);
 		undo_action = (GtkSourceUndoAction*) last->data;
-			
+
 		do
 		{
 			GList *tmp;
-			
+
 			if (undo_action->order_in_group == 1)
 				--um->priv->num_of_groups;
 
@@ -945,32 +945,32 @@
 			tmp = g_list_previous (last);
 			um->priv->actions = g_list_delete_link (um->priv->actions, last);
 			last = tmp;
-			g_return_if_fail (last != NULL); 
+			g_return_if_fail (last != NULL);
 
 			undo_action = (GtkSourceUndoAction*) last->data;
 
-		} while ((undo_action->order_in_group > 1) || 
+		} while ((undo_action->order_in_group > 1) ||
 			 (um->priv->num_of_groups > undo_levels));
-	}	
+	}
 }
 
 /**
  * gtk_source_undo_manager_merge_action:
- * @um: a #GtkSourceUndoManager. 
+ * @um: a #GtkSourceUndoManager.
  * @undo_action: a #GtkSourceUndoAction.
- * 
+ *
  * This function tries to merge the undo action at the top of
  * the stack with a new undo action. So when we undo for example
  * typing, we can undo the whole word and not each letter by itself.
- * 
- * Return Value: %TRUE is merge was sucessful, %FALSE otherwise.²
+ *
+ * Return Value: %TRUE is merge was successful, %FALSE otherwise.²
  **/
-static gboolean 
-gtk_source_undo_manager_merge_action (GtkSourceUndoManager 	*um, 
+static gboolean
+gtk_source_undo_manager_merge_action (GtkSourceUndoManager 	*um,
 				      const GtkSourceUndoAction *undo_action)
 {
 	GtkSourceUndoAction *last_action;
-	
+
 	g_return_val_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um), FALSE);
 	g_return_val_if_fail (um->priv != NULL, FALSE);
 
@@ -990,7 +990,7 @@
 	}
 
 	if (undo_action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
-	{				
+	{
 		if ((last_action->action.delete.forward != undo_action->action.delete.forward) ||
 		    ((last_action->action.delete.start != undo_action->action.delete.start) &&
 		     (last_action->action.delete.start != undo_action->action.delete.end)))
@@ -998,14 +998,14 @@
 			last_action->mergeable = FALSE;
 			return FALSE;
 		}
-		
+
 		if (last_action->action.delete.start == undo_action->action.delete.start)
 		{
 			gchar *str;
-			
+
 #define L  (last_action->action.delete.end - last_action->action.delete.start - 1)
 #define g_utf8_get_char_at(p,i) g_utf8_get_char(g_utf8_offset_to_pointer((p),(i)))
-		
+
 			/* Deleted with the delete key */
 			if ((g_utf8_get_char (undo_action->action.delete.text) != ' ') &&
 			    (g_utf8_get_char (undo_action->action.delete.text) != '\t') &&
@@ -1015,19 +1015,19 @@
 				last_action->mergeable = FALSE;
 				return FALSE;
 			}
-			
-			str = g_strdup_printf ("%s%s", last_action->action.delete.text, 
+
+			str = g_strdup_printf ("%s%s", last_action->action.delete.text,
 				undo_action->action.delete.text);
-			
+
 			g_free (last_action->action.delete.text);
-			last_action->action.delete.end += (undo_action->action.delete.end - 
+			last_action->action.delete.end += (undo_action->action.delete.end -
 							   undo_action->action.delete.start);
 			last_action->action.delete.text = str;
 		}
 		else
 		{
 			gchar *str;
-			
+
 			/* Deleted with the backspace key */
 			if ((g_utf8_get_char (undo_action->action.delete.text) != ' ') &&
 			    (g_utf8_get_char (undo_action->action.delete.text) != '\t') &&
@@ -1038,9 +1038,9 @@
 				return FALSE;
 			}
 
-			str = g_strdup_printf ("%s%s", undo_action->action.delete.text, 
+			str = g_strdup_printf ("%s%s", undo_action->action.delete.text,
 				last_action->action.delete.text);
-			
+
 			g_free (last_action->action.delete.text);
 			last_action->action.delete.start = undo_action->action.delete.start;
 			last_action->action.delete.text = str;
@@ -1049,10 +1049,10 @@
 	else if (undo_action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
 	{
 		gchar* str;
-		
+
 #define I (last_action->action.insert.chars - 1)
-		
-		if ((undo_action->action.insert.pos != 
+
+		if ((undo_action->action.insert.pos !=
 		     	(last_action->action.insert.pos + last_action->action.insert.chars)) ||
 		    ((g_utf8_get_char (undo_action->action.insert.text) != ' ') &&
 		      (g_utf8_get_char (undo_action->action.insert.text) != '\t') &&
@@ -1064,9 +1064,9 @@
 			return FALSE;
 		}
 
-		str = g_strdup_printf ("%s%s", last_action->action.insert.text, 
+		str = g_strdup_printf ("%s%s", last_action->action.insert.text,
 				undo_action->action.insert.text);
-		
+
 		g_free (last_action->action.insert.text);
 		last_action->action.insert.length += undo_action->action.insert.length;
 		last_action->action.insert.text = str;
@@ -1080,7 +1080,7 @@
 	else
 		/* Unknown action inside undo merge encountered */
 		g_return_val_if_reached (TRUE);
-		
+
 	return TRUE;
 }
 
@@ -1098,7 +1098,7 @@
 				  	     gint			 max_undo_levels)
 {
 	gint old_levels;
-	
+
 	g_return_if_fail (um != NULL);
 	g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
 
@@ -1107,7 +1107,7 @@
 
 	if (max_undo_levels < 1)
 		return;
-		
+
 	if (old_levels > max_undo_levels)
 	{
 		/* strip redo actions first */
@@ -1116,7 +1116,7 @@
 			gtk_source_undo_manager_free_first_n_actions (um, 1);
 			um->priv->next_redo--;
 		}
-		
+
 		/* now remove undo actions if necessary */
 		gtk_source_undo_manager_check_list_size (um);
 
@@ -1142,7 +1142,7 @@
 {
 	GtkSourceUndoAction *action;
 	GList *list;
-	
+
 	g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
 	g_return_if_fail (um->priv != NULL);
 
@@ -1157,7 +1157,7 @@
 		action = NULL;
 
 	if (gtk_text_buffer_get_modified (buffer) == FALSE)
-	{	
+	{
 		if (action != NULL)
 			action->mergeable = FALSE;
 
@@ -1178,7 +1178,7 @@
 
 		return;
 	}
-	
+
 	/* gtk_text_buffer_get_modified (buffer) == TRUE */
 
 	g_return_if_fail (um->priv->modified_action == NULL);
--- a/pidgin/gtksourceundomanager.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtksourceundomanager.h	Wed Jan 28 10:23:37 2009 +0000
@@ -4,8 +4,8 @@
  * This file is part of GtkSourceView
  *
  * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
- * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi 
- * Copyright (C) 2002, 2003 Paolo Maggi 
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002, 2003 Paolo Maggi
  *
  * 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
@@ -19,10 +19,10 @@
  *
  * 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, 
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02111-1301, USA. * *
  */
- 
+
 #ifndef __GTK_SOURCE_UNDO_MANAGER_H__
 #define __GTK_SOURCE_UNDO_MANAGER_H__
 
@@ -44,7 +44,7 @@
 struct _GtkSourceUndoManager
 {
 	GObject base;
-	
+
 	GtkSourceUndoManagerPrivate *priv;
 };
 
@@ -67,14 +67,14 @@
 void			gtk_source_undo_manager_undo 		(GtkSourceUndoManager 	*um);
 void			gtk_source_undo_manager_redo 		(GtkSourceUndoManager 	*um);
 
-void			gtk_source_undo_manager_begin_not_undoable_action 
+void			gtk_source_undo_manager_begin_not_undoable_action
 								(GtkSourceUndoManager	*um);
-void			gtk_source_undo_manager_end_not_undoable_action 
+void			gtk_source_undo_manager_end_not_undoable_action
 								(GtkSourceUndoManager	*um);
 
-gint			gtk_source_undo_manager_get_max_undo_levels 
+gint			gtk_source_undo_manager_get_max_undo_levels
 								(GtkSourceUndoManager 	*um);
-void			gtk_source_undo_manager_set_max_undo_levels 
+void			gtk_source_undo_manager_set_max_undo_levels
 								(GtkSourceUndoManager 	*um,
 				  	     			 gint		 	 undo_levels);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkstatus-icon-theme.c	Wed Jan 28 10:23:37 2009 +0000
@@ -0,0 +1,72 @@
+/*
+ * 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	Wed Jan 28 10:23:37 2009 +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/gtkstatusbox.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkstatusbox.c	Wed Jan 28 10:23:37 2009 +0000
@@ -1646,7 +1646,7 @@
 			pidgin_status_box_popdown (status_box);
 			return TRUE;
 		} else if (ewidget == status_box->toggle_button) {
-			status_box->popup_in_progress = TRUE;		
+			status_box->popup_in_progress = TRUE;
 		}
 
 		/* released outside treeview */
@@ -1698,7 +1698,7 @@
 				gtk_tree_path_free (path);
 				return ret;
 			}
-		} 
+		}
 	}
 	return FALSE;
 }
@@ -1777,9 +1777,9 @@
 	status_box->vsep = gtk_vseparator_new();
 	status_box->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
 
-	status_box->store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, 
+	status_box->store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
 					       G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN);
-	status_box->dropdown_store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING, 
+	status_box->dropdown_store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING,
 							G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN);
 
 	gtk_cell_view_set_model(GTK_CELL_VIEW(status_box->cell_view), GTK_TREE_MODEL(status_box->store));
@@ -2529,7 +2529,7 @@
 {
 	GtkTextBuffer *buffer;
 	GtkTextIter iter;
-	int wrapped_lines;
+	int display_lines;
 	int lines;
 	GdkRectangle oneline;
 	int height;
@@ -2545,28 +2545,44 @@
 	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(status_box->imhtml));
 
 	height = 0;
-	wrapped_lines = 1;
+	display_lines = 1;
 	gtk_text_buffer_get_start_iter(buffer, &iter);
 	do {
 		gtk_text_view_get_iter_location(GTK_TEXT_VIEW(status_box->imhtml), &iter, &oneline);
 		height += oneline.height;
-		wrapped_lines++;
-		if (wrapped_lines > 4)
-			break;
-	} while (gtk_text_view_forward_display_line(GTK_TEXT_VIEW(status_box->imhtml), &iter));
+		display_lines++;
+	} while (display_lines <= 4 &&
+		gtk_text_view_forward_display_line(GTK_TEXT_VIEW(status_box->imhtml), &iter));
+
+	/*
+	 * This check fixes the case where the last character entered is a
+	 * newline (shift+return).  For some reason the
+	 * gtk_text_view_forward_display_line() function doesn't treat this
+	 * like a new line, and so we think the input box only needs to be
+	 * two lines instead of three, for example.  So we check if the
+	 * last character was a newline and add some extra height if so.
+	 */
+	if (display_lines <= 4
+		&& gtk_text_iter_backward_char(&iter)
+		&& gtk_text_iter_get_char(&iter) == '\n')
+	{
+		gtk_text_view_get_iter_location(GTK_TEXT_VIEW(status_box->imhtml), &iter, &oneline);
+		height += oneline.height;
+		display_lines++;
+	}
 
 	lines = gtk_text_buffer_get_line_count(buffer);
 
 	/* Show a maximum of 4 lines */
 	lines = MIN(lines, 4);
-	wrapped_lines = MIN(wrapped_lines, 4);
+	display_lines = MIN(display_lines, 4);
 
 	pad_top = gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(status_box->imhtml));
 	pad_bottom = gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(status_box->imhtml));
 	pad_inside = gtk_text_view_get_pixels_inside_wrap(GTK_TEXT_VIEW(status_box->imhtml));
 
 	height += (pad_top + pad_bottom) * lines;
-	height += (pad_inside) * (wrapped_lines - lines);
+	height += (pad_inside) * (display_lines - lines);
 
 	gtk_widget_set_size_request(status_box->vbox, -1, height + PIDGIN_HIG_BOX_SPACE);
 }
--- a/pidgin/gtkthemes.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkthemes.c	Wed Jan 28 10:23:37 2009 +0000
@@ -83,7 +83,7 @@
 {
 	char *theme_dir = NULL, *last_slash = NULL;
 	g_return_if_fail(NULL != file);
-	
+
 	if (!g_file_test(file, G_FILE_TEST_EXISTS)) return;
 	if ((theme_dir = g_strdup(file)) == NULL) return ;
 
@@ -169,12 +169,12 @@
 	for (wer = theme->list; wer != NULL; wer = theme->list) {
 		while (wer->smileys) {
 			GtkIMHtmlSmiley *uio = wer->smileys->data;
-			
+
 			if (uio->imhtml) {
 				g_signal_handlers_disconnect_matched(uio->imhtml, G_SIGNAL_MATCH_DATA,
 					0, 0, NULL, NULL, uio);
 			}
-				
+
 			if (uio->icon)
 				g_object_unref(uio->icon);
 			if (g_hash_table_lookup(already_freed, uio->file) == NULL) {
--- a/pidgin/gtkutils.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkutils.c	Wed Jan 28 10:23:37 2009 +0000
@@ -56,6 +56,9 @@
 #include "signals.h"
 #include "util.h"
 
+#include "gtkaccount.h"
+#include "gtkprefs.h"
+
 #include "gtkconv.h"
 #include "gtkdialogs.h"
 #include "gtkimhtml.h"
@@ -71,6 +74,7 @@
 } AopMenu;
 
 static guint accels_save_timer = 0;
+static GList *gnome_url_handlers = NULL;
 
 static gboolean
 url_clicked_idle_cb(gpointer data)
@@ -80,10 +84,12 @@
 	return FALSE;
 }
 
-static void
-url_clicked_cb(GtkWidget *w, const char *uri)
+static gboolean
+url_clicked_cb(GtkIMHtml *unused, GtkIMHtmlLink *link)
 {
+	const char *uri = gtk_imhtml_link_get_url(link);
 	g_idle_add(url_clicked_idle_cb, g_strdup(uri));
+	return TRUE;
 }
 
 static GtkIMHtmlFuncs gtkimhtml_cbs = {
@@ -102,9 +108,6 @@
 	g_return_if_fail(imhtml != NULL);
 	g_return_if_fail(GTK_IS_IMHTML(imhtml));
 
-	g_signal_connect(G_OBJECT(imhtml), "url_clicked",
-					 G_CALLBACK(url_clicked_cb), NULL);
-
 	pidgin_themes_smiley_themeize(imhtml);
 
 	gtk_imhtml_set_funcs(GTK_IMHTML(imhtml), &gtkimhtml_cbs);
@@ -567,7 +570,7 @@
 	gtk_widget_show (label);
 	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-	
+
 	gtk_container_add(GTK_CONTAINER(item), hbox);
 	gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
 	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
@@ -1924,7 +1927,7 @@
 #endif /* !NEW_STYLE_COMPLETION */
 
 #ifdef NEW_STYLE_COMPLETION
-static gboolean screenname_completion_match_func(GtkEntryCompletion *completion,
+static gboolean buddyname_completion_match_func(GtkEntryCompletion *completion,
 		const gchar *key, GtkTreeIter *iter, gpointer user_data)
 {
 	GtkTreeModel *model;
@@ -1957,7 +1960,7 @@
 	return FALSE;
 }
 
-static gboolean screenname_completion_match_selected_cb(GtkEntryCompletion *completion,
+static gboolean buddyname_completion_match_selected_cb(GtkEntryCompletion *completion,
 		GtkTreeModel *model, GtkTreeIter *iter, PidginCompletionData *data)
 {
 	GValue val;
@@ -1983,22 +1986,22 @@
 }
 
 static void
-add_screenname_autocomplete_entry(GtkListStore *store, const char *buddy_alias, const char *contact_alias,
-								  const PurpleAccount *account, const char *screenname)
+add_buddyname_autocomplete_entry(GtkListStore *store, const char *buddy_alias, const char *contact_alias,
+								  const PurpleAccount *account, const char *buddyname)
 {
 	GtkTreeIter iter;
 	gboolean completion_added = FALSE;
-	gchar *normalized_screenname;
+	gchar *normalized_buddyname;
 	gchar *tmp;
 
-	tmp = g_utf8_normalize(screenname, -1, G_NORMALIZE_DEFAULT);
-	normalized_screenname = g_utf8_casefold(tmp, -1);
+	tmp = g_utf8_normalize(buddyname, -1, G_NORMALIZE_DEFAULT);
+	normalized_buddyname = g_utf8_casefold(tmp, -1);
 	g_free(tmp);
 
 	/* There's no sense listing things like: 'xxx "xxx"'
-	   when the screenname and buddy alias match. */
-	if (buddy_alias && strcmp(buddy_alias, screenname)) {
-		char *completion_entry = g_strdup_printf("%s \"%s\"", screenname, buddy_alias);
+	   when the name and buddy alias match. */
+	if (buddy_alias && strcmp(buddy_alias, buddyname)) {
+		char *completion_entry = g_strdup_printf("%s \"%s\"", buddyname, buddy_alias);
 		char *tmp2 = g_utf8_normalize(buddy_alias, -1, G_NORMALIZE_DEFAULT);
 
 		tmp = g_utf8_casefold(tmp2, -1);
@@ -2007,8 +2010,8 @@
 		gtk_list_store_append(store, &iter);
 		gtk_list_store_set(store, &iter,
 				0, completion_entry,
-				1, screenname,
-				2, normalized_screenname,
+				1, buddyname,
+				2, normalized_buddyname,
 				3, tmp,
 				4, account,
 				-1);
@@ -2018,12 +2021,12 @@
 	}
 
 	/* There's no sense listing things like: 'xxx "xxx"'
-	   when the screenname and contact alias match. */
-	if (contact_alias && strcmp(contact_alias, screenname)) {
+	   when the name and contact alias match. */
+	if (contact_alias && strcmp(contact_alias, buddyname)) {
 		/* We don't want duplicates when the contact and buddy alias match. */
 		if (!buddy_alias || strcmp(contact_alias, buddy_alias)) {
 			char *completion_entry = g_strdup_printf("%s \"%s\"",
-							screenname, contact_alias);
+							buddyname, contact_alias);
 			char *tmp2 = g_utf8_normalize(contact_alias, -1, G_NORMALIZE_DEFAULT);
 
 			tmp = g_utf8_casefold(tmp2, -1);
@@ -2032,8 +2035,8 @@
 			gtk_list_store_append(store, &iter);
 			gtk_list_store_set(store, &iter,
 					0, completion_entry,
-					1, screenname,
-					2, normalized_screenname,
+					1, buddyname,
+					2, normalized_buddyname,
 					3, tmp,
 					4, account,
 					-1);
@@ -2044,18 +2047,18 @@
 	}
 
 	if (completion_added == FALSE) {
-		/* Add the buddy's screenname. */
+		/* Add the buddy's name. */
 		gtk_list_store_append(store, &iter);
 		gtk_list_store_set(store, &iter,
-				0, screenname,
-				1, screenname,
-				2, normalized_screenname,
+				0, buddyname,
+				1, buddyname,
+				2, normalized_buddyname,
 				3, NULL,
 				4, account,
 				-1);
 	}
 
-	g_free(normalized_screenname);
+	g_free(normalized_buddyname);
 }
 #endif /* NEW_STYLE_COMPLETION */
 
@@ -2064,8 +2067,8 @@
 	PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func;
 	gpointer user_data = data->filter_func_user_data;
 
- 	/* 1. Don't show buddies because we will have gotten them already.
- 	 * 2. The boxes that use this autocomplete code handle only IMs. */
+	/* 1. Don't show buddies because we will have gotten them already.
+	 * 2. The boxes that use this autocomplete code handle only IMs. */
 	if (!set->buddy && set->type == PURPLE_LOG_IM) {
 		PidginBuddyCompletionEntry entry;
 		entry.is_buddy = FALSE;
@@ -2073,7 +2076,7 @@
 
 		if (filter_func(&entry, user_data)) {
 #ifdef NEW_STYLE_COMPLETION
-			add_screenname_autocomplete_entry(data->store,
+			add_buddyname_autocomplete_entry(data->store,
 												NULL, NULL, set->account, set->name);
 #else
 			/* Steal the name for the GCompletion. */
@@ -2119,7 +2122,7 @@
 
 				if (filter_func(&entry, user_data)) {
 #ifdef NEW_STYLE_COMPLETION
-					add_screenname_autocomplete_entry(data->store,
+					add_buddyname_autocomplete_entry(data->store,
 														((PurpleContact *)cnode)->alias,
 														purple_buddy_get_contact_alias(entry.entry.buddy),
 														entry.entry.buddy->account,
@@ -2150,7 +2153,7 @@
 }
 
 static void
-screenname_autocomplete_destroyed_cb(GtkWidget *widget, gpointer data)
+buddyname_autocomplete_destroyed_cb(GtkWidget *widget, gpointer data)
 {
 	g_free(data);
 	purple_signals_disconnect_by_handle(widget);
@@ -2162,15 +2165,17 @@
 	add_completion_list(data);
 }
 
-
 void
 pidgin_setup_screenname_autocomplete_with_filter(GtkWidget *entry, GtkWidget *accountopt, PidginFilterBuddyCompletionEntryFunc filter_func, gpointer user_data)
 {
 	PidginCompletionData *data;
 
 #ifdef NEW_STYLE_COMPLETION
-	/* Store the displayed completion value, the screenname, the UTF-8 normalized & casefolded screenname,
-	 * the UTF-8 normalized & casefolded value for comparison, and the account. */
+	/*
+	 * Store the displayed completion value, the buddy name, the UTF-8
+	 * normalized & casefolded buddy name, the UTF-8 normalized &
+	 * casefolded value for comparison, and the account.
+	 */
 	GtkListStore *store;
 
 	GtkEntryCompletion *completion;
@@ -2191,15 +2196,15 @@
 
 	add_completion_list(data);
 
-	/* Sort the completion list by screenname. */
+	/* Sort the completion list by buddy name */
 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
 	                                     1, GTK_SORT_ASCENDING);
 
 	completion = gtk_entry_completion_new();
-	gtk_entry_completion_set_match_func(completion, screenname_completion_match_func, NULL, NULL);
+	gtk_entry_completion_set_match_func(completion, buddyname_completion_match_func, NULL, NULL);
 
 	g_signal_connect(G_OBJECT(completion), "match-selected",
-		G_CALLBACK(screenname_completion_match_selected_cb), data);
+		G_CALLBACK(buddyname_completion_match_selected_cb), data);
 
 	gtk_entry_set_completion(GTK_ENTRY(entry), completion);
 	g_object_unref(completion);
@@ -2246,7 +2251,7 @@
 	purple_signal_connect(purple_accounts_get_handle(), "account-removed", entry,
 						PURPLE_CALLBACK(repopulate_autocomplete), data);
 
-	g_signal_connect(G_OBJECT(entry), "destroy", G_CALLBACK(screenname_autocomplete_destroyed_cb), data);
+	g_signal_connect(G_OBJECT(entry), "destroy", G_CALLBACK(buddyname_autocomplete_destroyed_cb), data);
 }
 
 gboolean
@@ -3240,7 +3245,7 @@
  	style = gtk_widget_get_style(widget);
 	if (!style)
 		return "dim grey";
-	
+
 	snprintf(dim_grey_string, sizeof(dim_grey_string), "#%02x%02x%02x",
 	style->text_aa[GTK_STATE_NORMAL].red >> 8,
 	style->text_aa[GTK_STATE_NORMAL].green >> 8,
@@ -3480,3 +3485,198 @@
 	return pixbuf;
 }
 
+static void url_copy(GtkWidget *w, gchar *url)
+{
+	GtkClipboard *clipboard;
+
+	clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_PRIMARY);
+	gtk_clipboard_set_text(clipboard, url, -1);
+
+	clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_CLIPBOARD);
+	gtk_clipboard_set_text(clipboard, url, -1);
+}
+
+static gboolean
+link_context_menu(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu)
+{
+	GtkWidget *img, *item;
+	const char *url;
+
+	url = gtk_imhtml_link_get_url(link);
+
+	/* Open Link */
+	img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU);
+	item = gtk_image_menu_item_new_with_mnemonic(_("_Open Link"));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
+	g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link);
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+	/* Copy Link Location */
+	img = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
+	item = gtk_image_menu_item_new_with_mnemonic(_("_Copy Link Location"));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
+	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_copy), (gpointer)url);
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+	return TRUE;
+}
+
+static gboolean
+copy_email_address(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu)
+{
+	GtkWidget *img, *item;
+	const char *text;
+	char *address;
+#define MAILTOSIZE  (sizeof("mailto:") - 1)
+
+	text = gtk_imhtml_link_get_url(link);
+	g_return_val_if_fail(text && strlen(text) > MAILTOSIZE, FALSE);
+	address = (char*)text + MAILTOSIZE;
+
+	/* Copy Email Address */
+	img = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
+	item = gtk_image_menu_item_new_with_mnemonic(_("_Copy Email Address"));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
+	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_copy), address);
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+	return TRUE;
+}
+
+/* XXX: The following two functions are for demonstration purposes only! */
+static gboolean
+open_dialog(GtkIMHtml *imhtml, GtkIMHtmlLink *link)
+{
+	const char *url;
+	const char *str;
+
+	url = gtk_imhtml_link_get_url(link);
+	if (!url || strlen(url) < sizeof("open://"))
+		return FALSE;
+
+	str = url + sizeof("open://") - 1;
+
+	if (strcmp(str, "accounts") == 0)
+		pidgin_accounts_window_show();
+	else if (strcmp(str, "prefs") == 0)
+		pidgin_prefs_show();
+	else
+		return FALSE;
+	return TRUE;
+}
+
+static gboolean
+dummy(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu)
+{
+	return TRUE;
+}
+
+static gboolean
+register_gnome_url_handlers(void)
+{
+	char *tmp;
+	char *err;
+	char *c;
+	char *start;
+
+	tmp = g_find_program_in_path("gconftool-2");
+	if (tmp == NULL)
+		return FALSE;
+
+	tmp = NULL;
+	if (!g_spawn_command_line_sync("gconftool-2 --all-dirs /desktop/gnome/url-handlers",
+	                               &tmp, &err, NULL, NULL))
+	{
+		g_free(tmp);
+		g_free(err);
+		g_return_val_if_reached(FALSE);
+	}
+	g_free(err);
+	err = NULL;
+
+	for (c = start = tmp ; *c ; c++)
+	{
+		/* Skip leading spaces. */
+		if (c == start && *c == ' ')
+			start = c + 1;
+		else if (*c == '\n')
+		{
+			*c = '\0';
+			if (g_str_has_prefix(start, "/desktop/gnome/url-handlers/"))
+			{
+				char *cmd;
+				char *tmp2 = NULL;
+				char *protocol;
+
+				/* If there is an enabled boolean, honor it. */
+				cmd = g_strdup_printf("gconftool-2 -g %s/enabled", start);
+				if (g_spawn_command_line_sync(cmd, &tmp2, &err, NULL, NULL))
+				{
+					g_free(err);
+					err = NULL;
+					if (!strcmp(tmp2, "false\n"))
+					{
+						g_free(tmp2);
+						g_free(cmd);
+						start = c + 1;
+						continue;
+					}
+				}
+				g_free(cmd);
+				g_free(tmp2);
+
+				start += sizeof("/desktop/gnome/url-handlers/") - 1;
+
+				protocol = g_strdup_printf("%s:", start);
+				gnome_url_handlers = g_list_prepend(gnome_url_handlers, protocol);
+				gtk_imhtml_class_register_protocol(protocol, url_clicked_cb, link_context_menu);
+			}
+			start = c + 1;
+		}
+	}
+	g_free(tmp);
+
+	return (gnome_url_handlers != NULL);
+}
+
+void pidgin_utils_init(void)
+{
+	gtk_imhtml_class_register_protocol("http://", url_clicked_cb, link_context_menu);
+	gtk_imhtml_class_register_protocol("https://", url_clicked_cb, link_context_menu);
+	gtk_imhtml_class_register_protocol("ftp://", url_clicked_cb, link_context_menu);
+	gtk_imhtml_class_register_protocol("gopher://", url_clicked_cb, link_context_menu);
+	gtk_imhtml_class_register_protocol("mailto:", url_clicked_cb, copy_email_address);
+
+	/* Example custom URL handler. */
+	gtk_imhtml_class_register_protocol("open://", open_dialog, dummy);
+
+	/* If we're under GNOME, try registering the system URL handlers. */
+	if (purple_running_gnome())
+		register_gnome_url_handlers();
+}
+
+void pidgin_utils_uninit(void)
+{
+	gtk_imhtml_class_register_protocol("open://", NULL, NULL);
+
+	/* If we have GNOME handlers registered, unregister them. */
+	if (gnome_url_handlers)
+	{
+		GList *l;
+		for (l = gnome_url_handlers ; l ; l = l->next)
+		{
+			gtk_imhtml_class_register_protocol((char *)l->data, NULL, NULL);
+			g_free(l->data);
+		}
+		g_list_free(gnome_url_handlers);
+		gnome_url_handlers = NULL;
+		return;
+	}
+
+	gtk_imhtml_class_register_protocol("http://", NULL, NULL);
+	gtk_imhtml_class_register_protocol("https://", NULL, NULL);
+	gtk_imhtml_class_register_protocol("ftp://", NULL, NULL);
+	gtk_imhtml_class_register_protocol("mailto:", NULL, NULL);
+	gtk_imhtml_class_register_protocol("gopher://", NULL, NULL);
+}
+
--- a/pidgin/gtkutils.h	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkutils.h	Wed Jan 28 10:23:37 2009 +0000
@@ -136,7 +136,7 @@
  * Retrieves the main content box (vbox) from a pidgin dialog window
  *
  * @param dialog       The dialog window
- * @param homogeneous  TRUE if all children are to be given equal space allotments. 
+ * @param homogeneous  TRUE if all children are to be given equal space allotments.
  * @param spacing      the number of pixels to place by default between children
  *
  * @since 2.4.0
@@ -184,8 +184,8 @@
 void pidgin_toggle_sensitive(GtkWidget *widget, GtkWidget *to_toggle);
 
 /**
- * Checks if text has been entered into a GtkTextEntry widget.  If 
- * so, the GTK_RESPONSE_OK on the given dialog is set to TRUE.  
+ * Checks if text has been entered into a GtkTextEntry widget.  If
+ * so, the GTK_RESPONSE_OK on the given dialog is set to TRUE.
  * Otherwise GTK_RESPONSE_OK is set to FALSE.
  *
  * @param entry  The text entry widget.
@@ -355,7 +355,7 @@
  *
  * @param entry       The GtkEntry on which to setup autocomplete.
  * @param optmenu     A menu for accounts, returned by gaim_gtk_account_option_menu_new().
- *                    If @a optmenu is not @c NULL, it'll be updated when a screenname is chosen
+ *                    If @a optmenu is not @c NULL, it'll be updated when a username is chosen
  *                    from the autocomplete list.
  * @param filter_func A function for checking if an autocomplete entry
  *                    should be shown. This can be @c NULL.
@@ -364,7 +364,7 @@
 void pidgin_setup_screenname_autocomplete_with_filter(GtkWidget *entry, GtkWidget *optmenu, PidginFilterBuddyCompletionEntryFunc filter_func, gpointer user_data);
 
 /**
- * The default filter function for screenname autocomplete.
+ * The default filter function for username autocomplete.
  *
  * @param completion_entry The completion entry to filter.
  * @param all_accounts  If this is @c FALSE, only the autocompletion entries
@@ -385,9 +385,9 @@
  * @param entry     The GtkEntry on which to setup autocomplete.
  * @param optmenu   A menu for accounts, returned by
  *                  pidgin_account_option_menu_new().  If @a optmenu is not @c
- *                  NULL, it'll be updated when a screenname is chosen from the
+ *                  NULL, it'll be updated when a username is chosen from the
  *                  autocomplete list.
- * @param all       Whether to include screennames from disconnected accounts.
+ * @param all       Whether to include usernames from disconnected accounts.
  */
 void pidgin_setup_screenname_autocomplete(GtkWidget *entry, GtkWidget *optmenu, gboolean all);
 
@@ -473,7 +473,7 @@
 									 char **ret_alias);
 
 /**
- * Sets an ATK name for a given widget.  Also sets the labelled-by 
+ * Sets an ATK name for a given widget.  Also sets the labelled-by
  * and label-for ATK relationships.
  *
  * @param w The widget that we want to name.
@@ -509,10 +509,10 @@
 										gboolean *push_in, gpointer data);
 
 /**
- * A valid GtkMenuPositionFunc.  This is used to determine where 
- * to draw context menus when the menu is activated with the 
- * keyboard (shift+F10).  If the menu is activated with the mouse, 
- * then you should just use GTK's built-in position function, 
+ * A valid GtkMenuPositionFunc.  This is used to determine where
+ * to draw context menus when the menu is activated with the
+ * keyboard (shift+F10).  If the menu is activated with the mouse,
+ * then you should just use GTK's built-in position function,
  * because it does a better job of positioning the menu.
  *
  * @param menu The menu we are positioning.
@@ -612,13 +612,13 @@
  * @param parent      The parent window
  * @param callback    The callback to call when the window is closed. If the user chose an icon, the char* argument will point to its path
  * @param data        Data to pass to @a callback
- * @return            The file dialog 
+ * @return            The file dialog
  */
 GtkWidget *pidgin_buddy_icon_chooser_new(GtkWindow *parent, void(*callback)(const char*,gpointer), gpointer data);
 
 /**
  * Converts a buddy icon to the required size and format
- * 
+ *
  * @param plugin     The prpl to convert the icon
  * @param path       The path of a file to convert
  * @param len        If not @c NULL, the length of the returned data will be set here.
@@ -706,7 +706,7 @@
 			const gchar *key, GtkTreeIter *iter, gpointer data);
 
 /**
- * Sets or resets a window to 'urgent,' by setting the URGENT hint in X 
+ * Sets or resets a window to 'urgent,' by setting the URGENT hint in X
  * or blinking in the win32 taskbar
  *
  * @param window  The window to draw attention to
@@ -792,7 +792,8 @@
  *
  * @param window    The window to make transient.
  *
- * @return  Whether the window was made transient or not.
+ * @return Whether the window was made transient or not.
+ *
  * @since 2.4.0
  */
 gboolean pidgin_auto_parent_window(GtkWidget *window);
@@ -818,9 +819,24 @@
  * @param  image   A PurpleStoredImage.
  *
  * @return   A GdkPixbuf created from the stored image.
+ *
  * @since 2.5.0
  */
-GdkPixbuf * pidgin_pixbuf_from_imgstore(PurpleStoredImage *image);
+GdkPixbuf *pidgin_pixbuf_from_imgstore(PurpleStoredImage *image);
+
+/**
+ * Initialize some utility functions.
+ *
+ * @since 2.6.0
+ */
+void pidgin_utils_init(void);
+
+/**
+ * Uninitialize some utility functions.
+ *
+ * @since 2.6.0
+ */
+void pidgin_utils_uninit(void);
 
 #endif /* _PIDGINUTILS_H_ */
 
--- a/pidgin/gtkwhiteboard.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/gtkwhiteboard.c	Wed Jan 28 10:23:37 2009 +0000
@@ -857,7 +857,7 @@
 {
 	GdkColor color;
 	GtkColorSelectionDialog *dialog;
-	
+
 	dialog = (GtkColorSelectionDialog *)gtk_color_selection_dialog_new(_("Select color"));
 
 	g_signal_connect(G_OBJECT(dialog->colorsel), "color-changed",
--- a/pidgin/pidgincombobox.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/pidgincombobox.c	Wed Jan 28 10:23:37 2009 +0000
@@ -112,7 +112,7 @@
 /* While debugging this evil code, I have learned that
  * there are actually 4 modes to this widget, which can
  * be characterized as follows
- * 
+ *
  * 1) menu mode, no child added
  *
  * tree_view -> NULL
@@ -127,9 +127,9 @@
  * popup_frame -> NULL
  *
  * 2) menu mode, child added
- * 
+ *
  * tree_view -> NULL
- * cell_view -> NULL 
+ * cell_view -> NULL
  * cell_view_frame -> NULL
  * button -> GtkToggleButton set_parent to combo
  * box -> NULL
@@ -140,7 +140,7 @@
  * popup_frame -> NULL
  *
  * 3) list mode, no child added
- * 
+ *
  * tree_view -> GtkTreeView, child of popup_frame
  * cell_view -> GtkCellView, regular child
  * cell_view_frame -> GtkFrame, set parent to combo
@@ -164,7 +164,7 @@
  * popup_widget -> tree_view
  * popup_window -> GtkWindow
  * popup_frame -> GtkFrame, child of popup_window
- * 
+ *
  */
 
 enum {
@@ -285,9 +285,9 @@
 						    gpointer          data);
 
 /* list */
-static void     gtk_combo_box_list_position        (GtkComboBox      *combo_box, 
-						    gint             *x, 
-						    gint             *y, 
+static void     gtk_combo_box_list_position        (GtkComboBox      *combo_box,
+						    gint             *x,
+						    gint             *y,
 						    gint             *width,
 						    gint             *height);
 
@@ -641,7 +641,7 @@
   if (GTK_WIDGET_REALIZED (widget))
     {
       if (combo_box->priv->tree_view && combo_box->priv->cell_view)
-	gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view), 
+	gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view),
 					    &widget->style->base[GTK_WIDGET_STATE (widget)]);
     }
 
@@ -694,7 +694,7 @@
   gtk_combo_box_check_appearance (combo_box);
 
   if (combo_box->priv->tree_view && combo_box->priv->cell_view)
-    gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view), 
+    gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view),
 					&widget->style->base[GTK_WIDGET_STATE (widget)]);
 }
 
@@ -725,7 +725,7 @@
       GTK_BIN (container)->child = NULL;
       gtk_widget_queue_resize (GTK_WIDGET (container));
     }
-  
+
   gtk_widget_set_parent (widget, GTK_WIDGET (container));
   GTK_BIN (container)->child = widget;
 
@@ -770,7 +770,7 @@
     appears_as_list = FALSE;
   else
     appears_as_list = TRUE;
-  
+
   if (appears_as_list)
     gtk_combo_box_list_destroy (combo_box);
   else if (GTK_IS_MENU (combo_box->priv->popup_widget))
@@ -785,7 +785,7 @@
       combo_box->priv->cell_view = gtk_cell_view_new ();
       gtk_widget_set_parent (combo_box->priv->cell_view, GTK_WIDGET (container));
       GTK_BIN (container)->child = combo_box->priv->cell_view;
-      
+
       gtk_widget_show (combo_box->priv->cell_view);
       gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view),
 			       combo_box->priv->model);
@@ -856,7 +856,7 @@
   g_signal_handlers_disconnect_by_func (menu,
 					gtk_combo_box_menu_hide,
 					combo_box);
-  
+
   combo_box->priv->popup_widget = NULL;
 }
 
@@ -940,12 +940,12 @@
   GdkScreen *screen;
   gint monitor_num;
   GdkRectangle monitor;
-  
+
   /* FIXME: is using the size request here broken? */
    child = GTK_BIN (combo_box)->child;
-   
+
    gdk_window_get_origin (child->window, &sx, &sy);
-   
+
    if (GTK_WIDGET_NO_WINDOW (child))
       {
 	sx += child->allocation.x;
@@ -961,20 +961,20 @@
    *y = sy;
 
   screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
-  monitor_num = gdk_screen_get_monitor_at_window (screen, 
+  monitor_num = gdk_screen_get_monitor_at_window (screen,
 						  GTK_WIDGET (combo_box)->window);
   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
-  
+
   if (*x < monitor.x)
     *x = monitor.x;
   else if (*x + req.width > monitor.x + monitor.width)
     *x = monitor.x + monitor.width - req.width;
-  
+
   if (monitor.y + monitor.height - *y - child->allocation.height >= req.height)
     *y += child->allocation.height;
   else if (*y - monitor.y >= req.height)
     *y -= req.height;
-  else if (monitor.y + monitor.height - *y - child->allocation.height > *y - monitor.y) 
+  else if (monitor.y + monitor.height - *y - child->allocation.height > *y - monitor.y)
     *y += child->allocation.height;
   else
     *y -= req.height;
@@ -1001,7 +1001,7 @@
   gint menu_width;
 
   g_return_if_fail (GTK_IS_COMBO_BOX (user_data));
-  
+
   combo_box = GTK_COMBO_BOX (user_data);
   widget = GTK_WIDGET (combo_box);
 
@@ -1042,7 +1042,7 @@
 
   /* Clamp the position on screen */
   screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget));
-  
+
   if (menu_xpos < 0)
     menu_xpos = 0;
   else if ((menu_xpos + menu_width) > screen_width)
@@ -1066,13 +1066,13 @@
 
   combo_box = GTK_COMBO_BOX (user_data);
 
-  if (combo_box->priv->wrap_width > 0 || combo_box->priv->cell_view == NULL)	
+  if (combo_box->priv->wrap_width > 0 || combo_box->priv->cell_view == NULL)
     gtk_combo_box_menu_position_below (menu, x, y, push_in, user_data);
   else
     {
       menu_item = gtk_menu_get_active (GTK_MENU (combo_box->priv->popup_widget));
       if (menu_item)
-	gtk_menu_shell_select_item (GTK_MENU_SHELL (combo_box->priv->popup_widget), 
+	gtk_menu_shell_select_item (GTK_MENU_SHELL (combo_box->priv->popup_widget),
 				    menu_item);
 
       gtk_combo_box_menu_position_over (menu, x, y, push_in, user_data);
@@ -1082,9 +1082,9 @@
 #endif /* Gtk 2.2 */
 
 static void
-gtk_combo_box_list_position (GtkComboBox *combo_box, 
-			     gint        *x, 
-			     gint        *y, 
+gtk_combo_box_list_position (GtkComboBox *combo_box,
+			     gint        *x,
+			     gint        *y,
 			     gint        *width,
 			     gint        *height)
 {
@@ -1095,7 +1095,7 @@
   gint monitor_num;
   GdkRectangle monitor;
 #endif
-  
+
   sample = GTK_BIN (combo_box)->child;
 
   *width = sample->allocation.width;
@@ -1117,30 +1117,30 @@
       *x += sample->allocation.x;
       *y += sample->allocation.y;
     }
-  
+
 #if GTK_CHECK_VERSION(2,2,0)
   screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
-  monitor_num = gdk_screen_get_monitor_at_window (screen, 
+  monitor_num = gdk_screen_get_monitor_at_window (screen,
 						  GTK_WIDGET (combo_box)->window);
   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
-  
+
   if (*x < monitor.x)
     *x = monitor.x;
   else if (*x + *width > monitor.x + monitor.width)
     *x = monitor.x + monitor.width - *width;
-  
+
   if (*y + sample->allocation.height + *height <= monitor.y + monitor.height)
     *y += sample->allocation.height;
   else
     *y -= *height;
 #endif /* Gtk 2.2 */
-} 
+}
 
 /**
  * gtk_combo_box_popup:
  * @combo_box: a #GtkComboBox
- * 
- * Pops up the menu or dropdown list of @combo_box. 
+ *
+ * Pops up the menu or dropdown list of @combo_box.
  *
  * This function is mostly intended for use by accessibility technologies;
  * applications should have little use for it.
@@ -1151,7 +1151,7 @@
 gtk_combo_box_popup (GtkComboBox *combo_box)
 {
   gint x, y, width, height;
-  
+
   g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
 
   if (GTK_WIDGET_MAPPED (combo_box->priv->popup_widget))
@@ -1172,7 +1172,7 @@
 	  gtk_widget_set_size_request (combo_box->priv->popup_widget,
                                        MAX (width, requisition.width), -1);
 	}
-      
+
       gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
 		      NULL, NULL,
 #if GTK_CHECK_VERSION(2,2,0)
@@ -1187,7 +1187,7 @@
   gtk_widget_show_all (combo_box->priv->popup_frame);
   gtk_combo_box_list_position (combo_box, &x, &y, &width, &height);
 
-  gtk_widget_set_size_request (combo_box->priv->popup_window, width, -1);  
+  gtk_widget_set_size_request (combo_box->priv->popup_window, width, -1);
   gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window), x, y);
 
   /* popup */
@@ -1217,7 +1217,7 @@
 /**
  * gtk_combo_box_popdown:
  * @combo_box: a #GtkComboBox
- * 
+ *
  * Hides the menu or dropdown list of @combo_box.
  *
  * This function is mostly intended for use by accessibility technologies;
@@ -1305,7 +1305,7 @@
       GtkRequisition req;
 
       if (combo_box->priv->cell_view)
-	gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view), 
+	gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
                                        path, &req);
       else
         req.width = 0;
@@ -1335,7 +1335,7 @@
   bin_req.width = MAX (bin_req.width, combo_box->priv->width);
 
   gtk_combo_box_check_appearance (combo_box);
-      
+
   if (!combo_box->priv->tree_view)
     {
       /* menu mode */
@@ -1454,10 +1454,10 @@
           if (is_rtl)
             {
               child.x += req.width;
-              child.width = MAX(1, allocation->x + allocation->width 
+              child.width = MAX(1, allocation->x + allocation->width
                 - (border_width + 1 + xthickness + 2) - child.x);
             }
-          else 
+          else
             {
               child.width = child.x;
               child.x = allocation->x + border_width + 1 + xthickness + 2;
@@ -1623,16 +1623,16 @@
   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
   gint index;
   gint items;
-    
+
   index = gtk_combo_box_get_active (combo_box);
 
   if (index != -1)
     {
       items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
-      
+
       if (event->direction == GDK_SCROLL_UP)
         index--;
-      else 
+      else
         index++;
 
       gtk_combo_box_set_active (combo_box, CLAMP (index, 0, items - 1));
@@ -1694,15 +1694,15 @@
                              GTK_BIN (combo_box)->child->parent);
 
       combo_box->priv->box = gtk_hbox_new (FALSE, 0);
-      gtk_container_add (GTK_CONTAINER (combo_box->priv->button), 
+      gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
 			 combo_box->priv->box);
 
       combo_box->priv->separator = gtk_vseparator_new ();
-      gtk_container_add (GTK_CONTAINER (combo_box->priv->box), 
+      gtk_container_add (GTK_CONTAINER (combo_box->priv->box),
 			 combo_box->priv->separator);
 
       combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
-      gtk_container_add (GTK_CONTAINER (combo_box->priv->box), 
+      gtk_container_add (GTK_CONTAINER (combo_box->priv->box),
 			 combo_box->priv->arrow);
 
       gtk_widget_show_all (combo_box->priv->button);
@@ -1792,7 +1792,7 @@
 
   /* unparent will remove our latest ref */
   gtk_widget_unparent (combo_box->priv->button);
-  
+
   combo_box->priv->box = NULL;
   combo_box->priv->button = NULL;
   combo_box->priv->arrow = NULL;
@@ -1895,17 +1895,17 @@
   item = nth->data;
   if (nth->prev)
     last = nth->prev->data;
-  else 
+  else
     last = NULL;
   g_list_free (list);
 
   gtk_combo_box_item_get_size (combo_box, index, &cols, &rows);
-      
+
    if (combo_box->priv->col_column == -1 &&
       combo_box->priv->row_column == -1 &&
       last)
     {
-      gtk_container_child_get (GTK_CONTAINER (menu), 
+      gtk_container_child_get (GTK_CONTAINER (menu),
 			       last,
 			       "right_attach", &current_col,
 			       "top_attach", &current_row,
@@ -1926,12 +1926,12 @@
 	      current_col = 0;
 	      current_row++;
 	    }
-	  
+
 	  if (!menu_occupied (GTK_MENU (menu),
 			      current_col, current_col + cols,
 			      current_row, current_row + rows))
 	    break;
-	  
+
 	  current_col++;
 	}
     }
@@ -1949,19 +1949,19 @@
   GtkWidget *menu;
 
   menu = combo_box->priv->popup_widget;
-  
+
   /* do nothing unless we are in menu style and realized */
   if (combo_box->priv->tree_view || !GTK_IS_MENU_SHELL (menu))
     return;
-  
+
   /* get rid of all children */
   list = gtk_container_get_children (GTK_CONTAINER (menu));
-  
+
   for (j = g_list_last (list); j; j = j->prev)
     gtk_container_remove (GTK_CONTAINER (menu), j->data);
-  
+
   g_list_free (list);
-      
+
   /* and relayout */
   gtk_combo_box_menu_fill (combo_box);
 }
@@ -1980,7 +1980,7 @@
   if (event->type == GDK_BUTTON_PRESS && event->button == 1)
     {
       combo_box->priv->popup_in_progress = TRUE;
-      
+
       gtk_menu_set_active (GTK_MENU (combo_box->priv->popup_widget),
 			   combo_box->priv->active_item);
 
@@ -2053,7 +2053,7 @@
 
   if (!combo_box->priv->tree_view)
     gtk_combo_box_menu_row_deleted (model, path, user_data);
-  
+
   if (index == combo_box->priv->active_item)
     {
       gint items = gtk_tree_model_iter_n_children (model, NULL);
@@ -2090,7 +2090,7 @@
   if (!combo_box->priv->tree_view)
     gtk_combo_box_menu_rows_reordered (model, path, iter, new_order, user_data);
 }
-						    
+
 static void
 gtk_combo_box_model_row_changed (GtkTreeModel     *model,
 				 GtkTreePath      *path,
@@ -2103,7 +2103,7 @@
   if (index == combo_box->priv->active_item &&
       combo_box->priv->cell_view)
     gtk_widget_queue_resize (GTK_WIDGET (combo_box->priv->cell_view));
-  
+
   if (combo_box->priv->tree_view)
     gtk_combo_box_list_row_changed (model, path, iter, user_data);
   else
@@ -2174,7 +2174,7 @@
 
   gtk_combo_box_relayout (combo_box);
 }
-				    
+
 static void
 gtk_combo_box_menu_row_changed (GtkTreeModel *model,
                                 GtkTreePath  *path,
@@ -2238,12 +2238,12 @@
       gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->cell_view_frame),
                                  GTK_SHADOW_IN);
 
-      gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view), 
+      gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view),
 					  &GTK_WIDGET (combo_box)->style->base[GTK_WIDGET_STATE (combo_box)]);
 
       combo_box->priv->box = gtk_event_box_new ();
       /*
-      gtk_event_box_set_visible_window (GTK_EVENT_BOX (combo_box->priv->box), 
+      gtk_event_box_set_visible_window (GTK_EVENT_BOX (combo_box->priv->box),
 					FALSE);
       */
 
@@ -2253,7 +2253,7 @@
       gtk_widget_show_all (combo_box->priv->cell_view_frame);
 
       g_signal_connect (combo_box->priv->box, "button_press_event",
-			G_CALLBACK (gtk_combo_box_list_button_pressed), 
+			G_CALLBACK (gtk_combo_box_list_button_pressed),
 			combo_box);
     }
 
@@ -2269,7 +2269,7 @@
   if (combo_box->priv->model)
     gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
 			     combo_box->priv->model);
-    
+
   g_signal_connect (combo_box->priv->tree_view, "button_press_event",
                     G_CALLBACK (gtk_combo_box_list_button_pressed),
                     combo_box);
@@ -2494,7 +2494,7 @@
   if (combo_box->priv->model)
     items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
 
-  if ((event->keyval == GDK_Down || event->keyval == GDK_KP_Down) && 
+  if ((event->keyval == GDK_Down || event->keyval == GDK_KP_Down) &&
       state == GDK_MOD1_MASK)
     {
       gtk_combo_box_popup (combo_box);
@@ -2502,7 +2502,7 @@
       return TRUE;
     }
 
-  switch (event->keyval) 
+  switch (event->keyval)
     {
     case GDK_Down:
     case GDK_KP_Down:
@@ -2514,20 +2514,20 @@
       break;
     case GDK_Page_Up:
     case GDK_KP_Page_Up:
-    case GDK_Home: 
+    case GDK_Home:
     case GDK_KP_Home:
       new_index = 0;
       break;
     case GDK_Page_Down:
     case GDK_KP_Page_Down:
-    case GDK_End: 
+    case GDK_End:
     case GDK_KP_End:
       new_index = items - 1;
       break;
     default:
       return FALSE;
     }
-      
+
   if (items > 0)
     gtk_combo_box_set_active (combo_box, CLAMP (new_index, 0, items - 1));
 
@@ -2542,14 +2542,14 @@
   GtkComboBox *combo_box = GTK_COMBO_BOX (data);
   guint state = event->state & gtk_accelerator_get_default_mod_mask ();
 
-  if ((event->keyval == GDK_Up || event->keyval == GDK_KP_Up) && 
+  if ((event->keyval == GDK_Up || event->keyval == GDK_KP_Up) &&
       state == GDK_MOD1_MASK)
     {
       gtk_combo_box_popdown (combo_box);
 
       return TRUE;
     }
-  
+
   return FALSE;
 }
 
@@ -2562,35 +2562,35 @@
   guint state = event->state & gtk_accelerator_get_default_mod_mask ();
 
   if (event->keyval == GDK_Escape ||
-      ((event->keyval == GDK_Up || event->keyval == GDK_KP_Up) && 
+      ((event->keyval == GDK_Up || event->keyval == GDK_KP_Up) &&
        state == GDK_MOD1_MASK))
     {
       /* reset active item -- this is incredibly lame and ugly */
       gtk_combo_box_set_active (combo_box,
 				gtk_combo_box_get_active (combo_box));
-      
+
       gtk_combo_box_popdown (combo_box);
-      
+
       return TRUE;
     }
-    
+
   if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ||
-      event->keyval == GDK_space || event->keyval == GDK_KP_Space) 
+      event->keyval == GDK_space || event->keyval == GDK_KP_Space)
   {
     gboolean ret = FALSE;
     GtkTreeIter iter;
     GtkTreeModel *model = NULL;
-    
+
     if (combo_box->priv->model)
       {
 	GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
-    
+
 	ret = gtk_tree_selection_get_selected (sel, &model, &iter);
       }
     if (ret)
       {
 	GtkTreePath *path;
-	
+
 	path = gtk_tree_model_get_path (model, &iter);
 	if (path)
 	  {
@@ -2600,7 +2600,7 @@
       }
 
     gtk_combo_box_popdown (combo_box);
-    
+
     return TRUE;
   }
 
@@ -2620,7 +2620,7 @@
 
   if (width > combo_box->priv->width)
     {
-      if (combo_box->priv->cell_view) 
+      if (combo_box->priv->cell_view)
 	{
 	  gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
 	  gtk_widget_queue_resize (combo_box->priv->cell_view);
@@ -2742,11 +2742,11 @@
   GtkWidget *menu;
   GtkComboBox *combo_box;
   GSList *i;
-  
+
   g_return_if_fail (GTK_IS_COMBO_BOX (layout));
 
   combo_box = GTK_COMBO_BOX (layout);
- 
+
   if (combo_box->priv->cell_view)
     gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box->priv->cell_view));
 
@@ -3082,7 +3082,7 @@
 
       gtk_combo_box_check_appearance (combo_box);
       gtk_combo_box_relayout (combo_box);
-      
+
       g_object_notify (G_OBJECT (combo_box), "wrap_width");
     }
 }
@@ -3112,9 +3112,9 @@
   if (row_span != combo_box->priv->row_column)
     {
       combo_box->priv->row_column = row_span;
-      
+
       gtk_combo_box_relayout (combo_box);
- 
+
       g_object_notify (G_OBJECT (combo_box), "row_span_column");
     }
 }
@@ -3144,7 +3144,7 @@
   if (column_span != combo_box->priv->col_column)
     {
       combo_box->priv->col_column = column_span;
-      
+
       gtk_combo_box_relayout (combo_box);
 
       g_object_notify (G_OBJECT (combo_box), "column_span_column");
@@ -3191,7 +3191,7 @@
 
   if (combo_box->priv->active_item == index_)
     return;
-  
+
   gtk_combo_box_set_active_internal (combo_box, index_);
 }
 
@@ -3252,9 +3252,9 @@
  * gtk_combo_box_get_active_iter:
  * @combo_box: A #GtkComboBox
  * @iter: The uninitialized #GtkTreeIter.
- * 
+ *
  * Sets @iter to point to the current active item, if it exists.
- * 
+ *
  * Return value: %TRUE, if @iter was set
  *
  * Since: 2.4
@@ -3293,10 +3293,10 @@
  * gtk_combo_box_set_active_iter:
  * @combo_box: A #GtkComboBox
  * @iter: The #GtkTreeIter.
- * 
- * Sets the current active item to be the one referenced by @iter. 
+ *
+ * Sets the current active item to be the one referenced by @iter.
  * @iter must correspond to a path of depth one.
- * 
+ *
  * Since: 2.4
  **/
 void
@@ -3310,7 +3310,7 @@
   path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter);
   g_return_if_fail (path != NULL);
   g_return_if_fail (gtk_tree_path_get_depth (path) == 1);
-  
+
   gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
   gtk_tree_path_free (path);
 }
@@ -3320,11 +3320,11 @@
  * @combo_box: A #GtkComboBox.
  * @model: A #GtkTreeModel.
  *
- * Sets the model used by @combo_box to be @model. Will unset a previously set 
+ * Sets the model used by @combo_box to be @model. Will unset a previously set
  * model (if applicable). If @model is %NULL, then it will unset the model.
- * 
- * Note that this function does not clear the cell renderers, you have to 
- * call gtk_combo_box_cell_layout_clear() yourself if you need to set up 
+ *
+ * Note that this function does not clear the cell renderers, you have to
+ * call gtk_combo_box_cell_layout_clear() yourself if you need to set up
  * different cell renderers for the new model.
  *
  * Since: 2.4
@@ -3345,7 +3345,7 @@
 
   if (model == combo_box->priv->model)
     return;
-  
+
   if (combo_box->priv->model)
     gtk_combo_box_unset_model (combo_box);
 
@@ -3368,7 +3368,7 @@
     g_signal_connect (combo_box->priv->model, "row_changed",
 		      G_CALLBACK (gtk_combo_box_model_row_changed),
 		      combo_box);
-      
+
   if (combo_box->priv->tree_view)
     {
       /* list mode */
@@ -3574,7 +3574,7 @@
 {
   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
 
-  gtk_combo_box_popdown (combo_box); 
+  gtk_combo_box_popdown (combo_box);
 
   combo_box->priv->destroying = 1;
 
@@ -3589,14 +3589,14 @@
 {
   GtkComboBox *combo_box = GTK_COMBO_BOX (object);
   GSList *i;
-  
+
   if (GTK_IS_MENU (combo_box->priv->popup_widget))
     {
       gtk_combo_box_menu_destroy (combo_box);
       gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget));
       combo_box->priv->popup_widget = NULL;
     }
-  
+
   if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
     gtk_combo_box_list_destroy (combo_box);
 
@@ -3655,13 +3655,13 @@
 {
   GObject *object = G_OBJECT (child);
   AttachInfo *ai = g_object_get_data (object, ATTACH_INFO_KEY);
-                                                                                                   
+
   if (!ai)
     {
       ai = g_new0 (AttachInfo, 1);
       g_object_set_data_full (object, ATTACH_INFO_KEY, ai, g_free);
     }
-                                                                                                   
+
   return ai;
 }
 
@@ -3693,25 +3693,25 @@
                  guint      bottom_attach)
 {
   GtkMenuShell *menu_shell;
-  
+
   g_return_if_fail (GTK_IS_MENU (menu));
   g_return_if_fail (GTK_IS_MENU_ITEM (child));
-  g_return_if_fail (child->parent == NULL || 
+  g_return_if_fail (child->parent == NULL ||
 		    child->parent == GTK_WIDGET (menu));
   g_return_if_fail (left_attach < right_attach);
   g_return_if_fail (top_attach < bottom_attach);
 
   menu_shell = GTK_MENU_SHELL (menu);
-  
+
   if (!child->parent)
     {
       AttachInfo *ai = get_attach_info (child);
-      
+
       ai->left_attach = left_attach;
       ai->right_attach = right_attach;
       ai->top_attach = top_attach;
       ai->bottom_attach = bottom_attach;
-      
+
       menu_shell->children = g_list_append (menu_shell->children, child);
 
       gtk_widget_set_parent (child, GTK_WIDGET (menu));
@@ -3741,7 +3741,7 @@
   /* g_return_val_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model), NULL); */
 
   if (gtk_combo_box_get_active_iter (combo_box, &iter))
-    gtk_tree_model_get (gtk_combo_box_get_model(combo_box), &iter, 
+    gtk_tree_model_get (gtk_combo_box_get_model(combo_box), &iter,
     			0, &text, -1);
   return text;
 }
--- a/pidgin/pidginstock.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/pidginstock.c	Wed Jan 28 10:23:37 2009 +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,19 +125,10 @@
   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  },
 	{ PIDGIN_STOCK_STATUS_OPERATOR,	"emblems", "operator.png",	FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  },
@@ -175,39 +181,53 @@
 	{ 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_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_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_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_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)
@@ -257,16 +277,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;
@@ -300,28 +314,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);
@@ -329,7 +363,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);
@@ -349,17 +383,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);
@@ -371,20 +404,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();
 
@@ -394,6 +497,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;
@@ -432,7 +536,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);
@@ -440,18 +543,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");
@@ -462,32 +560,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	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/pidginstock.h	Wed Jan 28 10:23:37 2009 +0000
@@ -8,7 +8,7 @@
  * 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
@@ -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/pixmaps/Makefile.am	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/pixmaps/Makefile.am	Wed Jan 28 10:23:37 2009 +0000
@@ -488,6 +488,7 @@
 		tray/32/tray-connecting.png \
 		tray/32/tray-extended-away.png \
 		tray/32/tray-invisible.png \
+		tray/32/tray-message.png \
 		tray/32/tray-new-im.png \
 		tray/32/tray-offline.png \
 		tray/32/tray-online.png
@@ -498,6 +499,7 @@
 		tray/48/tray-connecting.png \
 		tray/48/tray-extended-away.png \
 		tray/48/tray-invisible.png \
+		tray/48/tray-message.png \
 		tray/48/tray-new-im.png \
 		tray/48/tray-offline.png \
 		tray/48/tray-online.png
@@ -525,7 +527,6 @@
 		$(PROTOCOLS_16_SCALABLE)	\
 		$(PROTOCOLS_22_SCALABLE)	\
 		$(PROTOCOLS_48_SCALABLE)	\
-		$(TOOLBAR_11)		\
 		$(TOOLBAR_16_SCALABLE)	\
 		$(TOOLBAR_22_SCALABLE)
 
@@ -553,6 +554,7 @@
 		$(STATUS_32_RTL) \
 		$(STATUS_48) \
 		$(STATUS_48_RTL) \
+		$(TOOLBAR_11) \
 		$(TOOLBAR_16) \
 		$(TOOLBAR_22) \
 		$(TRAY_16) \
--- a/pidgin/plugins/gevolution/gevo-util.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/plugins/gevolution/gevo-util.c	Wed Jan 28 10:23:37 2009 +0000
@@ -27,13 +27,13 @@
 
 void
 gevo_add_buddy(PurpleAccount *account, const char *group_name,
-			   const char *screenname, const char *alias)
+			   const char *buddy_name, const char *alias)
 {
 	PurpleConversation *conv = NULL;
 	PurpleBuddy *buddy;
 	PurpleGroup *group;
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, screenname, account);
+	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, buddy_name, account);
 
 	if ((group = purple_find_group(group_name)) == NULL)
 	{
@@ -41,7 +41,7 @@
 		purple_blist_add_group(group, NULL);
 	}
 
-	buddy = purple_buddy_new(account, screenname, alias);
+	buddy = purple_buddy_new(account, buddy_name, alias);
 	purple_blist_add_buddy(buddy, NULL, group, NULL);
 	purple_account_add_buddy(account, buddy);
 
--- a/pidgin/plugins/gevolution/gevolution.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/plugins/gevolution/gevolution.c	Wed Jan 28 10:23:37 2009 +0000
@@ -52,7 +52,7 @@
 {
 	COLUMN_AUTOADD,
 	COLUMN_ICON,
-	COLUMN_SCREENNAME,
+	COLUMN_USERNAME,
 	COLUMN_DATA,
 	NUM_COLUMNS
 };
@@ -463,11 +463,11 @@
 	gtk_tree_view_column_add_attribute(column, renderer,
 									   "pixbuf", COLUMN_ICON);
 
-	/* Screenname */
+	/* Username */
 	renderer = gtk_cell_renderer_text_new();
 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
 	gtk_tree_view_column_add_attribute(column, renderer,
-									   "text", COLUMN_SCREENNAME);
+									   "text", COLUMN_USERNAME);
 
 
 	/* Populate */
@@ -489,7 +489,7 @@
 						   purple_account_get_bool(account, "gevo-autoadd",
 												 FALSE),
 						   COLUMN_ICON, pixbuf,
-						   COLUMN_SCREENNAME,
+						   COLUMN_USERNAME,
 						   purple_account_get_username(account),
 						   COLUMN_DATA, account,
 						   -1);
--- a/pidgin/plugins/gevolution/new_person_dialog.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/plugins/gevolution/new_person_dialog.c	Wed Jan 28 10:23:37 2009 +0000
@@ -67,7 +67,7 @@
 }
 
 static void
-screenname_changed_cb(GtkEntry *entry, GevoNewPersonDialog *dialog)
+username_changed_cb(GtkEntry *entry, GevoNewPersonDialog *dialog)
 {
 	gtk_widget_set_sensitive(dialog->add_button,
 							 *gtk_entry_get_text(entry) != '\0');
@@ -85,7 +85,7 @@
 add_cb(GtkWidget *w, GevoNewPersonDialog *dialog)
 {
 	EContact *contact = NULL;
-	const char *screenname;
+	const char *username;
 	const char *firstname;
 	const char *lastname;
 	const char *email;
@@ -96,9 +96,9 @@
 	char *full_name = NULL;
 
 	if (dialog->person_only)
-		screenname = dialog->buddy->name;
+		username = dialog->buddy->name;
 	else
-		screenname = gtk_entry_get_text(GTK_ENTRY(dialog->screenname));
+		username = gtk_entry_get_text(GTK_ENTRY(dialog->username));
 
 	firstname  = gtk_entry_get_text(GTK_ENTRY(dialog->firstname));
 	lastname   = gtk_entry_get_text(GTK_ENTRY(dialog->lastname));
@@ -143,7 +143,7 @@
 
 		if (!strcmp(im_service, "prpl-oscar"))
 		{
-			if (isdigit(*screenname))
+			if (isdigit(*username))
 				field = E_CONTACT_IM_ICQ;
 			else
 				field = E_CONTACT_IM_AIM;
@@ -163,7 +163,7 @@
 
 		if (field > 0)
 		{
-			GList *list = g_list_append(NULL, g_strdup(screenname));
+			GList *list = g_list_append(NULL, g_strdup(username));
 
 			e_contact_set(contact, field, list);
 
@@ -203,7 +203,7 @@
 
 		group_name = pidgin_text_combo_box_entry_get_text(dialog->group_combo);
 
-		gevo_add_buddy(dialog->account, group_name, screenname, full_name);
+		gevo_add_buddy(dialog->account, group_name, username, full_name);
 	}
 
 	if (name != NULL)
@@ -289,15 +289,15 @@
 											 NULL, dialog);
 		add_pref_box(sg, vbox, _("Account type:"), dialog->accounts_menu);
 
-		/* Screen Name */
-		dialog->screenname = gtk_entry_new();
-		add_pref_box(sg, vbox, _("Username:"), dialog->screenname);
+		/* Username */
+		dialog->username = gtk_entry_new();
+		add_pref_box(sg, vbox, _("Username:"), dialog->username);
 
 		if (username != NULL)
-			gtk_entry_set_text(GTK_ENTRY(dialog->screenname), username);
+			gtk_entry_set_text(GTK_ENTRY(dialog->username), username);
 
-		g_signal_connect(G_OBJECT(dialog->screenname), "changed",
-						 G_CALLBACK(screenname_changed_cb), dialog);
+		g_signal_connect(G_OBJECT(dialog->username), "changed",
+						 G_CALLBACK(username_changed_cb), dialog);
 
 		/* Group */
 		dialog->group_combo = pidgin_text_combo_box_entry_new(NULL,
--- a/pidgin/plugins/history.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/plugins/history.c	Wed Jan 28 10:23:37 2009 +0000
@@ -62,36 +62,39 @@
 			return;
 
 		/* Find buddies for this conversation. */
-	        buddies = purple_find_buddies(account, name);
+		buddies = purple_find_buddies(account, name);
 
 		/* If we found at least one buddy, save the first buddy's alias. */
 		if (buddies != NULL)
 			alias = purple_buddy_get_contact_alias((PurpleBuddy *)buddies->data);
 
-	        for (cur = buddies; cur != NULL; cur = cur->next)
-	        {
-	                PurpleBlistNode *node = cur->data;
-	                if ((node != NULL) && ((node->prev != NULL) || (node->next != NULL)))
-	                {
+		for (cur = buddies; cur != NULL; cur = cur->next)
+		{
+			PurpleBlistNode *node = cur->data;
+			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,
+					logs = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM,
 							purple_buddy_get_name((PurpleBuddy *)node2),
 							purple_buddy_get_account((PurpleBuddy *)node2)),
-						logs);
+							logs);
 				}
 				break;
-	                }
-	        }
-	        g_slist_free(buddies);
+			}
+		}
+		g_slist_free(buddies);
 
 		if (logs == NULL)
 			logs = purple_log_get_logs(PURPLE_LOG_IM, name, account);
@@ -118,7 +121,7 @@
 
 	protocol = g_strdup(gtk_imhtml_get_protocol_name(GTK_IMHTML(gtkconv->imhtml)));
 	gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml),
-							      purple_account_get_protocol_name(((PurpleLog*)logs->data)->account));
+			purple_account_get_protocol_name(((PurpleLog*)logs->data)->account));
 
 	if (gtk_text_buffer_get_char_count(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml))))
 		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR>", options);
--- a/pidgin/plugins/perl/common/GtkLog.xs	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/plugins/perl/common/GtkLog.xs	Wed Jan 28 10:23:37 2009 +0000
@@ -7,9 +7,9 @@
 pidgin_log_get_handle()
 
 void
-pidgin_log_show(type, screenname, account)
+pidgin_log_show(type, buddyname, account)
 	Purple::LogType type
-	const char * screenname
+	const char * buddyname
 	Purple::Account account
 
 void
--- a/pidgin/plugins/ticker/ticker.c	Wed Jan 28 04:27:01 2009 +0000
+++ b/pidgin/plugins/ticker/ticker.c	Wed Jan 28 10:23:37 2009 +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/po/POTFILES.in	Wed Jan 28 04:27:01 2009 +0000
+++ b/po/POTFILES.in	Wed Jan 28 10:23:37 2009 +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/README	Wed Jan 28 04:27:01 2009 +0000
+++ b/po/README	Wed Jan 28 10:23:37 2009 +0000
@@ -1,2 +1,2 @@
-For information on translating Pidgin, Libpurple, and Finch, please see
+For information on translating Pidgin, libpurple, and Finch, please see
 our wiki page at http://developer.pidgin.im/wiki/TipsForTranslators.
--- a/po/et.po	Wed Jan 28 04:27:01 2009 +0000
+++ b/po/et.po	Wed Jan 28 10:23:37 2009 +0000
@@ -2258,7 +2258,7 @@
 #. *  summary
 #. *  description
 msgid "Tests the ciphers that ship with libpurple."
-msgstr "Libpurple'ga kaasasolevate Å¡ifrite testimine."
+msgstr "libpurple'ga kaasasolevate Å¡ifrite testimine."
 
 #. *< type
 #. *< ui_requirement