changeset 30835:d48ae82c58ac

merge of '67241dfb975ba5ce0811cc461f1716d28bf8b730' and 'eca3adf7cdd9217fcf670611fb705385fcfaa48d'
author Mark Doliner <mark@kingant.net>
date Tue, 10 Aug 2010 17:09:32 +0000
parents a6511abec788 (diff) 242bcf6b1258 (current diff)
children a4d7d154d00d
files libpurple/protocols/oscar/family_advert.c libpurple/protocols/oscar/family_invite.c libpurple/protocols/oscar/family_odir.c libpurple/protocols/oscar/family_translate.c libpurple/protocols/oscar/visibility.c
diffstat 36 files changed, 793 insertions(+), 4075 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/oscar/Makefile.am	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/Makefile.am	Tue Aug 10 17:09:32 2010 +0000
@@ -9,8 +9,8 @@
 	authorization.c     \
 	bstream.c           \
 	clientlogin.c       \
+	encoding.c          \
 	family_admin.c      \
-	family_advert.c     \
 	family_alert.c      \
 	family_auth.c       \
 	family_bart.c       \
@@ -20,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         \
--- a/libpurple/protocols/oscar/bstream.c	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/bstream.c	Tue Aug 10 17:09:32 2010 +0000
@@ -34,7 +34,6 @@
 
 int byte_stream_init(ByteStream *bs, guint8 *data, int 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;
 }
@@ -62,102 +61,75 @@
 
 int byte_stream_setpos(ByteStream *bs, unsigned int 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);
 }
 
@@ -169,9 +141,7 @@
 
 int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int 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;
@@ -181,13 +151,10 @@
 {
 	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;
 }
 
@@ -195,94 +162,69 @@
 {
 	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)
 {
-
-	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;
 }
 
@@ -293,17 +235,12 @@
 
 int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int 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	Tue Aug 10 17:09:32 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	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_admin.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_alert.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_auth.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_bart.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_bos.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_buddy.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_chat.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_chatnav.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_feedbag.c	Tue Aug 10 17:09:32 2010 +0000
@@ -1155,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)
@@ -1205,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
@@ -1302,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);
 
@@ -1323,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
@@ -1361,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
@@ -1413,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);
@@ -1446,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;
 	}
@@ -1602,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)
@@ -1707,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);
 
@@ -1787,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);
 
--- a/libpurple/protocols/oscar/family_icbm.c	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_icbm.c	Tue Aug 10 17:09:32 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
@@ -290,7 +228,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);
 
@@ -348,40 +286,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)
 {
@@ -390,7 +302,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;
@@ -398,37 +309,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);
 
@@ -444,52 +335,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 */
@@ -524,7 +394,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 */
@@ -534,33 +404,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)
@@ -631,7 +474,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);
 
@@ -701,100 +544,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);
 
@@ -847,7 +597,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);
 }
@@ -882,7 +632,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);
 }
@@ -937,7 +687,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);
 }
@@ -1000,7 +750,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);
 }
@@ -1047,17 +797,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;
@@ -1086,7 +825,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);
 }
@@ -1139,17 +878,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;
@@ -1179,530 +907,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;
@@ -1711,93 +966,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);
@@ -1815,39 +997,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);
 		}
 
 		/*
@@ -1865,10 +1024,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;
 }
 
@@ -1894,7 +1050,7 @@
 	 *     ...
 	 *   ...
 	 */
-	while (byte_stream_empty(servdata))
+	while (byte_stream_bytes_left(servdata))
 	{
 		guint16 gnlen, numb;
 		int i;
@@ -1966,7 +1122,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);
 }
 
 /*
@@ -1980,33 +1136,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
@@ -2191,20 +1348,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
 	 */
@@ -2399,38 +1542,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)
 {
@@ -2439,7 +1550,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);
@@ -2459,9 +1570,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)
@@ -2488,7 +1597,7 @@
 	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);
 
@@ -2496,6 +1605,52 @@
 }
 
 /*
+ * 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)
+{
+	ByteStream bs;
+	aim_snacid_t snacid;
+	guint32 header_size, data_size;
+	guint16 cookie2 = (guint16)g_random_int();
+
+	purple_debug_misc("oscar", "Sending message ack to %s\n", bn);
+
+	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);
+
+	/* The message header. */
+	aim_im_puticbm(&bs, cookie, 0x0002, bn);
+	byte_stream_put16(&bs, 0x0003);	/* reason */
+
+	/* 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 */
+
+	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);
+}
+
+/*
  * Subtype 0x000b - Receive the response from an ICQ status message
  * request (in which case this contains the ICQ status message) or
  * a file transfer or direct IM request was declined.
@@ -2638,16 +1793,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;
@@ -2657,8 +1806,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);
@@ -2733,7 +1881,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);
 
@@ -2824,7 +1972,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(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
@@ -2906,7 +2054,7 @@
 	byte_stream_putraw(&bs, plugindata, sizeof(plugindata));
 	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);
@@ -2951,8 +2099,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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_icq.c	Tue Aug 10 17:09:32 2010 +0000
@@ -23,6 +23,7 @@
  *
  */
 
+#include "encoding.h"
 #include "oscar.h"
 
 #define AIM_ICQ_INFO_REQUEST 0x04b2
@@ -156,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);
 
@@ -206,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);
 
@@ -245,7 +246,7 @@
 	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);
 
@@ -292,7 +293,7 @@
 	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);
 
@@ -397,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);
 
@@ -727,7 +728,7 @@
 
 				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);
 			}
--- a/libpurple/protocols/oscar/family_invite.c	Thu Jul 08 14:58:55 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_locate.c	Tue Aug 10 17:09:32 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,60 +1166,6 @@
 	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
  */
@@ -1386,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);
 
@@ -1420,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);
 
@@ -1523,133 +1436,6 @@
 }
 
 /*
- * 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.
  *
@@ -1677,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);
 
@@ -1725,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	Thu Jul 08 14:58:55 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_oservice.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/family_userlookup.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/flap_connection.c	Tue Aug 10 17:09:32 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/misc.c	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/misc.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/msgcookie.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/odc.c	Tue Aug 10 17:09:32 2010 +0000
@@ -19,6 +19,7 @@
 */
 
 /* From the oscar PRPL */
+#include "encoding.h"
 #include "oscar.h"
 #include "peer.h"
 
@@ -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);
--- a/libpurple/protocols/oscar/oscar.c	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Tue Aug 10 17:09:32 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"
@@ -67,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};
@@ -107,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 *, ...);
@@ -152,368 +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;
-}
-
-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;
-}
-
 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)
@@ -1027,14 +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);
 	oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_RIGHTSINFO, purple_parse_locaterights, 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);
@@ -1294,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;
@@ -1776,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)
 			/*
@@ -1893,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) {
@@ -1943,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.
@@ -2039,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;
@@ -2068,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)
@@ -2117,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)
 		{
@@ -2171,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");
@@ -2249,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;
@@ -2306,7 +1877,7 @@
 				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",
@@ -2906,13 +2477,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);
 
@@ -2920,16 +2485,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);
 
@@ -2945,7 +2501,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;
@@ -2964,10 +2519,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);
 
@@ -3085,41 +2637,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;
@@ -3140,10 +2657,6 @@
 	 */
 	warning_level = info->warnlevel/10.0 + 0.5;
 
-#ifdef CRAZY_WARNING
-	purple_presence_set_warning_level(presence, warning_level);
-#endif
-
 	return 1;
 }
 
@@ -3282,6 +2795,7 @@
 	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);
@@ -3544,8 +3058,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;
@@ -3606,8 +3120,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);
@@ -3687,7 +3200,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;
@@ -3756,7 +3269,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. */
@@ -3773,14 +3286,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);
 	}
@@ -3807,43 +3318,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)
 {
@@ -3947,7 +3426,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)
@@ -3980,7 +3459,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)
@@ -4076,14 +3555,6 @@
 	oscar_set_info_and_status(account, FALSE, NULL, TRUE, status);
 }
 
-#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;
@@ -4281,6 +3752,7 @@
 	PurpleAccount *account;
 	PurpleGroup *g;
 	PurpleBuddy *b;
+	GSList *cur, *next, *buddies;
 	struct aim_ssi_item *curitem;
 	guint32 tmp;
 	PurpleStoredImage *img;
@@ -4300,110 +3772,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 (ICQ doesn't have one) */
-		if (!od->icq && 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, 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);
-				}
-			}
+	}
+
+	/* 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) {
@@ -4412,13 +3883,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) {
@@ -4427,14 +3892,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) {
@@ -4476,13 +3934,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);
@@ -4493,10 +3945,8 @@
 
 			case AIM_SSI_TYPE_PERMIT: { /* Permit buddy (unless we're on ICQ) */
 				if (!od->icq && 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) {
+					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);
@@ -4507,9 +3957,8 @@
 			case AIM_SSI_TYPE_ICQDENY:
 			case AIM_SSI_TYPE_DENY: { /* Deny buddy */
 				if (curitem->type == deny_entry_type && curitem->name) {
-					GSList *list;
-					for (list=account->deny; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next);
-					if (!list) {
+					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);
@@ -4541,6 +3990,8 @@
 		} /* End of switch on curitem->type */
 	} /* End of for loop */
 
+	/*** End code for adding from server list to local list ***/
+
 	if (od->icq) {
 		oscar_set_icq_permdeny(account);
 	} else {
@@ -4656,15 +4107,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);
@@ -4953,9 +4396,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;
@@ -4971,7 +4414,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"
@@ -4987,10 +4430,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);
@@ -5001,12 +4445,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);
@@ -5606,15 +5044,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)
@@ -6052,12 +5481,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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Tue Aug 10 17:09:32 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,8 @@
 #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"
@@ -596,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.
@@ -685,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);
 
@@ -698,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
@@ -777,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;
@@ -843,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 */
 
@@ -854,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.
@@ -885,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 */
@@ -997,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;
@@ -1012,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 */
@@ -1033,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);
@@ -1042,39 +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 *oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg);
-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
@@ -1147,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);
@@ -1170,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);
@@ -1188,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;
@@ -1222,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 */
@@ -1275,13 +883,6 @@
 #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
@@ -1308,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);
 
@@ -1346,18 +945,6 @@
 
 guint16 aim_ssi_getdenyentrytype(OscarData* od);
 
-/* 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
-
 struct aim_icq_info
 {
 	guint16 reqid;
@@ -1563,9 +1150,6 @@
 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);
@@ -1614,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);
@@ -1627,13 +1207,12 @@
 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);
 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);
 void byte_stream_rewind(ByteStream *bs);
@@ -1690,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;
@@ -1717,7 +1296,6 @@
 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);
--- a/libpurple/protocols/oscar/oscar_data.c	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/oscar_data.c	Tue Aug 10 17:09:32 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/peer_proxy.c	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/peer_proxy.c	Tue Aug 10 17:09:32 2010 +0000
@@ -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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/rxhandlers.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/snac.c	Tue Aug 10 17:09:32 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	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/tlv.c	Tue Aug 10 17:09:32 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 */
--- a/libpurple/protocols/oscar/userinfo.c	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/userinfo.c	Tue Aug 10 17:09:32 2010 +0000
@@ -22,6 +22,7 @@
  * Displaying various information about buddies.
  */
 
+#include "encoding.h"
 #include "oscar.h"
 
 static gchar *
@@ -139,7 +140,7 @@
 
 static void
 oscar_user_info_convert_and_add(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
-								const char *name, const char *value)
+					const char *name, const char *value)
 {
 	gchar *utf8;
 
@@ -149,6 +150,20 @@
 	}
 }
 
+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
  *
@@ -190,30 +205,21 @@
 	   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)
-		{
+		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);
+			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(account,
-						userinfo->status_encoding, userinfo->status,
-						userinfo->status_len);
+				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(account, userinfo->itmsurl_encoding,
-												 userinfo->itmsurl, userinfo->itmsurl_len);
+			if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) {
+				itmsurl = oscar_encoding_to_utf8(userinfo->itmsurl_encoding, userinfo->itmsurl, userinfo->itmsurl_len);
+			}
 #endif
 		}
 	} else {
@@ -389,8 +395,6 @@
 	struct buddyinfo *bi;
 	gchar who[16];
 	PurpleNotifyUserInfo *user_info;
-	gchar *utf8;
-	gchar *buf;
 	const gchar *alias;
 
 	if (!info->uin)
@@ -418,21 +422,11 @@
 	}
 	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);
-	}
+	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++) {
-			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_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);
@@ -462,13 +456,7 @@
 		snprintf(age, sizeof(age), "%hhd", info->age);
 		purple_notify_user_info_add_pair(user_info, _("Age"), age);
 	}
-	if (info->personalwebpage && info->personalwebpage[0] && (utf8 = oscar_utf8_try_convert(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);
-	}
-
+	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);
 
@@ -497,13 +485,7 @@
 		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);
-		}
+		oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Web Page"), info->email, "");
 	}
 
 	if (buddy != NULL)
@@ -551,17 +533,12 @@
 
 	/* 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);
+		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);
-		if (info_utf8 != NULL) {
-			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);
-		}
+		g_free(info_utf8);
 	}
 
 	purple_notify_user_info_add_section_break(user_info);
--- a/libpurple/protocols/oscar/util.c	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/util.c	Tue Aug 10 17:09:32 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.
  */
@@ -392,22 +307,20 @@
 oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message)
 {
 	GSList *cur;
-	gchar *result, *tmp;
+	GString *result;
 	if (!buddies) {
 		return g_strdup_printf("<i>%s</i>", no_buddies_message);
 	}
-	result = g_strdup("");
+	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) {
-			tmp = g_strdup_printf("%s%s (%s)<br>", result, bname, alias);
-		} else {
-			tmp = g_strdup_printf("%s%s<br>", result, bname);
+			g_string_append_printf(result, " (%s)", alias);
 		}
-		g_free(result);
-		result = tmp;
+		g_string_append(result, "<br>");
 	}
-	return result;
+	return g_string_free(result, FALSE);
 }
\ No newline at end of file
--- a/libpurple/protocols/oscar/visibility.c	Thu Jul 08 14:58:55 2010 +0000
+++ b/libpurple/protocols/oscar/visibility.c	Tue Aug 10 17:09:32 2010 +0000
@@ -28,7 +28,7 @@
 #define DONT_APPEAR_OFFLINE	N_("Don't Appear Offline")
 
 static guint16
-get_buddy_list_type(OscarData *od, const char *bname)
+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;
@@ -37,7 +37,7 @@
 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, bname)) != NULL;
+	return aim_ssi_itemlist_finditem(od->ssi.local, NULL, bname, get_buddy_list_type(od)) != NULL;
 }
 
 static void
@@ -46,7 +46,7 @@
 	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, bname);
+	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);