changeset 30876:f228c946a5bc

merge of '17e496a18cf8462d267f5220dd5f6283662eeba7' and 'c6846e134f765c0da81a81bb60301dedcbb0d4fe'
author Marcus Lundblad <ml@update.uu.se>
date Wed, 25 Aug 2010 19:12:08 +0000
parents 603638fad2f1 (current diff) 6d8c88a8af25 (diff)
children 797c03de8fa9
files ChangeLog libpurple/media/backend-fs2.c libpurple/protocols/oscar/family_advert.c libpurple/protocols/oscar/family_invite.c libpurple/protocols/oscar/family_odir.c libpurple/protocols/oscar/family_translate.c
diffstat 74 files changed, 2456 insertions(+), 6044 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Aug 25 19:11:38 2010 +0000
+++ b/ChangeLog	Wed Aug 25 19:12:08 2010 +0000
@@ -8,6 +8,13 @@
 	* Added ability to use TURN relaying via TCP and TLS (including preference
 	  settings for these).
 
+
+	Yahoo/Yahoo JAPAN:
+	* Stop doing unnecessary lookups of certain alias information.  This
+	  solves deadlocks when a given Yahoo account has a ridiculously large
+	  (>500 buddies) list and may improve login speed for those on slow
+	  connections.
+
 version 2.7.3 (08/10/2010):
 	General:
 	* Use silent build rules for automake >1.11. You can enable verbose
--- a/finch/libgnt/gntentry.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/finch/libgnt/gntentry.c	Wed Aug 25 19:12:08 2010 +0000
@@ -480,7 +480,7 @@
 {
 	GntEntry *entry = GNT_ENTRY(bind);
 	GList *iter;
-	const char *current , *pos;
+	const char *current;
 	int len;
 	
 	if (entry->history->prev && entry->search->needle)
@@ -497,7 +497,7 @@
 		const char *str = iter->data;
 		/* A more utf8-friendly version of strstr would have been better, but
 		 * for now, this will have to do. */
-		if ((pos = strstr(str, current)))
+		if (strstr(str, current) != NULL)
 			break;
 	}
 
--- a/finch/libgnt/gnttextview.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/finch/libgnt/gnttextview.c	Wed Aug 25 19:12:08 2010 +0000
@@ -711,7 +711,7 @@
 int gnt_text_view_get_lines_above(GntTextView *view)
 {
 	int above = 0;
-	GList *list = view->list;
+	GList *list;
 	list = g_list_nth(view->list, GNT_WIDGET(view)->priv.height);
 	if (!list)
 		return 0;
--- a/libpurple/log.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/log.c	Wed Aug 25 19:12:08 2010 +0000
@@ -1681,7 +1681,6 @@
 	struct tm tm;
 	char month[4];
 	struct old_logger_data *data = NULL;
-	char *newlog;
 	int logfound = 0;
 	int lastoff = 0;
 	int newlen;
@@ -1783,7 +1782,7 @@
 	}
 
 	while (fgets(buf, BUF_LONG, file)) {
-		if ((newlog = strstr(buf, "---- New C"))) {
+		if (strstr(buf, "---- New C") != NULL) {
 			int length;
 			int offset;
 			char convostart[32];
--- a/libpurple/media/backend-fs2.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/media/backend-fs2.c	Wed Aug 25 19:12:08 2010 +0000
@@ -1816,7 +1816,7 @@
 		const gchar *sess_id)
 {
 	PurpleMediaBackendFs2Private *priv;
-	gboolean ret;
+	gboolean ret = FALSE;
 
 	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), FALSE);
 
--- a/libpurple/plugins/tcl/tcl_cmd.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/plugins/tcl/tcl_cmd.c	Wed Aug 25 19:12:08 2010 +0000
@@ -125,7 +125,7 @@
                                    gchar **args, gchar **errors,
                                    struct tcl_cmd_handler *handler)
 {
-	int retval, error, i;
+	int retval, i;
 	Tcl_Obj *command, *arg, *tclargs, *result;
 
 	command = Tcl_NewListObj(0, NULL);
@@ -153,8 +153,7 @@
 	}
 	Tcl_ListObjAppendElement(handler->interp, command, tclargs);
 
-	if ((error = Tcl_EvalObjEx(handler->interp, command,
-	                           TCL_EVAL_GLOBAL)) != TCL_OK) {
+	if (Tcl_EvalObjEx(handler->interp, command, TCL_EVAL_GLOBAL) != TCL_OK) {
 		gchar *errorstr;
 
 		errorstr = g_strdup_printf("error evaluating callback: %s\n",
@@ -164,8 +163,8 @@
 		retval = PURPLE_CMD_RET_FAILED;
 	} else {
 		result = Tcl_GetObjResult(handler->interp);
-		if ((error = Tcl_GetIntFromObj(handler->interp, result,
-		                               &retval)) != TCL_OK) {
+		if (Tcl_GetIntFromObj(handler->interp, result,
+		                      &retval) != TCL_OK) {
 			gchar *errorstr;
 
 			errorstr = g_strdup_printf("Error retreiving procedure result: %s\n",
--- a/libpurple/plugins/tcl/tcl_signals.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/plugins/tcl/tcl_signals.c	Wed Aug 25 19:12:08 2010 +0000
@@ -160,7 +160,7 @@
 {
 	GString *name, *val;
 	PurpleBlistNode *node;
-	int error, i;
+	int i;
 	void *retval = NULL;
 	Tcl_Obj *cmd, *arg, *result;
 	void **vals; /* Used for inout parameters */
@@ -335,7 +335,7 @@
 	}
 
 	/* Call the friggin' procedure already */
-	if ((error = Tcl_EvalObjEx(handler->interp, cmd, TCL_EVAL_GLOBAL)) != TCL_OK) {
+	if (Tcl_EvalObjEx(handler->interp, cmd, TCL_EVAL_GLOBAL) != TCL_OK) {
 		purple_debug(PURPLE_DEBUG_ERROR, "tcl", "error evaluating callback: %s\n",
 			   Tcl_GetString(Tcl_GetObjResult(handler->interp)));
 	} else {
@@ -345,7 +345,7 @@
 			if (purple_value_get_type(handler->returntype) == PURPLE_TYPE_STRING) {
 				retval = (void *)g_strdup(Tcl_GetString(result));
 			} else {
-				if ((error = Tcl_GetIntFromObj(handler->interp, result, (int *)&retval)) != TCL_OK) {
+				if (Tcl_GetIntFromObj(handler->interp, result, (int *)&retval) != TCL_OK) {
 					purple_debug(PURPLE_DEBUG_ERROR, "tcl", "Error retrieving procedure result: %s\n",
 						   Tcl_GetString(Tcl_GetObjResult(handler->interp)));
 					retval = NULL;
--- a/libpurple/protocols/bonjour/jabber.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Wed Aug 25 19:12:08 2010 +0000
@@ -1273,7 +1273,6 @@
 static void
 xep_iq_parse(xmlnode *packet, PurpleBuddy *pb)
 {
-	xmlnode *child;
 	PurpleAccount *account;
 	PurpleConnection *gc;
 
@@ -1283,7 +1282,7 @@
 		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")))
+	if (xmlnode_get_child(packet, "si") != NULL || xmlnode_get_child(packet, "error") != NULL)
 		xep_si_parse(gc, packet, pb);
 	else
 		xep_bytestreams_parse(gc, packet, pb);
--- a/libpurple/protocols/bonjour/mdns_avahi.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/bonjour/mdns_avahi.c	Wed Aug 25 19:12:08 2010 +0000
@@ -115,7 +115,6 @@
 	AvahiStringList *l;
 	size_t size;
 	char *key, *value;
-	int ret;
 	char ip[AVAHI_ADDRESS_STR_MAX];
 	AvahiBuddyImplData *b_impl;
 	AvahiSvcResolverData *rd;
@@ -202,7 +201,7 @@
 			/* Obtain the parameters from the text_record */
 			clear_bonjour_buddy_values(bb);
 			for(l = txt; l != NULL; l = l->next) {
-				if ((ret = avahi_string_list_get_pair(l, &key, &value, &size)) < 0)
+				if (avahi_string_list_get_pair(l, &key, &value, &size) < 0)
 					continue;
 				set_bonjour_buddy_value(bb, key, value, size);
 				/* TODO: Since we're using the glib allocator, I think we
--- a/libpurple/protocols/jabber/auth_cyrus.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/jabber/auth_cyrus.c	Wed Aug 25 19:12:08 2010 +0000
@@ -103,6 +103,7 @@
 		return SASL_BADPARAM;
 
 	len = strlen(pw);
+	/* Not an off-by-one because sasl_secret_t defines char data[1] */
 	x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
 
 	if (!x)
--- a/libpurple/protocols/jabber/bosh.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/jabber/bosh.c	Wed Aug 25 19:12:08 2010 +0000
@@ -711,11 +711,10 @@
 		/* Make sure Content-Length is in headers, not body */
 		if (content_length && (!end_of_headers || content_length < end_of_headers)) {
 			const char *sep;
-			const char *eol;
 			int len;
 
 			if ((sep = strstr(content_length, ": ")) == NULL ||
-					(eol = strstr(sep, "\r\n")) == NULL)
+					strstr(sep, "\r\n") == NULL)
 				/*
 				 * The packet ends in the middle of the Content-Length line.
 				 * We'll try again later when we have more.
--- a/libpurple/protocols/jabber/disco.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/jabber/disco.c	Wed Aug 25 19:12:08 2010 +0000
@@ -604,7 +604,7 @@
 
 		/* we don't actually care about the specific nodes,
 		 * so we won't query them */
-		if((node = xmlnode_get_attrib(child, "node")))
+		if(xmlnode_get_attrib(child, "node") != NULL)
 			continue;
 
 		iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_DISCO_INFO);
--- a/libpurple/protocols/jabber/jabber.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Wed Aug 25 19:12:08 2010 +0000
@@ -205,7 +205,7 @@
 	 * resource string from being unreasonably long on systems which stuff the
 	 * whole FQDN in the hostname */
 	if((dot = strchr(hostname, '.')))
-			dot = '\0';
+		*dot = '\0';
 
 	return purple_strreplace(input, "__HOSTNAME__", hostname);
 }
@@ -3493,7 +3493,7 @@
 
 	if (js->pep) {
 		/* if no argument was given, unset mood */
-		if (!args | !args[0]) {
+		if (!args || !args[0]) {
 			jabber_mood_set(js, NULL, NULL);
 		} else if (!args[1]) {
 			jabber_mood_set(js, args[0], NULL);
--- a/libpurple/protocols/jabber/message.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/jabber/message.c	Wed Aug 25 19:12:08 2010 +0000
@@ -296,7 +296,6 @@
 }
 
 static void handle_buzz(JabberMessage *jm) {
-	PurpleBuddy *buddy;
 	PurpleAccount *account;
 
 	/* Delayed buzz MUST NOT be accepted */
@@ -309,7 +308,7 @@
 
 	account = purple_connection_get_account(jm->js->gc);
 
-	if ((buddy = purple_find_buddy(account, jm->from)) == NULL)
+	if (purple_find_buddy(account, jm->from) == NULL)
 		return; /* Do not accept buzzes from unknown people */
 
 	/* xmpp only has 1 attention type, so index is 0 */
--- a/libpurple/protocols/jabber/si.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/jabber/si.c	Wed Aug 25 19:12:08 2010 +0000
@@ -1734,7 +1734,7 @@
 	/* if they've already sent us this file transfer with the same damn id
 	 * then we're gonna ignore it, until I think of something better to do
 	 * with it */
-	if((xfer = jabber_si_xfer_find(js, stream_id, from)))
+	if(jabber_si_xfer_find(js, stream_id, from) != NULL)
 		return;
 
 	jsx = g_new0(JabberSIXfer, 1);
--- a/libpurple/protocols/msn/contact.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/msn/contact.c	Wed Aug 25 19:12:08 2010 +0000
@@ -536,7 +536,7 @@
 		abLastChange = purple_account_get_string(session->account,
 			"ablastChange", NULL);
 		dynamicItemLastChange = purple_account_get_string(session->account,
-			"dynamicItemLastChange", NULL);
+			"DynamicItemLastChanged", NULL);
 
 		if (state->partner_scenario == MSN_PS_INITIAL) {
 #ifdef MSN_PARTIAL_LISTS
@@ -684,20 +684,20 @@
 		xmlnode *annotation;
 		MsnUser *user;
 
+		g_free(passport);
+		g_free(Name);
+		g_free(uid);
+		g_free(type);
+		g_free(mobile_number);
+		g_free(alias);
+		passport = Name = uid = type = mobile_number = alias = NULL;
+		mobile = FALSE;
+
 		if (!(contactId = xmlnode_get_child(contactNode,"contactId"))
 				|| !(contactInfo = xmlnode_get_child(contactNode, "contactInfo"))
 				|| !(contactType = xmlnode_get_child(contactInfo, "contactType")))
 			continue;
 
-		g_free(passport);
-		g_free(Name);
-		g_free(alias);
-		g_free(uid);
-		g_free(type);
-		g_free(mobile_number);
-		passport = Name = uid = type = mobile_number = alias = NULL;
-		mobile = FALSE;
-
 		uid = xmlnode_get_data(contactId);
 		type = xmlnode_get_data(contactType);
 
@@ -836,6 +836,7 @@
 	g_free(uid);
 	g_free(type);
 	g_free(mobile_number);
+	g_free(alias);
 }
 
 static gboolean
@@ -885,7 +886,7 @@
 		msn_parse_addressbook_groups(session, groups);
 	}
 
-	/*add a default No group to set up the no group Membership*/
+	/* Add an "Other Contacts" group for buddies who aren't in a group */
 	msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID,
 				  MSN_INDIVIDUALS_GROUP_NAME);
 	purple_debug_misc("msn", "AB group_id:%s name:%s\n",
@@ -895,7 +896,7 @@
 		purple_blist_add_group(g, NULL);
 	}
 
-	/*add a default No group to set up the no group Membership*/
+	/* Add a "Non-IM Contacts" group */
 	msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
 	purple_debug_misc("msn", "AB group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
 	if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL) {
--- a/libpurple/protocols/oscar/Makefile.am	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/Makefile.am	Wed Aug 25 19:12:08 2010 +0000
@@ -6,10 +6,11 @@
 pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION)
 
 OSCARSOURCES = \
+	authorization.c     \
 	bstream.c           \
 	clientlogin.c       \
+	encoding.c          \
 	family_admin.c      \
-	family_advert.c     \
 	family_alert.c      \
 	family_auth.c       \
 	family_bart.c       \
@@ -19,14 +20,11 @@
 	family_chatnav.c    \
 	family_icq.c        \
 	family_icbm.c       \
-	family_invite.c     \
 	family_locate.c     \
-	family_odir.c       \
 	family_oservice.c   \
 	family_popup.c      \
 	family_feedbag.c    \
 	family_stats.c      \
-	family_translate.c  \
 	family_userlookup.c \
 	flap_connection.c   \
 	misc.c         \
@@ -44,7 +42,9 @@
 	snac.c              \
 	snactypes.h         \
 	tlv.c               \
-	util.c
+	userinfo.c          \
+	util.c              \
+	visibility.c
 
 AM_CFLAGS = $(st)
 
--- a/libpurple/protocols/oscar/Makefile.mingw	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/Makefile.mingw	Wed Aug 25 19:12:08 2010 +0000
@@ -41,10 +41,11 @@
 ##  SOURCES, OBJECTS
 ##
 C_SRC = \
+	authorization.c		\
 	bstream.c		\
 	clientlogin.c		\
+	encoding.c		\
 	family_admin.c		\
-	family_advert.c		\
 	family_alert.c		\
 	family_auth.c		\
 	family_bart.c		\
@@ -52,16 +53,13 @@
 	family_buddy.c		\
 	family_chat.c		\
 	family_chatnav.c	\
-	family_icq.c		\
+	family_feedbag.c	\
 	family_icbm.c		\
-	family_invite.c		\
+	family_icq.c		\
 	family_locate.c		\
-	family_odir.c		\
+	family_oservice.c	\
 	family_popup.c		\
-	family_oservice.c	\
-	family_feedbag.c	\
 	family_stats.c		\
-	family_translate.c	\
 	family_userlookup.c	\
 	flap_connection.c	\
 	misc.c			\
@@ -75,7 +73,9 @@
 	rxhandlers.c		\
 	snac.c			\
 	tlv.c			\
-	util.c
+	userinfo.c		\
+	util.c			\
+	visibility.c
 
 OBJECTS = $(C_SRC:%.c=%.o)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/authorization.c	Wed Aug 25 19:12:08 2010 +0000
@@ -0,0 +1,153 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+*/
+
+/*
+ * Everything related to OSCAR authorization requests.
+ */
+
+#include "oscar.h"
+#include "request.h"
+
+static void
+oscar_auth_request(struct name_data *data, char *msg)
+{
+	PurpleConnection *gc;
+	OscarData *od;
+	PurpleAccount *account;
+	PurpleBuddy *buddy;
+	PurpleGroup *group;
+	const char *bname, *gname;
+
+	gc = data->gc;
+	od = purple_connection_get_protocol_data(gc);
+	account = purple_connection_get_account(gc);
+	buddy = purple_find_buddy(account, data->name);
+	if (buddy != NULL)
+		group = purple_buddy_get_group(buddy);
+	else
+		group = NULL;
+
+	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",
+				   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, gname, bname, AIM_SSI_TYPE_BUDDY))
+		{
+			aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE);
+
+			/* Mobile users should always be online */
+			if (bname[0] == '+') {
+				purple_prpl_got_user_status(account,
+						purple_buddy_get_name(buddy),
+						OSCAR_STATUS_ID_AVAILABLE, NULL);
+				purple_prpl_got_user_status(account,
+						purple_buddy_get_name(buddy),
+						OSCAR_STATUS_ID_MOBILE, NULL);
+			}
+		}
+	}
+
+	oscar_free_name_data(data);
+}
+
+static void
+oscar_auth_grant(gpointer cbdata)
+{
+	struct name_data *data = cbdata;
+	PurpleConnection *gc = data->gc;
+	OscarData *od = purple_connection_get_protocol_data(gc);
+
+	aim_ssi_sendauthreply(od, data->name, 0x01, NULL);
+
+	oscar_free_name_data(data);
+}
+
+static void
+oscar_auth_dontgrant(struct name_data *data, char *msg)
+{
+	PurpleConnection *gc = data->gc;
+	OscarData *od = purple_connection_get_protocol_data(gc);
+
+	aim_ssi_sendauthreply(od, data->name, 0x00, msg ? msg : _("No reason given."));
+	
+	oscar_free_name_data(data);
+}
+
+static void
+oscar_auth_dontgrant_msgprompt(gpointer cbdata)
+{
+	struct name_data *data = cbdata;
+	purple_request_input(data->gc, NULL, _("Authorization Denied Message:"),
+					   NULL, _("No reason given."), TRUE, FALSE, NULL,
+					   _("_OK"), G_CALLBACK(oscar_auth_dontgrant),
+					   _("_Cancel"), G_CALLBACK(oscar_free_name_data),
+					   purple_connection_get_account(data->gc), data->name, NULL,
+					   data);
+}
+
+/* When you ask other people for authorization */
+void
+oscar_auth_sendrequest(PurpleConnection *gc, const char *name)
+{
+	struct name_data *data;
+
+	data = g_new0(struct name_data, 1);
+	data->gc = gc;
+	data->name = g_strdup(name);
+
+	purple_request_input(data->gc, NULL, _("Authorization Request Message:"),
+					   NULL, _("Please authorize me!"), TRUE, FALSE, NULL,
+					   _("_OK"), G_CALLBACK(oscar_auth_request),
+					   _("_Cancel"), G_CALLBACK(oscar_free_name_data),
+					   purple_connection_get_account(gc), name, NULL,
+					   data);
+}
+
+void
+oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored)
+{
+	PurpleBuddy *buddy;
+	PurpleConnection *gc;
+
+	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
+
+	buddy = (PurpleBuddy *) node;
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	oscar_auth_sendrequest(gc, purple_buddy_get_name(buddy));
+}
+
+/* When other people ask you for authorization */
+void
+oscar_auth_recvrequest(PurpleConnection *gc, gchar *name, gchar *nick, gchar *reason)
+{
+	PurpleAccount* account = purple_connection_get_account(gc);
+	struct name_data *data = g_new(struct name_data, 1);
+
+	data->gc = gc;
+	data->name = name;
+	data->nick = nick;
+
+	purple_account_request_authorization(account, data->name, NULL, data->nick,
+		reason, purple_find_buddy(account, data->name) != NULL,
+		oscar_auth_grant, oscar_auth_dontgrant_msgprompt, data);
+}
\ No newline at end of file
--- a/libpurple/protocols/oscar/bstream.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/bstream.c	Wed Aug 25 19:12:08 2010 +0000
@@ -24,7 +24,7 @@
 
 #include "oscar.h"
 
-int byte_stream_new(ByteStream *bs, guint32 len)
+int byte_stream_new(ByteStream *bs, size_t len)
 {
 	if (bs == NULL)
 		return -1;
@@ -32,9 +32,8 @@
 	return byte_stream_init(bs, g_malloc(len), len);
 }
 
-int byte_stream_init(ByteStream *bs, guint8 *data, int len)
+int byte_stream_init(ByteStream *bs, guint8 *data, size_t len)
 {
-
 	if (bs == NULL)
 		return -1;
 
@@ -50,7 +49,7 @@
 	g_free(bs->data);
 }
 
-int byte_stream_empty(ByteStream *bs)
+int byte_stream_bytes_left(ByteStream *bs)
 {
 	return bs->len - bs->offset;
 }
@@ -60,229 +59,172 @@
 	return bs->offset;
 }
 
-int byte_stream_setpos(ByteStream *bs, unsigned int off)
+int byte_stream_setpos(ByteStream *bs, size_t off)
 {
-
-	if (off > bs->len)
-		return -1;
+	g_return_val_if_fail(off <= bs->len, -1);
 
 	bs->offset = off;
-
 	return off;
 }
 
 void byte_stream_rewind(ByteStream *bs)
 {
-
 	byte_stream_setpos(bs, 0);
-
-	return;
 }
 
 /*
  * N can be negative, which can be used for going backwards
- * in a bstream.  I'm not sure if libfaim actually does
- * this anywhere...
+ * in a bstream.
  */
 int byte_stream_advance(ByteStream *bs, int n)
 {
-
-	if ((byte_stream_curpos(bs) + n < 0) || (byte_stream_empty(bs) < n))
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_curpos(bs) + n >= 0, 0);
+	g_return_val_if_fail(n <= byte_stream_bytes_left(bs), 0);
 
 	bs->offset += n;
-
 	return n;
 }
 
 guint8 byte_stream_get8(ByteStream *bs)
 {
-
-	if (byte_stream_empty(bs) < 1)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
 
 	bs->offset++;
-
 	return aimutil_get8(bs->data + bs->offset - 1);
 }
 
 guint16 byte_stream_get16(ByteStream *bs)
 {
-
-	if (byte_stream_empty(bs) < 2)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
 
 	bs->offset += 2;
-
 	return aimutil_get16(bs->data + bs->offset - 2);
 }
 
 guint32 byte_stream_get32(ByteStream *bs)
 {
-
-	if (byte_stream_empty(bs) < 4)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
 
 	bs->offset += 4;
-
 	return aimutil_get32(bs->data + bs->offset - 4);
 }
 
 guint8 byte_stream_getle8(ByteStream *bs)
 {
-
-	if (byte_stream_empty(bs) < 1)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
 
 	bs->offset++;
-
 	return aimutil_getle8(bs->data + bs->offset - 1);
 }
 
 guint16 byte_stream_getle16(ByteStream *bs)
 {
-
-	if (byte_stream_empty(bs) < 2)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
 
 	bs->offset += 2;
-
 	return aimutil_getle16(bs->data + bs->offset - 2);
 }
 
 guint32 byte_stream_getle32(ByteStream *bs)
 {
-
-	if (byte_stream_empty(bs) < 4)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
 
 	bs->offset += 4;
-
 	return aimutil_getle32(bs->data + bs->offset - 4);
 }
 
-static void byte_stream_getrawbuf_nocheck(ByteStream *bs, guint8 *buf, int len)
+static void byte_stream_getrawbuf_nocheck(ByteStream *bs, guint8 *buf, size_t len)
 {
 	memcpy(buf, bs->data + bs->offset, len);
 	bs->offset += len;
 }
 
-int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int len)
+int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, size_t len)
 {
-
-	if (byte_stream_empty(bs) < len)
-		return 0;
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0);
 
 	byte_stream_getrawbuf_nocheck(bs, buf, len);
 	return len;
 }
 
-guint8 *byte_stream_getraw(ByteStream *bs, int len)
+guint8 *byte_stream_getraw(ByteStream *bs, size_t len)
 {
 	guint8 *ob;
 
-	if (byte_stream_empty(bs) < len)
-		return NULL;
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, NULL);
 
 	ob = g_malloc(len);
-
 	byte_stream_getrawbuf_nocheck(bs, ob, len);
-
 	return ob;
 }
 
-char *byte_stream_getstr(ByteStream *bs, int len)
+char *byte_stream_getstr(ByteStream *bs, size_t len)
 {
 	char *ob;
 
-	if (byte_stream_empty(bs) < len)
-		return NULL;
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, NULL);
 
 	ob = g_malloc(len + 1);
-
 	byte_stream_getrawbuf_nocheck(bs, (guint8 *)ob, len);
-
 	ob[len] = '\0';
-
 	return ob;
 }
 
 int byte_stream_put8(ByteStream *bs, guint8 v)
 {
-
-	if (byte_stream_empty(bs) < 1)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
 
 	bs->offset += aimutil_put8(bs->data + bs->offset, v);
-
 	return 1;
 }
 
 int byte_stream_put16(ByteStream *bs, guint16 v)
 {
-
-	if (byte_stream_empty(bs) < 2)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
 
 	bs->offset += aimutil_put16(bs->data + bs->offset, v);
-
 	return 2;
 }
 
 int byte_stream_put32(ByteStream *bs, guint32 v)
 {
-
-	if (byte_stream_empty(bs) < 4)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
 
 	bs->offset += aimutil_put32(bs->data + bs->offset, v);
-
 	return 1;
 }
 
 int byte_stream_putle8(ByteStream *bs, guint8 v)
 {
-
-	if (byte_stream_empty(bs) < 1)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
 
 	bs->offset += aimutil_putle8(bs->data + bs->offset, v);
-
 	return 1;
 }
 
 int byte_stream_putle16(ByteStream *bs, guint16 v)
 {
-
-	if (byte_stream_empty(bs) < 2)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
 
 	bs->offset += aimutil_putle16(bs->data + bs->offset, v);
-
 	return 2;
 }
 
 int byte_stream_putle32(ByteStream *bs, guint32 v)
 {
-
-	if (byte_stream_empty(bs) < 4)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
 
 	bs->offset += aimutil_putle32(bs->data + bs->offset, v);
-
 	return 1;
 }
 
 
-int byte_stream_putraw(ByteStream *bs, const guint8 *v, int len)
+int byte_stream_putraw(ByteStream *bs, const guint8 *v, size_t len)
 {
-
-	if (byte_stream_empty(bs) < len)
-		return 0; /* XXX throw an exception */
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0);
 
 	memcpy(bs->data + bs->offset, v, len);
 	bs->offset += len;
-
 	return len;
 }
 
@@ -291,19 +233,14 @@
 	return byte_stream_putraw(bs, (guint8 *)str, strlen(str));
 }
 
-int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int len)
+int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, size_t len)
 {
-
-	if (byte_stream_empty(srcbs) < len)
-		return 0; /* XXX throw exception (underrun) */
-
-	if (byte_stream_empty(bs) < len)
-		return 0; /* XXX throw exception (overflow) */
+	g_return_val_if_fail(byte_stream_bytes_left(srcbs) >= len, 0);
+	g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0);
 
 	memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len);
 	bs->offset += len;
 	srcbs->offset += len;
-
 	return len;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/encoding.c	Wed Aug 25 19:12:08 2010 +0000
@@ -0,0 +1,235 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+*/
+
+#include "encoding.h"
+
+static gchar *
+encoding_extract(const char *encoding)
+{
+	char *begin, *end;
+
+	if (encoding == NULL) {
+		return NULL;
+	}
+
+	if (!g_str_has_prefix(encoding, "text/aolrtf; charset=") &&
+		!g_str_has_prefix(encoding, "text/x-aolrtf; charset=") &&
+		!g_str_has_prefix(encoding, "text/plain; charset=")) {
+		return g_strdup(encoding);
+	}
+
+	begin = strchr(encoding, '"');
+	end = strrchr(encoding, '"');
+
+	if ((begin == NULL) || (end == NULL) || (begin >= end)) {
+		return g_strdup(encoding);
+	}
+
+	return g_strndup(begin+1, (end-1) - begin);
+}
+
+gchar *
+oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen)
+{
+	gchar *utf8 = NULL;
+	const gchar *glib_encoding = NULL;
+	gchar *extracted_encoding = encoding_extract(encoding);
+	
+	if (extracted_encoding == NULL || *extracted_encoding == '\0') {
+		purple_debug_info("oscar", "Empty encoding, assuming UTF-8\n");
+	} else if (!g_ascii_strcasecmp(extracted_encoding, "iso-8859-1")) {
+		glib_encoding = "iso-8859-1";
+	} else if (!g_ascii_strcasecmp(extracted_encoding, "ISO-8859-1-Windows-3.1-Latin-1") || !g_ascii_strcasecmp(extracted_encoding, "us-ascii")) {
+		glib_encoding = "Windows-1252";
+	} else if (!g_ascii_strcasecmp(extracted_encoding, "unicode-2-0")) {
+		glib_encoding = "UTF-16BE";
+	} else if (g_ascii_strcasecmp(extracted_encoding, "utf-8")) {
+		purple_debug_warning("oscar", "Unrecognized character encoding \"%s\", attempting to convert to UTF-8 anyway\n", extracted_encoding);
+		glib_encoding = extracted_encoding;
+	}
+
+	if (glib_encoding != NULL) {
+		utf8 = g_convert(text, textlen, "UTF-8", glib_encoding, NULL, NULL, NULL);
+	}
+
+	/*
+	 * If utf8 is still NULL then either the encoding is utf-8 or
+	 * we have been unable to convert the text to utf-8 from the encoding
+	 * that was specified.  So we check if the text is valid utf-8 then
+	 * just copy it.
+	 */
+	if (utf8 == NULL) {
+		if (textlen != 0 && *text != '\0' && !g_utf8_validate(text, textlen, NULL))
+			utf8 = g_strdup(_("(There was an error receiving this message.  The buddy you are speaking with is probably using a different encoding than expected.  If you know what encoding he is using, you can specify it in the advanced account options for your AIM/ICQ account.)"));
+		else
+			utf8 = g_strndup(text, textlen);
+	}
+
+	g_free(extracted_encoding);
+	return utf8;
+}
+
+gchar *
+oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg)
+{
+	const char *charset = NULL;
+	char *ret = NULL;
+
+	if (msg == NULL)
+		return NULL;
+
+	if (g_utf8_validate(msg, -1, NULL))
+		return g_strdup(msg);
+
+	if (od->icq)
+		charset = purple_account_get_string(account, "encoding", NULL);
+
+	if(charset && *charset)
+		ret = g_convert(msg, -1, "UTF-8", charset, NULL, NULL, NULL);
+
+	if(!ret)
+		ret = purple_utf8_try_convert(msg);
+
+	return ret;
+}
+
+static gchar *
+oscar_convert_to_utf8(const gchar *data, gsize datalen, const char *charsetstr, gboolean fallback)
+{
+	gchar *ret = NULL;
+	GError *err = NULL;
+
+	if ((charsetstr == NULL) || (*charsetstr == '\0'))
+		return NULL;
+
+	if (g_ascii_strcasecmp("UTF-8", charsetstr)) {
+		if (fallback)
+			ret = g_convert_with_fallback(data, datalen, "UTF-8", charsetstr, "?", NULL, NULL, &err);
+		else
+			ret = g_convert(data, datalen, "UTF-8", charsetstr, NULL, NULL, &err);
+		if (err != NULL) {
+			purple_debug_warning("oscar", "Conversion from %s failed: %s.\n",
+							   charsetstr, err->message);
+			g_error_free(err);
+		}
+	} else {
+		if (g_utf8_validate(data, datalen, NULL))
+			ret = g_strndup(data, datalen);
+		else
+			purple_debug_warning("oscar", "String is not valid UTF-8.\n");
+	}
+
+	return ret;
+}
+
+gchar *
+oscar_decode_im(PurpleAccount *account, const char *sourcebn, guint16 charset, const gchar *data, gsize datalen)
+{
+	gchar *ret = NULL;
+	/* charsetstr1 is always set to what the correct encoding should be. */
+	const gchar *charsetstr1, *charsetstr2, *charsetstr3 = NULL;
+
+	if ((datalen == 0) || (data == NULL))
+		return NULL;
+
+	if (charset == AIM_CHARSET_UNICODE) {
+		charsetstr1 = "UTF-16BE";
+		charsetstr2 = "UTF-8";
+	} else if (charset == AIM_CHARSET_LATIN_1) {
+		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";
+		charsetstr2 = "UTF-8";
+	} else if (charset == AIM_CHARSET_ASCII) {
+		/* Should just be "ASCII" */
+		charsetstr1 = "ASCII";
+		charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
+	} else if (charset == 0x000d) {
+		/* iChat sending unicode over a Direct IM connection = UTF-8 */
+		/* Mobile AIM client on multiple devices (including Blackberry Tour, Nokia 3100, and LG VX6000) = ISO-8859-1 */
+		charsetstr1 = "UTF-8";
+		charsetstr2 = "ISO-8859-1";
+		charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
+	} else {
+		/* Unknown, hope for valid UTF-8... */
+		charsetstr1 = "UTF-8";
+		charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
+	}
+
+	purple_debug_info("oscar", "Parsing IM, charset=0x%04hx, datalen=%" G_GSIZE_FORMAT ", choice1=%s, choice2=%s, choice3=%s\n",
+					  charset, datalen, charsetstr1, charsetstr2, (charsetstr3 ? charsetstr3 : ""));
+
+	ret = oscar_convert_to_utf8(data, datalen, charsetstr1, FALSE);
+	if (ret == NULL) {
+		if (charsetstr3 != NULL) {
+			/* Try charsetstr2 without allowing substitutions, then fall through to charsetstr3 if needed */
+			ret = oscar_convert_to_utf8(data, datalen, charsetstr2, FALSE);
+			if (ret == NULL)
+				ret = oscar_convert_to_utf8(data, datalen, charsetstr3, TRUE);
+		} else {
+			/* Try charsetstr2, allowing substitutions */
+			ret = oscar_convert_to_utf8(data, datalen, charsetstr2, TRUE);
+		}
+	}
+	if (ret == NULL) {
+		char *str, *salvage, *tmp;
+
+		str = g_malloc(datalen + 1);
+		strncpy(str, data, datalen);
+		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.)"),
+					  sourcebn, sourcebn);
+		ret = g_strdup_printf("%s %s", salvage, tmp);
+		g_free(tmp);
+		g_free(str);
+		g_free(salvage);
+	}
+
+	return ret;
+}
+
+static guint16
+get_simplest_charset(const char *utf8)
+{
+	while (*utf8)
+	{
+		if ((unsigned char)(*utf8) > 0x7f) {
+			/* not ASCII! */
+			return AIM_CHARSET_UNICODE;
+		}
+		utf8++;
+	}
+	return AIM_CHARSET_ASCII;
+}
+
+gchar *
+oscar_encode_im(const gchar *msg, gsize *result_len, guint16 *charset, gchar **charsetstr)
+{
+	guint16 msg_charset = get_simplest_charset(msg);
+	if (charset != NULL) {
+		*charset = msg_charset;
+	}
+	if (charsetstr != NULL) {
+		*charsetstr = msg_charset == AIM_CHARSET_ASCII ? "us-ascii" : "unicode-2-0";
+	}
+	return g_convert(msg, -1, msg_charset == AIM_CHARSET_ASCII ? "ASCII" : "UTF-16BE", "UTF-8", NULL, result_len, NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/encoding.h	Wed Aug 25 19:12:08 2010 +0000
@@ -0,0 +1,46 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+*/
+
+#ifndef _ENCODING_H_
+#define _ENCODING_H_
+
+#include "oscar.h"
+#include "oscarcommon.h"
+
+gchar * oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen);
+gchar * oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg);
+
+/**
+ * This attemps to decode an incoming IM into a UTF8 string.
+ *
+ * We try decoding using two different character sets.  The charset
+ * specified in the IM determines the order in which we attempt to
+ * decode.  We do this because there are lots of broken ICQ clients
+ * that don't correctly send non-ASCII messages.  And if Purple isn't
+ * able to deal with that crap, then people complain like banshees.
+ */
+gchar * oscar_decode_im(PurpleAccount *account, const char *sourcebn, guint16 charset, const gchar *data, gsize datalen);
+
+/**
+ * Figure out what encoding to use when sending a given outgoing message.
+ */
+gchar * oscar_encode_im(const gchar *msg, gsize *result_len, guint16 *charset, gchar **charsetstr);
+
+#endif
\ No newline at end of file
--- a/libpurple/protocols/oscar/family_admin.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_admin.c	Wed Aug 25 19:12:08 2010 +0000
@@ -47,7 +47,7 @@
 	byte_stream_put16(&bs, 0x0000);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0002, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -68,7 +68,7 @@
 	perms = byte_stream_get16(bs);
 	tlvcount = byte_stream_get16(bs);
 
-	while (tlvcount && byte_stream_empty(bs)) {
+	while (tlvcount && byte_stream_bytes_left(bs)) {
 		guint16 type, length;
 
 		type = byte_stream_get16(bs);
@@ -127,7 +127,7 @@
 	aim_tlvlist_free(tlvlist);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -154,7 +154,7 @@
 	aim_tlvlist_free(tlvlist);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -177,7 +177,7 @@
 	aim_tlvlist_free(tlvlist);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
--- a/libpurple/protocols/oscar/family_advert.c	Wed Aug 25 19:11:38 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0005 - Advertisements.
- *
- */
-
-#include "oscar.h"
-
-void
-aim_ads_requestads(OscarData *od, FlapConnection *conn)
-{
-	aim_genericreq_n(od, conn, SNAC_FAMILY_ADVERT, 0x0002);
-}
-
-static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
-{
-	return 0;
-}
-
-int adverts_modfirst(OscarData *od, aim_module_t *mod)
-{
-
-	mod->family = SNAC_FAMILY_ADVERT;
-	mod->version = 0x0001;
-	mod->toolid = 0x0001;
-	mod->toolversion = 0x0001;
-	mod->flags = 0;
-	strncpy(mod->name, "advert", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_alert.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_alert.c	Wed Aug 25 19:12:08 2010 +0000
@@ -73,7 +73,7 @@
 	byte_stream_put16(&bs, 0x0631);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ALERT, 0x0006, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -189,7 +189,7 @@
 	byte_stream_put32(&bs, 0x00000000);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ALERT, 0x0016, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
--- a/libpurple/protocols/oscar/family_auth.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_auth.c	Wed Aug 25 19:12:08 2010 +0000
@@ -56,17 +56,10 @@
 aim_encode_password(const char *password, guint8 *encoded)
 {
 	guint8 encoding_table[] = {
-#if 0 /* old v1 table */
-		0xf3, 0xb3, 0x6c, 0x99,
-		0x95, 0x3f, 0xac, 0xb6,
-		0xc5, 0xfa, 0x6b, 0x63,
-		0x69, 0x6c, 0xc3, 0x9f
-#else /* v2.1 table, also works for ICQ */
 		0xf3, 0x26, 0x81, 0xc4,
 		0x39, 0x86, 0xdb, 0x92,
 		0x71, 0xa3, 0xb9, 0xe6,
 		0x53, 0x7a, 0x95, 0x7c
-#endif
 	};
 	unsigned int i;
 
@@ -234,7 +227,7 @@
 	frame = flap_frame_new(od, 0x02, 1152);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0002, 0x0000, snacid);
+	aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0002, snacid);
 
 	aim_tlvlist_add_str(&tlvlist, 0x0001, sn);
 
@@ -385,12 +378,6 @@
 	if (aim_tlv_gettlv(tlvlist, 0x0043, 1))
 		info->latestbeta.name = aim_tlv_getstr(tlvlist, 0x0043, 1);
 
-#if 0
-	if (aim_tlv_gettlv(tlvlist, 0x0048, 1)) {
-		/* beta serial */
-	}
-#endif
-
 	if (aim_tlv_gettlv(tlvlist, 0x0044, 1))
 		info->latestrelease.build = aim_tlv_get32(tlvlist, 0x0044, 1);
 	if (aim_tlv_gettlv(tlvlist, 0x0045, 1))
@@ -400,27 +387,12 @@
 	if (aim_tlv_gettlv(tlvlist, 0x0047, 1))
 		info->latestrelease.name = aim_tlv_getstr(tlvlist, 0x0047, 1);
 
-#if 0
-	if (aim_tlv_gettlv(tlvlist, 0x0049, 1)) {
-		/* lastest release serial */
-	}
-#endif
-
 	/*
 	 * URL to change password.
 	 */
 	if (aim_tlv_gettlv(tlvlist, 0x0054, 1))
 		info->chpassurl = aim_tlv_getstr(tlvlist, 0x0054, 1);
 
-#if 0
-	/*
-	 * Unknown.  Seen on an @mac.com username with value of 0x003f
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0055, 1)) {
-		/* Unhandled */
-	}
-#endif
-
 	od->authinfo = info;
 
 	if ((userfunc = aim_callhandler(od, snac ? snac->family : SNAC_FAMILY_AUTH, snac ? snac->subtype : 0x0003)))
@@ -504,7 +476,7 @@
 	frame = flap_frame_new(od, 0x02, 10+2+2+strlen(sn)+8);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0006, 0x0000, snacid);
+	aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0006, snacid);
 
 	aim_tlvlist_add_str(&tlvlist, 0x0001, sn);
 
@@ -602,7 +574,7 @@
 	frame = flap_frame_new(od, 0x02, 10+2+len);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, 0);
+	aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0);
 
 	byte_stream_put16(&frame->data, len);
 	byte_stream_putstr(&frame->data, securid);
--- a/libpurple/protocols/oscar/family_bart.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_bart.c	Wed Aug 25 19:12:08 2010 +0000
@@ -56,7 +56,7 @@
 	byte_stream_putraw(&bs, icon, iconlen);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_BART, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0002, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -121,7 +121,7 @@
 	byte_stream_putraw(&bs, iconcsum, iconcsumlen);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_BART, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0004, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0004, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
--- a/libpurple/protocols/oscar/family_bos.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_bos.c	Wed Aug 25 19:12:08 2010 +0000
@@ -68,98 +68,6 @@
 	return ret;
 }
 
-/*
- * Subtype 0x0004 - Set group permission mask.
- *
- * Normally 0x1f (all classes).
- *
- * The group permission mask allows you to keep users of a certain
- * class or classes from talking to you.  The mask should be
- * a bitwise OR of all the user classes you want to see you.
- *
- */
-void
-aim_bos_setgroupperm(OscarData *od, FlapConnection *conn, guint32 mask)
-{
-	aim_genericreq_l(od, conn, SNAC_FAMILY_BOS, 0x0004, &mask);
-}
-
-/*
- * Stubtypes 0x0005, 0x0006, 0x0007, and 0x0008 - Modify permit/deny lists.
- *
- * Changes your visibility depending on changetype:
- *
- *  AIM_VISIBILITYCHANGE_PERMITADD: Lets provided list of names see you
- *  AIM_VISIBILITYCHANGE_PERMIDREMOVE: Removes listed names from permit list
- *  AIM_VISIBILITYCHANGE_DENYADD: Hides you from provided list of names
- *  AIM_VISIBILITYCHANGE_DENYREMOVE: Lets list see you again
- *
- * 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
- *      with only your name on it.
- *   - Allow only users on my Buddy List: Send an
- *      AIM_VISIBILITYCHANGE_PERMITADD with the list the same as your
- *      buddy list
- *   - Allow only the uesrs below: Send an AIM_VISIBILITYCHANGE_PERMITADD
- *      with everyone listed that you want to see you.
- *   - Block all users: Send an AIM_VISIBILITYCHANGE_PERMITADD with only
- *      yourself in the list
- *   - Block the users below: Send an AIM_VISIBILITYCHANGE_DENYADD with
- *      the list of users to be blocked
- *
- * XXX ye gods.
- */
-int aim_bos_changevisibility(OscarData *od, FlapConnection *conn, int changetype, const char *denylist)
-{
-	ByteStream bs;
-	int packlen = 0;
-	guint16 subtype;
-	char *localcpy = NULL, *tmpptr = NULL;
-	int i;
-	int listcount;
-	aim_snacid_t snacid;
-
-	if (!denylist)
-		return -EINVAL;
-
-	if (changetype == AIM_VISIBILITYCHANGE_PERMITADD)
-		subtype = 0x05;
-	else if (changetype == AIM_VISIBILITYCHANGE_PERMITREMOVE)
-		subtype = 0x06;
-	else if (changetype == AIM_VISIBILITYCHANGE_DENYADD)
-		subtype = 0x07;
-	else if (changetype == AIM_VISIBILITYCHANGE_DENYREMOVE)
-		subtype = 0x08;
-	else
-		return -EINVAL;
-
-	localcpy = g_strdup(denylist);
-
-	listcount = aimutil_itemcnt(localcpy, '&');
-	packlen = aimutil_tokslen(localcpy, 99, '&') + listcount-1;
-
-	byte_stream_new(&bs, packlen);
-
-	for (i = 0; (i < (listcount - 1)) && (i < 99); i++) {
-		tmpptr = aimutil_itemindex(localcpy, i, '&');
-
-		byte_stream_put8(&bs, strlen(tmpptr));
-		byte_stream_putstr(&bs, tmpptr);
-
-		g_free(tmpptr);
-	}
-	g_free(localcpy);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_BOS, subtype, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_BOS, subtype, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
 static int
 snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
--- a/libpurple/protocols/oscar/family_buddy.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_buddy.c	Wed Aug 25 19:12:08 2010 +0000
@@ -88,117 +88,6 @@
 }
 
 /*
- * Subtype 0x0004 (SNAC_SUBTYPE_BUDDY_ADDBUDDY) - Add buddy to list.
- *
- * Adds a single buddy to your buddy list after login.
- * XXX This should just be an extension of setbuddylist()
- *
- */
-int
-aim_buddylist_addbuddy(OscarData *od, FlapConnection *conn, const char *sn)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!sn || !strlen(sn))
-		return -EINVAL;
-
-	byte_stream_new(&bs, 1+strlen(sn));
-
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, sn, strlen(sn)+1);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0004 (SNAC_SUBTYPE_BUDDY_ADDBUDDY) - Add multiple buddies to your buddy list.
- *
- * This just builds the "set buddy list" command then queues it.
- *
- * buddy_list = "Buddy Name One&BuddyNameTwo&";
- *
- * XXX Clean this up.
- *
- */
-int
-aim_buddylist_set(OscarData *od, FlapConnection *conn, const char *buddy_list)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-	int len = 0;
-	char *localcpy = NULL;
-	char *tmpptr = NULL;
-
-	if (!buddy_list || !(localcpy = g_strdup(buddy_list)))
-		return -EINVAL;
-
-	for (tmpptr = strtok(localcpy, "&"); tmpptr; ) {
-		purple_debug_misc("oscar", "---adding: %s (%" G_GSIZE_FORMAT
-				")\n", tmpptr, strlen(tmpptr));
-		len += 1 + strlen(tmpptr);
-		tmpptr = strtok(NULL, "&");
-	}
-
-	byte_stream_new(&bs, len);
-
-	strncpy(localcpy, buddy_list, strlen(buddy_list) + 1);
-
-	for (tmpptr = strtok(localcpy, "&"); tmpptr; ) {
-
-		purple_debug_misc("oscar", "---adding: %s (%" G_GSIZE_FORMAT
-				")\n", tmpptr, strlen(tmpptr));
-
-		byte_stream_put8(&bs, strlen(tmpptr));
-		byte_stream_putstr(&bs, tmpptr);
-		tmpptr = strtok(NULL, "&");
-	}
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	g_free(localcpy);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0005 (SNAC_SUBTYPE_BUDDY_REMBUDDY) - Remove buddy from list.
- *
- * XXX generalise to support removing multiple buddies (basically, its
- * the same as setbuddylist() but with a different snac subtype).
- *
- */
-int
-aim_buddylist_removebuddy(OscarData *od, FlapConnection *conn, const char *sn)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!sn || !strlen(sn))
-		return -EINVAL;
-
-	byte_stream_new(&bs, 1 + strlen(sn));
-
-	byte_stream_put8(&bs, strlen(sn));
-	byte_stream_putstr(&bs, sn);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0005, 0x0000, sn, strlen(sn)+1);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0005, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
  * Subtypes 0x000b (SNAC_SUBTYPE_BUDDY_ONCOMING) and 0x000c (SNAC_SUBTYPE_BUDDY_OFFGOING) - Change in buddy status
  *
  * Oncoming Buddy notifications contain a subset of the
--- a/libpurple/protocols/oscar/family_chat.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_chat.c	Wed Aug 25 19:12:08 2010 +0000
@@ -47,74 +47,6 @@
 	return;
 }
 
-char *
-aim_chat_getname(FlapConnection *conn)
-{
-	struct chatconnpriv *ccp;
-
-	if (!conn)
-		return NULL;
-
-	if (conn->type != SNAC_FAMILY_CHAT)
-		return NULL;
-
-	ccp = (struct chatconnpriv *)conn->internal;
-
-	return ccp->name;
-}
-
-/* XXX get this into conn.c -- evil!! */
-FlapConnection *
-aim_chat_getconn(OscarData *od, const char *name)
-{
-	GSList *cur;
-
-	for (cur = od->oscar_connections; cur; cur = cur->next)
-	{
-		FlapConnection *conn;
-		struct chatconnpriv *ccp;
-
-		conn = cur->data;
-		ccp = (struct chatconnpriv *)conn->internal;
-
-		if (conn->type != SNAC_FAMILY_CHAT)
-			continue;
-		if (!conn->internal)
-		{
-			purple_debug_misc("oscar", "%sfaim: chat: chat connection with no name! (fd = %d)\n",
-					conn->gsc ? "(ssl) " : "", conn->gsc ? conn->gsc->fd : conn->fd);
-			continue;
-		}
-
-		if (strcmp(ccp->name, name) == 0)
-			return conn;
-	}
-
-	return NULL;
-}
-
-int
-aim_chat_attachname(FlapConnection *conn, guint16 exchange, const char *roomname, guint16 instance)
-{
-	struct chatconnpriv *ccp;
-
-	if (!conn || !roomname)
-		return -EINVAL;
-
-	if (conn->internal)
-		g_free(conn->internal);
-
-	ccp = g_new(struct chatconnpriv, 1);
-
-	ccp->exchange = exchange;
-	ccp->name = g_strdup(roomname);
-	ccp->instance = instance;
-
-	conn->internal = (void *)ccp;
-
-	return 0;
-}
-
 int
 aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo)
 {
@@ -129,19 +61,6 @@
 	return 0;
 }
 
-int
-aim_chat_leaveroom(OscarData *od, const char *name)
-{
-	FlapConnection *conn;
-
-	if (!(conn = aim_chat_getconn(od, name)))
-		return -ENOENT;
-
-	flap_connection_close(od, conn);
-
-	return 0;
-}
-
 /*
  * Subtype 0x0002 - General room information.  Lots of stuff.
  *
@@ -153,21 +72,12 @@
 static int
 infoupdate(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-	aim_userinfo_t *userinfo = NULL;
 	aim_rxcallback_t userfunc;
 	int ret = 0;
-	int usercount;
 	guint8 detaillevel = 0;
-	char *roomname;
 	struct aim_chat_roominfo roominfo;
-	guint16 tlvcount = 0;
 	GSList *tlvlist;
-	aim_tlv_t *tlv;
-	char *roomdesc;
-	guint16 flags;
-	guint32 creationtime;
 	guint16 maxmsglen, maxvisiblemsglen;
-	guint16 unknown_d2, unknown_d5;
 
 	aim_chat_readroominfo(bs, &roominfo);
 
@@ -178,139 +88,27 @@
 		return 1;
 	}
 
-	tlvcount = byte_stream_get16(bs);
-
 	/*
 	 * Everything else are TLVs.
 	 */
 	tlvlist = aim_tlvlist_read(bs);
 
 	/*
-	 * TLV type 0x006a is the room name in Human Readable Form.
-	 */
-	roomname = aim_tlv_getstr(tlvlist, 0x006a, 1);
-
-	/*
-	 * Type 0x006f: Number of occupants.
-	 */
-	usercount = aim_tlv_get16(tlvlist, 0x006f, 1);
-
-	/*
-	 * Type 0x0073:  Occupant list.
-	 */
-	tlv = aim_tlv_gettlv(tlvlist, 0x0073, 1);
-	if (tlv != NULL)
-	{
-		int curoccupant = 0;
-		ByteStream occbs;
-
-		/* Allocate enough userinfo structs for all occupants */
-		userinfo = g_new0(aim_userinfo_t, usercount);
-
-		byte_stream_init(&occbs, tlv->value, tlv->length);
-
-		while (curoccupant < usercount)
-			aim_info_extract(od, &occbs, &userinfo[curoccupant++]);
-	}
-
-	/*
-	 * Type 0x00c9: Flags. (AIM_CHATROOM_FLAG)
-	 */
-	flags = aim_tlv_get16(tlvlist, 0x00c9, 1);
-
-	/*
-	 * Type 0x00ca: Creation time (4 bytes)
-	 */
-	creationtime = aim_tlv_get32(tlvlist, 0x00ca, 1);
-
-	/*
 	 * Type 0x00d1: Maximum Message Length
 	 */
 	maxmsglen = aim_tlv_get16(tlvlist, 0x00d1, 1);
 
 	/*
-	 * Type 0x00d2: Unknown. (2 bytes)
-	 */
-	unknown_d2 = aim_tlv_get16(tlvlist, 0x00d2, 1);
-
-	/*
-	 * Type 0x00d3: Room Description
-	 */
-	roomdesc = aim_tlv_getstr(tlvlist, 0x00d3, 1);
-
-#if 0
-	/*
-	 * Type 0x000d4: Unknown (flag only)
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x000d4, 1)) {
-		/* Unhandled */
-	}
-#endif
-
-	/*
-	 * Type 0x00d5: Unknown. (1 byte)
-	 */
-	unknown_d5 = aim_tlv_get8(tlvlist, 0x00d5, 1);
-
-#if 0
-	/*
-	 * Type 0x00d6: Encoding 1 ("us-ascii")
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x000d6, 1)) {
-		/* Unhandled */
-	}
-
-	/*
-	 * Type 0x00d7: Language 1 ("en")
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x000d7, 1)) {
-		/* Unhandled */
-	}
-
-	/*
-	 * Type 0x00d8: Encoding 2 ("us-ascii")
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x000d8, 1)) {
-		/* Unhandled */
-	}
-
-	/*
-	 * Type 0x00d9: Language 2 ("en")
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x000d9, 1)) {
-		/* Unhandled */
-	}
-#endif
-
-	/*
 	 * Type 0x00da: Maximum visible message length
 	 */
 	maxvisiblemsglen = aim_tlv_get16(tlvlist, 0x00da, 1);
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
-		ret = userfunc(od, conn,
-				frame,
-				&roominfo,
-				roomname,
-				usercount,
-				userinfo,
-				roomdesc,
-				flags,
-				creationtime,
-				maxmsglen,
-				unknown_d2,
-				unknown_d5,
-				maxvisiblemsglen);
+		ret = userfunc(od, conn, frame, maxmsglen, maxvisiblemsglen);
 	}
 
 	g_free(roominfo.name);
 
-	while (usercount > 0)
-		aim_info_free(&userinfo[--usercount]);
-
-	g_free(userinfo);
-	g_free(roomname);
-	g_free(roomdesc);
 	aim_tlvlist_free(tlvlist);
 
 	return ret;
@@ -324,7 +122,7 @@
 	aim_rxcallback_t userfunc;
 	int curcount = 0, ret = 0;
 
-	while (byte_stream_empty(bs)) {
+	while (byte_stream_bytes_left(bs)) {
 		curcount++;
 		userinfo = g_realloc(userinfo, curcount * sizeof(aim_userinfo_t));
 		aim_info_extract(od, bs, &userinfo[curcount-1]);
@@ -434,7 +232,7 @@
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -523,16 +321,6 @@
 		aim_info_extract(od, &tbs, &userinfo);
 	}
 
-#if 0
-	/*
-	 * Type 0x0001: If present, it means it was a message to the
-	 * room (as opposed to a whisper).
-	 */
-	if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) {
-		/* Unhandled */
-	}
-#endif
-
 	/*
 	 * Type 0x0005: Message Block.  Conains more TLVs.
 	 */
--- a/libpurple/protocols/oscar/family_chatnav.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_chatnav.c	Wed Aug 25 19:12:08 2010 +0000
@@ -139,7 +139,7 @@
 
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_CHATNAV, 0x0008, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_CHATNAV, 0x0008, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -185,32 +185,6 @@
 		exchanges[curexchange-1].number = byte_stream_get16(&tbs);
 		innerlist = aim_tlvlist_read(&tbs);
 
-#if 0
-		/*
-		 * Type 0x000a: Unknown.
-		 *
-		 * Usually three bytes: 0x0114 (exchange 1) or 0x010f (others).
-		 *
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x000a, 1)) {
-			/* Unhandled */
-		}
-
-		/*
-		 * Type 0x000d: Unknown.
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x000d, 1)) {
-			/* Unhandled */
-		}
-
-		/*
-		 * Type 0x0004: Unknown
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x0004, 1)) {
-			/* Unhandled */
-		}
-#endif
-
 		/*
 		 * Type 0x0002: Unknown
 		 */
@@ -234,36 +208,6 @@
 		if (aim_tlv_gettlv(innerlist, 0x00c9, 1))
 			exchanges[curexchange-1].flags = aim_tlv_get16(innerlist, 0x00c9, 1);
 
-#if 0
-		/*
-		 * Type 0x00ca: Creation Date
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00ca, 1)) {
-			/* Unhandled */
-		}
-
-		/*
-		 * Type 0x00d0: Mandatory Channels?
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d0, 1)) {
-			/* Unhandled */
-		}
-
-		/*
-		 * Type 0x00d1: Maximum Message length
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d1, 1)) {
-			/* Unhandled */
-		}
-
-		/*
-		 * Type 0x00d2: Maximum Occupancy?
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d2, 1)) {
-			/* Unhandled */
-		}
-#endif
-
 		/*
 		 * Type 0x00d3: Exchange Description
 		 */
@@ -272,15 +216,6 @@
 		else
 			exchanges[curexchange-1].name = NULL;
 
-#if 0
-		/*
-		 * Type 0x00d4: Exchange Description URL
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d4, 1)) {
-			/* Unhandled */
-		}
-#endif
-
 		/*
 		 * Type 0x00d5: Creation Permissions
 		 *
@@ -327,15 +262,6 @@
 		else
 			exchanges[curexchange-1].lang2 = NULL;
 
-#if 0
-		/*
-		 * Type 0x00da: Unknown
-		 */
-		if (aim_tlv_gettlv(innerlist, 0x00da, 1)) {
-			/* Unhandled */
-		}
-#endif
-
 		aim_tlvlist_free(innerlist);
 	}
 
--- a/libpurple/protocols/oscar/family_feedbag.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_feedbag.c	Wed Aug 25 19:12:08 2010 +0000
@@ -660,10 +660,8 @@
 		if (!cur->name) {
 			if (cur->type == AIM_SSI_TYPE_BUDDY)
 				aim_ssi_delbuddy(od, NULL, NULL);
-			else if (cur->type == AIM_SSI_TYPE_PERMIT)
-				aim_ssi_delpermit(od, NULL);
-			else if (cur->type == AIM_SSI_TYPE_DENY)
-				aim_ssi_deldeny(od, NULL);
+			else if (cur->type == AIM_SSI_TYPE_PERMIT || cur->type == AIM_SSI_TYPE_DENY || cur->type == AIM_SSI_TYPE_ICQDENY)
+				aim_ssi_del_from_private_list(od, NULL, cur->type);
 		} else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(od->ssi.local, cur->gid, 0x0000)))) {
 			char *alias = aim_ssi_getalias(od->ssi.local, NULL, cur->name);
 			aim_ssi_addbuddy(od, cur->name, "orphans", NULL, alias, NULL, NULL, FALSE);
@@ -748,51 +746,31 @@
 	return aim_ssi_sync(od);
 }
 
-/**
- * Add a permit buddy to the list.
- *
- * @param od The oscar odion.
- * @param name The name of the item..
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_addpermit(OscarData *od, const char *name)
+int
+aim_ssi_add_to_private_list(OscarData *od, const char* name, guint16 list_type)
 {
-
 	if (!od || !name || !od->ssi.received_data)
 		return -EINVAL;
 
-	/* Make sure the master group exists */
 	if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL)
-		aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
+		aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, list_type, NULL);
 
-	/* Add that bad boy */
-	aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL);
-
-	/* Sync our local list with the server list */
+	aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, list_type, NULL);
 	return aim_ssi_sync(od);
 }
 
-/**
- * Add a deny buddy to the list.
- *
- * @param od The oscar odion.
- * @param name The name of the item..
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_adddeny(OscarData *od, const char *name)
+int
+aim_ssi_del_from_private_list(OscarData* od, const char* name, guint16 list_type)
 {
+	struct aim_ssi_item *del;
 
-	if (!od || !name || !od->ssi.received_data)
+	if (!od)
 		return -EINVAL;
 
-	/* Make sure the master group exists */
-	if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL)
-		aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
+	if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, list_type)))
+		return -EINVAL;
 
-	/* Add that bad boy */
-	aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL);
-
-	/* Sync our local list with the server list */
+	aim_ssi_itemlist_del(&od->ssi.local, del);
 	return aim_ssi_sync(od);
 }
 
@@ -860,56 +838,6 @@
 }
 
 /**
- * Deletes a permit buddy from the list.
- *
- * @param od The oscar odion.
- * @param name The name of the item, or NULL.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_delpermit(OscarData *od, const char *name)
-{
-	struct aim_ssi_item *del;
-
-	if (!od)
-		return -EINVAL;
-
-	/* Find the item */
-	if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT)))
-		return -EINVAL;
-
-	/* Remove the item from the list */
-	aim_ssi_itemlist_del(&od->ssi.local, del);
-
-	/* Sync our local list with the server list */
-	return aim_ssi_sync(od);
-}
-
-/**
- * Deletes a deny buddy from the list.
- *
- * @param od The oscar odion.
- * @param name The name of the item, or NULL.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_deldeny(OscarData *od, const char *name)
-{
-	struct aim_ssi_item *del;
-
-	if (!od)
-		return -EINVAL;
-
-	/* Find the item */
-	if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, AIM_SSI_TYPE_DENY)))
-		return -EINVAL;
-
-	/* Remove the item from the list */
-	aim_ssi_itemlist_del(&od->ssi.local, del);
-
-	/* Sync our local list with the server list */
-	return aim_ssi_sync(od);
-}
-
-/**
  * Move a buddy from one group to another group.  This basically just deletes the
  * buddy and re-adds it.
  *
@@ -1030,17 +958,16 @@
  * Stores your permit/deny setting on the server, and starts using it.
  *
  * @param od The oscar odion.
- * @param permdeny Your permit/deny setting.  Can be one of the following:
+ * @param permdeny Your permit/deny setting. For ICQ accounts, it actually affects your visibility
+ *        and has nothing to do with blocking. Can be one of the following:
  *        1 - Allow all users
  *        2 - Block all users
  *        3 - Allow only the users below
  *        4 - Block only the users below
  *        5 - Allow only users on my buddy list
- * @param vismask A bitmask of the class of users to whom you want to be
- *        visible.  See the AIM_FLAG_BLEH #defines in oscar.h
  * @return Return 0 if no errors, otherwise return the error number.
  */
-int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny, guint32 vismask)
+int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny)
 {
 	struct aim_ssi_item *tmp;
 
@@ -1059,9 +986,6 @@
 	/* Need to add the 0x00ca TLV to the TLV chain */
 	aim_tlvlist_replace_8(&tmp->data, 0x00ca, permdeny);
 
-	/* Need to add the 0x00cb TLV to the TLV chain */
-	aim_tlvlist_replace_32(&tmp->data, 0x00cb, vismask);
-
 	/* Sync our local list with the server list */
 	return aim_ssi_sync(od);
 }
@@ -1231,41 +1155,6 @@
 }
 
 /*
- * Subtype 0x0005 - Request SSI Data when you have a timestamp and revision
- * number.
- *
- * The data will only be sent if it is newer than the posted local
- * timestamp and revision.
- *
- * Note that the client should never increment the revision, only the server.
- *
- */
-int aim_ssi_reqifchanged(OscarData *od, time_t timestamp, guint16 numitems)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
-		return -EINVAL;
-
-	byte_stream_new(&bs, 4+2);
-
-	byte_stream_put32(&bs, timestamp);
-	byte_stream_put16(&bs, numitems);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	/* Free any current data, just in case */
-	aim_ssi_freelist(od);
-
-	return 0;
-}
-
-/*
  * Subtype 0x0006 - SSI Data.
  */
 static int parsedata(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
@@ -1281,7 +1170,7 @@
 	od->ssi.numitems += byte_stream_get16(bs); /* # of items in this SSI SNAC */
 
 	/* Read in the list */
-	while (byte_stream_empty(bs) > 4) { /* last four bytes are timestamp */
+	while (byte_stream_bytes_left(bs) > 4) { /* last four bytes are timestamp */
 		if ((namelen = byte_stream_get16(bs)))
 			name = byte_stream_getstr(bs, namelen);
 		else
@@ -1378,7 +1267,7 @@
 	}
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -1399,7 +1288,7 @@
 	guint16 len, gid, bid, type;
 	GSList *data;
 
-	while (byte_stream_empty(bs)) {
+	while (byte_stream_bytes_left(bs)) {
 		if ((len = byte_stream_get16(bs)))
 			name = byte_stream_getstr(bs, len);
 		else
@@ -1437,7 +1326,7 @@
 	GSList *data;
 	struct aim_ssi_item *item;
 
-	while (byte_stream_empty(bs)) {
+	while (byte_stream_bytes_left(bs)) {
 		if ((len = byte_stream_get16(bs)))
 			name = byte_stream_getstr(bs, len);
 		else
@@ -1489,7 +1378,7 @@
 	guint16 gid, bid;
 	struct aim_ssi_item *del;
 
-	while (byte_stream_empty(bs)) {
+	while (byte_stream_bytes_left(bs)) {
 		byte_stream_advance(bs, byte_stream_get16(bs));
 		gid = byte_stream_get16(bs);
 		bid = byte_stream_get16(bs);
@@ -1522,7 +1411,7 @@
 
 	/* Read in the success/failure flags from the ack SNAC */
 	cur = od->ssi.pending;
-	while (cur && (byte_stream_empty(bs)>0)) {
+	while (cur && (byte_stream_bytes_left(bs)>0)) {
 		cur->ack = byte_stream_get16(bs);
 		cur = cur->next;
 	}
@@ -1678,45 +1567,6 @@
 }
 
 /*
- * Subtype 0x0014 - Grant authorization
- *
- * Authorizes a contact so they can add you to their contact list.
- *
- */
-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)) || !bn)
-		return -EINVAL;
-
-	byte_stream_new(&bs, 1+strlen(bn) + 2+(msg ? strlen(msg)+1 : 0) + 2);
-
-	/* Username */
-	byte_stream_put8(&bs, strlen(bn));
-	byte_stream_putstr(&bs, bn);
-
-	/* Message (null terminated) */
-	byte_stream_put16(&bs, msg ? strlen(msg) : 0);
-	if (msg) {
-		byte_stream_putstr(&bs, msg);
-		byte_stream_put8(&bs, 0x00);
-	}
-
-	/* Unknown */
-	byte_stream_put16(&bs, 0x0000);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
  * Subtype 0x0015 - Receive an authorization grant
  */
 static int receiveauthgrant(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
@@ -1783,7 +1633,7 @@
 	byte_stream_put16(&bs, 0x0000);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -1863,7 +1713,7 @@
 	byte_stream_put16(&bs, 0x0000);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -1935,6 +1785,16 @@
 	return ret;
 }
 
+/*
+ * If we're on ICQ, then AIM_SSI_TYPE_DENY is used for the "permanently invisible" list.
+ * AIM_SSI_TYPE_ICQDENY is used for blocking users instead.
+ */
+guint16
+aim_ssi_getdenyentrytype(OscarData* od)
+{
+	return od->icq ? AIM_SSI_TYPE_ICQDENY : AIM_SSI_TYPE_DENY;
+}
+
 static int
 snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
--- a/libpurple/protocols/oscar/family_icbm.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_icbm.c	Wed Aug 25 19:12:08 2010 +0000
@@ -44,6 +44,7 @@
  *       Make sure flap_connection_findbygroup is used by all functions.
  */
 
+#include "encoding.h"
 #include "oscar.h"
 #include "peer.h"
 
@@ -108,69 +109,6 @@
 }
 
 /*
- * Takes a msghdr (and a length) and returns a client type
- * code.  Note that this is *only a guess* and has a low likelihood
- * of actually being accurate.
- *
- * Its based on experimental data, with the help of Eric Warmenhoven
- * who seems to have collected a wide variety of different AIM clients.
- *
- *
- * Heres the current collection:
- *  0501 0003 0101 0101 01		AOL Mobile Communicator, WinAIM 1.0.414
- *  0501 0003 0101 0201 01		WinAIM 2.0.847, 2.1.1187, 3.0.1464,
- *					4.3.2229, 4.4.2286
- *  0501 0004 0101 0102 0101		WinAIM 4.1.2010, libfaim (right here)
- *  0501 0003 0101 02			WinAIM 5
- *  0501 0001 01			iChat x.x, mobile buddies
- *  0501 0001 0101 01			AOL v6.0, CompuServe 2000 v6.0, any TOC client
- *  0501 0002 0106			WinICQ 5.45.1.3777.85
- *
- * Note that in this function, only the feature bytes are tested, since
- * the rest will always be the same.
- *
- */
-guint16 aim_im_fingerprint(const guint8 *msghdr, int len)
-{
-	static const struct {
-		guint16 clientid;
-		int len;
-		guint8 data[10];
-	} fingerprints[] = {
-		/* AOL Mobile Communicator, WinAIM 1.0.414 */
-		{ AIM_CLIENTTYPE_MC,
-		  3, {0x01, 0x01, 0x01}},
-
-		/* WinAIM 2.0.847, 2.1.1187, 3.0.1464, 4.3.2229, 4.4.2286 */
-		{ AIM_CLIENTTYPE_WINAIM,
-		  3, {0x01, 0x01, 0x02}},
-
-		/* WinAIM 4.1.2010, libfaim */
-		{ AIM_CLIENTTYPE_WINAIM41,
-		  4, {0x01, 0x01, 0x01, 0x02}},
-
-		/* AOL v6.0, CompuServe 2000 v6.0, any TOC client */
-		{ AIM_CLIENTTYPE_AOL_TOC,
-		  1, {0x01}},
-
-		{ 0, 0, {0x00}}
-	};
-	int i;
-
-	if (!msghdr || (len <= 0))
-		return AIM_CLIENTTYPE_UNKNOWN;
-
-	for (i = 0; fingerprints[i].len; i++) {
-		if (fingerprints[i].len != len)
-			continue;
-		if (memcmp(fingerprints[i].data, msghdr, fingerprints[i].len) == 0)
-			return fingerprints[i].clientid;
-	}
-
-	return AIM_CLIENTTYPE_UNKNOWN;
-}
-
-/*
  * Subtype 0x0001 - Error
  */
 static int
@@ -287,7 +225,7 @@
 	byte_stream_put32(&bs, params->minmsginterval);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0002, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -345,40 +283,14 @@
  *
  * Possible flags:
  *   AIM_IMFLAGS_AWAY  -- Marks the message as an autoresponse
- *   AIM_IMFLAGS_ACK   -- Requests that the server send an ack
- *                        when the message is received (of type SNAC_FAMILY_ICBM/0x000c)
  *   AIM_IMFLAGS_OFFLINE--If destination is offline, store it until they are
  *                        online (probably ICQ only).
  *
- * Generally, you should use the lowest encoding possible to send
- * your message.  If you only use basic punctuation and the generic
- * Latin alphabet, use ASCII7 (no flags).  If you happen to use non-ASCII7
- * characters, but they are all clearly defined in ISO-8859-1, then
- * use that.  Keep in mind that not all characters in the PC ASCII8
- * character set are defined in the ISO standard. For those cases (most
- * notably when the (r) symbol is used), you must use the full UNICODE
- * encoding for your message.  In UNICODE mode, _all_ characters must
- * occupy 16bits, including ones that are not special.  (Remember that
- * the first 128 UNICODE symbols are equivalent to ASCII7, however they
- * must be prefixed with a zero high order byte.)
- *
- * I strongly discourage the use of UNICODE mode, mainly because none
- * of the clients I use can parse those messages (and besides that,
- * wchars are difficult and non-portable to handle in most UNIX environments).
- * If you really need to include special characters, use the HTML UNICODE
- * entities.  These are of the form &#2026; where 2026 is the hex
- * representation of the UNICODE index (in this case, UNICODE
- * "Horizontal Ellipsis", or 133 in in ASCII8).
- *
  * Implementation note:  Since this is one of the most-used functions
  * in all of libfaim, it is written with performance in mind.  As such,
  * it is not as clear as it could be in respect to how this message is
  * supposed to be layed out. Most obviously, tlvlists should be used
  * instead of writing out the bytes manually.
- *
- * XXX - more precise verification that we never send SNACs larger than 8192
- * XXX - check SNAC size for multipart
- *
  */
 int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args)
 {
@@ -387,7 +299,6 @@
 	ByteStream data;
 	guchar cookie[8];
 	int msgtlvlen;
-	static const guint8 deffeatures[] = { 0x01, 0x01, 0x01, 0x02 };
 
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
 		return -EINVAL;
@@ -395,37 +306,17 @@
 	if (!args)
 		return -EINVAL;
 
-	if (args->flags & AIM_IMFLAGS_MULTIPART) {
-		if (args->mpmsg->numparts == 0)
-			return -EINVAL;
-	} else {
-		if (!args->msg || (args->msglen <= 0))
-			return -EINVAL;
+	if (!args->msg || (args->msglen <= 0))
+		return -EINVAL;
 
-		if (args->msglen > MAXMSGLEN)
-			return -E2BIG;
-	}
+	if (args->msglen > MAXMSGLEN)
+		return -E2BIG;
 
 	/* Painfully calculate the size of the message TLV */
 	msgtlvlen = 1 + 1; /* 0501 */
-
-	if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES)
-		msgtlvlen += 2 + args->featureslen;
-	else
-		msgtlvlen += 2 + sizeof(deffeatures);
-
-	if (args->flags & AIM_IMFLAGS_MULTIPART) {
-		aim_mpmsg_section_t *sec;
-
-		for (sec = args->mpmsg->parts; sec; sec = sec->next) {
-			msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
-			msgtlvlen += 4 /* charset */ + sec->datalen;
-		}
-
-	} else {
-		msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
-		msgtlvlen += 4 /* charset */ + args->msglen;
-	}
+	msgtlvlen += 2 + args->featureslen;
+	msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
+	msgtlvlen += 4 /* charset */ + args->msglen;
 
 	byte_stream_new(&data, msgtlvlen + 128);
 
@@ -441,52 +332,31 @@
 
 	/* Features TLV (type 0x0501) */
 	byte_stream_put16(&data, 0x0501);
-	if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) {
-		byte_stream_put16(&data, args->featureslen);
-		byte_stream_putraw(&data, args->features, args->featureslen);
-	} else {
-		byte_stream_put16(&data, sizeof(deffeatures));
-		byte_stream_putraw(&data, deffeatures, sizeof(deffeatures));
-	}
+	byte_stream_put16(&data, args->featureslen);
+	byte_stream_putraw(&data, args->features, args->featureslen);
 
-	if (args->flags & AIM_IMFLAGS_MULTIPART) {
-		aim_mpmsg_section_t *sec;
+	/* Insert message text in a TLV (type 0x0101) */
+	byte_stream_put16(&data, 0x0101);
 
-		/* Insert each message part in a TLV (type 0x0101) */
-		for (sec = args->mpmsg->parts; sec; sec = sec->next) {
-			byte_stream_put16(&data, 0x0101);
-			byte_stream_put16(&data, sec->datalen + 4);
-			byte_stream_put16(&data, sec->charset);
-			byte_stream_put16(&data, sec->charsubset);
-			byte_stream_putraw(&data, (guchar *)sec->data, sec->datalen);
-		}
-
-	} else {
+	/* Message block length */
+	byte_stream_put16(&data, args->msglen + 0x04);
 
-		/* Insert message text in a TLV (type 0x0101) */
-		byte_stream_put16(&data, 0x0101);
-
-		/* Message block length */
-		byte_stream_put16(&data, args->msglen + 0x04);
+	/* Character set */
+	byte_stream_put16(&data, args->charset);
+	/* Character subset -- we always use 0 here */
+	byte_stream_put16(&data, 0x0);
 
-		/* Character set */
-		byte_stream_put16(&data, args->charset);
-		byte_stream_put16(&data, args->charsubset);
-
-		/* Message.  Not terminated */
-		byte_stream_putraw(&data, (guchar *)args->msg, args->msglen);
-	}
+	/* Message.  Not terminated */
+	byte_stream_putraw(&data, (guchar *)args->msg, args->msglen);
 
 	/* Set the Autoresponse flag */
 	if (args->flags & AIM_IMFLAGS_AWAY) {
 		byte_stream_put16(&data, 0x0004);
 		byte_stream_put16(&data, 0x0000);
 	} else {
-		if (args->flags & AIM_IMFLAGS_ACK) {
-			/* Set the Request Acknowledge flag */
-			byte_stream_put16(&data, 0x0003);
-			byte_stream_put16(&data, 0x0000);
-		}
+		/* Set the Request Acknowledge flag */
+		byte_stream_put16(&data, 0x0003);
+		byte_stream_put16(&data, 0x0000);
 
 		if (args->flags & AIM_IMFLAGS_OFFLINE) {
 			/* Allow this message to be queued as an offline message */
@@ -521,7 +391,7 @@
 	/* XXX - should be optional */
 	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);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &data);
 	byte_stream_destroy(&data);
 
 	/* clean out SNACs over 60sec old */
@@ -531,33 +401,6 @@
 }
 
 /*
- * Simple wrapper for aim_im_sendch1_ext()
- *
- * You cannot use aim_send_im if you need the HASICON flag.  You must
- * use aim_im_sendch1_ext directly for that.
- *
- * aim_send_im also cannot be used if you require UNICODE messages, because
- * that requires an explicit message length.  Use aim_im_sendch1_ext().
- *
- */
-int aim_im_sendch1(OscarData *od, const char *bn, guint16 flags, const char *msg)
-{
-	struct aim_sendimext_args args;
-
-	args.destbn = bn;
-	args.flags = flags;
-	args.msg = msg;
-	args.msglen = strlen(msg);
-	args.charset = 0x0000;
-	args.charsubset = 0x0000;
-
-	/* Make these don't get set by accident -- they need aim_im_sendch1_ext */
-	args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON | AIM_IMFLAGS_MULTIPART);
-
-	return aim_im_sendch1_ext(od, &args);
-}
-
-/*
  * Subtype 0x0006 - Send a chat invitation.
  */
 int aim_im_sendch2_chatinvite(OscarData *od, const char *bn, const char *msg, guint16 exchange, const char *roomname, guint16 instance)
@@ -628,7 +471,7 @@
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -698,100 +541,7 @@
 	byte_stream_put16(&bs, 0x0003);
 	byte_stream_put16(&bs, 0x0000);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0006 - Send a rich text message.
- *
- * This only works for ICQ 2001b (thats 2001 not 2000).  Better, only
- * send it to clients advertising the RTF capability.  In fact, if you send
- * it to a client that doesn't support that capability, the server will gladly
- * bounce it back to you.
- *
- * You'd think this would be in icq.c, but, well, I'm trying to stick with
- * the one-group-per-file scheme as much as possible.  This could easily
- * be an exception, since Rendezvous IMs are external of the Oscar core,
- * and therefore are undefined.  Really I just need to think of a good way to
- * make an interface similar to what AOL actually uses.  But I'm not using COM.
- *
- */
-int aim_im_sendch2_rtfmsg(OscarData *od, struct aim_sendrtfmsg_args *args)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	guchar cookie[8];
-	const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* OSCAR_CAPABILITY_ICQRTF capability in string form */
-	int servdatalen;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
-		return -EINVAL;
-
-	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;
-
-	aim_icbm_makecookie(cookie);
-
-	byte_stream_new(&bs, 128+servdatalen);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
-	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, args->destbn);
-
-	/* TLV t(0005) - Encompasses everything below. */
-	byte_stream_put16(&bs, 0x0005);
-	byte_stream_put16(&bs, 2+8+16  +  2+2+2  +  2+2  +  2+2+servdatalen);
-
-	byte_stream_put16(&bs, 0x0000);
-	byte_stream_putraw(&bs, cookie, 8);
-	byte_stream_putcaps(&bs, OSCAR_CAPABILITY_ICQSERVERRELAY);
-
-	/* t(000a) l(0002) v(0001) */
-	byte_stream_put16(&bs, 0x000a);
-	byte_stream_put16(&bs, 0x0002);
-	byte_stream_put16(&bs, 0x0001);
-
-	/* t(000f) l(0000) v() */
-	byte_stream_put16(&bs, 0x000f);
-	byte_stream_put16(&bs, 0x0000);
-
-	/* Service Data TLV */
-	byte_stream_put16(&bs, 0x2711);
-	byte_stream_put16(&bs, servdatalen);
-
-	byte_stream_putle16(&bs, 11 + 16 /* 11 + (sizeof CLSID) */);
-	byte_stream_putle16(&bs, 9);
-	byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY);
-	byte_stream_putle16(&bs, 0);
-	byte_stream_putle32(&bs, 0);
-	byte_stream_putle8(&bs, 0);
-	byte_stream_putle16(&bs, 0x03ea); /* trid1 */
-
-	byte_stream_putle16(&bs, 14);
-	byte_stream_putle16(&bs, 0x03eb); /* trid2 */
-	byte_stream_putle32(&bs, 0);
-	byte_stream_putle32(&bs, 0);
-	byte_stream_putle32(&bs, 0);
-
-	byte_stream_putle16(&bs, 0x0001);
-	byte_stream_putle32(&bs, 0);
-	byte_stream_putle16(&bs, strlen(args->rtfmsg)+1);
-	byte_stream_putraw(&bs, (const guint8 *)args->rtfmsg, strlen(args->rtfmsg)+1);
-
-	byte_stream_putle32(&bs, args->fgcolor);
-	byte_stream_putle32(&bs, args->bgcolor);
-	byte_stream_putle32(&bs, strlen(rtfcap)+1);
-	byte_stream_putraw(&bs, (const guint8 *)rtfcap, strlen(rtfcap)+1);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -844,7 +594,7 @@
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -879,7 +629,7 @@
 	byte_stream_putraw(&bs, peer_conn->cookie, 8);
 	byte_stream_putcaps(&bs, peer_conn->type);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -934,7 +684,7 @@
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -997,7 +747,7 @@
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -1044,17 +794,6 @@
 	aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
 	/* TODO: Send 0x0016 and 0x0017 */
 
-#if 0
-	/* TODO: If the following is ever enabled, ensure that it is
-	 *       not sent with a receive redirect or stage 3 proxy
-	 *       redirect for a file receive (same conditions for
-	 *       sending 0x000f above)
-	 */
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x000e, 2, "en");
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x000d, 8, "us-ascii");
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, 24, "Please accept this file.");
-#endif
-
 	if (filename != NULL)
 	{
 		ByteStream inner_bs;
@@ -1083,7 +822,7 @@
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -1136,17 +875,6 @@
 	aim_tlvlist_add_raw(&inner_tlvlist, 0x0016, 4, ip_comp);
 	aim_tlvlist_add_16(&inner_tlvlist, 0x0017, ~pin);
 
-#if 0
-	/* TODO: If the following is ever enabled, ensure that it is
-	 *       not sent with a receive redirect or stage 3 proxy
-	 *       redirect for a file receive (same conditions for
-	 *       sending 0x000f above)
-	 */
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x000e, 2, "en");
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x000d, 8, "us-ascii");
-	aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, 24, "Please accept this file.");
-#endif
-
 	if (filename != NULL)
 	{
 		ByteStream filename_bs;
@@ -1176,530 +904,57 @@
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
 
-/**
- * Subtype 0x0006 - Request the status message of the given ICQ user.
- *
- * @param od The oscar session.
- * @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 *bn, int type)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	guchar cookie[8];
-
-	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(bn) + 4+0x5e + 4);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
-	/* ICBM header */
-	aim_im_puticbm(&bs, cookie, 0x0002, bn);
-
-	/* TLV t(0005) - Encompasses almost everything below. */
-	byte_stream_put16(&bs, 0x0005); /* T */
-	byte_stream_put16(&bs, 0x005e); /* L */
-	{ /* V */
-		byte_stream_put16(&bs, 0x0000);
-
-		/* Cookie */
-		byte_stream_putraw(&bs, cookie, 8);
-
-		/* Put the 16 byte server relay capability */
-		byte_stream_putcaps(&bs, OSCAR_CAPABILITY_ICQSERVERRELAY);
-
-		/* TLV t(000a) */
-		byte_stream_put16(&bs, 0x000a);
-		byte_stream_put16(&bs, 0x0002);
-		byte_stream_put16(&bs, 0x0001);
-
-		/* TLV t(000f) */
-		byte_stream_put16(&bs, 0x000f);
-		byte_stream_put16(&bs, 0x0000);
-
-		/* TLV t(2711) */
-		byte_stream_put16(&bs, 0x2711);
-		byte_stream_put16(&bs, 0x0036);
-		{ /* V */
-			byte_stream_putle16(&bs, 0x001b); /* L */
-			byte_stream_putle16(&bs, 0x0009); /* Protocol version */
-			byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY);
-			byte_stream_putle16(&bs, 0x0000); /* Unknown */
-			byte_stream_putle16(&bs, 0x0001); /* Client features? */
-			byte_stream_putle16(&bs, 0x0000); /* Unknown */
-			byte_stream_putle8(&bs, 0x00); /* Unkizown */
-			byte_stream_putle16(&bs, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
-
-			byte_stream_putle16(&bs, 0x000e); /* L */
-			byte_stream_putle16(&bs, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
-			byte_stream_putle32(&bs, 0x00000000); /* Unknown */
-			byte_stream_putle32(&bs, 0x00000000); /* Unknown */
-			byte_stream_putle32(&bs, 0x00000000); /* Unknown */
-
-			/* The type of status message being requested */
-			if (type & AIM_ICQ_STATE_CHAT)
-				byte_stream_putle16(&bs, 0x03ec);
-			else if(type & AIM_ICQ_STATE_DND)
-				byte_stream_putle16(&bs, 0x03eb);
-			else if(type & AIM_ICQ_STATE_OUT)
-				byte_stream_putle16(&bs, 0x03ea);
-			else if(type & AIM_ICQ_STATE_BUSY)
-				byte_stream_putle16(&bs, 0x03e9);
-			else if(type & AIM_ICQ_STATE_AWAY)
-				byte_stream_putle16(&bs, 0x03e8);
-
-			byte_stream_putle16(&bs, 0x0001); /* Status? */
-			byte_stream_putle16(&bs, 0x0001); /* Priority of this message? */
-			byte_stream_putle16(&bs, 0x0001); /* L */
-			byte_stream_putle8(&bs, 0x00); /* String of length L */
-		} /* End TLV t(2711) */
-	} /* End TLV t(0005) */
-
-	/* TLV t(0003) */
-	byte_stream_put16(&bs, 0x0003);
-	byte_stream_put16(&bs, 0x0000);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/**
- * Subtype 0x0006 - Send an ICQ-esque ICBM.
- *
- * This can be used to send an ICQ authorization reply (deny or grant).  It is the "old way."
- * The new way is to use SSI.  I like the new way a lot better.  This seems like such a hack,
- * mostly because it's in network byte order.  Figuring this stuff out sometimes takes a while,
- * 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 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 *bn, guint16 type, const char *message)
+static void
+incomingim_ch1_parsemsg(OscarData *od, aim_userinfo_t *userinfo, ByteStream *message, struct aim_incomingim_ch1_args *args)
 {
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	guchar cookie[8];
-
-	if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
-		return -EINVAL;
-
-	if (!bn || !type || !message)
-		return -EINVAL;
-
-	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, bn);
-
+	PurpleAccount *account = purple_connection_get_account(od->gc);
 	/*
-	 * TLV t(0005)
-	 *
-	 * ICQ data (the UIN and the message).
+	 * We're interested in the inner TLV 0x101, which contains precious, precious message.
 	 */
-	byte_stream_put16(&bs, 0x0005);
-	byte_stream_put16(&bs, 4 + 2+2+strlen(message)+1);
-
-	/*
-	 * Your UIN
-	 */
-	byte_stream_putuid(&bs, od);
-
-	/*
-	 * TLV t(type) l(strlen(message)+1) v(message+NULL)
-	 */
-	byte_stream_putle16(&bs, type);
-	byte_stream_putle16(&bs, strlen(message)+1);
-	byte_stream_putraw(&bs, (const guint8 *)message, strlen(message)+1);
-
-	/*
-	 * TLV t(0006) l(0000) v()
-	 */
-	byte_stream_put16(&bs, 0x0006);
-	byte_stream_put16(&bs, 0x0000);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
+	while (byte_stream_bytes_left(message) >= 4) {
+		guint16 type = byte_stream_get16(message);
+		guint16 length = byte_stream_get16(message);
+		if (type == 0x101) {
+			gchar *msg;
+			guint16 msglen = length - 4; /* charset + charsubset */
+			guint16 charset = byte_stream_get16(message);
+			byte_stream_advance(message, 2); /* charsubset */
 
-/*
- * XXX - I don't see when this would ever get called...
- */
-static int outgoingim(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guchar cookie[8];
-	guint16 channel;
-	GSList *tlvlist;
-	char *bn;
-	int bnlen;
-	guint16 icbmflags = 0;
-	guint8 flag1 = 0, flag2 = 0;
-	gchar *msg = NULL;
-	aim_tlv_t *msgblock;
-
-	/* ICBM Cookie. */
-	aim_icbm_makecookie(cookie);
-
-	/* Channel ID */
-	channel = byte_stream_get16(bs);
-
-	if (channel != 0x01) {
-		purple_debug_misc("oscar", "icbm: ICBM received on unsupported channel.  Ignoring. (chan = %04x)\n", channel);
-		return 0;
+			msg = byte_stream_getstr(message, msglen);
+			args->msg = oscar_decode_im(account, userinfo->bn, charset, msg, msglen);
+		} else {
+			byte_stream_advance(message, length);
+		}
 	}
-
-	bnlen = byte_stream_get8(bs);
-	bn = byte_stream_getstr(bs, bnlen);
-
-	tlvlist = aim_tlvlist_read(bs);
-
-	if (aim_tlv_gettlv(tlvlist, 0x0003, 1))
-		icbmflags |= AIM_IMFLAGS_ACK;
-	if (aim_tlv_gettlv(tlvlist, 0x0004, 1))
-		icbmflags |= AIM_IMFLAGS_AWAY;
-
-	if ((msgblock = aim_tlv_gettlv(tlvlist, 0x0002, 1))) {
-		ByteStream mbs;
-		int featurelen, msglen;
-
-		byte_stream_init(&mbs, msgblock->value, msgblock->length);
-
-		byte_stream_get8(&mbs);
-		byte_stream_get8(&mbs);
-		for (featurelen = byte_stream_get16(&mbs); featurelen; featurelen--)
-			byte_stream_get8(&mbs);
-		byte_stream_get8(&mbs);
-		byte_stream_get8(&mbs);
-
-		msglen = byte_stream_get16(&mbs) - 4; /* final block length */
-
-		flag1 = byte_stream_get16(&mbs);
-		flag2 = byte_stream_get16(&mbs);
-
-		msg = byte_stream_getstr(&mbs, msglen);
-	}
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, channel, bn, msg, icbmflags, flag1, flag2);
-
-	g_free(bn);
-	g_free(msg);
-	aim_tlvlist_free(tlvlist);
-
-	return ret;
 }
 
-/*
- * Ahh, the joys of nearly ridiculous over-engineering.
- *
- * Not only do AIM ICBM's support multiple channels.  Not only do they
- * support multiple character sets.  But they support multiple character
- * sets / encodings within the same ICBM.
- *
- * These multipart messages allow for complex space savings techniques, which
- * seem utterly unnecessary by today's standards.  In fact, there is only
- * one client still in popular use that still uses this method: AOL for the
- * Macintosh, Version 5.0.  Obscure, yes, I know.
- *
- * In modern (non-"legacy") clients, if the user tries to send a character
- * that is not ISO-8859-1 or ASCII, the client will send the entire message
- * as UNICODE, meaning that every character in the message will occupy the
- * full 16 bit UNICODE field, even if the high order byte would be zero.
- * Multipart messages prevent this wasted space by allowing the client to
- * only send the characters in UNICODE that need to be sent that way, and
- * the rest of the message can be sent in whatever the native character
- * set is (probably ASCII).
- *
- * An important note is that sections will be displayed in the order that
- * they appear in the ICBM.  There is no facility for merging or rearranging
- * sections at run time.  So if you have, say, ASCII then UNICODE then ASCII,
- * you must supply two ASCII sections with a UNICODE in the middle, and incur
- * the associated overhead.
- *
- * Normally I would have laughed and given a firm 'no' to supporting this
- * seldom-used feature, but something is attracting me to it.  In the future,
- * it may be possible to abuse this to send mixed-media messages to other
- * open source clients (like encryption or something) -- see faimtest for
- * examples of how to do this.
- *
- * I would definitely recommend avoiding this feature unless you really
- * know what you are doing, and/or you have something neat to do with it.
- *
- */
-int aim_mpmsg_init(OscarData *od, aim_mpmsg_t *mpm)
-{
-
-	memset(mpm, 0, sizeof(aim_mpmsg_t));
-
-	return 0;
-}
-
-static int mpmsg_addsection(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, gchar *data, guint16 datalen)
-{
-	aim_mpmsg_section_t *sec;
-
-	sec = g_malloc(sizeof(aim_mpmsg_section_t));
-
-	sec->charset = charset;
-	sec->charsubset = charsubset;
-	sec->data = data;
-	sec->datalen = datalen;
-	sec->next = NULL;
-
-	if (!mpm->parts)
-		mpm->parts = sec;
-	else {
-		aim_mpmsg_section_t *cur;
-
-		for (cur = mpm->parts; cur->next; cur = cur->next)
-			;
-		cur->next = sec;
-	}
-
-	mpm->numparts++;
-
-	return 0;
-}
-
-int aim_mpmsg_addraw(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, const gchar *data, guint16 datalen)
-{
-	gchar *dup;
-
-	dup = g_malloc(datalen);
-	memcpy(dup, data, datalen);
-
-	if (mpmsg_addsection(od, mpm, charset, charsubset, dup, datalen) == -1) {
-		g_free(dup);
-		return -1;
-	}
-
-	return 0;
-}
-
-/* XXX - should provide a way of saying ISO-8859-1 specifically */
-int aim_mpmsg_addascii(OscarData *od, aim_mpmsg_t *mpm, const char *ascii)
-{
-	gchar *dup;
-
-	if (!(dup = g_strdup(ascii)))
-		return -1;
-
-	if (mpmsg_addsection(od, mpm, 0x0000, 0x0000, dup, strlen(ascii)) == -1) {
-		g_free(dup);
-		return -1;
-	}
-
-	return 0;
-}
-
-int aim_mpmsg_addunicode(OscarData *od, aim_mpmsg_t *mpm, const guint16 *unicode, guint16 unicodelen)
-{
-	gchar *buf;
-	ByteStream bs;
-	int i;
-
-	buf = g_malloc(unicodelen * 2);
-
-	byte_stream_init(&bs, (guchar *)buf, unicodelen * 2);
-
-	/* We assume unicode is in /host/ byte order -- convert to network */
-	for (i = 0; i < unicodelen; i++)
-		byte_stream_put16(&bs, unicode[i]);
-
-	if (mpmsg_addsection(od, mpm, 0x0002, 0x0000, buf, byte_stream_curpos(&bs)) == -1) {
-		g_free(buf);
-		return -1;
-	}
-
-	return 0;
-}
-
-void aim_mpmsg_free(OscarData *od, aim_mpmsg_t *mpm)
+static int
+incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, ByteStream *bs, guint8 *cookie)
 {
-	aim_mpmsg_section_t *cur;
-
-	for (cur = mpm->parts; cur; ) {
-		aim_mpmsg_section_t *tmp;
-
-		tmp = cur->next;
-		g_free(cur->data);
-		g_free(cur);
-		cur = tmp;
-	}
-
-	mpm->numparts = 0;
-	mpm->parts = NULL;
-
-	return;
-}
-
-/*
- * Start by building the multipart structures, then pick the first
- * human-readable section and stuff it into args->msg so no one gets
- * suspicious.
- */
-static int incomingim_ch1_parsemsgs(OscarData *od, aim_userinfo_t *userinfo, guint8 *data, int len, struct aim_incomingim_ch1_args *args)
-{
-	/* Should this be ASCII -> UNICODE -> Custom */
-	static const guint16 charsetpri[] = {
-		AIM_CHARSET_ASCII, /* ASCII first */
-		AIM_CHARSET_LATIN_1, /* then ISO-8859-1 */
-		AIM_CHARSET_UNICODE, /* UNICODE as last resort */
-	};
-	static const int charsetpricount = 3;
-	int i;
-	ByteStream mbs;
-	aim_mpmsg_section_t *sec;
-
-	byte_stream_init(&mbs, data, len);
-
-	while (byte_stream_empty(&mbs)) {
-		guint16 msglen, flag1, flag2;
-		gchar *msgbuf;
-
-		byte_stream_get8(&mbs); /* 01 */
-		byte_stream_get8(&mbs); /* 01 */
-
-		/* Message string length, including character set info. */
-		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->bn);
-			break;
-		}
-
-		/* Character set info */
-		flag1 = byte_stream_get16(&mbs);
-		flag2 = byte_stream_get16(&mbs);
-
-		/* Message. */
-		msglen -= 4;
-
-		/*
-		 * For now, we don't care what the encoding is.  Just copy
-		 * it into a multipart struct and deal with it later. However,
-		 * always pad the ending with a NULL.  This makes it easier
-		 * to treat ASCII sections as strings.  It won't matter for
-		 * UNICODE or binary data, as you should never read past
-		 * the specified data length, which will not include the pad.
-		 *
-		 * XXX - There's an API bug here.  For sending, the UNICODE is
-		 * given in host byte order (aim_mpmsg_addunicode), but here
-		 * the received messages are given in network byte order.
-		 *
-		 */
-		msgbuf = (gchar *)byte_stream_getraw(&mbs, msglen);
-		mpmsg_addsection(od, &args->mpmsg, flag1, flag2, msgbuf, msglen);
-
-	} /* while */
-
-	args->icbmflags |= AIM_IMFLAGS_MULTIPART; /* always set */
-
-	/*
-	 * Clients that support multiparts should never use args->msg, as it
-	 * will point to an arbitrary section.
-	 *
-	 * Here, we attempt to provide clients that do not support multipart
-	 * messages with something to look at -- hopefully a human-readable
-	 * string.  But, failing that, a UNICODE message, or nothing at all.
-	 *
-	 * Which means that even if args->msg is NULL, it does not mean the
-	 * message was blank.
-	 *
-	 */
-	for (i = 0; i < charsetpricount; i++) {
-		for (sec = args->mpmsg.parts; sec; sec = sec->next) {
-
-			if (sec->charset != charsetpri[i])
-				continue;
-
-			/* Great. We found one.  Fill it in. */
-			args->charset = sec->charset;
-			args->charsubset = sec->charsubset;
-
-			/* Set up the simple flags */
-			switch (args->charsubset)
-			{
-				case 0x0000:
-					/* standard subencoding? */
-					break;
-				case 0x000b:
-					args->icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH;
-					break;
-				case 0xffff:
-					/* no subencoding */
-					break;
-				default:
-					break;
-			}
-
-			args->msg = sec->data;
-			args->msglen = sec->datalen;
-
-			return 0;
-		}
-	}
-
-	/* No human-readable sections found.  Oh well. */
-	args->charset = args->charsubset = 0xffff;
-	args->msg = NULL;
-	args->msglen = 0;
-
-	return 0;
-}
-
-static int incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, ByteStream *bs, guint8 *cookie)
-{
-	guint16 type, length, magic1, msglen = 0;
+	guint16 type, length;
 	aim_rxcallback_t userfunc;
 	int ret = 0;
-	int rev = 0;
 	struct aim_incomingim_ch1_args args;
 	unsigned int endpos;
 
 	memset(&args, 0, sizeof(args));
 
-	aim_mpmsg_init(od, &args.mpmsg);
-
 	/*
 	 * This used to be done using tlvchains.  For performance reasons,
 	 * I've changed it to process the TLVs in-place.  This avoids lots
 	 * of per-IM memory allocations.
 	 */
-	while (byte_stream_empty(bs) >= 4)
+	while (byte_stream_bytes_left(bs) >= 4)
 	{
 		type = byte_stream_get16(bs);
 		length = byte_stream_get16(bs);
 
-		if (length > byte_stream_empty(bs))
+		if (length > byte_stream_bytes_left(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->bn);
 			break;
@@ -1708,93 +963,20 @@
 		endpos = byte_stream_curpos(bs) + length;
 
 		if (type == 0x0002) { /* Message Block */
-
-			/*
-			 * This TLV consists of the following:
-			 *   - 0501 -- Unknown
-			 *   - Features: Don't know how to interpret these
-			 *   - 0101 -- Unknown
-			 *   - Message
-			 *
-			 * Slick and possible others reverse 'Features' and 'Messages' section.
-			 * Thus, the TLV could have following layout:
-			 *   - 0101 -- Unknown (possibly magic for message section)
-			 *   - Message
-			 *   - 0501 -- Unknown (possibly magic for features section)
-			 *   - Features: Don't know how to interpret these
-			 */
-
-			magic1 = byte_stream_get16(bs); /* 0501 or 0101 */
-			if (magic1 == 0x101) /* Bad, message comes before attributes */
-			{
-				/* Jump to the features section */
-				msglen = byte_stream_get16(bs);
-				bs->offset += msglen;
-				rev = 1;
-
-				magic1 = byte_stream_get16(bs); /* 0501 */
-			}
-
-			if (magic1 != 0x501)
-			{
-				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;
-			}
-
-			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->bn);
-				break;
-			}
-			if (args.featureslen == 0)
-			{
-				args.features = NULL;
-			}
-			else
-			{
-				args.features = byte_stream_getraw(bs, args.featureslen);
-				args.icbmflags |= AIM_IMFLAGS_CUSTOMFEATURES;
-			}
-
-			if (rev)
-			{
-				/* Fix buffer back to message */
-				bs->offset -= args.featureslen + 2 + 2 + msglen + 2 + 2;
-			}
-
-			magic1 = byte_stream_get16(bs); /* 01 01 */
-			if (magic1 != 0x101) /* Bad, message comes before attributes */
-			{
-				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;
-			}
-			msglen = byte_stream_get16(bs);
-
-			/*
-			 * The rest of the TLV contains one or more message
-			 * blocks...
-			 */
-			incomingim_ch1_parsemsgs(od, userinfo, bs->data + bs->offset - 2 - 2 /* XXX evil!!! */, msglen + 2 + 2, &args);
-
+			ByteStream tlv02;
+			byte_stream_init(&tlv02, bs->data + bs->offset, length);
+			incomingim_ch1_parsemsg(od, userinfo, &tlv02, &args);
 		} else if (type == 0x0003) { /* Server Ack Requested */
-
 			args.icbmflags |= AIM_IMFLAGS_ACK;
-
 		} else if (type == 0x0004) { /* Message is Auto Response */
-
 			args.icbmflags |= AIM_IMFLAGS_AWAY;
-
 		} else if (type == 0x0006) { /* Message was received offline. */
-
 			/*
 			 * This flag is set on incoming offline messages for both
 			 * AIM and ICQ accounts.
 			 */
 			args.icbmflags |= AIM_IMFLAGS_OFFLINE;
-
 		} else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */
-
 			args.iconlen = byte_stream_get32(bs);
 			byte_stream_get16(bs); /* 0x0001 */
 			args.iconsum = byte_stream_get16(bs);
@@ -1812,39 +994,16 @@
 			 */
 			if (args.iconlen)
 				args.icbmflags |= AIM_IMFLAGS_HASICON;
-
 		} else if (type == 0x0009) {
-
 			args.icbmflags |= AIM_IMFLAGS_BUDDYREQ;
-
 		} else if (type == 0x000b) { /* Non-direct connect typing notification */
-
 			args.icbmflags |= AIM_IMFLAGS_TYPINGNOT;
-
 		} else if (type == 0x0016) {
-
 			/*
 			 * UTC timestamp for when the message was sent.  Only
 			 * provided for offline messages.
 			 */
 			args.timestamp = byte_stream_get32(bs);
-
-		} else if (type == 0x0017) {
-
-			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->bn);
-				break;
-			}
-			g_free(args.extdata);
-			args.extdatalen = length;
-			if (args.extdatalen == 0)
-				args.extdata = NULL;
-			else
-				args.extdata = byte_stream_getraw(bs, args.extdatalen);
-
-		} else {
-			purple_debug_misc("oscar", "incomingim_ch1: unknown TLV 0x%04x (len %d)\n", type, length);
 		}
 
 		/*
@@ -1862,10 +1021,7 @@
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
 		ret = userfunc(od, conn, frame, channel, userinfo, &args);
 
-	aim_mpmsg_free(od, &args.mpmsg);
-	g_free(args.features);
-	g_free(args.extdata);
-
+	g_free(args.msg);
 	return ret;
 }
 
@@ -1891,7 +1047,7 @@
 	 *     ...
 	 *   ...
 	 */
-	while (byte_stream_empty(servdata))
+	while (byte_stream_bytes_left(servdata))
 	{
 		guint16 gnlen, numb;
 		int i;
@@ -1963,7 +1119,7 @@
 static void
 incomingim_ch2_icqserverrelay_free(OscarData *od, IcbmArgsCh2 *args)
 {
-	g_free((char *)args->info.rtfmsg.rtfmsg);
+	g_free((char *)args->info.rtfmsg.msg);
 }
 
 /*
@@ -1977,33 +1133,34 @@
 static void
 incomingim_ch2_icqserverrelay(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
 {
-	guint16 hdrlen, anslen, msglen;
+	guint16 hdrlen, msglen;
+
+	args->destructor = (void *)incomingim_ch2_icqserverrelay_free;
 
-	if (byte_stream_empty(servdata) < 24)
-		/* Someone sent us a short server relay ICBM.  Weird.  (Maybe?) */
-		return;
-
-	hdrlen = byte_stream_getle16(servdata);
-	byte_stream_advance(servdata, hdrlen);
-
-	hdrlen = byte_stream_getle16(servdata);
+#define SKIP_HEADER(expected_hdrlen) \
+	hdrlen = byte_stream_getle16(servdata); \
+	if (hdrlen != expected_hdrlen) { \
+		purple_debug_warning("oscar", "Expected to find a header with length " #expected_hdrlen "; ignoring message"); \
+		return; \
+	} \
 	byte_stream_advance(servdata, hdrlen);
 
-	args->info.rtfmsg.msgtype = byte_stream_getle16(servdata);
+	SKIP_HEADER(0x001b);
+	SKIP_HEADER(0x000e);
 
-	anslen = byte_stream_getle32(servdata);
-	byte_stream_advance(servdata, anslen);
+	args->info.rtfmsg.msgtype = byte_stream_get8(servdata);
+	/*
+	 * Copied from http://iserverd.khstu.ru/oscar/message.html:
+	 * xx      byte       message flags
+	 * xx xx   word (LE)  status code
+	 * xx xx   word (LE)  priority code
+	 *
+	 * We don't need any of these, so just skip them.
+	 */
+	byte_stream_advance(servdata, 1 + 2 + 2);
 
 	msglen = byte_stream_getle16(servdata);
-	args->info.rtfmsg.rtfmsg = byte_stream_getstr(servdata, msglen);
-
-	args->info.rtfmsg.fgcolor = byte_stream_getle32(servdata);
-	args->info.rtfmsg.bgcolor = byte_stream_getle32(servdata);
-
-	hdrlen = byte_stream_getle32(servdata);
-	byte_stream_advance(servdata, hdrlen);
-
-	args->destructor = (void *)incomingim_ch2_icqserverrelay_free;
+	args->info.rtfmsg.msg = byte_stream_getstr(servdata, msglen);
 }
 
 static void
@@ -2188,20 +1345,6 @@
 	if (aim_tlv_gettlv(list2, 0x000e, 1))
 		args.language = aim_tlv_getstr(list2, 0x000e, 1);
 
-#if 0
-	/*
-	 * Unknown -- no value
-	 *
-	 * Maybe means we should connect directly to transfer the file?
-	 * Also used in ICQ Lite Beta 4.0 URLs.  Also empty.
-	 */
-	 /* I don't think this indicates a direct transfer; this flag is
-	  * also present in a stage 1 proxied file send request -- Jonathan */
-	if (aim_tlv_gettlv(list2, 0x000f, 1)) {
-		/* Unhandled */
-	}
-#endif
-
 	/*
 	 * Flag meaning we should proxy the file transfer through an AIM server
 	 */
@@ -2396,38 +1539,6 @@
 	return ret;
 }
 
-/*
- * Subtype 0x0008 - Send a warning to bn.
- *
- * Flags:
- *  AIM_WARN_ANON  Send as an anonymous (doesn't count as much)
- *
- * returns -1 on error (couldn't alloc packet), 0 on success.
- *
- */
-int aim_im_warn(OscarData *od, FlapConnection *conn, const char *bn, guint32 flags)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !conn || !bn)
-		return -EINVAL;
-
-	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(bn));
-	byte_stream_putstr(&bs, bn);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0008, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
 /* Subtype 0x000a */
 static int missedcall(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
@@ -2436,7 +1547,7 @@
 	guint16 channel, nummissed, reason;
 	aim_userinfo_t userinfo;
 
-	while (byte_stream_empty(bs)) {
+	while (byte_stream_bytes_left(bs)) {
 
 		channel = byte_stream_get16(bs);
 		aim_info_extract(od, bs, &userinfo);
@@ -2456,9 +1567,7 @@
  * Subtype 0x000b
  *
  * Possible codes:
- *    AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support"
  *    AIM_TRANSFER_DENY_DECLINE -- "client has declined transfer"
- *    AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers"
  *
  */
 int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, guint16 code)
@@ -2485,186 +1594,57 @@
 	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x000b, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x000b, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
 	return 0;
 }
 
-static void parse_status_note_text(OscarData *od, guchar *cookie, char *bn, ByteStream *bs)
+/*
+ * Subtype 0x000b.
+ * Send confirmation for a channel 2 message (Miranda wants it by default).
+ */
+void
+aim_im_send_icq_confirmation(OscarData *od, const char *bn, const guchar *cookie)
 {
-	struct aim_icq_info *info;
-	struct aim_icq_info *prev_info;
-	char *response;
-	char *encoding;
-	char *stripped_encoding;
-	char *status_note_title;
-	char *status_note_text;
-	char *stripped_status_note_text;
-	char *status_note;
-	guint32 length;
-	guint16 version;
-	guint32 capability;
-	guint8 message_type;
-	guint16 status_code;
-	guint16 text_length;
-	guint32 request_length;
-	guint32 response_length;
-	guint32 encoding_length;
-	PurpleAccount *account;
-	PurpleBuddy *buddy;
-	PurplePresence *presence;
-	PurpleStatus *status;
-
-	for (prev_info = NULL, info = od->icq_info; info != NULL; prev_info = info, info = info->next)
-	{
-		if (memcmp(&info->icbm_cookie, cookie, 8) == 0)
-		{
-			if (prev_info == NULL)
-				od->icq_info = info->next;
-			else
-				prev_info->next = info->next;
-
-			break;
-		}
-	}
-
-	if (info == NULL)
-		return;
+	ByteStream bs;
+	aim_snacid_t snacid;
+	guint32 header_size, data_size;
+	guint16 cookie2 = (guint16)g_random_int();
 
-	status_note_title = info->status_note_title;
-	g_free(info);
-
-	length = byte_stream_getle16(bs);
-	if (length != 27) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect header "
-				"size; expected 27, received %u.\n", length);
-		g_free(status_note_title);
-		return;
-	}
-
-	version = byte_stream_getle16(bs);
-	if (version != 9) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect version; "
-				"expected 9, received %u.\n", version);
-		g_free(status_note_title);
-		return;
-	}
+	purple_debug_misc("oscar", "Sending message ack to %s\n", bn);
 
-	capability = aim_locate_getcaps(od, bs, 0x10);
-	if (capability != OSCAR_CAPABILITY_EMPTY) {
-		purple_debug_misc("oscar", "clientautoresp: plugin ID is not null.\n");
-		g_free(status_note_title);
-		return;
-	}
+	header_size = 8 + 2 + 1 + strlen(bn) + 2;
+	data_size = 2 + 1 + 16 + 4*2 + 2*3 + 4*3 + 1*2 + 2*3 + 1;
+	byte_stream_new(&bs, header_size + data_size);
 
-	byte_stream_advance(bs, 2); /* unknown */
-	byte_stream_advance(bs, 4); /* client capabilities flags */
-	byte_stream_advance(bs, 1); /* unknown */
-	byte_stream_advance(bs, 2); /* downcouner? */
-
-	length = byte_stream_getle16(bs);
-	if (length != 14) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect header "
-				"size; expected 14, received %u.\n", length);
-		g_free(status_note_title);
-		return;
-	}
-
-	byte_stream_advance(bs, 2); /* downcounter? */
-	byte_stream_advance(bs, 12); /* unknown */
+	/* The message header. */
+	aim_im_puticbm(&bs, cookie, 0x0002, bn);
+	byte_stream_put16(&bs, 0x0003);	/* reason */
 
-	message_type = byte_stream_get8(bs);
-	if (message_type != 0x1a) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect message "
-				"type; expected 0x1a, received 0x%x.\n", message_type);
-		g_free(status_note_title);
-		return;
-	}
-
-	byte_stream_advance(bs, 1); /* message flags */
-
-	status_code = byte_stream_getle16(bs);
-	if (status_code != 0) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect status "
-				"code; expected 0, received %u.\n", status_code);
-		g_free(status_note_title);
-		return;
-	}
-
-	byte_stream_advance(bs, 2); /* priority code */
-
-	text_length = byte_stream_getle16(bs);
-	byte_stream_advance(bs, text_length); /* text */
-
-	length = byte_stream_getle16(bs);
-	byte_stream_advance(bs, 18); /* unknown */
-
-	request_length = byte_stream_getle32(bs);
-	if (length != 18 + 4 + request_length + 17) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect block; "
-				"expected length is %u, got %u.\n",
-				18 + 4 + request_length + 17, length);
-		g_free(status_note_title);
-		return;
-	}
-
-	byte_stream_advance(bs, request_length); /* x request */
-	byte_stream_advance(bs, 17); /* unknown */
+	/* The actual message. */
+	byte_stream_putle16(&bs, 0x1b);	/* subheader #1 length */
+	byte_stream_put8(&bs, 0x08);	/* protocol version */
+	byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY);
+	byte_stream_put32(&bs, 0x3);	/* client features */
+	byte_stream_put32(&bs, 0x0004);	/* DC type */
+	byte_stream_put16(&bs, cookie2);	/* a cookie, chosen by fair dice roll */
+	byte_stream_putle16(&bs, 0x0e);	/* header #2 len? */
+	byte_stream_put16(&bs, cookie2);	/* the same cookie again */
+	byte_stream_put32(&bs, 0);	/* unknown */
+	byte_stream_put32(&bs, 0);	/* unknown */
+	byte_stream_put32(&bs, 0);	/* unknown */
+	byte_stream_put8(&bs, 0x01);	/* plain text message */
+	byte_stream_put8(&bs, 0x00);	/* no message flags */
+	byte_stream_put16(&bs, 0x0000);	/* no icq status */
+	byte_stream_put16(&bs, 0x0100);	/* priority */
+	byte_stream_putle16(&bs, 1);	/* query message len */
+	byte_stream_put8(&bs, 0x00);	/* empty query message */
 
-	length = byte_stream_getle32(bs);
-	response_length = byte_stream_getle32(bs);
-	response = byte_stream_getstr(bs, response_length);
-	encoding_length = byte_stream_getle32(bs);
-	if (length != 4 + response_length + 4 + encoding_length) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect block; "
-				"expected length is %u, got %u.\n",
-				4 + response_length + 4 + encoding_length, length);
-		g_free(status_note_title);
-		g_free(response);
-		return;
-	}
-
-	encoding = byte_stream_getstr(bs, encoding_length);
-
-	account = purple_connection_get_account(od->gc);
-
-	stripped_encoding = oscar_encoding_extract(encoding);
-	status_note_text = oscar_encoding_to_utf8(account, stripped_encoding, response, response_length);
-	stripped_status_note_text = purple_markup_strip_html(status_note_text);
-
-	if (stripped_status_note_text != NULL && stripped_status_note_text[0] != 0)
-		status_note = g_strdup_printf("%s: %s", status_note_title, stripped_status_note_text);
-	else
-		status_note = g_strdup(status_note_title);
-
-	g_free(status_note_title);
-	g_free(response);
-	g_free(encoding);
-	g_free(stripped_encoding);
-	g_free(status_note_text);
-	g_free(stripped_status_note_text);
-
-	buddy = purple_find_buddy(account, bn);
-	if (buddy == NULL)
-	{
-		purple_debug_misc("oscar", "clientautoresp: buddy %s was not found.\n", bn);
-		g_free(status_note);
-		return;
-	}
-
-	purple_debug_misc("oscar", "clientautoresp: setting status "
-			"message to \"%s\".\n", status_note);
-
-	presence = purple_buddy_get_presence(buddy);
-	status = purple_presence_get_active_status(presence);
-
-	purple_prpl_got_user_status(account, bn,
-			purple_status_get_id(status),
-			"message", status_note, NULL);
-
-	g_free(status_note);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x000b, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, flap_connection_findbygroup(od, SNAC_FAMILY_ICBM), SNAC_FAMILY_ICBM, 0x000b, snacid, &bs);
+	byte_stream_destroy(&bs);
 }
 
 /*
@@ -2819,16 +1799,10 @@
 }
 
 /*
- * Subtype 0x000c - Receive an ack after sending an ICBM.
- *
- * You have to have send the message with the AIM_IMFLAGS_ACK flag set
- * (TLV t(0003)).  The ack contains the ICBM header of the message you
- * sent.
- *
+ * Subtype 0x000c - Receive an ack after sending an ICBM. The ack contains the ICBM header of the message you sent.
  */
 static int msgack(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-	aim_rxcallback_t userfunc;
 	guint16 ch;
 	guchar *cookie;
 	char *bn;
@@ -2838,8 +1812,7 @@
 	ch = byte_stream_get16(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, bn);
+	purple_debug_info("oscar", "Sent message to %s.\n", bn);
 
 	g_free(bn);
 	g_free(cookie);
@@ -2914,7 +1887,7 @@
 	 */
 	byte_stream_put16(&bs, event);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0014, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0014, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -3002,7 +1975,7 @@
 	aim_tlvlist_write(&bs, &outer_tlvlist);
 
 	purple_debug_misc("oscar", "X-Status Request\n");
-	flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, TRUE);
+	flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, snacid, &bs, TRUE);
 
 	aim_tlvlist_free(outer_tlvlist);
 	byte_stream_destroy(&header);
@@ -3088,9 +2061,9 @@
 	aim_im_puticbm(&bs, cookie, 0x0002, sn);
 	byte_stream_put16(&bs, 0x0003);
 	byte_stream_putraw(&bs, plugindata, sizeof(plugindata));
-	byte_stream_putraw(&bs, (const guint8 *)statxml, strlen(statxml));
+	byte_stream_putraw(&bs, (const guint8*)statxml, strlen(statxml));
 
-	flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x000b, 0x0000, snacid, &bs, TRUE);
+	flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x000b, snacid, &bs, TRUE);
 
 	g_free(statxml);
 	g_free(msg);
@@ -3135,8 +2108,6 @@
 		return error(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0005)
 		return aim_im_paraminfo(od, conn, mod, frame, snac, bs);
-	else if (snac->subtype == 0x0006)
-		return outgoingim(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0007)
 		return incomingim(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x000a)
--- a/libpurple/protocols/oscar/family_icq.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_icq.c	Wed Aug 25 19:12:08 2010 +0000
@@ -23,77 +23,104 @@
  *
  */
 
+#include "encoding.h"
 #include "oscar.h"
 
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-int aim_icq_reqofflinemsgs(OscarData *od)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	int bslen;
+#define AIM_ICQ_INFO_REQUEST 0x04b2
+#define AIM_ICQ_ALIAS_REQUEST 0x04ba
 
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
-		return -EINVAL;
+static
+int compare_icq_infos(gconstpointer a, gconstpointer b)
+{
+	const struct aim_icq_info* aa = a;
+	const guint16* bb = b;
+	return aa->reqid - *bb;
+}
 
-	purple_debug_info("oscar", "Requesting offline messages\n");
-
-	bslen = 2 + 4 + 2 + 2;
-
-	byte_stream_new(&bs, 4 + bslen);
+static void aim_icq_freeinfo(struct aim_icq_info *info) {
+	int i;
 
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
-
-	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put16(&bs, bslen);
-
-	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putuid(&bs, od);
-	byte_stream_putle16(&bs, 0x003c); /* I command thee. */
-	byte_stream_putle16(&bs, snacid); /* eh. */
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
+	if (!info)
+		return;
+	g_free(info->nick);
+	g_free(info->first);
+	g_free(info->last);
+	g_free(info->email);
+	g_free(info->homecity);
+	g_free(info->homestate);
+	g_free(info->homephone);
+	g_free(info->homefax);
+	g_free(info->homeaddr);
+	g_free(info->mobile);
+	g_free(info->homezip);
+	g_free(info->personalwebpage);
+	if (info->email2)
+		for (i = 0; i < info->numaddresses; i++)
+			g_free(info->email2[i]);
+	g_free(info->email2);
+	g_free(info->workcity);
+	g_free(info->workstate);
+	g_free(info->workphone);
+	g_free(info->workfax);
+	g_free(info->workaddr);
+	g_free(info->workzip);
+	g_free(info->workcompany);
+	g_free(info->workdivision);
+	g_free(info->workposition);
+	g_free(info->workwebpage);
+	g_free(info->info);
+	g_free(info->status_note_title);
+	g_free(info->auth_request_reason);
 }
 
-int aim_icq_ackofflinemsgs(OscarData *od)
+static
+int error(OscarData *od, aim_modsnac_t *error_snac, ByteStream *bs)
 {
-	ByteStream bs;
-	FlapFrame *frame;
-	aim_snacid_t snacid;
-	int bslen;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
-		return -EINVAL;
-
-	purple_debug_info("oscar", "Acknowledged receipt of offline messages\n");
-
-	bslen = 2 + 4 + 2 + 2;
-
-	byte_stream_new(&bs, 4 + bslen);
+	aim_snac_t *original_snac = aim_remsnac(od, error_snac->id);
+	guint16 *request_type;
+	GSList *original_info_ptr;
+	struct aim_icq_info *original_info;
+	guint16 reason;
+	gchar *uin;
 
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
-
-	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put16(&bs, bslen);
+	if (!original_snac || (original_snac->family != SNAC_FAMILY_ICQ) || !original_snac->data) {
+		purple_debug_misc("oscar", "icq: the original snac for the error packet was not found");
+		g_free(original_snac);
+		return 0;
+	}
+	
+	request_type = original_snac->data;
+	original_info_ptr = g_slist_find_custom(od->icq_info, &original_snac->id, compare_icq_infos);
+	original_info = original_info_ptr->data;
+	
+	if (!original_info_ptr) {
+		purple_debug_misc("oscar", "icq: the request info for the error packet was not found");
+		g_free(original_snac);
+		return 0;
+	}
+	
+	reason = byte_stream_get16(bs);
+	uin = g_strdup_printf("%u", original_info->uin);
+	switch (*request_type) {
+		case AIM_ICQ_INFO_REQUEST:
+			oscar_user_info_display_error(od, reason, uin);
+			break;
+		case AIM_ICQ_ALIAS_REQUEST:
+			/* Couldn't retrieve an alias for the buddy requesting authorization; have to make do with UIN only. */
+			if (original_info->for_auth_request)
+				oscar_auth_recvrequest(od->gc, uin, NULL, original_info->auth_request_reason);
+			break;
+		default:
+			purple_debug_misc("oscar", "icq: got an error packet with unknown request type %u", *request_type);
+			break;
+	}
 
-	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putuid(&bs, od);
-	byte_stream_putle16(&bs, 0x003e); /* I command thee. */
-	byte_stream_putle16(&bs, snacid); /* eh. */
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
+	aim_icq_freeinfo(original_info);
+	od->icq_info = g_slist_remove(od->icq_info, original_info_ptr);
+	g_free(original_snac->data);
+	g_free(original_snac);
+	return 1;
 }
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
 
 int
 aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware)
@@ -130,7 +157,7 @@
 	byte_stream_putle8(&bs, 0x00);
 	byte_stream_putle8(&bs, !auth_required);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -180,7 +207,7 @@
 	byte_stream_putraw(&bs, (const guint8 *)passwd, passwdlen);
 	byte_stream_putle8(&bs, '\0');
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -194,6 +221,7 @@
 	aim_snacid_t snacid;
 	int bslen;
 	struct aim_icq_info *info;
+	guint16 request_type = AIM_ICQ_INFO_REQUEST;
 
 	if (!uin || uin[0] < '0' || uin[0] > '9')
 		return -EINVAL;
@@ -205,7 +233,7 @@
 
 	byte_stream_new(&bs, 4 + bslen);
 
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
 
 	/* For simplicity, don't bother using a tlvlist */
 	byte_stream_put16(&bs, 0x0001);
@@ -215,10 +243,10 @@
 	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
-	byte_stream_putle16(&bs, 0x04b2); /* shrug. */
+	byte_stream_putle16(&bs, request_type); /* shrug. */
 	byte_stream_putle32(&bs, atoi(uin));
 
-	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
+	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs, FALSE);
 
 	byte_stream_destroy(&bs);
 
@@ -226,19 +254,19 @@
 	info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
 	info->reqid = snacid;
 	info->uin = atoi(uin);
-	info->next = od->icq_info;
-	od->icq_info = info;
+	od->icq_info = g_slist_prepend(od->icq_info, info);
 
 	return 0;
 }
 
-int aim_icq_getalias(OscarData *od, const char *uin)
+int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason)
 {
 	FlapConnection *conn;
 	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen;
 	struct aim_icq_info *info;
+	guint16 request_type = AIM_ICQ_ALIAS_REQUEST;
 
 	if (!uin || uin[0] < '0' || uin[0] > '9')
 		return -EINVAL;
@@ -252,7 +280,7 @@
 
 	byte_stream_new(&bs, 4 + bslen);
 
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
 
 	/* For simplicity, don't bother using a tlvlist */
 	byte_stream_put16(&bs, 0x0001);
@@ -262,10 +290,10 @@
 	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
-	byte_stream_putle16(&bs, 0x04ba); /* shrug. */
+	byte_stream_putle16(&bs, request_type); /* shrug. */
 	byte_stream_putle32(&bs, atoi(uin));
 
-	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
+	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs, FALSE);
 
 	byte_stream_destroy(&bs);
 
@@ -273,89 +301,13 @@
 	info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
 	info->reqid = snacid;
 	info->uin = atoi(uin);
-	info->next = od->icq_info;
-	od->icq_info = info;
+	info->for_auth_request = for_auth_request;
+	info->auth_request_reason = g_strdup(auth_request_reason);
+	od->icq_info = g_slist_prepend(od->icq_info, info);
 
 	return 0;
 }
 
-int aim_icq_getsimpleinfo(OscarData *od, const char *uin)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	int bslen;
-
-	if (!uin || uin[0] < '0' || uin[0] > '9')
-		return -EINVAL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
-		return -EINVAL;
-
-	bslen = 2 + 4 + 2 + 2 + 2 + 4;
-
-	byte_stream_new(&bs, 4 + bslen);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
-
-	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put16(&bs, bslen);
-
-	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putuid(&bs, od);
-	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&bs, snacid); /* eh. */
-	byte_stream_putle16(&bs, 0x051f); /* shrug. */
-	byte_stream_putle32(&bs, atoi(uin));
-
-	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-#if 0
-int aim_icq_sendxmlreq(OscarData *od, const char *xml)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	int bslen;
-
-	if (!xml || !strlen(xml))
-		return -EINVAL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
-		return -EINVAL;
-
-	bslen = 2 + 10 + 2 + strlen(xml) + 1;
-
-	byte_stream_new(&bs, 4 + bslen);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
-
-	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&bs, 0x0001);
-	byte_stream_put16(&bs, bslen);
-
-	byte_stream_putle16(&bs, bslen - 2);
-	byte_stream_putuid(&bs, od);
-	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&bs, snacid); /* eh. */
-	byte_stream_putle16(&bs, 0x0998); /* shrug. */
-	byte_stream_putle16(&bs, strlen(xml) + 1);
-	byte_stream_putraw(&bs, (guint8 *)xml, strlen(xml) + 1);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-#endif
-
 /*
  * Send an SMS message.  This is the non-US way.  The US-way is to IM
  * their cell phone number (+19195551234).
@@ -446,7 +398,7 @@
 	byte_stream_putstr(&bs, xml);
 	byte_stream_put8(&bs, 0x00);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -456,49 +408,35 @@
 	return 0;
 }
 
-static void aim_icq_freeinfo(struct aim_icq_info *info) {
-	int i;
+static int
+gotalias(OscarData *od, struct aim_icq_info *info)
+{
+	PurpleConnection *gc = od->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	gchar who[16], *utf8;
+	PurpleBuddy *b;
 
-	if (!info)
-		return;
-	g_free(info->nick);
-	g_free(info->first);
-	g_free(info->last);
-	g_free(info->email);
-	g_free(info->homecity);
-	g_free(info->homestate);
-	g_free(info->homephone);
-	g_free(info->homefax);
-	g_free(info->homeaddr);
-	g_free(info->mobile);
-	g_free(info->homezip);
-	g_free(info->personalwebpage);
-	if (info->email2)
-		for (i = 0; i < info->numaddresses; i++)
-			g_free(info->email2[i]);
-	g_free(info->email2);
-	g_free(info->workcity);
-	g_free(info->workstate);
-	g_free(info->workphone);
-	g_free(info->workfax);
-	g_free(info->workaddr);
-	g_free(info->workzip);
-	g_free(info->workcompany);
-	g_free(info->workdivision);
-	g_free(info->workposition);
-	g_free(info->workwebpage);
-	g_free(info->info);
-	g_free(info->status_note_title);
-	g_free(info);
+	if (info->nick[0] && (utf8 = oscar_utf8_try_convert(account, od, info->nick))) {
+		if (info->for_auth_request) {
+			oscar_auth_recvrequest(gc, g_strdup_printf("%u", info->uin), utf8, info->auth_request_reason);
+		} else {
+			g_snprintf(who, sizeof(who), "%u", info->uin);
+			serv_got_alias(gc, who, utf8);
+			if ((b = purple_find_buddy(account, who))) {
+				purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8);
+			}
+			g_free(utf8);
+		}
+	}
+	return 1;
 }
 
 /**
  * Subtype 0x0003 - Response to SNAC_FAMILY_ICQ/0x002, contains an ICQesque packet.
  */
 static int
-icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
+icqresponse(OscarData *od, aim_modsnac_t *snac, ByteStream *bs)
 {
-	int ret = 0;
 	GSList *tlvlist;
 	aim_tlv_t *datatlv;
 	ByteStream qbs;
@@ -520,53 +458,23 @@
 
 	purple_debug_misc("oscar", "icq response: %d bytes, %u, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid);
 
-	if (cmd == 0x0041) { /* offline message */
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-		struct aim_icq_offlinemsg msg;
-		aim_rxcallback_t userfunc;
-
-		memset(&msg, 0, sizeof(msg));
-
-		msg.sender = byte_stream_getle32(&qbs);
-		msg.year = byte_stream_getle16(&qbs);
-		msg.month = byte_stream_getle8(&qbs);
-		msg.day = byte_stream_getle8(&qbs);
-		msg.hour = byte_stream_getle8(&qbs);
-		msg.minute = byte_stream_getle8(&qbs);
-		msg.type = byte_stream_getle8(&qbs);
-		msg.flags = byte_stream_getle8(&qbs);
-		msg.msglen = byte_stream_getle16(&qbs);
-		msg.msg = byte_stream_getstr(&qbs, msg.msglen);
-
-		if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSG)))
-			ret = userfunc(od, conn, frame, &msg);
-
-		g_free(msg.msg);
-
-	} else if (cmd == 0x0042) {
-		aim_rxcallback_t userfunc;
-
-		if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE)))
-			ret = userfunc(od, conn, frame);
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
-
-	} else if (cmd == 0x07da) { /* information */
+	if (cmd == 0x07da) { /* information */
 		guint16 subtype;
+		GSList *info_ptr;
 		struct aim_icq_info *info;
-		aim_rxcallback_t userfunc;
 
 		subtype = byte_stream_getle16(&qbs);
 		byte_stream_advance(&qbs, 1); /* 0x0a */
 
 		/* find other data from the same request */
-		for (info = od->icq_info; info && (info->reqid != reqid); info = info->next);
-		if (!info) {
-			info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
-			info->reqid = reqid;
-			info->next = od->icq_info;
-			od->icq_info = info;
+		info_ptr = g_slist_find_custom(od->icq_info, &reqid, compare_icq_infos);
+		if (!info_ptr) {
+			struct aim_icq_info *new_info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
+			new_info->reqid = reqid;
+			info_ptr = od->icq_info = g_slist_prepend(od->icq_info, new_info);
 		}
 
+		info = info_ptr->data;
 		switch (subtype) {
 		case 0x00a0: { /* hide ip status */
 			/* nothing */
@@ -818,10 +726,9 @@
 
 				memcpy(&info->icbm_cookie, cookie, 8);
 
-				info->next = od->icq_info;
-				od->icq_info = info;
+				od->icq_info = g_slist_prepend(od->icq_info, info);
 
-				flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, FALSE);
+				flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, snacid, &bs, FALSE);
 
 				byte_stream_destroy(&bs);
 			}
@@ -834,35 +741,28 @@
 
 		if (!(snac->flags & 0x0001)) {
 			if (subtype != 0x0104)
-				if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_INFO)))
-					ret = userfunc(od, conn, frame, info);
+				oscar_user_info_display_icq(od, info);
 
 			if (info->uin && info->nick)
-				if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_ALIAS)))
-					ret = userfunc(od, conn, frame, info);
+				gotalias(od, info);
 
-			if (od->icq_info == info) {
-				od->icq_info = info->next;
-			} else {
-				struct aim_icq_info *cur;
-				for (cur=od->icq_info; (cur->next && (cur->next!=info)); cur=cur->next);
-				if (cur->next)
-					cur->next = cur->next->next;
-			}
 			aim_icq_freeinfo(info);
+			od->icq_info = g_slist_remove(od->icq_info, info);
 		}
 	}
 
 	aim_tlvlist_free(tlvlist);
 
-	return ret;
+	return 1;
 }
 
 static int
 snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-	if (snac->subtype == 0x0003)
-		return icqresponse(od, conn, mod, frame, snac, bs);
+	if (snac->subtype == 0x0001)
+		return error(od, snac, bs);
+	else if (snac->subtype == 0x0003)
+		return icqresponse(od, snac, bs);
 
 	return 0;
 }
@@ -870,15 +770,10 @@
 static void
 icq_shutdown(OscarData *od, aim_module_t *mod)
 {
-	struct aim_icq_info *del;
-
-	while (od->icq_info) {
-		del = od->icq_info;
-		od->icq_info = od->icq_info->next;
-		aim_icq_freeinfo(del);
-	}
-
-	return;
+	GSList *cur;
+	for (cur = od->icq_info; cur; cur = cur->next)
+		aim_icq_freeinfo(cur->data);
+	g_slist_free(od->icq_info);
 }
 
 int
--- a/libpurple/protocols/oscar/family_invite.c	Wed Aug 25 19:11:38 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x0006 - This isn't really ever used by anyone anymore.
- *
- * Once upon a time, there used to be a menu item in AIM clients that
- * said something like "Invite a friend to use AIM..." and then it would
- * ask for an email address and it would sent a mail to them saying
- * how perfectly wonderful the AIM service is and why you should use it
- * and click here if you hate the person who sent this to you and want to
- * complain and yell at them in a small box with pretty fonts.
- *
- * I could've sworn libfaim had this implemented once, a long long time ago,
- * but I can't find it.
- *
- * I'm mainly adding this so that I can keep advertising that we support
- * group 6, even though we don't.
- *
- */
-
-#include "oscar.h"
-
-int invite_modfirst(OscarData *od, aim_module_t *mod)
-{
-
-	mod->family = SNAC_FAMILY_INVITE;
-	mod->version = 0x0001;
-	mod->toolid = 0x0110;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "invite", sizeof(mod->name));
-	mod->snachandler = NULL;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_locate.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_locate.c	Wed Aug 25 19:12:08 2010 +0000
@@ -245,6 +245,10 @@
 	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
 
+	{OSCAR_CAPABILITY_HTML_MSGS,
+	 {0x01, 0x38, 0xca, 0x7b, 0x76, 0x9a, 0x49, 0x15,
+	  0x88, 0xf2, 0x13, 0xfc, 0x00, 0x97, 0x9e, 0xa8}},
+
 	{OSCAR_CAPABILITY_LAST,
 	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
@@ -583,7 +587,7 @@
 	guint64 flags = 0;
 	int offset;
 
-	for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x10) {
+	for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x10) {
 		guint8 *cap;
 		int i, identified;
 
@@ -617,7 +621,7 @@
 	int offset;
 	const char *result = NULL;
 
-	for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x10) {
+	for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x10) {
 		/* check wheather this capability is a custom user icon */
 		guint8 *cap;
 		int i;
@@ -643,7 +647,7 @@
 	guint64 flags = 0;
 	int offset;
 
-	for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x02) {
+	for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x02) {
 		guint8 *cap;
 		int i, identified;
 
@@ -674,16 +678,13 @@
 	if (!bs)
 		return -EINVAL;
 
-	for (i = 0; byte_stream_empty(bs); i++) {
-
+	for (i = 0; byte_stream_bytes_left(bs); i++) {
 		if (aim_caps[i].flag == OSCAR_CAPABILITY_LAST)
 			break;
 
 		if (caps & aim_caps[i].flag)
 			byte_stream_putraw(bs, aim_caps[i].data, 0x10);
-
 	}
-
 	return 0;
 }
 
@@ -804,7 +805,7 @@
 		type = byte_stream_get16(bs);
 		length = byte_stream_get16(bs);
 		curpos = byte_stream_curpos(bs);
-		endpos = curpos + MIN(length, byte_stream_empty(bs));
+		endpos = curpos + MIN(length, byte_stream_bytes_left(bs));
 
 		if (type == 0x0001) {
 			/*
@@ -1010,7 +1011,7 @@
 				number2 = byte_stream_get8(bs);
 				length2 = byte_stream_get8(bs);
 
-				endpos2 = byte_stream_curpos(bs) + MIN(length2, byte_stream_empty(bs));
+				endpos2 = byte_stream_curpos(bs) + MIN(length2, byte_stream_bytes_left(bs));
 
 				switch (type2) {
 					case 0x0000: { /* This is an official buddy icon? */
@@ -1165,68 +1166,12 @@
 	return 0;
 }
 
-/* Apparently, this is never called.
- * If you activate it, figure out a way to know what mood to pass to
- * aim_tlvlist_add_caps() below. --rlaager */
-#if 0
-/*
- * Inverse of aim_info_extract()
- */
-int
-aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info)
-{
-	GSList *tlvlist = NULL;
-
-	if (!bs || !info)
-		return -EINVAL;
-
-	byte_stream_put8(bs, strlen(info->bn));
-	byte_stream_putstr(bs, info->bn);
-
-	byte_stream_put16(bs, info->warnlevel);
-
-	if (info->present & AIM_USERINFO_PRESENT_FLAGS)
-		aim_tlvlist_add_16(&tlvlist, 0x0001, info->flags);
-	if (info->present & AIM_USERINFO_PRESENT_MEMBERSINCE)
-		aim_tlvlist_add_32(&tlvlist, 0x0002, info->membersince);
-	if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE)
-		aim_tlvlist_add_32(&tlvlist, 0x0003, info->onlinesince);
-	if (info->present & AIM_USERINFO_PRESENT_IDLE)
-		aim_tlvlist_add_16(&tlvlist, 0x0004, info->idletime);
-
-/* XXX - So, ICQ_OSCAR_SUPPORT is never defined anywhere... */
-#ifdef ICQ_OSCAR_SUPPORT
-	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)
-			aim_tlvlist_add_32(&tlvlist, 0x000a, info->icqinfo.ipaddr);
-	}
-#endif
-
-	if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) {
-		aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities, NULL);
-	}
-
-	if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
-		aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen);
-
-	byte_stream_put16(bs, aim_tlvlist_count(tlvlist));
-	aim_tlvlist_write(bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	return 0;
-}
-#endif
-
 /*
  * Subtype 0x0001
  */
 static int
 error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-	int ret = 0;
-	aim_rxcallback_t userfunc;
 	aim_snac_t *snac2;
 	guint16 reason;
 	char *bn;
@@ -1253,14 +1198,12 @@
 
 	reason = byte_stream_get16(bs);
 
-	/* Notify the user that we do not have info for this buddy */
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, reason, bn);
+	oscar_user_info_display_error(od, reason, bn);
 
 	g_free(snac2->data);
 	g_free(snac2);
 
-	return ret;
+	return 1;
 }
 
 /*
@@ -1390,7 +1333,7 @@
 	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -1424,41 +1367,7 @@
 	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x0005 - Request info of another AIM user.
- *
- * @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 *bn, guint16 infotype)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn)
-		return -EINVAL;
-
-	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(bn));
-	byte_stream_putstr(&bs, bn);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0005, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -1470,7 +1379,6 @@
 userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
-	aim_rxcallback_t userfunc;
 	aim_userinfo_t *userinfo, *userinfo2;
 	GSList *tlvlist;
 	aim_tlv_t *tlv = NULL;
@@ -1522,140 +1430,12 @@
 	g_free(userinfo);
 
 	/* Show the info to the user */
-	if (userinfo2 != NULL && ((userfunc = aim_callhandler(od, snac->family, snac->subtype))))
-		ret = userfunc(od, conn, frame, userinfo2);
+	oscar_user_info_display_aim(od, userinfo2);
 
 	return ret;
 }
 
 /*
- * Subtype 0x0009 - Set directory profile data.
- *
- * This is not the same as aim_location_setprofile!
- * privacy: 1 to allow searching, 0 to disallow.
- *
- */
-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)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
-		return -EINVAL;
-
-	aim_tlvlist_add_16(&tlvlist, 0x000a, privacy);
-
-	if (first)
-		aim_tlvlist_add_str(&tlvlist, 0x0001, first);
-	if (last)
-		aim_tlvlist_add_str(&tlvlist, 0x0002, last);
-	if (middle)
-		aim_tlvlist_add_str(&tlvlist, 0x0003, middle);
-	if (maiden)
-		aim_tlvlist_add_str(&tlvlist, 0x0004, maiden);
-
-	if (state)
-		aim_tlvlist_add_str(&tlvlist, 0x0007, state);
-	if (city)
-		aim_tlvlist_add_str(&tlvlist, 0x0008, city);
-
-	if (nickname)
-		aim_tlvlist_add_str(&tlvlist, 0x000c, nickname);
-	if (zip)
-		aim_tlvlist_add_str(&tlvlist, 0x000d, zip);
-
-	if (street)
-		aim_tlvlist_add_str(&tlvlist, 0x0021, street);
-
-	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, NULL, 0);
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x000b - Huh? What is this?
- */
-int aim_locate_000b(OscarData *od, const char *bn)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-		return -EINVAL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn)
-		return -EINVAL;
-
-	byte_stream_new(&bs, 1+strlen(bn));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, NULL, 0);
-
-	byte_stream_put8(&bs, strlen(bn));
-	byte_stream_putstr(&bs, bn);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-/*
- * Subtype 0x000f
- *
- * XXX pass these in better
- *
- */
-int
-aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
-		return -EINVAL;
-
-	/* ?? privacy ?? */
-	aim_tlvlist_add_16(&tlvlist, 0x000a, privacy);
-
-	if (interest1)
-		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest1);
-	if (interest2)
-		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest2);
-	if (interest3)
-		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest3);
-	if (interest4)
-		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest4);
-	if (interest5)
-		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest5);
-
-	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, NULL, 0);
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-	return 0;
-}
-
-/*
  * Subtype 0x0015 - Request the info of a user using the short method.  This is
  * what iChat uses.  It normally is VERY leniently rate limited.
  *
@@ -1683,7 +1463,7 @@
 	byte_stream_putstr(&bs, bn);
 
 	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);
+	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, snacid, &bs, FALSE);
 
 	byte_stream_destroy(&bs);
 
@@ -1731,15 +1511,6 @@
 	return 0;
 }
 
-#if 0 //rlaager
-const char* aim_get_custom_icon_mood(gint32 no)
-{
-	if (no >= G_N_ELEMENTS(aim_custom_icons) || no < 1)
-		return NULL;
-	return aim_custom_icons[no].mood.mood;
-}
-#endif
-
 const char*
 icq_get_custom_icon_description(const char *mood)
 {
--- a/libpurple/protocols/oscar/family_odir.c	Wed Aug 25 19:11:38 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,264 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x000f - Newer Search Method
- *
- * Used for searching for other AIM users by email address, name,
- * location, commmon interests, and a few other similar things.
- *
- */
-
-#include "oscar.h"
-
-/**
- * Subtype 0x0002 - Submit a User Search Request
- *
- * 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.
- * @param email The email address you want to search for.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_odir_email(OscarData *od, const char *region, const char *email)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region || !email)
-		return -EINVAL;
-
-	/* Create a TLV chain, write it to the outgoing frame, then free the chain */
-	aim_tlvlist_add_str(&tlvlist, 0x001c, region);
-	aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0001); /* Type of search */
-	aim_tlvlist_add_str(&tlvlist, 0x0005, email);
-
-	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-
-/**
- * Subtype 0x0002 - Submit a User Search Request
- *
- * Search for an AIM buddy based on various info
- * about the person.
- *
- * @param od The oscar session.
- * @param region Should be "us-ascii" unless you know what you're doing.
- * @param first The first name of the person you want to search for.
- * @param middle The middle name of the person you want to search for.
- * @param last The last name of the person you want to search for.
- * @param maiden The maiden name of the person you want to search for.
- * @param nick The nick name of the person you want to search for.
- * @param city The city where the person you want to search for resides.
- * @param state The state where the person you want to search for resides.
- * @param country The country where the person you want to search for resides.
- * @param zip The zip code where the person you want to search for resides.
- * @param address The street address where the person you want to seach for resides.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_odir_name(OscarData *od, const char *region, const char *first, const char *middle, const char *last, const char *maiden, const char *nick, const char *city, const char *state, const char *country, const char *zip, const char *address)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region)
-		return -EINVAL;
-
-	/* Create a TLV chain, write it to the outgoing frame, then free the chain */
-	aim_tlvlist_add_str(&tlvlist, 0x001c, region);
-	aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0000); /* Type of search */
-	if (first)
-		aim_tlvlist_add_str(&tlvlist, 0x0001, first);
-	if (last)
-		aim_tlvlist_add_str(&tlvlist, 0x0002, last);
-	if (middle)
-		aim_tlvlist_add_str(&tlvlist, 0x0003, middle);
-	if (maiden)
-		aim_tlvlist_add_str(&tlvlist, 0x0004, maiden);
-	if (country)
-		aim_tlvlist_add_str(&tlvlist, 0x0006, country);
-	if (state)
-		aim_tlvlist_add_str(&tlvlist, 0x0007, state);
-	if (city)
-		aim_tlvlist_add_str(&tlvlist, 0x0008, city);
-	if (nick)
-		aim_tlvlist_add_str(&tlvlist, 0x000c, nick);
-	if (zip)
-		aim_tlvlist_add_str(&tlvlist, 0x000d, zip);
-	if (address)
-		aim_tlvlist_add_str(&tlvlist, 0x0021, address);
-
-	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-
-/**
- * Subtype 0x0002 - Submit a User Search Request
- *
- * @param od The oscar session.
- * @param interest1 An interest you want to search for.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_odir_interest(OscarData *od, const char *region, const char *interest)
-{
-	FlapConnection *conn;
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tlvlist = NULL;
-
-	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region)
-		return -EINVAL;
-
-	/* Create a TLV chain, write it to the outgoing frame, then free the chain */
-	aim_tlvlist_add_str(&tlvlist, 0x001c, region);
-	aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0001); /* Type of search */
-	if (interest)
-		aim_tlvlist_add_str(&tlvlist, 0x0001, interest);
-
-	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
-	aim_tlvlist_write(&bs, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-
-	return 0;
-}
-
-
-/**
- * Subtype 0x0003 - Receive Reply From a User Search
- *
- */
-static int parseresults(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint16 tmp, numresults;
-	struct aim_odir *results = NULL;
-
-	tmp = byte_stream_get16(bs); /* Unknown */
-	tmp = byte_stream_get16(bs); /* Unknown */
-	byte_stream_advance(bs, tmp);
-
-	numresults = byte_stream_get16(bs); /* Number of results to follow */
-
-	/* Allocate a linked list, 1 node per result */
-	while (numresults) {
-		struct aim_odir *new;
-		GSList *tlvlist = aim_tlvlist_readnum(bs, byte_stream_get16(bs));
-		new = (struct aim_odir *)g_malloc(sizeof(struct aim_odir));
-		new->first = aim_tlv_getstr(tlvlist, 0x0001, 1);
-		new->last = aim_tlv_getstr(tlvlist, 0x0002, 1);
-		new->middle = aim_tlv_getstr(tlvlist, 0x0003, 1);
-		new->maiden = aim_tlv_getstr(tlvlist, 0x0004, 1);
-		new->email = aim_tlv_getstr(tlvlist, 0x0005, 1);
-		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->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);
-		new->region = aim_tlv_getstr(tlvlist, 0x001c, 1);
-		new->address = aim_tlv_getstr(tlvlist, 0x0021, 1);
-		new->next = results;
-		results = new;
-		numresults--;
-	}
-
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, results);
-
-	/* Now free everything from above */
-	while (results) {
-		struct aim_odir *del = results;
-		results = results->next;
-		g_free(del->first);
-		g_free(del->last);
-		g_free(del->middle);
-		g_free(del->maiden);
-		g_free(del->email);
-		g_free(del->country);
-		g_free(del->state);
-		g_free(del->city);
-		g_free(del->bn);
-		g_free(del->interest);
-		g_free(del->nick);
-		g_free(del->zip);
-		g_free(del->region);
-		g_free(del->address);
-		g_free(del);
-	}
-
-	return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
-	if (snac->subtype == 0x0003)
-		return parseresults(od, conn, mod, frame, snac, bs);
-
-	return 0;
-}
-
-int
-odir_modfirst(OscarData *od, aim_module_t *mod)
-{
-	mod->family = SNAC_FAMILY_ODIR;
-	mod->version = 0x0001;
-	mod->toolid = 0x0010;
-	mod->toolversion = 0x0629;
-	mod->flags = 0;
-	strncpy(mod->name, "odir", sizeof(mod->name));
-	mod->snachandler = snachandler;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_oservice.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_oservice.c	Wed Aug 25 19:12:08 2010 +0000
@@ -73,7 +73,7 @@
 	}
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0002, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0002, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -97,7 +97,7 @@
 {
 	int group;
 
-	while (byte_stream_empty(bs))
+	while (byte_stream_bytes_left(bs))
 	{
 		group = byte_stream_get16(bs);
 		conn->groups = g_slist_prepend(conn->groups, GUINT_TO_POINTER(group));
@@ -141,7 +141,7 @@
 	aim_tlvlist_free(tlvlist);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -187,7 +187,7 @@
 	aim_tlvlist_free(tlvlist);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, &csi, sizeof(csi));
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
@@ -444,30 +444,7 @@
 	}
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0008, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0008, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-/* Subtype 0x0009 - Delete Rate Parameter */
-void
-aim_srv_rates_delparam(OscarData *od, FlapConnection *conn)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *tmp;
-
-	byte_stream_new(&bs, 502);
-
-	for (tmp = conn->rateclasses; tmp != NULL; tmp = tmp->next)
-	{
-		struct rateclass *rateclass;
-		rateclass = tmp->data;
-		byte_stream_put16(&bs, rateclass->classid);
-	}
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0009, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0009, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0008, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -558,40 +535,6 @@
 	return ret;
 }
 
-/*
- * Subtype 0x000c - Service Pause Acknowledgement
- *
- * It is rather important that aim_srv_sendpauseack() gets called for the exact
- * same connection that the Server Pause callback was called for, since
- * libfaim extracts the data for the SNAC from the connection structure.
- *
- * Of course, if you don't do that, more bad things happen than just what
- * libfaim can cause.
- *
- */
-void
-aim_srv_sendpauseack(OscarData *od, FlapConnection *conn)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-	GSList *cur;
-
-	byte_stream_new(&bs, 1014);
-
-	/*
-	 * This list should have all the groups that the original
-	 * Host Online / Server Ready said this host supports.  And
-	 * we want them all back after the migration.
-	 */
-	for (cur = conn->groups; cur != NULL; cur = cur->next)
-		byte_stream_put16(&bs, GPOINTER_TO_UINT(cur->data));
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x000c, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x000c, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
 /* Subtype 0x000d - Service Resume */
 static int
 serverresume(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
@@ -643,7 +586,7 @@
 
 	newevil = byte_stream_get16(bs);
 
-	if (byte_stream_empty(bs))
+	if (byte_stream_bytes_left(bs))
 		aim_info_extract(od, bs, &userinfo);
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
@@ -770,36 +713,6 @@
 }
 
 /*
- * Subtype 0x0014 - Set privacy flags
- *
- * Normally 0x03.
- *
- *  Bit 1:  Allows other AIM users to see how long you've been idle.
- *  Bit 2:  Allows other AIM users to see how long you've been a member.
- *
- */
-void
-aim_srv_setprivacyflags(OscarData *od, FlapConnection *conn, guint32 flags)
-{
-	aim_genericreq_l(od, conn, SNAC_FAMILY_OSERVICE, 0x0014, &flags);
-}
-
-/*
- * Subtype 0x0016 - No-op
- *
- * WinAIM sends these every 4min or so to keep the connection alive.  Its not
- * really necessary.
- *
- * Wha?  No?  Since when?  I think WinAIM sends an empty channel 5
- * FLAP as a no-op...
- */
-void
-aim_srv_nop(OscarData *od, FlapConnection *conn)
-{
-	aim_genericreq_n(od, conn, SNAC_FAMILY_OSERVICE, 0x0016);
-}
-
-/*
  * Subtype 0x0017 - Set client versions
  *
  * If you've seen the clientonline/clientready SNAC you're probably
@@ -837,7 +750,7 @@
 	}
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0017, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0017, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0017, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -850,8 +763,8 @@
 	guint8 *versions;
 
 	/* This is frivolous. (Thank you SmarterChild.) */
-	vercount = byte_stream_empty(bs)/4;
-	versions = byte_stream_getraw(bs, byte_stream_empty(bs));
+	vercount = byte_stream_bytes_left(bs)/4;
+	versions = byte_stream_getraw(bs, byte_stream_bytes_left(bs));
 	g_free(versions);
 
 	/*
@@ -899,16 +812,6 @@
 				AIM_ICQ_STATE_HIDEIP | AIM_ICQ_STATE_DIRECTREQUIREAUTH);
 	}
 
-#if 0
-	if (other_stuff_that_isnt_implemented)
-	{
-		aim_tlvlist_add_raw(&tlvlist, 0x000c, 0x0025,
-				chunk_of_x25_bytes_with_ip_address_etc);
-		aim_tlvlist_add_raw(&tlvlist, 0x0011, 0x0005, unknown 0x01 61 10 f6 41);
-		aim_tlvlist_add_16(&tlvlist, 0x0012, unknown 0x00 00);
-	}
-#endif
-
 	if (setstatusmsg)
 	{
 		size_t statusmsglen, itmsurllen;
@@ -932,13 +835,57 @@
 	aim_tlvlist_free(tlvlist);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x001e, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
 	return 0;
 }
 
+/* Send dummy DC (direct connect) information to the server.
+ * Direct connect is ICQ's counterpart for AIM's DirectIM,
+ * as far as I can tell. Anyway, we don't support it;
+ * the reason to send this packet is that some clients
+ * (Miranda, QIP) won't send us channel 2 ICBM messages
+ * unless we specify DC version >= 8.
+ *
+ * See #12044 for more information.
+ */
+void
+aim_srv_set_dc_info(OscarData *od)
+{
+	ByteStream bs, tlv0c;
+	aim_snacid_t snacid;
+	GSList *tlvlist = NULL;
+
+	/* http://iserverd.khstu.ru/oscar/snac_01_1e.html has a nice analysis of what goes in 0xc tlv.
+	 * Kopete sends a dummy DC info, too, so I just copied the values from them.
+	 */
+	byte_stream_new(&tlv0c, 4*2 + 1 + 2 + 4*6 + 2);
+	byte_stream_put32(&tlv0c, 0x0);
+	byte_stream_put32(&tlv0c, 0x0);
+	byte_stream_put8(&tlv0c, 0x0); /* We don't support DC */
+	byte_stream_put16(&tlv0c, 8); /* DC version */
+	byte_stream_put32(&tlv0c, 0x0);
+	byte_stream_put32(&tlv0c, 0x50);
+	byte_stream_put32(&tlv0c, 0x3);
+	byte_stream_put32(&tlv0c, 0x0);
+	byte_stream_put32(&tlv0c, 0x0);
+	byte_stream_put32(&tlv0c, 0x0);
+	byte_stream_put16(&tlv0c, 0x0);
+	aim_tlvlist_add_raw(&tlvlist, 0x000c, byte_stream_curpos(&tlv0c), tlv0c.data);
+	byte_stream_destroy(&tlv0c);
+
+	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
+	aim_tlvlist_write(&bs, &tlvlist);
+	aim_tlvlist_free(tlvlist);
+
+	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, flap_connection_findbygroup(od, SNAC_FAMILY_ICBM), SNAC_FAMILY_OSERVICE, 0x001e, snacid, &bs);
+
+	byte_stream_destroy(&bs);
+}
+
 /**
  * Starting this past week (26 Mar 2001, say), AOL has started sending
  * this nice little extra SNAC.  AFAIK, it has never been used until now.
@@ -1077,7 +1024,7 @@
 	}
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0020, 0x0000, NULL, 0);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0020, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0020, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
--- a/libpurple/protocols/oscar/family_translate.c	Wed Aug 25 19:11:38 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
-*/
-
-/*
- * Family 0x000c - Translation.
- *
- * I have no idea why this group was issued.  I have never seen anything
- * that uses it.  From what I remember, the last time I tried to poke at
- * the server with this group, it whined about not supporting it.
- *
- * But we advertise it anyway, because its fun.
- *
- */
-
-#include "oscar.h"
-
-int translate_modfirst(OscarData *od, aim_module_t *mod)
-{
-
-	mod->family = SNAC_FAMILY_TRANSLATE;
-	mod->version = 0x0001;
-	mod->toolid = 0x0104;
-	mod->toolversion = 0x0001;
-	mod->flags = 0;
-	strncpy(mod->name, "translate", sizeof(mod->name));
-	mod->snachandler = NULL;
-
-	return 0;
-}
--- a/libpurple/protocols/oscar/family_userlookup.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/family_userlookup.c	Wed Aug 25 19:12:08 2010 +0000
@@ -75,7 +75,7 @@
 	byte_stream_putstr(&bs, address);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_USERLOOKUP, 0x0002, 0x0000, address, strlen(address)+1);
-	flap_connection_send_snac(od, conn, SNAC_FAMILY_USERLOOKUP, 0x0002, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_USERLOOKUP, 0x0002, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 
--- a/libpurple/protocols/oscar/flap_connection.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/flap_connection.c	Wed Aug 25 19:12:08 2010 +0000
@@ -212,7 +212,7 @@
  *        only if all high priority SNACs have been sent.
  */
 void
-flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority)
+flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data, gboolean high_priority)
 {
 	FlapFrame *frame;
 	guint32 length;
@@ -222,7 +222,7 @@
 	length = data != NULL ? data->offset : 0;
 
 	frame = flap_frame_new(od, 0x02, 10 + length);
-	aim_putsnac(&frame->data, family, subtype, flags, snacid);
+	aim_putsnac(&frame->data, family, subtype, snacid);
 
 	if (length > 0)
 	{
@@ -284,9 +284,9 @@
 }
 
 void
-flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data)
+flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data)
 {
-	flap_connection_send_snac_with_priority(od, conn, family, subtype, flags, snacid, data, TRUE);
+	flap_connection_send_snac_with_priority(od, conn, family, subtype, snacid, data, TRUE);
 }
 
 /**
@@ -733,7 +733,7 @@
 	aim_module_t *cur;
 	aim_modsnac_t snac;
 
-	if (byte_stream_empty(&frame->data) < 10)
+	if (byte_stream_bytes_left(&frame->data) < 10)
 		return;
 
 	snac.family = byte_stream_get16(&frame->data);
@@ -800,7 +800,7 @@
 	GSList *tlvlist;
 	char *msg = NULL;
 
-	if (byte_stream_empty(&frame->data) == 0) {
+	if (byte_stream_bytes_left(&frame->data) == 0) {
 		/* XXX should do something with this */
 		return;
 	}
@@ -931,18 +931,6 @@
 				break;
 			}
 
-			/* Verify the sequence number sent by the server. */
-#if 0
-			/* TODO: Need to initialize conn->seqnum_in somewhere before we can use this. */
-			if (aimutil_get16(&conn->header[1]) != conn->seqnum_in++)
-			{
-				/* Received an out-of-order FLAP! */
-				flap_connection_schedule_destroy(conn,
-						OSCAR_DISCONNECT_INVALID_DATA, NULL);
-				break;
-			}
-#endif
-
 			/* Initialize a new temporary FlapFrame for incoming data */
 			conn->buffer_incoming.channel = aimutil_get8(&conn->header[1]);
 			conn->buffer_incoming.seqnum = aimutil_get16(&conn->header[2]);
@@ -1074,8 +1062,8 @@
 		return;
 
 	/* Make sure we don't send past the end of the bs */
-	if (count > byte_stream_empty(bs))
-		count = byte_stream_empty(bs); /* truncate to remaining space */
+	if (count > byte_stream_bytes_left(bs))
+		count = byte_stream_bytes_left(bs); /* truncate to remaining space */
 
 	if (count == 0)
 		return;
--- a/libpurple/protocols/oscar/libaim.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/libaim.c	Wed Aug 25 19:12:08 2010 +0000
@@ -25,6 +25,7 @@
  */
 
 #include "oscarcommon.h"
+#include "oscar.h"
 
 static PurplePluginProtocolInfo prpl_info =
 {
@@ -57,7 +58,7 @@
 	oscar_add_deny,			/* add_deny */
 	oscar_rem_permit,		/* rem_permit */
 	oscar_rem_deny,			/* rem_deny */
-	oscar_set_permit_deny,	/* set_permit_deny */
+	oscar_set_aim_permdeny,	/* set_permit_deny */
 	oscar_join_chat,		/* join_chat */
 	NULL,					/* reject_chat */
 	oscar_get_chat_name,	/* get_chat_name */
--- a/libpurple/protocols/oscar/libicq.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/libicq.c	Wed Aug 25 19:12:08 2010 +0000
@@ -63,11 +63,11 @@
 	NULL,					/* add_buddies */
 	oscar_remove_buddy,		/* remove_buddy */
 	NULL,					/* remove_buddies */
-	oscar_add_permit,		/* add_permit */
+	NULL,		/* add_permit */
 	oscar_add_deny,			/* add_deny */
-	oscar_rem_permit,		/* rem_permit */
+	NULL,		/* rem_permit */
 	oscar_rem_deny,			/* rem_deny */
-	oscar_set_permit_deny,	/* set_permit_deny */
+	NULL,	/* set_permit_deny */
 	oscar_join_chat,		/* join_chat */
 	NULL,					/* reject_chat */
 	oscar_get_chat_name,	/* get_chat_name */
--- a/libpurple/protocols/oscar/misc.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/misc.c	Wed Aug 25 19:12:08 2010 +0000
@@ -41,7 +41,7 @@
 {
 	aim_snacid_t snacid = 0x00000000;
 
-	flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, NULL);
+	flap_connection_send_snac(od, conn, family, subtype, snacid, NULL);
 }
 
 void
@@ -51,7 +51,7 @@
 
 	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
 
-	flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, NULL);
+	flap_connection_send_snac(od, conn, family, subtype, snacid, NULL);
 }
 
 void
@@ -72,30 +72,7 @@
 
 	byte_stream_put32(&bs, *longdata);
 
-	flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, &bs);
-
-	byte_stream_destroy(&bs);
-}
-
-void
-aim_genericreq_s(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 *shortdata)
-{
-	ByteStream bs;
-	aim_snacid_t snacid;
-
-	if (!shortdata)
-	{
-		aim_genericreq_n(od, conn, family, subtype);
-		return;
-	}
-
-	byte_stream_new(&bs, 2);
-
-	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
-
-	byte_stream_put16(&bs, *shortdata);
-
-	flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, &bs);
+	flap_connection_send_snac(od, conn, family, subtype, snacid, &bs);
 
 	byte_stream_destroy(&bs);
 }
@@ -114,7 +91,7 @@
 
 	snac2 = aim_remsnac(od, snac->id);
 
-	if (byte_stream_empty(bs))
+	if (byte_stream_bytes_left(bs))
 		error = byte_stream_get16(bs);
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
--- a/libpurple/protocols/oscar/msgcookie.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/msgcookie.c	Wed Aug 25 19:12:08 2010 +0000
@@ -177,18 +177,3 @@
 
 	return 0;
 }
-
-/* XXX I hate switch */
-int aim_msgcookie_gettype(guint64 type)
-{
-	/* XXX: hokey-assed. needs fixed. */
-	switch(type) {
-	case OSCAR_CAPABILITY_BUDDYICON: return AIM_COOKIETYPE_OFTICON;
-	case OSCAR_CAPABILITY_TALK: return AIM_COOKIETYPE_OFTVOICE;
-	case OSCAR_CAPABILITY_DIRECTIM: return AIM_COOKIETYPE_OFTIMAGE;
-	case OSCAR_CAPABILITY_CHAT: return AIM_COOKIETYPE_CHAT;
-	case OSCAR_CAPABILITY_GETFILE: return AIM_COOKIETYPE_OFTGET;
-	case OSCAR_CAPABILITY_SENDFILE: return AIM_COOKIETYPE_OFTSEND;
-	default: return AIM_COOKIETYPE_UNKNOWN;
-	}
-}
--- a/libpurple/protocols/oscar/odc.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/odc.c	Wed Aug 25 19:12:08 2010 +0000
@@ -19,6 +19,7 @@
 */
 
 /* From the oscar PRPL */
+#include "encoding.h"
 #include "oscar.h"
 #include "peer.h"
 
@@ -89,7 +90,7 @@
 	ByteStream bs;
 
 	purple_debug_info("oscar", "Outgoing ODC frame to %s with "
-		"type=0x%04x, flags=0x%04x, payload length=%u\n",
+		"type=0x%04x, flags=0x%04x, payload length=%" G_GSIZE_FORMAT "\n",
 		conn->bn, frame->type, frame->flags, frame->payload.len);
 
 	account = purple_connection_get_account(conn->od->gc);
@@ -366,8 +367,7 @@
 		g_datalist_clear(&attributes);
 
 		/* Append the message up to the tag */
-		utf8 = purple_plugin_oscar_decode_im_part(account, conn->bn,
-				encoding, 0x0000, tmp, start - tmp);
+		utf8 = oscar_decode_im(account, conn->bn, encoding, tmp, start - tmp);
 		if (utf8 != NULL) {
 			g_string_append(newmsg, utf8);
 			g_free(utf8);
@@ -386,8 +386,7 @@
 	/* Append any remaining message data */
 	if (tmp <= msgend)
 	{
-		utf8 = purple_plugin_oscar_decode_im_part(account, conn->bn,
-				encoding, 0x0000, tmp, msgend - tmp);
+		utf8 = oscar_decode_im(account, conn->bn, encoding, tmp, msgend - tmp);
 		if (utf8 != NULL) {
 			g_string_append(newmsg, utf8);
 			g_free(utf8);
@@ -506,7 +505,7 @@
 	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",
+			"type=0x%04x, flags=0x%04x, payload length=%" G_GSIZE_FORMAT "\n",
 			frame->bn, frame->type, frame->flags, frame->payload.len);
 
 	if (!conn->ready)
--- a/libpurple/protocols/oscar/oscar.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Wed Aug 25 19:12:08 2010 +0000
@@ -37,6 +37,7 @@
 #include "conversation.h"
 #include "core.h"
 #include "debug.h"
+#include "encoding.h"
 #include "imgstore.h"
 #include "network.h"
 #include "notify.h"
@@ -46,27 +47,12 @@
 #include "request.h"
 #include "util.h"
 #include "version.h"
+#include "visibility.h"
 
 #include "oscarcommon.h"
 #include "oscar.h"
 #include "peer.h"
 
-#define OSCAR_STATUS_ID_INVISIBLE   "invisible"
-#define OSCAR_STATUS_ID_OFFLINE     "offline"
-#define OSCAR_STATUS_ID_AVAILABLE   "available"
-#define OSCAR_STATUS_ID_AWAY        "away"
-#define OSCAR_STATUS_ID_DND         "dnd"
-#define OSCAR_STATUS_ID_NA          "na"
-#define OSCAR_STATUS_ID_OCCUPIED    "occupied"
-#define OSCAR_STATUS_ID_FREE4CHAT   "free4chat"
-#define OSCAR_STATUS_ID_CUSTOM      "custom"
-#define OSCAR_STATUS_ID_MOBILE	    "mobile"
-#define OSCAR_STATUS_ID_EVIL        "evil"
-#define OSCAR_STATUS_ID_DEPRESSION	 "depression"
-#define OSCAR_STATUS_ID_ATHOME      "athome"
-#define OSCAR_STATUS_ID_ATWORK      "atwork"
-#define OSCAR_STATUS_ID_LUNCH       "lunch"
-
 #define AIMHASHDATA "http://pidgin.im/aim_data.php3"
 
 #define OSCAR_CONNECT_STEPS 6
@@ -82,7 +68,8 @@
 		| OSCAR_CAPABILITY_TYPING
 		| OSCAR_CAPABILITY_ICQSERVERRELAY
 		| OSCAR_CAPABILITY_NEWCAPS
-		| OSCAR_CAPABILITY_XTRAZ;
+		| OSCAR_CAPABILITY_XTRAZ
+		| OSCAR_CAPABILITY_HTML_MSGS;
 
 static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02};
 static guint8 features_icq[] = {0x01};
@@ -99,35 +86,6 @@
 	char *who;
 };
 
-/*
- * Various PRPL-specific buddy info that we want to keep track of
- * Some other info is maintained by locate.c, and I'd like to move
- * the rest of this to libfaim, mostly im.c
- *
- * TODO: More of this should use the status API.
- */
-struct buddyinfo {
-	gboolean typingnot;
-	guint32 ipaddr;
-
-	unsigned long ico_me_len;
-	unsigned long ico_me_csum;
-	time_t ico_me_time;
-	gboolean ico_informed;
-
-	unsigned long ico_len;
-	unsigned long ico_csum;
-	time_t ico_time;
-	gboolean ico_need;
-	gboolean ico_sent;
-};
-
-struct name_data {
-	PurpleConnection *gc;
-	gchar *name;
-	gchar *nick;
-};
-
 /* All the libfaim->purple callback functions */
 
 /* Only used when connecting with the old-style BUCP login */
@@ -143,7 +101,6 @@
 static int purple_parse_incoming_im(OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_parse_misses     (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_parse_clientauto (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_userinfo   (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_parse_motd       (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_chatnav_info     (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_conv_chat_join        (OscarData *, FlapConnection *, FlapFrame *, ...);
@@ -152,8 +109,6 @@
 static int purple_conv_chat_incoming_msg(OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_email_parseupdate(OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_icon_parseicon   (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_msgack     (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_evilnotify (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_parse_searcherror(OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_parse_searchreply(OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_bosrights        (OscarData *, FlapConnection *, FlapFrame *, ...);
@@ -161,16 +116,9 @@
 static int purple_parse_mtn        (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_parse_locaterights(OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_parse_buddyrights(OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_locerr     (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_parse_genericerr (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_memrequest       (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_selfinfo         (OscarData *, FlapConnection *, FlapFrame *, ...);
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-static int purple_offlinemsg       (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_offlinemsgdone   (OscarData *, FlapConnection *, FlapFrame *, ...);
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
-static int purple_icqalias         (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_icqinfo          (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_popup            (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_ssi_parseerr     (OscarData *, FlapConnection *, FlapFrame *, ...);
 static int purple_ssi_parserights  (OscarData *, FlapConnection *, FlapFrame *, ...);
@@ -186,10 +134,10 @@
 
 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_set_extended_status(PurpleConnection *gc);
 static gboolean purple_ssi_rerequestdata(gpointer data);
 
-static void oscar_free_name_data(struct name_data *data) {
+void oscar_free_name_data(struct name_data *data) {
 	g_free(data->name);
 	g_free(data->nick);
 	g_free(data);
@@ -204,536 +152,6 @@
 }
 #endif
 
-/**
- * Determine how we can send this message.  Per the warnings elsewhere
- * in this file, these little checks determine the simplest encoding
- * we can use for a given message send using it.
- */
-static guint32
-oscar_charset_check(const char *utf8)
-{
-	int i = 0;
-	int charset = AIM_CHARSET_ASCII;
-
-	/*
-	 * Can we get away with using our custom encoding?
-	 */
-	while (utf8[i])
-	{
-		if ((unsigned char)utf8[i] > 0x7f) {
-			/* not ASCII! */
-			charset = AIM_CHARSET_LATIN_1;
-			break;
-		}
-		i++;
-	}
-
-	/*
-	 * Must we send this message as UNICODE (in the UTF-16BE encoding)?
-	 */
-	while (utf8[i])
-	{
-		/* ISO-8859-1 is 0x00-0xbf in the first byte
-		 * followed by 0xc0-0xc3 in the second */
-		if ((unsigned char)utf8[i] < 0x80) {
-			i++;
-			continue;
-		} else if (((unsigned char)utf8[i] & 0xfc) == 0xc0 &&
-				   ((unsigned char)utf8[i + 1] & 0xc0) == 0x80) {
-			i += 2;
-			continue;
-		}
-		charset = AIM_CHARSET_UNICODE;
-		break;
-	}
-
-	return charset;
-}
-
-/**
- * Take a string of the form charset="bleh" where bleh is
- * one of us-ascii, utf-8, iso-8859-1, or unicode-2-0, and
- * return a newly allocated string containing bleh.
- */
-gchar *
-oscar_encoding_extract(const char *encoding)
-{
-	gchar *ret = NULL;
-	char *begin, *end;
-
-	g_return_val_if_fail(encoding != NULL, NULL);
-
-	/* Make sure encoding begins with charset= */
-	if (strncmp(encoding, "text/aolrtf; charset=", 21) &&
-		strncmp(encoding, "text/x-aolrtf; charset=", 23) &&
-		strncmp(encoding, "text/plain; charset=", 20))
-	{
-		return NULL;
-	}
-
-	begin = strchr(encoding, '"');
-	end = strrchr(encoding, '"');
-
-	if ((begin == NULL) || (end == NULL) || (begin >= end))
-		return NULL;
-
-	ret = g_strndup(begin+1, (end-1) - begin);
-
-	return ret;
-}
-
-gchar *
-oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen)
-{
-	gchar *utf8 = NULL;
-
-	if ((encoding == NULL) || encoding[0] == '\0') {
-		purple_debug_info("oscar", "Empty encoding, assuming UTF-8\n");
-	} else if (!g_ascii_strcasecmp(encoding, "iso-8859-1")) {
-		utf8 = g_convert(text, textlen, "UTF-8", "iso-8859-1", NULL, NULL, NULL);
-	} else if (!g_ascii_strcasecmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1") ||
-	           !g_ascii_strcasecmp(encoding, "us-ascii"))
-	{
-		utf8 = g_convert(text, textlen, "UTF-8", "Windows-1252", NULL, NULL, NULL);
-	} else if (!g_ascii_strcasecmp(encoding, "unicode-2-0")) {
-		/* Some official ICQ clients are apparently total crack,
-		 * and have been known to save a UTF-8 string converted
-		 * from the locale character set to UTF-16 (not from UTF-8
-		 * to UTF-16!) in the away message.  This hack should find
-		 * and do something (un)reasonable with that, and not
-		 * mess up too much else. */
-		const gchar *charset = purple_account_get_string(account, "encoding", NULL);
-		if (charset) {
-			gsize len;
-			utf8 = g_convert(text, textlen, charset, "UTF-16BE", &len, NULL, NULL);
-			if (!utf8 || len != textlen || !g_utf8_validate(utf8, -1, NULL)) {
-				g_free(utf8);
-				utf8 = NULL;
-			} else {
-				purple_debug_info("oscar", "Used broken ICQ fallback encoding\n");
-			}
-		}
-		if (!utf8)
-			utf8 = g_convert(text, textlen, "UTF-8", "UTF-16BE", NULL, NULL, NULL);
-	} else if (g_ascii_strcasecmp(encoding, "utf-8")) {
-		purple_debug_warning("oscar", "Unrecognized character encoding \"%s\", "
-						   "attempting to convert to UTF-8 anyway\n", encoding);
-		utf8 = g_convert(text, textlen, "UTF-8", encoding, NULL, NULL, NULL);
-	}
-
-	/*
-	 * If utf8 is still NULL then either the encoding is utf-8 or
-	 * we have been unable to convert the text to utf-8 from the encoding
-	 * that was specified.  So we check if the text is valid utf-8 then
-	 * just copy it.
-	 */
-	if (utf8 == NULL) {
-		if (textlen != 0 && *text != '\0'
-				&& !g_utf8_validate(text, textlen, NULL))
-			utf8 = g_strdup(_("(There was an error receiving this message.  The buddy you are speaking with is probably using a different encoding than expected.  If you know what encoding he is using, you can specify it in the advanced account options for your AIM/ICQ account.)"));
-		else
-			utf8 = g_strndup(text, textlen);
-	}
-
-	return utf8;
-}
-
-static gchar *
-oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg)
-{
-	const char *charset = NULL;
-	char *ret = NULL;
-
-	if (od->icq)
-		charset = purple_account_get_string(account, "encoding", NULL);
-
-	if(charset && *charset)
-		ret = g_convert(msg, -1, "UTF-8", charset, NULL, NULL, NULL);
-
-	if(!ret)
-		ret = purple_utf8_try_convert(msg);
-
-	return ret;
-}
-
-static gchar *
-purple_plugin_oscar_convert_to_utf8(const gchar *data, gsize datalen, const char *charsetstr, gboolean fallback)
-{
-	gchar *ret = NULL;
-	GError *err = NULL;
-
-	if ((charsetstr == NULL) || (*charsetstr == '\0'))
-		return NULL;
-
-	if (g_ascii_strcasecmp("UTF-8", charsetstr)) {
-		if (fallback)
-			ret = g_convert_with_fallback(data, datalen, "UTF-8", charsetstr, "?", NULL, NULL, &err);
-		else
-			ret = g_convert(data, datalen, "UTF-8", charsetstr, NULL, NULL, &err);
-		if (err != NULL) {
-			purple_debug_warning("oscar", "Conversion from %s failed: %s.\n",
-							   charsetstr, err->message);
-			g_error_free(err);
-		}
-	} else {
-		if (g_utf8_validate(data, datalen, NULL))
-			ret = g_strndup(data, datalen);
-		else
-			purple_debug_warning("oscar", "String is not valid UTF-8.\n");
-	}
-
-	return ret;
-}
-
-/**
- * This attemps to decode an incoming IM into a UTF8 string.
- *
- * We try decoding using two different character sets.  The charset
- * specified in the IM determines the order in which we attempt to
- * decode.  We do this because there are lots of broken ICQ clients
- * that don't correctly send non-ASCII messages.  And if Purple isn't
- * able to deal with that crap, then people complain like banshees.
- * charsetstr1 is always set to what the correct encoding should be.
- */
-gchar *
-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, *charsetstr3 = NULL;
-
-	if ((datalen == 0) || (data == NULL))
-		return NULL;
-
-	if (charset == AIM_CHARSET_UNICODE) {
-		charsetstr1 = "UTF-16BE";
-		charsetstr2 = "UTF-8";
-	} else if (charset == AIM_CHARSET_LATIN_1) {
-		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";
-		charsetstr2 = "UTF-8";
-	} else if (charset == AIM_CHARSET_ASCII) {
-		/* Should just be "ASCII" */
-		charsetstr1 = "ASCII";
-		charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-	} else if (charset == 0x000d) {
-		/* iChat sending unicode over a Direct IM connection = UTF-8 */
-		/* Mobile AIM client on multiple devices (including Blackberry Tour, Nokia 3100, and LG VX6000) = ISO-8859-1 */
-		charsetstr1 = "UTF-8";
-		charsetstr2 = "ISO-8859-1";
-		charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-	} else {
-		/* Unknown, hope for valid UTF-8... */
-		charsetstr1 = "UTF-8";
-		charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-	}
-
-	purple_debug_info("oscar", "Parsing IM part, charset=0x%04hx, charsubset=0x%04hx, datalen=%" G_GSIZE_FORMAT ", choice1=%s, choice2=%s, choice3=%s\n",
-					  charset, charsubset, datalen, charsetstr1, charsetstr2, (charsetstr3 ? charsetstr3 : ""));
-
-	ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr1, FALSE);
-	if (ret == NULL) {
-		if (charsetstr3 != NULL) {
-			/* Try charsetstr2 without allowing substitutions, then fall through to charsetstr3 if needed */
-			ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr2, FALSE);
-			if (ret == NULL)
-				ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr3, TRUE);
-		} else {
-			/* Try charsetstr2, allowing substitutions */
-			ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr2, TRUE);
-		}
-	}
-	if (ret == NULL) {
-		char *str, *salvage, *tmp;
-
-		str = g_malloc(datalen + 1);
-		strncpy(str, data, datalen);
-		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.)"),
-					  sourcebn, sourcebn);
-		ret = g_strdup_printf("%s %s", salvage, tmp);
-		g_free(tmp);
-		g_free(str);
-		g_free(salvage);
-	}
-
-	return ret;
-}
-
-/**
- * Figure out what encoding to use when sending a given outgoing message.
- */
-static void
-purple_plugin_oscar_convert_to_best_encoding(PurpleConnection *gc,
-				const char *destbn, const gchar *from,
-				gchar **msg, int *msglen_int,
-				guint16 *charset, guint16 *charsubset)
-{
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	PurpleAccount *account = purple_connection_get_account(gc);
-	GError *err = NULL;
-	aim_userinfo_t *userinfo = NULL;
-	const gchar *charsetstr;
-	gsize msglen;
-
-	/* Attempt to send as ASCII */
-	if (oscar_charset_check(from) == AIM_CHARSET_ASCII) {
-		*msg = g_convert(from, -1, "ASCII", "UTF-8", NULL, &msglen, NULL);
-		*charset = AIM_CHARSET_ASCII;
-		*charsubset = 0x0000;
-		*msglen_int = msglen;
-		return;
-	}
-
-	/*
-	 * If we're sending to an ICQ user, and they are in our
-	 * buddy list, and they are advertising the Unicode
-	 * capability, and they are online, then attempt to send
-	 * as UTF-16BE.
-	 */
-	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, destbn);
-		if ((b != NULL) && (PURPLE_BUDDY_IS_ONLINE(b)))
-		{
-			*msg = g_convert(from, -1, "UTF-16BE", "UTF-8", NULL, &msglen, &err);
-			if (*msg != NULL)
-			{
-				*charset = AIM_CHARSET_UNICODE;
-				*charsubset = 0x0000;
-				*msglen_int = msglen;
-				return;
-			}
-
-			purple_debug_error("oscar", "Conversion from UTF-8 to UTF-16BE failed: %s.\n",
-							   err->message);
-			g_error_free(err);
-			err = NULL;
-		}
-	}
-
-	/*
-	 * If this is AIM then attempt to send as ISO-8859-1.  If this is
-	 * ICQ then attempt to send as the user specified character encoding.
-	 */
-	charsetstr = "ISO-8859-1";
-	if ((destbn != NULL) && oscar_util_valid_name_icq(destbn))
-		charsetstr = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-
-	/*
-	 * XXX - We need a way to only attempt to convert if we KNOW "from"
-	 * can be converted to "charsetstr"
-	 */
-	*msg = g_convert(from, -1, charsetstr, "UTF-8", NULL, &msglen, &err);
-	if (*msg != NULL) {
-		*charset = AIM_CHARSET_LATIN_1;
-		*charsubset = 0x0000;
-		*msglen_int = msglen;
-		return;
-	}
-
-	purple_debug_info("oscar", "Conversion from UTF-8 to %s failed (%s). Falling back to unicode.\n",
-					  charsetstr, err->message);
-	g_error_free(err);
-	err = NULL;
-
-	/*
-	 * Nothing else worked, so send as UTF-16BE.
-	 */
-	*msg = g_convert(from, -1, "UTF-16BE", "UTF-8", NULL, &msglen, &err);
-	if (*msg != NULL) {
-		*charset = AIM_CHARSET_UNICODE;
-		*charsubset = 0x0000;
-		*msglen_int = msglen;
-		return;
-	}
-
-	purple_debug_error("oscar", "Error converting a Unicode message: %s\n", err->message);
-	g_error_free(err);
-	err = NULL;
-
-	purple_debug_error("oscar", "This should NEVER happen!  Sending UTF-8 text flagged as ASCII.\n");
-	*msg = g_strdup(from);
-	*msglen_int = strlen(*msg);
-	*charset = AIM_CHARSET_ASCII;
-	*charsubset = 0x0000;
-	return;
-}
-
-/**
- * Looks for %n, %d, or %t in a string, and replaces them with the
- * specified name, date, and time, respectively.
- *
- * @param str  The string that may contain the special variables.
- * @param name The sender name.
- *
- * @return A newly allocated string where the special variables are
- *         expanded.  This should be g_free'd by the caller.
- */
-static gchar *
-purple_str_sub_away_formatters(const char *str, const char *name)
-{
-	char *c;
-	GString *cpy;
-	time_t t;
-	struct tm *tme;
-
-	g_return_val_if_fail(str  != NULL, NULL);
-	g_return_val_if_fail(name != NULL, NULL);
-
-	/* Create an empty GString that is hopefully big enough for most messages */
-	cpy = g_string_sized_new(1024);
-
-	t = time(NULL);
-	tme = localtime(&t);
-
-	c = (char *)str;
-	while (*c) {
-		switch (*c) {
-		case '%':
-			if (*(c + 1)) {
-				switch (*(c + 1)) {
-				case 'n':
-					/* append name */
-					g_string_append(cpy, name);
-					c++;
-					break;
-				case 'd':
-					/* append date */
-					g_string_append(cpy, purple_date_format_short(tme));
-					c++;
-					break;
-				case 't':
-					/* append time */
-					g_string_append(cpy, purple_time_format(tme));
-					c++;
-					break;
-				default:
-					g_string_append_c(cpy, *c);
-				}
-			} else {
-				g_string_append_c(cpy, *c);
-			}
-			break;
-		default:
-			g_string_append_c(cpy, *c);
-		}
-		c++;
-	}
-
-	return g_string_free(cpy, FALSE);
-}
-
-static gchar *oscar_caps_to_string(guint64 caps)
-{
-	GString *str;
-	const gchar *tmp;
-	guint64 bit = 1;
-
-	str = g_string_new("");
-
-	if (!caps) {
-		return NULL;
-	} else while (bit <= OSCAR_CAPABILITY_LAST) {
-		if (bit & caps) {
-			switch (bit) {
-			case OSCAR_CAPABILITY_BUDDYICON:
-				tmp = _("Buddy Icon");
-				break;
-			case OSCAR_CAPABILITY_TALK:
-				tmp = _("Voice");
-				break;
-			case OSCAR_CAPABILITY_DIRECTIM:
-				tmp = _("AIM Direct IM");
-				break;
-			case OSCAR_CAPABILITY_CHAT:
-				tmp = _("Chat");
-				break;
-			case OSCAR_CAPABILITY_GETFILE:
-				tmp = _("Get File");
-				break;
-			case OSCAR_CAPABILITY_SENDFILE:
-				tmp = _("Send File");
-				break;
-			case OSCAR_CAPABILITY_GAMES:
-			case OSCAR_CAPABILITY_GAMES2:
-				tmp = _("Games");
-				break;
-			case OSCAR_CAPABILITY_XTRAZ:
-			case OSCAR_CAPABILITY_NEWCAPS:
-				tmp = _("ICQ Xtraz");
-				break;
-			case OSCAR_CAPABILITY_ADDINS:
-				tmp = _("Add-Ins");
-				break;
-			case OSCAR_CAPABILITY_SENDBUDDYLIST:
-				tmp = _("Send Buddy List");
-				break;
-			case OSCAR_CAPABILITY_ICQ_DIRECT:
-				tmp = _("ICQ Direct Connect");
-				break;
-			case OSCAR_CAPABILITY_APINFO:
-				tmp = _("AP User");
-				break;
-			case OSCAR_CAPABILITY_ICQRTF:
-				tmp = _("ICQ RTF");
-				break;
-			case OSCAR_CAPABILITY_EMPTY:
-				tmp = _("Nihilist");
-				break;
-			case OSCAR_CAPABILITY_ICQSERVERRELAY:
-				tmp = _("ICQ Server Relay");
-				break;
-			case OSCAR_CAPABILITY_UNICODEOLD:
-				tmp = _("Old ICQ UTF8");
-				break;
-			case OSCAR_CAPABILITY_TRILLIANCRYPT:
-				tmp = _("Trillian Encryption");
-				break;
-			case OSCAR_CAPABILITY_UNICODE:
-				tmp = _("ICQ UTF8");
-				break;
-			case OSCAR_CAPABILITY_HIPTOP:
-				tmp = _("Hiptop");
-				break;
-			case OSCAR_CAPABILITY_SECUREIM:
-				tmp = _("Security Enabled");
-				break;
-			case OSCAR_CAPABILITY_VIDEO:
-				tmp = _("Video Chat");
-				break;
-			/* Not actually sure about this one... WinAIM doesn't show anything */
-			case OSCAR_CAPABILITY_ICHATAV:
-				tmp = _("iChat AV");
-				break;
-			case OSCAR_CAPABILITY_LIVEVIDEO:
-				tmp = _("Live Video");
-				break;
-			case OSCAR_CAPABILITY_CAMERA:
-				tmp = _("Camera");
-				break;
-			case OSCAR_CAPABILITY_ICHAT_SCREENSHARE:
-				tmp = _("Screen Sharing");
-				break;
-			default:
-				tmp = NULL;
-				break;
-			}
-			if (tmp)
-				g_string_append_printf(str, "%s%s", (*(str->str) == '\0' ? "" : ", "), tmp);
-		}
-		bit <<= 1;
-	}
-
-	return g_string_free(str, FALSE);
-}
-
 static char *oscar_icqstatus(int state) {
 	/* Make a cute little string that shows the status of the dude or dudet */
 	if (state & AIM_ICQ_STATE_CHAT)
@@ -764,255 +182,6 @@
 		return g_strdup(_("Online"));
 }
 
-static void
-oscar_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *name, const char *value)
-{
-	if (value && value[0]) {
-		purple_notify_user_info_add_pair(user_info, name, value);
-	}
-}
-
-static void
-oscar_user_info_convert_and_add_pair(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
-									 const char *name, const char *value)
-{
-	gchar *utf8;
-
-	if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) {
-		purple_notify_user_info_add_pair(user_info, name, utf8);
-		g_free(utf8);
-	}
-}
-
-static void
-oscar_user_info_convert_and_add(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
-								const char *name, const char *value)
-{
-	gchar *utf8;
-
-	if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) {
-		purple_notify_user_info_add_pair(user_info, name, utf8);
-		g_free(utf8);
-	}
-}
-
-/**
- * @brief Append the status information to a user_info struct
- *
- * The returned information is HTML-ready, appropriately escaped, as all information in a user_info struct should be HTML.
- *
- * @param gc The PurpleConnection
- * @param user_info A PurpleNotifyUserInfo object to which status information will be added
- * @param b The PurpleBuddy whose status is desired. This or the aim_userinfo_t (or both) must be passed to oscar_user_info_append_status().
- * @param userinfo The aim_userinfo_t of the buddy whose status is desired. This or the PurpleBuddy (or both) must be passed to oscar_user_info_append_status().
- * @param strip_html_tags If strip_html_tags is TRUE, tags embedded in the status message will be stripped, returning a non-formatted string. The string will still be HTML escaped.
- */
-static void oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean strip_html_tags)
-{
-	PurpleAccount *account = purple_connection_get_account(gc);
-	OscarData *od;
-	PurplePresence *presence = NULL;
-	PurpleStatus *status = NULL;
-	gchar *message = NULL, *itmsurl = NULL, *tmp;
-	gboolean is_away;
-
-	od = purple_connection_get_protocol_data(gc);
-
-	if (b == NULL && userinfo == NULL)
-		return;
-
-	if (b == NULL)
-		b = purple_find_buddy(purple_connection_get_account(gc), userinfo->bn);
-	else
-		userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
-
-	if (b) {
-		presence = purple_buddy_get_presence(b);
-		status = purple_presence_get_active_status(presence);
-	}
-
-	/* If we have both b and userinfo we favor userinfo, because if we're
-	   viewing someone's profile then we want the HTML away message, and
-	   the "message" attribute of the status contains only the plaintext
-	   message. */
-	if (userinfo) {
-		if ((userinfo->flags & AIM_FLAG_AWAY)
-				&& userinfo->away_len > 0
-				&& userinfo->away != NULL
-				&& userinfo->away_encoding != NULL)
-		{
-			/* Away message */
-			tmp = oscar_encoding_extract(userinfo->away_encoding);
-			message = oscar_encoding_to_utf8(account,
-					tmp, userinfo->away, userinfo->away_len);
-			g_free(tmp);
-		} else {
-			/*
-			 * Available message or non-HTML away message (because that's
-			 * all we have right now.
-			 */
-			if ((userinfo->status != NULL) && userinfo->status[0] != '\0') {
-				message = oscar_encoding_to_utf8(account,
-						userinfo->status_encoding, userinfo->status,
-						userinfo->status_len);
-			}
-#if defined (_WIN32) || defined (__APPLE__)
-			if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0'))
-				itmsurl = oscar_encoding_to_utf8(account, userinfo->itmsurl_encoding,
-												 userinfo->itmsurl, userinfo->itmsurl_len);
-#endif
-		}
-	} else {
-		message = g_strdup(purple_status_get_attr_string(status, "message"));
-		itmsurl = g_strdup(purple_status_get_attr_string(status, "itmsurl"));
-	}
-
-	is_away = ((status && !purple_status_is_available(status)) ||
-			   (userinfo && (userinfo->flags & AIM_FLAG_AWAY)));
-
-	if (strip_html_tags) {
-		/* Away messages are HTML, but available messages were originally plain text.
-		 * We therefore need to strip away messages but not available messages if we're asked to remove HTML tags.
-		 */
-		/*
-		 * It seems like the above comment no longer applies.  All messages need
-		 * to be escaped.
-		 */
-		if (message) {
-			gchar *tmp2;
-			tmp = purple_markup_strip_html(message);
-			g_free(message);
-			tmp2 = g_markup_escape_text(tmp, -1);
-			g_free(tmp);
-			message = tmp2;
-		}
-
-	} else {
-		if (itmsurl) {
-			tmp = g_strdup_printf("<a href=\"%s\">%s</a>",
-								  itmsurl, message);
-			g_free(message);
-			message = tmp;
-		}
-	}
-	g_free(itmsurl);
-
-	if (message) {
-		tmp = purple_str_sub_away_formatters(message, purple_account_get_username(account));
-		g_free(message);
-		message = tmp;
-	}
-
-	if (b) {
-		if (purple_presence_is_online(presence)) {
-			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);
-				if (status_name && message && !strcmp(status_name, message))
-					status_name = NULL;
-
-				tmp = g_strdup_printf("%s%s%s",
-									   status_name ? status_name : "",
-									   ((status_name && 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, 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 {
-			g_free(message);
-			message = g_strdup(_("Offline"));
-		}
-	}
-
-	if (presence) {
-		const char *mood;
-		const char *description;
-		status = purple_presence_get_status(presence, "mood");
-		mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
-		description = icq_get_custom_icon_description(mood);
-		if (description && *description)
-			purple_notify_user_info_add_pair(user_info, _("Mood"), _(description));
-	}
-
-	purple_notify_user_info_add_pair(user_info, _("Status"), message);
-	g_free(message);
-}
-
-static void oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo)
-{
-	OscarData *od;
-	PurpleAccount *account;
-	PurplePresence *presence = NULL;
-	PurpleStatus *status = NULL;
-	PurpleGroup *g = NULL;
-	struct buddyinfo *bi = NULL;
-	char *tmp;
-	const char *bname = NULL, *gname = NULL;
-
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-
-	if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL)))
-		return;
-
-	if (userinfo == NULL)
-		userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
-
-	if (b == NULL)
-		b = purple_find_buddy(account, userinfo->bn);
-
-	if (b != NULL) {
-		bname = purple_buddy_get_name(b);
-		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->bn));
-
-	if ((bi != NULL) && (bi->ipaddr != 0)) {
-		tmp =  g_strdup_printf("%hhu.%hhu.%hhu.%hhu",
-						(bi->ipaddr & 0xff000000) >> 24,
-						(bi->ipaddr & 0x00ff0000) >> 16,
-						(bi->ipaddr & 0x0000ff00) >> 8,
-						(bi->ipaddr & 0x000000ff));
-		oscar_user_info_add_pair(user_info, _("IP Address"), tmp);
-		g_free(tmp);
-	}
-
-	if ((userinfo != NULL) && (userinfo->warnlevel != 0)) {
-		tmp = g_strdup_printf("%d", (int)(userinfo->warnlevel/10.0 + .5));
-		oscar_user_info_add_pair(user_info, _("Warning Level"), tmp);
-		g_free(tmp);
-	}
-
-	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);
-
-			oscar_user_info_convert_and_add_pair(account, od, user_info, _("Buddy Comment"), tmp2);
-			g_free(tmp2);
-		}
-	}
-}
-
 static char *extract_name(const char *name) {
 	char *tmp, *x;
 	int i, j;
@@ -1496,22 +665,12 @@
 	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MISSEDCALL, purple_parse_misses, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_CLIENTAUTORESP, purple_parse_clientauto, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MTN, purple_parse_mtn, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_ACK, purple_parse_msgack, 0);
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-	oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSG, purple_offlinemsg, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE, purple_offlinemsgdone, 0);
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
-	oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_ALIAS, purple_icqalias, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_INFO, purple_icqinfo, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_RIGHTSINFO, purple_parse_locaterights, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_USERINFO, purple_parse_userinfo, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_ERROR, purple_parse_locerr, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x0001, purple_parse_genericerr, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x000f, purple_selfinfo, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x001f, purple_memrequest, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_REDIRECT, purple_handle_redirect, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_MOTD, purple_parse_motd, 0);
-	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_EVIL, purple_parse_evilnotify, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_POPUP, 0x0002, purple_popup, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, SNAC_SUBTYPE_USERLOOKUP_ERROR, purple_parse_searcherror, 0);
 	oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, 0x0003, purple_parse_searchreply, 0);
@@ -1771,34 +930,6 @@
 				AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
 		return 1;
 	}
-	/* uncomment this when you're convinced it's right. remember, it's been wrong before. */
-#if 0
-	if (offset > AIM_MAX_FILE_SIZE || len > AIM_MAX_FILE_SIZE) {
-		char *buf;
-		int i = 8;
-		if (modname)
-			i += strlen(modname);
-		buf = g_malloc(i);
-		i = 0;
-		if (modname) {
-			memcpy(buf, modname, strlen(modname));
-			i += strlen(modname);
-		}
-		buf[i++] = offset & 0xff;
-		buf[i++] = (offset >> 8) & 0xff;
-		buf[i++] = (offset >> 16) & 0xff;
-		buf[i++] = (offset >> 24) & 0xff;
-		buf[i++] = len & 0xff;
-		buf[i++] = (len >> 8) & 0xff;
-		buf[i++] = (len >> 16) & 0xff;
-		buf[i++] = (len >> 24) & 0xff;
-		purple_debug_misc("oscar", "len + offset is invalid, "
-		           "hashing request\n");
-		aim_sendmemblock(od, command->conn, offset, i, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
-		g_free(buf);
-		return 1;
-	}
-#endif
 
 	pos = g_new0(struct pieceofcrap, 1);
 	pos->gc = od->gc;
@@ -2253,18 +1384,18 @@
 		purple_prpl_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE);
 	}
 
-	if (info->status != NULL && info->status[0] != '\0')
+	if (info->status != NULL && info->status[0] != '\0') {
 		/* Grab the available message */
-		message = oscar_encoding_to_utf8(account, info->status_encoding,
-										 info->status, info->status_len);
+		message = oscar_encoding_to_utf8(info->status_encoding, info->status, info->status_len);
+	}
 
 	tmp2 = tmp = (message ? purple_markup_escape_text(message, -1) : NULL);
 
 	if (strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) == 0) {
-		if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len)
+		if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len) {
 			/* Grab the iTunes Music Store URL */
-			itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding,
-											 info->itmsurl, info->itmsurl_len);
+			itmsurl = oscar_encoding_to_utf8(info->itmsurl_encoding, info->itmsurl, info->itmsurl_len);
+		}
 
 		if (tmp2 == NULL && itmsurl != NULL)
 			/*
@@ -2370,17 +1501,11 @@
 	PurpleMessageFlags flags = 0;
 	struct buddyinfo *bi;
 	PurpleStoredImage *img;
-	GString *message;
 	gchar *tmp;
-	aim_mpmsg_section_t *curpart;
 	const char *start, *end;
 	GData *attribs;
 
-	purple_debug_misc("oscar", "Received IM from %s with %d parts\n",
-					userinfo->bn, args->mpmsg.numparts);
-
-	if (args->mpmsg.numparts == 0)
-		return 1;
+	purple_debug_misc("oscar", "Received IM from %s\n", userinfo->bn);
 
 	bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn));
 	if (!bi) {
@@ -2420,19 +1545,7 @@
 	}
 	purple_imgstore_unref(img);
 
-	message = g_string_new("");
-	curpart = args->mpmsg.parts;
-	while (curpart != NULL) {
-		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);
-			g_free(tmp);
-		}
-
-		curpart = curpart->next;
-	}
-	tmp = g_string_free(message, FALSE);
+	tmp = g_strdup(args->msg);
 
 	/*
 	 * Convert iChat color tags to normal font tags.
@@ -2516,8 +1629,7 @@
 		tmp = tmp2;
 	}
 
-	serv_got_im(gc, userinfo->bn, tmp, flags,
-			(args->icbmflags & AIM_IMFLAGS_OFFLINE) ? args->timestamp : time(NULL));
+	serv_got_im(gc, userinfo->bn, tmp, flags, (args->icbmflags & AIM_IMFLAGS_OFFLINE) ? args->timestamp : time(NULL));
 	g_free(tmp);
 
 	return 1;
@@ -2545,35 +1657,20 @@
 			G_GUINT64_FORMAT ", user %s, status %hu\n",
 			args->type, userinfo->bn, args->status);
 
-	if (args->msg != NULL)
-	{
-		if (args->encoding != NULL)
-		{
-			char *encoding = NULL;
-			encoding = oscar_encoding_extract(args->encoding);
-			message = oscar_encoding_to_utf8(account, encoding, args->msg,
-			                                 args->msglen);
-			g_free(encoding);
-		} else {
-			if (g_utf8_validate(args->msg, args->msglen, NULL))
-				message = g_strdup(args->msg);
-		}
+	if (args->msg != NULL) {
+		message = oscar_encoding_to_utf8(args->encoding, args->msg, args->msglen);
 	}
 
 	if (args->type & OSCAR_CAPABILITY_CHAT)
 	{
-		char *encoding, *utf8name, *tmp;
+		char *utf8name, *tmp;
 		GHashTable *components;
 
 		if (!args->info.chat.roominfo.name || !args->info.chat.roominfo.exchange) {
 			g_free(message);
 			return 1;
 		}
-		encoding = args->encoding ? oscar_encoding_extract(args->encoding) : NULL;
-		utf8name = oscar_encoding_to_utf8(account, encoding,
-				args->info.chat.roominfo.name,
-				args->info.chat.roominfo.namelen);
-		g_free(encoding);
+		utf8name = oscar_encoding_to_utf8(args->encoding, args->info.chat.roominfo.name, args->info.chat.roominfo.namelen);
 
 		tmp = extract_name(utf8name);
 		if (tmp != NULL)
@@ -2594,8 +1691,7 @@
 				     components);
 	}
 
-	else if ((args->type & OSCAR_CAPABILITY_SENDFILE) ||
-			 (args->type & OSCAR_CAPABILITY_DIRECTIM))
+	else if ((args->type & OSCAR_CAPABILITY_SENDFILE) || (args->type & OSCAR_CAPABILITY_DIRECTIM))
 	{
 		if (args->status == AIM_RENDEZVOUS_PROPOSE)
 		{
@@ -2648,24 +1744,22 @@
 		purple_debug_info("oscar", "Got an ICQ Server Relay message of "
 				"type %d\n", args->info.rtfmsg.msgtype);
 
-		if (args->info.rtfmsg.msgtype == 1)
-		{
-			if (args->info.rtfmsg.rtfmsg != NULL)
-			{
-				char *rtfmsg = NULL;
-				if (args->encoding != NULL) {
-					char *encoding = oscar_encoding_extract(args->encoding);
-					rtfmsg = oscar_encoding_to_utf8(account, encoding,
-							args->info.rtfmsg.rtfmsg, strlen(args->info.rtfmsg.rtfmsg));
-					g_free(encoding);
-				} else {
-					if (g_utf8_validate(args->info.rtfmsg.rtfmsg, strlen(args->info.rtfmsg.rtfmsg), NULL))
-						rtfmsg = g_strdup(args->info.rtfmsg.rtfmsg);
-				}
-				if (rtfmsg) {
-					serv_got_im(gc, userinfo->bn, rtfmsg, flags, time(NULL));
-					g_free(rtfmsg);
-				}
+		if (args->info.rtfmsg.msgtype == 1) {
+			if (args->info.rtfmsg.msg != NULL) {
+				char *rtfmsg = oscar_encoding_to_utf8(args->encoding, args->info.rtfmsg.msg, strlen(args->info.rtfmsg.msg));
+				char *tmp, *tmp2;
+
+				/* Channel 2 messages are supposed to be plain-text (never mind the name "rtfmsg", even
+				 * the official client doesn't parse them as RTF). Therefore, we should escape them before
+				 * showing to the user. */
+				tmp = g_markup_escape_text(rtfmsg, -1);
+				g_free(rtfmsg);
+				tmp2 = purple_strreplace(tmp, "\r\n", "<br>");
+				g_free(tmp);
+
+				serv_got_im(gc, userinfo->bn, tmp2, flags, time(NULL));
+				aim_im_send_icq_confirmation(od, userinfo->bn, args->cookie);
+				g_free(tmp2);
 			}
 		} else if (args->info.rtfmsg.msgtype == 26) {
 			purple_debug_info("oscar", "Sending X-Status Reply\n");
@@ -2683,122 +1777,6 @@
 	return 1;
 }
 
-/*
- * Authorization Functions
- * Most of these are callbacks from dialogs.  They're used by both
- * methods of authorization (SSI and old-school channel 4 ICBM)
- */
-/* When you ask other people for authorization */
-static void
-purple_auth_request(struct name_data *data, char *msg)
-{
-	PurpleConnection *gc;
-	OscarData *od;
-	PurpleAccount *account;
-	PurpleBuddy *buddy;
-	PurpleGroup *group;
-	const char *bname, *gname;
-
-	gc = data->gc;
-	od = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-	buddy = purple_find_buddy(account, data->name);
-	if (buddy != NULL)
-		group = purple_buddy_get_group(buddy);
-	else
-		group = NULL;
-
-	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",
-				   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, gname, bname, AIM_SSI_TYPE_BUDDY))
-		{
-			aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE);
-
-			/* Mobile users should always be online */
-			if (bname[0] == '+') {
-				purple_prpl_got_user_status(account,
-						purple_buddy_get_name(buddy),
-						OSCAR_STATUS_ID_AVAILABLE, NULL);
-				purple_prpl_got_user_status(account,
-						purple_buddy_get_name(buddy),
-						OSCAR_STATUS_ID_MOBILE, NULL);
-			}
-		}
-	}
-
-	oscar_free_name_data(data);
-}
-
-static void
-purple_auth_sendrequest(PurpleConnection *gc, const char *name)
-{
-	struct name_data *data;
-
-	data = g_new0(struct name_data, 1);
-	data->gc = gc;
-	data->name = g_strdup(name);
-
-	purple_request_input(data->gc, NULL, _("Authorization Request Message:"),
-					   NULL, _("Please authorize me!"), TRUE, FALSE, NULL,
-					   _("_OK"), G_CALLBACK(purple_auth_request),
-					   _("_Cancel"), G_CALLBACK(oscar_free_name_data),
-					   purple_connection_get_account(gc), name, NULL,
-					   data);
-}
-
-static void
-purple_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored)
-{
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-
-	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *) node;
-	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 */
-static void
-purple_auth_grant(gpointer cbdata)
-{
-	struct name_data *data = cbdata;
-	PurpleConnection *gc = data->gc;
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	aim_ssi_sendauthreply(od, data->name, 0x01, NULL);
-
-	oscar_free_name_data(data);
-}
-
-/* When other people ask you for authorization */
-static void
-purple_auth_dontgrant(struct name_data *data, char *msg)
-{
-	PurpleConnection *gc = data->gc;
-	OscarData *od = purple_connection_get_protocol_data(gc);
-
-	aim_ssi_sendauthreply(od, data->name, 0x00, msg ? msg : _("No reason given."));
-}
-
-static void
-purple_auth_dontgrant_msgprompt(gpointer cbdata)
-{
-	struct name_data *data = cbdata;
-	purple_request_input(data->gc, NULL, _("Authorization Denied Message:"),
-					   NULL, _("No reason given."), TRUE, FALSE, NULL,
-					   _("_OK"), G_CALLBACK(purple_auth_dontgrant),
-					   _("_Cancel"), G_CALLBACK(oscar_free_name_data),
-					   purple_connection_get_account(data->gc), data->name, NULL,
-					   data);
-}
-
 /* When someone sends you buddies */
 static void
 purple_icq_buddyadd(struct name_data *data)
@@ -2842,7 +1820,7 @@
 
 		purple_str_strip_char(msg1[i], '\r');
 		/* TODO: Should use an encoding other than ASCII? */
-		msg2[i] = purple_plugin_oscar_decode_im_part(account, uin, AIM_CHARSET_ASCII, 0x0000, msg1[i], strlen(msg1[i]));
+		msg2[i] = oscar_decode_im(account, uin, AIM_CHARSET_ASCII, msg1[i], strlen(msg1[i]));
 		g_free(uin);
 	}
 	msg2[i] = NULL;
@@ -2895,24 +1873,17 @@
 
 		case 0x06: { /* Someone requested authorization */
 			if (i >= 6) {
-				struct name_data *data = g_new(struct name_data, 1);
 				gchar *bn = g_strdup_printf("%u", args->uin);
 				gchar *reason = NULL;
 
 				if (msg2[5] != NULL)
-					reason = purple_plugin_oscar_decode_im_part(account, bn, AIM_CHARSET_LATIN_1, 0x0000, msg2[5], strlen(msg2[5]));
+					reason = oscar_decode_im(account, bn, AIM_CHARSET_LATIN_1, msg2[5], strlen(msg2[5]));
 
 				purple_debug_info("oscar",
 						   "Received an authorization request from UIN %u\n",
 						   args->uin);
-				data->gc = gc;
-				data->name = bn;
-				data->nick = NULL;
-
-				purple_account_request_authorization(account, bn, NULL, NULL,
-						reason, purple_find_buddy(account, bn) != NULL,
-						purple_auth_grant,
-						purple_auth_dontgrant_msgprompt, data);
+				aim_icq_getalias(od, bn, TRUE, reason);
+				g_free(bn);
 				g_free(reason);
 			}
 		} break;
@@ -3376,105 +2347,6 @@
 	return 1;
 }
 
-/*
- * We get this error when there was an error in the locate family.  This
- * happens when you request info of someone who is offline.
- */
-static int purple_parse_locerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	gchar *buf;
-	va_list ap;
-	guint16 reason;
-	char *destn;
-	PurpleNotifyUserInfo *user_info;
-
-	va_start(ap, fr);
-	reason = (guint16) va_arg(ap, unsigned int);
-	destn = va_arg(ap, char *);
-	va_end(ap);
-
-	if (destn == NULL)
-		return 1;
-
-	user_info = purple_notify_user_info_new();
-	buf = g_strdup_printf(_("User information not available: %s"), oscar_get_msgerr_reason(reason));
-	purple_notify_user_info_add_pair(user_info, NULL, buf);
-	purple_notify_userinfo(od->gc, destn, user_info, NULL, NULL);
-	purple_notify_user_info_destroy(user_info);
-	purple_conv_present_error(destn, purple_connection_get_account(od->gc), buf);
-	g_free(buf);
-
-	return 1;
-}
-
-static int purple_parse_userinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleNotifyUserInfo *user_info;
-	gchar *tmp = NULL, *info_utf8 = NULL, *base_profile_url = NULL;
-	va_list ap;
-	aim_userinfo_t *userinfo;
-
-	va_start(ap, fr);
-	userinfo = va_arg(ap, aim_userinfo_t *);
-	va_end(ap);
-
-	user_info = purple_notify_user_info_new();
-
-	oscar_user_info_append_status(gc, user_info, /* PurpleBuddy */ NULL, userinfo, /* strip_html_tags */ FALSE);
-
-	if ((userinfo->present & AIM_USERINFO_PRESENT_IDLE) && userinfo->idletime != 0) {
-		tmp = purple_str_seconds_to_string(userinfo->idletime*60);
-		oscar_user_info_add_pair(user_info, _("Idle"), tmp);
-		g_free(tmp);
-	}
-
-	oscar_user_info_append_extra_info(gc, user_info, NULL, userinfo);
-
-	if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !oscar_util_valid_name_sms(userinfo->bn)) {
-		/* An SMS contact is always online; its Online Since value is not useful */
-		time_t t = userinfo->onlinesince;
-		oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t)));
-	}
-
-	if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) {
-		time_t t = userinfo->membersince;
-		oscar_user_info_add_pair(user_info, _("Member Since"), purple_date_format_full(localtime(&t)));
-	}
-
-	if (userinfo->capabilities != 0) {
-		tmp = oscar_caps_to_string(userinfo->capabilities);
-		oscar_user_info_add_pair(user_info, _("Capabilities"), tmp);
-		g_free(tmp);
-	}
-
-	/* Info */
-	if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) {
-		tmp = oscar_encoding_extract(userinfo->info_encoding);
-		info_utf8 = oscar_encoding_to_utf8(account, tmp, userinfo->info,
-		                                   userinfo->info_len);
-		g_free(tmp);
-		if (info_utf8 != NULL) {
-			tmp = purple_str_sub_away_formatters(info_utf8, purple_account_get_username(account));
-			purple_notify_user_info_add_section_break(user_info);
-			oscar_user_info_add_pair(user_info, _("Profile"), tmp);
-			g_free(tmp);
-			g_free(info_utf8);
-		}
-	}
-
-	purple_notify_user_info_add_section_break(user_info);
-	base_profile_url = oscar_util_valid_name_icq(userinfo->bn) ? "http://www.icq.com/people" : "http://profiles.aim.com";
-	tmp = g_strdup_printf("<a href=\"%s/%s\">%s</a>",
-			base_profile_url, 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->bn, user_info, NULL, NULL);
-	purple_notify_user_info_destroy(user_info);
-
-	return 1;
-}
-
 static int purple_parse_motd(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
 	char *msg;
@@ -3617,13 +2489,7 @@
 
 static int purple_conv_chat_info_update(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
-	aim_userinfo_t *userinfo;
-	struct aim_chat_roominfo *roominfo;
-	char *roomname;
-	int usercount;
-	char *roomdesc;
-	guint16 unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
-	guint32 creationtime;
+	guint16 maxmsglen, maxvisiblemsglen;
 	PurpleConnection *gc = od->gc;
 	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn);
 
@@ -3631,16 +2497,7 @@
 		return 1;
 
 	va_start(ap, fr);
-	roominfo = va_arg(ap, struct aim_chat_roominfo *);
-	roomname = va_arg(ap, char *);
-	usercount= va_arg(ap, int);
-	userinfo = va_arg(ap, aim_userinfo_t *);
-	roomdesc = va_arg(ap, char *);
-	unknown_c9 = (guint16)va_arg(ap, unsigned int);
-	creationtime = va_arg(ap, guint32);
 	maxmsglen = (guint16)va_arg(ap, unsigned int);
-	unknown_d2 = (guint16)va_arg(ap, unsigned int);
-	unknown_d5 = (guint16)va_arg(ap, unsigned int);
 	maxvisiblemsglen = (guint16)va_arg(ap, unsigned int);
 	va_end(ap);
 
@@ -3656,7 +2513,6 @@
 
 static int purple_conv_chat_incoming_msg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
 	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn);
 	gchar *utf8;
 	va_list ap;
@@ -3675,10 +2531,7 @@
 	charset = va_arg(ap, char *);
 	va_end(ap);
 
-	utf8 = oscar_encoding_to_utf8(account, charset, msg, len);
-	if (utf8 == NULL)
-		/* The conversion failed! */
-		utf8 = g_strdup(_("[Unable to display a message from this user because it contained invalid characters.]"));
+	utf8 = oscar_encoding_to_utf8(charset, msg, len);
 	serv_got_chat_in(gc, ccon->id, info->bn, 0, utf8, time(NULL));
 	g_free(utf8);
 
@@ -3796,41 +2649,6 @@
 	purple_debug_misc("oscar", "no more icons to request\n");
 }
 
-/*
- * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
- */
-static int purple_parse_msgack(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	guint16 type;
-	char *bn;
-
-	va_start(ap, fr);
-	type = (guint16) va_arg(ap, unsigned int);
-	bn = va_arg(ap, char *);
-	va_end(ap);
-
-	purple_debug_info("oscar", "Sent message to %s.\n", bn);
-
-	return 1;
-}
-
-static int purple_parse_evilnotify(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-#ifdef CRAZY_WARNING
-	va_list ap;
-	guint16 newevil;
-	aim_userinfo_t *userinfo;
-
-	va_start(ap, fr);
-	newevil = (guint16) va_arg(ap, unsigned int);
-	userinfo = va_arg(ap, aim_userinfo_t *);
-	va_end(ap);
-
-	purple_prpl_got_account_warning_level(account, (userinfo && userinfo->bn) ? userinfo->bn : NULL, (newevil/10.0) + 0.5);
-#endif
-
-	return 1;
-}
-
 static int purple_selfinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	int warning_level;
 	va_list ap;
@@ -3851,10 +2669,6 @@
 	 */
 	warning_level = info->warnlevel/10.0 + 0.5;
 
-#ifdef CRAZY_WARNING
-	purple_presence_set_warning_level(presence, warning_level);
-#endif
-
 	return 1;
 }
 
@@ -3993,16 +2807,14 @@
 	tmp = purple_markup_strip_html(message);
 	itmsurl = purple_status_get_attr_string(status, "itmsurl");
 	aim_srv_setextrainfo(od, FALSE, 0, is_available, tmp, itmsurl);
+	aim_srv_set_dc_info(od);
 	g_free(tmp);
 
 	presence = purple_status_get_presence(status);
 	aim_srv_setidle(od, !purple_presence_is_idle(presence) ? 0 : time(NULL) - purple_presence_get_idle_time(presence));
 
 	if (od->icq) {
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-		aim_icq_reqofflinemsgs(od);
-#endif
-		oscar_set_extendedstatus(gc);
+		oscar_set_extended_status(gc);
 		aim_icq_setsecurity(od,
 			purple_account_get_bool(account, "authorization", OSCAR_DEFAULT_AUTHORIZATION),
 			purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE));
@@ -4034,206 +2846,6 @@
 	return 1;
 }
 
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-static int purple_offlinemsg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-	va_list ap;
-	struct aim_icq_offlinemsg *msg;
-	struct aim_incomingim_ch4_args args;
-	time_t t;
-
-	va_start(ap, fr);
-	msg = va_arg(ap, struct aim_icq_offlinemsg *);
-	va_end(ap);
-
-	purple_debug_info("oscar",
-			   "Received offline message.  Converting to channel 4 ICBM...\n");
-	args.uin = msg->sender;
-	args.type = msg->type;
-	args.flags = msg->flags;
-	args.msglen = msg->msglen;
-	args.msg = msg->msg;
-	t = purple_time_build(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0);
-	incomingim_chan4(od, conn, NULL, &args, t);
-
-	return 1;
-}
-
-static int purple_offlinemsgdone(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	aim_icq_ackofflinemsgs(od);
-	return 1;
-}
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
-
-static int purple_icqinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc;
-	PurpleAccount *account;
-	PurpleBuddy *buddy;
-	struct buddyinfo *bi;
-	gchar who[16];
-	PurpleNotifyUserInfo *user_info;
-	gchar *utf8;
-	gchar *buf;
-	const gchar *alias;
-	va_list ap;
-	struct aim_icq_info *info;
-
-	gc = od->gc;
-	account = purple_connection_get_account(gc);
-
-	va_start(ap, fr);
-	info = va_arg(ap, struct aim_icq_info *);
-	va_end(ap);
-
-	if (!info->uin)
-		return 0;
-
-	user_info = purple_notify_user_info_new();
-
-	g_snprintf(who, sizeof(who), "%u", info->uin);
-	buddy = purple_find_buddy(account, who);
-	if (buddy != NULL)
-		bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, purple_buddy_get_name(buddy)));
-	else
-		bi = NULL;
-
-	purple_notify_user_info_add_pair(user_info, _("UIN"), who);
-	oscar_user_info_convert_and_add(account, od, user_info, _("Nick"), info->nick);
-	if ((bi != NULL) && (bi->ipaddr != 0)) {
-		char *tstr =  g_strdup_printf("%hhu.%hhu.%hhu.%hhu",
-						(bi->ipaddr & 0xff000000) >> 24,
-						(bi->ipaddr & 0x00ff0000) >> 16,
-						(bi->ipaddr & 0x0000ff00) >> 8,
-						(bi->ipaddr & 0x000000ff));
-		purple_notify_user_info_add_pair(user_info, _("IP Address"), tstr);
-		g_free(tstr);
-	}
-	oscar_user_info_convert_and_add(account, od, user_info, _("First Name"), info->first);
-	oscar_user_info_convert_and_add(account, od, user_info, _("Last Name"), info->last);
-	if (info->email && info->email[0] && (utf8 = oscar_utf8_try_convert(account, od, 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);
-		g_free(utf8);
-	}
-	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(account, od, 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);
-				g_free(utf8);
-			}
-		}
-	}
-	oscar_user_info_convert_and_add(account, od, user_info, _("Mobile Phone"), info->mobile);
-
-	if (info->gender != 0)
-		purple_notify_user_info_add_pair(user_info, _("Gender"), (info->gender == 1 ? _("Female") : _("Male")));
-
-	if ((info->birthyear > 1900) && (info->birthmonth > 0) && (info->birthday > 0)) {
-		/* Initialize the struct properly or strftime() will crash
-		 * under some conditions (e.g. Debian sarge w/ LANG=en_HK). */
-		time_t t = time(NULL);
-		struct tm *tm = localtime(&t);
-
-		tm->tm_mday = (int)info->birthday;
-		tm->tm_mon  = (int)info->birthmonth - 1;
-		tm->tm_year = (int)info->birthyear - 1900;
-
-		/* To be 100% sure that the fields are re-normalized.
-		 * If you're sure strftime() ALWAYS does this EVERYWHERE,
-		 * feel free to remove it.  --rlaager */
-		mktime(tm);
-
-		oscar_user_info_convert_and_add(account, od, user_info, _("Birthday"), purple_date_format_short(tm));
-	}
-	if ((info->age > 0) && (info->age < 255)) {
-		char age[5];
-		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(account, od, 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);
-		g_free(utf8);
-	}
-
-	if (buddy != NULL)
-		oscar_user_info_append_status(gc, user_info, buddy, /* aim_userinfo_t */ NULL, /* strip_html_tags */ FALSE);
-
-	oscar_user_info_convert_and_add(account, od, user_info, _("Additional Information"), info->info);
-	purple_notify_user_info_add_section_break(user_info);
-
-	if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) {
-		purple_notify_user_info_add_section_header(user_info, _("Home Address"));
-
-		oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->homeaddr);
-		oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->homecity);
-		oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->homestate);
-		oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->homezip);
-	}
-	if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) {
-		purple_notify_user_info_add_section_header(user_info, _("Work Address"));
-
-		oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->workaddr);
-		oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->workcity);
-		oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->workstate);
-		oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->workzip);
-	}
-	if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) {
-		purple_notify_user_info_add_section_header(user_info, _("Work Information"));
-
-		oscar_user_info_convert_and_add(account, od, user_info, _("Company"), info->workcompany);
-		oscar_user_info_convert_and_add(account, od, user_info, _("Division"), info->workdivision);
-		oscar_user_info_convert_and_add(account, od, user_info, _("Position"), info->workposition);
-
-		if (info->workwebpage && info->workwebpage[0] && (utf8 = oscar_utf8_try_convert(account, od, 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);
-			g_free(utf8);
-		}
-	}
-
-	if (buddy != NULL)
-		alias = purple_buddy_get_alias(buddy);
-	else
-		alias = who;
-	purple_notify_userinfo(gc, who, user_info, NULL, NULL);
-	purple_notify_user_info_destroy(user_info);
-
-	return 1;
-}
-
-static int purple_icqalias(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
-	PurpleConnection *gc = od->gc;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	gchar who[16], *utf8;
-	PurpleBuddy *b;
-	va_list ap;
-	struct aim_icq_info *info;
-
-	va_start(ap, fr);
-	info = va_arg(ap, struct aim_icq_info *);
-	va_end(ap);
-
-	if (info->uin && info->nick && info->nick[0] && (utf8 = oscar_utf8_try_convert(account, od, info->nick))) {
-		g_snprintf(who, sizeof(who), "%u", info->uin);
-		serv_got_alias(gc, who, utf8);
-		if ((b = purple_find_buddy(account, who))) {
-			purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8);
-		}
-		g_free(utf8);
-	}
-
-	return 1;
-}
-
 static int purple_popup(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
 	PurpleConnection *gc = od->gc;
@@ -4458,8 +3070,8 @@
 	GString *msg;
 	GString *data;
 	gchar *tmp;
-	int tmplen;
-	guint16 charset, charsubset;
+	gsize tmplen;
+	guint16 charset;
 	GData *attribs;
 	const char *start, *end, *last;
 	int oscar_id = 0;
@@ -4520,8 +3132,7 @@
 	g_string_append(msg, "</BODY></HTML>");
 
 	/* Convert the message to a good encoding */
-	purple_plugin_oscar_convert_to_best_encoding(conn->od->gc,
-			conn->bn, msg->str, &tmp, &tmplen, &charset, &charsubset);
+	tmp = oscar_encode_im(msg->str, &tmplen, &charset, NULL);
 	g_string_free(msg, TRUE);
 	msg = g_string_new_len(tmp, tmplen);
 	g_free(tmp);
@@ -4568,7 +3179,7 @@
 	}
 
 	if (imflags & PURPLE_MESSAGE_AUTO_RESP)
-		tmp1 = purple_str_sub_away_formatters(message, name);
+		tmp1 = oscar_util_format_string(message, name);
 	else
 		tmp1 = g_strdup(message);
 
@@ -4601,7 +3212,7 @@
 			g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, name)), bi);
 		}
 
-		args.flags = AIM_IMFLAGS_ACK | AIM_IMFLAGS_CUSTOMFEATURES;
+		args.flags = 0;
 
 		if (!is_sms && (!buddy || !PURPLE_BUDDY_IS_ONLINE(buddy)))
 			args.flags |= AIM_IMFLAGS_OFFLINE;
@@ -4670,7 +3281,7 @@
 		g_free(tmp1);
 		tmp1 = tmp2;
 
-		purple_plugin_oscar_convert_to_best_encoding(gc, name, tmp1, (char **)&args.msg, &args.msglen, &args.charset, &args.charsubset);
+		args.msg = oscar_encode_im(tmp1, &args.msglen, &args.charset, NULL);
 		if (is_html && (args.msglen > MAXMSGLEN)) {
 			/* If the length was too long, try stripping the HTML and then running it back through
 			* purple_strdup_withhtml() and the encoding process. The result may be shorter. */
@@ -4687,14 +3298,12 @@
 			g_free(tmp1);
 			tmp1 = tmp2;
 
-			purple_plugin_oscar_convert_to_best_encoding(gc, name, tmp1, (char **)&args.msg, &args.msglen, &args.charset, &args.charsubset);
-
+			args.msg = oscar_encode_im(tmp1, &args.msglen, &args.charset, NULL);
 			purple_debug_info("oscar", "Sending %s as %s because the original was too long.\n",
 								  message, (char *)args.msg);
 		}
 
-		purple_debug_info("oscar", "Sending IM, charset=0x%04hx, charsubset=0x%04hx, length=%d\n",
-						args.charset, args.charsubset, args.msglen);
+		purple_debug_info("oscar", "Sending IM, charset=0x%04hx, length=%" G_GSIZE_FORMAT "\n", args.charset, args.msglen);
 		ret = aim_im_sendch1_ext(od, &args);
 		g_free((char *)args.msg);
 	}
@@ -4721,43 +3330,11 @@
 		aim_locate_getinfoshort(od, name, 0x00000003);
 }
 
-#if 0
-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 = 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 = purple_connection_get_protocol_data(gc);
 	aim_srv_setidle(od, time);
 }
 
-static
-gchar *purple_prpl_oscar_convert_to_infotext(const gchar *str, gsize *ret_len, char **encoding)
-{
-	int charset = 0;
-	char *encoded = NULL;
-
-	charset = oscar_charset_check(str);
-	if (charset == AIM_CHARSET_UNICODE) {
-		encoded = g_convert(str, -1, "UTF-16BE", "UTF-8", NULL, ret_len, NULL);
-		*encoding = "unicode-2-0";
-	} else if (charset == AIM_CHARSET_LATIN_1) {
-		encoded = g_convert(str, -1, "ISO-8859-1", "UTF-8", NULL, ret_len, NULL);
-		*encoding = "iso-8859-1";
-	} else {
-		encoded = g_strdup(str);
-		*ret_len = strlen(str);
-		*encoding = "us-ascii";
-	}
-
-	return encoded;
-}
-
 void
 oscar_set_info(PurpleConnection *gc, const char *rawinfo)
 {
@@ -4769,8 +3346,8 @@
 	oscar_set_info_and_status(account, TRUE, rawinfo, FALSE, status);
 }
 
-static void
-oscar_set_extendedstatus(PurpleConnection *gc)
+static guint32
+oscar_get_extended_status(PurpleConnection *gc)
 {
 	OscarData *od;
 	PurpleAccount *account;
@@ -4814,7 +3391,13 @@
 	else if (!strcmp(status_id, OSCAR_STATUS_ID_CUSTOM))
 		data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY;
 
-	aim_srv_setextrainfo(od, TRUE, data, FALSE, NULL, NULL);
+	return data;
+}
+
+static void
+oscar_set_extended_status(PurpleConnection *gc)
+{
+	aim_srv_setextrainfo(purple_connection_get_protocol_data(gc), TRUE, oscar_get_extended_status(gc), FALSE, NULL, NULL);
 }
 
 static void
@@ -4855,7 +3438,7 @@
 	else if (rawinfo != NULL)
 	{
 		char *htmlinfo = purple_strdup_withhtml(rawinfo);
-		info = purple_prpl_oscar_convert_to_infotext(htmlinfo, &infolen, &info_encoding);
+		info = oscar_encode_im(htmlinfo, &infolen, NULL, &info_encoding);
 		g_free(htmlinfo);
 
 		if (infolen > od->rights.maxsiglen)
@@ -4888,7 +3471,7 @@
 
 			/* We do this for icq too so that they work for old third party clients */
 			linkified = purple_markup_linkify(status_html);
-			away = purple_prpl_oscar_convert_to_infotext(linkified, &awaylen, &away_encoding);
+			away = oscar_encode_im(linkified, &awaylen, NULL, &away_encoding);
 			g_free(linkified);
 
 			if (awaylen > od->rights.maxawaymsglen)
@@ -4917,8 +3500,6 @@
 		const char *status_html;
 
 		status_html = purple_status_get_attr_string(status, "message");
-		if (od->icq && (status_html == NULL || status_html[0] == '\0'))
-			status_html = purple_status_type_get_name(status_type);
 		if (status_html != NULL)
 		{
 			status_text = purple_markup_strip_html(status_html);
@@ -4931,28 +3512,27 @@
 		}
 
 		itmsurl = purple_status_get_attr_string(status, "itmsurl");
-
-		/* TODO: Combine these two calls! */
-		aim_srv_setextrainfo(od, FALSE, 0, TRUE, status_text, itmsurl);
-		oscar_set_extendedstatus(gc);
+		
+		aim_srv_setextrainfo(od, TRUE, oscar_get_extended_status(gc), TRUE, status_text, itmsurl);
 		g_free(status_text);
 	}
 }
 
 static void
-oscar_set_status_icq(PurpleAccount *account)
+oscar_set_icq_permdeny(PurpleAccount *account)
 {
 	PurpleConnection *gc = purple_account_get_connection(account);
-
-	/* Our permit/deny setting affects our invisibility */
-	oscar_set_permit_deny(gc);
+	OscarData *od = purple_connection_get_protocol_data(gc);
+	gboolean invisible = purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE);
 
 	/*
-	 * TODO: I guess we should probably wait and do this after we get
-	 * confirmation from the above SSI call?  Right now other people
-	 * see our status blip to "invisible" before we appear offline.
+	 * For ICQ the permit/deny setting controls who can see you
+	 * online. Mimicking the official client's behavior, we use PURPLE_PRIVACY_ALLOW_USERS
+	 * when our status is "invisible" and PURPLE_PRIVACY_DENY_USERS otherwise.
+	 * In the former case, we are visible only to buddies on our "permanently visible" list.
+	 * In the latter, we are invisible only to buddies on our "permanently invisible" list.
 	 */
-	oscar_set_extendedstatus(gc);
+	aim_ssi_setpermdeny(od, invisible ? PURPLE_PRIVACY_ALLOW_USERS : PURPLE_PRIVACY_DENY_USERS);
 }
 
 void
@@ -4978,22 +3558,15 @@
 		return;
 	}
 
+	if (od->icq) {
+		/* Set visibility */
+		oscar_set_icq_permdeny(account);
+	}
+
 	/* Set the AIM-style away message for both AIM and ICQ accounts */
 	oscar_set_info_and_status(account, FALSE, NULL, TRUE, status);
-
-	/* Set the ICQ status for ICQ accounts only */
-	if (od->icq)
-		oscar_set_status_icq(account);
 }
 
-#ifdef CRAZY_WARN
-void
-oscar_warn(PurpleConnection *gc, const char *name, gboolean anonymous) {
-	OscarData *od = purple_connection_get_protocol_data(gc);
-	aim_im_warn(od, od->conn, name, anonymous ? AIM_WARN_ANON : 0);
-}
-#endif
-
 void
 oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
 	OscarData *od;
@@ -5035,13 +3608,13 @@
 		                                  aim_ssi_itemlist_findparentname(od->ssi.local, bname),
 		                                  bname)) {
 			/* Not authorized -- Re-request authorization */
-			purple_auth_sendrequest(gc, bname);
+			oscar_auth_sendrequest(gc, bname);
 		}
 	}
 
 	/* XXX - Should this be done from AIM accounts, as well? */
 	if (od->icq)
-		aim_icq_getalias(od, bname);
+		aim_icq_getalias(od, bname, FALSE, NULL);
 }
 
 void oscar_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
@@ -5151,8 +3724,6 @@
 		return 1;
 	}
 
-	oscar_set_status_icq(purple_connection_get_account(gc));
-
 	return 1;
 }
 
@@ -5193,12 +3764,14 @@
 	PurpleAccount *account;
 	PurpleGroup *g;
 	PurpleBuddy *b;
+	GSList *cur, *next, *buddies;
 	struct aim_ssi_item *curitem;
 	guint32 tmp;
 	PurpleStoredImage *img;
 	va_list ap;
 	guint16 fmtver, numitems;
 	guint32 timestamp;
+	guint16 deny_entry_type = aim_ssi_getdenyentrytype(od);
 
 	gc = od->gc;
 	od = purple_connection_get_protocol_data(gc);
@@ -5211,110 +3784,109 @@
 	va_end(ap);
 
 	/* Don't attempt to re-request our buddy list later */
-	if (od->getblisttimer != 0)
+	if (od->getblisttimer != 0) {
 		purple_timeout_remove(od->getblisttimer);
-	od->getblisttimer = 0;
-
-	purple_debug_info("oscar",
-			   "ssi: syncing local list and server list\n");
+		od->getblisttimer = 0;
+	}
+
+	purple_debug_info("oscar", "ssi: syncing local list and server list\n");
 
 	/* Clean the buddy list */
 	aim_ssi_cleanlist(od);
 
-	{ /* If not in server list then prune from local list */
-		GSList *cur, *next;
-		GSList *buddies = purple_find_buddies(account, NULL);
-
-		/* Buddies */
-		cur = NULL;
-
-		while(buddies) {
-			PurpleGroup *g;
-			const char *gname;
-			const char *bname;
-
-			b = buddies->data;
-			g = purple_buddy_get_group(b);
-			gname = purple_group_get_name(g);
-			bname = purple_buddy_get_name(b);
-
-			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, bname, servernick);
-
-				/* Store local alias on server */
-				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 {
+	/*** Begin code for pruning buddies from local list if they're not in server list ***/
+
+	/* Buddies */
+	cur = NULL;
+	for (buddies = purple_find_buddies(account, NULL);
+			buddies;
+			buddies = g_slist_delete_link(buddies, buddies))
+	{
+		PurpleGroup *g;
+		const char *gname;
+		const char *bname;
+
+		b = buddies->data;
+		g = purple_buddy_get_group(b);
+		gname = purple_group_get_name(g);
+		bname = purple_buddy_get_name(b);
+
+		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, bname, servernick);
+
+			/* Store local alias on server */
+			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", bname);
+			/* Queue the buddy for removal from the local list */
+			cur = g_slist_prepend(cur, b);
+		}
+	}
+	while (cur != NULL) {
+		purple_blist_remove_buddy(cur->data);
+		cur = g_slist_delete_link(cur, cur);
+	}
+
+	/* Permit list (ICQ doesn't have one) */
+	if (!od->icq) {
+		next = account->permit;
+		while (next != NULL) {
+			cur = next;
+			next = next->next;
+			if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
 				purple_debug_info("oscar",
-						"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);
-			}
-			buddies = g_slist_delete_link(buddies, buddies);
-		}
-
-		while (cur != NULL) {
-			b = cur->data;
-			cur = g_slist_remove(cur, b);
-			purple_blist_remove_buddy(b);
-		}
-
-		/* Permit list */
-		if (account->permit) {
-			next = account->permit;
-			while (next != NULL) {
-				cur = next;
-				next = next->next;
-				if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
-					purple_debug_info("oscar",
-							"ssi: removing permit %s from local list\n", (const char *)cur->data);
-					purple_privacy_permit_remove(account, cur->data, TRUE);
-				}
+						"ssi: removing permit %s from local list\n", (const char *)cur->data);
+				purple_privacy_permit_remove(account, cur->data, TRUE);
 			}
 		}
-
-		/* Deny list */
-		if (account->deny) {
-			next = account->deny;
-			while (next != NULL) {
-				cur = next;
-				next = next->next;
-				if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_DENY)) {
-					purple_debug_info("oscar",
-							"ssi: removing deny %s from local list\n", (const char *)cur->data);
-					purple_privacy_deny_remove(account, cur->data, TRUE);
-				}
-			}
+	}
+
+	/* Deny list */
+	next = account->deny;
+	while (next != NULL) {
+		cur = next;
+		next = next->next;
+		if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, deny_entry_type)) {
+			purple_debug_info("oscar",
+					"ssi: removing deny %s from local list\n", (const char *)cur->data);
+			purple_privacy_deny_remove(account, cur->data, TRUE);
 		}
-		/* Presence settings (idle time visibility) */
-		tmp = aim_ssi_getpresence(od->ssi.local);
-		if (tmp != 0xFFFFFFFF) {
-			const char *idle_reporting_pref;
-			gboolean report_idle;
-
-			idle_reporting_pref = purple_prefs_get_string("/purple/away/idle_reporting");
-			report_idle = strcmp(idle_reporting_pref, "none") != 0;
-
-			if (report_idle)
-				aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
-			else
-				aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
-		}
-
-
-	} /* end pruning buddies from local list */
-
-	/* Add from server list to local list */
+	}
+
+	/* Presence settings (idle time visibility) */
+	tmp = aim_ssi_getpresence(od->ssi.local);
+	if (tmp != 0xFFFFFFFF) {
+		const char *idle_reporting_pref;
+		gboolean report_idle;
+
+		idle_reporting_pref = purple_prefs_get_string("/purple/away/idle_reporting");
+		report_idle = strcmp(idle_reporting_pref, "none") != 0;
+
+		if (report_idle)
+			aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
+		else
+			aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
+	}
+
+	/*** End code for pruning buddies from local list ***/
+
+	/*** Begin code for adding from server list to local list ***/
+
 	for (curitem=od->ssi.local; curitem; curitem=curitem->next) {
-	  if ((curitem->name == NULL) || (g_utf8_validate(curitem->name, -1, NULL)))
+		if (curitem->name && !g_utf8_validate(curitem->name, -1, NULL))
+			/* Got node with invalid UTF-8 in the name.  Skip it. */
+			break;
+
 		switch (curitem->type) {
 			case AIM_SSI_TYPE_BUDDY: { /* Buddy */
 				if (curitem->name) {
@@ -5323,13 +3895,7 @@
 
 					groupitem = aim_ssi_itemlist_find(od->ssi.local, curitem->gid, 0x0000);
 					gname = groupitem ? groupitem->name : NULL;
-					if (gname != NULL) {
-						if (g_utf8_validate(gname, -1, NULL))
-							gname_utf8 = g_strdup(gname);
-						else
-							gname_utf8 = oscar_utf8_try_convert(account, od, gname);
-					} else
-						gname_utf8 = NULL;
+					gname_utf8 = oscar_utf8_try_convert(account, od, gname);
 
 					g = purple_find_group(gname_utf8 ? gname_utf8 : _("Orphans"));
 					if (g == NULL) {
@@ -5338,14 +3904,7 @@
 					}
 
 					alias = aim_ssi_getalias(od->ssi.local, gname, curitem->name);
-					if (alias != NULL) {
-						if (g_utf8_validate(alias, -1, NULL))
-							alias_utf8 = g_strdup(alias);
-						else
-							alias_utf8 = oscar_utf8_try_convert(account, od, alias);
-						g_free(alias);
-					} else
-						alias_utf8 = NULL;
+					alias_utf8 = oscar_utf8_try_convert(account, od, alias);
 
 					b = purple_find_buddy_in_group(account, curitem->name, g);
 					if (b) {
@@ -5387,13 +3946,7 @@
 				char *gname_utf8;
 
 				gname = curitem->name;
-				if (gname != NULL) {
-					if (g_utf8_validate(gname, -1, NULL))
-						gname_utf8 = g_strdup(gname);
-					else
-						gname_utf8 = oscar_utf8_try_convert(account, od, gname);
-				} else
-					gname_utf8 = NULL;
+				gname_utf8 = oscar_utf8_try_convert(account, od, gname);
 
 				if (gname_utf8 != NULL && purple_find_group(gname_utf8) == NULL) {
 					g = purple_group_new(gname_utf8);
@@ -5402,12 +3955,10 @@
 				g_free(gname_utf8);
 			} break;
 
-			case AIM_SSI_TYPE_PERMIT: { /* Permit buddy */
-				if (curitem->name) {
-					/* if (!find_permdeny_by_name(gc->permit, curitem->name)) { AAA */
-					GSList *list;
-					for (list=account->permit; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next);
-					if (!list) {
+			case AIM_SSI_TYPE_PERMIT: { /* Permit buddy (unless we're on ICQ) */
+				if (!od->icq && curitem->name) {
+					for (cur = account->permit; (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next);
+					if (!cur) {
 						purple_debug_info("oscar",
 								   "ssi: adding permit buddy %s to local list\n", curitem->name);
 						purple_privacy_permit_add(account, curitem->name, TRUE);
@@ -5415,11 +3966,11 @@
 				}
 			} break;
 
+			case AIM_SSI_TYPE_ICQDENY:
 			case AIM_SSI_TYPE_DENY: { /* Deny buddy */
-				if (curitem->name) {
-					GSList *list;
-					for (list=account->deny; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next);
-					if (!list) {
+				if (curitem->type == deny_entry_type && curitem->name) {
+					for (cur = account->deny; (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next);
+					if (!cur) {
 						purple_debug_info("oscar",
 								   "ssi: adding deny buddy %s to local list\n", curitem->name);
 						purple_privacy_deny_add(account, curitem->name, TRUE);
@@ -5451,7 +4002,13 @@
 		} /* End of switch on curitem->type */
 	} /* End of for loop */
 
-	oscar_set_status_icq(account);
+	/*** End code for adding from server list to local list ***/
+
+	if (od->icq) {
+		oscar_set_icq_permdeny(account);
+	} else {
+		oscar_set_aim_permdeny(gc);
+	}
 
 	/* Activate SSI */
 	/* Sending the enable causes other people to be able to see you, and you to see them */
@@ -5513,7 +4070,7 @@
 
 			case 0x000e: { /* buddy requires authorization */
 				if ((retval->action == SNAC_SUBTYPE_FEEDBAG_ADD) && (retval->name))
-					purple_auth_sendrequest(gc, retval->name);
+					oscar_auth_sendrequest(gc, retval->name);
 			} break;
 
 			default: { /* La la la */
@@ -5562,15 +4119,7 @@
 	gname_utf8 = gname ? oscar_utf8_try_convert(account, od, gname) : NULL;
 
 	alias = aim_ssi_getalias(od->ssi.local, gname, name);
-	if (alias != NULL)
-	{
-		if (g_utf8_validate(alias, -1, NULL))
-			alias_utf8 = g_strdup(alias);
-		else
-			alias_utf8 = oscar_utf8_try_convert(account, od, alias);
-	}
-	else
-		alias_utf8 = NULL;
+	alias_utf8 = oscar_utf8_try_convert(account, od, alias);
 	g_free(alias);
 
 	b = purple_find_buddy(account, name);
@@ -5665,24 +4214,18 @@
 
 static int purple_ssi_authrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	PurpleConnection *gc = od->gc;
 	va_list ap;
 	const char *bn;
-	const char *msg;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	struct name_data *data;
-	PurpleBuddy *buddy;
+	char *msg;
 
 	va_start(ap, fr);
 	bn = va_arg(ap, const char *);
-	msg = va_arg(ap, const char *);
+	msg = va_arg(ap, char *);
 	va_end(ap);
 
 	purple_debug_info("oscar",
 			"ssi: received authorization request from %s\n", bn);
 
-	buddy = purple_find_buddy(account, bn);
-
 	if (!msg) {
 		purple_debug_warning("oscar", "Received auth request from %s with "
 				"empty message\n", bn);
@@ -5692,16 +4235,7 @@
 		msg = NULL;
 	}
 
-	data = g_new(struct name_data, 1);
-	data->gc = gc;
-	data->name = g_strdup(bn);
-	data->nick = (buddy ? g_strdup(purple_buddy_get_alias_only(buddy)) : NULL);
-
-	purple_account_request_authorization(account, bn, NULL,
-			(buddy ? purple_buddy_get_alias_only(buddy) : NULL),
-			msg, buddy != NULL, purple_auth_grant,
-			purple_auth_dontgrant_msgprompt, data);
-
+	aim_icq_getalias(od, bn, TRUE, msg);
 	return 1;
 }
 
@@ -5874,9 +4408,9 @@
 	PurpleConversation *conv = NULL;
 	struct chat_connection *c = NULL;
 	char *buf, *buf2, *buf3;
-	guint16 charset, charsubset;
-	char *charsetstr = NULL;
-	int len;
+	guint16 charset;
+	char *charsetstr;
+	gsize len;
 
 	if (!(conv = purple_find_chat(gc, id)))
 		return -EINVAL;
@@ -5892,7 +4426,7 @@
 			  "You cannot send IM Images in AIM chats."),
 			PURPLE_MESSAGE_ERROR, time(NULL));
 
-	purple_plugin_oscar_convert_to_best_encoding(gc, NULL, buf, &buf2, &len, &charset, &charsubset);
+	buf2 = oscar_encode_im(buf, &len, &charset, &charsetstr);
 	/*
 	 * Evan S. suggested that maxvis really does mean "number of
 	 * visible characters" and not "number of bytes"
@@ -5908,10 +4442,11 @@
 		buf = purple_strdup_withhtml(buf3);
 		g_free(buf3);
 
-		purple_plugin_oscar_convert_to_best_encoding(gc, NULL, buf, &buf2, &len, &charset, &charsubset);
+		buf2 = oscar_encode_im(buf, &len, &charset, &charsetstr);
 
 		if ((len > c->maxlen) || (len > c->maxvis)) {
-			purple_debug_warning("oscar", "Could not send %s because (%i > maxlen %i) or (%i > maxvis %i)\n",
+			purple_debug_warning("oscar",
+					"Could not send %s because (%" G_GSIZE_FORMAT " > maxlen %i) or (%" G_GSIZE_FORMAT " > maxvis %i)\n",
 					buf2, len, c->maxlen, len, c->maxvis);
 			g_free(buf);
 			g_free(buf2);
@@ -5922,12 +4457,6 @@
 				message, buf2);
 	}
 
-	if (charset == AIM_CHARSET_ASCII)
-		charsetstr = "us-ascii";
-	else if (charset == AIM_CHARSET_UNICODE)
-		charsetstr = "unicode-2-0";
-	else if (charset == AIM_CHARSET_LATIN_1)
-		charsetstr = "iso-8859-1";
 	aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "en");
 	g_free(buf2);
 	g_free(buf);
@@ -6082,7 +4611,7 @@
 			tmp1 = purple_markup_strip_html(message);
 			purple_util_chrreplace(tmp1, '\n', ' ');
 			tmp2 = g_markup_escape_text(tmp1, -1);
-			ret = purple_str_sub_away_formatters(tmp2, purple_account_get_username(account));
+			ret = oscar_util_format_string(tmp2, purple_account_get_username(account));
 			g_free(tmp1);
 			g_free(tmp2);
 		}
@@ -6099,67 +4628,40 @@
 	return ret;
 }
 
-void oscar_set_permit_deny(PurpleConnection *gc) {
+void oscar_set_aim_permdeny(PurpleConnection *gc) {
 	PurpleAccount *account = purple_connection_get_account(gc);
 	OscarData *od = purple_connection_get_protocol_data(gc);
-	PurplePrivacyType perm_deny;
 
 	/*
-	 * For ICQ the permit/deny setting controls who you can see you
-	 * online when you set your status to "invisible."  If we're ICQ
-	 * and we're invisible then we need to use one of
-	 * PURPLE_PRIVACY_ALLOW_USERS or PURPLE_PRIVACY_ALLOW_BUDDYLIST or
-	 * PURPLE_PRIVACY_DENY_USERS if we actually want to be invisible
-	 * to anyone.
-	 *
-	 * These three permit/deny settings correspond to:
-	 * 1. Invisible to everyone except the people on my "permit" list
-	 * 2. Invisible to everyone except the people on my buddy list
-	 * 3. Invisible only to the people on my "deny" list
-	 *
-	 * It would be nice to allow cases 2 and 3, but our UI doesn't have
-	 * a nice way to do it.  For now we just force case 1.
+	 * Conveniently there is a one-to-one mapping between the
+	 * values of libpurple's PurplePrivacyType and the values used
+	 * by the oscar protocol.
 	 */
-	if (od->icq && purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE))
-		perm_deny = PURPLE_PRIVACY_ALLOW_USERS;
-	else
-		perm_deny = account->perm_deny;
-
-	if (od->ssi.received_data)
-		/*
-		 * Conveniently there is a one-to-one mapping between the
-		 * values of libpurple's PurplePrivacyType and the values used
-		 * by the oscar protocol.
-		 */
-		aim_ssi_setpermdeny(od, perm_deny, 0xffffffff);
+	aim_ssi_setpermdeny(od, account->perm_deny);
 }
 
 void oscar_add_permit(PurpleConnection *gc, const char *who) {
 	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);
+	aim_ssi_add_to_private_list(od, who, AIM_SSI_TYPE_PERMIT);
 }
 
 void oscar_add_deny(PurpleConnection *gc, const char *who) {
 	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);
+	aim_ssi_add_to_private_list(od, who, aim_ssi_getdenyentrytype(od));
 }
 
 void oscar_rem_permit(PurpleConnection *gc, const char *who) {
 	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);
+	aim_ssi_del_from_private_list(od, who, AIM_SSI_TYPE_PERMIT);
 }
 
 void oscar_rem_deny(PurpleConnection *gc, const char *who) {
 	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);
+	aim_ssi_del_from_private_list(od, who, aim_ssi_getdenyentrytype(od));
 }
 
 GList *
@@ -6491,7 +4993,6 @@
 
 static GList *
 oscar_buddy_menu(PurpleBuddy *buddy) {
-
 	PurpleConnection *gc;
 	OscarData *od;
 	GList *menu;
@@ -6529,6 +5030,7 @@
 		                           PURPLE_CALLBACK(oscar_get_icqxstatusmsg),
 		                           NULL, NULL);
 		menu = g_list_prepend(menu, act);
+		menu = g_list_prepend(menu, create_visibility_menu_item(od, bname));
 	}
 
 	if (userinfo &&
@@ -6554,15 +5056,6 @@
 			}
 			menu = g_list_prepend(menu, act);
 		}
-#if 0
-		/* TODO: This menu item should be added by the core */
-		if (userinfo->capabilities & OSCAR_CAPABILITY_GETFILE) {
-			act = purple_menu_action_new(_("Get File"),
-			                           PURPLE_CALLBACK(oscar_ask_getfile),
-			                           NULL, NULL);
-			menu = g_list_prepend(menu, act);
-		}
-#endif
 	}
 
 	if (od->ssi.received_data && purple_buddy_get_group(buddy) != NULL)
@@ -6576,7 +5069,7 @@
 		if (gname && aim_ssi_waitingforauth(od->ssi.local, gname, bname))
 		{
 			act = purple_menu_action_new(_("Re-request Authorization"),
-			                           PURPLE_CALLBACK(purple_auth_sendrequest_menu),
+			                           PURPLE_CALLBACK(oscar_auth_sendrequest_menu),
 			                           NULL, NULL);
 			menu = g_list_prepend(menu, act);
 		}
@@ -6613,7 +5106,7 @@
 	purple_account_set_bool(account, "authorization", auth);
 	purple_account_set_bool(account, "web_aware", web_aware);
 
-	oscar_set_extendedstatus(gc);
+	oscar_set_extended_status(gc);
 	aim_icq_setsecurity(od, auth, web_aware);
 }
 
@@ -6728,41 +5221,29 @@
 {
 	PurpleConnection *gc = (PurpleConnection *) action->context;
 	OscarData *od = purple_connection_get_protocol_data(gc);
-	gchar *text, *tmp;
-	GSList *buddies;
-	PurpleAccount *account;
-	int num=0;
-
-	text = g_strdup("");
-	account = purple_connection_get_account(gc);
+	PurpleAccount *account = purple_connection_get_account(gc);
+	GSList *buddies, *filtered_buddies, *cur;
+	gchar *text;
 
 	buddies = purple_find_buddies(account, NULL);
-	while (buddies) {
+	filtered_buddies = NULL;
+	for (cur = buddies; cur != NULL; cur = cur->next) {
 		PurpleBuddy *buddy;
 		const gchar *bname, *gname;
 
-		buddy = buddies->data;
+		buddy = cur->data;
 		bname = purple_buddy_get_name(buddy);
 		gname = purple_group_get_name(purple_buddy_get_group(buddy));
 		if (aim_ssi_waitingforauth(od->ssi.local, gname, bname)) {
-			const gchar *alias = purple_buddy_get_alias_only(buddy);
-			if (alias)
-				tmp = g_strdup_printf("%s %s (%s)<br>", text, bname, alias);
-			else
-				tmp = g_strdup_printf("%s %s<br>", text, bname);
-			g_free(text);
-			text = tmp;
-
-			num++;
+			filtered_buddies = g_slist_prepend(filtered_buddies, buddy);
 		}
-
-		buddies = g_slist_delete_link(buddies, buddies);
 	}
 
-	if (!num) {
-		g_free(text);
-		text = g_strdup(_("<i>you are not waiting for authorization</i>"));
-	}
+	g_slist_free(buddies);
+
+	filtered_buddies = g_slist_reverse(filtered_buddies);
+	text = oscar_format_buddies(filtered_buddies, _("you are not waiting for authorization"));
+	g_slist_free(filtered_buddies);
 
 	purple_notify_formatted(gc, NULL, _("You are awaiting authorization from "
 						  "the following buddies"),	_("You can re-request "
@@ -6977,6 +5458,12 @@
 		act = purple_plugin_action_new(_("Set Privacy Options..."),
 				oscar_show_icq_privacy_opts);
 		menu = g_list_prepend(menu, act);
+
+		act = purple_plugin_action_new("Show Visible List", oscar_show_visible_list);
+		menu = g_list_prepend(menu, act);
+
+		act = purple_plugin_action_new("Show Invisible List", oscar_show_invisible_list);
+		menu = g_list_prepend(menu, act);
 	}
 	else
 	{
@@ -7006,12 +5493,6 @@
 			oscar_show_find_email);
 	menu = g_list_prepend(menu, act);
 
-#if 0
-	act = purple_plugin_action_new(_("Search for Buddy by Information"),
-			show_find_info);
-	menu = g_list_prepend(menu, act);
-#endif
-
 	menu = g_list_reverse(menu);
 
 	return menu;
--- a/libpurple/protocols/oscar/oscar.h	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Wed Aug 25 19:12:08 2010 +0000
@@ -103,16 +103,6 @@
 #define AIM_ICONIDENT "AVT1picture.id"
 
 /*
- * Current Maximum Length for Chat Room Messages
- *
- * This is actually defined by the protocol to be
- * dynamic, but I have yet to see due cause to
- * define it dynamically here.  Maybe later.
- *
- */
-#define MAXCHATMSGLEN 512
-
-/*
  * Found by trial and error.
  */
 #define MAXAVAILMSGLEN 251
@@ -143,167 +133,6 @@
 	const char *lang; /* two-letter abbrev */
 };
 
-/* Needs to be checked */
-#define CLIENTINFO_AIM_3_5_1670 { \
-	"AOL Instant Messenger (SM), version 3.5.1670/WIN32", \
-	0x0004, \
-	0x0003, 0x0005, \
-	0x0000, 0x0686, \
-	0x0000002a, \
-	"us", "en", \
-}
-
-/* Needs to be checked */
-/* Latest winaim without ssi */
-#define CLIENTINFO_AIM_4_1_2010 { \
-	"AOL Instant Messenger (SM), version 4.1.2010/WIN32", \
-	0x0004, \
-	0x0004, 0x0001, \
-	0x0000, 0x07da, \
-	0x0000004b, \
-	"us", "en", \
-}
-
-/* Needs to be checked */
-#define CLIENTINFO_AIM_4_3_2188 { \
-	"AOL Instant Messenger (SM), version 4.3.2188/WIN32", \
-	0x0109, \
-	0x0400, 0x0003, \
-	0x0000, 0x088c, \
-	0x00000086, \
-	"us", "en", \
-}
-
-/* Needs to be checked */
-#define CLIENTINFO_AIM_4_8_2540 { \
-	"AOL Instant Messenger (SM), version 4.8.2540/WIN32", \
-	0x0109, \
-	0x0004, 0x0008, \
-	0x0000, 0x09ec, \
-	0x000000af, \
-	"us", "en", \
-}
-
-/* Needs to be checked */
-#define CLIENTINFO_AIM_5_0_2938 { \
-	"AOL Instant Messenger, version 5.0.2938/WIN32", \
-	0x0109, \
-	0x0005, 0x0000, \
-	0x0000, 0x0b7a, \
-	0x00000000, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_AIM_5_1_3036 { \
-	"AOL Instant Messenger, version 5.1.3036/WIN32", \
-	0x0109, \
-	0x0005, 0x0001, \
-	0x0000, 0x0bdc, \
-	0x000000d2, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_AIM_5_5_3415 { \
-	"AOL Instant Messenger, version 5.5.3415/WIN32", \
-	0x0109, \
-	0x0005, 0x0005, \
-	0x0000, 0x0057, \
-	0x000000ef, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_AIM_5_9_3702 { \
-	"AOL Instant Messenger, version 5.9.3702/WIN32", \
-	0x0109, \
-	0x0005, 0x0009, \
-	0x0000, 0x0e76, \
-	0x00000111, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_ICHAT_1_0 { \
-	"Apple iChat", \
-	0x311a, \
-	0x0001, 0x0000, \
-	0x0000, 0x003c, \
-	0x000000c6, \
-	"us", "en", \
-}
-
-/* Needs to be checked */
-#define CLIENTINFO_ICQ_4_65_3281 { \
-	"ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85", \
-	0x010a, \
-	0x0004, 0x0041, \
-	0x0001, 0x0cd1, \
-	0x00000055, \
-	"us", "en", \
-}
-
-/* Needs to be checked */
-#define CLIENTINFO_ICQ_5_34_3728 { \
-	"ICQ Inc. - Product of ICQ (TM).2002a.5.34.1.3728.85", \
-	0x010a, \
-	0x0005, 0x0022, \
-	0x0001, 0x0e8f, \
-	0x00000055, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_ICQ_5_45_3777 { \
-	"ICQ Inc. - Product of ICQ (TM).2003a.5.45.1.3777.85", \
-	0x010a, \
-	0x0005, 0x002d, \
-	0x0001, 0x0ec1, \
-	0x00000055, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_ICQ6_6_0_6059 { \
-	"ICQ Client", \
-	0x010a, \
-	0x0006, 0x0000, \
-	0x0000, 0x17ab, \
-	0x00007535, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_ICQBASIC_14_3_1068 { \
-	"ICQBasic", \
-	0x010a, \
-	0x0014, 0x0003, \
-	0x0000, 0x042c, \
-	0x0000043d, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_ICQBASIC_14_34_3000 { \
-	"ICQBasic", \
-	0x010a, \
-	0x0014, 0x0034, \
-	0x0000, 0x0bb8, \
-	0x0000043d, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_ICQBASIC_14_34_3096 { \
-	"ICQBasic", \
-	0x010a, \
-	0x0014, 0x0034, \
-	0x0000, 0x0c18, \
-	0x0000043d, \
-	"us", "en", \
-}
-
-#define CLIENTINFO_NETSCAPE_7_0_1 { \
-	"Netscape 2000 an approved user of AOL Instant Messenger (SM)", \
-	0x1d0d, \
-	0x0007, 0x0000, \
-	0x0001, 0x0000, \
-	0x00000058, \
-	"us", "en", \
-}
-
 /*
  * We need to use the major-minor-micro versions from the official
  * AIM and ICQ programs here or AOL won't let us use certain features.
@@ -329,9 +158,6 @@
 	"us", "en", \
 }
 
-#define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_5_1_3036
-#define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQBASIC_14_34_3096
-
 typedef enum
 {
 	OSCAR_DISCONNECT_DONE, /* not considered an error */
@@ -376,7 +202,24 @@
 #define OSCAR_CAPABILITY_NEWCAPS               0x0000000020000000LL
 #define OSCAR_CAPABILITY_XTRAZ                 0x0000000040000000LL
 #define OSCAR_CAPABILITY_GENERICUNKNOWN        0x0000000080000000LL
-#define OSCAR_CAPABILITY_LAST                  0x0000000100000000LL
+#define OSCAR_CAPABILITY_HTML_MSGS             0x0000000100000000LL
+#define OSCAR_CAPABILITY_LAST                  0x0000000200000000LL
+
+#define OSCAR_STATUS_ID_INVISIBLE   "invisible"
+#define OSCAR_STATUS_ID_OFFLINE     "offline"
+#define OSCAR_STATUS_ID_AVAILABLE   "available"
+#define OSCAR_STATUS_ID_AWAY        "away"
+#define OSCAR_STATUS_ID_DND         "dnd"
+#define OSCAR_STATUS_ID_NA          "na"
+#define OSCAR_STATUS_ID_OCCUPIED    "occupied"
+#define OSCAR_STATUS_ID_FREE4CHAT   "free4chat"
+#define OSCAR_STATUS_ID_CUSTOM      "custom"
+#define OSCAR_STATUS_ID_MOBILE	    "mobile"
+#define OSCAR_STATUS_ID_EVIL        "evil"
+#define OSCAR_STATUS_ID_DEPRESSION	 "depression"
+#define OSCAR_STATUS_ID_ATHOME      "athome"
+#define OSCAR_STATUS_ID_ATWORK      "atwork"
+#define OSCAR_STATUS_ID_LUNCH       "lunch"
 
 /*
  * Byte Stream type. Sort of.
@@ -395,8 +238,8 @@
 struct _ByteStream
 {
 	guint8 *data;
-	guint32 len;
-	guint32 offset;
+	size_t len;
+	size_t offset;
 };
 
 struct _QueuedSnac
@@ -526,7 +369,7 @@
 	 */
 
 	IcbmCookie *msgcookies;
-	struct aim_icq_info *icq_info;
+	GSList *icq_info;
 
 	/** Only used when connecting with the old-style BUCP login. */
 	struct aim_authresp_info *authinfo;
@@ -580,10 +423,8 @@
 #define AIM_ICQ_STATE_WEBAWARE          0x00010000
 #define AIM_ICQ_STATE_HIDEIP            0x00020000
 #define AIM_ICQ_STATE_BIRTHDAY          0x00080000
-#define AIM_ICQ_STATE_DIRECTDISABLED    0x00100000
 #define AIM_ICQ_STATE_ICQHOMEPAGE       0x00200000
 #define AIM_ICQ_STATE_DIRECTREQUIREAUTH 0x10000000
-#define AIM_ICQ_STATE_DIRECTCONTACTLIST 0x20000000
 
 /**
  * Only used when connecting with the old-style BUCP login.
@@ -669,8 +510,8 @@
 void flap_connection_send_version(OscarData *od, FlapConnection *conn);
 void flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy);
 void flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_login);
-void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data);
-void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority);
+void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data);
+void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data, gboolean high_priority);
 void flap_connection_send_keepalive(OscarData *od, FlapConnection *conn);
 FlapFrame *flap_frame_new(OscarData *od, guint16 channel, int datalen);
 
@@ -682,64 +523,26 @@
 void oscar_data_addhandler(OscarData *od, guint16 family, guint16 subtype, aim_rxcallback_t newhandler, guint16 flags);
 aim_rxcallback_t aim_callhandler(OscarData *od, guint16 family, guint16 subtype);
 
-/* misc.c */
-#define AIM_VISIBILITYCHANGE_PERMITADD    0x05
-#define AIM_VISIBILITYCHANGE_PERMITREMOVE 0x06
-#define AIM_VISIBILITYCHANGE_DENYADD      0x07
-#define AIM_VISIBILITYCHANGE_DENYREMOVE   0x08
-
-#define AIM_PRIVFLAGS_ALLOWIDLE           0x01
-#define AIM_PRIVFLAGS_ALLOWMEMBERSINCE    0x02
-
-#define AIM_WARN_ANON                     0x01
-
-
-
 /* 0x0001 - family_oservice.c */
 /* 0x0002 */ void aim_srv_clientready(OscarData *od, FlapConnection *conn);
 /* 0x0004 */ void aim_srv_requestnew(OscarData *od, guint16 serviceid);
 /* 0x0006 */ void aim_srv_reqrates(OscarData *od, FlapConnection *conn);
 /* 0x0008 */ void aim_srv_rates_addparam(OscarData *od, FlapConnection *conn);
-/* 0x0009 */ void aim_srv_rates_delparam(OscarData *od, FlapConnection *conn);
-/* 0x000c */ void aim_srv_sendpauseack(OscarData *od, FlapConnection *conn);
 /* 0x000e */ void aim_srv_reqpersonalinfo(OscarData *od, FlapConnection *conn);
 /* 0x0011 */ void aim_srv_setidle(OscarData *od, guint32 idletime);
-/* 0x0014 */ void aim_srv_setprivacyflags(OscarData *od, FlapConnection *conn, guint32);
-/* 0x0016 */ void aim_srv_nop(OscarData *od, FlapConnection *conn);
 /* 0x0017 */ void aim_srv_setversions(OscarData *od, FlapConnection *conn);
 /* 0x001e */ int aim_srv_setextrainfo(OscarData *od, gboolean seticqstatus, guint32 icqstatus, gboolean setstatusmsg, const char *statusmsg, const char *itmsurl);
+void aim_srv_set_dc_info(OscarData *od);
 
 
 void aim_bos_reqrights(OscarData *od, FlapConnection *conn);
-int aim_bos_changevisibility(OscarData *od, FlapConnection *conn, int, const char *);
-void aim_bos_setgroupperm(OscarData *od, FlapConnection *conn, guint32 mask);
 
-
-
-#define AIM_CLIENTTYPE_UNKNOWN  0x0000
-#define AIM_CLIENTTYPE_MC       0x0001
-#define AIM_CLIENTTYPE_WINAIM   0x0002
-#define AIM_CLIENTTYPE_WINAIM41 0x0003
-#define AIM_CLIENTTYPE_AOL_TOC  0x0004
-guint16 aim_im_fingerprint(const guint8 *msghdr, int len);
-
-#define AIM_RATE_CODE_CHANGE     0x0001
-#define AIM_RATE_CODE_WARNING    0x0002
 #define AIM_RATE_CODE_LIMIT      0x0003
-#define AIM_RATE_CODE_CLEARLIMIT 0x0004
-void aim_ads_requestads(OscarData *od, FlapConnection *conn);
-
-
 
 /* family_icbm.c */
-#define AIM_OFT_SUBTYPE_SEND_FILE	0x0001
 #define AIM_OFT_SUBTYPE_SEND_DIR	0x0002
-#define AIM_OFT_SUBTYPE_GET_FILE	0x0011
-#define AIM_OFT_SUBTYPE_GET_LIST	0x0012
 
-#define AIM_TRANSFER_DENY_NOTSUPPORTED	0x0000
 #define AIM_TRANSFER_DENY_DECLINE	0x0001
-#define AIM_TRANSFER_DENY_NOTACCEPTING	0x0002
 
 #define AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED   0x00000001
 #define AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED   0x00000002
@@ -761,26 +564,6 @@
  */
 #define AIM_IMPARAM_FLAG_USE_HTML_FOR_ICQ       0x00000400
 
-/* This is what the server will give you if you don't set them yourself. */
-/* This is probably out of date. */
-#define AIM_IMPARAM_DEFAULTS { \
-	0, \
-	AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED, \
-	512, /* !! Note how small this is. */ \
-	(99.9)*10, (99.9)*10, \
-	1000 /* !! And how large this is. */ \
-}
-
-/* This is what most AIM versions use. */
-/* This is probably out of date. */
-#define AIM_IMPARAM_REASONABLE { \
-	0, \
-	AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED, \
-	8000, \
-	(99.9)*10, (99.9)*10, \
-	0 \
-}
-
 struct aim_icbmparameters
 {
 	guint16 maxchan;
@@ -827,9 +610,6 @@
 #define AIM_IMFLAGS_HASICON				0x0020 /* already has icon */
 #define AIM_IMFLAGS_SUBENC_MACINTOSH	0x0040 /* damn that Steve Jobs! */
 #define AIM_IMFLAGS_CUSTOMFEATURES		0x0080 /* features field present */
-#define AIM_IMFLAGS_EXTDATA				0x0100
-#define AIM_IMFLAGS_X					0x0200
-#define AIM_IMFLAGS_MULTIPART			0x0400 /* ->mpmsg section valid */
 #define AIM_IMFLAGS_OFFLINE				0x0800 /* send to offline user */
 #define AIM_IMFLAGS_TYPINGNOT			0x1000 /* typing notification */
 
@@ -838,30 +618,6 @@
 #define AIM_CHARSET_LATIN_1 0x0003 /* ISO 8859-1 */
 
 /*
- * Multipart message structures.
- */
-typedef struct aim_mpmsg_section_s
-{
-	guint16 charset;
-	guint16 charsubset;
-	gchar *data;
-	guint16 datalen;
-	struct aim_mpmsg_section_s *next;
-} aim_mpmsg_section_t;
-
-typedef struct aim_mpmsg_s
-{
-	unsigned int numparts;
-	aim_mpmsg_section_t *parts;
-} aim_mpmsg_t;
-
-int aim_mpmsg_init(OscarData *od, aim_mpmsg_t *mpm);
-int aim_mpmsg_addraw(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, const gchar *data, guint16 datalen);
-int aim_mpmsg_addascii(OscarData *od, aim_mpmsg_t *mpm, const char *ascii);
-int aim_mpmsg_addunicode(OscarData *od, aim_mpmsg_t *mpm, const guint16 *unicode, guint16 unicodelen);
-void aim_mpmsg_free(OscarData *od, aim_mpmsg_t *mpm);
-
-/*
  * Arguments to aim_send_im_ext().
  *
  * This is really complicated.  But immensely versatile.
@@ -869,84 +625,39 @@
  */
 struct aim_sendimext_args
 {
-
 	/* These are _required_ */
 	const char *destbn;
 	guint32 flags; /* often 0 */
 
-	/* Only required if not using multipart messages */
 	const char *msg;
-	int msglen;
-
-	/* Required if ->msg is not provided */
-	aim_mpmsg_t *mpmsg;
+	gsize msglen;
 
 	/* Only used if AIM_IMFLAGS_HASICON is set */
 	guint32 iconlen;
 	time_t iconstamp;
 	guint32 iconsum;
 
-	/* Only used if AIM_IMFLAGS_CUSTOMFEATURES is set */
 	guint16 featureslen;
 	guint8 *features;
 
-	/* Only used if AIM_IMFLAGS_CUSTOMCHARSET is set and mpmsg not used */
 	guint16 charset;
-	guint16 charsubset;
-};
-
-/*
- * Arguments to aim_send_rtfmsg().
- */
-struct aim_sendrtfmsg_args
-{
-	const char *destbn;
-	guint32 fgcolor;
-	guint32 bgcolor;
-	const char *rtfmsg; /* must be in RTF */
 };
 
 /*
  * This information is provided in the Incoming ICBM callback for
  * Channel 1 ICBM's.
- *
- * Note that although CUSTOMFEATURES and CUSTOMCHARSET say they
- * are optional, both are always set by the current libfaim code.
- * That may or may not change in the future.  It is mainly for
- * consistency with aim_sendimext_args.
- *
- * Multipart messages require some explanation. If you want to use them,
- * I suggest you read all the comments in family_icbm.c.
- *
  */
 struct aim_incomingim_ch1_args
 {
-
-	/* Always provided */
-	aim_mpmsg_t mpmsg;
 	guint32 icbmflags; /* some flags apply only to ->msg, not all mpmsg */
 	time_t timestamp; /* Only set for offline messages */
 
-	/* Only provided if message has a human-readable section */
 	gchar *msg;
-	int msglen;
 
 	/* Only provided if AIM_IMFLAGS_HASICON is set */
 	time_t iconstamp;
 	guint32 iconlen;
 	guint16 iconsum;
-
-	/* Only provided if AIM_IMFLAGS_CUSTOMFEATURES is set */
-	guint8 *features;
-	guint8 featureslen;
-
-	/* Only provided if AIM_IMFLAGS_EXTDATA is set */
-	guint8 extdatalen;
-	guint8 *extdata;
-
-	/* Only used if AIM_IMFLAGS_CUSTOMCHARSET is set */
-	guint16 charset;
-	guint16 charsubset;
 };
 
 /* Valid values for channel 2 args->status */
@@ -981,10 +692,8 @@
 			struct aim_chat_roominfo roominfo;
 		} chat;
 		struct {
-			guint16 msgtype;
-			guint32 fgcolor;
-			guint32 bgcolor;
-			const char *rtfmsg;
+			guint8 msgtype;
+			const char *msg;
 		} rtfmsg;
 		struct {
 			guint16 subtype;
@@ -996,11 +705,6 @@
 	void *destructor; /* used internally only */
 };
 
-/* Valid values for channel 4 args->type */
-#define AIM_ICQMSG_AUTHREQUEST	0x0006
-#define AIM_ICQMSG_AUTHDENIED	0x0007
-#define AIM_ICQMSG_AUTHGRANTED	0x0008
-
 struct aim_incomingim_ch4_args
 {
 	guint32 uin; /* Of the sender of the ICBM */
@@ -1017,7 +721,6 @@
 /* 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);
@@ -1026,38 +729,23 @@
 /* 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 *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 *bn, guint16 type2);
 /* 0x000b */ int icq_relay_xstatus (OscarData *od, const char *sn, const guchar* cookie);
 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 *sourcebn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen);
-
+void aim_im_send_icq_confirmation(OscarData *od, const char *bn, const guchar *cookie);
 
 /* 0x0002 - family_locate.c */
 /*
  * AIM User Info, Standard Form.
  */
-#define AIM_FLAG_UNCONFIRMED     0x0001 /* "damned transients" */
 #define AIM_FLAG_ADMINISTRATOR   0x0002
 #define AIM_FLAG_AOL             0x0004
-#define AIM_FLAG_OSCAR_PAY       0x0008
-#define AIM_FLAG_FREE            0x0010
 #define AIM_FLAG_AWAY            0x0020
-#define AIM_FLAG_ICQ             0x0040
 #define AIM_FLAG_WIRELESS        0x0080
-#define AIM_FLAG_UNKNOWN100      0x0100
-#define AIM_FLAG_IMFORWARDING    0x0200
+#define AIM_FLAG_ICQ             0x0040
 #define AIM_FLAG_ACTIVEBUDDY     0x0400
-#define AIM_FLAG_UNKNOWN800      0x0800
-#define AIM_FLAG_ONEWAYWIRELESS  0x1000
-#define AIM_FLAG_NOKNOCKKNOCK    0x00040000
-#define AIM_FLAG_FORWARD_MOBILE  0x00080000
 
 #define AIM_USERINFO_PRESENT_FLAGS        0x00000001
 #define AIM_USERINFO_PRESENT_MEMBERSINCE  0x00000002
@@ -1130,22 +818,8 @@
 	guint16 instance;
 };
 
-#define AIM_COOKIETYPE_UNKNOWN  0x00
-#define AIM_COOKIETYPE_ICBM     0x01
-#define AIM_COOKIETYPE_ADS      0x02
-#define AIM_COOKIETYPE_BOS      0x03
-#define AIM_COOKIETYPE_IM       0x04
-#define AIM_COOKIETYPE_CHAT     0x05
-#define AIM_COOKIETYPE_CHATNAV  0x06
-#define AIM_COOKIETYPE_INVITE   0x07
-/* we'll move OFT up a bit to give breathing room.  not like it really
- * matters. */
-#define AIM_COOKIETYPE_OFTIM    0x10
-#define AIM_COOKIETYPE_OFTGET   0x11
-#define AIM_COOKIETYPE_OFTSEND  0x12
-#define AIM_COOKIETYPE_OFTVOICE 0x13
-#define AIM_COOKIETYPE_OFTIMAGE 0x14
-#define AIM_COOKIETYPE_OFTICON  0x15
+#define AIM_COOKIETYPE_CHAT     0x01
+#define AIM_COOKIETYPE_INVITE   0x02
 
 aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *bn);
 void aim_locate_dorequest(OscarData *od);
@@ -1153,10 +827,6 @@
 /* 0x0002 */ int aim_locate_reqrights(OscarData *od);
 /* 0x0004 */ int aim_locate_setcaps(OscarData *od, guint64 caps);
 /* 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 *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 *bn, guint32 flags);
 
 guint64 aim_locate_getcaps(OscarData *od, ByteStream *bs, int len);
@@ -1171,25 +841,11 @@
 
 /* 0x0003 - family_buddy.c */
 /* 0x0002 */ void aim_buddylist_reqrights(OscarData *, FlapConnection *);
-/* 0x0004 */ int aim_buddylist_set(OscarData *, FlapConnection *, const char *);
-/* 0x0004 */ int aim_buddylist_addbuddy(OscarData *, FlapConnection *, const char *);
-/* 0x0005 */ int aim_buddylist_removebuddy(OscarData *, FlapConnection *, const char *);
-
 
 
 /* 0x000a - family_userlookup.c */
 int aim_search_address(OscarData *, const char *);
 
-
-
-/* 0x000d - family_chatnav.c */
-/* 0x000e - family_chat.c */
-/* These apply to exchanges as well. */
-#define AIM_CHATROOM_FLAG_EVILABLE 0x0001
-#define AIM_CHATROOM_FLAG_NAV_ONLY 0x0002
-#define AIM_CHATROOM_FLAG_INSTANCING_ALLOWED 0x0004
-#define AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED 0x0008
-
 struct aim_chat_exchangeinfo
 {
 	guint16 number;
@@ -1205,41 +861,10 @@
 #define AIM_CHATFLAGS_AWAY      0x0002
 int aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language);
 int aim_chat_join(OscarData *od, guint16 exchange, const char *roomname, guint16 instance);
-int aim_chat_attachname(FlapConnection *conn, guint16 exchange, const char *roomname, guint16 instance);
-char *aim_chat_getname(FlapConnection *conn);
-FlapConnection *aim_chat_getconn(OscarData *, const char *name);
 
 void aim_chatnav_reqrights(OscarData *od, FlapConnection *conn);
 
 int aim_chatnav_createroom(OscarData *od, FlapConnection *conn, const char *name, guint16 exchange);
-int aim_chat_leaveroom(OscarData *od, const char *name);
-
-
-
-/* 0x000f - family_odir.c */
-struct aim_odir
-{
-	char *first;
-	char *last;
-	char *middle;
-	char *maiden;
-	char *email;
-	char *country;
-	char *state;
-	char *city;
-	char *bn;
-	char *interest;
-	char *nick;
-	char *zip;
-	char *region;
-	char *address;
-	struct aim_odir *next;
-};
-
-int aim_odir_email(OscarData *, const char *, const char *);
-int aim_odir_name(OscarData *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *);
-int aim_odir_interest(OscarData *, const char *, const char *);
-
 
 
 /* 0x0010 - family_bart.c */
@@ -1255,15 +880,9 @@
 #define AIM_SSI_TYPE_DENY		0x0003
 #define AIM_SSI_TYPE_PDINFO		0x0004
 #define AIM_SSI_TYPE_PRESENCEPREFS	0x0005
+#define AIM_SSI_TYPE_ICQDENY		0x000e
 #define AIM_SSI_TYPE_ICONINFO		0x0014
 
-#define AIM_SSI_ACK_SUCCESS		0x0000
-#define AIM_SSI_ACK_ITEMNOTFOUND	0x0002
-#define AIM_SSI_ACK_IDNUMINUSE		0x000a
-#define AIM_SSI_ACK_ATMAX		0x000c
-#define AIM_SSI_ACK_INVALIDNAME		0x000d
-#define AIM_SSI_ACK_AUTHREQUIRED	0x000e
-
 /* These flags are set in the 0x00c9 TLV of SSI type 0x0005 */
 #define AIM_SSI_PRESENCE_FLAG_SHOWIDLE        0x00000400
 #define AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES 0x00020000
@@ -1290,11 +909,9 @@
 /* These build the actual SNACs and queue them to be sent */
 /* 0x0002 */ int aim_ssi_reqrights(OscarData *od);
 /* 0x0004 */ int aim_ssi_reqdata(OscarData *od);
-/* 0x0005 */ int aim_ssi_reqifchanged(OscarData *od, time_t localstamp, guint16 localrev);
 /* 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 *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);
 
@@ -1311,49 +928,22 @@
 
 /* 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);
-int aim_ssi_addpermit(OscarData *od, const char *name);
-int aim_ssi_adddeny(OscarData *od, const char *name);
 int aim_ssi_delbuddy(OscarData *od, const char *name, const char *group);
 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 *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);
-int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny, guint32 vismask);
+int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny);
 int aim_ssi_setpresence(OscarData *od, guint32 presence);
 int aim_ssi_seticon(OscarData *od, const guint8 *iconsum, guint8 iconsumlen);
 int aim_ssi_delicon(OscarData *od);
-
-
+int aim_ssi_add_to_private_list(OscarData *od, const char* name, guint16 list_type);
+int aim_ssi_del_from_private_list(OscarData* od, const char* name, guint16 list_type);
 
-/* 0x0015 - family_icq.c */
-#define AIM_ICQ_INFO_SIMPLE	0x001
-#define AIM_ICQ_INFO_SUMMARY	0x002
-#define AIM_ICQ_INFO_EMAIL	0x004
-#define AIM_ICQ_INFO_PERSONAL	0x008
-#define AIM_ICQ_INFO_ADDITIONAL	0x010
-#define AIM_ICQ_INFO_WORK	0x020
-#define AIM_ICQ_INFO_INTERESTS	0x040
-#define AIM_ICQ_INFO_ORGS	0x080
-#define AIM_ICQ_INFO_UNKNOWN	0x100
-#define AIM_ICQ_INFO_HAVEALL	0x1ff
-
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-struct aim_icq_offlinemsg
-{
-	guint32 sender;
-	guint16 year;
-	guint8 month, day, hour, minute;
-	guint8 type;
-	guint8 flags;
-	char *msg;
-	int msglen;
-};
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
+guint16 aim_ssi_getdenyentrytype(OscarData* od);
 
 struct aim_icq_info
 {
@@ -1410,22 +1000,17 @@
 	guint16 numaddresses;
 	char **email2;
 
-	/* we keep track of these in a linked list because we're 1337 */
-	struct aim_icq_info *next;
-
 	/* status note info */
 	guint8 icbm_cookie[8];
 	char *status_note_title;
+
+	gboolean for_auth_request;
+	char *auth_request_reason;
 };
 
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-int aim_icq_reqofflinemsgs(OscarData *od);
-int aim_icq_ackofflinemsgs(OscarData *od);
-#endif
 int aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware);
 int aim_icq_changepasswd(OscarData *od, const char *passwd);
-int aim_icq_getsimpleinfo(OscarData *od, const char *uin);
-int aim_icq_getalias(OscarData *od, const char *uin);
+int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason);
 int aim_icq_getallinfo(OscarData *od, const char *uin);
 int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias);
 
@@ -1565,17 +1150,13 @@
 gchar *oscar_get_clientstring(void);
 
 guint16 aimutil_iconsum(const guint8 *buf, int buflen);
-int aimutil_tokslen(char *toSearch, int theindex, char dl);
-int aimutil_itemcnt(char *toSearch, char dl);
-char *aimutil_itemindex(char *toSearch, int theindex, char dl);
 
 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);
-
-
-
+gchar *oscar_util_format_string(const char *str, const char *name);
+gchar *oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message);
 
 typedef struct {
 	guint16 family;
@@ -1617,11 +1198,7 @@
 int chat_modfirst(OscarData *od, aim_module_t *mod);
 int locate_modfirst(OscarData *od, aim_module_t *mod);
 int service_modfirst(OscarData *od, aim_module_t *mod);
-int invite_modfirst(OscarData *od, aim_module_t *mod);
-int translate_modfirst(OscarData *od, aim_module_t *mod);
 int popups_modfirst(OscarData *od, aim_module_t *mod);
-int adverts_modfirst(OscarData *od, aim_module_t *mod);
-int odir_modfirst(OscarData *od, aim_module_t *mod);
 int bart_modfirst(OscarData *od, aim_module_t *mod);
 int ssi_modfirst(OscarData *od, aim_module_t *mod);
 int icq_modfirst(OscarData *od, aim_module_t *mod);
@@ -1630,15 +1207,14 @@
 void aim_genericreq_n(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype);
 void aim_genericreq_n_snacid(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype);
 void aim_genericreq_l(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint32 *);
-void aim_genericreq_s(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 *);
 
 /* bstream.c */
-int byte_stream_new(ByteStream *bs, guint32 len);
-int byte_stream_init(ByteStream *bs, guint8 *data, int len);
+int byte_stream_new(ByteStream *bs, size_t len);
+int byte_stream_init(ByteStream *bs, guint8 *data, size_t len);
 void byte_stream_destroy(ByteStream *bs);
-int byte_stream_empty(ByteStream *bs);
+int byte_stream_bytes_left(ByteStream *bs);
 int byte_stream_curpos(ByteStream *bs);
-int byte_stream_setpos(ByteStream *bs, unsigned int off);
+int byte_stream_setpos(ByteStream *bs, size_t off);
 void byte_stream_rewind(ByteStream *bs);
 int byte_stream_advance(ByteStream *bs, int n);
 guint8 byte_stream_get8(ByteStream *bs);
@@ -1647,18 +1223,18 @@
 guint8 byte_stream_getle8(ByteStream *bs);
 guint16 byte_stream_getle16(ByteStream *bs);
 guint32 byte_stream_getle32(ByteStream *bs);
-int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int len);
-guint8 *byte_stream_getraw(ByteStream *bs, int len);
-char *byte_stream_getstr(ByteStream *bs, int len);
+int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, size_t len);
+guint8 *byte_stream_getraw(ByteStream *bs, size_t len);
+char *byte_stream_getstr(ByteStream *bs, size_t len);
 int byte_stream_put8(ByteStream *bs, guint8 v);
 int byte_stream_put16(ByteStream *bs, guint16 v);
 int byte_stream_put32(ByteStream *bs, guint32 v);
 int byte_stream_putle8(ByteStream *bs, guint8 v);
 int byte_stream_putle16(ByteStream *bs, guint16 v);
 int byte_stream_putle32(ByteStream *bs, guint32 v);
-int byte_stream_putraw(ByteStream *bs, const guint8 *v, int len);
+int byte_stream_putraw(ByteStream *bs, const guint8 *v, size_t len);
 int byte_stream_putstr(ByteStream *bs, const char *str);
-int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int len);
+int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, size_t len);
 int byte_stream_putuid(ByteStream *bs, OscarData *od);
 int byte_stream_putcaps(ByteStream *bs, guint64 caps);
 
@@ -1693,7 +1269,7 @@
 aim_snacid_t aim_cachesnac(OscarData *od, const guint16 family, const guint16 type, const guint16 flags, const void *data, const int datalen);
 aim_snac_t *aim_remsnac(OscarData *, aim_snacid_t id);
 void aim_cleansnacs(OscarData *, int maxage);
-int aim_putsnac(ByteStream *, guint16 family, guint16 type, guint16 flags, aim_snacid_t id);
+int aim_putsnac(ByteStream *, guint16 family, guint16 type, aim_snacid_t id);
 
 struct chatsnacinfo {
 	guint16 exchange;
@@ -1720,13 +1296,53 @@
 IcbmCookie *aim_mkcookie(guint8 *, int, void *);
 IcbmCookie *aim_checkcookie(OscarData *, const unsigned char *, const int);
 int aim_freecookie(OscarData *od, IcbmCookie *cookie);
-int aim_msgcookie_gettype(guint64 type);
 int aim_cookie_free(OscarData *od, IcbmCookie *cookie);
 
 int aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo);
 
 void flap_connection_destroy_chat(OscarData *od, FlapConnection *conn);
 
+/* userinfo.c - displaying user information */
+
+void oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean strip_html_tags);
+void oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo);
+void oscar_user_info_display_error(OscarData *od, guint16 error_reason, char *buddy);
+void oscar_user_info_display_icq(OscarData *od, struct aim_icq_info *info);
+void oscar_user_info_display_aim(OscarData *od, aim_userinfo_t *userinfo);
+
+/* authorization.c - OSCAR authorization requests */
+void oscar_auth_sendrequest(PurpleConnection *gc, const char *name);
+void oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored);
+void oscar_auth_recvrequest(PurpleConnection *gc, gchar *name, gchar *nick, gchar *reason);
+
+void oscar_set_aim_permdeny(PurpleConnection *gc);
+
+struct buddyinfo
+{
+	gboolean typingnot;
+	guint32 ipaddr;
+
+	unsigned long ico_me_len;
+	unsigned long ico_me_csum;
+	time_t ico_me_time;
+	gboolean ico_informed;
+
+	unsigned long ico_len;
+	unsigned long ico_csum;
+	time_t ico_time;
+	gboolean ico_need;
+	gboolean ico_sent;
+};
+
+struct name_data
+{
+	PurpleConnection *gc;
+	gchar *name;
+	gchar *nick;
+};
+
+void oscar_free_name_data(struct name_data *data);
+
 #ifdef __cplusplus
 }
 #endif
--- a/libpurple/protocols/oscar/oscar_data.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/oscar_data.c	Wed Aug 25 19:12:08 2010 +0000
@@ -53,17 +53,13 @@
 	aim__registermodule(od, locate_modfirst);
 	aim__registermodule(od, buddylist_modfirst);
 	aim__registermodule(od, msg_modfirst);
-	/* aim__registermodule(od, adverts_modfirst); */
-	/* aim__registermodule(od, invite_modfirst); */
 	aim__registermodule(od, admin_modfirst);
 	aim__registermodule(od, popups_modfirst);
 	aim__registermodule(od, bos_modfirst);
 	aim__registermodule(od, search_modfirst);
 	aim__registermodule(od, stats_modfirst);
-	/* aim__registermodule(od, translate_modfirst); */
 	aim__registermodule(od, chatnav_modfirst);
 	aim__registermodule(od, chat_modfirst);
-	aim__registermodule(od, odir_modfirst);
 	aim__registermodule(od, bart_modfirst);
 	/* missing 0x11 - 0x12 */
 	aim__registermodule(od, ssi_modfirst);
--- a/libpurple/protocols/oscar/oscarcommon.h	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/oscarcommon.h	Wed Aug 25 19:12:08 2010 +0000
@@ -77,7 +77,6 @@
 void oscar_add_deny(PurpleConnection *gc, const char *who);
 void oscar_rem_permit(PurpleConnection *gc, const char *who);
 void oscar_rem_deny(PurpleConnection *gc, const char *who);
-void oscar_set_permit_deny(PurpleConnection *gc);
 void oscar_join_chat(PurpleConnection *gc, GHashTable *data);
 char *oscar_get_chat_name(GHashTable *data);
 void oscar_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name);
--- a/libpurple/protocols/oscar/peer_proxy.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/peer_proxy.c	Wed Aug 25 19:12:08 2010 +0000
@@ -32,8 +32,8 @@
 	ByteStream bs;
 
 	purple_debug_info("oscar", "Outgoing peer proxy frame with "
-			"type=0x%04hx, unknown=0x%08x, "
-			"flags=0x%04hx, and payload length=%hd\n",
+			"type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and "
+			"payload length=%" G_GSIZE_FORMAT "\n",
 			frame->type, frame->unknown,
 			frame->flags, frame->payload.len);
 
@@ -129,8 +129,8 @@
 peer_proxy_recv_frame(PeerConnection *conn, ProxyFrame *frame)
 {
 	purple_debug_info("oscar", "Incoming peer proxy frame with "
-			"type=0x%04hx, unknown=0x%08x, "
-			"flags=0x%04hx, and payload length=%hd\n", frame->type,
+			"type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and "
+			"payload length=%" G_GSIZE_FORMAT "\n", frame->type,
 			frame->unknown, frame->flags, frame->payload.len);
 
 	if (frame->type == PEER_PROXY_TYPE_CREATED)
@@ -168,7 +168,7 @@
 	}
 	else if (frame->type == PEER_PROXY_TYPE_ERROR)
 	{
-		if (byte_stream_empty(&frame->payload) >= 2)
+		if (byte_stream_bytes_left(&frame->payload) >= 2)
 		{
 			guint16 error;
 			const char *msg;
--- a/libpurple/protocols/oscar/rxhandlers.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/rxhandlers.c	Wed Aug 25 19:12:08 2010 +0000
@@ -95,194 +95,3 @@
 
 	return;
 }
-
-#if 0
-/*
- * Bleck functions get called when there's no non-bleck functions
- * around to cleanup the mess...
- */
-static int bleck(OscarData *od, FlapFrame *frame, ...)
-{
-	guint16 family, subtype;
-	guint16 maxf, maxs;
-
-	static const char *channels[6] = {
-		"Invalid (0)",
-		"FLAP Version",
-		"SNAC",
-		"Invalid (3)",
-		"Negotiation",
-		"FLAP NOP"
-	};
-	static const int maxchannels = 5;
-
-	/* XXX: this is ugly. and big just for debugging. */
-	static const char *literals[14][25] = {
-		{"Invalid",
-		 NULL
-		},
-		{"General",
-		 "Invalid",
-		 "Error",
-		 "Client Ready",
-		 "Server Ready",
-		 "Service Request",
-		 "Redirect",
-		 "Rate Information Request",
-		 "Rate Information",
-		 "Rate Information Ack",
-		 NULL,
-		 "Rate Information Change",
-		 "Server Pause",
-		 NULL,
-		 "Server Resume",
-		 "Request Personal User Information",
-		 "Personal User Information",
-		 "Evil Notification",
-		 NULL,
-		 "Migration notice",
-		 "Message of the Day",
-		 "Set Privacy Flags",
-		 "Well Known URL",
-		 "NOP"
-		},
-		{"Location",
-		 "Invalid",
-		 "Error",
-		 "Request Rights",
-		 "Rights Information",
-		 "Set user information",
-		 "Request User Information",
-		 "User Information",
-		 "Watcher Sub Request",
-		 "Watcher Notification"
-		},
-		{"Buddy List Management",
-		 "Invalid",
-		 "Error",
-		 "Request Rights",
-		 "Rights Information",
-		 "Add Buddy",
-		 "Remove Buddy",
-		 "Watcher List Query",
-		 "Watcher List Response",
-		 "Watcher SubRequest",
-		 "Watcher Notification",
-		 "Reject Notification",
-		 "Oncoming Buddy",
-		 "Offgoing Buddy"
-		},
-		{"Messeging",
-		 "Invalid",
-		 "Error",
-		 "Add ICBM Parameter",
-		 "Remove ICBM Parameter",
-		 "Request Parameter Information",
-		 "Parameter Information",
-		 "Outgoing Message",
-		 "Incoming Message",
-		 "Evil Request",
-		 "Evil Reply",
-		 "Missed Calls",
-		 "Message Error",
-		 "Host Ack"
-		},
-		{"Advertisements",
-		 "Invalid",
-		 "Error",
-		 "Request Ad",
-		 "Ad Data (GIFs)"
-		},
-		{"Invitation / Client-to-Client",
-		 "Invalid",
-		 "Error",
-		 "Invite a Friend",
-		 "Invitation Ack"
-		},
-		{"Administrative",
-		 "Invalid",
-		 "Error",
-		 "Information Request",
-		 "Information Reply",
-		 "Information Change Request",
-		 "Information Chat Reply",
-		 "Account Confirm Request",
-		 "Account Confirm Reply",
-		 "Account Delete Request",
-		 "Account Delete Reply"
-		},
-		{"Popups",
-		 "Invalid",
-		 "Error",
-		 "Display Popup"
-		},
-		{"BOS",
-		 "Invalid",
-		 "Error",
-		 "Request Rights",
-		 "Rights Response",
-		 "Set group permission mask",
-		 "Add permission list entries",
-		 "Delete permission list entries",
-		 "Add deny list entries",
-		 "Delete deny list entries",
-		 "Server Error"
-		},
-		{"User Lookup",
-		 "Invalid",
-		 "Error",
-		 "Search Request",
-		 "Search Response"
-		},
-		{"Stats",
-		 "Invalid",
-		 "Error",
-		 "Set minimum report interval",
-		 "Report Events"
-		},
-		{"Translate",
-		 "Invalid",
-		 "Error",
-		 "Translate Request",
-		 "Translate Reply",
-		},
-		{"Chat Navigation",
-		 "Invalid",
-		 "Error",
-		 "Request rights",
-		 "Request Exchange Information",
-		 "Request Room Information",
-		 "Request Occupant List",
-		 "Search for Room",
-		 "Outgoing Message",
-		 "Incoming Message",
-		 "Evil Request",
-		 "Evil Reply",
-		 "Chat Error",
-		}
-	};
-
-	maxf = sizeof(literals) / sizeof(literals[0]);
-	maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
-
-	if (frame->channel == 0x02) {
-
-		family = byte_stream_get16(&frame->data);
-		subtype = byte_stream_get16(&frame->data);
-
-		if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
-			purple_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->channel], family, subtype, literals[family][subtype+1]);
-		else
-			purple_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->channel], family, subtype);
-	} else {
-
-		if (frame->channel <= maxchannels)
-			purple_debug_misc("oscar", "bleck: channel %s (0x%02x)\n", channels[frame->channel], frame->channel);
-		else
-			purple_debug_misc("oscar", "bleck: unknown channel 0x%02x\n", frame->channel);
-
-	}
-
-	return 1;
-}
-#endif
--- a/libpurple/protocols/oscar/snac.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/snac.c	Wed Aug 25 19:12:08 2010 +0000
@@ -151,12 +151,12 @@
 	return;
 }
 
-int aim_putsnac(ByteStream *bs, guint16 family, guint16 subtype, guint16 flags, aim_snacid_t snacid)
+int aim_putsnac(ByteStream *bs, guint16 family, guint16 subtype, aim_snacid_t snacid)
 {
 
 	byte_stream_put16(bs, family);
 	byte_stream_put16(bs, subtype);
-	byte_stream_put16(bs, flags);
+	byte_stream_put16(bs, 0x0000);
 	byte_stream_put32(bs, snacid);
 
 	return 10;
--- a/libpurple/protocols/oscar/tlv.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/tlv.c	Wed Aug 25 19:12:08 2010 +0000
@@ -49,27 +49,7 @@
 	type = byte_stream_get16(bs);
 	length = byte_stream_get16(bs);
 
-#if 0
-	/*
-	 * This code hasn't been needed in years.  It's been commented
-	 * out since 2003, at the latest.  It seems likely that it was
-	 * just a bug in their server code that has since been fixed.
-	 * In any case, here's the orignal comment, kept for historical
-	 * purposes:
-	 *
-	 * Okay, so now AOL has decided that any TLV of
-	 * type 0x0013 can only be two bytes, despite
-	 * what the actual given length is.  So here
-	 * we dump any invalid TLVs of that sort.  Hopefully
-	 * there's no special cases to this special case.
-	 *   - mid (30jun2000)
-	 */
-	if ((type == 0x0013) && (length != 0x0002)) {
-		length = 0x0002;
-		return list;
-	}
-#endif
-	if (length > byte_stream_empty(bs)) {
+	if (length > byte_stream_bytes_left(bs)) {
 		aim_tlvlist_free(list);
 		return NULL;
 	}
@@ -108,7 +88,7 @@
 {
 	GSList *list = NULL;
 
-	while (byte_stream_empty(bs) > 0) {
+	while (byte_stream_bytes_left(bs) > 0) {
 		list = aim_tlv_read(list, bs);
 		if (list == NULL)
 			return NULL;
@@ -142,7 +122,7 @@
 {
 	GSList *list = NULL;
 
-	while ((byte_stream_empty(bs) > 0) && (num != 0)) {
+	while ((byte_stream_bytes_left(bs) > 0) && (num != 0)) {
 		list = aim_tlv_read(list, bs);
 		if (list == NULL)
 			return NULL;
@@ -177,7 +157,7 @@
 {
 	GSList *list = NULL;
 
-	while ((byte_stream_empty(bs) > 0) && (len > 0)) {
+	while ((byte_stream_bytes_left(bs) > 0) && (len > 0)) {
 		list = aim_tlv_read(list, bs);
 		if (list == NULL)
 			return NULL;
@@ -391,6 +371,17 @@
 	return aim_tlvlist_add_raw(list, type, strlen(value), (guint8 *)value);
 }
 
+static int
+count_caps(guint64 caps)
+{
+	int set_bits = 0;
+	while (caps) {
+		set_bits += caps & 1;
+		caps >>= 1;
+	}
+	return set_bits;
+}
+
 /**
  * Adds a block of capability blocks to a TLV chain. The bitfield
  * passed in should be a bitwise %OR of any of the %AIM_CAPS constants:
@@ -409,23 +400,24 @@
  */
 int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint64 caps, const char *mood)
 {
-	guint8 buf[256]; /* TODO: Don't use a fixed length buffer */
 	ByteStream bs;
+	guint32 bs_size;
 	guint8 *data;
 
 	if (caps == 0)
 		return 0; /* nothing there anyway */
 
-	byte_stream_init(&bs, buf, sizeof(buf));
+	data = icq_get_custom_icon_data(mood);
+	bs_size = 16*(count_caps(caps) + (data != NULL ? 1 : 0));
 
+	byte_stream_new(&bs, bs_size);
 	byte_stream_putcaps(&bs, caps);
-	
+
 	/* adding of custom icon GUID */
-	data = icq_get_custom_icon_data(mood);
 	if (data != NULL)
 		byte_stream_putraw(&bs, data, 16);
 
-	return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), buf);
+	return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data);
 }
 
 /**
@@ -668,7 +660,7 @@
 	/* do an initial run to test total length */
 	goodbuflen = aim_tlvlist_size(*list);
 
-	if (goodbuflen > byte_stream_empty(bs))
+	if (goodbuflen > byte_stream_bytes_left(bs))
 		return 0; /* not enough buffer */
 
 	/* do the real write-out */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/userinfo.c	Wed Aug 25 19:12:08 2010 +0000
@@ -0,0 +1,553 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+*/
+
+/*
+ * Displaying various information about buddies.
+ */
+
+#include "encoding.h"
+#include "oscar.h"
+
+static gchar *
+oscar_caps_to_string(guint64 caps)
+{
+	GString *str;
+	const gchar *tmp;
+	guint64 bit = 1;
+
+	str = g_string_new("");
+
+	if (!caps) {
+		return NULL;
+	} else while (bit <= OSCAR_CAPABILITY_LAST) {
+		if (bit & caps) {
+			switch (bit) {
+			case OSCAR_CAPABILITY_BUDDYICON:
+				tmp = _("Buddy Icon");
+				break;
+			case OSCAR_CAPABILITY_TALK:
+				tmp = _("Voice");
+				break;
+			case OSCAR_CAPABILITY_DIRECTIM:
+				tmp = _("AIM Direct IM");
+				break;
+			case OSCAR_CAPABILITY_CHAT:
+				tmp = _("Chat");
+				break;
+			case OSCAR_CAPABILITY_GETFILE:
+				tmp = _("Get File");
+				break;
+			case OSCAR_CAPABILITY_SENDFILE:
+				tmp = _("Send File");
+				break;
+			case OSCAR_CAPABILITY_GAMES:
+			case OSCAR_CAPABILITY_GAMES2:
+				tmp = _("Games");
+				break;
+			case OSCAR_CAPABILITY_XTRAZ:
+			case OSCAR_CAPABILITY_NEWCAPS:
+				tmp = _("ICQ Xtraz");
+				break;
+			case OSCAR_CAPABILITY_ADDINS:
+				tmp = _("Add-Ins");
+				break;
+			case OSCAR_CAPABILITY_SENDBUDDYLIST:
+				tmp = _("Send Buddy List");
+				break;
+			case OSCAR_CAPABILITY_ICQ_DIRECT:
+				tmp = _("ICQ Direct Connect");
+				break;
+			case OSCAR_CAPABILITY_APINFO:
+				tmp = _("AP User");
+				break;
+			case OSCAR_CAPABILITY_ICQRTF:
+				tmp = _("ICQ RTF");
+				break;
+			case OSCAR_CAPABILITY_EMPTY:
+				tmp = _("Nihilist");
+				break;
+			case OSCAR_CAPABILITY_ICQSERVERRELAY:
+				tmp = _("ICQ Server Relay");
+				break;
+			case OSCAR_CAPABILITY_UNICODEOLD:
+				tmp = _("Old ICQ UTF8");
+				break;
+			case OSCAR_CAPABILITY_TRILLIANCRYPT:
+				tmp = _("Trillian Encryption");
+				break;
+			case OSCAR_CAPABILITY_UNICODE:
+				tmp = _("ICQ UTF8");
+				break;
+			case OSCAR_CAPABILITY_HIPTOP:
+				tmp = _("Hiptop");
+				break;
+			case OSCAR_CAPABILITY_SECUREIM:
+				tmp = _("Security Enabled");
+				break;
+			case OSCAR_CAPABILITY_VIDEO:
+				tmp = _("Video Chat");
+				break;
+			/* Not actually sure about this one... WinAIM doesn't show anything */
+			case OSCAR_CAPABILITY_ICHATAV:
+				tmp = _("iChat AV");
+				break;
+			case OSCAR_CAPABILITY_LIVEVIDEO:
+				tmp = _("Live Video");
+				break;
+			case OSCAR_CAPABILITY_CAMERA:
+				tmp = _("Camera");
+				break;
+			case OSCAR_CAPABILITY_ICHAT_SCREENSHARE:
+				tmp = _("Screen Sharing");
+				break;
+			default:
+				tmp = NULL;
+				break;
+			}
+			if (tmp)
+				g_string_append_printf(str, "%s%s", (*(str->str) == '\0' ? "" : ", "), tmp);
+		}
+		bit <<= 1;
+	}
+
+	return g_string_free(str, FALSE);
+}
+
+static void
+oscar_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *name, const char *value)
+{
+	if (value && value[0]) {
+		purple_notify_user_info_add_pair(user_info, name, value);
+	}
+}
+
+static void
+oscar_user_info_convert_and_add(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
+					const char *name, const char *value)
+{
+	gchar *utf8;
+
+	if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) {
+		purple_notify_user_info_add_pair(user_info, name, utf8);
+		g_free(utf8);
+	}
+}
+
+static void
+oscar_user_info_convert_and_add_hyperlink(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
+						const char *name, const char *value, const char *url_prefix)
+{
+	gchar *utf8;
+
+	if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) {
+		gchar *tmp = g_strdup_printf("<a href=\"%s%s\">%s</a>", url_prefix, utf8, utf8);
+		purple_notify_user_info_add_pair(user_info, name, tmp);
+		g_free(utf8);
+		g_free(tmp);
+	}
+}
+
+/**
+ * @brief Append the status information to a user_info struct
+ *
+ * The returned information is HTML-ready, appropriately escaped, as all information in a user_info struct should be HTML.
+ *
+ * @param gc The PurpleConnection
+ * @param user_info A PurpleNotifyUserInfo object to which status information will be added
+ * @param b The PurpleBuddy whose status is desired. This or the aim_userinfo_t (or both) must be passed to oscar_user_info_append_status().
+ * @param userinfo The aim_userinfo_t of the buddy whose status is desired. This or the PurpleBuddy (or both) must be passed to oscar_user_info_append_status().
+ * @param strip_html_tags If strip_html_tags is TRUE, tags embedded in the status message will be stripped, returning a non-formatted string. The string will still be HTML escaped.
+ */
+void
+oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean strip_html_tags)
+{
+	PurpleAccount *account = purple_connection_get_account(gc);
+	OscarData *od;
+	PurplePresence *presence = NULL;
+	PurpleStatus *status = NULL;
+	gchar *message = NULL, *itmsurl = NULL, *tmp;
+	gboolean is_away;
+
+	od = purple_connection_get_protocol_data(gc);
+
+	if (b == NULL && userinfo == NULL)
+		return;
+
+	if (b == NULL)
+		b = purple_find_buddy(purple_connection_get_account(gc), userinfo->bn);
+	else
+		userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
+
+	if (b) {
+		presence = purple_buddy_get_presence(b);
+		status = purple_presence_get_active_status(presence);
+	}
+
+	/* If we have both b and userinfo we favor userinfo, because if we're
+	   viewing someone's profile then we want the HTML away message, and
+	   the "message" attribute of the status contains only the plaintext
+	   message. */
+	if (userinfo) {
+		if ((userinfo->flags & AIM_FLAG_AWAY) && userinfo->away_len > 0 && userinfo->away != NULL && userinfo->away_encoding != NULL) {
+			/* Away message */
+			message = oscar_encoding_to_utf8(userinfo->away_encoding, userinfo->away, userinfo->away_len);
+		} else {
+			/*
+			 * Available message or non-HTML away message (because that's
+			 * all we have right now.
+			 */
+			if ((userinfo->status != NULL) && userinfo->status[0] != '\0') {
+				message = oscar_encoding_to_utf8(userinfo->status_encoding, userinfo->status, userinfo->status_len);
+			}
+#if defined (_WIN32) || defined (__APPLE__)
+			if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) {
+				itmsurl = oscar_encoding_to_utf8(userinfo->itmsurl_encoding, userinfo->itmsurl, userinfo->itmsurl_len);
+			}
+#endif
+		}
+	} else {
+		message = g_strdup(purple_status_get_attr_string(status, "message"));
+		itmsurl = g_strdup(purple_status_get_attr_string(status, "itmsurl"));
+	}
+
+	is_away = ((status && !purple_status_is_available(status)) ||
+			   (userinfo && (userinfo->flags & AIM_FLAG_AWAY)));
+
+	if (strip_html_tags) {
+		/* Away messages are HTML, but available messages were originally plain text.
+		 * We therefore need to strip away messages but not available messages if we're asked to remove HTML tags.
+		 */
+		/*
+		 * It seems like the above comment no longer applies.  All messages need
+		 * to be escaped.
+		 */
+		if (message) {
+			gchar *tmp2;
+			tmp = purple_markup_strip_html(message);
+			g_free(message);
+			tmp2 = g_markup_escape_text(tmp, -1);
+			g_free(tmp);
+			message = tmp2;
+		}
+
+	} else {
+		if (itmsurl) {
+			tmp = g_strdup_printf("<a href=\"%s\">%s</a>",
+								  itmsurl, message);
+			g_free(message);
+			message = tmp;
+		}
+	}
+	g_free(itmsurl);
+
+	if (message) {
+		tmp = oscar_util_format_string(message, purple_account_get_username(account));
+		g_free(message);
+		message = tmp;
+	}
+
+	if (b) {
+		if (purple_presence_is_online(presence)) {
+			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);
+				if (status_name && message && !strcmp(status_name, message))
+					status_name = NULL;
+
+				tmp = g_strdup_printf("%s%s%s",
+									   status_name ? status_name : "",
+									   ((status_name && 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, 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 {
+			g_free(message);
+			message = g_strdup(_("Offline"));
+		}
+	}
+
+	if (presence) {
+		const char *mood;
+		const char *description;
+		status = purple_presence_get_status(presence, "mood");
+		mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
+		description = icq_get_custom_icon_description(mood);
+		if (description && *description)
+			purple_notify_user_info_add_pair(user_info, _("Mood"), _(description));
+	}
+
+	purple_notify_user_info_add_pair(user_info, _("Status"), message);
+	g_free(message);
+}
+
+void
+oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo)
+{
+	OscarData *od;
+	PurpleAccount *account;
+	PurplePresence *presence = NULL;
+	PurpleStatus *status = NULL;
+	PurpleGroup *g = NULL;
+	struct buddyinfo *bi = NULL;
+	char *tmp;
+	const char *bname = NULL, *gname = NULL;
+
+	od = purple_connection_get_protocol_data(gc);
+	account = purple_connection_get_account(gc);
+
+	if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL)))
+		return;
+
+	if (userinfo == NULL)
+		userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
+
+	if (b == NULL)
+		b = purple_find_buddy(account, userinfo->bn);
+
+	if (b != NULL) {
+		bname = purple_buddy_get_name(b);
+		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->bn));
+
+	if ((bi != NULL) && (bi->ipaddr != 0)) {
+		tmp =  g_strdup_printf("%hhu.%hhu.%hhu.%hhu",
+						(bi->ipaddr & 0xff000000) >> 24,
+						(bi->ipaddr & 0x00ff0000) >> 16,
+						(bi->ipaddr & 0x0000ff00) >> 8,
+						(bi->ipaddr & 0x000000ff));
+		oscar_user_info_add_pair(user_info, _("IP Address"), tmp);
+		g_free(tmp);
+	}
+
+	if ((userinfo != NULL) && (userinfo->warnlevel != 0)) {
+		tmp = g_strdup_printf("%d", (int)(userinfo->warnlevel/10.0 + .5));
+		oscar_user_info_add_pair(user_info, _("Warning Level"), tmp);
+		g_free(tmp);
+	}
+
+	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);
+
+			oscar_user_info_convert_and_add(account, od, user_info, _("Buddy Comment"), tmp2);
+			g_free(tmp2);
+		}
+	}
+}
+
+void
+oscar_user_info_display_error(OscarData *od, guint16 error_reason, gchar *buddy)
+{
+	PurpleNotifyUserInfo *user_info = purple_notify_user_info_new();
+	gchar *buf = g_strdup_printf(_("User information not available: %s"), oscar_get_msgerr_reason(error_reason));
+	purple_notify_user_info_add_pair(user_info, NULL, buf);
+	purple_notify_userinfo(od->gc, buddy, user_info, NULL, NULL);
+	purple_notify_user_info_destroy(user_info);
+	purple_conv_present_error(buddy, purple_connection_get_account(od->gc), buf);
+	g_free(buf);
+}
+
+void
+oscar_user_info_display_icq(OscarData *od, struct aim_icq_info *info)
+{
+	PurpleConnection *gc = od->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	PurpleBuddy *buddy;
+	struct buddyinfo *bi;
+	gchar who[16];
+	PurpleNotifyUserInfo *user_info;
+	const gchar *alias;
+
+	if (!info->uin)
+		return;
+
+	user_info = purple_notify_user_info_new();
+
+	g_snprintf(who, sizeof(who), "%u", info->uin);
+	buddy = purple_find_buddy(account, who);
+	if (buddy != NULL)
+		bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, purple_buddy_get_name(buddy)));
+	else
+		bi = NULL;
+
+	purple_notify_user_info_add_pair(user_info, _("UIN"), who);
+	oscar_user_info_convert_and_add(account, od, user_info, _("Nick"), info->nick);
+	if ((bi != NULL) && (bi->ipaddr != 0)) {
+		char *tstr =  g_strdup_printf("%hhu.%hhu.%hhu.%hhu",
+						(bi->ipaddr & 0xff000000) >> 24,
+						(bi->ipaddr & 0x00ff0000) >> 16,
+						(bi->ipaddr & 0x0000ff00) >> 8,
+						(bi->ipaddr & 0x000000ff));
+		purple_notify_user_info_add_pair(user_info, _("IP Address"), tstr);
+		g_free(tstr);
+	}
+	oscar_user_info_convert_and_add(account, od, user_info, _("First Name"), info->first);
+	oscar_user_info_convert_and_add(account, od, user_info, _("Last Name"), info->last);
+	oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Email Address"), info->email, "mailto:");
+	if (info->numaddresses && info->email2) {
+		int i;
+		for (i = 0; i < info->numaddresses; i++) {
+			oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Email Address"), info->email2[i], "mailto:");
+		}
+	}
+	oscar_user_info_convert_and_add(account, od, user_info, _("Mobile Phone"), info->mobile);
+
+	if (info->gender != 0)
+		purple_notify_user_info_add_pair(user_info, _("Gender"), (info->gender == 1 ? _("Female") : _("Male")));
+
+	if ((info->birthyear > 1900) && (info->birthmonth > 0) && (info->birthday > 0)) {
+		/* Initialize the struct properly or strftime() will crash
+		 * under some conditions (e.g. Debian sarge w/ LANG=en_HK). */
+		time_t t = time(NULL);
+		struct tm *tm = localtime(&t);
+
+		tm->tm_mday = (int)info->birthday;
+		tm->tm_mon  = (int)info->birthmonth - 1;
+		tm->tm_year = (int)info->birthyear - 1900;
+
+		/* To be 100% sure that the fields are re-normalized.
+		 * If you're sure strftime() ALWAYS does this EVERYWHERE,
+		 * feel free to remove it.  --rlaager */
+		mktime(tm);
+
+		oscar_user_info_convert_and_add(account, od, user_info, _("Birthday"), purple_date_format_short(tm));
+	}
+	if ((info->age > 0) && (info->age < 255)) {
+		char age[5];
+		snprintf(age, sizeof(age), "%hhd", info->age);
+		purple_notify_user_info_add_pair(user_info, _("Age"), age);
+	}
+	oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Personal Web Page"), info->email, "");
+	if (buddy != NULL)
+		oscar_user_info_append_status(gc, user_info, buddy, /* aim_userinfo_t */ NULL, /* strip_html_tags */ FALSE);
+
+	oscar_user_info_convert_and_add(account, od, user_info, _("Additional Information"), info->info);
+	purple_notify_user_info_add_section_break(user_info);
+
+	if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) {
+		purple_notify_user_info_add_section_header(user_info, _("Home Address"));
+
+		oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->homeaddr);
+		oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->homecity);
+		oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->homestate);
+		oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->homezip);
+	}
+	if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) {
+		purple_notify_user_info_add_section_header(user_info, _("Work Address"));
+
+		oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->workaddr);
+		oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->workcity);
+		oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->workstate);
+		oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->workzip);
+	}
+	if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) {
+		purple_notify_user_info_add_section_header(user_info, _("Work Information"));
+
+		oscar_user_info_convert_and_add(account, od, user_info, _("Company"), info->workcompany);
+		oscar_user_info_convert_and_add(account, od, user_info, _("Division"), info->workdivision);
+		oscar_user_info_convert_and_add(account, od, user_info, _("Position"), info->workposition);
+		oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Web Page"), info->email, "");
+	}
+
+	if (buddy != NULL)
+		alias = purple_buddy_get_alias(buddy);
+	else
+		alias = who;
+	purple_notify_userinfo(gc, who, user_info, NULL, NULL);
+	purple_notify_user_info_destroy(user_info);
+}
+
+void
+oscar_user_info_display_aim(OscarData *od, aim_userinfo_t *userinfo)
+{
+	PurpleConnection *gc = od->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	PurpleNotifyUserInfo *user_info = purple_notify_user_info_new();
+	gchar *tmp = NULL, *info_utf8 = NULL, *base_profile_url = NULL;
+
+	oscar_user_info_append_status(gc, user_info, /* PurpleBuddy */ NULL, userinfo, /* strip_html_tags */ FALSE);
+
+	if ((userinfo->present & AIM_USERINFO_PRESENT_IDLE) && userinfo->idletime != 0) {
+		tmp = purple_str_seconds_to_string(userinfo->idletime*60);
+		oscar_user_info_add_pair(user_info, _("Idle"), tmp);
+		g_free(tmp);
+	}
+
+	oscar_user_info_append_extra_info(gc, user_info, NULL, userinfo);
+
+	if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !oscar_util_valid_name_sms(userinfo->bn)) {
+		/* An SMS contact is always online; its Online Since value is not useful */
+		time_t t = userinfo->onlinesince;
+		oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t)));
+	}
+
+	if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) {
+		time_t t = userinfo->membersince;
+		oscar_user_info_add_pair(user_info, _("Member Since"), purple_date_format_full(localtime(&t)));
+	}
+
+	if (userinfo->capabilities != 0) {
+		tmp = oscar_caps_to_string(userinfo->capabilities);
+		oscar_user_info_add_pair(user_info, _("Capabilities"), tmp);
+		g_free(tmp);
+	}
+
+	/* Info */
+	if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) {
+		info_utf8 = oscar_encoding_to_utf8(userinfo->info_encoding, userinfo->info, userinfo->info_len);
+		tmp = oscar_util_format_string(info_utf8, purple_account_get_username(account));
+		purple_notify_user_info_add_section_break(user_info);
+		oscar_user_info_add_pair(user_info, _("Profile"), tmp);
+		g_free(tmp);
+		g_free(info_utf8);
+	}
+
+	purple_notify_user_info_add_section_break(user_info);
+	base_profile_url = oscar_util_valid_name_icq(userinfo->bn) ? "http://www.icq.com/people" : "http://profiles.aim.com";
+	tmp = g_strdup_printf("<a href=\"%s/%s\">%s</a>",
+			base_profile_url, 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->bn, user_info, NULL, NULL);
+	purple_notify_user_info_destroy(user_info);
+}
\ No newline at end of file
--- a/libpurple/protocols/oscar/util.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/oscar/util.c	Wed Aug 25 19:12:08 2010 +0000
@@ -107,91 +107,6 @@
 	return g_strdup_printf("%s/%s", name, version);;
 }
 
-/*
- * Tokenizing functions.  Used to portably replace strtok/sep.
- *   -- DMP.
- *
- */
-/* TODO: Get rid of this and use glib functions */
-int
-aimutil_tokslen(char *toSearch, int theindex, char dl)
-{
-	int curCount = 1;
-	char *next;
-	char *last;
-	int toReturn;
-
-	last = toSearch;
-	next = strchr(toSearch, dl);
-
-	while(curCount < theindex && next != NULL) {
-		curCount++;
-		last = next + 1;
-		next = strchr(last, dl);
-	}
-
-	if ((curCount < theindex) || (next == NULL))
-		toReturn = strlen(toSearch) - (curCount - 1);
-	else
-		toReturn = next - toSearch - (curCount - 1);
-
-	return toReturn;
-}
-
-int
-aimutil_itemcnt(char *toSearch, char dl)
-{
-	int curCount;
-	char *next;
-
-	curCount = 1;
-
-	next = strchr(toSearch, dl);
-
-	while(next != NULL) {
-		curCount++;
-		next = strchr(next + 1, dl);
-	}
-
-	return curCount;
-}
-
-char *
-aimutil_itemindex(char *toSearch, int theindex, char dl)
-{
-	int curCount;
-	char *next;
-	char *last;
-	char *toReturn;
-
-	curCount = 0;
-
-	last = toSearch;
-	next = strchr(toSearch, dl);
-
-	while (curCount < theindex && next != NULL) {
-		curCount++;
-		last = next + 1;
-		next = strchr(last, dl);
-	}
-	next = strchr(last, dl);
-
-	if (curCount < theindex) {
-		toReturn = g_malloc(sizeof(char));
-		*toReturn = '\0';
-	} else {
-		if (next == NULL) {
-			toReturn = g_malloc((strlen(last) + 1) * sizeof(char));
-			strcpy(toReturn, last);
-		} else {
-			toReturn = g_malloc((next - last + 1) * sizeof(char));
-			memcpy(toReturn, last, (next - last));
-			toReturn[next - last] = '\0';
-		}
-	}
-	return toReturn;
-}
-
 /**
  * Calculate the checksum of a given icon.
  */
@@ -323,3 +238,89 @@
 
 	return 0;
 }
+
+/**
+ * Looks for %n, %d, or %t in a string, and replaces them with the
+ * specified name, date, and time, respectively.
+ *
+ * @param str  The string that may contain the special variables.
+ * @param name The sender name.
+ *
+ * @return A newly allocated string where the special variables are
+ *         expanded.  This should be g_free'd by the caller.
+ */
+gchar *
+oscar_util_format_string(const char *str, const char *name)
+{
+	char *c;
+	GString *cpy;
+	time_t t;
+	struct tm *tme;
+
+	g_return_val_if_fail(str  != NULL, NULL);
+	g_return_val_if_fail(name != NULL, NULL);
+
+	/* Create an empty GString that is hopefully big enough for most messages */
+	cpy = g_string_sized_new(1024);
+
+	t = time(NULL);
+	tme = localtime(&t);
+
+	c = (char *)str;
+	while (*c) {
+		switch (*c) {
+		case '%':
+			if (*(c + 1)) {
+				switch (*(c + 1)) {
+				case 'n':
+					/* append name */
+					g_string_append(cpy, name);
+					c++;
+					break;
+				case 'd':
+					/* append date */
+					g_string_append(cpy, purple_date_format_short(tme));
+					c++;
+					break;
+				case 't':
+					/* append time */
+					g_string_append(cpy, purple_time_format(tme));
+					c++;
+					break;
+				default:
+					g_string_append_c(cpy, *c);
+				}
+			} else {
+				g_string_append_c(cpy, *c);
+			}
+			break;
+		default:
+			g_string_append_c(cpy, *c);
+		}
+		c++;
+	}
+
+	return g_string_free(cpy, FALSE);
+}
+
+gchar *
+oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message)
+{
+	GSList *cur;
+	GString *result;
+	if (!buddies) {
+		return g_strdup_printf("<i>%s</i>", no_buddies_message);
+	}
+	result = g_string_new("");
+	for (cur = buddies; cur != NULL; cur = cur->next) {
+		PurpleBuddy *buddy = cur->data;
+		const gchar *bname = purple_buddy_get_name(buddy);
+		const gchar *alias = purple_buddy_get_alias_only(buddy);
+		g_string_append(result, bname);
+		if (alias) {
+			g_string_append_printf(result, " (%s)", alias);
+		}
+		g_string_append(result, "<br>");
+	}
+	return g_string_free(result, FALSE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/visibility.c	Wed Aug 25 19:12:08 2010 +0000
@@ -0,0 +1,199 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "visibility.h"
+#include "request.h"
+
+/* 4 separate strings are needed in order to ease translators' job */
+#define APPEAR_ONLINE		N_("Appear Online")
+#define DONT_APPEAR_ONLINE	N_("Don't Appear Online")
+#define APPEAR_OFFLINE		N_("Appear Offline")
+#define DONT_APPEAR_OFFLINE	N_("Don't Appear Offline")
+
+static guint16
+get_buddy_list_type(OscarData *od)
+{
+	PurpleAccount *account = purple_connection_get_account(od->gc);
+	return purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE) ? AIM_SSI_TYPE_PERMIT : AIM_SSI_TYPE_DENY;
+}
+
+static gboolean
+is_buddy_on_list(OscarData *od, const char *bname)
+{
+	return aim_ssi_itemlist_finditem(od->ssi.local, NULL, bname, get_buddy_list_type(od)) != NULL;
+}
+
+static void
+visibility_cb(PurpleBlistNode *node, gpointer whatever)
+{
+	PurpleBuddy *buddy = PURPLE_BUDDY(node);
+	const char* bname = purple_buddy_get_name(buddy);
+	OscarData *od = purple_connection_get_protocol_data(purple_account_get_connection(purple_buddy_get_account(buddy)));
+	guint16 list_type = get_buddy_list_type(od);
+
+	if (!is_buddy_on_list(od, bname)) {
+		aim_ssi_add_to_private_list(od, bname, list_type);
+	} else {
+		aim_ssi_del_from_private_list(od, bname, list_type);
+	}
+}
+
+PurpleMenuAction *
+create_visibility_menu_item(OscarData *od, const char *bname)
+{
+	PurpleAccount *account = purple_connection_get_account(od->gc);
+	gboolean invisible = purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE);
+	gboolean on_list = is_buddy_on_list(od, bname);
+	const gchar *label;
+
+	if (invisible) {
+		label = on_list ? _(DONT_APPEAR_ONLINE) : _(APPEAR_ONLINE);
+	} else {
+		label = on_list ? _(DONT_APPEAR_OFFLINE) : _(APPEAR_OFFLINE);
+	}
+	return purple_menu_action_new(label, PURPLE_CALLBACK(visibility_cb), NULL, NULL);
+}
+
+typedef void (*ShowDialog)(PurplePluginAction *);
+
+struct list_remove_data
+{
+	PurplePluginAction *action;
+	ShowDialog show_dialog_again;
+	OscarData *od;
+	guint16 list_type;
+	const gchar *list_name;
+};
+
+static void
+list_remove_cb(struct list_remove_data *data, PurpleRequestFields *fields)
+{
+	ShowDialog show_dialog_again = data->show_dialog_again;
+	PurplePluginAction *action = data->action;
+	PurpleRequestField *field = purple_request_fields_get_field(fields, "list-items");
+	GList *sels = purple_request_field_list_get_selected(field);
+	for (; sels; sels = sels->next) {
+		const gchar *name = sels->data;
+		const gchar *bname = purple_request_field_list_get_data(field, name);
+
+		purple_debug_info("oscar", "Removing %s from %s\n", bname, data->list_name);
+
+		aim_ssi_del_from_private_list(data->od, bname, data->list_type);
+	}
+
+	g_free(data);
+	show_dialog_again(action);
+}
+
+static void
+list_close_cb(struct list_remove_data *data, gpointer ignored)
+{
+	g_free(data);
+}
+
+static void
+show_private_list(PurplePluginAction *action,
+		  guint16 list_type,
+		  const gchar *list_name,
+		  const gchar *list_description,
+		  const gchar *menu_action_name,
+		  ShowDialog caller)
+{
+	PurpleConnection *gc = (PurpleConnection *) action->context;
+	OscarData *od = purple_connection_get_protocol_data(gc);
+	PurpleAccount *account = purple_connection_get_account(gc);
+	GSList *buddies, *cur;
+	gchar *desc;
+	struct list_remove_data *data;
+
+	PurpleRequestField *field;
+	PurpleRequestFields *fields = purple_request_fields_new();
+	PurpleRequestFieldGroup *group = purple_request_field_group_new(NULL);
+
+	purple_request_fields_add_group(fields, group);
+
+	desc = g_strdup_printf(_("You can add a buddy to this list "
+				 "by right-clicking on them and "
+				 "selecting \"%s\""), menu_action_name);
+
+	field = purple_request_field_list_new("list-items", desc);
+	g_free(desc);
+
+	purple_request_field_group_add_field(group, field);
+
+	purple_request_field_list_set_multi_select(field, TRUE);
+	purple_request_field_set_required(field, TRUE);
+
+	buddies = purple_find_buddies(account, NULL);
+	for (cur = buddies; cur != NULL; cur = cur->next) {
+		PurpleBuddy *buddy;
+		const gchar *bname;
+
+		buddy = cur->data;
+		bname = purple_buddy_get_name(buddy);
+		if (aim_ssi_itemlist_finditem(od->ssi.local, NULL, bname, list_type)) {
+			const gchar *alias = purple_buddy_get_alias_only(buddy);
+			char *dname = alias ? g_strdup_printf("%s (%s)", bname, alias) : NULL;
+			purple_request_field_list_add(field, dname ? dname : bname, (void *)bname);
+			g_free(dname);
+		}
+	}
+
+	g_slist_free(buddies);
+
+	data = g_new0(struct list_remove_data, 1);
+	data->action = action;
+	data->show_dialog_again = caller;
+	data->od = od;
+	data->list_type = list_type;
+	data->list_name = list_name;
+
+	purple_request_fields(gc, list_name, list_description, NULL,
+			      fields,
+			      _("Close"), G_CALLBACK(list_close_cb),
+			      _("Remove"), G_CALLBACK(list_remove_cb),
+			      account, NULL, NULL,
+			      data);
+}
+
+void
+oscar_show_visible_list(PurplePluginAction *action)
+{
+	show_private_list(action,
+			  AIM_SSI_TYPE_PERMIT,
+			  _("Visible List"),
+			  _("These buddies will see "
+			    "your status when you switch "
+			    "to \"Invisible\""),
+			  _(APPEAR_ONLINE),
+			  oscar_show_visible_list);
+}
+
+void
+oscar_show_invisible_list(PurplePluginAction *action)
+{
+	show_private_list(action,
+			  AIM_SSI_TYPE_DENY,
+			  _("Invisible List"),
+			  _("These buddies will always see you as offline"),
+			  _(APPEAR_OFFLINE),
+			  oscar_show_invisible_list);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/visibility.h	Wed Aug 25 19:12:08 2010 +0000
@@ -0,0 +1,32 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+*/
+
+#ifndef _VISIBILITY_H_
+#define _VISIBILITY_H_
+
+#include "oscar.h"
+#include "plugin.h"
+#include "util.h"
+
+PurpleMenuAction * create_visibility_menu_item(OscarData *od, const char *bname);
+void oscar_show_visible_list(PurplePluginAction *action);
+void oscar_show_invisible_list(PurplePluginAction *action);
+
+#endif
\ No newline at end of file
--- a/libpurple/protocols/qq/char_conv.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/qq/char_conv.c	Wed Aug 25 19:12:08 2010 +0000
@@ -37,7 +37,7 @@
 
 /* convert a string from from_charset to to_charset, using g_convert */
 /* Warning: do not return NULL */
-static gchar *do_convert(const gchar *str, gssize len, const gchar *to_charset, const gchar *from_charset)
+static gchar *do_convert(const gchar *str, gssize len, guint8 *out_len, const gchar *to_charset, const gchar *from_charset)
 {
 	GError *error = NULL;
 	gchar *ret;
@@ -48,6 +48,8 @@
 	ret = g_convert(str, len, to_charset, from_charset, &byte_read, &byte_write, &error);
 
 	if (error == NULL) {
+		if (out_len)
+			*out_len = byte_write;
 		return ret;	/* convert is OK */
 	}
 
@@ -67,7 +69,8 @@
  */
 gint qq_get_vstr(gchar **ret, const gchar *from_charset, guint8 *data)
 {
-	guint8 len;
+	gssize len;
+	guint8 out_len;
 
 	g_return_val_if_fail(data != NULL && from_charset != NULL, -1);
 
@@ -76,9 +79,9 @@
 		*ret = g_strdup("");
 		return 1;
 	}
-	*ret = do_convert((gchar *) (data + 1), (gssize) len, UTF8, from_charset);
+	*ret = do_convert((gchar *) (data + 1), len, &out_len, UTF8, from_charset);
 
-	return len + 1;
+	return out_len + 1;
 }
 
 gint qq_put_vstr(guint8 *buf, const gchar *str_utf8, const gchar *to_charset)
@@ -86,12 +89,11 @@
 	gchar *str;
 	guint8 len;
 
-	if (str_utf8 == NULL || (len = strlen(str_utf8)) == 0) {
+	if (str_utf8 == NULL || str_utf8[0] == '\0') {
 		buf[0] = 0;
 		return 1;
 	}
-	str = do_convert(str_utf8, -1, to_charset, UTF8);
-	len = strlen(str_utf8);
+	str = do_convert(str_utf8, -1, &len, to_charset, UTF8);
 	buf[0] = len;
 	if (len > 0) {
 		memcpy(buf + 1, str, len);
@@ -102,12 +104,12 @@
 /* Warning: do not return NULL */
 gchar *utf8_to_qq(const gchar *str, const gchar *to_charset)
 {
-	return do_convert(str, -1, to_charset, UTF8);
+	return do_convert(str, -1, NULL, to_charset, UTF8);
 }
 
 /* Warning: do not return NULL */
 gchar *qq_to_utf8(const gchar *str, const gchar *from_charset)
 {
-	return do_convert(str, -1, UTF8, from_charset);
+	return do_convert(str, -1, NULL, UTF8, from_charset);
 }
 
--- a/libpurple/protocols/qq/qq.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/qq/qq.c	Wed Aug 25 19:12:08 2010 +0000
@@ -382,12 +382,10 @@
 {
 	PurpleAccount *account;
 	PurpleConnection *gc;
-	qq_data *qd;
 	qq_buddy_data *buddy;
 
 	if (!b || !(account = purple_buddy_get_account(b)) ||
-		!(gc = purple_account_get_connection(account)) ||
-		!(qd = purple_connection_get_protocol_data(gc)))
+		!(gc = purple_account_get_connection(account)))
 		return NULL;
 
 	buddy = purple_buddy_get_protocol_data(b);
--- a/libpurple/protocols/qq/qq_trans.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/qq/qq_trans.c	Wed Aug 25 19:12:08 2010 +0000
@@ -138,10 +138,11 @@
 /* Remove a packet with seq from send trans */
 static void trans_remove(PurpleConnection *gc, qq_transaction *trans)
 {
-	qq_data *qd = (qq_data *)gc->proto_data;
+	qq_data *qd;
 
-	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+	g_return_if_fail(gc != NULL);
 	qd = (qq_data *) gc->proto_data;
+	g_return_if_fail(qd != NULL);
 
 	g_return_if_fail(trans != NULL);
 #if 0
--- a/libpurple/protocols/yahoo/libymsg.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/yahoo/libymsg.c	Wed Aug 25 19:12:08 2010 +0000
@@ -502,8 +502,6 @@
 	char *temp = NULL;
 	YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */
 	                       /* But what if you had no friends? */
-	PurpleBuddy *b;
-	PurpleGroup *g;
 	YahooFederation fed = YAHOO_FEDERATION_NONE;
 	int stealth = 0;
 
@@ -549,7 +547,9 @@
 				if (yd->current_list15_grp) {
 					/* This buddy is in a group */
 					f = yahoo_friend_find_or_new(gc, norm_bud);
-					if (!(b = purple_find_buddy(account, norm_bud))) {
+					if (!purple_find_buddy(account, norm_bud)) {
+						PurpleBuddy *b;
+						PurpleGroup *g;
 						if (!(g = purple_find_group(yd->current_list15_grp))) {
 							g = purple_group_new(yd->current_list15_grp);
 							purple_blist_add_group(g, NULL);
@@ -636,8 +636,6 @@
 	GSList *l = pkt->hash;
 	gboolean export = FALSE;
 	gboolean got_serv_list = FALSE;
-	PurpleBuddy *b;
-	PurpleGroup *g;
 	YahooFriend *f = NULL;
 	PurpleAccount *account = purple_connection_get_account(gc);
 	YahooData *yd = gc->proto_data;
@@ -705,7 +703,9 @@
 				norm_bud = g_strdup(purple_normalize(account, *bud));
 				f = yahoo_friend_find_or_new(gc, norm_bud);
 
-				if (!(b = purple_find_buddy(account, norm_bud))) {
+				if (!purple_find_buddy(account, norm_bud)) {
+					PurpleBuddy *b;
+					PurpleGroup *g;
 					if (!(g = purple_find_group(grp))) {
 						g = purple_group_new(grp);
 						purple_blist_add_group(g, NULL);
@@ -3806,13 +3806,12 @@
 {
 	PurpleAccount *account;
 	PurpleConnection *gc;
-	YahooData *yd;
 	YahooFriend *f;
 	PurplePresence *presence;
 
 	if (!b || !(account = purple_buddy_get_account(b)) ||
 			!(gc = purple_account_get_connection(account)) ||
-			!(yd = gc->proto_data))
+			!gc->proto_data)
 		return NULL;
 
 	f = yahoo_friend_find(gc, purple_buddy_get_name(b));
--- a/libpurple/protocols/yahoo/yahoo_aliases.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoo_aliases.c	Wed Aug 25 19:12:08 2010 +0000
@@ -145,7 +145,7 @@
 					if (alias != NULL) {
 						serv_got_alias(gc, yid, alias);
 						purple_debug_info("yahoo", "Fetched alias '%s' (%s)\n", alias, id);
-					} else if (buddy_alias != NULL && strcmp(buddy_alias, "") != 0) {
+					} else if (buddy_alias && *buddy_alias && !g_str_equal(buddy_alias, yid)) {
 					/* Or if we have an alias that Yahoo doesn't, send it up */
 						yahoo_update_alias(gc, yid, buddy_alias);
 						purple_debug_info("yahoo", "Sent updated alias '%s'\n", buddy_alias);
--- a/libpurple/protocols/yahoo/yahoochat.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoochat.c	Wed Aug 25 19:12:08 2010 +0000
@@ -121,7 +121,6 @@
 	char *msg = NULL;
 	GString *members = NULL;
 	GHashTable *components;
-	PurpleConversation *c = NULL;
 
 	if ( (pkt->status == 2) || (pkt->status == 11) )
 		return; /* Status is 11 when we are being notified about invitation being sent to someone else */
@@ -133,7 +132,7 @@
 		if (pair->key == 57)
 		{
 			room = yahoo_string_decode(gc, pair->value, FALSE);
-			if((c = yahoo_find_conference(gc, room)))
+			if (yahoo_find_conference(gc, room) != NULL)
 			{
 				/* Looks like we got invited to an already open conference. */
 				/* Laters: Should we accept this conference rather than ignoring the invitation ? */
@@ -880,7 +879,6 @@
 {
 	YahooData *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
-	PurpleConversation *c;
 
 	char *eroom;
 	gboolean utf8 = 1;
@@ -905,7 +903,7 @@
 		yd->chat_name = NULL;
 	}
 
-	if ((c = purple_find_chat(gc, YAHOO_CHAT_ID)))
+	if (purple_find_chat(gc, YAHOO_CHAT_ID) != NULL)
 		serv_got_chat_left(gc, YAHOO_CHAT_ID);
 
 	if (!logout)
--- a/libpurple/proxy.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/libpurple/proxy.c	Wed Aug 25 19:12:08 2010 +0000
@@ -1023,7 +1023,7 @@
 
 				g_free(response);
 
-			} else if((header = g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: Basic"))) {
+			} else if (g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: Basic") != NULL) {
 				gchar *t1, *t2;
 				const char *username, *password;
 
--- a/pidgin/gtkaccount.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/pidgin/gtkaccount.c	Wed Aug 25 19:12:08 2010 +0000
@@ -2418,35 +2418,38 @@
 	g_free(buffer);
 }
 
-struct auth_and_add {
+struct auth_request
+{
 	PurpleAccountRequestAuthorizationCb auth_cb;
 	PurpleAccountRequestAuthorizationCb deny_cb;
 	void *data;
 	char *username;
 	char *alias;
 	PurpleAccount *account;
+	gboolean add_buddy_after_auth;
 };
 
 static void
-free_auth_and_add(struct auth_and_add *aa)
+free_auth_request(struct auth_request *ar)
 {
-	g_free(aa->username);
-	g_free(aa->alias);
-	g_free(aa);
+	g_free(ar->username);
+	g_free(ar->alias);
+	g_free(ar);
 }
 
 static void
-authorize_and_add_cb(struct auth_and_add *aa)
+authorize_and_add_cb(struct auth_request *ar)
 {
-	aa->auth_cb(aa->data);
-	purple_blist_request_add_buddy(aa->account, aa->username,
-	 	                    NULL, aa->alias);
+	ar->auth_cb(ar->data);
+	if (ar->add_buddy_after_auth) {
+		purple_blist_request_add_buddy(ar->account, ar->username, NULL, ar->alias);
+	}
 }
 
 static void
-deny_no_add_cb(struct auth_and_add *aa)
+deny_no_add_cb(struct auth_request *ar)
 {
-	aa->deny_cb(aa->data);
+	ar->deny_cb(ar->data);
 }
 
 static void *
@@ -2463,49 +2466,48 @@
 	char *buffer;
 	PurpleConnection *gc;
 	GtkWidget *alert;
+	GdkPixbuf *prpl_icon;
+	struct auth_request *aa;
 
 	gc = purple_account_get_connection(account);
 	if (message != NULL && *message == '\0')
 		message = NULL;
 
-	buffer = g_strdup_printf(_("%s%s%s%s wants to add %s to his or her buddy list%s%s"),
+	buffer = g_strdup_printf(_("%s%s%s%s wants to add you (%s) to his or her buddy list%s%s"),
 				remote_user,
-	 	                (alias != NULL ? " ("  : ""),
-		                (alias != NULL ? alias : ""),
-		                (alias != NULL ? ")"   : ""),
-		                (id != NULL
-		                ? id
-		                : (purple_connection_get_display_name(gc) != NULL
-		                ? purple_connection_get_display_name(gc)
-		                : purple_account_get_username(account))),
-		                (message != NULL ? ": " : "."),
-		                (message != NULL ? message  : ""));
-
-
-	if (!on_list) {
-		struct auth_and_add *aa = g_new0(struct auth_and_add, 1);
-		aa->auth_cb = auth_cb;
-		aa->deny_cb = deny_cb;
-		aa->data = user_data;
-		aa->username = g_strdup(remote_user);
-		aa->alias = g_strdup(alias);
-		aa->account = account;
-		alert = pidgin_make_mini_dialog(gc, PIDGIN_STOCK_DIALOG_QUESTION,
-						  _("Authorize buddy?"), buffer, aa,
-						  _("Authorize"), authorize_and_add_cb,
-						  _("Deny"), deny_no_add_cb,
-						  NULL);
-		g_signal_connect_swapped(G_OBJECT(alert), "destroy", G_CALLBACK(free_auth_and_add), aa);
-	} else {
-		alert = pidgin_make_mini_dialog(gc, PIDGIN_STOCK_DIALOG_QUESTION,
-						  _("Authorize buddy?"), buffer, user_data,
-						  _("Authorize"), auth_cb,
-						  _("Deny"), deny_cb,
-						  NULL);
-	}
+				(alias != NULL ? " ("  : ""),
+				(alias != NULL ? alias : ""),
+				(alias != NULL ? ")"   : ""),
+				(id != NULL
+				? id
+				: (purple_connection_get_display_name(gc) != NULL
+				? purple_connection_get_display_name(gc)
+				: purple_account_get_username(account))),
+				(message != NULL ? ": " : "."),
+				(message != NULL ? message  : ""));
+
+
+	prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
+	
+	aa = g_new0(struct auth_request, 1);
+	aa->auth_cb = auth_cb;
+	aa->deny_cb = deny_cb;
+	aa->data = user_data;
+	aa->username = g_strdup(remote_user);
+	aa->alias = g_strdup(alias);
+	aa->account = account;
+	aa->add_buddy_after_auth = !on_list;
+	
+	alert = pidgin_make_mini_dialog_with_custom_icon(
+		gc, prpl_icon,
+		_("Authorize buddy?"), buffer, aa,
+		_("Authorize"), authorize_and_add_cb,
+		_("Deny"), deny_no_add_cb,
+		NULL);
+	
+	g_signal_connect_swapped(G_OBJECT(alert), "destroy", G_CALLBACK(free_auth_request), aa);
+	g_signal_connect(G_OBJECT(alert), "destroy", G_CALLBACK(purple_account_request_close), NULL);
 	pidgin_blist_add_alert(alert);
-	g_signal_connect(G_OBJECT(alert), "destroy",
-		G_CALLBACK(purple_account_request_close), NULL);
 
 	g_free(buffer);
 
--- a/pidgin/gtkblist.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/pidgin/gtkblist.c	Wed Aug 25 19:12:08 2010 +0000
@@ -3168,7 +3168,6 @@
 	} else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
 		PurpleBlistNode *child;
 		PurpleBuddy *b = purple_contact_get_priority_buddy((PurpleContact *)node);
-		width = height = 0;
 
 		for(child = node->child; child; child = child->next)
 		{
--- a/pidgin/gtksourceundomanager.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/pidgin/gtksourceundomanager.c	Wed Aug 25 19:12:08 2010 +0000
@@ -963,7 +963,7 @@
  * 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 successful, %FALSE otherwise.
+ * Return Value: %TRUE is merge was successful, %FALSE otherwise.
  **/
 static gboolean
 gtk_source_undo_manager_merge_action (GtkSourceUndoManager 	*um,
--- a/pidgin/gtkutils.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/pidgin/gtkutils.c	Wed Aug 25 19:12:08 2010 +0000
@@ -1036,7 +1036,7 @@
 	char *username = NULL;
 	char *alias    = NULL;
 	char *str;
-	char *c, *s;
+	char *s;
 	gboolean valid;
 
 	g_return_val_if_fail(msg          != NULL, FALSE);
@@ -1078,7 +1078,7 @@
 		if (*s == '\r') *s++ = '\0';
 		if (*s == '\n') *s++ = '\0';
 
-		if ((c = strchr(key, ':')) != NULL)
+		if (strchr(key, ':') != NULL)
 		{
 			if (!g_ascii_strcasecmp(key, "X-IM-Username:"))
 				username = g_strdup(value);
@@ -2611,18 +2611,11 @@
 	}
 }
 
-GtkWidget *
-pidgin_make_mini_dialog(PurpleConnection *gc,
-                        const char *icon_name,
-                        const char *primary,
-                        const char *secondary,
-                        void *user_data,
-                        ...)
+static void
+mini_dialog_init(PidginMiniDialog *mini_dialog, PurpleConnection *gc, void *user_data, va_list args)
 {
-	PidginMiniDialog *mini_dialog;
 	const char *button_text;
 	GList *cb_datas = NULL;
-	va_list args;
 	static gboolean first_call = TRUE;
 
 	if (first_call) {
@@ -2632,12 +2625,10 @@
 		                      PURPLE_CALLBACK(connection_signed_off_cb), NULL);
 	}
 
-	mini_dialog = pidgin_mini_dialog_new(primary, secondary, icon_name);
 	g_object_set_data(G_OBJECT(mini_dialog), "gc" ,gc);
 	g_signal_connect(G_OBJECT(mini_dialog), "destroy",
 		G_CALLBACK(alert_killed_cb), NULL);
 
-	va_start(args, user_data);
 	while ((button_text = va_arg(args, char*))) {
 		struct _old_button_clicked_cb_data *data = NULL;
 		PidginMiniDialogCallback wrapper_cb = NULL;
@@ -2654,12 +2645,40 @@
 			wrapper_cb, data);
 		cb_datas = g_list_append(cb_datas, data);
 	}
-	va_end(args);
 
 	g_signal_connect(G_OBJECT(mini_dialog), "destroy",
 		G_CALLBACK(old_mini_dialog_destroy_cb), cb_datas);
-
+}
+
+#define INIT_AND_RETURN_MINI_DIALOG(mini_dialog) \
+	va_list args; \
+	va_start(args, user_data); \
+	mini_dialog_init(mini_dialog, gc, user_data, args); \
+	va_end(args); \
 	return GTK_WIDGET(mini_dialog);
+
+GtkWidget *
+pidgin_make_mini_dialog(PurpleConnection *gc,
+                        const char *icon_name,
+                        const char *primary,
+                        const char *secondary,
+                        void *user_data,
+                        ...)
+{
+	PidginMiniDialog *mini_dialog = pidgin_mini_dialog_new(primary, secondary, icon_name);
+	INIT_AND_RETURN_MINI_DIALOG(mini_dialog);
+}
+
+GtkWidget *
+pidgin_make_mini_dialog_with_custom_icon(PurpleConnection *gc,
+					GdkPixbuf *custom_icon,
+					const char *primary,
+					const char *secondary,
+					void *user_data,
+					...)
+{
+	PidginMiniDialog *mini_dialog = pidgin_mini_dialog_new_with_custom_icon(primary, secondary, custom_icon);
+	INIT_AND_RETURN_MINI_DIALOG(mini_dialog);
 }
 
 /*
--- a/pidgin/gtkutils.h	Wed Aug 25 19:11:38 2010 +0000
+++ b/pidgin/gtkutils.h	Wed Aug 25 19:12:08 2010 +0000
@@ -718,6 +718,17 @@
 	void *user_data, ...) G_GNUC_NULL_TERMINATED;
 
 /**
+ * Does exactly what pidgin_make_mini_dialog() does, except you can specify
+ * a custom icon for the dialog.
+ */
+GtkWidget *pidgin_make_mini_dialog_with_custom_icon(PurpleConnection *gc,
+	GdkPixbuf *custom_icon,
+	const char *primary,
+	const char *secondary,
+	void *user_data,
+	...) G_GNUC_NULL_TERMINATED;
+
+/**
  * This is a callback function to be used for Ctrl+F searching in treeviews.
  * Sample Use:
  * 		gtk_tree_view_set_search_equal_func(treeview,
--- a/pidgin/minidialog.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/pidgin/minidialog.c	Wed Aug 25 19:12:08 2010 +0000
@@ -75,6 +75,7 @@
 	PROP_TITLE = 1,
 	PROP_DESCRIPTION,
 	PROP_ICON_NAME,
+	PROP_CUSTOM_ICON,
 
 	LAST_PROPERTY
 } HazeConnectionProperties;
@@ -93,17 +94,32 @@
 #define PIDGIN_MINI_DIALOG_GET_PRIVATE(dialog) \
 	((PidginMiniDialogPrivate *) ((dialog)->priv))
 
+static PidginMiniDialog *
+mini_dialog_new(const gchar *title, const gchar *description)
+{
+	return g_object_new(PIDGIN_TYPE_MINI_DIALOG,
+		"title", title,
+		"description", description,
+		NULL);
+}
+
 PidginMiniDialog *
 pidgin_mini_dialog_new(const gchar *title,
                        const gchar *description,
                        const gchar *icon_name)
 {
-	PidginMiniDialog *mini_dialog = g_object_new(PIDGIN_TYPE_MINI_DIALOG,
-		"title", title,
-		"description", description,
-		"icon-name", icon_name,
-		NULL);
+	PidginMiniDialog *mini_dialog = mini_dialog_new(title, description);
+	pidgin_mini_dialog_set_icon_name(mini_dialog, icon_name);
+	return mini_dialog;
+}
 
+PidginMiniDialog *
+pidgin_mini_dialog_new_with_custom_icon(const gchar *title,
+					const gchar *description,
+					GdkPixbuf *custom_icon)
+{
+	PidginMiniDialog *mini_dialog = mini_dialog_new(title, description);
+	pidgin_mini_dialog_set_custom_icon(mini_dialog, custom_icon);
 	return mini_dialog;
 }
 
@@ -125,7 +141,13 @@
 pidgin_mini_dialog_set_icon_name(PidginMiniDialog *mini_dialog,
                                  const char *icon_name)
 {
-	g_object_set(G_OBJECT(mini_dialog), "icon_name", icon_name, NULL);
+	g_object_set(G_OBJECT(mini_dialog), "icon-name", icon_name, NULL);
+}
+
+void
+pidgin_mini_dialog_set_custom_icon(PidginMiniDialog *mini_dialog, GdkPixbuf *custom_icon)
+{
+	g_object_set(G_OBJECT(mini_dialog), "custom-icon", custom_icon, NULL);
 }
 
 struct _mini_dialog_button_clicked_cb_data
@@ -233,6 +255,9 @@
 			g_value_set_string(value, icon_name);
 			break;
 		}
+		case PROP_CUSTOM_ICON:
+			g_value_set_object(value, gtk_image_get_pixbuf(priv->icon));
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 	}
@@ -305,6 +330,8 @@
 			gtk_image_set_from_stock(priv->icon, g_value_get_string(value),
 				gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
 			break;
+		case PROP_CUSTOM_ICON:
+			gtk_image_set_from_pixbuf(priv->icon, g_value_get_object(value));
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 	}
@@ -355,6 +382,13 @@
 		G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
 		G_PARAM_READWRITE);
 	g_object_class_install_property (object_class, PROP_ICON_NAME, param_spec);
+	
+	param_spec = g_param_spec_object("custom-icon", "custom-icon",
+		"Pixbuf to use as the dialog's icon",
+		GDK_TYPE_PIXBUF,
+		G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+		G_PARAM_READWRITE);
+	g_object_class_install_property (object_class, PROP_CUSTOM_ICON, param_spec);
 }
 
 /* 16 is the width of the icon, due to PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL */
--- a/pidgin/minidialog.h	Wed Aug 25 19:11:38 2010 +0000
+++ b/pidgin/minidialog.h	Wed Aug 25 19:12:08 2010 +0000
@@ -73,6 +73,8 @@
  *   <dd>The Gtk stock id of an icon for the dialog, or @c NULL for no icon.
  *       @see pidginstock.h
  *   </dd>
+ *   <dt><tt>"custom-icon"</tt> (<tt>GdkPixbuf *</tt>)</dt>
+ *   <dd>The custom icon to use instead of a stock one (overrides the "icon-name" property).</dd>
  * </dl>
  */
 typedef struct {
@@ -108,13 +110,20 @@
 /** Get the GType of #PidginMiniDialog. */
 GType pidgin_mini_dialog_get_type (void);
 
-/** Creates a new #PidginMiniDialog.  This is a shortcut for creating the dialog
+/** Creates a new #PidginMiniDialog with a stock icon. This is a shortcut for creating the dialog
  *  with @c g_object_new() then setting each property yourself.
  *  @return a new #PidginMiniDialog.
  */
 PidginMiniDialog *pidgin_mini_dialog_new(const gchar *title,
 	const gchar *description, const gchar *icon_name);
 
+/** Creates a new #PidginMiniDialog with a custom icon. This is a shortcut for creating the dialog
+ *  with @c g_object_new() then setting each property yourself.
+ *  @return a new #PidginMiniDialog.
+ */
+PidginMiniDialog *pidgin_mini_dialog_new_with_custom_icon(const gchar *title,
+	const gchar *description, GdkPixbuf *custom_icon);
+
 /** Shortcut for setting a mini-dialog's title via GObject properties.
  *  @param mini_dialog a mini-dialog
  *  @param title       the new title for @a mini_dialog
@@ -137,6 +146,13 @@
 void pidgin_mini_dialog_set_icon_name(PidginMiniDialog *mini_dialog,
 	const char *icon_name);
 
+/** Shortcut for setting a mini-dialog's custom icon via GObject properties.
+ *  @param mini_dialog a mini-dialog
+ *  @param icon_name   the pixbuf to use as a custom icon
+ */
+void pidgin_mini_dialog_set_custom_icon(PidginMiniDialog *mini_dialog,
+	GdkPixbuf *custom_icon);
+
 /** Adds a new button to a mini-dialog, and attaches the supplied callback to
  *  its <tt>clicked</tt> signal.  After a button is clicked, the dialog is
  *  destroyed.
--- a/pidgin/plugins/xmppconsole.c	Wed Aug 25 19:11:38 2010 +0000
+++ b/pidgin/plugins/xmppconsole.c	Wed Aug 25 19:12:08 2010 +0000
@@ -183,7 +183,7 @@
 {
 	GtkTextIter start, end;
 	PurplePluginProtocolInfo *prpl_info = NULL;
-	PurpleConnection *gc = console->gc;
+	PurpleConnection *gc;
 	GtkTextBuffer *buffer;
 	char *text;
 
--- a/po/hu.po	Wed Aug 25 19:11:38 2010 +0000
+++ b/po/hu.po	Wed Aug 25 19:12:08 2010 +0000
@@ -9,14 +9,14 @@
 msgstr ""
 "Project-Id-Version: pidgin 2.7\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-07-27 01:17-0400\n"
-"PO-Revision-Date: 2010-05-29 02:36+0200\n"
+"POT-Creation-Date: 2010-08-15 21:49+0200\n"
+"PO-Revision-Date: 2010-08-15 21:48+0200\n"
 "Last-Translator: Gabor Kelemen <kelemeng at gnome dot hu>\n"
 "Language-Team: Hungarian <gnome at fsf dot hu>\n"
-"Language: \n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"Language: \n"
 "Plural-Forms:  nplurals=2; plural=(n != 1);\n"
 "X-Generator: KBabel 1.11.4\n"
 
@@ -64,9 +64,8 @@
 msgid "Error"
 msgstr "Hiba"
 
-#, fuzzy
 msgid "Account was not modified"
-msgstr "A fiók nem lett felvéve"
+msgstr "A fiók nem lett módosítva"
 
 msgid "Account was not added"
 msgstr "A fiók nem lett felvéve"
@@ -77,10 +76,13 @@
 msgid ""
 "The account's protocol cannot be changed while it is connected to the server."
 msgstr ""
+"A fiók protokollja nem módosítható, ha épp csatlakozva van a kiszolgálóhoz."
 
 msgid ""
 "The account's username cannot be changed while it is connected to the server."
 msgstr ""
+"A fiók felhasználóneve nem módosítható, ha épp csatlakozva van a "
+"kiszolgálóhoz."
 
 msgid "New mail notifications"
 msgstr "Értesítések új levélre"
@@ -691,7 +693,7 @@
 
 msgid "me &lt;action&gt;:  Send an IRC style action to a buddy or chat."
 msgstr ""
-"me &lt;művelet&gt;: IRC stílusú művelet küldése egy partnernak vagy "
+"me &lt;művelet&gt;: IRC stílusú művelet küldése egy partnernek vagy "
 "csevegésnek."
 
 msgid ""
@@ -1689,6 +1691,8 @@
 "The certificate is not valid yet.  Check that your computer's date and time "
 "are accurate."
 msgstr ""
+"A tanúsítvány még nem érvényes. Ellenőrizze a számítógép dátumának és "
+"idejének pontosságát."
 
 msgid "The certificate has expired and should not be considered valid."
 msgstr "A tanúsítvány lejárt és nem tekinthető érvényesnek."
@@ -3834,7 +3838,7 @@
 "this and continue authentication?"
 msgstr ""
 "%s szöveges hitelesítést követel meg egy nem titkosított csatornán. "
-"Engedélyezi ezt és folytatja a hitelesítést?"
+"Engedélyezi ezt, és folytatja a hitelesítést?"
 
 msgid "Plaintext Authentication"
 msgstr "Egyszerű szöveges hitelesítés"
@@ -3848,18 +3852,18 @@
 msgid "Server thinks authentication is complete, but client does not"
 msgstr "A kiszolgáló szerint a hitelesítés kész, a kliens szerint nem"
 
-#, fuzzy
 msgid "Server may require plaintext authentication over an unencrypted stream"
 msgstr ""
-"A kiszolgáló szöveges hitelesítést követel meg egy nem titkosított csatornán"
-
-#, fuzzy, c-format
+"A kiszolgáló egyszerű szöveges hitelesítést követel meg egy nem titkosított "
+"csatornán"
+
+#, c-format
 msgid ""
 "%s may require plaintext authentication over an unencrypted connection.  "
 "Allow this and continue authentication?"
 msgstr ""
-"%s szöveges hitelesítést követel meg egy nem titkosított csatornán. "
-"Engedélyezi ezt és folytatja a hitelesítést?"
+"%s egyszerű szöveges hitelesítést követelhet meg egy nem titkosított "
+"kapcsolaton. Engedélyezi ezt, és folytatja a hitelesítést?"
 
 msgid "SASL authentication failed"
 msgstr "A SASL hitelesítés meghiúsult"
@@ -5939,8 +5943,8 @@
 msgid "The two PINs you entered do not match."
 msgstr "A megadott két PIN nem egyezik."
 
-msgid "The name you entered is invalid."
-msgstr "A megadott név érvénytelen."
+msgid "The Display Name you entered is invalid."
+msgstr "A megadott megjelenő név érvénytelen."
 
 msgid ""
 "The birthday you entered is invalid. The correct format is: 'YYYY-MM-DD'."
@@ -5958,9 +5962,8 @@
 msgid "Your profile information is not yet retrieved. Please try again later."
 msgstr "A profilinformációi még nincsenek lekérve. Próbálja újra később."
 
-#, fuzzy
 msgid "Your UID"
-msgstr "Az Ön MXitId-ja"
+msgstr "Az Ön UID-ja"
 
 #. pin
 #. pin (required)
@@ -6032,16 +6035,12 @@
 msgid "Connecting..."
 msgstr "Kapcsolódás…"
 
-#, fuzzy
-msgid "The Display Name you entered is invalid."
-msgstr "A megadott név érvénytelen."
-
 msgid "The PIN you entered has an invalid length [7-10]."
 msgstr "A megadott PIN érvénytelen hosszúságú [7-10]."
 
 #. mxit login name
 msgid "MXit ID"
-msgstr ""
+msgstr "MXit azonosító"
 
 #. show the form to the user to complete
 msgid "Register New MXit Account"
@@ -6069,14 +6068,13 @@
 msgid "Invalid country selected. Please try again."
 msgstr "Érvénytelen országot választott. Próbálja újra később."
 
-#, fuzzy
 msgid "The MXit ID you entered is not registered. Please register first."
-msgstr "A felhasználónév nincs regisztrálva. Először regisztráljon."
-
-#, fuzzy
+msgstr "A megadott MXit azonosító nincs regisztrálva. Először regisztráljon."
+
 msgid "The MXit ID you entered is already registered. Please choose another."
 msgstr ""
-"A felhasználónév már használatban van. Válasszon másik felhasználónevet."
+"A megadott MXit azonosító már használatban van. Válasszon másik "
+"felhasználónevet."
 
 msgid "Internal error. Please try again later."
 msgstr "Belső hiba. Próbálja újra később."
@@ -6120,9 +6118,8 @@
 msgid "Hidden Number"
 msgstr "Rejtett szám"
 
-#, fuzzy
 msgid "Your MXit ID..."
-msgstr "Az Ön MXitId-ja"
+msgstr "Az Ön MXit ID-ja…"
 
 #. Configuration options
 #. WAP server (reference: "libpurple/accountopt.h")
@@ -6136,26 +6133,21 @@
 msgstr "Felugró indítókép engedélyezése"
 
 #. you were kicked
-#, fuzzy
 msgid "You have been kicked from this MultiMX."
-msgstr "Kirúgták Önt: (%s)"
-
-#, fuzzy
+msgstr "Kirúgták ebből a MultiMX-ből."
+
 msgid "was kicked"
-msgstr "Rossz jegy"
-
-#, fuzzy
+msgstr "kirúgva"
+
 msgid "_Room Name:"
-msgstr "Sz_oba:"
+msgstr "Sz_obanév:"
 
 #. Display system message in chat window
-#, fuzzy
 msgid "You have invited"
-msgstr "Levele érkezett!"
-
-#, fuzzy
+msgstr "Meghívták"
+
 msgid "Last Online"
-msgstr "Elérhető"
+msgstr "Utoljára elérhető"
 
 #. we must have lost the connection, so terminate it so that we can reconnect
 msgid "We have lost the connection to MXit. Please reconnect."
@@ -6727,8 +6719,8 @@
 #, c-format
 msgid "Unable to send message. Could not get details for user (%s)."
 msgstr ""
-"Az üzenetet nem lehet elküldeni. A felhasználó részletei nem kérhetőek le "
-"(%s)."
+"Az üzenetet nem lehet elküldeni. A felhasználó részletei nem kérhetőek le (%"
+"s)."
 
 #, c-format
 msgid "Unable to add %s to your buddy list (%s)."
@@ -7128,102 +7120,13 @@
 "%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"
 msgstr ""
-"%s egy %s fájlt próbált küldeni, de közvetlen kapcsolatban legfeljebb csak "
-"%s méretű fájl küldhető. Próbálkozzon inkább a fájlátvitellel.\n"
+"%s egy %s fájlt próbált küldeni, de közvetlen kapcsolatban legfeljebb csak %"
+"s méretű fájl küldhető. Próbálkozzon inkább a fájlátvitellel.\n"
 
 #, c-format
 msgid "File %s is %s, which is larger than the maximum size of %s."
 msgstr "A(z) %s fájl %s, amely nagyobb, mint a legnagyobb méret (%s)."
 
-msgid ""
-"(There was an error receiving this message.  The buddy you are speaking with "
-"is probably using a different encoding than expected.  If you know what "
-"encoding he is using, you can specify it in the advanced account options for "
-"your AIM/ICQ account.)"
-msgstr ""
-"(Hiba történt az üzenet fogadása során. A partner, akivel cseveg "
-"valószínűleg a várttól eltérő kódolást használ. Ha tudja, hogy a partner "
-"milyen kódolást használ, akkor megadhatja azt az AIM/ICQ fiók haladó "
-"fiókbeállításainál.)"
-
-#, c-format
-msgid ""
-"(There was an error receiving this message.  Either you and %s have "
-"different encodings selected, or %s has a buggy client.)"
-msgstr ""
-"(Hiba az üzenet fogadása közben. Lehetséges, hogy Ön és %s különböző "
-"kódolást használnak, vagy %s hibás klienst használ.)"
-
-#. Label
-msgid "Buddy Icon"
-msgstr "Partnerikon"
-
-msgid "Voice"
-msgstr "Hang"
-
-msgid "AIM Direct IM"
-msgstr "AIM közvetlen azonnali üzenetek"
-
-msgid "Get File"
-msgstr "Fájl letöltése"
-
-msgid "Games"
-msgstr "Játékok"
-
-msgid "ICQ Xtraz"
-msgstr "ICQ Xtraz"
-
-msgid "Add-Ins"
-msgstr "Kiegészítők"
-
-msgid "Send Buddy List"
-msgstr "Partnerlista küldése"
-
-msgid "ICQ Direct Connect"
-msgstr "ICQ közvetlen kapcsolat"
-
-msgid "AP User"
-msgstr "AP felhasználó"
-
-msgid "ICQ RTF"
-msgstr "ICQ RTF"
-
-msgid "Nihilist"
-msgstr "Nihilista"
-
-msgid "ICQ Server Relay"
-msgstr "ICQ közvetítő kiszolgáló"
-
-msgid "Old ICQ UTF8"
-msgstr "Régi ICQ UTF8"
-
-msgid "Trillian Encryption"
-msgstr "Trillian titkosítás"
-
-msgid "ICQ UTF8"
-msgstr "ICQ UTF8"
-
-msgid "Hiptop"
-msgstr "Hiptop"
-
-msgid "Security Enabled"
-msgstr "Biztonság engedélyezve"
-
-msgid "Video Chat"
-msgstr "Videócsevegés"
-
-msgid "iChat AV"
-msgstr "iChat AV"
-
-msgid "Live Video"
-msgstr "Élő videó"
-
-msgid "Camera"
-msgstr "Fényképezőgép"
-
-msgid "Screen Sharing"
-msgstr "Képernyőmegosztás"
-
 msgid "Free For Chat"
 msgstr "Ráérek csevegni"
 
@@ -7254,15 +7157,6 @@
 msgid "At lunch"
 msgstr "Ebédel"
 
-msgid "IP Address"
-msgstr "IP cím"
-
-msgid "Warning Level"
-msgstr "Figyelmeztetési szint"
-
-msgid "Buddy Comment"
-msgstr "Partnermegjegyzés"
-
 #, c-format
 msgid "Unable to connect to authentication server: %s"
 msgstr "Nem lehet kapcsolódni a hitelesítési kiszolgálóhoz: %s"
@@ -7361,15 +7255,6 @@
 msgid "Unable to initialize connection"
 msgstr "A kapcsolat nem inicializálható"
 
-msgid "Please authorize me so I can add you to my buddy list."
-msgstr "Kérem engedélyezze, hogy felvehessem a partnereim közé."
-
-msgid "No reason given."
-msgstr "Nincs ok megadva."
-
-msgid "Authorization Denied Message:"
-msgstr "Engedélyezést elutasító üzenet:"
-
 #, c-format
 msgid ""
 "The user %u has denied your request to add them to your buddy list for the "
@@ -7380,6 +7265,9 @@
 "következő indoklással:\n"
 "%s"
 
+msgid "No reason given."
+msgstr "Nincs ok megadva."
+
 msgid "ICQ authorization denied."
 msgstr "ICQ engedélyezés elutasítva."
 
@@ -7498,60 +7386,13 @@
 msgstr[0] "Nem kapott meg %hu üzenetet a következőtől: %s, ismeretlen okból."
 msgstr[1] "Nem kapott meg %hu üzenetet a következőtől: %s, ismeretlen okból."
 
-#, c-format
-msgid "User information not available: %s"
-msgstr "A felhasználó információi nem érhetőek el: %s"
-
-msgid "Online Since"
-msgstr "Kapcsolódva ezóta"
-
-msgid "Member Since"
-msgstr "Tagság kezdete"
-
-msgid "Capabilities"
-msgstr "Képességek"
-
 msgid "Your AIM connection may be lost."
 msgstr "Az AIM kapcsolata megszakadhatott."
 
-#. The conversion failed!
-msgid ""
-"[Unable to display a message from this user because it contained invalid "
-"characters.]"
-msgstr ""
-"[Nem lehet megjeleníteni az üzenetet ettől a felhasználótól, mert az "
-"érvénytelen karaktereket tartalmazott.]"
-
 #, c-format
 msgid "You have been disconnected from chat room %s."
 msgstr "Kilépett a(z) %s csevegőszobából."
 
-msgid "Mobile Phone"
-msgstr "Mobiltelefon"
-
-msgid "Personal Web Page"
-msgstr "Saját weboldal"
-
-#. aim_userinfo_t
-#. strip_html_tags
-msgid "Additional Information"
-msgstr "További információ"
-
-msgid "Zip Code"
-msgstr "Irányítószám"
-
-msgid "Work Information"
-msgstr "Munkahelyi adatok"
-
-msgid "Division"
-msgstr "Részleg"
-
-msgid "Position"
-msgstr "Pozíció"
-
-msgid "Web Page"
-msgstr "Weboldal"
-
 msgid "Pop-Up Message"
 msgstr "Felbukkanó üzenet"
 
@@ -7831,8 +7672,8 @@
 msgid "Change Address To:"
 msgstr "Cím módosítása a következőre:"
 
-msgid "<i>you are not waiting for authorization</i>"
-msgstr "<i>Ön nem vár engedélyezésre</i>"
+msgid "you are not waiting for authorization"
+msgstr "Ön nem vár engedélyezésre"
 
 msgid "You are awaiting authorization from the following buddies"
 msgstr "A következő partnerektől vár engedélyezésre"
@@ -7886,9 +7727,6 @@
 msgid "Search for Buddy by Email Address..."
 msgstr "Partner keresése e-mail cím szerint…"
 
-msgid "Search for Buddy by Information"
-msgstr "Partner keresése információ alapján"
-
 msgid "Use clientLogin"
 msgstr "Kliensbejelentkezés használata"
 
@@ -7929,85 +7767,74 @@
 "képekhez. Ezzel láthatóvá válik az IP címe, ami veszélyeztetheti a "
 "magánszférája biztonságát."
 
-#, fuzzy
 msgid "Invalid SNAC"
-msgstr "Érvénytelen azonosító"
+msgstr "Érvénytelen SNAC"
 
 msgid "Server rate limit exceeded"
-msgstr ""
+msgstr "A kiszolgáló sebességkorlátja túllépve"
 
 msgid "Client rate limit exceeded"
-msgstr ""
-
-#, fuzzy
+msgstr "A kliens sebességkorlátja túllépve"
+
 msgid "Service unavailable"
 msgstr "A szolgáltatás nem érhető el"
 
-#, fuzzy
 msgid "Service not defined"
-msgstr "A konferencia nem található"
+msgstr "A szolgáltatás nincs meghatározva"
 
 msgid "Obsolete SNAC"
-msgstr ""
-
-#, fuzzy
+msgstr "Elavult SNAC"
+
 msgid "Not supported by host"
-msgstr "Nem támogatott"
-
-#, fuzzy
+msgstr "A kiszolgáló nem támogatja"
+
 msgid "Not supported by client"
-msgstr "Nem támogatott"
+msgstr "A kliens nem támogatja"
 
 msgid "Refused by client"
-msgstr ""
+msgstr "A kliens visszautasította"
 
 msgid "Reply too big"
-msgstr ""
-
-#, fuzzy
+msgstr "A válasz túl nagy"
+
 msgid "Responses lost"
-msgstr "Válasz valószínűsége:"
-
-#, fuzzy
+msgstr "A válaszok elvesztek"
+
 msgid "Request denied"
-msgstr "Kérés"
+msgstr "A kérés elutasítva"
 
 msgid "Busted SNAC payload"
-msgstr ""
+msgstr "Sérült SNAC tartalom"
 
 msgid "Insufficient rights"
-msgstr ""
+msgstr "Elégtelen jogosultságok"
 
 msgid "In local permit/deny"
-msgstr ""
+msgstr "A helyi engedélyezésben/tiltásban"
 
 msgid "Warning level too high (sender)"
-msgstr ""
+msgstr "A figyelmeztetési szint túl magas (küldő)"
 
 msgid "Warning level too high (receiver)"
-msgstr ""
-
-#, fuzzy
+msgstr "A figyelmeztetési szint túl magas (fogadó)"
+
 msgid "User temporarily unavailable"
-msgstr "A szolgáltatás átmenetileg nem érhető el"
-
-#, fuzzy
+msgstr "A felhasználó átmenetileg nem érhető el"
+
 msgid "No match"
 msgstr "Nincs találat"
 
-#, fuzzy
 msgid "List overflow"
-msgstr "A lista megtelt"
-
-#, fuzzy
+msgstr "A lista túlcsordult"
+
 msgid "Request ambiguous"
-msgstr "Kérés"
+msgstr "A kérés kétértelmű"
 
 msgid "Queue full"
-msgstr ""
+msgstr "A sor tele"
 
 msgid "Not while on AOL"
-msgstr ""
+msgstr "Nem az AOL-on"
 
 msgid "Aquarius"
 msgstr "Vízöntő"
@@ -10064,6 +9891,9 @@
 msgid "Computer"
 msgstr "Számítógép"
 
+msgid "Mobile Phone"
+msgstr "Mobiltelefon"
+
 msgid "PDA"
 msgstr "PDA"
 
@@ -10232,9 +10062,8 @@
 msgid "Ignore conference and chatroom invitations"
 msgstr "Konferencia- és csevegőszoba-meghívások figyelmen kívül hagyása"
 
-#, fuzzy
 msgid "Use account proxy for HTTP and HTTPS connections"
-msgstr "Fiókproxy használata SSL kapcsolatokhoz"
+msgstr "Fiókproxy használata HTTP és HTTPS kapcsolatokhoz"
 
 msgid "Chat room list URL"
 msgstr "Csevegőszobák listájának URL címe"
@@ -10493,6 +10322,9 @@
 msgid "Write Error"
 msgstr "Írási hiba"
 
+msgid "IP Address"
+msgstr "IP cím"
+
 msgid "Yahoo! Japan Profile"
 msgstr "Yahoo! Japán profil"
 
@@ -10534,6 +10366,9 @@
 msgid "Cool Link 3"
 msgstr "Érdekes link 3"
 
+msgid "Member Since"
+msgstr "Tagság kezdete"
+
 msgid "Last Update"
 msgstr "Utolsó frissítés"
 
@@ -10762,8 +10597,8 @@
 #, c-format
 msgid "Access denied: HTTP proxy server forbids port %d tunneling"
 msgstr ""
-"Hozzáférés megtagadva: a HTTP proxy kiszolgáló tiltja az alagutazást a(z) "
-"%d. porton"
+"Hozzáférés megtagadva: a HTTP proxy kiszolgáló tiltja az alagutazást a(z) %"
+"d. porton"
 
 #, c-format
 msgid "Error resolving %s"
@@ -11016,8 +10851,8 @@
 "An error was encountered reading your %s.  The file has not been loaded, and "
 "the old file has been renamed to %s~."
 msgstr ""
-"Hiba történt a(z) %s olvasásakor. Ez a fájl nem lett betöltve, a régi fájl "
-"%s~ néven lett elmentve."
+"Hiba történt a(z) %s olvasásakor. Ez a fájl nem lett betöltve, a régi fájl %"
+"s~ néven lett elmentve."
 
 msgid ""
 "Chat over IM.  Supports AIM, Google Talk, Jabber/XMPP, MSN, Yahoo and more"
@@ -11154,6 +10989,10 @@
 "segítségével visszatérhet ehhez az ablakhoz fiókok hozzáadásához, "
 "szerkesztéséhez vagy eltávolításához."
 
+#, c-format
+msgid "%s%s%s%s wants to add you (%s) to his or her buddy list%s%s"
+msgstr "%s%s%s%s felhasználó szeretné Önt (%s) felvenni a partnerlistájára%s%s"
+
 #. Buddy List
 msgid "Background Color"
 msgstr "Háttérszín"
@@ -12437,8 +12276,8 @@
 "to multiple messaging services at once.  %s is written in C using GTK+.  %s "
 "is released, and may be modified and redistributed,  under the terms of the "
 "GPL version 2 (or later).  A copy of the GPL is distributed with %s.  %s is "
-"copyrighted by its contributors, a list of whom is also distributed with "
-"%s.  There is no warranty for %s.<BR><BR>"
+"copyrighted by its contributors, a list of whom is also distributed with %"
+"s.  There is no warranty for %s.<BR><BR>"
 msgstr ""
 "A %s egy libpurple alapú moduláris üzenetküldő kliens, amely egyszerre több "
 "üzenetküldő szolgáltatáshoz is képes csatlakozni. A %s GTK+ használatával, C "
@@ -12988,16 +12827,16 @@
 
 #, c-format
 msgid ""
-"Are you sure you want to permanently delete the log of the conversation in "
-"%s which started at %s?"
+"Are you sure you want to permanently delete the log of the conversation in %"
+"s which started at %s?"
 msgstr ""
 "Biztos, hogy törölni akarja a(z) %s csatornán folytatott, %s időpontban "
 "kezdődött beszélgetés naplóját?"
 
 #, c-format
 msgid ""
-"Are you sure you want to permanently delete the system log which started at "
-"%s?"
+"Are you sure you want to permanently delete the system log which started at %"
+"s?"
 msgstr ""
 "Biztos, hogy törölni akarja a(z) %s időpontban kezdődött rendszernaplót?"
 
@@ -13103,13 +12942,11 @@
 msgid "Exiting because another libpurple client is already running.\n"
 msgstr "Kilépés, mert már fut egy másik libpurple kliens.\n"
 
-#, fuzzy
 msgid "_Media"
-msgstr "/_Média"
-
-#, fuzzy
+msgstr "Méd_ia"
+
 msgid "_Hangup"
-msgstr "Lerakás"
+msgstr "_Lerakás"
 
 #, c-format
 msgid "%s wishes to start an audio/video session with you."
@@ -14016,6 +13853,10 @@
 "<b>Fájlméret:</b> %s\n"
 "<b>Képméret:</b> %dx%d"
 
+#. Label
+msgid "Buddy Icon"
+msgstr "Partnerikon"
+
 #, c-format
 msgid "The file '%s' is too large for %s.  Please try a smaller image.\n"
 msgstr ""
@@ -14948,6 +14789,9 @@
 msgid "Half Operator"
 msgstr "Féloperátor"
 
+msgid "Voice"
+msgstr "Hang"
+
 msgid "Authorization dialog"
 msgstr "Hitelesítési ablak"
 
@@ -15266,7 +15110,7 @@
 "Ez a bővítmény XMPP kiszolgálókban vagy kliensekben végzett hibakereséshez "
 "hasznos."
 
-#. $(^Name) is the current Version name (e.g. Pidgin 2.7.0).  $_CLICK will become a translated version of "Click Next to continue."
+#. $(^Name) is the current Version name (e.g. Pidgin 2.7.0).  $_CLICK will become a translated version of "Click Next to continue."  DO NOT translate the CLICK in $_CLICK.  It will break the installer.
 msgid ""
 "$(^Name) is released under the GNU General Public License (GPL). The license "
 "is provided here for information purposes only. $_CLICK"
@@ -15328,8 +15172,8 @@
 #, no-c-format
 msgid ""
 "Error Installing Spellchecking ($R3).$\\rIf retrying fails, manual "
-"installation instructions are at: http://developer.pidgin.im/wiki/Installing"
-"%20Pidgin#manual_win32_spellcheck_installation"
+"installation instructions are at: http://developer.pidgin.im/wiki/Installing%"
+"20Pidgin#manual_win32_spellcheck_installation"
 msgstr ""
 "Hiba a helyesírás-ellenőrző telepítésekor. ($R3).$\\rHa az újrapróbálkozás "
 "meghiúsul, akkor saját kezűleg is telepítheti a http://developer.pidgin.im/"
@@ -15411,29 +15255,3 @@
 
 msgid "You do not have permission to uninstall this application."
 msgstr "Nincs jogosultsága az alkalmazás eltávolításához."
-
-#~ msgid "The certificate is not valid yet."
-#~ msgstr "A tanúsítvány még nem érvényes."
-
-#~ msgid "The nick name you entered is invalid."
-#~ msgstr "A megadott becenév érvénytelen."
-
-#~ msgid "MXit Login Name"
-#~ msgstr "MXit bejelentkezési név"
-
-#~ msgid "Nick Name"
-#~ msgstr "Becenév"
-
-#~ msgid "Your Mobile Number..."
-#~ msgstr "Az Ön mobiltelefonszáma…"
-
-#, fuzzy
-#~ msgid "Rate to host"
-#~ msgstr "Meghívás csevegésre"
-
-#, fuzzy
-#~ msgid "Rate to client"
-#~ msgstr "Utolsó ismert kliens"
-
-#~ msgid "/Media/_Hangup"
-#~ msgstr "/Média/_Lerakás"