changeset 13592:6519aeb66b31

[gaim-migrate @ 15978] Holy cow this is crazy. 34 files changed, 5760 insertions(+), 8517 deletions(-) * Non-blocking I/O for all of oscar. That includes normal FLAP connections as well as file transfers and direct IM. * Kick-ass file transfer and direct IM. Either party can request the connection. Gaim will try both the "public" IP and the "client" IP. It'll fall back to transferring through a proxy if that fails. Should be relatively few memleaks (I didn't have a lot of confidence in the non-memleakiness of the old code). And the code is reasonably generic, so it shouldn't be too much work to add voice chat. This might still be a LITTLE buggy, but it shouldn't be too bad. If anything, file transfer will be more buggy than direct IM. And sending a file will be more buggy than receiving a file. Bug reports with a series of steps to reproduce are welcome. * I merged OscarData and aim_session_t * Somewhere between 50 and 100 hours of work. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Fri, 07 Apr 2006 05:10:56 +0000
parents dcfda39ad547
children 165bf3145cbf
files src/protocols/oscar/Makefile.am src/protocols/oscar/Makefile.mingw src/protocols/oscar/bstream.c src/protocols/oscar/conn.c src/protocols/oscar/family_admin.c src/protocols/oscar/family_advert.c src/protocols/oscar/family_alert.c src/protocols/oscar/family_auth.c src/protocols/oscar/family_bart.c src/protocols/oscar/family_bos.c src/protocols/oscar/family_buddy.c src/protocols/oscar/family_chat.c src/protocols/oscar/family_chatnav.c src/protocols/oscar/family_feedbag.c src/protocols/oscar/family_icbm.c src/protocols/oscar/family_icq.c src/protocols/oscar/family_invite.c src/protocols/oscar/family_locate.c src/protocols/oscar/family_odir.c src/protocols/oscar/family_oservice.c src/protocols/oscar/family_popup.c src/protocols/oscar/family_stats.c src/protocols/oscar/family_translate.c src/protocols/oscar/family_userlookup.c src/protocols/oscar/flap_connection.c src/protocols/oscar/misc.c src/protocols/oscar/msgcookie.c src/protocols/oscar/odc.c src/protocols/oscar/oft.c src/protocols/oscar/oscar.c src/protocols/oscar/oscar.h src/protocols/oscar/oscar_data.c src/protocols/oscar/oscar_internal.h src/protocols/oscar/peer.c src/protocols/oscar/peer.h src/protocols/oscar/peer_proxy.c src/protocols/oscar/rxhandlers.c src/protocols/oscar/rxqueue.c src/protocols/oscar/session.c src/protocols/oscar/snac.c src/protocols/oscar/snactypes.h src/protocols/oscar/tlv.c src/protocols/oscar/txqueue.c src/protocols/oscar/util.c
diffstat 44 files changed, 8511 insertions(+), 10269 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/oscar/Makefile.am	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/Makefile.am	Fri Apr 07 05:10:56 2006 +0000
@@ -7,7 +7,6 @@
 
 OSCARSOURCES = \
 	bstream.c           \
-	conn.c              \
 	family_admin.c      \
 	family_advert.c     \
 	family_alert.c      \
@@ -28,20 +27,21 @@
 	family_stats.c      \
 	family_translate.c  \
 	family_userlookup.c \
+	flap_connection.c   \
 	misc.c         \
 	msgcookie.c         \
+	odc.c               \
+	oft.c               \
 	oscar.c             \
 	oscar.h             \
-	oscar_internal.h    \
+	oscar_data.c        \
 	peer.c              \
 	peer.h              \
+	peer_proxy.c        \
 	rxhandlers.c        \
-	rxqueue.c           \
-	session.c           \
 	snac.c              \
 	snactypes.h         \
 	tlv.c               \
-	txqueue.c           \
 	util.c
 
 AM_CFLAGS = $(st)
--- a/src/protocols/oscar/Makefile.mingw	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/Makefile.mingw	Fri Apr 07 05:10:56 2006 +0000
@@ -69,7 +69,6 @@
 
 C_SRC = \
 	bstream.c			\
-	conn.c				\
 	family_admin.c		\
 	family_advert.c		\
 	family_alert.c		\
@@ -90,16 +89,18 @@
 	family_stats.c		\
 	family_translate.c	\
 	family_userlookup.c	\
+	flap_connection.c	\
 	misc.c		\
 	msgcookie.c			\
+	odc.c				\
+	oft.c				\
 	oscar.c				\
+	oscar_data.c		\
 	peer.c				\
+	peer_proxy.c		\
 	rxhandlers.c		\
-	rxqueue.c			\
-	session.c			\
 	snac.c				\
 	tlv.c				\
-	txqueue.c			\
 	util.c
 
 
--- a/src/protocols/oscar/bstream.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/bstream.c	Fri Apr 07 05:10:56 2006 +0000
@@ -24,7 +24,7 @@
 
 #include "oscar.h"
 
-faim_internal int aim_bstream_init(ByteStream *bs, guint8 *data, int len)
+int byte_stream_init(ByteStream *bs, guint8 *data, int len)
 {
 
 	if (!bs)
@@ -37,17 +37,17 @@
 	return 0;
 }
 
-faim_internal int aim_bstream_empty(ByteStream *bs)
+int byte_stream_empty(ByteStream *bs)
 {
 	return bs->len - bs->offset;
 }
 
-faim_internal int aim_bstream_curpos(ByteStream *bs)
+int byte_stream_curpos(ByteStream *bs)
 {
 	return bs->offset;
 }
 
-faim_internal int aim_bstream_setpos(ByteStream *bs, unsigned int off)
+int byte_stream_setpos(ByteStream *bs, unsigned int off)
 {
 
 	if (off > bs->len)
@@ -58,10 +58,10 @@
 	return off;
 }
 
-faim_internal void aim_bstream_rewind(ByteStream *bs)
+void byte_stream_rewind(ByteStream *bs)
 {
 
-	aim_bstream_setpos(bs, 0);
+	byte_stream_setpos(bs, 0);
 
 	return;
 }
@@ -71,10 +71,10 @@
  * in a bstream.  I'm not sure if libfaim actually does
  * this anywhere...
  */
-faim_internal int aim_bstream_advance(ByteStream *bs, int n)
+int byte_stream_advance(ByteStream *bs, int n)
 {
 
-	if ((aim_bstream_curpos(bs) + n < 0) || (aim_bstream_empty(bs) < n))
+	if ((byte_stream_curpos(bs) + n < 0) || (byte_stream_empty(bs) < n))
 		return 0; /* XXX throw an exception */
 
 	bs->offset += n;
@@ -82,10 +82,10 @@
 	return n;
 }
 
-faim_internal guint8 aimbs_get8(ByteStream *bs)
+guint8 byte_stream_get8(ByteStream *bs)
 {
 
-	if (aim_bstream_empty(bs) < 1)
+	if (byte_stream_empty(bs) < 1)
 		return 0; /* XXX throw an exception */
 
 	bs->offset++;
@@ -93,10 +93,10 @@
 	return aimutil_get8(bs->data + bs->offset - 1);
 }
 
-faim_internal guint16 aimbs_get16(ByteStream *bs)
+guint16 byte_stream_get16(ByteStream *bs)
 {
 
-	if (aim_bstream_empty(bs) < 2)
+	if (byte_stream_empty(bs) < 2)
 		return 0; /* XXX throw an exception */
 
 	bs->offset += 2;
@@ -104,10 +104,10 @@
 	return aimutil_get16(bs->data + bs->offset - 2);
 }
 
-faim_internal guint32 aimbs_get32(ByteStream *bs)
+guint32 byte_stream_get32(ByteStream *bs)
 {
 
-	if (aim_bstream_empty(bs) < 4)
+	if (byte_stream_empty(bs) < 4)
 		return 0; /* XXX throw an exception */
 
 	bs->offset += 4;
@@ -115,10 +115,10 @@
 	return aimutil_get32(bs->data + bs->offset - 4);
 }
 
-faim_internal guint8 aimbs_getle8(ByteStream *bs)
+guint8 byte_stream_getle8(ByteStream *bs)
 {
 
-	if (aim_bstream_empty(bs) < 1)
+	if (byte_stream_empty(bs) < 1)
 		return 0; /* XXX throw an exception */
 
 	bs->offset++;
@@ -126,10 +126,10 @@
 	return aimutil_getle8(bs->data + bs->offset - 1);
 }
 
-faim_internal guint16 aimbs_getle16(ByteStream *bs)
+guint16 byte_stream_getle16(ByteStream *bs)
 {
 
-	if (aim_bstream_empty(bs) < 2)
+	if (byte_stream_empty(bs) < 2)
 		return 0; /* XXX throw an exception */
 
 	bs->offset += 2;
@@ -137,10 +137,10 @@
 	return aimutil_getle16(bs->data + bs->offset - 2);
 }
 
-faim_internal guint32 aimbs_getle32(ByteStream *bs)
+guint32 byte_stream_getle32(ByteStream *bs)
 {
 
-	if (aim_bstream_empty(bs) < 4)
+	if (byte_stream_empty(bs) < 4)
 		return 0; /* XXX throw an exception */
 
 	bs->offset += 4;
@@ -148,10 +148,10 @@
 	return aimutil_getle32(bs->data + bs->offset - 4);
 }
 
-faim_internal int aimbs_getrawbuf(ByteStream *bs, guint8 *buf, int len)
+int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int len)
 {
 
-	if (aim_bstream_empty(bs) < len)
+	if (byte_stream_empty(bs) < len)
 		return 0;
 
 	memcpy(buf, bs->data + bs->offset, len);
@@ -160,14 +160,13 @@
 	return len;
 }
 
-faim_internal guint8 *aimbs_getraw(ByteStream *bs, int len)
+guint8 *byte_stream_getraw(ByteStream *bs, int len)
 {
 	guint8 *ob;
 
-	if (!(ob = malloc(len)))
-		return NULL;
+	ob = malloc(len);
 
-	if (aimbs_getrawbuf(bs, ob, len) < len) {
+	if (byte_stream_getrawbuf(bs, ob, len) < len) {
 		free(ob);
 		return NULL;
 	}
@@ -175,14 +174,13 @@
 	return ob;
 }
 
-faim_internal char *aimbs_getstr(ByteStream *bs, int len)
+char *byte_stream_getstr(ByteStream *bs, int len)
 {
 	char *ob;
 
-	if (!(ob = malloc(len + 1)))
-		return NULL;
+	ob = malloc(len + 1);
 
-	if (aimbs_getrawbuf(bs, (guint8 *)ob, len) < len) {
+	if (byte_stream_getrawbuf(bs, (guint8 *)ob, len) < len) {
 		free(ob);
 		return NULL;
 	}
@@ -192,10 +190,10 @@
 	return ob;
 }
 
-faim_internal int aimbs_put8(ByteStream *bs, guint8 v)
+int byte_stream_put8(ByteStream *bs, guint8 v)
 {
 
-	if (aim_bstream_empty(bs) < 1)
+	if (byte_stream_empty(bs) < 1)
 		return 0; /* XXX throw an exception */
 
 	bs->offset += aimutil_put8(bs->data + bs->offset, v);
@@ -203,10 +201,10 @@
 	return 1;
 }
 
-faim_internal int aimbs_put16(ByteStream *bs, guint16 v)
+int byte_stream_put16(ByteStream *bs, guint16 v)
 {
 
-	if (aim_bstream_empty(bs) < 2)
+	if (byte_stream_empty(bs) < 2)
 		return 0; /* XXX throw an exception */
 
 	bs->offset += aimutil_put16(bs->data + bs->offset, v);
@@ -214,10 +212,10 @@
 	return 2;
 }
 
-faim_internal int aimbs_put32(ByteStream *bs, guint32 v)
+int byte_stream_put32(ByteStream *bs, guint32 v)
 {
 
-	if (aim_bstream_empty(bs) < 4)
+	if (byte_stream_empty(bs) < 4)
 		return 0; /* XXX throw an exception */
 
 	bs->offset += aimutil_put32(bs->data + bs->offset, v);
@@ -225,10 +223,10 @@
 	return 1;
 }
 
-faim_internal int aimbs_putle8(ByteStream *bs, guint8 v)
+int byte_stream_putle8(ByteStream *bs, guint8 v)
 {
 
-	if (aim_bstream_empty(bs) < 1)
+	if (byte_stream_empty(bs) < 1)
 		return 0; /* XXX throw an exception */
 
 	bs->offset += aimutil_putle8(bs->data + bs->offset, v);
@@ -236,10 +234,10 @@
 	return 1;
 }
 
-faim_internal int aimbs_putle16(ByteStream *bs, guint16 v)
+int byte_stream_putle16(ByteStream *bs, guint16 v)
 {
 
-	if (aim_bstream_empty(bs) < 2)
+	if (byte_stream_empty(bs) < 2)
 		return 0; /* XXX throw an exception */
 
 	bs->offset += aimutil_putle16(bs->data + bs->offset, v);
@@ -247,10 +245,10 @@
 	return 2;
 }
 
-faim_internal int aimbs_putle32(ByteStream *bs, guint32 v)
+int byte_stream_putle32(ByteStream *bs, guint32 v)
 {
 
-	if (aim_bstream_empty(bs) < 4)
+	if (byte_stream_empty(bs) < 4)
 		return 0; /* XXX throw an exception */
 
 	bs->offset += aimutil_putle32(bs->data + bs->offset, v);
@@ -259,10 +257,10 @@
 }
 
 
-faim_internal int aimbs_putraw(ByteStream *bs, const guint8 *v, int len)
+int byte_stream_putraw(ByteStream *bs, const guint8 *v, int len)
 {
 
-	if (aim_bstream_empty(bs) < len)
+	if (byte_stream_empty(bs) < len)
 		return 0; /* XXX throw an exception */
 
 	memcpy(bs->data + bs->offset, v, len);
@@ -271,18 +269,18 @@
 	return len;
 }
 
-faim_internal int aimbs_putstr(ByteStream *bs, const char *str)
+int byte_stream_putstr(ByteStream *bs, const char *str)
 {
-	return aimbs_putraw(bs, (guint8 *)str, strlen(str));
+	return byte_stream_putraw(bs, (guint8 *)str, strlen(str));
 }
 
-faim_internal int aimbs_putbs(ByteStream *bs, ByteStream *srcbs, int len)
+int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int len)
 {
 
-	if (aim_bstream_empty(srcbs) < len)
+	if (byte_stream_empty(srcbs) < len)
 		return 0; /* XXX throw exception (underrun) */
 
-	if (aim_bstream_empty(bs) < len)
+	if (byte_stream_empty(bs) < len)
 		return 0; /* XXX throw exception (overflow) */
 
 	memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len);
--- a/src/protocols/oscar/conn.c	Fri Apr 07 01:05:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,452 +0,0 @@
-/*
- * Gaim'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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/**
- * Low-level connection handling.
- *
- * Does all this gloriously nifty connection handling stuff...
- *
- */
-
-#include "oscar.h"
-
-#ifndef _WIN32
-#include <netdb.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#endif
-
-#ifdef _WIN32
-#include "win32dep.h"
-#endif
-
-/**
- * In OSCAR, every connection has a set of SNAC groups associated
- * with it.  These are the groups that you can send over this connection
- * without being guaranteed a "Not supported" SNAC error.
- *
- * The grand theory of things says that these associations transcend
- * what libfaim calls "connection types" (conn->type).  You can probably
- * see the elegance here, but since I want to revel in it for a bit, you
- * get to hear it all spelled out.
- *
- * So let us say that you have your core BOS connection running.  One
- * of your modules has just given you a SNAC of the group 0x0004 to send
- * you.  Maybe an IM destined for some twit in Greenland.  So you start
- * at the top of your connection list, looking for a connection that
- * claims to support group 0x0004.  You find one.  Why, that neat BOS
- * connection of yours can do that.  So you send it on its way.
- *
- * Now, say, that fellow from Greenland has friends and they all want to
- * meet up with you in a lame chat room.  This has landed you a SNAC
- * in the family 0x000e and you have to admit you're a bit lost.  You've
- * searched your connection list for someone who wants to make your life
- * easy and deliver this SNAC for you, but there isn't one there.
- *
- * Here comes the good bit.  Without even letting anyone know, particularly
- * the module that decided to send this SNAC, and definitely not that twit
- * in Greenland, you send out a service request.  In this request, you have
- * marked the need for a connection supporting group 0x000e.  A few seconds
- * later, you receive a service redirect with an IP address and a cookie in
- * it.  Great, you say.  Now I have something to do.  Off you go, making
- * that connection.  One of the first things you get from this new server
- * is a message saying that indeed it does support the group you were looking
- * for.  So you continue and send rate confirmation and all that.
- *
- * Then you remember you had that SNAC to send, and now you have a means to
- * do it, and you do, and everyone is happy.  Except the Greenlander, who is
- * still stuck in the bitter cold.
- *
- * Oh, and this is useful for building the Migration SNACs, too.  In the
- * future, this may help convince me to implement rate limit mitigation
- * for real.  We'll see.
- *
- * Just to make me look better, I'll say that I've known about this great
- * scheme for quite some time now.  But I still haven't convinced myself
- * to make libfaim work that way.  It would take a fair amount of effort,
- * and probably some client API changes as well.  (Whenever I don't want
- * to do something, I just say it would change the client API.  Then I
- * instantly have a couple of supporters of not doing it.)
- *
- * Generally, addgroup is only called by the internal handling of the
- * server ready SNAC.  So if you want to do something before that, you'll
- * have to be more creative.  That is done rather early, though, so I don't
- * think you have to worry about it.  Unless you're me.  I care deeply
- * about such inane things.
- *
- */
-void
-aim_conn_addgroup(OscarConnection *conn, guint16 group)
-{
-	aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
-	struct snacgroup *sg;
-
-	sg = g_new0(struct snacgroup, 1);
-
-	gaim_debug_misc("oscar", "adding group 0x%04x\n", group);
-	sg->group = group;
-
-	sg->next = ins->groups;
-	ins->groups = sg;
-}
-
-OscarConnection *
-aim_conn_findbygroup(OscarSession *sess, guint16 group)
-{
-	GList *cur;;
-
-	for (cur = sess->oscar_connections; cur; cur = cur->next)
-	{
-		OscarConnection *conn;
-		aim_conn_inside_t *ins;
-		struct snacgroup *sg;
-
-		conn = cur->data;
-		ins = (aim_conn_inside_t *)conn->inside;
-
-		for (sg = ins->groups; sg; sg = sg->next)
-		{
-			if (sg->group == group)
-				return conn;
-		}
-	}
-
-	return NULL;
-}
-
-static void
-connkill_snacgroups(struct snacgroup *head)
-{
-	struct snacgroup *sg;
-	for (sg = head; sg; )
-	{
-		struct snacgroup *tmp;
-
-		tmp = sg->next;
-		free(sg);
-		sg = tmp;
-	}
-}
-
-static void
-connkill_rates(struct rateclass *head)
-{
-	struct rateclass *rc;
-
-	for (rc = head; rc; )
-	{
-		struct rateclass *tmp;
-		struct snacpair *sp;
-
-		tmp = rc->next;
-
-		for (sp = rc->members; sp; ) {
-			struct snacpair *tmpsp;
-
-			tmpsp = sp->next;
-			free(sp);
-			sp = tmpsp;
-		}
-		free(rc);
-
-		rc = tmp;
-	}
-}
-
-void
-oscar_connection_destroy(OscarSession *sess, OscarConnection *conn)
-{
-	aim_rxqueue_cleanbyconn(sess, conn);
-	aim_tx_cleanqueue(sess, conn);
-
-	if (conn->fd != -1)
-		aim_conn_close(sess, conn);
-
-	/*
-	 * This will free ->internal if it necessary...
-	 */
-	if (conn->type == AIM_CONN_TYPE_CHAT)
-		oscar_connection_destroy_chat(sess, conn);
-
-	if (conn->inside != NULL)
-	{
-		aim_conn_inside_t *inside = (aim_conn_inside_t *)conn->inside;
-
-		connkill_snacgroups(inside->groups);
-		connkill_rates(inside->rates);
-
-		free(inside);
-	}
-
-	gaim_circ_buffer_destroy(conn->buffer_outgoing);
-	g_free(conn);
-
-	sess->oscar_connections = g_list_remove(sess->oscar_connections, conn);
-}
-
-/**
- * This sends an empty channel 4 SNAC.  This is sent to signify
- * that we're logging off.  This shouldn't really be necessary--
- * usually the AIM server will detect that the TCP connection has
- * been destroyed.
- */
-static int
-aim_flap_close(OscarSession *sess, OscarConnection *conn)
-{
-	FlapFrame *fr;
-
-	if (!sess || !conn)
-		return -EINVAL;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x04, 0)))
-		return -ENOMEM;
-
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
-}
-
-/**
- * Allocate a new empty connection structure.
- *
- * @param sess The oscar session associated with this connection.
- * @return Returns the new connection structure.
- */
-static OscarConnection *
-aim_conn_getnext(OscarSession *sess)
-{
-	OscarConnection *conn;
-
-	conn = g_new0(OscarConnection, 1);
-	conn->inside = g_new0(aim_conn_inside_t, 1);
-	conn->buffer_outgoing = gaim_circ_buffer_new(-1);
-	conn->fd = -1;
-	conn->subtype = -1;
-	conn->type = -1;
-	conn->seqnum = 0;
-	conn->lastactivity = 0;
-	conn->handlerlist = NULL;
-
-	sess->oscar_connections = g_list_prepend(sess->oscar_connections, conn);
-
-	return conn;
-}
-
-/**
- * Close (but not free) a connection.
- *
- * This leaves everything untouched except for clearing the
- * handler list and setting the fd to -1 (used to recognize
- * dead connections).  It will also remove cookies if necessary.
- *
- * @param conn The connection to close.
- */
-void
-aim_conn_close(OscarSession *sess, OscarConnection *conn)
-{
-	if (conn->type == AIM_CONN_TYPE_BOS)
-		aim_flap_close(sess, conn);
-
-	if (conn->fd >= 0)
-		close(conn->fd);
-
-	conn->fd = -1;
-
-	if (conn->handlerlist)
-		aim_clearhandlers(conn);
-}
-
-/**
- * Locates a connection of the specified type in the
- * specified session.
- *
- * XXX - Except for rendezvous, all uses of this should be removed and
- * aim_conn_findbygroup() should be used instead.
- *
- * @param sess The session to search.
- * @param type The type of connection to look for.
- * @return Returns the first connection found of the given target type,
- *         or NULL if none could be found.
- */
-OscarConnection *
-aim_getconn_type(OscarSession *sess, int type)
-{
-	GList *cur;
-
-	for (cur = sess->oscar_connections; cur; cur = cur->next)
-	{
-		OscarConnection *conn;
-		conn = cur->data;
-		if ((conn->type == type) &&
-				!(conn->status & AIM_CONN_STATUS_INPROGRESS))
-			return conn;
-	}
-
-	return NULL;
-}
-
-OscarConnection *
-aim_getconn_type_all(OscarSession *sess, int type)
-{
-	GList *cur;
-
-	for (cur = sess->oscar_connections; cur; cur = cur->next)
-	{
-		OscarConnection *conn;
-		conn = cur->data;
-		if (conn->type == type)
-			return conn;
-	}
-
-	return NULL;
-}
-
-/**
- * Clone an OscarConnection.
- *
- * A new connection is allocated, and the values are filled in
- * appropriately.
- *
- * @param sess The session containing this connection.
- * @param src The connection to clone.
- * @return Returns a pointer to the new OscarConnection, or %NULL on error.
- */
-OscarConnection *
-aim_cloneconn(OscarSession *sess, OscarConnection *src)
-{
-	OscarConnection *conn;
-
-	conn = aim_conn_getnext(sess);
-	conn->fd = src->fd;
-	conn->type = src->type;
-	conn->subtype = src->subtype;
-	conn->seqnum = src->seqnum;
-	conn->internal = src->internal;
-	conn->lastactivity = src->lastactivity;
-	conn->sessv = src->sessv;
-	aim_clonehandlers(sess, conn, src);
-
-	if (src->inside) {
-		/*
-		 * XXX should clone this section as well, but since currently
-		 * this function only gets called for some of that rendezvous
-		 * crap, and not on SNAC connections, its probably okay for
-		 * now.
-		 *
-		 */
-	}
-
-	return conn;
-}
-
-/**
- * Opens a new connection to the specified dest host of specified
- * type, using the proxy settings if available.  If @host is %NULL,
- * the connection is allocated and returned, but no connection
- * is made.
- *
- * FIXME: Return errors in a more sane way.
- *
- * @param sess Session to create connection in
- * @param type Type of connection to create
- */
-OscarConnection *
-oscar_connection_new(OscarSession *sess, int type)
-{
-	OscarConnection *conn;
-
-	conn = aim_conn_getnext(sess);
-	conn->sessv = sess;
-	conn->type = type;
-	conn->fd = -1;
-	conn->status = 0;
-
-	return conn;
-}
-
-/**
- * Determine if a connection is connecting.
- *
- * @param conn Connection to examine.
- * @return Returns nonzero if the connection is in the process of
- *         connecting (or if it just completed and
- *         aim_conn_completeconnect() has yet to be called on it).
- */
-int
-aim_conn_isconnecting(OscarConnection *conn)
-{
-
-	if (!conn)
-		return 0;
-
-	return !!(conn->status & AIM_CONN_STATUS_INPROGRESS);
-}
-
-/*
- * XXX this is nearly as ugly as proxyconnect().
- */
-int
-aim_conn_completeconnect(OscarSession *sess, OscarConnection *conn)
-{
-	if (!conn || (conn->fd == -1))
-		return -1;
-
-	if (!(conn->status & AIM_CONN_STATUS_INPROGRESS))
-		return -1;
-
-	fcntl(conn->fd, F_SETFL, 0);
-
-	conn->status &= ~AIM_CONN_STATUS_INPROGRESS;
-
-	/* Flush out the queues if there was something waiting for this conn  */
-	aim_tx_flushqueue(sess);
-
-	return 0;
-}
-
-OscarSession *
-aim_conn_getsess(OscarConnection *conn)
-{
-
-	if (!conn)
-		return NULL;
-
-	return (OscarSession *)conn->sessv;
-}
-
-/**
- * No-op.  This sends an empty channel 5 SNAC.  WinAIM 4.x and higher
- * sends these _every minute_ to keep the connection alive.
- */
-int
-aim_flap_nop(OscarSession *sess, OscarConnection *conn)
-{
-	FlapFrame *fr;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x05, 0)))
-		return -ENOMEM;
-
-	aim_tx_enqueue(sess, fr);
-
-	/* clean out SNACs over 60sec old */
-	aim_cleansnacs(sess, 60);
-
-	return 0;
-}
--- a/src/protocols/oscar/family_admin.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_admin.c	Fri Apr 07 05:10:56 2006 +0000
@@ -37,21 +37,21 @@
  * 0x0013 - Unknown
  *
  */
-faim_export int aim_admin_getinfo(OscarSession *sess, OscarConnection *conn, guint16 info)
+int
+aim_admin_getinfo(OscarData *od, FlapConnection *conn, guint16 info)
 {
 	FlapFrame *fr;
 	aim_snacid_t snacid;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 14)))
-		return -ENOMEM;
+	fr = flap_frame_new(od, 0x02, 14);
 
-	snacid = aim_cachesnac(sess, 0x0007, 0x0002, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, 0x0007, 0x0002, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0007, 0x0002, 0x0000, snacid);
 
-	aimbs_put16(&fr->data, info);
-	aimbs_put16(&fr->data, 0x0000);
+	byte_stream_put16(&fr->data, info);
+	byte_stream_put16(&fr->data, 0x0000);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, fr);
 
 	return 0;
 }
@@ -63,48 +63,48 @@
  * an information change (subtype 0x0004).
  *
  */
-static int infochange(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+infochange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	aim_rxcallback_t userfunc;
 	char *url=NULL, *sn=NULL, *email=NULL;
 	guint16 perms, tlvcount, err=0;
 
-	perms = aimbs_get16(bs);
-	tlvcount = aimbs_get16(bs);
+	perms = byte_stream_get16(bs);
+	tlvcount = byte_stream_get16(bs);
 
-	while (tlvcount && aim_bstream_empty(bs)) {
+	while (tlvcount && byte_stream_empty(bs)) {
 		guint16 type, length;
 
-		type = aimbs_get16(bs);
-		length = aimbs_get16(bs);
+		type = byte_stream_get16(bs);
+		length = byte_stream_get16(bs);
 
 		switch (type) {
 			case 0x0001: {
-				sn = aimbs_getstr(bs, length);
+				sn = byte_stream_getstr(bs, length);
 			} break;
 
 			case 0x0004: {
-				url = aimbs_getstr(bs, length);
+				url = byte_stream_getstr(bs, length);
 			} break;
 
 			case 0x0008: {
-				err = aimbs_get16(bs);
+				err = byte_stream_get16(bs);
 			} break;
 
 			case 0x0011: {
-				if (length == 0) {
-					email = (char*)malloc(13*sizeof(char));
-					strcpy(email, "*suppressed*");
-				} else
-					email = aimbs_getstr(bs, length);
+				if (length == 0)
+					email = g_strdup("*suppressed");
+				else
+					email = byte_stream_getstr(bs, length);
 			} break;
 		}
 
 		tlvcount--;
 	}
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		userfunc(sess, rx, (snac->subtype == 0x0005) ? 1 : 0, perms, err, url, sn, email);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		userfunc(od, conn, frame, (snac->subtype == 0x0005) ? 1 : 0, perms, err, url, sn, email);
 
 	free(sn);
 	free(url);
@@ -117,16 +117,17 @@
  * Subtype 0x0004 - Set screenname formatting.
  *
  */
-faim_export int aim_admin_setnick(OscarSession *sess, OscarConnection *conn, const char *newnick)
+int
+aim_admin_setnick(OscarData *od, FlapConnection *conn, const char *newnick)
 {
 	FlapFrame *fr;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newnick))))
+	fr = flap_frame_new(od, 0x02, 10+2+2+strlen(newnick));
 		return -ENOMEM;
 
-	snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid);
 
 	aim_tlvlist_add_str(&tl, 0x0001, newnick);
@@ -134,7 +135,7 @@
 	aim_tlvlist_write(&fr->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, fr);
 
 
 	return 0;
@@ -144,16 +145,16 @@
  * Subtype 0x0004 - Change password.
  *
  */
-faim_export int aim_admin_changepasswd(OscarSession *sess, OscarConnection *conn, const char *newpw, const char *curpw)
+int
+aim_admin_changepasswd(OscarData *od, FlapConnection *conn, const char *newpw, const char *curpw)
 {
 	FlapFrame *fr;
 	aim_tlvlist_t *tl = NULL;
 	aim_snacid_t snacid;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+strlen(curpw)+4+strlen(newpw))))
-		return -ENOMEM;
+	fr = flap_frame_new(od, 0x02, 10+4+strlen(curpw)+4+strlen(newpw));
 
-	snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid);
 
 	/* new password TLV t(0002) */
@@ -165,7 +166,7 @@
 	aim_tlvlist_write(&fr->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, fr);
 
 	return 0;
 }
@@ -174,16 +175,16 @@
  * Subtype 0x0004 - Change email address.
  *
  */
-faim_export int aim_admin_setemail(OscarSession *sess, OscarConnection *conn, const char *newemail)
+int
+aim_admin_setemail(OscarData *od, FlapConnection *conn, const char *newemail)
 {
 	FlapFrame *fr;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newemail))))
-		return -ENOMEM;
+	flap_frame_new(od, 0x02, 10+2+2+strlen(newemail));
 
-	snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid);
 
 	aim_tlvlist_add_str(&tl, 0x0011, newemail);
@@ -191,7 +192,7 @@
 	aim_tlvlist_write(&fr->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, fr);
 
 	return 0;
 }
@@ -204,47 +205,48 @@
  * get the TRIAL flag removed from your account.
  *
  */
-faim_export int aim_admin_reqconfirm(OscarSession *sess, OscarConnection *conn)
+int
+aim_admin_reqconfirm(OscarData *od, FlapConnection *conn)
 {
-	return aim_genericreq_n(sess, conn, 0x0007, 0x0006);
+	return aim_genericreq_n(od, conn, 0x0007, 0x0006);
 }
 
 /*
  * Subtype 0x0007 - Account confirmation request acknowledgement.
  *
  */
-static int accountconfirm(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+accountconfirm(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 status;
 	aim_tlvlist_t *tl;
 
-	status = aimbs_get16(bs);
+	status = byte_stream_get16(bs);
 	/* This is 0x0013 if unable to confirm at this time */
 
 	tl = aim_tlvlist_read(bs);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, status);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, status);
 
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if ((snac->subtype == 0x0003) || (snac->subtype == 0x0005))
-		return infochange(sess, mod, rx, snac, bs);
+		return infochange(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0007)
-		return accountconfirm(sess, mod, rx, snac, bs);
+		return accountconfirm(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int admin_modfirst(OscarSession *sess, aim_module_t *mod)
+int admin_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x0007;
 	mod->version = 0x0001;
 	mod->toolid = 0x0010;
--- a/src/protocols/oscar/family_advert.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_advert.c	Fri Apr 07 05:10:56 2006 +0000
@@ -25,17 +25,17 @@
 
 #include "oscar.h"
 
-faim_export int aim_ads_requestads(OscarSession *sess, OscarConnection *conn)
+int aim_ads_requestads(OscarData *od, FlapConnection *conn)
 {
-	return aim_genericreq_n(sess, conn, 0x0005, 0x0002);
+	return aim_genericreq_n(od, conn, 0x0005, 0x0002);
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
 {
 	return 0;
 }
 
-faim_internal int adverts_modfirst(OscarSession *sess, aim_module_t *mod)
+int adverts_modfirst(OscarData *od, aim_module_t *mod)
 {
 
 	mod->family = 0x0005;
--- a/src/protocols/oscar/family_alert.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_alert.c	Fri Apr 07 05:10:56 2006 +0000
@@ -33,48 +33,48 @@
 /**
  * Subtype 0x0006 - Request information about your email account
  *
- * @param sess The oscar session.
+ * @param od The oscar session.
  * @param conn The email connection for this session.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_email_sendcookies(OscarSession *sess)
+int
+aim_email_sendcookies(OscarData *od)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 	FlapFrame *fr;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_ALERT)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ALERT)))
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+16+16)))
-		return -ENOMEM;
-	snacid = aim_cachesnac(sess, 0x0018, 0x0006, 0x0000, NULL, 0);
+	fr = flap_frame_new(od, 0x02, 10+2+16+16);
+	snacid = aim_cachesnac(od, 0x0018, 0x0006, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0018, 0x0006, 0x0000, snacid);
 
 	/* Number of cookies to follow */
-	aimbs_put16(&fr->data, 0x0002);
+	byte_stream_put16(&fr->data, 0x0002);
 
 	/* Cookie */
-	aimbs_put16(&fr->data, 0x5d5e);
-	aimbs_put16(&fr->data, 0x1708);
-	aimbs_put16(&fr->data, 0x55aa);
-	aimbs_put16(&fr->data, 0x11d3);
-	aimbs_put16(&fr->data, 0xb143);
-	aimbs_put16(&fr->data, 0x0060);
-	aimbs_put16(&fr->data, 0xb0fb);
-	aimbs_put16(&fr->data, 0x1ecb);
+	byte_stream_put16(&fr->data, 0x5d5e);
+	byte_stream_put16(&fr->data, 0x1708);
+	byte_stream_put16(&fr->data, 0x55aa);
+	byte_stream_put16(&fr->data, 0x11d3);
+	byte_stream_put16(&fr->data, 0xb143);
+	byte_stream_put16(&fr->data, 0x0060);
+	byte_stream_put16(&fr->data, 0xb0fb);
+	byte_stream_put16(&fr->data, 0x1ecb);
 
 	/* Cookie */
-	aimbs_put16(&fr->data, 0xb380);
-	aimbs_put16(&fr->data, 0x9ad8);
-	aimbs_put16(&fr->data, 0x0dba);
-	aimbs_put16(&fr->data, 0x11d5);
-	aimbs_put16(&fr->data, 0x9f8a);
-	aimbs_put16(&fr->data, 0x0060);
-	aimbs_put16(&fr->data, 0xb0ee);
-	aimbs_put16(&fr->data, 0x0631);
+	byte_stream_put16(&fr->data, 0xb380);
+	byte_stream_put16(&fr->data, 0x9ad8);
+	byte_stream_put16(&fr->data, 0x0dba);
+	byte_stream_put16(&fr->data, 0x11d5);
+	byte_stream_put16(&fr->data, 0x9f8a);
+	byte_stream_put16(&fr->data, 0x0060);
+	byte_stream_put16(&fr->data, 0xb0ee);
+	byte_stream_put16(&fr->data, 0x0631);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, fr);
 
 	return 0;
 }
@@ -92,7 +92,8 @@
  * this is just a periodic status update, this will also contain
  * the number of unread emails that you have.
  */
-static int parseinfo(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+parseinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -103,11 +104,11 @@
 
 	char *alertitle = NULL, *alerturl = NULL;
 
-	cookie8 = aimbs_getraw(bs, 8); /* Possibly the code used to log you in to mail? */
-	cookie16 = aimbs_getraw(bs, 16); /* Mail cookie sent above */
+	cookie8 = byte_stream_getraw(bs, 8); /* Possibly the code used to log you in to mail? */
+	cookie16 = byte_stream_getraw(bs, 16); /* Mail cookie sent above */
 
 	/* See if we already have some info associated with this cookie */
-	for (new = sess->emailinfo; (new && memcmp(cookie16, new->cookie16, 16)); new = new->next);
+	for (new = od->emailinfo; (new && memcmp(cookie16, new->cookie16, 16)); new = new->next);
 	if (new) {
 		/* Free some of the old info, if it exists */
 		free(new->cookie8);
@@ -116,17 +117,15 @@
 		free(new->domain);
 	} else {
 		/* We don't already have info, so create a new struct for it */
-		if (!(new = malloc(sizeof(struct aim_emailinfo))))
-			return -ENOMEM;
-		memset(new, 0, sizeof(struct aim_emailinfo));
-		new->next = sess->emailinfo;
-		sess->emailinfo = new;
+		new = g_new0(struct aim_emailinfo, 1);
+		new->next = od->emailinfo;
+		od->emailinfo = new;
 	}
 
 	new->cookie8 = cookie8;
 	new->cookie16 = cookie16;
 
-	tlvlist = aim_tlvlist_readnum(bs, aimbs_get16(bs));
+	tlvlist = aim_tlvlist_readnum(bs, byte_stream_get16(bs));
 
 	tmp = aim_tlv_get16(tlvlist, 0x0080, 1);
 	if (tmp) {
@@ -150,8 +149,8 @@
 	alertitle = aim_tlv_getstr(tlvlist, 0x0005, 1);
 	alerturl  = aim_tlv_getstr(tlvlist, 0x000d, 1);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, new, havenewmail, alertitle, (alerturl ? alerturl + 2 : NULL));
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, new, havenewmail, alertitle, (alerturl ? alerturl + 2 : NULL));
 
 	aim_tlvlist_free(&tlvlist);
 
@@ -164,51 +163,53 @@
 /**
  * Subtype 0x0016 - Send something or other
  *
- * @param sess The oscar session.
+ * @param od The oscar session.
  * @param conn The email connection for this session.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_email_activate(OscarSession *sess)
+int
+aim_email_activate(OscarData *od)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 	FlapFrame *fr;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_ALERT)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ALERT)))
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+16)))
-		return -ENOMEM;
-	snacid = aim_cachesnac(sess, 0x0018, 0x0016, 0x0000, NULL, 0);
+	fr = flap_frame_new(od, 0x02, 10+1+16);
+	snacid = aim_cachesnac(od, 0x0018, 0x0016, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0018, 0x0016, 0x0000, snacid);
 
 	/* I would guess this tells AIM that you want updates for your mail accounts */
 	/* ...but I really have no idea */
-	aimbs_put8(&fr->data, 0x02);
-	aimbs_put32(&fr->data, 0x04000000);
-	aimbs_put32(&fr->data, 0x04000000);
-	aimbs_put32(&fr->data, 0x04000000);
-	aimbs_put32(&fr->data, 0x00000000);
+	byte_stream_put8(&fr->data, 0x02);
+	byte_stream_put32(&fr->data, 0x04000000);
+	byte_stream_put32(&fr->data, 0x04000000);
+	byte_stream_put32(&fr->data, 0x04000000);
+	byte_stream_put32(&fr->data, 0x00000000);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, fr);
 
 	return 0;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0007)
-		return parseinfo(sess, mod, rx, snac, bs);
+		return parseinfo(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-static void email_shutdown(OscarSession *sess, aim_module_t *mod)
+static void
+email_shutdown(OscarData *od, aim_module_t *mod)
 {
-	while (sess->emailinfo) {
-		struct aim_emailinfo *tmp = sess->emailinfo;
-		sess->emailinfo = sess->emailinfo->next;
+	while (od->emailinfo)
+	{
+		struct aim_emailinfo *tmp = od->emailinfo;
+		od->emailinfo = od->emailinfo->next;
 		free(tmp->cookie16);
 		free(tmp->cookie8);
 		free(tmp->url);
@@ -219,9 +220,9 @@
 	return;
 }
 
-faim_internal int email_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+email_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x0018;
 	mod->version = 0x0001;
 	mod->toolid = 0x0010;
--- a/src/protocols/oscar/family_auth.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_auth.c	Fri Apr 07 05:10:56 2006 +0000
@@ -52,7 +52,8 @@
  * @param password Incoming password.
  * @param encoded Buffer to put encoded password.
  */
-static int aim_encode_password(const char *password, guint8 *encoded)
+static int
+aim_encode_password(const char *password, guint8 *encoded)
 {
 	guint8 encoding_table[] = {
 #if 0 /* old v1 table */
@@ -77,7 +78,8 @@
 #endif
 
 #ifdef USE_OLD_MD5
-static int aim_encode_password_md5(const char *password, const char *key, guint8 *digest)
+static int
+aim_encode_password_md5(const char *password, const char *key, guint8 *digest)
 {
 	GaimCipher *cipher;
 	GaimCipherContext *context;
@@ -94,7 +96,8 @@
 	return 0;
 }
 #else
-static int aim_encode_password_md5(const char *password, const char *key, guint8 *digest)
+static int
+aim_encode_password_md5(const char *password, const char *key, guint8 *digest)
 {
 	GaimCipher *cipher;
 	GaimCipherContext *context;
@@ -118,76 +121,28 @@
 }
 #endif
 
-/*
- * The FLAP version is sent by itself at the beginning of authorization
- * connections.  The FLAP version is also sent before the cookie when connecting
- * for other services (BOS, chatnav, chat, etc.).
- */
-faim_export int aim_sendflapver(OscarSession *sess, OscarConnection *conn)
-{
-	FlapFrame *fr;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 4)))
-		return -ENOMEM;
-
-	aimbs_put32(&fr->data, 0x00000001);
-
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
-}
-
-/*
- * This just pushes the passed cookie onto the passed connection, without
- * the SNAC header or any of that.
- *
- * Very commonly used, as every connection except auth will require this to
- * be the first thing you send.
- *
- */
-faim_export int aim_sendcookie(OscarSession *sess, OscarConnection *conn, const guint16 length, const guint8 *chipsahoy)
-{
-	FlapFrame *fr;
-	aim_tlvlist_t *tl = NULL;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 4+2+2+length)))
-		return -ENOMEM;
-
-	aimbs_put32(&fr->data, 0x00000001);
-	aim_tlvlist_add_raw(&tl, 0x0006, length, chipsahoy);
-	aim_tlvlist_write(&fr->data, &tl);
-	aim_tlvlist_free(&tl);
-
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
-}
-
 #ifdef USE_XOR_FOR_ICQ
 /*
  * Part two of the ICQ hack.  Note the ignoring of the key.
  */
-static int goddamnicq2(OscarSession *sess, OscarConnection *conn, const char *sn, const char *password, ClientInfo *ci)
+static int
+goddamnicq2(OscarData *od, FlapConnection *conn, const char *sn, const char *password, ClientInfo *ci)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_tlvlist_t *tl = NULL;
 	int passwdlen;
 	guint8 *password_encoded;
 
 	passwdlen = strlen(password);
-	if (!(password_encoded = (guint8 *)malloc(passwdlen+1)))
-		return -ENOMEM;
+	password_encoded = (guint8 *)malloc(passwdlen+1);
 	if (passwdlen > MAXICQPASSLEN)
 		passwdlen = MAXICQPASSLEN;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 1152))) {
-		free(password_encoded);
-		return -ENOMEM;
-	}
+	frame = flap_frame_new(od, 0x01, 1152);
 
 	aim_encode_password(password, password_encoded);
 
-	aimbs_put32(&fr->data, 0x00000001); /* FLAP Version */
+	byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */
 	aim_tlvlist_add_str(&tl, 0x0001, sn);
 	aim_tlvlist_add_raw(&tl, 0x0002, passwdlen, password_encoded);
 
@@ -202,12 +157,12 @@
 	aim_tlvlist_add_str(&tl, 0x000f, ci->lang);
 	aim_tlvlist_add_str(&tl, 0x000e, ci->country);
 
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 
 	free(password_encoded);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -242,9 +197,10 @@
  *   serverstore = 0x01
  *
  */
-faim_export int aim_send_login(OscarSession *sess, OscarConnection *conn, const char *sn, const char *password, ClientInfo *ci, const char *key)
+int
+aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, ClientInfo *ci, const char *key)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_tlvlist_t *tl = NULL;
 	guint8 digest[16];
 	aim_snacid_t snacid;
@@ -255,14 +211,13 @@
 #ifdef USE_XOR_FOR_ICQ
 	/* If we're signing on an ICQ account then use the older, XOR login method */
 	if (isdigit(sn[0]))
-		return goddamnicq2(sess, conn, sn, password, ci);
+		return goddamnicq2(od, conn, sn, password, ci);
 #endif
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 1152);
 
-	snacid = aim_cachesnac(sess, 0x0017, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0017, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0017, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0017, 0x0002, 0x0000, snacid);
 
 	aim_tlvlist_add_str(&tl, 0x0001, sn);
 
@@ -302,11 +257,11 @@
 	 */
 	aim_tlvlist_add_8(&tl, 0x004a, 0x01);
 
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -314,20 +269,20 @@
 /*
  * This is sent back as a general response to the login command.
  * It can be either an error or a success, depending on the
- * presence of certain TLVs.  
+ * presence of certain TLVs.
  *
  * The client should check the value passed as errorcode. If
  * its nonzero, there was an error.
  */
-static int parse(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+parse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	aim_tlvlist_t *tlvlist;
 	aim_rxcallback_t userfunc;
 	struct aim_authresp_info *info;
 	int ret = 0;
 
-	info = (struct aim_authresp_info *)malloc(sizeof(struct aim_authresp_info));
-	memset(info, 0, sizeof(struct aim_authresp_info));
+	info = g_new0(struct aim_authresp_info, 1);
 
 	/*
 	 * Read block of TLVs.  All further data is derived
@@ -338,10 +293,10 @@
 	/*
 	 * No matter what, we should have a screen name.
 	 */
-	memset(sess->sn, 0, sizeof(sess->sn));
+	memset(od->sn, 0, sizeof(od->sn));
 	if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) {
 		info->sn = aim_tlv_getstr(tlvlist, 0x0001, 1);
-		strncpy(sess->sn, info->sn, sizeof(sess->sn));
+		strncpy(od->sn, info->sn, sizeof(od->sn));
 	}
 
 	/*
@@ -374,7 +329,7 @@
 	/*
 	 * The email address attached to this account
 	 *   Not available for ICQ or @mac.com logins.
-	 *   If you receive this TLV, then you are allowed to use 
+	 *   If you receive this TLV, then you are allowed to use
 	 *   family 0x0018 to check the status of your email.
 	 * XXX - Not really true!
 	 */
@@ -443,10 +398,10 @@
 	}
 #endif
 
-	sess->authinfo = info;
+	od->authinfo = info;
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003)))
-		ret = userfunc(sess, rx, info);
+	if ((userfunc = aim_callhandler(od, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003)))
+		ret = userfunc(od, conn, frame, info);
 
 	aim_tlvlist_free(&tlvlist);
 
@@ -489,15 +444,14 @@
  * being called from the context of aim_rxdispatch()...
  *
  */
-static int goddamnicq(OscarSession *sess, OscarConnection *conn, const char *sn)
+static int
+goddamnicq(OscarData *od, FlapConnection *conn, const char *sn)
 {
-	FlapFrame fr;
+	FlapFrame frame;
 	aim_rxcallback_t userfunc;
 
-	fr.conn = conn;
-
-	if ((userfunc = aim_callhandler(sess, conn, 0x0017, 0x0007)))
-		userfunc(sess, &fr, "");
+	if ((userfunc = aim_callhandler(od, 0x0017, 0x0007)))
+		userfunc(od, conn, &frame, "");
 
 	return 0;
 }
@@ -506,34 +460,32 @@
 /*
  * Subtype 0x0006
  *
- * In AIM 3.5 protocol, the first stage of login is to request login from the 
- * Authorizer, passing it the screen name for verification.  If the name is 
- * invalid, a 0017/0003 is spit back, with the standard error contents.  If 
- * valid, a 0017/0007 comes back, which is the signal to send it the main 
- * login command (0017/0002). 
+ * In AIM 3.5 protocol, the first stage of login is to request login from the
+ * Authorizer, passing it the screen name for verification.  If the name is
+ * invalid, a 0017/0003 is spit back, with the standard error contents.  If
+ * valid, a 0017/0007 comes back, which is the signal to send it the main
+ * login command (0017/0002).
  *
  */
-faim_export int aim_request_login(OscarSession *sess, OscarConnection *conn, const char *sn)
+int
+aim_request_login(OscarData *od, FlapConnection *conn, const char *sn)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!sess || !conn || !sn)
+	if (!od || !conn || !sn)
 		return -EINVAL;
 
 #ifdef USE_XOR_FOR_ICQ
 	if (isdigit(sn[0]))
-		return goddamnicq(sess, conn, sn);
+		return goddamnicq(od, conn, sn);
 #endif
 
-	aim_sendflapver(sess, conn);
+	frame = flap_frame_new(od, 0x02, 10+2+2+strlen(sn)+8);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(sn)+8 )))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0017, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0017, 0x0006, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0017, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0017, 0x0006, 0x0000, snacid);
 
 	aim_tlvlist_add_str(&tl, 0x0001, sn);
 
@@ -543,10 +495,10 @@
 	/* Unknown.  Sent in recent WinAIM clients.*/
 	aim_tlvlist_add_noval(&tl, 0x005a);
 
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -560,21 +512,22 @@
  * Calls the client, which should then use the value to call aim_send_login.
  *
  */
-static int keyparse(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+keyparse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int keylen, ret = 1;
 	aim_rxcallback_t userfunc;
 	char *keystr;
 
-	keylen = aimbs_get16(bs);
-	keystr = aimbs_getstr(bs, keylen);
+	keylen = byte_stream_get16(bs);
+	keystr = byte_stream_getstr(bs, keylen);
 
-	/* XXX - When GiantGrayPanda signed on AIM I got a thing asking me to register 
-	 * for the netscape network.  This SNAC had a type 0x0058 TLV with length 10.  
+	/* XXX - When GiantGrayPanda signed on AIM I got a thing asking me to register
+	 * for the netscape network.  This SNAC had a type 0x0058 TLV with length 10.
 	 * Data is 0x0007 0004 3e19 ae1e 0006 0004 0000 0005 */
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, keystr);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, keystr);
 
 	free(keystr);
 
@@ -586,13 +539,14 @@
  *
  * Receive SecurID request.
  */
-static int got_securid_request(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+got_securid_request(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame);
 
 	return ret;
 }
@@ -602,66 +556,68 @@
  *
  * Send SecurID response.
  */
-faim_export int aim_auth_securid_send(OscarSession *sess, const char *securid)
+int
+aim_auth_securid_send(OscarData *od, const char *securid)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int len;
 
-	if (!sess || !(conn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH)) || !securid)
+	if (!od || !(conn = flap_connection_getbytype_all(od, SNAC_FAMILY_AUTH)) || !securid)
 		return -EINVAL;
 
 	len = strlen(securid);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+len)))
-		return -ENOMEM;
+	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);
 
-	snacid = aim_cachesnac(sess, OSCAR_FAMILY_AUTH, OSCAR_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, OSCAR_FAMILY_AUTH, OSCAR_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, 0);
+	byte_stream_put16(&frame->data, len);
+	byte_stream_putstr(&frame->data, securid);
 
-	aimbs_put16(&fr->data, len);
-	aimbs_putstr(&fr->data, securid);
-
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
-static void auth_shutdown(OscarSession *sess, aim_module_t *mod)
+static void
+auth_shutdown(OscarData *od, aim_module_t *mod)
 {
-	if (sess->authinfo) {
-		free(sess->authinfo->sn);
-		free(sess->authinfo->bosip);
-		free(sess->authinfo->errorurl);
-		free(sess->authinfo->email);
-		free(sess->authinfo->chpassurl);
-		free(sess->authinfo->latestrelease.name);
-		free(sess->authinfo->latestrelease.url);
-		free(sess->authinfo->latestrelease.info);
-		free(sess->authinfo->latestbeta.name);
-		free(sess->authinfo->latestbeta.url);
-		free(sess->authinfo->latestbeta.info);
-		free(sess->authinfo);
+	if (od->authinfo != NULL)
+	{
+		free(od->authinfo->sn);
+		free(od->authinfo->bosip);
+		free(od->authinfo->errorurl);
+		free(od->authinfo->email);
+		free(od->authinfo->chpassurl);
+		free(od->authinfo->latestrelease.name);
+		free(od->authinfo->latestrelease.url);
+		free(od->authinfo->latestrelease.info);
+		free(od->authinfo->latestbeta.name);
+		free(od->authinfo->latestbeta.url);
+		free(od->authinfo->latestbeta.info);
+		free(od->authinfo);
 	}
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0003)
-		return parse(sess, mod, rx, snac, bs);
+		return parse(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0007)
-		return keyparse(sess, mod, rx, snac, bs);
+		return keyparse(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x000a)
-		return got_securid_request(sess, mod, rx, snac, bs);
+		return got_securid_request(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int auth_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+auth_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x0017;
 	mod->version = 0x0000;
 	mod->flags = 0;
--- a/src/protocols/oscar/family_bart.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_bart.c	Fri Apr 07 05:10:56 2006 +0000
@@ -31,34 +31,33 @@
 /**
  * Subtype 0x0002 - Upload your icon.
  *
- * @param sess The oscar session.
- * @param conn The icon connection for this session.
+ * @param od The oscar session.
  * @param icon The raw data of the icon image file.
  * @param iconlen Length of the raw data of the icon image file.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_bart_upload(OscarSession *sess, const guint8 *icon, guint16 iconlen)
+int
+aim_bart_upload(OscarData *od, const guint8 *icon, guint16 iconlen)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 	FlapFrame *fr;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0010)) || !icon || !iconlen)
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0010)) || !icon || !iconlen)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 2 + 2+iconlen)))
-		return -ENOMEM;
-	snacid = aim_cachesnac(sess, 0x0010, 0x0002, 0x0000, NULL, 0);
+	fr = flap_frame_new(od, 0x02, 10 + 2 + 2+iconlen);
+	snacid = aim_cachesnac(od, 0x0010, 0x0002, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0010, 0x0002, 0x0000, snacid);
 
 	/* The reference number for the icon */
-	aimbs_put16(&fr->data, 1);
+	byte_stream_put16(&fr->data, 1);
 
 	/* The icon */
-	aimbs_put16(&fr->data, iconlen);
-	aimbs_putraw(&fr->data, icon, iconlen);
+	byte_stream_put16(&fr->data, iconlen);
+	byte_stream_putraw(&fr->data, icon, iconlen);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, fr);
 
 	return 0;
 }
@@ -68,19 +67,20 @@
  *
  * You get this honky after you upload a buddy icon.
  */
-static int uploadack(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+uploadack(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 something, somethingelse;
 	guint8 onemorething;
 
-	something = aimbs_get16(bs);
-	somethingelse = aimbs_get16(bs);
-	onemorething = aimbs_get8(bs);
+	something = byte_stream_get16(bs);
+	somethingelse = byte_stream_get16(bs);
+	onemorething = byte_stream_get8(bs);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame);
 
 	return ret;
 }
@@ -88,41 +88,40 @@
 /**
  * Subtype 0x0004 - Request someone's icon.
  *
- * @param sess The oscar session.
- * @param conn The icon connection for this session.
+ * @param od The oscar session.
  * @param sn The screen name of the person who's icon you are requesting.
  * @param iconcsum The MD5 checksum of the icon you are requesting.
  * @param iconcsumlen Length of the MD5 checksum given above.  Should be 10 bytes.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_bart_request(OscarSession *sess, const char *sn, guint8 iconcsumtype, const guint8 *iconcsum, guint16 iconcsumlen)
+int
+aim_bart_request(OscarData *od, const char *sn, guint8 iconcsumtype, const guint8 *iconcsum, guint16 iconcsumlen)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 	FlapFrame *fr;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0010)) || !sn || !strlen(sn) || !iconcsum || !iconcsumlen)
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0010)) || !sn || !strlen(sn) || !iconcsum || !iconcsumlen)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 1+strlen(sn) + 4 + 1+iconcsumlen)))
-		return -ENOMEM;
-	snacid = aim_cachesnac(sess, 0x0010, 0x0004, 0x0000, NULL, 0);
+	fr = flap_frame_new(od, 0x02, 10 + 1+strlen(sn) + 4 + 1+iconcsumlen);
+	snacid = aim_cachesnac(od, 0x0010, 0x0004, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0010, 0x0004, 0x0000, snacid);
 
 	/* Screen name */
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
+	byte_stream_put8(&fr->data, strlen(sn));
+	byte_stream_putstr(&fr->data, sn);
 
 	/* Some numbers.  You like numbers, right? */
-	aimbs_put8(&fr->data, 0x01);
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put8(&fr->data, iconcsumtype);
+	byte_stream_put8(&fr->data, 0x01);
+	byte_stream_put16(&fr->data, 0x0001);
+	byte_stream_put8(&fr->data, iconcsumtype);
 
 	/* Icon string */
-	aimbs_put8(&fr->data, iconcsumlen);
-	aimbs_putraw(&fr->data, iconcsum, iconcsumlen);
+	byte_stream_put8(&fr->data, iconcsumlen);
+	byte_stream_putraw(&fr->data, iconcsum, iconcsumlen);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, fr);
 
 	return 0;
 }
@@ -132,7 +131,8 @@
  *
  * This is sent in response to a buddy icon request.
  */
-static int parseicon(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+parseicon(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -140,16 +140,16 @@
 	guint16 flags, iconlen;
 	guint8 iconcsumtype, iconcsumlen, *iconcsum, *icon;
 
-	sn = aimbs_getstr(bs, aimbs_get8(bs));
-	flags = aimbs_get16(bs);
-	iconcsumtype = aimbs_get8(bs);
-	iconcsumlen = aimbs_get8(bs);
-	iconcsum = aimbs_getraw(bs, iconcsumlen);
-	iconlen = aimbs_get16(bs);
-	icon = aimbs_getraw(bs, iconlen);
+	sn = byte_stream_getstr(bs, byte_stream_get8(bs));
+	flags = byte_stream_get16(bs);
+	iconcsumtype = byte_stream_get8(bs);
+	iconcsumlen = byte_stream_get8(bs);
+	iconcsum = byte_stream_getraw(bs, iconcsumlen);
+	iconlen = byte_stream_get16(bs);
+	icon = byte_stream_getraw(bs, iconlen);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, sn, iconcsumtype, iconcsum, iconcsumlen, icon, iconlen);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, sn, iconcsumtype, iconcsum, iconcsumlen, icon, iconlen);
 
 	free(sn);
 	free(iconcsum);
@@ -158,20 +158,20 @@
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0003)
-		return uploadack(sess, mod, rx, snac, bs);
+		return uploadack(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0005)
-		return parseicon(sess, mod, rx, snac, bs);
+		return parseicon(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int bart_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+bart_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x0010;
 	mod->version = 0x0001;
 	mod->toolid = 0x0010;
--- a/src/protocols/oscar/family_bos.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_bos.c	Fri Apr 07 05:10:56 2006 +0000
@@ -29,13 +29,13 @@
 #include <string.h>
 
 /* Subtype 0x0002 - Request BOS rights. */
-faim_export int aim_bos_reqrights(OscarSession *sess, OscarConnection *conn)
+int aim_bos_reqrights(OscarData *od, FlapConnection *conn)
 {
-	return aim_genericreq_n_snacid(sess, conn, 0x0009, 0x0002);
+	return aim_genericreq_n_snacid(od, conn, 0x0009, 0x0002);
 }
 
 /* Subtype 0x0003 - BOS Rights. */
-static int rights(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	aim_rxcallback_t userfunc;
 	aim_tlvlist_t *tlvlist;
@@ -59,8 +59,8 @@
 	if (aim_tlv_gettlv(tlvlist, 0x0002, 1))
 		maxdenies = aim_tlv_get16(tlvlist, 0x0002, 1);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, maxpermits, maxdenies);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, maxpermits, maxdenies);
 
 	aim_tlvlist_free(&tlvlist);
 
@@ -77,9 +77,9 @@
  * a bitwise OR of all the user classes you want to see you.
  *
  */
-faim_export int aim_bos_setgroupperm(OscarSession *sess, OscarConnection *conn, guint32 mask)
+int aim_bos_setgroupperm(OscarData *od, FlapConnection *conn, guint32 mask)
 {
-	return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask);
+	return aim_genericreq_l(od, conn, 0x0009, 0x0004, &mask);
 }
 
 /*
@@ -110,9 +110,9 @@
  *
  * XXX ye gods.
  */
-faim_export int aim_bos_changevisibility(OscarSession *sess, OscarConnection *conn, int changetype, const char *denylist)
+int aim_bos_changevisibility(OscarData *od, FlapConnection *conn, int changetype, const char *denylist)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	int packlen = 0;
 	guint16 subtype;
 	char *localcpy = NULL, *tmpptr = NULL;
@@ -139,41 +139,38 @@
 	listcount = aimutil_itemcnt(localcpy, '&');
 	packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, packlen))) {
-		free(localcpy);
-		return -ENOMEM;
-	}
+	frame = flap_frame_new(od, 0x02, packlen);
 
-	snacid = aim_cachesnac(sess, 0x0009, subtype, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0009, subtype, 0x00, snacid);
+	snacid = aim_cachesnac(od, 0x0009, subtype, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0009, subtype, 0x00, snacid);
 
 	for (i = 0; (i < (listcount - 1)) && (i < 99); i++) {
 		tmpptr = aimutil_itemindex(localcpy, i, '&');
 
-		aimbs_put8(&fr->data, strlen(tmpptr));
-		aimbs_putstr(&fr->data, tmpptr);
+		byte_stream_put8(&frame->data, strlen(tmpptr));
+		byte_stream_putstr(&frame->data, tmpptr);
 
 		free(tmpptr);
 	}
 	free(localcpy);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0003)
-		return rights(sess, mod, rx, snac, bs);
+		return rights(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int bos_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+bos_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x0009;
 	mod->version = 0x0001;
 	mod->toolid = 0x0110;
--- a/src/protocols/oscar/family_buddy.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_buddy.c	Fri Apr 07 05:10:56 2006 +0000
@@ -33,16 +33,18 @@
  * Request Buddy List rights.
  *
  */
-faim_export int aim_buddylist_reqrights(OscarSession *sess, OscarConnection *conn)
+int
+aim_buddylist_reqrights(OscarData *od, FlapConnection *conn)
 {
-	return aim_genericreq_n_snacid(sess, conn, 0x0003, 0x0002);
+	return aim_genericreq_n_snacid(od, conn, 0x0003, 0x0002);
 }
 
 /*
  * Subtype 0x0003 - Rights.
  *
  */
-static int rights(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	aim_rxcallback_t userfunc;
 	aim_tlvlist_t *tlvlist;
@@ -77,8 +79,8 @@
 	 * ICQ only?
 	 */
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, maxbuddies, maxwatchers);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, maxbuddies, maxwatchers);
 
 	aim_tlvlist_free(&tlvlist);
 
@@ -92,24 +94,24 @@
  * XXX This should just be an extension of setbuddylist()
  *
  */
-faim_export int aim_buddylist_addbuddy(OscarSession *sess, OscarConnection *conn, const char *sn)
+int
+aim_buddylist_addbuddy(OscarData *od, FlapConnection *conn, const char *sn)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
 	if (!sn || !strlen(sn))
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn));
+
+	snacid = aim_cachesnac(od, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1);
+	aim_putsnac(&frame->data, 0x0003, 0x0004, 0x0000, snacid);
 
-	snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1);
-	aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid);
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
 
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
-
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -124,9 +126,10 @@
  * XXX Clean this up.
  *
  */
-faim_export int aim_buddylist_set(OscarSession *sess, OscarConnection *conn, const char *buddy_list)
+int
+aim_buddylist_set(OscarData *od, FlapConnection *conn, const char *buddy_list)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int len = 0;
 	char *localcpy = NULL;
@@ -141,11 +144,10 @@
 		tmpptr = strtok(NULL, "&");
 	}
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+len)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+len);
 
-	snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0003, 0x0004, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0003, 0x0004, 0x0000, snacid);
 
 	strncpy(localcpy, buddy_list, strlen(buddy_list) + 1);
 
@@ -153,12 +155,12 @@
 
 		gaim_debug_misc("oscar", "---adding: %s (%d)\n", tmpptr, strlen(tmpptr));
 
-		aimbs_put8(&fr->data, strlen(tmpptr));
-		aimbs_putstr(&fr->data, tmpptr);
+		byte_stream_put8(&frame->data, strlen(tmpptr));
+		byte_stream_putstr(&frame->data, tmpptr);
 		tmpptr = strtok(NULL, "&");
 	}
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	free(localcpy);
 
@@ -172,79 +174,24 @@
  * the same as setbuddylist() but with a different snac subtype).
  *
  */
-faim_export int aim_buddylist_removebuddy(OscarSession *sess, OscarConnection *conn, const char *sn)
+int
+aim_buddylist_removebuddy(OscarData *od, FlapConnection *conn, const char *sn)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
 	if (!sn || !strlen(sn))
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1);
-	aim_putsnac(&fr->data, 0x0003, 0x0005, 0x0000, snacid);
-
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
-
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
-}
+	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn));
 
-/*
- * Subtype 0x000b
- *
- * XXX Why would we send this?
- *
- */
-faim_export int aim_buddylist_oncoming(OscarSession *sess, OscarConnection *conn, aim_userinfo_t *info)
-{
-	FlapFrame *fr;
-	aim_snacid_t snacid;
-
-	if (!sess || !conn || !info)
-		return -EINVAL;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0003, 0x000b, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1);
+	aim_putsnac(&frame->data, 0x0003, 0x0005, 0x0000, snacid);
 
-	aim_putsnac(&fr->data, 0x0003, 0x000b, 0x0000, snacid);
-	aim_putuserinfo(&fr->data, info);
-
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
-}
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
 
-/* 
- * Subtype 0x000c
- *
- * XXX Why would we send this?
- *
- */
-faim_export int aim_buddylist_offgoing(OscarSession *sess, OscarConnection *conn, const char *sn)
-{
-	FlapFrame *fr;
-	aim_snacid_t snacid;
-
-	if (!sess || !conn || !sn)
-		return -EINVAL;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0003, 0x000c, 0x0000, NULL, 0);
-
-	aim_putsnac(&fr->data, 0x0003, 0x000c, 0x0000, snacid);
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
-
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -260,38 +207,39 @@
  * it is still in a format parsable by aim_info_extract().
  *
  */
-static int buddychange(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+buddychange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_userinfo_t userinfo;
 	aim_rxcallback_t userfunc;
 
-	aim_info_extract(sess, bs, &userinfo);
+	aim_info_extract(od, bs, &userinfo);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, &userinfo);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, &userinfo);
 
 	if (snac->subtype == 0x000b)
-		aim_locate_requestuserinfo(sess, userinfo.sn);
+		aim_locate_requestuserinfo(od, userinfo.sn);
 	aim_info_free(&userinfo);
 
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0003)
-		return rights(sess, mod, rx, snac, bs);
+		return rights(od, conn, mod, frame, snac, bs);
 	else if ((snac->subtype == 0x000b) || (snac->subtype == 0x000c))
-		return buddychange(sess, mod, rx, snac, bs);
+		return buddychange(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int buddylist_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+buddylist_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x0003;
 	mod->version = 0x0001;
 	mod->toolid = 0x0110;
--- a/src/protocols/oscar/family_chat.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_chat.c	Fri Apr 07 05:10:56 2006 +0000
@@ -28,13 +28,15 @@
 #include <string.h>
 
 /* Stored in the ->internal of chat connections */
-struct chatconnpriv {
+struct chatconnpriv
+{
 	guint16 exchange;
 	char *name;
 	guint16 instance;
 };
 
-faim_internal void oscar_connection_destroy_chat(OscarSession *sess, OscarConnection *conn)
+void
+flap_connection_destroy_chat(OscarData *od, FlapConnection *conn)
 {
 	struct chatconnpriv *ccp = (struct chatconnpriv *)conn->internal;
 
@@ -45,14 +47,15 @@
 	return;
 }
 
-faim_export char *aim_chat_getname(OscarConnection *conn)
+char *
+aim_chat_getname(FlapConnection *conn)
 {
 	struct chatconnpriv *ccp;
 
 	if (!conn)
 		return NULL;
 
-	if (conn->type != AIM_CONN_TYPE_CHAT)
+	if (conn->type != SNAC_FAMILY_CHAT)
 		return NULL;
 
 	ccp = (struct chatconnpriv *)conn->internal;
@@ -61,19 +64,20 @@
 }
 
 /* XXX get this into conn.c -- evil!! */
-faim_export OscarConnection *aim_chat_getconn(OscarSession *sess, const char *name)
+FlapConnection *
+aim_chat_getconn(OscarData *od, const char *name)
 {
 	GList *cur;
 
-	for (cur = sess->oscar_connections; cur; cur = cur->next)
+	for (cur = od->oscar_connections; cur; cur = cur->next)
 	{
-		OscarConnection *conn;
+		FlapConnection *conn;
 		struct chatconnpriv *ccp;
 
 		conn = cur->data;
 		ccp = (struct chatconnpriv *)conn->internal;
 
-		if (conn->type != AIM_CONN_TYPE_CHAT)
+		if (conn->type != SNAC_FAMILY_CHAT)
 			continue;
 		if (!conn->internal) {
 			gaim_debug_misc("oscar", "faim: chat: chat connection with no name! (fd = %d)\n", conn->fd);
@@ -87,7 +91,8 @@
 	return NULL;
 }
 
-faim_export int aim_chat_attachname(OscarConnection *conn, guint16 exchange, const char *roomname, guint16 instance)
+int
+aim_chat_attachname(FlapConnection *conn, guint16 exchange, const char *roomname, guint16 instance)
 {
 	struct chatconnpriv *ccp;
 
@@ -97,8 +102,7 @@
 	if (conn->internal)
 		free(conn->internal);
 
-	if (!(ccp = malloc(sizeof(struct chatconnpriv))))
-		return -ENOMEM;
+	ccp = g_new(struct chatconnpriv, 1);
 
 	ccp->exchange = exchange;
 	ccp->name = strdup(roomname);
@@ -109,29 +113,31 @@
 	return 0;
 }
 
-faim_internal int aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo)
+int
+aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo)
 {
 	int namelen;
 
 	if (!bs || !outinfo)
 		return 0;
 
-	outinfo->exchange = aimbs_get16(bs);
-	namelen = aimbs_get8(bs);
-	outinfo->name = aimbs_getstr(bs, namelen);
-	outinfo->instance = aimbs_get16(bs);
+	outinfo->exchange = byte_stream_get16(bs);
+	namelen = byte_stream_get8(bs);
+	outinfo->name = byte_stream_getstr(bs, namelen);
+	outinfo->instance = byte_stream_get16(bs);
 
 	return 0;
 }
 
-faim_export int aim_chat_leaveroom(OscarSession *sess, const char *name)
+int
+aim_chat_leaveroom(OscarData *od, const char *name)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 
-	if (!(conn = aim_chat_getconn(sess, name)))
+	if (!(conn = aim_chat_getconn(od, name)))
 		return -ENOENT;
 
-	aim_conn_close(sess, conn);
+	flap_connection_close(od, conn);
 
 	return 0;
 }
@@ -144,7 +150,8 @@
  *	- Language (English)
  *
  */
-static int infoupdate(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+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;
@@ -163,14 +170,14 @@
 
 	aim_chat_readroominfo(bs, &roominfo);
 
-	detaillevel = aimbs_get8(bs);
+	detaillevel = byte_stream_get8(bs);
 
 	if (detaillevel != 0x02) {
 		gaim_debug_misc("oscar", "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel);
 		return 1;
 	}
 
-	tlvcount = aimbs_get16(bs);
+	tlvcount = byte_stream_get16(bs);
 
 	/*
 	 * Everything else are TLVs.
@@ -202,10 +209,10 @@
 		/* Allocate enough userinfo structs for all occupants */
 		userinfo = calloc(usercount, sizeof(aim_userinfo_t));
 
-		aim_bstream_init(&occbs, tmptlv->value, tmptlv->length);
+		byte_stream_init(&occbs, tmptlv->value, tmptlv->length);
 
 		while (curoccupant < usercount)
-			aim_info_extract(sess, &occbs, &userinfo[curoccupant++]);
+			aim_info_extract(od, &occbs, &userinfo[curoccupant++]);
 	}
 
 	/*
@@ -289,9 +296,9 @@
 	if (aim_tlv_gettlv(tlvlist, 0x000da, 1))
 		maxvisiblemsglen = aim_tlv_get16(tlvlist, 0x00da, 1);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
-		ret = userfunc(sess,
-				rx,
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
+		ret = userfunc(od, conn,
+				frame,
 				&roominfo,
 				roomname,
 				usercount,
@@ -319,20 +326,21 @@
 }
 
 /* Subtypes 0x0003 and 0x0004 */
-static int userlistchange(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+userlistchange(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 curcount = 0, ret = 0;
 
-	while (aim_bstream_empty(bs)) {
+	while (byte_stream_empty(bs)) {
 		curcount++;
 		userinfo = realloc(userinfo, curcount * sizeof(aim_userinfo_t));
-		aim_info_extract(sess, bs, &userinfo[curcount-1]);
+		aim_info_extract(od, bs, &userinfo[curcount-1]);
 	}
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, curcount, userinfo);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, curcount, userinfo);
 
 	aim_info_free(userinfo);
 	free(userinfo);
@@ -352,23 +360,23 @@
  *
  * XXX convert this to use tlvchains
  */
-faim_export int aim_chat_send_im(OscarSession *sess, OscarConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language)
+int
+aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language)
 {
 	int i;
-	FlapFrame *fr;
+	FlapFrame *frame;
 	IcbmCookie *cookie;
 	aim_snacid_t snacid;
 	guint8 ckstr[8];
 	aim_tlvlist_t *otl = NULL, *itl = NULL;
 
-	if (!sess || !conn || !msg || (msglen <= 0))
+	if (!od || !conn || !msg || (msglen <= 0))
 		return 0;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 1152);
 
-	snacid = aim_cachesnac(sess, 0x000e, 0x0005, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x000e, 0x0005, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x000e, 0x0005, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x000e, 0x0005, 0x0000, snacid);
 
 	/*
 	 * Cookie
@@ -382,11 +390,11 @@
 	cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL);
 	cookie->data = NULL; /* XXX store something useful here */
 
-	aim_cachecookie(sess, cookie);
+	aim_cachecookie(od, cookie);
 
 	/* ICBM Header */
-	aimbs_putraw(&fr->data, ckstr, 8); /* Cookie */
-	aimbs_put16(&fr->data, 0x0003); /* Channel */
+	byte_stream_putraw(&frame->data, ckstr, 8); /* Cookie */
+	byte_stream_put16(&frame->data, 0x0003); /* Channel */
 
 	/*
 	 * Type 1: Flag meaning this message is destined to the room.
@@ -431,12 +439,12 @@
 	 */
 	aim_tlvlist_add_frozentlvlist(&otl, 0x0005, &itl);
 
-	aim_tlvlist_write(&fr->data, &otl);
+	aim_tlvlist_write(&frame->data, &otl);
 
 	aim_tlvlist_free(&itl);
 	aim_tlvlist_free(&otl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -466,7 +474,8 @@
  *       possibly others
  *
  */
-static int incomingim_ch3(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+incomingim_ch3(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0, i;
 	aim_rxcallback_t userfunc;
@@ -485,9 +494,9 @@
 	 * Read ICBM Cookie.
 	 */
 	for (i = 0; i < 8; i++)
-		cookie[i] = aimbs_get8(bs);
+		cookie[i] = byte_stream_get8(bs);
 
-	if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) {
+	if ((ck = aim_uncachecookie(od, cookie, AIM_COOKIETYPE_CHAT))) {
 		free(ck->data);
 		free(ck);
 	}
@@ -498,7 +507,7 @@
 	 * Channel 0x0003 is used for chat messages.
 	 *
 	 */
-	channel = aimbs_get16(bs);
+	channel = byte_stream_get16(bs);
 
 	if (channel != 0x0003) {
 		gaim_debug_misc("oscar", "faim: chat_incoming: unknown channel! (0x%04x)\n", channel);
@@ -519,8 +528,8 @@
 
 		userinfotlv = aim_tlv_gettlv(otl, 0x0003, 1);
 
-		aim_bstream_init(&tbs, userinfotlv->value, userinfotlv->length);
-		aim_info_extract(sess, &tbs, &userinfo);
+		byte_stream_init(&tbs, userinfotlv->value, userinfotlv->length);
+		aim_info_extract(od, &tbs, &userinfo);
 	}
 
 #if 0
@@ -542,7 +551,7 @@
 		ByteStream tbs;
 
 		msgblock = aim_tlv_gettlv(otl, 0x0005, 1);
-		aim_bstream_init(&tbs, msgblock->value, msgblock->length);
+		byte_stream_init(&tbs, msgblock->value, msgblock->length);
 		itl = aim_tlvlist_read(&tbs);
 
 		/*
@@ -568,8 +577,8 @@
 		aim_tlvlist_free(&itl);
 	}
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, &userinfo, len, msg, encoding, language);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, &userinfo, len, msg, encoding, language);
 
 	aim_info_free(&userinfo);
 	free(msg);
@@ -578,22 +587,22 @@
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0002)
-		return infoupdate(sess, mod, rx, snac, bs);
+		return infoupdate(od, conn, mod, frame, snac, bs);
 	else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004))
-		return userlistchange(sess, mod, rx, snac, bs);
+		return userlistchange(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0006)
-		return incomingim_ch3(sess, mod, rx, snac, bs);
+		return incomingim_ch3(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int chat_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+chat_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x000e;
 	mod->version = 0x0001;
 	mod->toolid = 0x0010;
--- a/src/protocols/oscar/family_chatnav.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_chatnav.c	Fri Apr 07 05:10:56 2006 +0000
@@ -35,36 +35,35 @@
  * conn must be a chatnav connection!
  *
  */
-faim_export int aim_chatnav_reqrights(OscarSession *sess, OscarConnection *conn)
+int aim_chatnav_reqrights(OscarData *od, FlapConnection *conn)
 {
-	return aim_genericreq_n_snacid(sess, conn, 0x000d, 0x0002);
+	return aim_genericreq_n_snacid(od, conn, 0x000d, 0x0002);
 }
 
 /*
  * Subtype 0x0008
  */
-faim_export int aim_chatnav_createroom(OscarSession *sess, OscarConnection *conn, const char *name, guint16 exchange)
+int aim_chatnav_createroom(OscarData *od, FlapConnection *conn, const char *name, guint16 exchange)
 {
 	static const char ck[] = {"create"};
 	static const char lang[] = {"en"};
 	static const char charset[] = {"us-ascii"};
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 1152);
 
-	snacid = aim_cachesnac(sess, 0x000d, 0x0008, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x000d, 0x0008, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x000d, 0x0008, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x000d, 0x0008, 0x0000, snacid);
 
 	/* exchange */
-	aimbs_put16(&fr->data, exchange);
+	byte_stream_put16(&frame->data, exchange);
 
 	/*
 	 * This looks to be a big hack.  You'll note that this entire
 	 * SNAC is just a room info structure, but the hard room name,
-	 * here, is set to "create".  
+	 * here, is set to "create".
 	 *
 	 * Either this goes on the "list of questions concerning
 	 * why-the-hell-did-you-do-that", or this value is completely
@@ -72,36 +71,37 @@
 	 * AOL style, I'm going to guess that it is the latter, and that
 	 * the value of the room name in create requests is ignored.
 	 */
-	aimbs_put8(&fr->data, strlen(ck));
-	aimbs_putstr(&fr->data, ck);
+	byte_stream_put8(&frame->data, strlen(ck));
+	byte_stream_putstr(&frame->data, ck);
 
-	/* 
+	/*
 	 * instance
-	 * 
+	 *
 	 * Setting this to 0xffff apparently assigns the last instance.
 	 *
 	 */
-	aimbs_put16(&fr->data, 0xffff);
+	byte_stream_put16(&frame->data, 0xffff);
 
 	/* detail level */
-	aimbs_put8(&fr->data, 0x01);
+	byte_stream_put8(&frame->data, 0x01);
 
 	aim_tlvlist_add_str(&tl, 0x00d3, name);
 	aim_tlvlist_add_str(&tl, 0x00d6, charset);
 	aim_tlvlist_add_str(&tl, 0x00d7, lang);
 
 	/* tlvcount */
-	aimbs_put16(&fr->data, aim_tlvlist_count(&tl));
-	aim_tlvlist_write(&fr->data, &tl);
+	byte_stream_put16(&frame->data, aim_tlvlist_count(&tl));
+	aim_tlvlist_write(&frame->data, &tl);
 
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
-static int parseinfo_perms(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs, aim_snac_t *snac2)
+static int
+parseinfo_perms(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs, aim_snac_t *snac2)
 {
 	aim_rxcallback_t userfunc;
 	int ret = 0;
@@ -113,30 +113,30 @@
 
 	tlvlist = aim_tlvlist_read(bs);
 
-	/* 
+	/*
 	 * Type 0x0002: Maximum concurrent rooms.
-	 */ 
+	 */
 	if (aim_tlv_gettlv(tlvlist, 0x0002, 1))
 		maxrooms = aim_tlv_get8(tlvlist, 0x0002, 1);
 
-	/* 
+	/*
 	 * Type 0x0003: Exchange information
 	 *
 	 * There can be any number of these, each one
-	 * representing another exchange.  
-	 * 
+	 * representing another exchange.
+	 *
 	 */
 	for (curexchange = 0; ((exchangetlv = aim_tlv_gettlv(tlvlist, 0x0003, curexchange+1))); ) {
 		ByteStream tbs;
 
-		aim_bstream_init(&tbs, exchangetlv->value, exchangetlv->length);
+		byte_stream_init(&tbs, exchangetlv->value, exchangetlv->length);
 
 		curexchange++;
 
 		exchanges = realloc(exchanges, curexchange * sizeof(struct aim_chat_exchangeinfo));
 
 		/* exchange number */
-		exchanges[curexchange-1].number = aimbs_get16(&tbs);
+		exchanges[curexchange-1].number = byte_stream_get16(&tbs);
 		innerlist = aim_tlvlist_read(&tbs);
 
 #if 0
@@ -213,7 +213,7 @@
 		/*
 		 * Type 0x00d2: Maximum Occupancy?
 		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d2, 1)) {	
+		if (aim_tlv_gettlv(innerlist, 0x00d2, 1)) {
 			/* Unhandled */
 		}
 #endif
@@ -221,7 +221,7 @@
 		/*
 		 * Type 0x00d3: Exchange Description
 		 */
-		if (aim_tlv_gettlv(innerlist, 0x00d3, 1))	
+		if (aim_tlv_gettlv(innerlist, 0x00d3, 1))
 			exchanges[curexchange-1].name = aim_tlv_getstr(innerlist, 0x00d3, 1);
 		else
 			exchanges[curexchange-1].name = NULL;
@@ -241,7 +241,7 @@
 		 * 0  Creation not allowed
 		 * 1  Room creation allowed
 		 * 2  Exchange creation allowed
-		 * 
+		 *
 		 */
 		if (aim_tlv_gettlv(innerlist, 0x00d5, 1)) {
 			guint8 createperms;
@@ -251,32 +251,32 @@
 
 		/*
 		 * Type 0x00d6: Character Set (First Time)
-		 */	      
-		if (aim_tlv_gettlv(innerlist, 0x00d6, 1))	
+		 */
+		if (aim_tlv_gettlv(innerlist, 0x00d6, 1))
 			exchanges[curexchange-1].charset1 = aim_tlv_getstr(innerlist, 0x00d6, 1);
 		else
 			exchanges[curexchange-1].charset1 = NULL;
-		      
+
 		/*
 		 * Type 0x00d7: Language (First Time)
-		 */	      
-		if (aim_tlv_gettlv(innerlist, 0x00d7, 1))	
+		 */
+		if (aim_tlv_gettlv(innerlist, 0x00d7, 1))
 			exchanges[curexchange-1].lang1 = aim_tlv_getstr(innerlist, 0x00d7, 1);
 		else
 			exchanges[curexchange-1].lang1 = NULL;
 
 		/*
 		 * Type 0x00d8: Character Set (Second Time)
-		 */	      
-		if (aim_tlv_gettlv(innerlist, 0x00d8, 1))	
+		 */
+		if (aim_tlv_gettlv(innerlist, 0x00d8, 1))
 			exchanges[curexchange-1].charset2 = aim_tlv_getstr(innerlist, 0x00d8, 1);
 		else
 			exchanges[curexchange-1].charset2 = NULL;
 
 		/*
 		 * Type 0x00d9: Language (Second Time)
-		 */	      
-		if (aim_tlv_gettlv(innerlist, 0x00d9, 1))	
+		 */
+		if (aim_tlv_gettlv(innerlist, 0x00d9, 1))
 			exchanges[curexchange-1].lang2 = aim_tlv_getstr(innerlist, 0x00d9, 1);
 		else
 			exchanges[curexchange-1].lang2 = NULL;
@@ -296,8 +296,8 @@
 	/*
 	 * Call client.
 	 */
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, snac2->type, maxrooms, curexchange, exchanges);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, snac2->type, maxrooms, curexchange, exchanges);
 
 	for (curexchange--; curexchange >= 0; curexchange--) {
 		free(exchanges[curexchange].name);
@@ -312,7 +312,8 @@
 	return ret;
 }
 
-static int parseinfo_create(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs, aim_snac_t *snac2)
+static int
+parseinfo_create(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs, aim_snac_t *snac2)
 {
 	aim_rxcallback_t userfunc;
 	aim_tlvlist_t *tlvlist, *innerlist;
@@ -333,13 +334,13 @@
 		return 0;
 	}
 
-	aim_bstream_init(&bbbs, bigblock->value, bigblock->length);
+	byte_stream_init(&bbbs, bigblock->value, bigblock->length);
 
-	exchange = aimbs_get16(&bbbs);
-	cklen = aimbs_get8(&bbbs);
-	ck = aimbs_getstr(&bbbs, cklen);
-	instance = aimbs_get16(&bbbs);
-	detaillevel = aimbs_get8(&bbbs);
+	exchange = byte_stream_get16(&bbbs);
+	cklen = byte_stream_get8(&bbbs);
+	ck = byte_stream_getstr(&bbbs, cklen);
+	instance = byte_stream_get16(&bbbs);
+	detaillevel = byte_stream_get8(&bbbs);
 
 	if (detaillevel != 0x02) {
 		gaim_debug_misc("oscar", "unknown detaillevel in create room response (0x%02x)\n", detaillevel);
@@ -348,7 +349,7 @@
 		return 0;
 	}
 
-	unknown = aimbs_get16(&bbbs);
+	unknown = byte_stream_get16(&bbbs);
 
 	innerlist = aim_tlvlist_read(&bbbs);
 
@@ -373,8 +374,8 @@
 	if (aim_tlv_gettlv(innerlist, 0x00d5, 1))
 		createperms = aim_tlv_get8(innerlist, 0x00d5, 1);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
-		ret = userfunc(sess, rx, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
+		ret = userfunc(od, conn, frame, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck);
 	}
 
 	free(ck);
@@ -389,7 +390,7 @@
 /*
  * Subtype 0x0009
  *
- * Since multiple things can trigger this callback, we must lookup the 
+ * Since multiple things can trigger this callback, we must lookup the
  * snacid to determine the original snac subtype that was called.
  *
  * XXX This isn't really how this works.  But this is:  Every d/9 response
@@ -399,17 +400,18 @@
  *    Instance Info = 4
  *    Nav Short Desc = 8
  *    Nav Instance Info = 16
- * And then everything is really asynchronous.  There is no specific 
+ * And then everything is really asynchronous.  There is no specific
  * attachment of a response to a create room request, for example.  Creating
  * the room yields no different a response than requesting the room's info.
  *
  */
-static int parseinfo(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+parseinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	aim_snac_t *snac2;
 	int ret = 0;
 
-	if (!(snac2 = aim_remsnac(sess, snac->id))) {
+	if (!(snac2 = aim_remsnac(od, snac->id))) {
 		gaim_debug_misc("oscar", "faim: chatnav_parse_info: received response to unknown request! (%08lx)\n", snac->id);
 		return 0;
 	}
@@ -423,7 +425,7 @@
 	 * We now know what the original SNAC subtype was.
 	 */
 	if (snac2->type == 0x0002) /* request chat rights */
-		ret = parseinfo_perms(sess, mod, rx, snac, bs, snac2);
+		ret = parseinfo_perms(od, conn, mod, frame, snac, bs, snac2);
 	else if (snac2->type == 0x0003) /* request exchange info */
 		gaim_debug_misc("oscar", "chatnav_parse_info: resposne to exchange info\n");
 	else if (snac2->type == 0x0004) /* request room info */
@@ -435,7 +437,7 @@
 	else if (snac2->type == 0x0007) /* search for a room */
 		gaim_debug_misc("oscar", "chatnav_parse_info: search results\n");
 	else if (snac2->type == 0x0008) /* create room */
-		ret = parseinfo_create(sess, mod, rx, snac, bs, snac2);
+		ret = parseinfo_create(od, conn, mod, frame, snac, bs, snac2);
 	else
 		gaim_debug_misc("oscar", "chatnav_parse_info: unknown request subtype (%04x)\n", snac2->type);
 
@@ -446,18 +448,18 @@
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0009)
-		return parseinfo(sess, mod, rx, snac, bs);
+		return parseinfo(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int chatnav_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+chatnav_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x000d;
 	mod->version = 0x0001;
 	mod->toolid = 0x0010;
--- a/src/protocols/oscar/family_feedbag.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_feedbag.c	Fri Apr 07 05:10:56 2006 +0000
@@ -81,8 +81,7 @@
 	if (newlen > 0) {
 		guint8 *newdata;
 
-		if (!(newdata = (guint8 *)malloc((newlen)*sizeof(guint8))))
-			return NULL;
+		newdata = (guint8 *)malloc((newlen)*sizeof(guint8));
 		newlen = 0;
 		if (group->gid == 0x0000) {
 			for (cur=list; cur; cur=cur->next)
@@ -105,7 +104,7 @@
  * Locally add a new item to the given item list.
  *
  * @param list A pointer to a pointer to the current list of items.
- * @param name A null terminated string of the name of the new item, or NULL if the 
+ * @param name A null terminated string of the name of the new item, or NULL if the
  *        item should have no name.
  * @param gid The group ID# you want the new item to have, or 0xFFFF if we should pick something.
  * @param bid The buddy ID# you want the new item to have, or 0xFFFF if we should pick something.
@@ -121,8 +120,7 @@
 	if (!list)
 		return NULL;
 
-	if (!(new = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item))))
-		return NULL;
+	new = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item));
 
 	/* Set the name */
 	if (name) {
@@ -268,7 +266,7 @@
  * @param bid The buddy ID# of the desired item.
  * @return Return a pointer to the item if found, else return NULL;
  */
-faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid)
+struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid)
 {
 	struct aim_ssi_item *cur;
 	for (cur=list; cur; cur=cur->next)
@@ -287,7 +285,7 @@
  * @param type The type of the desired item.
  * @return Return a pointer to the item if found, else return NULL.
  */
-faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, guint16 type)
+struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, guint16 type)
 {
 	struct aim_ssi_item *cur;
 	if (!list)
@@ -332,7 +330,7 @@
  * @param sn The group name of the desired item.
  * @return Return a pointer to the name of the item if found, else return NULL;
  */
-faim_export struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn)
+struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn)
 {
 	struct aim_ssi_item *cur;
 	if (!list || !sn)
@@ -350,7 +348,7 @@
  * @param bn The buddy name of the desired item.
  * @return Return a pointer to the name of the item if found, else return NULL;
  */
-faim_export char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn)
+char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn)
 {
 	struct aim_ssi_item *cur, *curg;
 	if (!list || !sn)
@@ -368,7 +366,7 @@
  * @param list A pointer to the current list of items.
  * @return Return the current SSI permit deny setting, or 0 if no setting was found.
  */
-faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list)
+int aim_ssi_getpermdeny(struct aim_ssi_item *list)
 {
 	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO);
 	if (cur) {
@@ -387,7 +385,7 @@
  * @param list A pointer to the current list of items.
  * @return Return the current visibility mask.
  */
-faim_export guint32 aim_ssi_getpresence(struct aim_ssi_item *list)
+guint32 aim_ssi_getpresence(struct aim_ssi_item *list)
 {
 	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS);
 	if (cur) {
@@ -404,11 +402,11 @@
  * @param list A pointer to the current list of items.
  * @param gn The group of the buddy.
  * @param sn The name of the buddy.
- * @return A pointer to a NULL terminated string that is the buddy's 
+ * @return A pointer to a NULL terminated string that is the buddy's
  *         alias, or NULL if the buddy has no alias.  You should free
  *         this returned value!
  */
-faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn)
+char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn)
 {
 	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
 	if (cur) {
@@ -429,11 +427,11 @@
  * @param list A pointer to the current list of items.
  * @param gn The group of the buddy.
  * @param sn The name of the buddy.
- * @return A pointer to a NULL terminated string that is the buddy's 
+ * @return A pointer to a NULL terminated string that is the buddy's
  *         comment, or NULL if the buddy has no comment.  You should free
  *         this returned value!
  */
-faim_export char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *sn)
+char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *sn)
 {
 	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
 	if (cur) {
@@ -456,7 +454,7 @@
  * @param sn The name of the buddy.
  * @return 1 if you are waiting for authorization; 0 if you are not
  */
-faim_export int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn)
+int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn)
 {
 	struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
 	if (cur) {
@@ -470,100 +468,100 @@
  * If there are changes, then create temporary items and 
  * call addmoddel.
  *
- * @param sess The oscar session.
+ * @param od The oscar session.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-static int aim_ssi_sync(OscarSession *sess)
+static int aim_ssi_sync(OscarData *od)
 {
 	struct aim_ssi_item *cur1, *cur2;
 	struct aim_ssi_tmp *cur, *new;
 
-	if (!sess)
+	if (!od)
 		return -EINVAL;
 
 	/* If we're waiting for an ack, we shouldn't do anything else */
-	if (sess->ssi.waiting_for_ack)
+	if (od->ssi.waiting_for_ack)
 		return 0;
 
 	/*
-	 * Compare the 2 lists and create an aim_ssi_tmp for each difference.  
-	 * We should only send either additions, modifications, or deletions 
-	 * before waiting for an acknowledgement.  So first do deletions, then 
-	 * additions, then modifications.  Also, both the official and the local 
-	 * list should be in ascending numerical order for the group ID#s and the 
+	 * Compare the 2 lists and create an aim_ssi_tmp for each difference.
+	 * We should only send either additions, modifications, or deletions
+	 * before waiting for an acknowledgement.  So first do deletions, then
+	 * additions, then modifications.  Also, both the official and the local
+	 * list should be in ascending numerical order for the group ID#s and the
 	 * buddy ID#s, which makes things more efficient.  I think.
 	 */
 
 	/* Additions */
-	if (!sess->ssi.pending) {
-		for (cur1=sess->ssi.local; cur1; cur1=cur1->next) {
-			if (!aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid)) {
+	if (!od->ssi.pending) {
+		for (cur1=od->ssi.local; cur1; cur1=cur1->next) {
+			if (!aim_ssi_itemlist_find(od->ssi.official, cur1->gid, cur1->bid)) {
 				new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
-				new->action = OSCAR_SUBTYPE_FEEDBAG_ADD;
+				new->action = SNAC_SUBTYPE_FEEDBAG_ADD;
 				new->ack = 0xffff;
 				new->name = NULL;
 				new->item = cur1;
 				new->next = NULL;
-				if (sess->ssi.pending) {
-					for (cur=sess->ssi.pending; cur->next; cur=cur->next);
+				if (od->ssi.pending) {
+					for (cur=od->ssi.pending; cur->next; cur=cur->next);
 					cur->next = new;
 				} else
-					sess->ssi.pending = new;
+					od->ssi.pending = new;
 			}
 		}
 	}
 
 	/* Deletions */
-	if (!sess->ssi.pending) {
-		for (cur1=sess->ssi.official; cur1; cur1=cur1->next) {
-			if (!aim_ssi_itemlist_find(sess->ssi.local, cur1->gid, cur1->bid)) {
+	if (!od->ssi.pending) {
+		for (cur1=od->ssi.official; cur1; cur1=cur1->next) {
+			if (!aim_ssi_itemlist_find(od->ssi.local, cur1->gid, cur1->bid)) {
 				new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
-				new->action = OSCAR_SUBTYPE_FEEDBAG_DEL;
+				new->action = SNAC_SUBTYPE_FEEDBAG_DEL;
 				new->ack = 0xffff;
 				new->name = NULL;
 				new->item = cur1;
 				new->next = NULL;
-				if (sess->ssi.pending) {
-					for (cur=sess->ssi.pending; cur->next; cur=cur->next);
+				if (od->ssi.pending) {
+					for (cur=od->ssi.pending; cur->next; cur=cur->next);
 					cur->next = new;
 				} else
-					sess->ssi.pending = new;
+					od->ssi.pending = new;
 			}
 		}
 	}
 
 	/* Modifications */
-	if (!sess->ssi.pending) {
-		for (cur1=sess->ssi.local; cur1; cur1=cur1->next) {
-			cur2 = aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid);
+	if (!od->ssi.pending) {
+		for (cur1=od->ssi.local; cur1; cur1=cur1->next) {
+			cur2 = aim_ssi_itemlist_find(od->ssi.official, cur1->gid, cur1->bid);
 			if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) {
 				new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
-				new->action = OSCAR_SUBTYPE_FEEDBAG_MOD;
+				new->action = SNAC_SUBTYPE_FEEDBAG_MOD;
 				new->ack = 0xffff;
 				new->name = NULL;
 				new->item = cur1;
 				new->next = NULL;
-				if (sess->ssi.pending) {
-					for (cur=sess->ssi.pending; cur->next; cur=cur->next);
+				if (od->ssi.pending) {
+					for (cur=od->ssi.pending; cur->next; cur=cur->next);
 					cur->next = new;
 				} else
-					sess->ssi.pending = new;
+					od->ssi.pending = new;
 			}
 		}
 	}
 
 	/* We're out of stuff to do, so tell the AIM servers we're done and exit */
-	if (!sess->ssi.pending) {
-		aim_ssi_modend(sess);
+	if (!od->ssi.pending) {
+		aim_ssi_modend(od);
 		return 0;
 	}
 
 	/* Make sure we don't send anything else between now 
 	 * and when we receive the ack for the following operation */
-	sess->ssi.waiting_for_ack = 1;
+	od->ssi.waiting_for_ack = 1;
 
 	/* Now go mail off our data and wait 4 to 6 weeks */
-	aim_ssi_addmoddel(sess);
+	aim_ssi_addmoddel(od);
 
 	return 0;
 }
@@ -573,15 +571,15 @@
  *
  * This doesn't remove it from the server, that's different.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-static int aim_ssi_freelist(OscarSession *sess)
+static int aim_ssi_freelist(OscarData *od)
 {
 	struct aim_ssi_item *cur, *del;
 	struct aim_ssi_tmp *curtmp, *deltmp;
 
-	cur = sess->ssi.official;
+	cur = od->ssi.official;
 	while (cur) {
 		del = cur;
 		cur = cur->next;
@@ -590,7 +588,7 @@
 		free(del);
 	}
 
-	cur = sess->ssi.local;
+	cur = od->ssi.local;
 	while (cur) {
 		del = cur;
 		cur = cur->next;
@@ -599,18 +597,18 @@
 		free(del);
 	}
 
-	curtmp = sess->ssi.pending;
+	curtmp = od->ssi.pending;
 	while (curtmp) {
 		deltmp = curtmp;
 		curtmp = curtmp->next;
 		free(deltmp);
 	}
 
-	sess->ssi.numitems = 0;
-	sess->ssi.official = NULL;
-	sess->ssi.local = NULL;
-	sess->ssi.pending = NULL;
-	sess->ssi.timestamp = (time_t)0;
+	od->ssi.numitems = 0;
+	od->ssi.official = NULL;
+	od->ssi.local = NULL;
+	od->ssi.pending = NULL;
+	od->ssi.timestamp = (time_t)0;
 
 	return 0;
 }
@@ -618,18 +616,18 @@
 /**
  * Delete all SSI data.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_deletelist(OscarSession *sess)
+int aim_ssi_deletelist(OscarData *od)
 {
 	struct aim_ssi_item *cur, *del;
 
-	if (!sess)
+	if (!od)
 		return -EINVAL;
 
 	/* Free the local list */
-	cur = sess->ssi.local;
+	cur = od->ssi.local;
 	while (cur) {
 		del = cur;
 		cur = cur->next;
@@ -637,10 +635,10 @@
 		aim_tlvlist_free(&del->data);
 		free(del);
 	}
-	sess->ssi.local = NULL;
+	od->ssi.local = NULL;
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -651,14 +649,14 @@
  * 2) Makes sure that all buddies are in a group that exist.
  * 3) Deletes any empty groups
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_cleanlist(OscarSession *sess)
+int aim_ssi_cleanlist(OscarData *od)
 {
 	struct aim_ssi_item *cur, *next;
 
-	if (!sess)
+	if (!od)
 		return -EINVAL;
 
 	/* Delete any buddies, permits, or denies with empty names. */
@@ -666,27 +664,27 @@
 	/* DESTROY any buddies that are directly in the master group. */
 	/* Do the same for buddies that are in a non-existant group. */
 	/* This will kind of mess up if you hit the item limit, but this function isn't too critical */
-	cur = sess->ssi.local;
+	cur = od->ssi.local;
 	while (cur) {
 		next = cur->next;
 		if (!cur->name) {
 			if (cur->type == AIM_SSI_TYPE_BUDDY)
-				aim_ssi_delbuddy(sess, NULL, NULL);
+				aim_ssi_delbuddy(od, NULL, NULL);
 			else if (cur->type == AIM_SSI_TYPE_PERMIT)
-				aim_ssi_delpermit(sess, NULL);
+				aim_ssi_delpermit(od, NULL);
 			else if (cur->type == AIM_SSI_TYPE_DENY)
-				aim_ssi_deldeny(sess, NULL);
-		} else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(sess->ssi.local, cur->gid, 0x0000)))) {
-			char *alias = aim_ssi_getalias(sess->ssi.local, NULL, cur->name);
-			aim_ssi_addbuddy(sess, cur->name, "orphans", alias, NULL, NULL, 0);
-			aim_ssi_delbuddy(sess, cur->name, NULL);
+				aim_ssi_deldeny(od, NULL);
+		} else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(od->ssi.local, cur->gid, 0x0000)))) {
+			char *alias = aim_ssi_getalias(od->ssi.local, NULL, cur->name);
+			aim_ssi_addbuddy(od, cur->name, "orphans", alias, NULL, NULL, 0);
+			aim_ssi_delbuddy(od, cur->name, NULL);
 			free(alias);
 		}
 		cur = next;
 	}
 
 	/* Make sure there aren't any duplicate buddies in a group, or duplicate permits or denies */
-	cur = sess->ssi.local;
+	cur = od->ssi.local;
 	while (cur) {
 		if ((cur->type == AIM_SSI_TYPE_BUDDY) || (cur->type == AIM_SSI_TYPE_PERMIT) || (cur->type == AIM_SSI_TYPE_DENY))
 		{
@@ -695,7 +693,7 @@
 			while (cur2) {
 				next2 = cur2->next;
 				if ((cur->type == cur2->type) && (cur->gid == cur2->gid) && (cur->name != NULL) && (cur2->name != NULL) && (!strcmp(cur->name, cur2->name))) {
-					aim_ssi_itemlist_del(&sess->ssi.local, cur2);
+					aim_ssi_itemlist_del(&od->ssi.local, cur2);
 				}
 				cur2 = next2;
 			}
@@ -704,23 +702,23 @@
 	}
 
 	/* Check if there are empty groups and delete them */
-	cur = sess->ssi.local;
+	cur = od->ssi.local;
 	while (cur) {
 		next = cur->next;
 		if (cur->type == AIM_SSI_TYPE_GROUP) {
 			aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00c8, 1);
 			if (!tlv || !tlv->length)
-				aim_ssi_itemlist_del(&sess->ssi.local, cur);
+				aim_ssi_itemlist_del(&od->ssi.local, cur);
 		}
 		cur = next;
 	}
 
 	/* Check if the master group is empty */
-	if ((cur = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!cur->data))
-		aim_ssi_itemlist_del(&sess->ssi.local, cur);
+	if ((cur = aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000)) && (!cur->data))
+		aim_ssi_itemlist_del(&od->ssi.local, cur);
 
 	/* If we've made any changes then sync our list with the server's */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -728,7 +726,7 @@
 /**
  * Add a buddy to the list.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param name The name of the item.
  * @param group The group of the item.
  * @param alias The alias/nickname of the item, or NULL.
@@ -736,26 +734,26 @@
  * @param smsnum The locally assigned SMS number, or NULL.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_addbuddy(OscarSession *sess, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth)
+int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth)
 {
 	struct aim_ssi_item *parent;
 	aim_tlvlist_t *data = NULL;
 
-	if (!sess || !name || !group)
+	if (!od || !name || !group)
 		return -EINVAL;
 
 	/* Find the parent */
-	if (!(parent = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) {
+	if (!(parent = aim_ssi_itemlist_finditem(od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) {
 		/* Find the parent's parent (the master group) */
-		if (!(parent = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)))
-			if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL)))
+		if (!(parent = aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000)))
+			if (!(parent = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL)))
 				return -ENOMEM;
 		/* Add the parent */
-		if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL)))
+		if (!(parent = aim_ssi_itemlist_add(&od->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL)))
 			return -ENOMEM;
 
 		/* Modify the parent's parent (the master group) */
-		aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL);
+		aim_ssi_itemlist_rebuildgroup(od->ssi.local, NULL);
 	}
 
 	/* Create a TLV list for the new buddy */
@@ -769,14 +767,14 @@
 		aim_tlvlist_add_str(&data, 0x013c, comment);
 
 	/* Add that bad boy */
-	aim_ssi_itemlist_add(&sess->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data);
+	aim_ssi_itemlist_add(&od->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data);
 	aim_tlvlist_free(&data);
 
 	/* Modify the parent group */
-	aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group);
+	aim_ssi_itemlist_rebuildgroup(od->ssi.local, group);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -784,21 +782,21 @@
 /**
  * Add a permit buddy to the list.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param name The name of the item..
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_addpermit(OscarSession *sess, const char *name)
+int aim_ssi_addpermit(OscarData *od, const char *name)
 {
 
-	if (!sess || !name)
+	if (!od || !name)
 		return -EINVAL;
 
 	/* Add that bad boy */
-	aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL);
+	aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -806,21 +804,21 @@
 /**
  * Add a deny buddy to the list.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param name The name of the item..
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_adddeny(OscarSession *sess, const char *name)
+int aim_ssi_adddeny(OscarData *od, const char *name)
 {
 
-	if (!sess || !name)
+	if (!od || !name)
 		return -EINVAL;
 
 	/* Add that bad boy */
-	aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL);
+	aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -828,43 +826,43 @@
 /**
  * Deletes a buddy from the list.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param name The name of the item, or NULL.
  * @param group The group of the item, or NULL.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_delbuddy(OscarSession *sess, const char *name, const char *group)
+int aim_ssi_delbuddy(OscarData *od, const char *name, const char *group)
 {
 	struct aim_ssi_item *del;
 
-	if (!sess)
+	if (!od)
 		return -EINVAL;
 
 	/* Find the buddy */
-	if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, group, name, AIM_SSI_TYPE_BUDDY)))
+	if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, group, name, AIM_SSI_TYPE_BUDDY)))
 		return -EINVAL;
 
 	/* Remove the item from the list */
-	aim_ssi_itemlist_del(&sess->ssi.local, del);
+	aim_ssi_itemlist_del(&od->ssi.local, del);
 
 	/* Modify the parent group */
-	aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group);
+	aim_ssi_itemlist_rebuildgroup(od->ssi.local, group);
 
 	/* Check if we should delete the parent group */
-	if ((del = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP)) && (!del->data)) {
-		aim_ssi_itemlist_del(&sess->ssi.local, del);
+	if ((del = aim_ssi_itemlist_finditem(od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP)) && (!del->data)) {
+		aim_ssi_itemlist_del(&od->ssi.local, del);
 
 		/* Modify the parent group */
-		aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL);
+		aim_ssi_itemlist_rebuildgroup(od->ssi.local, NULL);
 
 		/* Check if we should delete the parent's parent (the master group) */
-		if ((del = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!del->data)) {
-			aim_ssi_itemlist_del(&sess->ssi.local, del);
+		if ((del = aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000)) && (!del->data)) {
+			aim_ssi_itemlist_del(&od->ssi.local, del);
 		}
 	}
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -872,26 +870,26 @@
 /**
  * Deletes a permit buddy from the list.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param name The name of the item, or NULL.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_delpermit(OscarSession *sess, const char *name)
+int aim_ssi_delpermit(OscarData *od, const char *name)
 {
 	struct aim_ssi_item *del;
 
-	if (!sess)
+	if (!od)
 		return -EINVAL;
 
 	/* Find the item */
-	if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT)))
+	if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT)))
 		return -EINVAL;
 
 	/* Remove the item from the list */
-	aim_ssi_itemlist_del(&sess->ssi.local, del);
+	aim_ssi_itemlist_del(&od->ssi.local, del);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -899,26 +897,26 @@
 /**
  * Deletes a deny buddy from the list.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param name The name of the item, or NULL.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_deldeny(OscarSession *sess, const char *name)
+int aim_ssi_deldeny(OscarData *od, const char *name)
 {
 	struct aim_ssi_item *del;
 
-	if (!sess)
+	if (!od)
 		return -EINVAL;
 
 	/* Find the item */
-	if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_DENY)))
+	if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, AIM_SSI_TYPE_DENY)))
 		return -EINVAL;
 
 	/* Remove the item from the list */
-	aim_ssi_itemlist_del(&sess->ssi.local, del);
+	aim_ssi_itemlist_del(&od->ssi.local, del);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -927,17 +925,17 @@
  * Move a buddy from one group to another group.  This basically just deletes the 
  * buddy and re-adds it.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param oldgn The group that the buddy is currently in.
  * @param newgn The group that the buddy should be moved in to.
  * @param sn The name of the buddy to be moved.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_movebuddy(OscarSession *sess, const char *oldgn, const char *newgn, const char *sn)
+int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *sn)
 {
-	char *alias = aim_ssi_getalias(sess->ssi.local, oldgn, sn);
-	aim_ssi_addbuddy(sess, sn, newgn, alias, NULL, NULL, aim_ssi_waitingforauth(sess->ssi.local, oldgn, sn));
-	aim_ssi_delbuddy(sess, sn, oldgn);
+	char *alias = aim_ssi_getalias(od->ssi.local, oldgn, sn);
+	aim_ssi_addbuddy(od, sn, newgn, alias, NULL, NULL, aim_ssi_waitingforauth(od->ssi.local, oldgn, sn));
+	aim_ssi_delbuddy(od, sn, oldgn);
 	free(alias);
 	return 0;
 }
@@ -945,21 +943,21 @@
 /**
  * Change the alias stored on the server for a given buddy.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param gn The group that the buddy is currently in.
  * @param sn The screen name of the buddy.
  * @param alias The new alias for the buddy, or NULL if you want to remove 
  *        a buddy's comment.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_aliasbuddy(OscarSession *sess, const char *gn, const char *sn, const char *alias)
+int aim_ssi_aliasbuddy(OscarData *od, const char *gn, const char *sn, const char *alias)
 {
 	struct aim_ssi_item *tmp;
 
-	if (!sess || !gn || !sn)
+	if (!od || !gn || !sn)
 		return -EINVAL;
 
-	if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY)))
+	if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY)))
 		return -EINVAL;
 
 	/* Either add or remove the 0x0131 TLV from the TLV chain */
@@ -969,7 +967,7 @@
 		aim_tlvlist_remove(&tmp->data, 0x0131);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -977,21 +975,21 @@
 /**
  * Change the comment stored on the server for a given buddy.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param gn The group that the buddy is currently in.
  * @param sn The screen name of the buddy.
  * @param alias The new comment for the buddy, or NULL if you want to remove 
  *        a buddy's comment.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_editcomment(OscarSession *sess, const char *gn, const char *sn, const char *comment)
+int aim_ssi_editcomment(OscarData *od, const char *gn, const char *sn, const char *comment)
 {
 	struct aim_ssi_item *tmp;
 
-	if (!sess || !gn || !sn)
+	if (!od || !gn || !sn)
 		return -EINVAL;
 
-	if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY)))
+	if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY)))
 		return -EINVAL;
 
 	/* Either add or remove the 0x0131 TLV from the TLV chain */
@@ -1001,7 +999,7 @@
 		aim_tlvlist_remove(&tmp->data, 0x013c);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -1009,19 +1007,19 @@
 /**
  * Rename a group.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param oldgn The old group name.
  * @param newgn The new group name.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_rename_group(OscarSession *sess, const char *oldgn, const char *newgn)
+int aim_ssi_rename_group(OscarData *od, const char *oldgn, const char *newgn)
 {
 	struct aim_ssi_item *group;
 
-	if (!sess || !oldgn || !newgn)
+	if (!od || !oldgn || !newgn)
 		return -EINVAL;
 
-	if (!(group = aim_ssi_itemlist_finditem(sess->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP)))
+	if (!(group = aim_ssi_itemlist_finditem(od->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP)))
 		return -EINVAL;
 
 	free(group->name);
@@ -1029,7 +1027,7 @@
 	strcpy(group->name, newgn);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -1037,7 +1035,7 @@
 /**
  * Stores your permit/deny setting on the server, and starts using it.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param permdeny Your permit/deny setting.  Can be one of the following:
  *        1 - Allow all users
  *        2 - Block all users
@@ -1048,16 +1046,16 @@
  *        visible.  See the AIM_FLAG_BLEH #defines in oscar.h
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_setpermdeny(OscarSession *sess, guint8 permdeny, guint32 vismask)
+int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny, guint32 vismask)
 {
 	struct aim_ssi_item *tmp;
 
-	if (!sess)
+	if (!od)
 		return -EINVAL;
 
 	/* Find the PDINFO item, or add it if it does not exist */
-	if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO)))
-		tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, NULL);
+	if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO)))
+		tmp = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, NULL);
 
 	/* Need to add the 0x00ca TLV to the TLV chain */
 	aim_tlvlist_replace_8(&tmp->data, 0x00ca, permdeny);
@@ -1066,7 +1064,7 @@
 	aim_tlvlist_replace_32(&tmp->data, 0x00cb, vismask);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -1074,27 +1072,26 @@
 /**
  * Set buddy icon information
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param iconcsum The MD5 checksum of the icon you are using.
  * @param iconcsumlen Length of the MD5 checksum given above.  Should be 0x10 bytes.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_seticon(OscarSession *sess, guint8 *iconsum, guint16 iconsumlen)
+int aim_ssi_seticon(OscarData *od, guint8 *iconsum, guint16 iconsumlen)
 {
 	struct aim_ssi_item *tmp;
 	guint8 *csumdata;
 
-	if (!sess || !iconsum || !iconsumlen)
+	if (!od || !iconsum || !iconsumlen)
 		return -EINVAL;
 
 	/* Find the ICONINFO item, or add it if it does not exist */
-	if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) {
-		tmp = aim_ssi_itemlist_add(&sess->ssi.local, "1", 0x0000, 0x51F4, AIM_SSI_TYPE_ICONINFO, NULL);
+	if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) {
+		tmp = aim_ssi_itemlist_add(&od->ssi.local, "1", 0x0000, 0x51F4, AIM_SSI_TYPE_ICONINFO, NULL);
 	}
 
 	/* Need to add the 0x00d5 TLV to the TLV chain */
-	if (!(csumdata = (guint8 *)malloc((iconsumlen+2)*sizeof(guint8))))
-		return -ENOMEM;
+	csumdata = (guint8 *)malloc((iconsumlen+2)*sizeof(guint8));
 	csumdata[0] = 0x00;
 	csumdata[1] = 0x10;
 	memcpy(&csumdata[2], iconsum, iconsumlen);
@@ -1105,30 +1102,30 @@
 	aim_tlvlist_replace_noval(&tmp->data, 0x0131);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 	return 0;
 }
 
 /**
- * Remove a reference to a server stored buddy icon.  This will make your 
+ * Remove a reference to a server stored buddy icon.  This will make your
  * icon stop showing up to other people.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_delicon(OscarSession *sess)
+int aim_ssi_delicon(OscarData *od)
 {
 	struct aim_ssi_item *tmp;
 
-	if (!sess)
+	if (!od)
 		return -EINVAL;
 
 	/* Find the ICONINFO item and delete it if it exists*/
-	if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO)))
-		aim_ssi_itemlist_del(&sess->ssi.local, tmp);
+	if ((tmp = aim_ssi_itemlist_finditem(od->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO)))
+		aim_ssi_itemlist_del(&od->ssi.local, tmp);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 	return 0;
 }
 
@@ -1136,27 +1133,27 @@
  * Stores your setting for various SSI settings.  Whether you 
  * should show up as idle or not, etc.
  *
- * @param sess The oscar session.
+ * @param od The oscar odion.
  * @param presence I think it's a bitmask, but I only know what one of the bits is:
  *        0x00000002 - Hide wireless?
  *        0x00000400 - Allow others to see your idle time
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_ssi_setpresence(OscarSession *sess, guint32 presence) {
+int aim_ssi_setpresence(OscarData *od, guint32 presence) {
 	struct aim_ssi_item *tmp;
 
-	if (!sess)
+	if (!od)
 		return -EINVAL;
 
 	/* Find the PRESENCEPREFS item, or add it if it does not exist */
-	if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS)))
-		tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, NULL);
+	if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS)))
+		tmp = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, NULL);
 
 	/* Need to add the x00c9 TLV to the TLV chain */
 	aim_tlvlist_replace_32(&tmp->data, 0x00c9, presence);
 
 	/* Sync our local list with the server list */
-	aim_ssi_sync(sess);
+	aim_ssi_sync(od);
 
 	return 0;
 }
@@ -1164,20 +1161,20 @@
 /*
  * Subtype 0x0002 - Request SSI Rights.
  */
-faim_export int aim_ssi_reqrights(OscarSession *sess)
+int aim_ssi_reqrights(OscarData *od)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_FEEDBAG)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
 		return -EINVAL;
 
-	return aim_genericreq_n_snacid(sess, conn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_REQRIGHTS);
+	return aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQRIGHTS);
 }
 
 /*
  * Subtype 0x0003 - SSI Rights Information.
  */
-static int parserights(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int parserights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0, i;
 	aim_rxcallback_t userfunc;
@@ -1195,18 +1192,15 @@
 		return 0;
 	}
 
-	aim_bstream_init(&bstream, tlv->value, tlv->length);
+	byte_stream_init(&bstream, tlv->value, tlv->length);
 
-	if (!(maxitems = (guint16 *)malloc((tlv->length/2)*sizeof(guint16)))) {
-		aim_tlvlist_free(&tlvlist);
-		return 0;
-	}
+	maxitems = (guint16 *)malloc((tlv->length/2)*sizeof(guint16));
 
 	for (i=0; i<(tlv->length/2); i++)
-		maxitems[i] = aimbs_get16(&bstream);
+		maxitems[i] = byte_stream_get16(&bstream);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, tlv->length/2, maxitems);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, tlv->length/2, maxitems);
 
 	aim_tlvlist_free(&tlvlist);
 	free(maxitems);
@@ -1215,55 +1209,54 @@
 }
 
 /*
- * Subtype 0x0004 - Request SSI Data when you don't have a timestamp and 
+ * Subtype 0x0004 - Request SSI Data when you don't have a timestamp and
  * revision number.
- * 
+ *
  */
-faim_export int aim_ssi_reqdata(OscarSession *sess)
+int aim_ssi_reqdata(OscarData *od)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_FEEDBAG)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
 		return -EINVAL;
 
 	/* Free any current data, just in case */
-	aim_ssi_freelist(sess);
+	aim_ssi_freelist(od);
 
-	return aim_genericreq_n_snacid(sess, conn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_REQDATA);
+	return aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQDATA);
 }
 
 /*
- * Subtype 0x0005 - Request SSI Data when you have a timestamp and revision 
+ * 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.
- * 
+ *
  */
-faim_export int aim_ssi_reqifchanged(OscarSession *sess, time_t timestamp, guint16 numitems)
+int aim_ssi_reqifchanged(OscarData *od, time_t timestamp, guint16 numitems)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_FEEDBAG)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+2)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+4+2);
 
-	snacid = aim_cachesnac(sess, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, NULL, 0);
 
-	aim_putsnac(&fr->data, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, snacid);
-	aimbs_put32(&fr->data, timestamp);
-	aimbs_put16(&fr->data, numitems);
+	aim_putsnac(&frame->data, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, snacid);
+	byte_stream_put32(&frame->data, timestamp);
+	byte_stream_put16(&frame->data, numitems);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	/* Free any current data, just in case */
-	aim_ssi_freelist(sess);
+	aim_ssi_freelist(od);
 
 	return 0;
 }
@@ -1271,7 +1264,7 @@
 /*
  * Subtype 0x0006 - SSI Data.
  */
-static int parsedata(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int parsedata(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -1280,37 +1273,37 @@
 	char *name;
 	aim_tlvlist_t *data;
 
-	fmtver = aimbs_get8(bs); /* Version of ssi data.  Should be 0x00 */
-	sess->ssi.numitems += aimbs_get16(bs); /* # of items in this SSI SNAC */
+	fmtver = byte_stream_get8(bs); /* Version of ssi data.  Should be 0x00 */
+	od->ssi.numitems += byte_stream_get16(bs); /* # of items in this SSI SNAC */
 
 	/* Read in the list */
-	while (aim_bstream_empty(bs) > 4) { /* last four bytes are timestamp */
-		if ((namelen = aimbs_get16(bs)))
-			name = aimbs_getstr(bs, namelen);
+	while (byte_stream_empty(bs) > 4) { /* last four bytes are timestamp */
+		if ((namelen = byte_stream_get16(bs)))
+			name = byte_stream_getstr(bs, namelen);
 		else
 			name = NULL;
-		gid = aimbs_get16(bs);
-		bid = aimbs_get16(bs);
-		type = aimbs_get16(bs);
-		data = aim_tlvlist_readlen(bs, aimbs_get16(bs));
-		aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data);
+		gid = byte_stream_get16(bs);
+		bid = byte_stream_get16(bs);
+		type = byte_stream_get16(bs);
+		data = aim_tlvlist_readlen(bs, byte_stream_get16(bs));
+		aim_ssi_itemlist_add(&od->ssi.official, name, gid, bid, type, data);
 		free(name);
 		aim_tlvlist_free(&data);
 	}
 
 	/* Read in the timestamp */
-	sess->ssi.timestamp = aimbs_get32(bs);
+	od->ssi.timestamp = byte_stream_get32(bs);
 
 	if (!(snac->flags & 0x0001)) {
 		/* Make a copy of the list */
 		struct aim_ssi_item *cur;
-		for (cur=sess->ssi.official; cur; cur=cur->next)
-			aim_ssi_itemlist_add(&sess->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data);
+		for (cur=od->ssi.official; cur; cur=cur->next)
+			aim_ssi_itemlist_add(&od->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data);
 
-		sess->ssi.received_data = 1;
+		od->ssi.received_data = 1;
 
-		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-			ret = userfunc(sess, rx, fmtver, sess->ssi.numitems, sess->ssi.official, sess->ssi.timestamp);
+		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+			ret = userfunc(od, conn, frame, fmtver, od->ssi.numitems, od->ssi.official, od->ssi.timestamp);
 	}
 
 	return ret;
@@ -1325,14 +1318,14 @@
  * settings into effect.
  * 
  */
-faim_export int aim_ssi_enable(OscarSession *sess)
+int aim_ssi_enable(OscarData *od)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_FEEDBAG)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
 		return -EINVAL;
 
-	return aim_genericreq_n(sess, conn, OSCAR_FAMILY_FEEDBAG, 0x0007);
+	return aim_genericreq_n(od, conn, SNAC_FAMILY_FEEDBAG, 0x0007);
 }
 
 /*
@@ -1343,20 +1336,20 @@
  * difference is the subtype that is set for the SNAC.
  * 
  */
-faim_export int aim_ssi_addmoddel(OscarSession *sess)
+int aim_ssi_addmoddel(OscarData *od)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int snaclen;
 	struct aim_ssi_tmp *cur;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_FEEDBAG)) || !sess->ssi.pending || !sess->ssi.pending->item)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !od->ssi.pending || !od->ssi.pending->item)
 		return -EINVAL;
 
 	/* Calculate total SNAC size */
 	snaclen = 10; /* For family, subtype, flags, and SNAC ID */
-	for (cur=sess->ssi.pending; cur; cur=cur->next) {
+	for (cur=od->ssi.pending; cur; cur=cur->next) {
 		snaclen += 10; /* For length, GID, BID, type, and length */
 		if (cur->item->name)
 			snaclen += strlen(cur->item->name);
@@ -1364,25 +1357,24 @@
 			snaclen += aim_tlvlist_size(&cur->item->data);
 	}
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, snaclen);
 
-	snacid = aim_cachesnac(sess, OSCAR_FAMILY_FEEDBAG, sess->ssi.pending->action, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, OSCAR_FAMILY_FEEDBAG, sess->ssi.pending->action, 0x0000, snacid);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, snacid);
 
-	for (cur=sess->ssi.pending; cur; cur=cur->next) {
-		aimbs_put16(&fr->data, cur->item->name ? strlen(cur->item->name) : 0);
+	for (cur=od->ssi.pending; cur; cur=cur->next) {
+		byte_stream_put16(&frame->data, cur->item->name ? strlen(cur->item->name) : 0);
 		if (cur->item->name)
-			aimbs_putstr(&fr->data, cur->item->name);
-		aimbs_put16(&fr->data, cur->item->gid);
-		aimbs_put16(&fr->data, cur->item->bid);
-		aimbs_put16(&fr->data, cur->item->type);
-		aimbs_put16(&fr->data, cur->item->data ? aim_tlvlist_size(&cur->item->data) : 0);
+			byte_stream_putstr(&frame->data, cur->item->name);
+		byte_stream_put16(&frame->data, cur->item->gid);
+		byte_stream_put16(&frame->data, cur->item->bid);
+		byte_stream_put16(&frame->data, cur->item->type);
+		byte_stream_put16(&frame->data, cur->item->data ? aim_tlvlist_size(&cur->item->data) : 0);
 		if (cur->item->data)
-			aim_tlvlist_write(&fr->data, &cur->item->data);
+			aim_tlvlist_write(&frame->data, &cur->item->data);
 	}
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1393,7 +1385,7 @@
  * Sent by the server, for example, when someone is added to 
  * your "Recent Buddies" group.
  */
-static int parseadd(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int parseadd(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -1401,25 +1393,25 @@
 	guint16 len, gid, bid, type;
 	aim_tlvlist_t *data;
 
-	while (aim_bstream_empty(bs)) {
-		if ((len = aimbs_get16(bs)))
-			name = aimbs_getstr(bs, len);
+	while (byte_stream_empty(bs)) {
+		if ((len = byte_stream_get16(bs)))
+			name = byte_stream_getstr(bs, len);
 		else
 			name = NULL;
-		gid = aimbs_get16(bs);
-		bid = aimbs_get16(bs);
-		type = aimbs_get16(bs);
-		if ((len = aimbs_get16(bs)))
+		gid = byte_stream_get16(bs);
+		bid = byte_stream_get16(bs);
+		type = byte_stream_get16(bs);
+		if ((len = byte_stream_get16(bs)))
 			data = aim_tlvlist_readlen(bs, len);
 		else
 			data = NULL;
 
-		aim_ssi_itemlist_add(&sess->ssi.local, name, gid, bid, type, data);
-		aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data);
+		aim_ssi_itemlist_add(&od->ssi.local, name, gid, bid, type, data);
+		aim_ssi_itemlist_add(&od->ssi.official, name, gid, bid, type, data);
 		aim_tlvlist_free(&data);
 
-		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-			ret = userfunc(sess, rx, type, name);
+		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+			ret = userfunc(od, conn, frame, type, name);
 
 		free(name);
 	}
@@ -1432,7 +1424,7 @@
  *
  * XXX - It would probably be good for the client to actually do something when it gets this.
  */
-static int parsemod(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int parsemod(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -1441,21 +1433,21 @@
 	aim_tlvlist_t *data;
 	struct aim_ssi_item *item;
 
-	while (aim_bstream_empty(bs)) {
-		if ((len = aimbs_get16(bs)))
-			name = aimbs_getstr(bs, len);
+	while (byte_stream_empty(bs)) {
+		if ((len = byte_stream_get16(bs)))
+			name = byte_stream_getstr(bs, len);
 		else
 			name = NULL;
-		gid = aimbs_get16(bs);
-		bid = aimbs_get16(bs);
-		type = aimbs_get16(bs);
-		if ((len = aimbs_get16(bs)))
+		gid = byte_stream_get16(bs);
+		bid = byte_stream_get16(bs);
+		type = byte_stream_get16(bs);
+		if ((len = byte_stream_get16(bs)))
 			data = aim_tlvlist_readlen(bs, len);
 		else
 			data = NULL;
 
 		/* Replace the 2 local items with the given one */
-		if ((item = aim_ssi_itemlist_find(sess->ssi.local, gid, bid))) {
+		if ((item = aim_ssi_itemlist_find(od->ssi.local, gid, bid))) {
 			item->type = type;
 			free(item->name);
 			if (name) {
@@ -1467,7 +1459,7 @@
 			item->data = aim_tlvlist_copy(data);
 		}
 
-		if ((item = aim_ssi_itemlist_find(sess->ssi.official, gid, bid))) {
+		if ((item = aim_ssi_itemlist_find(od->ssi.official, gid, bid))) {
 			item->type = type;
 			free(item->name);
 			if (name) {
@@ -1479,8 +1471,8 @@
 			item->data = aim_tlvlist_copy(data);
 		}
 
-		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-			ret = userfunc(sess, rx);
+		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+			ret = userfunc(od, conn, frame);
 
 		free(name);
 		aim_tlvlist_free(&data);
@@ -1494,27 +1486,27 @@
  *
  * XXX - It would probably be good for the client to actually do something when it gets this.
  */
-static int parsedel(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int parsedel(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 gid, bid;
 	struct aim_ssi_item *del;
 
-	while (aim_bstream_empty(bs)) {
-		aim_bstream_advance(bs, aimbs_get16(bs));
-		gid = aimbs_get16(bs);
-		bid = aimbs_get16(bs);
-		aimbs_get16(bs);
-		aim_bstream_advance(bs, aimbs_get16(bs));
+	while (byte_stream_empty(bs)) {
+		byte_stream_advance(bs, byte_stream_get16(bs));
+		gid = byte_stream_get16(bs);
+		bid = byte_stream_get16(bs);
+		byte_stream_get16(bs);
+		byte_stream_advance(bs, byte_stream_get16(bs));
 
-		if ((del = aim_ssi_itemlist_find(sess->ssi.local, gid, bid)))
-			aim_ssi_itemlist_del(&sess->ssi.local, del);
-		if ((del = aim_ssi_itemlist_find(sess->ssi.official, gid, bid)))
-			aim_ssi_itemlist_del(&sess->ssi.official, del);
+		if ((del = aim_ssi_itemlist_find(od->ssi.local, gid, bid)))
+			aim_ssi_itemlist_del(&od->ssi.local, del);
+		if ((del = aim_ssi_itemlist_find(od->ssi.official, gid, bid)))
+			aim_ssi_itemlist_del(&od->ssi.official, del);
 
-		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-			ret = userfunc(sess, rx);
+		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+			ret = userfunc(od, conn, frame);
 	}
 
 	return ret;
@@ -1526,45 +1518,45 @@
  * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel).
  *
  */
-static int parseack(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int parseack(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	struct aim_ssi_tmp *cur, *del;
 
 	/* Read in the success/failure flags from the ack SNAC */
-	cur = sess->ssi.pending;
-	while (cur && (aim_bstream_empty(bs)>0)) {
-		cur->ack = aimbs_get16(bs);
+	cur = od->ssi.pending;
+	while (cur && (byte_stream_empty(bs)>0)) {
+		cur->ack = byte_stream_get16(bs);
 		cur = cur->next;
 	}
 
 	/*
-	 * If outcome is 0, then add the item to the item list, or replace the other item, 
-	 * or remove the old item.  If outcome is non-zero, then remove the item from the 
+	 * If outcome is 0, then add the item to the item list, or replace the other item,
+	 * or remove the old item.  If outcome is non-zero, then remove the item from the
 	 * local list, or unmodify it, or add it.
 	 */
-	for (cur=sess->ssi.pending; (cur && (cur->ack != 0xffff)); cur=cur->next) {
+	for (cur=od->ssi.pending; (cur && (cur->ack != 0xffff)); cur=cur->next) {
 	if (cur->item) {
 		if (cur->ack) {
 			/* Our action was unsuccessful, so change the local list back to how it was */
-			if (cur->action == OSCAR_SUBTYPE_FEEDBAG_ADD) {
+			if (cur->action == SNAC_SUBTYPE_FEEDBAG_ADD) {
 				/* Remove the item from the local list */
 				/* Make sure cur->item is still valid memory */
-				if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
+				if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) {
 					if (cur->item->name) {
 						cur->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char));
 						strcpy(cur->name, cur->item->name);
 					}
-					aim_ssi_itemlist_del(&sess->ssi.local, cur->item);
+					aim_ssi_itemlist_del(&od->ssi.local, cur->item);
 				}
 				cur->item = NULL;
 
-			} else if (cur->action == OSCAR_SUBTYPE_FEEDBAG_MOD) {
+			} else if (cur->action == SNAC_SUBTYPE_FEEDBAG_MOD) {
 				/* Replace the local item with the item from the official list */
-				if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
+				if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) {
 					struct aim_ssi_item *cur1;
-					if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) {
+					if ((cur1 = aim_ssi_itemlist_find(od->ssi.official, cur->item->gid, cur->item->bid))) {
 						free(cur->item->name);
 						if (cur1->name) {
 							cur->item->name = (char *)malloc((strlen(cur1->name)+1)*sizeof(char));
@@ -1577,28 +1569,28 @@
 				} else
 					cur->item = NULL;
 
-			} else if (cur->action == OSCAR_SUBTYPE_FEEDBAG_DEL) {
+			} else if (cur->action == SNAC_SUBTYPE_FEEDBAG_DEL) {
 				/* Add the item back into the local list */
-				if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item)) {
-					aim_ssi_itemlist_add(&sess->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
+				if (aim_ssi_itemlist_valid(od->ssi.official, cur->item)) {
+					aim_ssi_itemlist_add(&od->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
 				} else
 					cur->item = NULL;
 			}
 
 		} else {
 			/* Do the exact opposite */
-			if (cur->action == OSCAR_SUBTYPE_FEEDBAG_ADD) {
+			if (cur->action == SNAC_SUBTYPE_FEEDBAG_ADD) {
 			/* Add the local item to the official list */
-				if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
-					aim_ssi_itemlist_add(&sess->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
+				if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) {
+					aim_ssi_itemlist_add(&od->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
 				} else
 					cur->item = NULL;
 
-			} else if (cur->action == OSCAR_SUBTYPE_FEEDBAG_MOD) {
+			} else if (cur->action == SNAC_SUBTYPE_FEEDBAG_MOD) {
 				/* Replace the official item with the item from the local list */
-				if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
+				if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) {
 					struct aim_ssi_item *cur1;
-					if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) {
+					if ((cur1 = aim_ssi_itemlist_find(od->ssi.official, cur->item->gid, cur->item->bid))) {
 						free(cur1->name);
 						if (cur->item->name) {
 							cur1->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char));
@@ -1611,10 +1603,10 @@
 				} else
 					cur->item = NULL;
 
-			} else if (cur->action == OSCAR_SUBTYPE_FEEDBAG_DEL) {
+			} else if (cur->action == SNAC_SUBTYPE_FEEDBAG_DEL) {
 				/* Remove the item from the official list */
-				if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item))
-					aim_ssi_itemlist_del(&sess->ssi.official, cur->item);
+				if (aim_ssi_itemlist_valid(od->ssi.official, cur->item))
+					aim_ssi_itemlist_del(&od->ssi.official, cur->item);
 				cur->item = NULL;
 			}
 
@@ -1622,24 +1614,24 @@
 	} /* End if (cur->item) */
 	} /* End for loop */
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, sess->ssi.pending);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, od->ssi.pending);
 
 	/* Free all aim_ssi_tmp's with an outcome */
-	cur = sess->ssi.pending;
+	cur = od->ssi.pending;
 	while (cur && (cur->ack != 0xffff)) {
 		del = cur;
 		cur = cur->next;
 		free(del->name);
 		free(del);
 	}
-	sess->ssi.pending = cur;
+	od->ssi.pending = cur;
 
 	/* If we're not waiting for any more acks, then send more SNACs */
-	if (!sess->ssi.pending) {
-		sess->ssi.pending = NULL;
-		sess->ssi.waiting_for_ack = 0;
-		aim_ssi_sync(sess);
+	if (!od->ssi.pending) {
+		od->ssi.pending = NULL;
+		od->ssi.waiting_for_ack = 0;
+		aim_ssi_sync(od);
 	}
 
 	return ret;
@@ -1652,15 +1644,15 @@
  * posted local stamp/revision.
  *
  */
-static int parsedataunchanged(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int parsedataunchanged(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 
-	sess->ssi.received_data = 1;
+	od->ssi.received_data = 1;
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame);
 
 	return ret;
 }
@@ -1668,33 +1660,32 @@
 /*
  * Subtype 0x0011 - SSI Begin Data Modification.
  *
- * Tells the server you're going to start modifying data.
- * 
+ * Tell the server you're going to start modifying data.
  */
-faim_export int aim_ssi_modbegin(OscarSession *sess)
+int aim_ssi_modbegin(OscarData *od)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_FEEDBAG)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
 		return -EINVAL;
 
-	return aim_genericreq_n(sess, conn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_EDITSTART);
+	return aim_genericreq_n(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_EDITSTART);
 }
 
 /*
  * Subtype 0x0012 - SSI End Data Modification.
  *
- * Tells the server you're finished modifying data.
+ * Tell the server you're finished modifying data.
  *
  */
-faim_export int aim_ssi_modend(OscarSession *sess)
+int aim_ssi_modend(OscarData *od)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_FEEDBAG)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
 		return -EINVAL;
 
-	return aim_genericreq_n(sess, conn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_EDITSTOP);
+	return aim_genericreq_n(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_EDITSTOP);
 }
 
 /*
@@ -1703,36 +1694,35 @@
  * Authorizes a contact so they can add you to their contact list.
  *
  */
-faim_export int aim_ssi_sendauth(OscarSession *sess, char *sn, char *msg)
+int aim_ssi_sendauth(OscarData *od, char *sn, char *msg)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_FEEDBAG)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !sn)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2);
 
-	snacid = aim_cachesnac(sess, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, snacid);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, snacid);
 
 	/* Screen name */
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
 
 	/* Message (null terminated) */
-	aimbs_put16(&fr->data, msg ? strlen(msg) : 0);
+	byte_stream_put16(&frame->data, msg ? strlen(msg) : 0);
 	if (msg) {
-		aimbs_putstr(&fr->data, msg);
-		aimbs_put8(&fr->data, 0x00);
+		byte_stream_putstr(&frame->data, msg);
+		byte_stream_put8(&frame->data, 0x00);
 	}
 
 	/* Unknown */
-	aimbs_put16(&fr->data, 0x0000);
+	byte_stream_put16(&frame->data, 0x0000);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1740,7 +1730,7 @@
 /*
  * Subtype 0x0015 - Receive an authorization grant
  */
-static int receiveauthgrant(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int receiveauthgrant(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -1748,22 +1738,22 @@
 	char *sn, *msg;
 
 	/* Read screen name */
-	if ((tmp = aimbs_get8(bs)))
-		sn = aimbs_getstr(bs, tmp);
+	if ((tmp = byte_stream_get8(bs)))
+		sn = byte_stream_getstr(bs, tmp);
 	else
 		sn = NULL;
 
 	/* Read message (null terminated) */
-	if ((tmp = aimbs_get16(bs)))
-		msg = aimbs_getstr(bs, tmp);
+	if ((tmp = byte_stream_get16(bs)))
+		msg = byte_stream_getstr(bs, tmp);
 	else
 		msg = NULL;
 
 	/* Unknown */
-	tmp = aimbs_get16(bs);
+	tmp = byte_stream_get16(bs);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, sn, msg);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, sn, msg);
 
 	free(sn);
 	free(msg);
@@ -1778,36 +1768,35 @@
  * granted, denied, or dropped.
  *
  */
-faim_export int aim_ssi_sendauthrequest(OscarSession *sess, char *sn, const char *msg)
+int aim_ssi_sendauthrequest(OscarData *od, char *sn, const char *msg)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_FEEDBAG)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !sn)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2);
 
-	snacid = aim_cachesnac(sess, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, snacid);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, snacid);
 
 	/* Screen name */
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
 
 	/* Message (null terminated) */
-	aimbs_put16(&fr->data, msg ? strlen(msg) : 0);
+	byte_stream_put16(&frame->data, msg ? strlen(msg) : 0);
 	if (msg) {
-		aimbs_putstr(&fr->data, msg);
-		aimbs_put8(&fr->data, 0x00);
+		byte_stream_putstr(&frame->data, msg);
+		byte_stream_put8(&frame->data, 0x00);
 	}
 
 	/* Unknown */
-	aimbs_put16(&fr->data, 0x0000);
+	byte_stream_put16(&frame->data, 0x0000);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1815,7 +1804,7 @@
 /*
  * Subtype 0x0019 - Receive an authorization request
  */
-static int receiveauthrequest(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int receiveauthrequest(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -1823,22 +1812,22 @@
 	char *sn, *msg;
 
 	/* Read screen name */
-	if ((tmp = aimbs_get8(bs)))
-		sn = aimbs_getstr(bs, tmp);
+	if ((tmp = byte_stream_get8(bs)))
+		sn = byte_stream_getstr(bs, tmp);
 	else
 		sn = NULL;
 
 	/* Read message (null terminated) */
-	if ((tmp = aimbs_get16(bs)))
-		msg = aimbs_getstr(bs, tmp);
+	if ((tmp = byte_stream_get16(bs)))
+		msg = byte_stream_getstr(bs, tmp);
 	else
 		msg = NULL;
 
 	/* Unknown */
-	tmp = aimbs_get16(bs);
+	tmp = byte_stream_get16(bs);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, sn, msg);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, sn, msg);
 
 	free(sn);
 	free(msg);
@@ -1856,39 +1845,38 @@
  * if reply=0x01 then grant
  *
  */
-faim_export int aim_ssi_sendauthreply(OscarSession *sess, char *sn, guint8 reply, const char *msg)
+int aim_ssi_sendauthreply(OscarData *od, char *sn, guint8 reply, const char *msg)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_FEEDBAG)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !sn)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 1+strlen(sn) + 1 + 2+(msg ? strlen(msg)+1 : 0) + 2)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + 1+strlen(sn) + 1 + 2+(msg ? strlen(msg)+1 : 0) + 2);
 
-	snacid = aim_cachesnac(sess, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, snacid);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, snacid);
 
 	/* Screen name */
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
 
 	/* Grant or deny */
-	aimbs_put8(&fr->data, reply);
+	byte_stream_put8(&frame->data, reply);
 
 	/* Message (null terminated) */
-	aimbs_put16(&fr->data, msg ? (strlen(msg)+1) : 0);
+	byte_stream_put16(&frame->data, msg ? (strlen(msg)+1) : 0);
 	if (msg) {
-		aimbs_putstr(&fr->data, msg);
-		aimbs_put8(&fr->data, 0x00);
+		byte_stream_putstr(&frame->data, msg);
+		byte_stream_put8(&frame->data, 0x00);
 	}
 
 	/* Unknown */
-	aimbs_put16(&fr->data, 0x0000);
+	byte_stream_put16(&frame->data, 0x0000);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1898,7 +1886,7 @@
  * You get this bad boy when other people respond to the authorization 
  * request that you have previously sent them.
  */
-static int receiveauthreply(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int receiveauthreply(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -1907,25 +1895,25 @@
 	char *sn, *msg;
 
 	/* Read screen name */
-	if ((tmp = aimbs_get8(bs)))
-		sn = aimbs_getstr(bs, tmp);
+	if ((tmp = byte_stream_get8(bs)))
+		sn = byte_stream_getstr(bs, tmp);
 	else
 		sn = NULL;
 
 	/* Read reply */
-	reply = aimbs_get8(bs);
+	reply = byte_stream_get8(bs);
 
 	/* Read message (null terminated) */
-	if ((tmp = aimbs_get16(bs)))
-		msg = aimbs_getstr(bs, tmp);
+	if ((tmp = byte_stream_get16(bs)))
+		msg = byte_stream_getstr(bs, tmp);
 	else
 		msg = NULL;
 
 	/* Unknown */
-	tmp = aimbs_get16(bs);
+	tmp = byte_stream_get16(bs);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, sn, reply, msg);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, sn, reply, msg);
 
 	free(sn);
 	free(msg);
@@ -1936,7 +1924,7 @@
 /*
  * Subtype 0x001c - Receive a message telling you someone added you to their list.
  */
-static int receiveadded(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int receiveadded(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -1944,57 +1932,58 @@
 	char *sn;
 
 	/* Read screen name */
-	if ((tmp = aimbs_get8(bs)))
-		sn = aimbs_getstr(bs, tmp);
+	if ((tmp = byte_stream_get8(bs)))
+		sn = byte_stream_getstr(bs, tmp);
 	else
 		sn = NULL;
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, sn);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, sn);
 
 	free(sn);
 
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
-	if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_RIGHTSINFO)
-		return parserights(sess, mod, rx, snac, bs);
-	else if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_LIST)
-		return parsedata(sess, mod, rx, snac, bs);
-	else if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_ADD)
-		return parseadd(sess, mod, rx, snac, bs);
-	else if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_MOD)
-		return parsemod(sess, mod, rx, snac, bs);
-	else if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_DEL)
-		return parsedel(sess, mod, rx, snac, bs);
-	else if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_SRVACK)
-		return parseack(sess, mod, rx, snac, bs);
-	else if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_NOLIST)
-		return parsedataunchanged(sess, mod, rx, snac, bs);
-	else if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_RECVAUTH)
-		return receiveauthgrant(sess, mod, rx, snac, bs);
-	else if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_RECVAUTHREQ)
-		return receiveauthrequest(sess, mod, rx, snac, bs);
-	else if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_RECVAUTHREP)
-		return receiveauthreply(sess, mod, rx, snac, bs);
-	else if (snac->subtype == OSCAR_SUBTYPE_FEEDBAG_ADDED)
-		return receiveadded(sess, mod, rx, snac, bs);
+	if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_RIGHTSINFO)
+		return parserights(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_LIST)
+		return parsedata(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_ADD)
+		return parseadd(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_MOD)
+		return parsemod(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_DEL)
+		return parsedel(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_SRVACK)
+		return parseack(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_NOLIST)
+		return parsedataunchanged(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_RECVAUTH)
+		return receiveauthgrant(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_RECVAUTHREQ)
+		return receiveauthrequest(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_RECVAUTHREP)
+		return receiveauthreply(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == SNAC_SUBTYPE_FEEDBAG_ADDED)
+		return receiveadded(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-static void ssi_shutdown(OscarSession *sess, aim_module_t *mod)
+static void
+ssi_shutdown(OscarData *od, aim_module_t *mod)
 {
-	aim_ssi_freelist(sess);
+	aim_ssi_freelist(od);
 }
 
-faim_internal int ssi_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+ssi_modfirst(OscarData *od, aim_module_t *mod)
 {
-
-	mod->family = OSCAR_FAMILY_FEEDBAG;
+	mod->family = SNAC_FAMILY_FEEDBAG;
 	mod->version = 0x0004;
 	mod->toolid = 0x0110;
 	mod->toolversion = 0x0629;
--- a/src/protocols/oscar/family_icbm.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_icbm.c	Fri Apr 07 05:10:56 2006 +0000
@@ -41,9 +41,7 @@
  * TODO: Split this up into an im.c file an an icbm.c file.  It
  *       will be beautiful, you'll see.
  *
- *       Need to rename all the mpmsg messages to aim_im_bleh.
- *
- *       Make sure aim_conn_findbygroup is used by all functions.
+ *       Make sure flap_connection_findbygroup is used by all functions.
  */
 
 #include "oscar.h"
@@ -65,19 +63,19 @@
  */
 static int aim_im_puticbm(ByteStream *bs, const guchar *c, guint16 channel, const char *sn)
 {
-	aimbs_putraw(bs, c, 8);
-	aimbs_put16(bs, channel);
-	aimbs_put8(bs, strlen(sn));
-	aimbs_putstr(bs, sn);
+	byte_stream_putraw(bs, c, 8);
+	byte_stream_put16(bs, channel);
+	byte_stream_put8(bs, strlen(sn));
+	byte_stream_putstr(bs, sn);
 	return 8+2+1+strlen(sn);
 }
 
-/*
- * Extracted from aim_im_sendch2_sendfile_ask
+/**
  * Generates a random ICBM cookie in a character array of length 8
  * and copies it into the variable passed as cookie
+ * TODO: Maybe we should stop limiting our characters to the visible range?
  */
-faim_export void aim_icbm_makecookie(guchar *cookie)
+void aim_icbm_makecookie(guchar *cookie)
 {
 	int i;
 
@@ -110,7 +108,7 @@
  * the rest will always be the same.
  *
  */
-faim_export guint16 aim_im_fingerprint(const guint8 *msghdr, int len)
+guint16 aim_im_fingerprint(const guint8 *msghdr, int len)
 {
 	static const struct {
 		guint16 clientid;
@@ -157,35 +155,34 @@
  * with the rather unreasonable defaults.
  *
  */
-faim_export int aim_im_setparams(OscarSession *sess, struct aim_icbmparameters *params)
+int aim_im_setparams(OscarData *od, struct aim_icbmparameters *params)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
 		return -EINVAL;
 
 	if (!params)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+16)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0004, 0x0002, 0x0000, snacid);
+	frame = flap_frame_new(od, 0x02, 10+16);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0002, 0x0000, snacid);
 
 	/* This is read-only (see Parameter Reply). Must be set to zero here. */
-	aimbs_put16(&fr->data, 0x0000);
+	byte_stream_put16(&frame->data, 0x0000);
 
 	/* These are all read-write */
-	aimbs_put32(&fr->data, params->flags);
-	aimbs_put16(&fr->data, params->maxmsglen);
-	aimbs_put16(&fr->data, params->maxsenderwarn);
-	aimbs_put16(&fr->data, params->maxrecverwarn);
-	aimbs_put32(&fr->data, params->minmsginterval);
-
-	aim_tx_enqueue(sess, fr);
+	byte_stream_put32(&frame->data, params->flags);
+	byte_stream_put16(&frame->data, params->maxmsglen);
+	byte_stream_put16(&frame->data, params->maxsenderwarn);
+	byte_stream_put16(&frame->data, params->maxrecverwarn);
+	byte_stream_put32(&frame->data, params->minmsginterval);
+
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -194,34 +191,34 @@
  * Subtype 0x0004 - Request ICBM parameter information.
  *
  */
-faim_export int aim_im_reqparams(OscarSession *sess)
+int aim_im_reqparams(OscarData *od)
 {
-	OscarConnection *conn;
-
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
+	FlapConnection *conn;
+
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
 		return -EINVAL;
 
-	return aim_genericreq_n_snacid(sess, conn, 0x0004, 0x0004);
+	return aim_genericreq_n_snacid(od, conn, 0x0004, 0x0004);
 }
 
 /**
  * Subtype 0x0005 - Receive parameter information.
  *
  */
-static int aim_im_paraminfo(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int aim_im_paraminfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	aim_rxcallback_t userfunc;
 	struct aim_icbmparameters params;
 
-	params.maxchan = aimbs_get16(bs);
-	params.flags = aimbs_get32(bs);
-	params.maxmsglen = aimbs_get16(bs);
-	params.maxsenderwarn = aimbs_get16(bs);
-	params.maxrecverwarn = aimbs_get16(bs);
-	params.minmsginterval = aimbs_get32(bs);
-
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		return userfunc(sess, rx, &params);
+	params.maxchan = byte_stream_get16(bs);
+	params.flags = byte_stream_get32(bs);
+	params.maxmsglen = byte_stream_get16(bs);
+	params.maxsenderwarn = byte_stream_get16(bs);
+	params.maxrecverwarn = byte_stream_get16(bs);
+	params.minmsginterval = byte_stream_get32(bs);
+
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		return userfunc(od, conn, frame, &params);
 
 	return 0;
 }
@@ -267,16 +264,16 @@
  * XXX - check SNAC size for multipart
  *
  */
-faim_export int aim_im_sendch1_ext(OscarSession *sess, struct aim_sendimext_args *args)
+int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	guchar cookie[8];
 	int msgtlvlen;
 	static const guint8 deffeatures[] = { 0x01, 0x01, 0x01, 0x02 };
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
 		return -EINVAL;
 
 	if (!args)
@@ -314,31 +311,30 @@
 		msgtlvlen += 4 /* charset */ + args->msglen;
 	}
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, msgtlvlen+128);
 
 	/* XXX - should be optional */
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1);
-	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* Generate an ICBM cookie */
 	aim_icbm_makecookie(cookie);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, cookie, 0x0001, args->destsn);
+	aim_im_puticbm(&frame->data, cookie, 0x0001, args->destsn);
 
 	/* Message TLV (type 0x0002) */
-	aimbs_put16(&fr->data, 0x0002);
-	aimbs_put16(&fr->data, msgtlvlen);
+	byte_stream_put16(&frame->data, 0x0002);
+	byte_stream_put16(&frame->data, msgtlvlen);
 
 	/* Features TLV (type 0x0501) */
-	aimbs_put16(&fr->data, 0x0501);
+	byte_stream_put16(&frame->data, 0x0501);
 	if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) {
-		aimbs_put16(&fr->data, args->featureslen);
-		aimbs_putraw(&fr->data, args->features, args->featureslen);
+		byte_stream_put16(&frame->data, args->featureslen);
+		byte_stream_putraw(&frame->data, args->features, args->featureslen);
 	} else {
-		aimbs_put16(&fr->data, sizeof(deffeatures));
-		aimbs_putraw(&fr->data, deffeatures, sizeof(deffeatures));
+		byte_stream_put16(&frame->data, sizeof(deffeatures));
+		byte_stream_putraw(&frame->data, deffeatures, sizeof(deffeatures));
 	}
 
 	if (args->flags & AIM_IMFLAGS_MULTIPART) {
@@ -346,42 +342,42 @@
 
 		/* Insert each message part in a TLV (type 0x0101) */
 		for (sec = args->mpmsg->parts; sec; sec = sec->next) {
-			aimbs_put16(&fr->data, 0x0101);
-			aimbs_put16(&fr->data, sec->datalen + 4);
-			aimbs_put16(&fr->data, sec->charset);
-			aimbs_put16(&fr->data, sec->charsubset);
-			aimbs_putraw(&fr->data, (guchar *)sec->data, sec->datalen);
+			byte_stream_put16(&frame->data, 0x0101);
+			byte_stream_put16(&frame->data, sec->datalen + 4);
+			byte_stream_put16(&frame->data, sec->charset);
+			byte_stream_put16(&frame->data, sec->charsubset);
+			byte_stream_putraw(&frame->data, (guchar *)sec->data, sec->datalen);
 		}
 
 	} else {
 
 		/* Insert message text in a TLV (type 0x0101) */
-		aimbs_put16(&fr->data, 0x0101);
+		byte_stream_put16(&frame->data, 0x0101);
 
 		/* Message block length */
-		aimbs_put16(&fr->data, args->msglen + 0x04);
+		byte_stream_put16(&frame->data, args->msglen + 0x04);
 
 		/* Character set */
-		aimbs_put16(&fr->data, args->charset);
-		aimbs_put16(&fr->data, args->charsubset);
+		byte_stream_put16(&frame->data, args->charset);
+		byte_stream_put16(&frame->data, args->charsubset);
 
 		/* Message.  Not terminated */
-		aimbs_putraw(&fr->data, (guchar *)args->msg, args->msglen);
+		byte_stream_putraw(&frame->data, (guchar *)args->msg, args->msglen);
 	}
 
 	/* Set the Autoresponse flag */
 	if (args->flags & AIM_IMFLAGS_AWAY) {
-		aimbs_put16(&fr->data, 0x0004);
-		aimbs_put16(&fr->data, 0x0000);
+		byte_stream_put16(&frame->data, 0x0004);
+		byte_stream_put16(&frame->data, 0x0000);
 	} else if (args->flags & AIM_IMFLAGS_ACK) {
 		/* Set the Request Acknowledge flag */
-		aimbs_put16(&fr->data, 0x0003);
-		aimbs_put16(&fr->data, 0x0000);
+		byte_stream_put16(&frame->data, 0x0003);
+		byte_stream_put16(&frame->data, 0x0000);
 	}
 
 	if (args->flags & AIM_IMFLAGS_OFFLINE) {
-		aimbs_put16(&fr->data, 0x0006);
-		aimbs_put16(&fr->data, 0x0000);
+		byte_stream_put16(&frame->data, 0x0006);
+		byte_stream_put16(&frame->data, 0x0000);
 	}
 
 	/*
@@ -390,12 +386,12 @@
 	 * IMs and when you change your icon.
 	 */
 	if (args->flags & AIM_IMFLAGS_HASICON) {
-		aimbs_put16(&fr->data, 0x0008);
-		aimbs_put16(&fr->data, 0x000c);
-		aimbs_put32(&fr->data, args->iconlen);
-		aimbs_put16(&fr->data, 0x0001);
-		aimbs_put16(&fr->data, args->iconsum);
-		aimbs_put32(&fr->data, args->iconstamp);
+		byte_stream_put16(&frame->data, 0x0008);
+		byte_stream_put16(&frame->data, 0x000c);
+		byte_stream_put32(&frame->data, args->iconlen);
+		byte_stream_put16(&frame->data, 0x0001);
+		byte_stream_put16(&frame->data, args->iconsum);
+		byte_stream_put32(&frame->data, args->iconstamp);
 	}
 
 	/*
@@ -403,14 +399,14 @@
 	 * XXX - Every time?  Surely not...
 	 */
 	if (args->flags & AIM_IMFLAGS_BUDDYREQ) {
-		aimbs_put16(&fr->data, 0x0009);
-		aimbs_put16(&fr->data, 0x0000);
+		byte_stream_put16(&frame->data, 0x0009);
+		byte_stream_put16(&frame->data, 0x0000);
 	}
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	/* clean out SNACs over 60sec old */
-	aim_cleansnacs(sess, 60);
+	aim_cleansnacs(od, 60);
 
 	return 0;
 }
@@ -425,7 +421,7 @@
  * that requires an explicit message length.  Use aim_im_sendch1_ext().
  *
  */
-faim_export int aim_im_sendch1(OscarSession *sess, const char *sn, guint16 flags, const char *msg)
+int aim_im_sendch1(OscarData *od, const char *sn, guint16 flags, const char *msg)
 {
 	struct aim_sendimext_args args;
 
@@ -439,16 +435,16 @@
 	/* 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(sess, &args);
+	return aim_im_sendch1_ext(od, &args);
 }
 
 /*
  * Subtype 0x0006 - Send a chat invitation.
  */
-faim_export int aim_im_sendch2_chatinvite(OscarSession *sess, const char *sn, const char *msg, guint16 exchange, const char *roomname, guint16 instance)
+int aim_im_sendch2_chatinvite(OscarData *od, const char *sn, const char *msg, guint16 exchange, const char *roomname, guint16 instance)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	IcbmCookie *msgcookie;
 	struct aim_invite_priv *priv;
@@ -458,7 +454,7 @@
 	int hdrlen;
 	ByteStream hdrbs;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
 		return -EINVAL;
 
 	if (!sn || !msg || !roomname)
@@ -466,27 +462,25 @@
 
 	aim_icbm_makecookie(cookie);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg))))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1);
-	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
+	frame = flap_frame_new(od, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg));
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* XXX should be uncached by an unwritten 'invite accept' handler */
-	if ((priv = malloc(sizeof(struct aim_invite_priv)))) {
-		priv->sn = strdup(sn);
-		priv->roomname = strdup(roomname);
-		priv->exchange = exchange;
-		priv->instance = instance;
-	}
+	priv = malloc(sizeof(struct aim_invite_priv));
+	priv->sn = strdup(sn);
+	priv->roomname = strdup(roomname);
+	priv->exchange = exchange;
+	priv->instance = instance;
 
 	if ((msgcookie = aim_mkcookie(cookie, AIM_COOKIETYPE_INVITE, priv)))
-		aim_cachecookie(sess, msgcookie);
+		aim_cachecookie(od, msgcookie);
 	else
 		free(priv);
 
 	/* ICBM Header */
-	aim_im_puticbm(&fr->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
 
 	/*
 	 * TLV t(0005)
@@ -500,11 +494,11 @@
 	 */
 	hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2;
 	hdr = malloc(hdrlen);
-	aim_bstream_init(&hdrbs, hdr, hdrlen);
-
-	aimbs_put16(&hdrbs, 0x0000); /* Unknown! */
-	aimbs_putraw(&hdrbs, cookie, sizeof(cookie)); /* I think... */
-	aimbs_putcaps(&hdrbs, AIM_CAPS_CHAT);
+	byte_stream_init(&hdrbs, hdr, hdrlen);
+
+	byte_stream_put16(&hdrbs, 0x0000); /* Unknown! */
+	byte_stream_putraw(&hdrbs, cookie, sizeof(cookie)); /* I think... */
+	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_CHAT);
 
 	aim_tlvlist_add_16(&itl, 0x000a, 0x0001);
 	aim_tlvlist_add_noval(&itl, 0x000f);
@@ -512,15 +506,15 @@
 	aim_tlvlist_add_chatroom(&itl, 0x2711, exchange, roomname, instance);
 	aim_tlvlist_write(&hdrbs, &itl);
 
-	aim_tlvlist_add_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr);
-
-	aim_tlvlist_write(&fr->data, &otl);
+	aim_tlvlist_add_raw(&otl, 0x0005, byte_stream_curpos(&hdrbs), hdr);
+
+	aim_tlvlist_write(&frame->data, &otl);
 
 	free(hdr);
 	aim_tlvlist_free(&itl);
 	aim_tlvlist_free(&otl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -531,14 +525,14 @@
  * This is also performance sensitive. (If you can believe it...)
  *
  */
-faim_export int aim_im_sendch2_icon(OscarSession *sess, const char *sn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum)
+int aim_im_sendch2_icon(OscarData *od, const char *sn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	guchar cookie[8];
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
 		return -EINVAL;
 
 	if (!sn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN))
@@ -546,51 +540,50 @@
 
 	aim_icbm_makecookie(cookie);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
+	frame = flap_frame_new(od, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
 
 	/*
 	 * TLV t(0005)
 	 *
 	 * Encompasses everything below.
 	 */
-	aimbs_put16(&fr->data, 0x0005);
-	aimbs_put16(&fr->data, 2+8+16+6+4+4+iconlen+4+4+4+strlen(AIM_ICONIDENT));
-
-	aimbs_put16(&fr->data, 0x0000);
-	aimbs_putraw(&fr->data, cookie, 8);
-	aimbs_putcaps(&fr->data, AIM_CAPS_BUDDYICON);
+	byte_stream_put16(&frame->data, 0x0005);
+	byte_stream_put16(&frame->data, 2+8+16+6+4+4+iconlen+4+4+4+strlen(AIM_ICONIDENT));
+
+	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_putraw(&frame->data, cookie, 8);
+	byte_stream_putcaps(&frame->data, OSCAR_CAPABILITY_BUDDYICON);
 
 	/* TLV t(000a) */
-	aimbs_put16(&fr->data, 0x000a);
-	aimbs_put16(&fr->data, 0x0002);
-	aimbs_put16(&fr->data, 0x0001);
+	byte_stream_put16(&frame->data, 0x000a);
+	byte_stream_put16(&frame->data, 0x0002);
+	byte_stream_put16(&frame->data, 0x0001);
 
 	/* TLV t(000f) */
-	aimbs_put16(&fr->data, 0x000f);
-	aimbs_put16(&fr->data, 0x0000);
+	byte_stream_put16(&frame->data, 0x000f);
+	byte_stream_put16(&frame->data, 0x0000);
 
 	/* TLV t(2711) */
-	aimbs_put16(&fr->data, 0x2711);
-	aimbs_put16(&fr->data, 4+4+4+iconlen+strlen(AIM_ICONIDENT));
-	aimbs_put16(&fr->data, 0x0000);
-	aimbs_put16(&fr->data, iconsum);
-	aimbs_put32(&fr->data, iconlen);
-	aimbs_put32(&fr->data, stamp);
-	aimbs_putraw(&fr->data, icon, iconlen);
-	aimbs_putstr(&fr->data, AIM_ICONIDENT);
+	byte_stream_put16(&frame->data, 0x2711);
+	byte_stream_put16(&frame->data, 4+4+4+iconlen+strlen(AIM_ICONIDENT));
+	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&frame->data, iconsum);
+	byte_stream_put32(&frame->data, iconlen);
+	byte_stream_put32(&frame->data, stamp);
+	byte_stream_putraw(&frame->data, icon, iconlen);
+	byte_stream_putstr(&frame->data, AIM_ICONIDENT);
 
 	/* TLV t(0003) */
-	aimbs_put16(&fr->data, 0x0003);
-	aimbs_put16(&fr->data, 0x0000);
-
-	aim_tx_enqueue(sess, fr);
+	byte_stream_put16(&frame->data, 0x0003);
+	byte_stream_put16(&frame->data, 0x0000);
+
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -610,16 +603,16 @@
  * make an interface similar to what AOL actually uses.  But I'm not using COM.
  *
  */
-faim_export int aim_im_sendch2_rtfmsg(OscarSession *sess, struct aim_sendrtfmsg_args *args)
+int aim_im_sendch2_rtfmsg(OscarData *od, struct aim_sendrtfmsg_args *args)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	guchar cookie[8];
-	const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* AIM_CAPS_ICQRTF capability in string form */
+	const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* OSCAR_CAPABILITY_ICQRTF capability in string form */
 	int servdatalen;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
 		return -EINVAL;
 
 	if (!args || !args->destsn || !args->rtfmsg)
@@ -629,459 +622,553 @@
 
 	aim_icbm_makecookie(cookie);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+128+servdatalen)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
+	frame = flap_frame_new(od, 0x02, 10+128+servdatalen);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, cookie, 0x0002, args->destsn);
+	aim_im_puticbm(&frame->data, cookie, 0x0002, args->destsn);
 
 	/* TLV t(0005) - Encompasses everything below. */
-	aimbs_put16(&fr->data, 0x0005);
-	aimbs_put16(&fr->data, 2+8+16  +  2+2+2  +  2+2  +  2+2+servdatalen);
-
-	aimbs_put16(&fr->data, 0x0000);
-	aimbs_putraw(&fr->data, cookie, 8);
-	aimbs_putcaps(&fr->data, AIM_CAPS_ICQSERVERRELAY);
+	byte_stream_put16(&frame->data, 0x0005);
+	byte_stream_put16(&frame->data, 2+8+16  +  2+2+2  +  2+2  +  2+2+servdatalen);
+
+	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_putraw(&frame->data, cookie, 8);
+	byte_stream_putcaps(&frame->data, OSCAR_CAPABILITY_ICQSERVERRELAY);
 
 	/* t(000a) l(0002) v(0001) */
-	aimbs_put16(&fr->data, 0x000a);
-	aimbs_put16(&fr->data, 0x0002);
-	aimbs_put16(&fr->data, 0x0001);
+	byte_stream_put16(&frame->data, 0x000a);
+	byte_stream_put16(&frame->data, 0x0002);
+	byte_stream_put16(&frame->data, 0x0001);
 
 	/* t(000f) l(0000) v() */
-	aimbs_put16(&fr->data, 0x000f);
-	aimbs_put16(&fr->data, 0x0000);
+	byte_stream_put16(&frame->data, 0x000f);
+	byte_stream_put16(&frame->data, 0x0000);
 
 	/* Service Data TLV */
-	aimbs_put16(&fr->data, 0x2711);
-	aimbs_put16(&fr->data, servdatalen);
-
-	aimbs_putle16(&fr->data, 11 + 16 /* 11 + (sizeof CLSID) */);
-	aimbs_putle16(&fr->data, 9);
-	aimbs_putcaps(&fr->data, AIM_CAPS_EMPTY);
-	aimbs_putle16(&fr->data, 0);
-	aimbs_putle32(&fr->data, 0);
-	aimbs_putle8(&fr->data, 0);
-	aimbs_putle16(&fr->data, 0x03ea); /* trid1 */
-
-	aimbs_putle16(&fr->data, 14);
-	aimbs_putle16(&fr->data, 0x03eb); /* trid2 */
-	aimbs_putle32(&fr->data, 0);
-	aimbs_putle32(&fr->data, 0);
-	aimbs_putle32(&fr->data, 0);
-
-	aimbs_putle16(&fr->data, 0x0001);
-	aimbs_putle32(&fr->data, 0);
-	aimbs_putle16(&fr->data, strlen(args->rtfmsg)+1);
-	aimbs_putraw(&fr->data, (const guint8 *)args->rtfmsg, strlen(args->rtfmsg)+1);
-
-	aimbs_putle32(&fr->data, args->fgcolor);
-	aimbs_putle32(&fr->data, args->bgcolor);
-	aimbs_putle32(&fr->data, strlen(rtfcap)+1);
-	aimbs_putraw(&fr->data, (const guint8 *)rtfcap, strlen(rtfcap)+1);
-
-	aim_tx_enqueue(sess, fr);
+	byte_stream_put16(&frame->data, 0x2711);
+	byte_stream_put16(&frame->data, servdatalen);
+
+	byte_stream_putle16(&frame->data, 11 + 16 /* 11 + (sizeof CLSID) */);
+	byte_stream_putle16(&frame->data, 9);
+	byte_stream_putcaps(&frame->data, OSCAR_CAPABILITY_EMPTY);
+	byte_stream_putle16(&frame->data, 0);
+	byte_stream_putle32(&frame->data, 0);
+	byte_stream_putle8(&frame->data, 0);
+	byte_stream_putle16(&frame->data, 0x03ea); /* trid1 */
+
+	byte_stream_putle16(&frame->data, 14);
+	byte_stream_putle16(&frame->data, 0x03eb); /* trid2 */
+	byte_stream_putle32(&frame->data, 0);
+	byte_stream_putle32(&frame->data, 0);
+	byte_stream_putle32(&frame->data, 0);
+
+	byte_stream_putle16(&frame->data, 0x0001);
+	byte_stream_putle32(&frame->data, 0);
+	byte_stream_putle16(&frame->data, strlen(args->rtfmsg)+1);
+	byte_stream_putraw(&frame->data, (const guint8 *)args->rtfmsg, strlen(args->rtfmsg)+1);
+
+	byte_stream_putle32(&frame->data, args->fgcolor);
+	byte_stream_putle32(&frame->data, args->bgcolor);
+	byte_stream_putle32(&frame->data, strlen(rtfcap)+1);
+	byte_stream_putraw(&frame->data, (const guint8 *)rtfcap, strlen(rtfcap)+1);
+
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
 /**
- * Subtype 0x0006 - Send an "I want to directly connect to you" message
- *
+ * Cancel a rendezvous invitation.  It could be an invitation to
+ * establish a direct connection, or a file-send, or a chat invite.
  */
-faim_export int aim_im_sendch2_odcrequest(OscarSession *sess, guchar *usercookie, gboolean usecookie, const char *sn, const guint8 *ip, guint16 port)
+void
+aim_im_sendch2_cancel(PeerConnection *peer_conn)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	OscarData *od;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
-	guchar cookie[8];
+	aim_tlvlist_t *tl = NULL, *itl = NULL;
+	int hdrlen;
+	guint8 *hdr;
+	ByteStream hdrbs;
+
+	od = peer_conn->od;
+	conn = flap_connection_findbygroup(od, 0x0004);
+	if (conn == NULL)
+		return;
+
+	frame = flap_frame_new(od, 0x02, 128+strlen(peer_conn->sn));
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
+
+	/* ICBM header */
+	aim_im_puticbm(&frame->data, peer_conn->cookie, 0x0002, peer_conn->sn);
+
+	aim_tlvlist_add_noval(&tl, 0x0003);
+
+	hdrlen = 64;
+	hdr = malloc(hdrlen);
+	byte_stream_init(&hdrbs, hdr, hdrlen);
+
+	byte_stream_put16(&hdrbs, AIM_RENDEZVOUS_CANCEL);
+	byte_stream_putraw(&hdrbs, peer_conn->cookie, 8);
+	byte_stream_putcaps(&hdrbs, peer_conn->type);
+
+	/* This TLV means "cancel!" */
+	aim_tlvlist_add_16(&itl, 0x000b, 0x0001);
+	aim_tlvlist_write(&hdrbs, &itl);
+
+	aim_tlvlist_add_raw(&tl, 0x0005, byte_stream_curpos(&hdrbs), hdr);
+
+	aim_tlvlist_write(&frame->data, &tl);
+
+	free(hdr);
+	aim_tlvlist_free(&itl);
+	aim_tlvlist_free(&tl);
+
+	flap_connection_send(conn, frame);
+}
+
+/**
+ * Subtype 0x0006 - Send an "I accept and I've connected to
+ * you" message.
+ */
+void
+aim_im_sendch2_connected(PeerConnection *peer_conn)
+{
+	OscarData *od;
+	FlapConnection *conn;
+	FlapFrame *frame;
+	aim_snacid_t snacid;
+
+	od = peer_conn->od;
+	conn = flap_connection_findbygroup(od, 0x0004);
+	if (conn == NULL)
+		return;
+
+	frame = flap_frame_new(od, 0x02, 10 + 11+strlen(peer_conn->sn) + 4+2+8+16);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
+
+	/* ICBM header */
+	aim_im_puticbm(&frame->data, peer_conn->cookie, 0x0002, peer_conn->sn);
+
+	byte_stream_put16(&frame->data, 0x0005);
+	byte_stream_put16(&frame->data, 0x001a);
+	byte_stream_put16(&frame->data, AIM_RENDEZVOUS_CONNECTED);
+	byte_stream_putraw(&frame->data, peer_conn->cookie, 8);
+	byte_stream_putcaps(&frame->data, peer_conn->type);
+
+	flap_connection_send(conn, frame);
+}
+
+/**
+ * Subtype 0x0006 - Send a direct connect rendezvous ICBM.  This
+ * could have a number of meanings, depending on the content:
+ * "I want you to connect to me"
+ * "I want to connect to you"
+ * "I want to connect through a proxy server"
+ */
+void
+aim_im_sendch2_odc_requestdirect(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 port, guint16 requestnumber)
+{
+	FlapConnection *conn;
+	FlapFrame *frame;
+	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL, *itl = NULL;
 	int hdrlen;
 	guint8 *hdr;
 	ByteStream hdrbs;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
-		return -EINVAL;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 256+strlen(sn))))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
-
-	/*
-	 * Generate a random message cookie
-	 *
-	 * This cookie needs to be alphanumeric and NULL-terminated to be
-	 * TOC-compatible.
-	 *
-	 * XXX - have I mentioned these should be generated in msgcookie.c?
-	 *
-	 */
-
-	if (usercookie && usecookie) /* allow user-specified cookie */
-		memcpy(cookie, usercookie, 8);
-	else
-		aim_icbm_makecookie(cookie);
-	cookie[7] = '\0';
-
-	if (usercookie && !usecookie)
-		memcpy(cookie, usercookie, 8);
+	conn = flap_connection_findbygroup(od, 0x0004);
+	if (conn == NULL)
+		return;
+
+	frame = flap_frame_new(od, 0x02, 256+strlen(sn));
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
 
 	aim_tlvlist_add_noval(&tl, 0x0003);
 
-	hdrlen = 2+8+16+6+8+6+4;
+	hdrlen = 128;
 	hdr = malloc(hdrlen);
-	aim_bstream_init(&hdrbs, hdr, hdrlen);
-
-	aimbs_put16(&hdrbs, 0x0000);
-	aimbs_putraw(&hdrbs, cookie, 8);
-	aimbs_putcaps(&hdrbs, AIM_CAPS_DIRECTIM);
-
-	aim_tlvlist_add_16(&itl, 0x000a, 0x0001);
+	byte_stream_init(&hdrbs, hdr, hdrlen);
+
+	byte_stream_put16(&hdrbs, AIM_RENDEZVOUS_PROPOSE);
+	byte_stream_putraw(&hdrbs, cookie, 8);
+	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_DIRECTIM);
+
+	aim_tlvlist_add_raw(&itl, 0x0002, 4, ip);
 	aim_tlvlist_add_raw(&itl, 0x0003, 4, ip);
 	aim_tlvlist_add_16(&itl, 0x0005, port);
+	aim_tlvlist_add_16(&itl, 0x000a, requestnumber);
 	aim_tlvlist_add_noval(&itl, 0x000f);
-
 	aim_tlvlist_write(&hdrbs, &itl);
 
-	aim_tlvlist_add_raw(&tl, 0x0005, aim_bstream_curpos(&hdrbs), hdr);
-
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_add_raw(&tl, 0x0005, byte_stream_curpos(&hdrbs), hdr);
+
+	aim_tlvlist_write(&frame->data, &tl);
 
 	free(hdr);
 	aim_tlvlist_free(&itl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
+	flap_connection_send(conn, frame);
+}
+
+/**
+ * Subtype 0x0006 - Send a direct connect rendezvous ICBM asking the
+ * remote user to connect to us via a proxy server.
+ */
+void
+aim_im_sendch2_odc_requestproxy(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 pin, guint16 requestnumber)
+{
+	FlapConnection *conn;
+	FlapFrame *frame;
+	aim_snacid_t snacid;
+	aim_tlvlist_t *tl = NULL, *itl = NULL;
+	int hdrlen;
+	guint8 *hdr;
+	ByteStream hdrbs;
+	guint8 ip_comp[4];
+
+	conn = flap_connection_findbygroup(od, 0x0004);
+	if (conn == NULL)
+		return;
+
+	frame = flap_frame_new(od, 0x02, 256+strlen(sn));
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
+
+	/* ICBM header */
+	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
+
+	aim_tlvlist_add_noval(&tl, 0x0003);
+
+	hdrlen = 128;
+	hdr = malloc(hdrlen);
+	byte_stream_init(&hdrbs, hdr, hdrlen);
+
+	byte_stream_put16(&hdrbs, AIM_RENDEZVOUS_PROPOSE);
+	byte_stream_putraw(&hdrbs, cookie, 8);
+	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_DIRECTIM);
+
+	aim_tlvlist_add_raw(&itl, 0x0002, 4, ip);
+	aim_tlvlist_add_raw(&itl, 0x0003, 4, ip);
+	aim_tlvlist_add_16(&itl, 0x0005, pin);
+	aim_tlvlist_add_16(&itl, 0x000a, requestnumber);
+	aim_tlvlist_add_noval(&itl, 0x000f);
+	aim_tlvlist_add_noval(&itl, 0x0010);
+
+	/* Send the bitwise complement of the port and ip.  As a check? */
+	ip_comp[0] = ~ip[0];
+	ip_comp[1] = ~ip[1];
+	ip_comp[2] = ~ip[2];
+	ip_comp[3] = ~ip[3];
+	aim_tlvlist_add_raw(&itl, 0x0016, 4, ip_comp);
+	aim_tlvlist_add_16(&itl, 0x0017, ~pin);
+
+	aim_tlvlist_write(&hdrbs, &itl);
+
+	aim_tlvlist_add_raw(&tl, 0x0005, byte_stream_curpos(&hdrbs), hdr);
+
+	aim_tlvlist_write(&frame->data, &tl);
+
+	free(hdr);
+	aim_tlvlist_free(&itl);
+	aim_tlvlist_free(&tl);
+
+	flap_connection_send(conn, frame);
 }
 
 /**
  * Subtype 0x0006 - Send an "I want to send you this file" message
  *
  */
-faim_export int aim_im_sendch2_sendfile_ask(OscarSession *sess, PeerConnection *peer_connection)
+void
+aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
-	aim_tlvlist_t *tl=NULL, *subtl=NULL;
-
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !peer_connection)
-		return -EINVAL;
-
-	/* The cookie must already have been generated by this point */
-
-	{ /* Create the subTLV chain */
-		guint8 *buf;
-		int buflen;
-		ByteStream bs;
-		guint8 ip[4];
-		guint8 ip_comp[4]; /* The bitwise complement of the ip */
-		char *nexttoken;
-		int i;
-
-		/* In a stage 2 proxied transfer & a transfer redirect, we send a second "reply request"
-		 * Being the second request for this transfer, its request number is 2
-		 * You can fill in the blank for a stage 3's request number... */
-		if ((peer_connection->send_or_recv == AIM_XFER_RECV && peer_connection->stage == AIM_XFER_PROXY_STG2)
-			|| (peer_connection->send_or_recv == AIM_XFER_RECV
-				&& peer_connection->stage == AIM_XFER_PROXY_STG3)
-			|| peer_connection->method == AIM_XFER_REDIR)
-			aim_tlvlist_add_16(&subtl, 0x000a, 0x0002);
-		else if(peer_connection->send_or_recv == AIM_XFER_SEND && peer_connection->stage == AIM_XFER_PROXY_STG3)
-			aim_tlvlist_add_16(&subtl, 0x000a, 0x0003);
-		else
-			aim_tlvlist_add_16(&subtl, 0x000a, 0x0001);
-
-		/* This is usually necessary, but ruins a redirect and a stg3 proxy request */
-		if(!(peer_connection->send_or_recv == AIM_XFER_RECV
-			&& (peer_connection->method == AIM_XFER_REDIR || peer_connection->stage == AIM_XFER_PROXY_STG3))) {
-			aim_tlvlist_add_noval(&subtl, 0x000f);
-		}
-
-		/* 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(&subtl, 0x000e, 2, "en");
-		aim_tlvlist_add_raw(&subtl, 0x000d, 8, "us-ascii");
-		aim_tlvlist_add_raw(&subtl, 0x000c, 24, "Please accept this file."); */
-		/* XXX - Change peer_connection->clientip to an array of 4 bytes */
-		if (peer_connection->clientip) {
-			i = 0;
-			nexttoken = strtok(peer_connection->clientip, ".");
-			while (nexttoken && i<4) {
-				ip[i] = atoi(nexttoken);
-				ip_comp[i] = ~ip[i];
-				nexttoken = strtok(NULL, ".");
-				i++;
-			}
-
-			/* If there is no proxyip, we must fill it in with the clientip */
-			if(!peer_connection->proxyip) {
-				aim_tlvlist_add_raw(&subtl, 0x0002, 4, ip);
-				aim_tlvlist_add_raw(&subtl, 0x0016, 4, ip_comp); /* check? value */
-			}
-
-			aim_tlvlist_add_raw(&subtl, 0x0003, 4, ip);
-		}
-
-		/* Don't send the proxyip & accompanying info during a receive redirect or stg3 proxy request */
-		if(!(peer_connection->send_or_recv == AIM_XFER_RECV
-			&& (peer_connection->method == AIM_XFER_REDIR || peer_connection->stage == AIM_XFER_PROXY_STG3))) {
-			if (peer_connection->proxyip) { /* Generate the proxyip */
-				i = 0;
-				nexttoken = strtok(peer_connection->proxyip, ".");
-				while (nexttoken && i<4) {
-					ip[i] = atoi(nexttoken);
-					ip_comp[i] = ~ip[i];
-					nexttoken = strtok(NULL, ".");
-					i++;
-				}
-				aim_tlvlist_add_raw(&subtl, 0x0002, 4, ip);
-				/* This zero-length TLV specifies a proxy will be used */
-				aim_tlvlist_add_noval(&subtl, 0x0010);
-
-				/* Proxied transfers fail without this next (check?) value */
-				aim_tlvlist_add_raw(&subtl, 0x0016, 4, ip_comp);
-			}
-		}
-
-		/* Don't send the port & its check during a stage 3 proxy request */
-		if(!(peer_connection->send_or_recv == AIM_XFER_RECV && peer_connection->stage == AIM_XFER_PROXY_STG3)) {
-			aim_tlvlist_add_16(&subtl, 0x0005, peer_connection->port);
-
-			/* Check value? Bitwise complement of the port */
-			aim_tlvlist_add_16(&subtl, 0x0017, ~(peer_connection->port));
-		}
-
-		/* winAIM gets mad at us if we send too much info during a send redirect or stg3 proxy request */
-		if(!(peer_connection->send_or_recv == AIM_XFER_RECV
-			&& (peer_connection->method == AIM_XFER_REDIR || peer_connection->stage == AIM_XFER_PROXY_STG3))) {
-			/* TLV t(2711) */
-			buflen = 2+2+4+strlen(peer_connection->fh.name)+1;
-			buf = malloc(buflen);
-			aim_bstream_init(&bs, buf, buflen);
-			aimbs_put16(&bs, (peer_connection->fh.totfiles > 1) ? 0x0002 : 0x0001);
-			aimbs_put16(&bs, peer_connection->fh.totfiles);
-			aimbs_put32(&bs, peer_connection->fh.totsize);
-
-			/* Filename - NULL terminated, for some odd reason */
-			aimbs_putstr(&bs, peer_connection->fh.name);
-			aimbs_put8(&bs, 0x00);
-
-			aim_tlvlist_add_raw(&subtl, 0x2711, bs.len, bs.data);
-			free(buf);
-		}
-	}
-
-	{ /* Create the main TLV chain */
-		guint8 *buf;
-		int buflen;
-		ByteStream bs;
-
-		/* TLV t(0005) - Encompasses everything from above. Gee. */
-		buflen = 2+8+16+aim_tlvlist_size(&subtl);
-		buf = malloc(buflen);
-		aim_bstream_init(&bs, buf, buflen);
-		aimbs_put16(&bs, AIM_RENDEZVOUS_PROPOSE);
-		aimbs_putraw(&bs, peer_connection->cookie, 8);
-		aimbs_putcaps(&bs, AIM_CAPS_SENDFILE);
-		aim_tlvlist_write(&bs, &subtl);
-		aim_tlvlist_free(&subtl);
-		aim_tlvlist_add_raw(&tl, 0x0005, bs.len, bs.data);
-		free(buf);
-
-		/* TLV t(0003) - Request an ack */
-		aim_tlvlist_add_noval(&tl, 0x0003);
-	}
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(peer_connection->sn) + aim_tlvlist_size(&tl))))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, peer_connection->cookie, sizeof(peer_connection->cookie));
-	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
+	aim_tlvlist_t *tl = NULL, *itl = NULL;
+	int hdrlen, buflen;
+	guint8 *hdr;
+	ByteStream hdrbs;
+
+	conn = flap_connection_findbygroup(od, 0x0004);
+	if (conn == NULL)
+		return;
+
+	frame = flap_frame_new(od, 0x02, 1024);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, peer_connection->cookie, 0x0002, peer_connection->sn);
-
-	/* All that crap from above (the 0x0005 TLV and the 0x0003 TLV) */
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
+
+	aim_tlvlist_add_noval(&tl, 0x0003);
+
+	hdrlen = 512;
+	hdr = malloc(hdrlen);
+	byte_stream_init(&hdrbs, hdr, hdrlen);
+
+	byte_stream_put16(&hdrbs, AIM_RENDEZVOUS_PROPOSE);
+	byte_stream_putraw(&hdrbs, cookie, 8);
+	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_SENDFILE);
+
+	aim_tlvlist_add_raw(&itl, 0x0002, 4, ip);
+	aim_tlvlist_add_raw(&itl, 0x0003, 4, ip);
+	aim_tlvlist_add_16(&itl, 0x0005, port);
+	aim_tlvlist_add_16(&itl, 0x000a, requestnumber);
+	aim_tlvlist_add_noval(&itl, 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(&itl, 0x000e, 2, "en");
+	aim_tlvlist_add_raw(&itl, 0x000d, 8, "us-ascii");
+	aim_tlvlist_add_raw(&itl, 0x000c, 24, "Please accept this file.");
+#endif
+
+	if (filename != NULL)
+	{
+		ByteStream bs;
+
+		/* Begin TLV t(2711) */
+		buflen = 2+2+4+strlen(filename)+1;
+		byte_stream_init(&bs, malloc(buflen), buflen);
+		byte_stream_put16(&bs, (numfiles > 1) ? 0x0002 : 0x0001);
+		byte_stream_put16(&bs, numfiles);
+		byte_stream_put32(&bs, size);
+
+		/* Filename - NULL terminated, for some odd reason */
+		byte_stream_putstr(&bs, filename);
+		byte_stream_put8(&bs, 0x00);
+
+		aim_tlvlist_add_raw(&itl, 0x2711, bs.len, bs.data);
+		free(bs.data);
+		/* End TLV t(2711) */
+	}
+
+	aim_tlvlist_write(&hdrbs, &itl);
+	aim_tlvlist_add_raw(&tl, 0x0005, byte_stream_curpos(&hdrbs), hdr);
+
+	aim_tlvlist_write(&frame->data, &tl);
+
+	free(hdr);
+	aim_tlvlist_free(&itl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
+	flap_connection_send(conn, frame);
 }
 
 /**
- * Subtype 0x0006 - Send an "I will accept this file" message?
- *
- * @param rendid Capability type (AIM_CAPS_GETFILE or AIM_CAPS_SENDFILE)
+ * Subtype 0x0006 - Send a sendfile connect rendezvous ICBM asking the
+ * remote user to connect to us via a proxy server.
  */
-faim_export int aim_im_sendch2_sendfile_accept(OscarSession *sess, PeerConnection *peer_connection)
+void
+aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
-
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !peer_connection)
-		return -EINVAL;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(peer_connection->sn) + 4+2+8+16)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
+	aim_tlvlist_t *tl = NULL, *itl = NULL;
+	int hdrlen, buflen;
+	guint8 *hdr;
+	ByteStream hdrbs;
+	guint8 ip_comp[4];
+
+	conn = flap_connection_findbygroup(od, 0x0004);
+	if (conn == NULL)
+		return;
+
+	frame = flap_frame_new(od, 0x02, 1024);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, peer_connection->cookie, 0x0002, peer_connection->sn);
-
-	aimbs_put16(&fr->data, 0x0005);
-	aimbs_put16(&fr->data, 0x001a);
-	aimbs_put16(&fr->data, AIM_RENDEZVOUS_ACCEPT);
-	aimbs_putraw(&fr->data, peer_connection->cookie, 8);
-	aimbs_putcaps(&fr->data, AIM_CAPS_SENDFILE);
-
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
-}
-
-/**
- * Subtype 0x0006 - Send a "cancel this file transfer" message?
- *
- */
-faim_export int aim_im_sendch2_sendfile_cancel(OscarSession *sess, PeerConnection *peer_connection)
-{
-	OscarConnection *conn;
-	FlapFrame *fr;
-	aim_snacid_t snacid;
-
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !peer_connection)
-		return -EINVAL;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(peer_connection->sn) + 4+2+8+16)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
-
-	/* ICBM header */
-	aim_im_puticbm(&fr->data, peer_connection->cookie, 0x0002, peer_connection->sn);
-
-	aimbs_put16(&fr->data, 0x0005);
-	aimbs_put16(&fr->data, 0x001a);
-	aimbs_put16(&fr->data, AIM_RENDEZVOUS_CANCEL);
-	aimbs_putraw(&fr->data, (const guchar *)peer_connection->cookie, 8);
-	aimbs_putcaps(&fr->data, AIM_CAPS_SENDFILE);
-
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
+	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
+
+	aim_tlvlist_add_noval(&tl, 0x0003);
+
+	hdrlen = 512;
+	hdr = malloc(hdrlen);
+	byte_stream_init(&hdrbs, hdr, hdrlen);
+
+	byte_stream_put16(&hdrbs, AIM_RENDEZVOUS_PROPOSE);
+	byte_stream_putraw(&hdrbs, cookie, 8);
+	byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_SENDFILE);
+
+	aim_tlvlist_add_raw(&itl, 0x0002, 4, ip);
+	aim_tlvlist_add_raw(&itl, 0x0003, 4, ip);
+	aim_tlvlist_add_16(&itl, 0x0005, pin);
+	aim_tlvlist_add_16(&itl, 0x000a, requestnumber);
+	aim_tlvlist_add_noval(&itl, 0x000f);
+	aim_tlvlist_add_noval(&itl, 0x0010);
+
+	/* Send the bitwise complement of the port and ip.  As a check? */
+	ip_comp[0] = ~ip[0];
+	ip_comp[1] = ~ip[1];
+	ip_comp[2] = ~ip[2];
+	ip_comp[3] = ~ip[3];
+	aim_tlvlist_add_raw(&itl, 0x0016, 4, ip_comp);
+	aim_tlvlist_add_16(&itl, 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(&itl, 0x000e, 2, "en");
+	aim_tlvlist_add_raw(&itl, 0x000d, 8, "us-ascii");
+	aim_tlvlist_add_raw(&itl, 0x000c, 24, "Please accept this file.");
+#endif
+
+	if (filename != NULL)
+	{
+		ByteStream bs;
+
+		/* Begin TLV t(2711) */
+		buflen = 2+2+4+strlen(filename)+1;
+		byte_stream_init(&bs, malloc(buflen), buflen);
+		byte_stream_put16(&bs, (numfiles > 1) ? 0x0002 : 0x0001);
+		byte_stream_put16(&bs, numfiles);
+		byte_stream_put32(&bs, size);
+
+		/* Filename - NULL terminated, for some odd reason */
+		byte_stream_putstr(&bs, filename);
+		byte_stream_put8(&bs, 0x00);
+
+		aim_tlvlist_add_raw(&itl, 0x2711, bs.len, bs.data);
+		free(bs.data);
+		/* End TLV t(2711) */
+	}
+
+	aim_tlvlist_write(&hdrbs, &itl);
+
+	aim_tlvlist_add_raw(&tl, 0x0005, byte_stream_curpos(&hdrbs), hdr);
+
+	aim_tlvlist_write(&frame->data, &tl);
+
+	free(hdr);
+	aim_tlvlist_free(&itl);
+	aim_tlvlist_free(&tl);
+
+	flap_connection_send(conn, frame);
 }
 
 /**
  * Subtype 0x0006 - Request the status message of the given ICQ user.
  *
- * @param sess The oscar session.
+ * @param od The oscar session.
  * @param sn 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.
  */
-faim_export int aim_im_sendch2_geticqaway(OscarSession *sess, const char *sn, int type)
+int aim_im_sendch2_geticqaway(OscarData *od, const char *sn, int type)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	guchar cookie[8];
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)) || !sn)
 		return -EINVAL;
 
 	aim_icbm_makecookie(cookie);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn) + 4+0x5e + 4)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
+	frame = flap_frame_new(od, 0x02, 10+8+2+1+strlen(sn) + 4+0x5e + 4);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
 
 	/* TLV t(0005) - Encompasses almost everything below. */
-	aimbs_put16(&fr->data, 0x0005); /* T */
-	aimbs_put16(&fr->data, 0x005e); /* L */
+	byte_stream_put16(&frame->data, 0x0005); /* T */
+	byte_stream_put16(&frame->data, 0x005e); /* L */
 	{ /* V */
-		aimbs_put16(&fr->data, 0x0000);
+		byte_stream_put16(&frame->data, 0x0000);
 
 		/* Cookie */
-		aimbs_putraw(&fr->data, cookie, 8);
+		byte_stream_putraw(&frame->data, cookie, 8);
 
 		/* Put the 16 byte server relay capability */
-		aimbs_putcaps(&fr->data, AIM_CAPS_ICQSERVERRELAY);
+		byte_stream_putcaps(&frame->data, OSCAR_CAPABILITY_ICQSERVERRELAY);
 
 		/* TLV t(000a) */
-		aimbs_put16(&fr->data, 0x000a);
-		aimbs_put16(&fr->data, 0x0002);
-		aimbs_put16(&fr->data, 0x0001);
+		byte_stream_put16(&frame->data, 0x000a);
+		byte_stream_put16(&frame->data, 0x0002);
+		byte_stream_put16(&frame->data, 0x0001);
 
 		/* TLV t(000f) */
-		aimbs_put16(&fr->data, 0x000f);
-		aimbs_put16(&fr->data, 0x0000);
+		byte_stream_put16(&frame->data, 0x000f);
+		byte_stream_put16(&frame->data, 0x0000);
 
 		/* TLV t(2711) */
-		aimbs_put16(&fr->data, 0x2711);
-		aimbs_put16(&fr->data, 0x0036);
+		byte_stream_put16(&frame->data, 0x2711);
+		byte_stream_put16(&frame->data, 0x0036);
 		{ /* V */
-			aimbs_putle16(&fr->data, 0x001b); /* L */
-			aimbs_putle16(&fr->data, 0x0009); /* Protocol version */
-			aimbs_putcaps(&fr->data, AIM_CAPS_EMPTY);
-			aimbs_putle16(&fr->data, 0x0000); /* Unknown */
-			aimbs_putle16(&fr->data, 0x0001); /* Client features? */
-			aimbs_putle16(&fr->data, 0x0000); /* Unknown */
-			aimbs_putle8(&fr->data, 0x00); /* Unkizown */
-			aimbs_putle16(&fr->data, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
-
-			aimbs_putle16(&fr->data, 0x000e); /* L */
-			aimbs_putle16(&fr->data, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
-			aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
-			aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
-			aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
+			byte_stream_putle16(&frame->data, 0x001b); /* L */
+			byte_stream_putle16(&frame->data, 0x0009); /* Protocol version */
+			byte_stream_putcaps(&frame->data, OSCAR_CAPABILITY_EMPTY);
+			byte_stream_putle16(&frame->data, 0x0000); /* Unknown */
+			byte_stream_putle16(&frame->data, 0x0001); /* Client features? */
+			byte_stream_putle16(&frame->data, 0x0000); /* Unknown */
+			byte_stream_putle8(&frame->data, 0x00); /* Unkizown */
+			byte_stream_putle16(&frame->data, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
+
+			byte_stream_putle16(&frame->data, 0x000e); /* L */
+			byte_stream_putle16(&frame->data, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
+			byte_stream_putle32(&frame->data, 0x00000000); /* Unknown */
+			byte_stream_putle32(&frame->data, 0x00000000); /* Unknown */
+			byte_stream_putle32(&frame->data, 0x00000000); /* Unknown */
 
 			/* The type of status message being requested */
 			if (type & AIM_ICQ_STATE_CHAT)
-				aimbs_putle16(&fr->data, 0x03ec);
+				byte_stream_putle16(&frame->data, 0x03ec);
 			else if(type & AIM_ICQ_STATE_DND)
-				aimbs_putle16(&fr->data, 0x03eb);
+				byte_stream_putle16(&frame->data, 0x03eb);
 			else if(type & AIM_ICQ_STATE_OUT)
-				aimbs_putle16(&fr->data, 0x03ea);
+				byte_stream_putle16(&frame->data, 0x03ea);
 			else if(type & AIM_ICQ_STATE_BUSY)
-				aimbs_putle16(&fr->data, 0x03e9);
+				byte_stream_putle16(&frame->data, 0x03e9);
 			else if(type & AIM_ICQ_STATE_AWAY)
-				aimbs_putle16(&fr->data, 0x03e8);
-
-			aimbs_putle16(&fr->data, 0x0001); /* Status? */
-			aimbs_putle16(&fr->data, 0x0001); /* Priority of this message? */
-			aimbs_putle16(&fr->data, 0x0001); /* L */
-			aimbs_putle8(&fr->data, 0x00); /* String of length L */
+				byte_stream_putle16(&frame->data, 0x03e8);
+
+			byte_stream_putle16(&frame->data, 0x0001); /* Status? */
+			byte_stream_putle16(&frame->data, 0x0001); /* Priority of this message? */
+			byte_stream_putle16(&frame->data, 0x0001); /* L */
+			byte_stream_putle8(&frame->data, 0x00); /* String of length L */
 		} /* End TLV t(2711) */
 	} /* End TLV t(0005) */
 
 	/* TLV t(0003) */
-	aimbs_put16(&fr->data, 0x0003);
-	aimbs_put16(&fr->data, 0x0000);
-
-	aim_tx_enqueue(sess, fr);
+	byte_stream_put16(&frame->data, 0x0003);
+	byte_stream_put16(&frame->data, 0x0000);
+
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1100,57 +1187,56 @@
  * @param message The message you want to send, it should be null terminated.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_im_sendch4(OscarSession *sess, const char *sn, guint16 type, const char *message)
+int aim_im_sendch4(OscarData *od, const char *sn, guint16 type, const char *message)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	guchar cookie[8];
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
 		return -EINVAL;
 
 	if (!sn || !type || !message)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+3+strlen(sn)+12+strlen(message)+1+4)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
+	frame = flap_frame_new(od, 0x02, 10+8+3+strlen(sn)+12+strlen(message)+1+4);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	aim_icbm_makecookie(cookie);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, cookie, 0x0004, sn);
+	aim_im_puticbm(&frame->data, cookie, 0x0004, sn);
 
 	/*
 	 * TLV t(0005)
 	 *
 	 * ICQ data (the UIN and the message).
 	 */
-	aimbs_put16(&fr->data, 0x0005);
-	aimbs_put16(&fr->data, 4 + 2+2+strlen(message)+1);
+	byte_stream_put16(&frame->data, 0x0005);
+	byte_stream_put16(&frame->data, 4 + 2+2+strlen(message)+1);
 
 	/*
 	 * Your UIN
 	 */
-	aimbs_putle32(&fr->data, atoi(sess->sn));
+	byte_stream_putle32(&frame->data, atoi(od->sn));
 
 	/*
 	 * TLV t(type) l(strlen(message)+1) v(message+NULL)
 	 */
-	aimbs_putle16(&fr->data, type);
-	aimbs_putle16(&fr->data, strlen(message)+1);
-	aimbs_putraw(&fr->data, (const guint8 *)message, strlen(message)+1);
+	byte_stream_putle16(&frame->data, type);
+	byte_stream_putle16(&frame->data, strlen(message)+1);
+	byte_stream_putraw(&frame->data, (const guint8 *)message, strlen(message)+1);
 
 	/*
 	 * TLV t(0006) l(0000) v()
 	 */
-	aimbs_put16(&fr->data, 0x0006);
-	aimbs_put16(&fr->data, 0x0000);
-
-	aim_tx_enqueue(sess, fr);
+	byte_stream_put16(&frame->data, 0x0006);
+	byte_stream_put16(&frame->data, 0x0000);
+
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1158,7 +1244,7 @@
 /*
  * XXX - I don't see when this would ever get called...
  */
-static int outgoingim(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+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;
@@ -1176,15 +1262,15 @@
 	aim_icbm_makecookie(cookie);
 
 	/* Channel ID */
-	channel = aimbs_get16(bs);
+	channel = byte_stream_get16(bs);
 
 	if (channel != 0x01) {
 		gaim_debug_misc("oscar", "icbm: ICBM recieved on unsupported channel.  Ignoring. (chan = %04x)\n", channel);
 		return 0;
 	}
 
-	snlen = aimbs_get8(bs);
-	sn = aimbs_getstr(bs, snlen);
+	snlen = byte_stream_get8(bs);
+	sn = byte_stream_getstr(bs, snlen);
 
 	tlvlist = aim_tlvlist_read(bs);
 
@@ -1197,25 +1283,25 @@
 		ByteStream mbs;
 		int featurelen, msglen;
 
-		aim_bstream_init(&mbs, msgblock->value, msgblock->length);
-
-		aimbs_get8(&mbs);
-		aimbs_get8(&mbs);
-		for (featurelen = aimbs_get16(&mbs); featurelen; featurelen--)
-			aimbs_get8(&mbs);
-		aimbs_get8(&mbs);
-		aimbs_get8(&mbs);
-
-		msglen = aimbs_get16(&mbs) - 4; /* final block length */
-
-		flag1 = aimbs_get16(&mbs);
-		flag2 = aimbs_get16(&mbs);
-
-		msg = aimbs_getstr(&mbs, 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(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, channel, sn, msg, icbmflags, flag1, flag2);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, channel, sn, msg, icbmflags, flag1, flag2);
 
 	free(sn);
 	aim_tlvlist_free(&tlvlist);
@@ -1260,7 +1346,7 @@
  * know what you are doing, and/or you have something neat to do with it.
  *
  */
-faim_export int aim_mpmsg_init(OscarSession *sess, aim_mpmsg_t *mpm)
+int aim_mpmsg_init(OscarData *od, aim_mpmsg_t *mpm)
 {
 
 	memset(mpm, 0, sizeof(aim_mpmsg_t));
@@ -1268,12 +1354,11 @@
 	return 0;
 }
 
-static int mpmsg_addsection(OscarSession *sess, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, gchar *data, guint16 datalen)
+static int mpmsg_addsection(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, gchar *data, guint16 datalen)
 {
 	aim_mpmsg_section_t *sec;
 
-	if (!(sec = malloc(sizeof(aim_mpmsg_section_t))))
-		return -1;
+	sec = malloc(sizeof(aim_mpmsg_section_t));
 
 	sec->charset = charset;
 	sec->charsubset = charsubset;
@@ -1296,15 +1381,14 @@
 	return 0;
 }
 
-faim_export int aim_mpmsg_addraw(OscarSession *sess, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, const gchar *data, guint16 datalen)
+int aim_mpmsg_addraw(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, const gchar *data, guint16 datalen)
 {
 	gchar *dup;
 
-	if (!(dup = malloc(datalen)))
-		return -1;
+	dup = malloc(datalen);
 	memcpy(dup, data, datalen);
 
-	if (mpmsg_addsection(sess, mpm, charset, charsubset, dup, datalen) == -1) {
+	if (mpmsg_addsection(od, mpm, charset, charsubset, dup, datalen) == -1) {
 		free(dup);
 		return -1;
 	}
@@ -1313,14 +1397,14 @@
 }
 
 /* XXX - should provide a way of saying ISO-8859-1 specifically */
-faim_export int aim_mpmsg_addascii(OscarSession *sess, aim_mpmsg_t *mpm, const char *ascii)
+int aim_mpmsg_addascii(OscarData *od, aim_mpmsg_t *mpm, const char *ascii)
 {
 	gchar *dup;
 
 	if (!(dup = strdup(ascii)))
 		return -1;
 
-	if (mpmsg_addsection(sess, mpm, 0x0000, 0x0000, dup, strlen(ascii)) == -1) {
+	if (mpmsg_addsection(od, mpm, 0x0000, 0x0000, dup, strlen(ascii)) == -1) {
 		free(dup);
 		return -1;
 	}
@@ -1328,22 +1412,21 @@
 	return 0;
 }
 
-faim_export int aim_mpmsg_addunicode(OscarSession *sess, aim_mpmsg_t *mpm, const guint16 *unicode, guint16 unicodelen)
+int aim_mpmsg_addunicode(OscarData *od, aim_mpmsg_t *mpm, const guint16 *unicode, guint16 unicodelen)
 {
 	gchar *buf;
 	ByteStream bs;
 	int i;
 
-	if (!(buf = malloc(unicodelen * 2)))
-		return -1;
-
-	aim_bstream_init(&bs, (guchar *)buf, unicodelen * 2);
+	buf = 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++)
-		aimbs_put16(&bs, unicode[i]);
-
-	if (mpmsg_addsection(sess, mpm, 0x0002, 0x0000, buf, aim_bstream_curpos(&bs)) == -1) {
+		byte_stream_put16(&bs, unicode[i]);
+
+	if (mpmsg_addsection(od, mpm, 0x0002, 0x0000, buf, byte_stream_curpos(&bs)) == -1) {
 		free(buf);
 		return -1;
 	}
@@ -1351,7 +1434,7 @@
 	return 0;
 }
 
-faim_export void aim_mpmsg_free(OscarSession *sess, aim_mpmsg_t *mpm)
+void aim_mpmsg_free(OscarData *od, aim_mpmsg_t *mpm)
 {
 	aim_mpmsg_section_t *cur;
 
@@ -1374,9 +1457,8 @@
  * 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(OscarSession *sess, aim_userinfo_t *userinfo, guint8 *data, int len, struct aim_incomingim_ch1_args *args)
+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[] = {
@@ -1389,26 +1471,26 @@
 	ByteStream mbs;
 	aim_mpmsg_section_t *sec;
 
-	aim_bstream_init(&mbs, data, len);
-
-	while (aim_bstream_empty(&mbs)) {
+	byte_stream_init(&mbs, data, len);
+
+	while (byte_stream_empty(&mbs)) {
 		guint16 msglen, flag1, flag2;
 		gchar *msgbuf;
 
-		aimbs_get8(&mbs); /* 01 */
-		aimbs_get8(&mbs); /* 01 */
+		byte_stream_get8(&mbs); /* 01 */
+		byte_stream_get8(&mbs); /* 01 */
 
 		/* Message string length, including character set info. */
-		msglen = aimbs_get16(&mbs);
-		if (msglen > aim_bstream_empty(&mbs))
+		msglen = byte_stream_get16(&mbs);
+		if (msglen > byte_stream_empty(&mbs))
 		{
 			gaim_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.", userinfo->sn);
 			break;
 		}
 
 		/* Character set info */
-		flag1 = aimbs_get16(&mbs);
-		flag2 = aimbs_get16(&mbs);
+		flag1 = byte_stream_get16(&mbs);
+		flag2 = byte_stream_get16(&mbs);
 
 		/* Message. */
 		msglen -= 4;
@@ -1426,8 +1508,8 @@
 		 * the received messages are given in network byte order.
 		 *
 		 */
-		msgbuf = (gchar *)aimbs_getraw(&mbs, msglen);
-		mpmsg_addsection(sess, &args->mpmsg, flag1, flag2, msgbuf, msglen);
+		msgbuf = (gchar *)byte_stream_getraw(&mbs, msglen);
+		mpmsg_addsection(od, &args->mpmsg, flag1, flag2, msgbuf, msglen);
 
 	} /* while */
 
@@ -1486,7 +1568,7 @@
 	return 0;
 }
 
-static int incomingim_ch1(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, ByteStream *bs, guint8 *cookie)
+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;
 	aim_rxcallback_t userfunc;
@@ -1496,25 +1578,25 @@
 
 	memset(&args, 0, sizeof(args));
 
-	aim_mpmsg_init(sess, &args.mpmsg);
+	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 (aim_bstream_empty(bs))
+	while (byte_stream_empty(bs))
 	{
-		type = aimbs_get16(bs);
-		length = aimbs_get16(bs);
-
-		if (length > aim_bstream_empty(bs))
+		type = byte_stream_get16(bs);
+		length = byte_stream_get16(bs);
+
+		if (length > byte_stream_empty(bs))
 		{
 			gaim_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->sn);
 			break;
 		}
 
-		endpos = aim_bstream_curpos(bs) + length;
+		endpos = byte_stream_curpos(bs) + length;
 
 		if (type == 0x0002) { /* Message Block */
 
@@ -1527,11 +1609,11 @@
 			 *
 			 */
 
-			aimbs_get8(bs); /* 05 */
-			aimbs_get8(bs); /* 01 */
-
-			args.featureslen = aimbs_get16(bs);
-			if (args.featureslen > aim_bstream_empty(bs))
+			byte_stream_get8(bs); /* 05 */
+			byte_stream_get8(bs); /* 01 */
+
+			args.featureslen = byte_stream_get16(bs);
+			if (args.featureslen > byte_stream_empty(bs))
 			{
 				gaim_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->sn);
 				break;
@@ -1542,7 +1624,7 @@
 			}
 			else
 			{
-				args.features = aimbs_getraw(bs, args.featureslen);
+				args.features = byte_stream_getraw(bs, args.featureslen);
 				args.icbmflags |= AIM_IMFLAGS_CUSTOMFEATURES;
 			}
 
@@ -1550,7 +1632,7 @@
 			 * The rest of the TLV contains one or more message
 			 * blocks...
 			 */
-			incomingim_ch1_parsemsgs(sess, userinfo, bs->data + bs->offset /* XXX evil!!! */, length - 2 - 2 - args.featureslen, &args);
+			incomingim_ch1_parsemsgs(od, userinfo, bs->data + bs->offset /* XXX evil!!! */, length - 2 - 2 - args.featureslen, &args);
 
 		} else if (type == 0x0003) { /* Server Ack Requested */
 
@@ -1567,10 +1649,10 @@
 
 		} else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */
 
-			args.iconlen = aimbs_get32(bs);
-			aimbs_get16(bs); /* 0x0001 */
-			args.iconsum = aimbs_get16(bs);
-			args.iconstamp = aimbs_get32(bs);
+			args.iconlen = byte_stream_get32(bs);
+			byte_stream_get16(bs); /* 0x0001 */
+			args.iconsum = byte_stream_get16(bs);
+			args.iconstamp = byte_stream_get32(bs);
 
 			/*
 			 * This looks to be a client bug.  MacAIM 4.3 will
@@ -1597,7 +1679,7 @@
 
 			free(args.extdata);
 			args.extdatalen = length;
-			if (args.extdatalen > aim_bstream_empty(bs))
+			if (args.extdatalen > byte_stream_empty(bs))
 			{
 				gaim_debug_misc("oscar", "Received an IM containing an invalid message part from %s.  They are probably trying to do something malicious.\n", userinfo->sn);
 				break;
@@ -1605,7 +1687,7 @@
 			if (args.extdatalen == 0)
 				args.extdata = NULL;
 			else
-				args.extdata = aimbs_getraw(bs, args.extdatalen);
+				args.extdata = byte_stream_getraw(bs, args.extdatalen);
 
 		} else {
 			gaim_debug_misc("oscar", "incomingim_ch1: unknown TLV 0x%04x (len %d)\n", type, length);
@@ -1619,21 +1701,21 @@
 		 * TLV when the loop continues.
 		 *
 		 */
-		aim_bstream_setpos(bs, endpos);
+		byte_stream_setpos(bs, endpos);
 	}
 
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, channel, userinfo, &args);
-
-	aim_mpmsg_free(sess, &args.mpmsg);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, channel, userinfo, &args);
+
+	aim_mpmsg_free(od, &args.mpmsg);
 	free(args.features);
 	free(args.extdata);
 
 	return ret;
 }
 
-static void incomingim_ch2_buddylist(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, ByteStream *servdata)
+static void incomingim_ch2_buddylist(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
 {
 
 	/*
@@ -1655,21 +1737,21 @@
 	 *     ...
 	 *   ...
 	 */
-	while (servdata && aim_bstream_empty(servdata)) {
+	while (servdata && byte_stream_empty(servdata)) {
 		guint16 gnlen, numb;
 		int i;
 		char *gn;
 
-		gnlen = aimbs_get16(servdata);
-		gn = aimbs_getstr(servdata, gnlen);
-		numb = aimbs_get16(servdata);
+		gnlen = byte_stream_get16(servdata);
+		gn = byte_stream_getstr(servdata, gnlen);
+		numb = byte_stream_get16(servdata);
 
 		for (i = 0; i < numb; i++) {
 			guint16 bnlen;
 			char *bn;
 
-			bnlen = aimbs_get16(servdata);
-			bn = aimbs_getstr(servdata, bnlen);
+			bnlen = byte_stream_get16(servdata);
+			bn = byte_stream_getstr(servdata, bnlen);
 
 			gaim_debug_misc("oscar", "got a buddy list from %s: group %s, buddy %s\n", userinfo->sn, gn, bn);
 
@@ -1682,7 +1764,7 @@
 	return;
 }
 
-static void incomingim_ch2_buddyicon_free(OscarSession *sess, struct aim_incomingim_ch2_args *args)
+static void incomingim_ch2_buddyicon_free(OscarData *od, IcbmArgsCh2 *args)
 {
 
 	free(args->info.icon.icon);
@@ -1690,14 +1772,14 @@
 	return;
 }
 
-static void incomingim_ch2_buddyicon(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, ByteStream *servdata)
+static void incomingim_ch2_buddyicon(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
 {
 
 	if (servdata) {
-		args->info.icon.checksum = aimbs_get32(servdata);
-		args->info.icon.length = aimbs_get32(servdata);
-		args->info.icon.timestamp = aimbs_get32(servdata);
-		args->info.icon.icon = aimbs_getraw(servdata, args->info.icon.length);
+		args->info.icon.checksum = byte_stream_get32(servdata);
+		args->info.icon.length = byte_stream_get32(servdata);
+		args->info.icon.timestamp = byte_stream_get32(servdata);
+		args->info.icon.icon = byte_stream_getraw(servdata, args->info.icon.length);
 	}
 
 	args->destructor = (void *)incomingim_ch2_buddyicon_free;
@@ -1705,7 +1787,7 @@
 	return;
 }
 
-static void incomingim_ch2_chat_free(OscarSession *sess, struct aim_incomingim_ch2_args *args)
+static void incomingim_ch2_chat_free(OscarData *od, IcbmArgsCh2 *args)
 {
 
 	/* XXX - aim_chat_roominfo_free() */
@@ -1714,7 +1796,7 @@
 	return;
 }
 
-static void incomingim_ch2_chat(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, ByteStream *servdata)
+static void incomingim_ch2_chat(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
 {
 
 	/*
@@ -1728,7 +1810,7 @@
 	return;
 }
 
-static void incomingim_ch2_icqserverrelay_free(OscarSession *sess, struct aim_incomingim_ch2_args *args)
+static void incomingim_ch2_icqserverrelay_free(OscarData *od, IcbmArgsCh2 *args)
 {
 
 	free((char *)args->info.rtfmsg.rtfmsg);
@@ -1737,48 +1819,48 @@
 }
 
 /*
- * The relationship between AIM_CAPS_ICQSERVERRELAY and AIM_CAPS_ICQRTF is
+ * The relationship between OSCAR_CAPABILITY_ICQSERVERRELAY and OSCAR_CAPABILITY_ICQRTF is
  * kind of odd. This sends the client ICQRTF since that is all that I've seen
  * SERVERRELAY used for.
  *
  * Note that this is all little-endian.  Cringe.
  *
  */
-static void incomingim_ch2_icqserverrelay(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, ByteStream *servdata)
+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;
 
-	hdrlen = aimbs_getle16(servdata);
-	aim_bstream_advance(servdata, hdrlen);
-
-	hdrlen = aimbs_getle16(servdata);
-	aim_bstream_advance(servdata, hdrlen);
-
-	args->info.rtfmsg.msgtype = aimbs_getle16(servdata);
-
-	anslen = aimbs_getle32(servdata);
-	aim_bstream_advance(servdata, anslen);
-
-	msglen = aimbs_getle16(servdata);
-	args->info.rtfmsg.rtfmsg = aimbs_getstr(servdata, msglen);
-
-	args->info.rtfmsg.fgcolor = aimbs_getle32(servdata);
-	args->info.rtfmsg.bgcolor = aimbs_getle32(servdata);
-
-	hdrlen = aimbs_getle32(servdata);
-	aim_bstream_advance(servdata, hdrlen);
+	hdrlen = byte_stream_getle16(servdata);
+	byte_stream_advance(servdata, hdrlen);
+
+	hdrlen = byte_stream_getle16(servdata);
+	byte_stream_advance(servdata, hdrlen);
+
+	args->info.rtfmsg.msgtype = byte_stream_getle16(servdata);
+
+	anslen = byte_stream_getle32(servdata);
+	byte_stream_advance(servdata, anslen);
+
+	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;
 
 	return;
 }
 
-static void incomingim_ch2_sendfile_free(OscarSession *sess, struct aim_incomingim_ch2_args *args)
+static void incomingim_ch2_sendfile_free(OscarData *od, IcbmArgsCh2 *args)
 {
 	free(args->info.sendfile.filename);
 }
 
-static void incomingim_ch2_sendfile(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, ByteStream *servdata)
+static void incomingim_ch2_sendfile(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
 {
 
 	args->destructor = (void *)incomingim_ch2_sendfile_free;
@@ -1789,9 +1871,9 @@
 		int flen;
 
 		/* subtype is one of AIM_OFT_SUBTYPE_* */
-		args->info.sendfile.subtype = aimbs_get16(servdata);
-		args->info.sendfile.totfiles = aimbs_get16(servdata);
-		args->info.sendfile.totsize = aimbs_get32(servdata);
+		args->info.sendfile.subtype = byte_stream_get16(servdata);
+		args->info.sendfile.totfiles = byte_stream_get16(servdata);
+		args->info.sendfile.totsize = byte_stream_get32(servdata);
 
 		/*
 		 * I hope to God I'm right when I guess that there is a
@@ -1799,12 +1881,12 @@
 		 * OFT tends to do that.  Gotta love inconsistency.  I saw
 		 * a 26 byte filename?
 		 */
-		/* AAA - create an aimbs_getnullstr function (don't anymore)(maybe) */
+		/* AAA - create an byte_stream_getnullstr function (don't anymore)(maybe) */
 		/* Use an inelegant way of getting the null-terminated filename,
 		 * since there's no easy bstream routine. */
-		for (flen = 0; aimbs_get8(servdata); flen++);
-		aim_bstream_advance(servdata, -flen -1);
-		args->info.sendfile.filename = aimbs_getstr(servdata, flen);
+		for (flen = 0; byte_stream_get8(servdata); flen++);
+		byte_stream_advance(servdata, -flen -1);
+		args->info.sendfile.filename = byte_stream_getstr(servdata, flen);
 
 		/* There is sometimes more after the null-terminated filename,
 		 * but I'm unsure of its format. */
@@ -1817,14 +1899,14 @@
 	return;
 }
 
-typedef void (*ch2_args_destructor_t)(OscarSession *sess, struct aim_incomingim_ch2_args *args);
-
-static int incomingim_ch2(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, guint8 *cookie)
+typedef void (*ch2_args_destructor_t)(OscarData *od, IcbmArgsCh2 *args);
+
+static int incomingim_ch2(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, guint8 *cookie)
 {
 	aim_rxcallback_t userfunc;
 	aim_tlv_t *block1, *servdatatlv;
 	aim_tlvlist_t *list2;
-	struct aim_incomingim_ch2_args args;
+	IcbmArgsCh2 args;
 	ByteStream bbs, sdbs, *sdbsptr = NULL;
 	guint8 *cookie2;
 	int ret = 0;
@@ -1839,19 +1921,20 @@
 	 * There's another block of TLVs embedded in the type 5 here.
 	 */
 	block1 = aim_tlv_gettlv(tlvlist, 0x0005, 1);
-	aim_bstream_init(&bbs, block1->value, block1->length);
+	byte_stream_init(&bbs, block1->value, block1->length);
 
 	/*
 	 * First two bytes represent the status of the connection.
+	 * One of the AIM_RENDEZVOUS_ defines.
 	 *
 	 * 0 is a request, 1 is a cancel, 2 is an accept
 	 */
-	args.status = aimbs_get16(&bbs);
+	args.status = byte_stream_get16(&bbs);
 
 	/*
 	 * Next comes the cookie.  Should match the ICBM cookie.
 	 */
-	cookie2 = aimbs_getraw(&bbs, 8);
+	cookie2 = byte_stream_getraw(&bbs, 8);
 	if (memcmp(cookie, cookie2, 8) != 0)
 		gaim_debug_misc("oscar", "rend: warning cookies don't match!\n");
 	memcpy(args.cookie, cookie2, 8);
@@ -1861,7 +1944,7 @@
 	 * The next 16bytes are a capability block so we can
 	 * identify what type of rendezvous this is.
 	 */
-	args.reqclass = aim_locate_getcaps(sess, &bbs, 0x10);
+	args.type = aim_locate_getcaps(od, &bbs, 0x10);
 
 	/*
 	 * What follows may be TLVs or nothing, depending on the
@@ -1874,7 +1957,7 @@
 	/*
 	 * IP address to proxy the file transfer through.
 	 *
-	 * XXX - I don't like this.  Maybe just read in an int?  Or inet_ntoa...
+	 * TODO: I don't like this.  Maybe just read in an int?  Or inet_ntoa...
 	 */
 	if (aim_tlv_gettlv(list2, 0x0002, 1)) {
 		aim_tlv_t *iptlv;
@@ -1921,23 +2004,17 @@
 		args.port = aim_tlv_get16(list2, 0x0005, 1);
 
 	/*
-	 * Something to do with ft? -- two bytes
-	 * 0x0001 - "I want to send you this file"
-	 * 0x0002 - "I will accept this file from you"
-	 * 0x0002 - Also used in ICQ Lite Beta 4.0 URLs
+	 * File transfer "request number":
+	 * 0x0001 - Initial file transfer request for no proxy or stage 1 proxy
+	 * 0x0002 - "Reply request" for a stage 2 proxy (receiver wants to use proxy)
+	 * 0x0003 - A third request has been sent; applies only to stage 3 proxied transfers
 	 */
-	 /*
-	  * This is what I call the request number of the file transfer
-	  * 0x0001 - Initial file transfer request for no proxy or stage 1 proxy
-	  * 0x0002 - "Reply request" for a stage 2 proxy (receiver wants to use proxy)
-	  * 0x0003 - A third request has been sent; applies only to stage 3 proxied transfers
-	  * -- Jonathan
-	  */
 	if (aim_tlv_gettlv(list2, 0x000a, 1))
-		args.info.sendfile.reqnum = aim_tlv_get16(list2, 0x000a, 1);
+		args.requestnumber = aim_tlv_get16(list2, 0x000a, 1);
 
 	/*
-	 * Error code.
+	 * Terminate connection/error code.  0x0001 means the other user
+	 * canceled the connection.
 	 */
 	if (aim_tlv_gettlv(list2, 0x000b, 1))
 		args.errorcode = aim_tlv_get16(list2, 0x000b, 1);
@@ -1980,9 +2057,7 @@
 	 * Flag meaning we should proxy the file transfer through an AIM server
 	 */
 	if (aim_tlv_gettlv(list2, 0x0010, 1))
-		args.info.sendfile.use_proxy = TRUE;
-	else
-		args.info.sendfile.use_proxy = FALSE;
+		args.use_proxy = TRUE;
 
 	if (strlen(proxyip))
 		args.proxyip = (char *)proxyip;
@@ -1994,13 +2069,13 @@
 	/*
 	 * This must be present in PROPOSALs, but will probably not
 	 * exist in CANCELs and ACCEPTs.  Also exists in ICQ Lite
-	 * Beta 4.0 URLs (AIM_CAPS_ICQSERVERRELAY).
+	 * Beta 4.0 URLs (OSCAR_CAPABILITY_ICQSERVERRELAY).
 	 *
 	 * Service Data blocks are module-specific in format.
 	 */
 	if ((servdatatlv = aim_tlv_gettlv(list2, 0x2711 /* 10001 */, 1))) {
 
-		aim_bstream_init(&sdbs, servdatatlv->value, servdatatlv->length);
+		byte_stream_init(&sdbs, servdatatlv->value, servdatatlv->length);
 		sdbsptr = &sdbs;
 	}
 
@@ -2009,23 +2084,23 @@
 	 *
 	 * Not all of them have special handling (yet).
 	 */
-	if (args.reqclass & AIM_CAPS_BUDDYICON)
-		incomingim_ch2_buddyicon(sess, mod, rx, snac, userinfo, &args, sdbsptr);
-	else if (args.reqclass & AIM_CAPS_SENDBUDDYLIST)
-		incomingim_ch2_buddylist(sess, mod, rx, snac, userinfo, &args, sdbsptr);
-	else if (args.reqclass & AIM_CAPS_CHAT)
-		incomingim_ch2_chat(sess, mod, rx, snac, userinfo, &args, sdbsptr);
-	else if (args.reqclass & AIM_CAPS_ICQSERVERRELAY)
-		incomingim_ch2_icqserverrelay(sess, mod, rx, snac, userinfo, &args, sdbsptr);
-	else if (args.reqclass & AIM_CAPS_SENDFILE)
-		incomingim_ch2_sendfile(sess, mod, rx, snac, userinfo, &args, sdbsptr);
-
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, channel, userinfo, &args);
+	if (args.type & OSCAR_CAPABILITY_BUDDYICON)
+		incomingim_ch2_buddyicon(od, conn, mod, frame, snac, userinfo, &args, sdbsptr);
+	else if (args.type & OSCAR_CAPABILITY_SENDBUDDYLIST)
+		incomingim_ch2_buddylist(od, conn, mod, frame, snac, userinfo, &args, sdbsptr);
+	else if (args.type & OSCAR_CAPABILITY_CHAT)
+		incomingim_ch2_chat(od, conn, mod, frame, snac, userinfo, &args, sdbsptr);
+	else if (args.type & OSCAR_CAPABILITY_ICQSERVERRELAY)
+		incomingim_ch2_icqserverrelay(od, conn, mod, frame, snac, userinfo, &args, sdbsptr);
+	else if (args.type & OSCAR_CAPABILITY_SENDFILE)
+		incomingim_ch2_sendfile(od, conn, mod, frame, snac, userinfo, &args, sdbsptr);
+
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, channel, userinfo, &args);
 
 
 	if (args.destructor)
-		((ch2_args_destructor_t)args.destructor)(sess, &args);
+		((ch2_args_destructor_t)args.destructor)(od, &args);
 
 	free((char *)args.msg);
 	free((char *)args.encoding);
@@ -2036,7 +2111,7 @@
 	return ret;
 }
 
-static int incomingim_ch4(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, guint8 *cookie)
+static int incomingim_ch4(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, guint8 *cookie)
 {
 	ByteStream meat;
 	aim_rxcallback_t userfunc;
@@ -2049,16 +2124,16 @@
 	 */
 	if (!(block = aim_tlv_gettlv(tlvlist, 0x0005, 1)))
 		return -1;
-	aim_bstream_init(&meat, block->value, block->length);
-
-	args.uin = aimbs_getle32(&meat);
-	args.type = aimbs_getle8(&meat);
-	args.flags = aimbs_getle8(&meat);
-	args.msglen = aimbs_getle16(&meat);
-	args.msg = (gchar *)aimbs_getraw(&meat, args.msglen);
-
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, channel, userinfo, &args);
+	byte_stream_init(&meat, block->value, block->length);
+
+	args.uin = byte_stream_getle32(&meat);
+	args.type = byte_stream_getle8(&meat);
+	args.flags = byte_stream_getle8(&meat);
+	args.msglen = byte_stream_getle16(&meat);
+	args.msg = (gchar *)byte_stream_getraw(&meat, args.msglen);
+
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, channel, userinfo, &args);
 
 	free(args.msg);
 
@@ -2078,7 +2153,7 @@
  * I have access to.  Its not fast, its not clean.  But it works.
  *
  */
-static int incomingim(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int incomingim(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	guchar *cookie;
@@ -2090,7 +2165,7 @@
 	/*
 	 * Read ICBM Cookie.
 	 */
-	cookie = aimbs_getraw(bs, 8);
+	cookie = byte_stream_getraw(bs, 8);
 
 	/*
 	 * Channel ID.
@@ -2108,7 +2183,7 @@
 	 * possibly any system notice.
 	 *
 	 */
-	channel = aimbs_get16(bs);
+	channel = byte_stream_get16(bs);
 
 	/*
 	 * Extract the standard user info block.
@@ -2125,7 +2200,7 @@
 	 * never be two TLVs of the same type in one block.
 	 *
 	 */
-	aim_info_extract(sess, bs, &userinfo);
+	aim_info_extract(od, bs, &userinfo);
 
 	/*
 	 * From here on, its depends on what channel we're on.
@@ -2136,7 +2211,7 @@
 	 */
 	if (channel == 1) {
 
-		ret = incomingim_ch1(sess, mod, rx, snac, channel, &userinfo, bs, cookie);
+		ret = incomingim_ch1(od, conn, mod, frame, snac, channel, &userinfo, bs, cookie);
 
 	} else if (channel == 2) {
 		aim_tlvlist_t *tlvlist;
@@ -2147,7 +2222,7 @@
 		 */
 		tlvlist = aim_tlvlist_read(bs);
 
-		ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);
+		ret = incomingim_ch2(od, conn, mod, frame, snac, channel, &userinfo, tlvlist, cookie);
 
 		aim_tlvlist_free(&tlvlist);
 
@@ -2155,7 +2230,7 @@
 		aim_tlvlist_t *tlvlist;
 
 		tlvlist = aim_tlvlist_read(bs);
-		ret = incomingim_ch4(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);
+		ret = incomingim_ch4(od, conn, mod, frame, snac, channel, &userinfo, tlvlist, cookie);
 		aim_tlvlist_free(&tlvlist);
 
 	} else {
@@ -2177,46 +2252,45 @@
  * returns -1 on error (couldn't alloc packet), 0 on success.
  *
  */
-faim_export int aim_im_warn(OscarSession *sess, OscarConnection *conn, const char *sn, guint32 flags)
+int aim_im_warn(OscarData *od, FlapConnection *conn, const char *sn, guint32 flags)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !conn || !sn)
+	if (!od || !conn || !sn)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(sn)+13)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, sn, strlen(sn)+1);
-	aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid);
-
-	aimbs_put16(&fr->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000);
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
-
-	aim_tx_enqueue(sess, fr);
+	frame = flap_frame_new(od, 0x02, strlen(sn)+13);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0008, 0x0000, sn, strlen(sn)+1);
+	aim_putsnac(&frame->data, 0x0004, 0x0008, 0x0000, snacid);
+
+	byte_stream_put16(&frame->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000);
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
+
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
 /* Subtype 0x000a */
-static int missedcall(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int missedcall(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 channel, nummissed, reason;
 	aim_userinfo_t userinfo;
 
-	while (aim_bstream_empty(bs)) {
-
-		channel = aimbs_get16(bs);
-		aim_info_extract(sess, bs, &userinfo);
-		nummissed = aimbs_get16(bs);
-		reason = aimbs_get16(bs);
-
-		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-			 ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason);
+	while (byte_stream_empty(bs)) {
+
+		channel = byte_stream_get16(bs);
+		aim_info_extract(od, bs, &userinfo);
+		nummissed = byte_stream_get16(bs);
+		reason = byte_stream_get16(bs);
+
+		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+			 ret = userfunc(od, conn, frame, channel, &userinfo, nummissed, reason);
 
 		aim_info_free(&userinfo);
 	}
@@ -2233,44 +2307,42 @@
  *    AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers"
  *
  */
-faim_export int aim_im_denytransfer(OscarSession *sess, const char *sender, const guchar *cookie, guint16 code)
+int aim_im_denytransfer(OscarData *od, const char *sn, const guchar *cookie, guint16 code)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sender)+6)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x000b, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0004, 0x000b, 0x0000, snacid);
-
-	aimbs_putraw(&fr->data, cookie, 8);
-
-	aimbs_put16(&fr->data, 0x0002); /* channel */
-	aimbs_put8(&fr->data, strlen(sender));
-	aimbs_putstr(&fr->data, sender);
+	frame = flap_frame_new(od, 0x02, 10+8+2+1+strlen(sn)+6);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x000b, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x000b, 0x0000, snacid);
+
+	byte_stream_putraw(&frame->data, cookie, 8);
+
+	byte_stream_put16(&frame->data, 0x0002); /* channel */
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
 
 	aim_tlvlist_add_16(&tl, 0x0003, code);
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
 /*
- * Subtype 0x000b - Receive the response from an ICQ status message request.
- *
- * This contains the ICQ status message.  Go figure.
- *
+ * 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.
  */
-static int clientautoresp(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int clientautoresp(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -2279,17 +2351,17 @@
 	guchar *cookie;
 	guint8 snlen;
 
-	cookie = aimbs_getraw(bs, 8);
-	channel = aimbs_get16(bs);
-	snlen = aimbs_get8(bs);
-	sn = aimbs_getstr(bs, snlen);
-	reason = aimbs_get16(bs);
+	cookie = byte_stream_getraw(bs, 8);
+	channel = byte_stream_get16(bs);
+	snlen = byte_stream_get8(bs);
+	sn = byte_stream_getstr(bs, snlen);
+	reason = byte_stream_get16(bs);
 
 	if (channel == 0x0002) { /* File transfer declined */
-		aimbs_get16(bs); /* Unknown */
-		aimbs_get16(bs); /* Unknown */
-		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-			ret = userfunc(sess, rx, channel, sn, reason, cookie);
+		byte_stream_get16(bs); /* Unknown */
+		byte_stream_get16(bs); /* Unknown */
+		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+			ret = userfunc(od, conn, frame, channel, sn, reason, cookie);
 	} else if (channel == 0x0004) { /* ICQ message */
 		switch (reason) {
 			case 0x0003: { /* ICQ status message.  Maybe other stuff too, you never know with these people. */
@@ -2297,13 +2369,13 @@
 				guint16 len;
 				guint32 state;
 
-				len = aimbs_getle16(bs); /* Should be 0x001b */
-				aim_bstream_advance(bs, len); /* Unknown */
-
-				len = aimbs_getle16(bs); /* Should be 0x000e */
-				aim_bstream_advance(bs, len); /* Unknown */
-
-				statusmsgtype = aimbs_getle8(bs);
+				len = byte_stream_getle16(bs); /* Should be 0x001b */
+				byte_stream_advance(bs, len); /* Unknown */
+
+				len = byte_stream_getle16(bs); /* Should be 0x000e */
+				byte_stream_advance(bs, len); /* Unknown */
+
+				statusmsgtype = byte_stream_getle8(bs);
 				switch (statusmsgtype) {
 					case 0xe8:
 						state = AIM_ICQ_STATE_AWAY;
@@ -2325,22 +2397,22 @@
 						break;
 				}
 
-				aimbs_getle8(bs); /* Unknown - 0x03 Maybe this means this is an auto-reply */
-				aimbs_getle16(bs); /* Unknown - 0x0000 */
-				aimbs_getle16(bs); /* Unknown - 0x0000 */
-
-				len = aimbs_getle16(bs);
-				msg = aimbs_getraw(bs, len);
-
-				if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-					ret = userfunc(sess, rx, channel, sn, reason, state, msg);
+				byte_stream_getle8(bs); /* Unknown - 0x03 Maybe this means this is an auto-reply */
+				byte_stream_getle16(bs); /* Unknown - 0x0000 */
+				byte_stream_getle16(bs); /* Unknown - 0x0000 */
+
+				len = byte_stream_getle16(bs);
+				msg = byte_stream_getraw(bs, len);
+
+				if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+					ret = userfunc(od, conn, frame, channel, sn, reason, state, msg);
 
 				free(msg);
 			} break;
 
 			default: {
-				if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-					ret = userfunc(sess, rx, channel, sn, reason);
+				if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+					ret = userfunc(od, conn, frame, channel, sn, reason);
 			} break;
 		} /* end switch */
 	}
@@ -2359,7 +2431,7 @@
  * sent.
  *
  */
-static int msgack(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+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;
@@ -2367,12 +2439,12 @@
 	char *sn;
 	int ret = 0;
 
-	cookie = aimbs_getraw(bs, 8);
-	ch = aimbs_get16(bs);
-	sn = aimbs_getstr(bs, aimbs_get8(bs));
-
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, ch, sn);
+	cookie = byte_stream_getraw(bs, 8);
+	ch = byte_stream_get16(bs);
+	sn = byte_stream_getstr(bs, byte_stream_get8(bs));
+
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, ch, sn);
 
 	free(sn);
 	free(cookie);
@@ -2387,50 +2459,49 @@
  * and Gaim 0.60 and newer.
  *
  */
-faim_export int aim_im_sendmtn(OscarSession *sess, guint16 type1, const char *sn, guint16 type2)
+int aim_im_sendmtn(OscarData *od, guint16 type1, const char *sn, guint16 type2)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
 		return -EINVAL;
 
 	if (!sn)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+11+strlen(sn)+2)))
-		return -ENOMEM;
-
-	snacid = aim_cachesnac(sess, 0x0004, 0x0014, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0004, 0x0014, 0x0000, snacid);
+	frame = flap_frame_new(od, 0x02, 10+11+strlen(sn)+2);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0014, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0004, 0x0014, 0x0000, snacid);
 
 	/*
 	 * 8 days of light
 	 * Er, that is to say, 8 bytes of 0's
 	 */
-	aimbs_put16(&fr->data, 0x0000);
-	aimbs_put16(&fr->data, 0x0000);
-	aimbs_put16(&fr->data, 0x0000);
-	aimbs_put16(&fr->data, 0x0000);
+	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&frame->data, 0x0000);
 
 	/*
 	 * Type 1 (should be 0x0001 for mtn)
 	 */
-	aimbs_put16(&fr->data, type1);
+	byte_stream_put16(&frame->data, type1);
 
 	/*
 	 * Dest sn
 	 */
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
 
 	/*
 	 * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn)
 	 */
-	aimbs_put16(&fr->data, type2);
-
-	aim_tx_enqueue(sess, fr);
+	byte_stream_put16(&frame->data, type2);
+
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -2442,7 +2513,7 @@
  * and Gaim 0.60 and newer.
  *
  */
-static int mtn_receive(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int mtn_receive(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -2450,44 +2521,44 @@
 	guint8 snlen;
 	guint16 type1, type2;
 
-	aim_bstream_advance(bs, 8); /* Unknown - All 0's */
-	type1 = aimbs_get16(bs);
-	snlen = aimbs_get8(bs);
-	sn = aimbs_getstr(bs, snlen);
-	type2 = aimbs_get16(bs);
-
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, type1, sn, type2);
+	byte_stream_advance(bs, 8); /* Unknown - All 0's */
+	type1 = byte_stream_get16(bs);
+	snlen = byte_stream_get8(bs);
+	sn = byte_stream_getstr(bs, snlen);
+	type2 = byte_stream_get16(bs);
+
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, type1, sn, type2);
 
 	free(sn);
 
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0005)
-		return aim_im_paraminfo(sess, mod, rx, snac, bs);
+		return aim_im_paraminfo(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0006)
-		return outgoingim(sess, mod, rx, snac, bs);
+		return outgoingim(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0007)
-		return incomingim(sess, mod, rx, snac, bs);
+		return incomingim(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x000a)
-		return missedcall(sess, mod, rx, snac, bs);
+		return missedcall(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x000b)
-		return clientautoresp(sess, mod, rx, snac, bs);
+		return clientautoresp(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x000c)
-		return msgack(sess, mod, rx, snac, bs);
+		return msgack(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0014)
-		return mtn_receive(sess, mod, rx, snac, bs);
+		return mtn_receive(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int msg_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+msg_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x0004;
 	mod->version = 0x0001;
 	mod->toolid = 0x0110;
--- a/src/protocols/oscar/family_icq.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_icq.c	Fri Apr 07 05:10:56 2006 +0000
@@ -25,108 +25,105 @@
 
 #include "oscar.h"
 
-faim_export int aim_icq_reqofflinemsgs(OscarSession *sess)
+int aim_icq_reqofflinemsgs(OscarData *od)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int bslen;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0015)))
 		return -EINVAL;
 
 	bslen = 2 + 4 + 2 + 2;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
 
-	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put16(&fr->data, bslen);
+	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&frame->data, bslen);
 
-	aimbs_putle16(&fr->data, bslen - 2);
-	aimbs_putle32(&fr->data, atoi(sess->sn));
-	aimbs_putle16(&fr->data, 0x003c); /* I command thee. */
-	aimbs_putle16(&fr->data, snacid); /* eh. */
+	byte_stream_putle16(&frame->data, bslen - 2);
+	byte_stream_putle32(&frame->data, atoi(od->sn));
+	byte_stream_putle16(&frame->data, 0x003c); /* I command thee. */
+	byte_stream_putle16(&frame->data, snacid); /* eh. */
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
-faim_export int aim_icq_ackofflinemsgs(OscarSession *sess)
+int aim_icq_ackofflinemsgs(OscarData *od)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int bslen;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0015)))
 		return -EINVAL;
 
 	bslen = 2 + 4 + 2 + 2;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
 
-	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put16(&fr->data, bslen);
+	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&frame->data, bslen);
 
-	aimbs_putle16(&fr->data, bslen - 2);
-	aimbs_putle32(&fr->data, atoi(sess->sn));
-	aimbs_putle16(&fr->data, 0x003e); /* I command thee. */
-	aimbs_putle16(&fr->data, snacid); /* eh. */
+	byte_stream_putle16(&frame->data, bslen - 2);
+	byte_stream_putle32(&frame->data, atoi(od->sn));
+	byte_stream_putle16(&frame->data, 0x003e); /* I command thee. */
+	byte_stream_putle16(&frame->data, snacid); /* eh. */
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
-faim_export int
-aim_icq_setsecurity(OscarSession *sess, gboolean auth_required, gboolean webaware)
+int
+aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int bslen;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0015)))
 		return -EINVAL;
 
 	bslen = 2+4+2+2+2+2+2+1+1+1+1+1+1;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
 
-	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put16(&fr->data, bslen);
+	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&frame->data, bslen);
 
-	aimbs_putle16(&fr->data, bslen - 2);
-	aimbs_putle32(&fr->data, atoi(sess->sn));
-	aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
-	aimbs_putle16(&fr->data, snacid); /* eh. */
-	aimbs_putle16(&fr->data, 0x0c3a); /* shrug. */
-	aimbs_putle16(&fr->data, 0x030c);
-	aimbs_putle16(&fr->data, 0x0001);
-	aimbs_putle8(&fr->data, webaware);
-	aimbs_putle8(&fr->data, 0xf8);
-	aimbs_putle8(&fr->data, 0x02);
-	aimbs_putle8(&fr->data, 0x01);
-	aimbs_putle8(&fr->data, 0x00);
-	aimbs_putle8(&fr->data, !auth_required);
+	byte_stream_putle16(&frame->data, bslen - 2);
+	byte_stream_putle32(&frame->data, atoi(od->sn));
+	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&frame->data, snacid); /* eh. */
+	byte_stream_putle16(&frame->data, 0x0c3a); /* shrug. */
+	byte_stream_putle16(&frame->data, 0x030c);
+	byte_stream_putle16(&frame->data, 0x0001);
+	byte_stream_putle8(&frame->data, webaware);
+	byte_stream_putle8(&frame->data, 0xf8);
+	byte_stream_putle8(&frame->data, 0x02);
+	byte_stream_putle8(&frame->data, 0x01);
+	byte_stream_putle8(&frame->data, 0x00);
+	byte_stream_putle8(&frame->data, !auth_required);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -134,22 +131,22 @@
 /**
  * Change your ICQ password.
  *
- * @param sess The oscar session
+ * @param od The oscar session
  * @param passwd The new password.  If this is longer than 8 characters it
  *        will be truncated.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_icq_changepasswd(OscarSession *sess, const char *passwd)
+int aim_icq_changepasswd(OscarData *od, const char *passwd)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int bslen, passwdlen;
 
 	if (!passwd)
 		return -EINVAL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0015)))
 		return -EINVAL;
 
 	passwdlen = strlen(passwd);
@@ -157,34 +154,33 @@
 		passwdlen = MAXICQPASSLEN;
 	bslen = 2+4+2+2+2+2+passwdlen+1;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
 
-	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put16(&fr->data, bslen);
+	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&frame->data, bslen);
 
-	aimbs_putle16(&fr->data, bslen - 2);
-	aimbs_putle32(&fr->data, atoi(sess->sn));
-	aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
-	aimbs_putle16(&fr->data, snacid); /* eh. */
-	aimbs_putle16(&fr->data, 0x042e); /* shrug. */
-	aimbs_putle16(&fr->data, passwdlen+1);
-	aimbs_putstr(&fr->data, passwd);
-	aimbs_putle8(&fr->data, '\0');
+	byte_stream_putle16(&frame->data, bslen - 2);
+	byte_stream_putle32(&frame->data, atoi(od->sn));
+	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&frame->data, snacid); /* eh. */
+	byte_stream_putle16(&frame->data, 0x042e); /* shrug. */
+	byte_stream_putle16(&frame->data, passwdlen+1);
+	byte_stream_putstr(&frame->data, passwd);
+	byte_stream_putle8(&frame->data, '\0');
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
-faim_export int aim_icq_getallinfo(OscarSession *sess, const char *uin)
+int aim_icq_getallinfo(OscarData *od, const char *uin)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int bslen;
 	struct aim_icq_info *info;
@@ -192,44 +188,43 @@
 	if (!uin || uin[0] < '0' || uin[0] > '9')
 		return -EINVAL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0015)))
 		return -EINVAL;
 
 	bslen = 2 + 4 + 2 + 2 + 2 + 4;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
 
-	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put16(&fr->data, bslen);
+	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&frame->data, bslen);
 
-	aimbs_putle16(&fr->data, bslen - 2);
-	aimbs_putle32(&fr->data, atoi(sess->sn));
-	aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
-	aimbs_putle16(&fr->data, snacid); /* eh. */
-	aimbs_putle16(&fr->data, 0x04b2); /* shrug. */
-	aimbs_putle32(&fr->data, atoi(uin));
+	byte_stream_putle16(&frame->data, bslen - 2);
+	byte_stream_putle32(&frame->data, atoi(od->sn));
+	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&frame->data, snacid); /* eh. */
+	byte_stream_putle16(&frame->data, 0x04b2); /* shrug. */
+	byte_stream_putle32(&frame->data, atoi(uin));
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	/* Keep track of this request and the ICQ number and request ID */
 	info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info));
 	info->reqid = snacid;
 	info->uin = atoi(uin);
-	info->next = sess->icq_info;
-	sess->icq_info = info;
+	info->next = od->icq_info;
+	od->icq_info = info;
 
 	return 0;
 }
 
-faim_export int aim_icq_getalias(OscarSession *sess, const char *uin)
+int aim_icq_getalias(OscarData *od, const char *uin)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int bslen;
 	struct aim_icq_info *info;
@@ -237,112 +232,109 @@
 	if (!uin || uin[0] < '0' || uin[0] > '9')
 		return -EINVAL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0015)))
 		return -EINVAL;
 
 	bslen = 2 + 4 + 2 + 2 + 2 + 4;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
 
-	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put16(&fr->data, bslen);
+	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&frame->data, bslen);
 
-	aimbs_putle16(&fr->data, bslen - 2);
-	aimbs_putle32(&fr->data, atoi(sess->sn));
-	aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
-	aimbs_putle16(&fr->data, snacid); /* eh. */
-	aimbs_putle16(&fr->data, 0x04ba); /* shrug. */
-	aimbs_putle32(&fr->data, atoi(uin));
+	byte_stream_putle16(&frame->data, bslen - 2);
+	byte_stream_putle32(&frame->data, atoi(od->sn));
+	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&frame->data, snacid); /* eh. */
+	byte_stream_putle16(&frame->data, 0x04ba); /* shrug. */
+	byte_stream_putle32(&frame->data, atoi(uin));
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	/* Keep track of this request and the ICQ number and request ID */
 	info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info));
 	info->reqid = snacid;
 	info->uin = atoi(uin);
-	info->next = sess->icq_info;
-	sess->icq_info = info;
+	info->next = od->icq_info;
+	od->icq_info = info;
 
 	return 0;
 }
 
-faim_export int aim_icq_getsimpleinfo(OscarSession *sess, const char *uin)
+int aim_icq_getsimpleinfo(OscarData *od, const char *uin)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int bslen;
 
 	if (!uin || uin[0] < '0' || uin[0] > '9')
 		return -EINVAL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0015)))
 		return -EINVAL;
 
 	bslen = 2 + 4 + 2 + 2 + 2 + 4;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
 
-	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put16(&fr->data, bslen);
+	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&frame->data, bslen);
 
-	aimbs_putle16(&fr->data, bslen - 2);
-	aimbs_putle32(&fr->data, atoi(sess->sn));
-	aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
-	aimbs_putle16(&fr->data, snacid); /* eh. */
-	aimbs_putle16(&fr->data, 0x051f); /* shrug. */
-	aimbs_putle32(&fr->data, atoi(uin));
+	byte_stream_putle16(&frame->data, bslen - 2);
+	byte_stream_putle32(&frame->data, atoi(od->sn));
+	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&frame->data, snacid); /* eh. */
+	byte_stream_putle16(&frame->data, 0x051f); /* shrug. */
+	byte_stream_putle32(&frame->data, atoi(uin));
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
 #if 0
-faim_export int aim_icq_sendxmlreq(OscarSession *sess, const char *xml)
+int aim_icq_sendxmlreq(OscarData *od, const char *xml)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int bslen;
 
 	if (!xml || !strlen(xml))
 		return -EINVAL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0015)))
 		return -EINVAL;
 
 	bslen = 2 + 10 + 2 + strlen(xml) + 1;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
 
-	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put16(&fr->data, bslen);
+	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&frame->data, bslen);
 
-	aimbs_putle16(&fr->data, bslen - 2);
-	aimbs_putle32(&fr->data, atoi(sess->sn));
-	aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
-	aimbs_putle16(&fr->data, snacid); /* eh. */
-	aimbs_putle16(&fr->data, 0x0998); /* shrug. */
-	aimbs_putle16(&fr->data, strlen(xml) + 1);
-	aimbs_putraw(&fr->data, (guint8 *)xml, strlen(xml) + 1);
+	byte_stream_putle16(&frame->data, bslen - 2);
+	byte_stream_putle32(&frame->data, atoi(od->sn));
+	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&frame->data, snacid); /* eh. */
+	byte_stream_putle16(&frame->data, 0x0998); /* shrug. */
+	byte_stream_putle16(&frame->data, strlen(xml) + 1);
+	byte_stream_putraw(&frame->data, (guint8 *)xml, strlen(xml) + 1);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -367,10 +359,10 @@
  * Yeah hi Peter, whaaaat's happening.  If there's any way to use
  * a codepage other than 1252 that would be great.  Thaaaanks.
  */
-faim_export int aim_icq_sendsms(OscarSession *sess, const char *name, const char *msg, const char *alias)
+int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int bslen, xmllen;
 	char *xml;
@@ -378,7 +370,7 @@
 	time_t t;
 	struct tm *tm;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0015)))
 		return -EINVAL;
 
 	if (!name || !msg || !alias)
@@ -389,10 +381,9 @@
 	timestr = gaim_utf8_strftime("%a, %d %b %Y %T %Z", tm);
 
 	/* The length of xml included the null terminating character */
-	xmllen = 225 + strlen(name) + strlen(msg) + strlen(sess->sn) + strlen(alias) + strlen(timestr) + 1;
+	xmllen = 225 + strlen(name) + strlen(msg) + strlen(od->sn) + strlen(alias) + strlen(timestr) + 1;
 
-	if (!(xml = (char *)malloc(xmllen*sizeof(char))))
-		return -ENOMEM;
+	xml = g_new(char, xmllen);
 	snprintf(xml, xmllen, "<icq_sms_message>\n"
 		"\t<destination>%s</destination>\n"
 		"\t<text>%s</text>\n"
@@ -402,41 +393,38 @@
 		"\t<delivery_receipt>Yes</delivery_receipt>\n"
 		"\t<time>%s</time>\n"
 		"</icq_sms_message>\n",
-		name, msg, sess->sn, alias, timestr);
+		name, msg, od->sn, alias, timestr);
 
 	bslen = 37 + xmllen;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) {
-		free(xml);
-		return -ENOMEM;
-	}
+	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
 
-	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put16(&fr->data, bslen);
+	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&frame->data, bslen);
 
-	aimbs_putle16(&fr->data, bslen - 2);
-	aimbs_putle32(&fr->data, atoi(sess->sn));
-	aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
-	aimbs_putle16(&fr->data, snacid); /* eh. */
+	byte_stream_putle16(&frame->data, bslen - 2);
+	byte_stream_putle32(&frame->data, atoi(od->sn));
+	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&frame->data, snacid); /* eh. */
 
 	/* From libicq200-0.3.2/src/SNAC-SRV.cpp */
-	aimbs_putle16(&fr->data, 0x8214);
-	aimbs_put16(&fr->data, 0x0001);
-	aimbs_put16(&fr->data, 0x0016);
-	aimbs_put32(&fr->data, 0x00000000);
-	aimbs_put32(&fr->data, 0x00000000);
-	aimbs_put32(&fr->data, 0x00000000);
-	aimbs_put32(&fr->data, 0x00000000);
+	byte_stream_putle16(&frame->data, 0x8214);
+	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&frame->data, 0x0016);
+	byte_stream_put32(&frame->data, 0x00000000);
+	byte_stream_put32(&frame->data, 0x00000000);
+	byte_stream_put32(&frame->data, 0x00000000);
+	byte_stream_put32(&frame->data, 0x00000000);
 
-	aimbs_put16(&fr->data, 0x0000);
-	aimbs_put16(&fr->data, xmllen);
-	aimbs_putstr(&fr->data, xml);
+	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&frame->data, xmllen);
+	byte_stream_putstr(&frame->data, xml);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	free(xml);
 
@@ -482,7 +470,8 @@
 /**
  * Subtype 0x0003 - Response to 0x0015/0x002, contains an ICQesque packet.
  */
-static int icqresponse(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_tlvlist_t *tl;
@@ -497,12 +486,12 @@
 		return 0;
 	}
 
-	aim_bstream_init(&qbs, datatlv->value, datatlv->length);
+	byte_stream_init(&qbs, datatlv->value, datatlv->length);
 
-	cmdlen = aimbs_getle16(&qbs);
-	ouruin = aimbs_getle32(&qbs);
-	cmd = aimbs_getle16(&qbs);
-	reqid = aimbs_getle16(&qbs);
+	cmdlen = byte_stream_getle16(&qbs);
+	ouruin = byte_stream_getle32(&qbs);
+	cmd = byte_stream_getle16(&qbs);
+	reqid = byte_stream_getle16(&qbs);
 
 	gaim_debug_misc("oscar", "icq response: %d bytes, %ld, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid);
 
@@ -512,43 +501,43 @@
 
 		memset(&msg, 0, sizeof(msg));
 
-		msg.sender = aimbs_getle32(&qbs);
-		msg.year = aimbs_getle16(&qbs);
-		msg.month = aimbs_getle8(&qbs);
-		msg.day = aimbs_getle8(&qbs);
-		msg.hour = aimbs_getle8(&qbs);
-		msg.minute = aimbs_getle8(&qbs);
-		msg.type = aimbs_getle8(&qbs);
-		msg.flags = aimbs_getle8(&qbs);
-		msg.msglen = aimbs_getle16(&qbs);
-		msg.msg = aimbs_getstr(&qbs, msg.msglen);
+		msg.sender = byte_stream_getle32(&qbs);
+		msg.year = byte_stream_getle16(&qbs);
+		msg.month = byte_stream_getle8(&qbs);
+		msg.day = byte_stream_getle8(&qbs);
+		msg.hour = byte_stream_getle8(&qbs);
+		msg.minute = byte_stream_getle8(&qbs);
+		msg.type = byte_stream_getle8(&qbs);
+		msg.flags = byte_stream_getle8(&qbs);
+		msg.msglen = byte_stream_getle16(&qbs);
+		msg.msg = byte_stream_getstr(&qbs, msg.msglen);
 
-		if ((userfunc = aim_callhandler(sess, rx->conn, OSCAR_FAMILY_ICQ, OSCAR_SUBTYPE_ICQ_OFFLINEMSG)))
-			ret = userfunc(sess, rx, &msg);
+		if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSG)))
+			ret = userfunc(od, conn, frame, &msg);
 
 		free(msg.msg);
 
 	} else if (cmd == 0x0042) {
 		aim_rxcallback_t userfunc;
 
-		if ((userfunc = aim_callhandler(sess, rx->conn, OSCAR_FAMILY_ICQ, OSCAR_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE)))
-			ret = userfunc(sess, rx);
+		if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE)))
+			ret = userfunc(od, conn, frame);
 
 	} else if (cmd == 0x07da) { /* information */
 		guint16 subtype;
 		struct aim_icq_info *info;
 		aim_rxcallback_t userfunc;
 
-		subtype = aimbs_getle16(&qbs);
-		aim_bstream_advance(&qbs, 1); /* 0x0a */
+		subtype = byte_stream_getle16(&qbs);
+		byte_stream_advance(&qbs, 1); /* 0x0a */
 
 		/* find other data from the same request */
-		for (info = sess->icq_info; info && (info->reqid != reqid); info = info->next);
+		for (info = od->icq_info; info && (info->reqid != reqid); info = info->next);
 		if (!info) {
 			info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info));
 			info->reqid = reqid;
-			info->next = sess->icq_info;
-			sess->icq_info = info;
+			info->next = od->icq_info;
+			od->icq_info = info;
 		}
 
 		switch (subtype) {
@@ -561,64 +550,64 @@
 		} break;
 
 		case 0x00c8: { /* general and "home" information */
-			info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->homecity = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->homestate = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->homephone = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->homefax = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->homeaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->mobile = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->homezip = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->homecountry = aimbs_getle16(&qbs);
+			info->nick = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->first = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->last = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->email = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->homecity = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->homestate = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->homephone = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->homefax = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->homeaddr = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->mobile = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->homezip = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->homecountry = byte_stream_getle16(&qbs);
 			/* 0x0a 00 02 00 */
 			/* 1 byte timezone? */
 			/* 1 byte hide email flag? */
 		} break;
 
 		case 0x00dc: { /* personal information */
-			info->age = aimbs_getle8(&qbs);
-			info->unknown = aimbs_getle8(&qbs);
-			info->gender = aimbs_getle8(&qbs); /* Not specified=0x00, Female=0x01, Male=0x02 */
-			info->personalwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->birthyear = aimbs_getle16(&qbs);
-			info->birthmonth = aimbs_getle8(&qbs);
-			info->birthday = aimbs_getle8(&qbs);
-			info->language1 = aimbs_getle8(&qbs);
-			info->language2 = aimbs_getle8(&qbs);
-			info->language3 = aimbs_getle8(&qbs);
+			info->age = byte_stream_getle8(&qbs);
+			info->unknown = byte_stream_getle8(&qbs);
+			info->gender = byte_stream_getle8(&qbs); /* Not specified=0x00, Female=0x01, Male=0x02 */
+			info->personalwebpage = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->birthyear = byte_stream_getle16(&qbs);
+			info->birthmonth = byte_stream_getle8(&qbs);
+			info->birthday = byte_stream_getle8(&qbs);
+			info->language1 = byte_stream_getle8(&qbs);
+			info->language2 = byte_stream_getle8(&qbs);
+			info->language3 = byte_stream_getle8(&qbs);
 			/* 0x00 00 01 00 00 01 00 00 00 00 00 */
 		} break;
 
 		case 0x00d2: { /* work information */
-			info->workcity = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->workstate = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->workphone = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->workfax = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->workaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->workzip = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->workcountry = aimbs_getle16(&qbs);
-			info->workcompany = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->workdivision = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->workposition = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			aim_bstream_advance(&qbs, 2); /* 0x01 00 */
-			info->workwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
+			info->workcity = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->workstate = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->workphone = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->workfax = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->workaddr = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->workzip = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->workcountry = byte_stream_getle16(&qbs);
+			info->workcompany = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->workdivision = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->workposition = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			byte_stream_advance(&qbs, 2); /* 0x01 00 */
+			info->workwebpage = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
 		} break;
 
 		case 0x00e6: { /* additional personal information */
-			info->info = aimbs_getstr(&qbs, aimbs_getle16(&qbs)-1);
+			info->info = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs)-1);
 		} break;
 
 		case 0x00eb: { /* email address(es) */
 			int i;
-			info->numaddresses = aimbs_getle16(&qbs);
+			info->numaddresses = byte_stream_getle16(&qbs);
 			info->email2 = (char **)calloc(info->numaddresses, sizeof(char *));
 			for (i = 0; i < info->numaddresses; i++) {
-				info->email2[i] = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
+				info->email2[i] = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
 				if (i+1 != info->numaddresses)
-					aim_bstream_advance(&qbs, 1); /* 0x00 */
+					byte_stream_advance(&qbs, 1); /* 0x00 */
 			}
 		} break;
 
@@ -629,10 +618,10 @@
 		} break;
 
 		case 0x0104: { /* alias info */
-			info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			aim_bstream_advance(&qbs, aimbs_getle16(&qbs)); /* email address? */
+			info->nick = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->first = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->last = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			byte_stream_advance(&qbs, byte_stream_getle16(&qbs)); /* email address? */
 			/* Then 0x00 02 00 */
 		} break;
 
@@ -641,30 +630,30 @@
 		} break;
 
 		case 0x019a: { /* simple info */
-			aim_bstream_advance(&qbs, 2);
-			info->uin = aimbs_getle32(&qbs);
-			info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
+			byte_stream_advance(&qbs, 2);
+			info->uin = byte_stream_getle32(&qbs);
+			info->nick = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->first = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->last = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
+			info->email = byte_stream_getstr(&qbs, byte_stream_getle16(&qbs));
 			/* Then 0x00 02 00 00 00 00 00 */
 		} break;
 		} /* End switch statement */
 
 		if (!(snac->flags & 0x0001)) {
 			if (subtype != 0x0104)
-				if ((userfunc = aim_callhandler(sess, rx->conn, OSCAR_FAMILY_ICQ, OSCAR_SUBTYPE_ICQ_INFO)))
-					ret = userfunc(sess, rx, info);
+				if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_INFO)))
+					ret = userfunc(od, conn, frame, info);
 
 			if (info->uin && info->nick)
-				if ((userfunc = aim_callhandler(sess, rx->conn, OSCAR_FAMILY_ICQ, OSCAR_SUBTYPE_ICQ_ALIAS)))
-					ret = userfunc(sess, rx, info);
+				if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_ALIAS)))
+					ret = userfunc(od, conn, frame, info);
 
-			if (sess->icq_info == info) {
-				sess->icq_info = info->next;
+			if (od->icq_info == info) {
+				od->icq_info = info->next;
 			} else {
 				struct aim_icq_info *cur;
-				for (cur=sess->icq_info; (cur->next && (cur->next!=info)); cur=cur->next);
+				for (cur=od->icq_info; (cur->next && (cur->next!=info)); cur=cur->next);
 				if (cur->next)
 					cur->next = cur->next->next;
 			}
@@ -677,31 +666,32 @@
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0003)
-		return icqresponse(sess, mod, rx, snac, bs);
+		return icqresponse(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-static void icq_shutdown(OscarSession *sess, aim_module_t *mod)
+static void
+icq_shutdown(OscarData *od, aim_module_t *mod)
 {
 	struct aim_icq_info *del;
 
-	while (sess->icq_info) {
-		del = sess->icq_info;
-		sess->icq_info = sess->icq_info->next;
+	while (od->icq_info) {
+		del = od->icq_info;
+		od->icq_info = od->icq_info->next;
 		aim_icq_freeinfo(del);
 	}
 
 	return;
 }
 
-faim_internal int icq_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+icq_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x0015;
 	mod->version = 0x0001;
 	mod->toolid = 0x0110;
--- a/src/protocols/oscar/family_invite.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_invite.c	Fri Apr 07 05:10:56 2006 +0000
@@ -38,7 +38,7 @@
 
 #include "oscar.h"
 
-faim_internal int invite_modfirst(OscarSession *sess, aim_module_t *mod)
+int invite_modfirst(OscarData *od, aim_module_t *mod)
 {
 
 	mod->family = 0x0006;
--- a/src/protocols/oscar/family_locate.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_locate.c	Fri Apr 07 05:10:56 2006 +0000
@@ -51,37 +51,37 @@
 	 */
 
 	/*
-	 * Perhaps better called AIM_CAPS_SHORTCAPS
+	 * Perhaps better called OSCAR_CAPABILITY_SHORTCAPS
 	 */
-	{AIM_CAPS_ICHAT,
+	{OSCAR_CAPABILITY_ICHAT,
 	 {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_SECUREIM,
+	{OSCAR_CAPABILITY_SECUREIM,
 	 {0x09, 0x46, 0x00, 0x01, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_VIDEO,
+	{OSCAR_CAPABILITY_VIDEO,
 	 {0x09, 0x46, 0x01, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
 	/* "Live Video" support in Windows AIM 5.5.3501 and newer */
-	{AIM_CAPS_LIVEVIDEO,
+	{OSCAR_CAPABILITY_LIVEVIDEO,
 	 {0x09, 0x46, 0x01, 0x01, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
 	/* "Camera" support in Windows AIM 5.5.3501 and newer */
-	{AIM_CAPS_CAMERA,
+	{OSCAR_CAPABILITY_CAMERA,
 	 {0x09, 0x46, 0x01, 0x02, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
 	/* In Windows AIM 5.5.3501 and newer */
-	{AIM_CAPS_GENERICUNKNOWN,
+	{OSCAR_CAPABILITY_GENERICUNKNOWN,
 	 {0x09, 0x46, 0x01, 0x03, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
 	/* In iChatAV (version numbers...?) */
-	{AIM_CAPS_ICHATAV,
+	{OSCAR_CAPABILITY_ICHATAV,
 	 {0x09, 0x46, 0x01, 0x05, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x45, 0x53, 0x54, 0x00}},
 
@@ -90,55 +90,55 @@
 	 * 26 Sep 2003, Matthew Sachs suggested that, "this
 	 * is probably the capability for the SMS features."
 	 */
-	{AIM_CAPS_SMS,
+	{OSCAR_CAPABILITY_SMS,
 	 {0x09, 0x46, 0x01, 0xff, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_GENERICUNKNOWN,
+	{OSCAR_CAPABILITY_GENERICUNKNOWN,
 	 {0x09, 0x46, 0xf0, 0x03, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_GENERICUNKNOWN,
+	{OSCAR_CAPABILITY_GENERICUNKNOWN,
 	 {0x09, 0x46, 0xf0, 0x04, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_GENERICUNKNOWN,
+	{OSCAR_CAPABILITY_GENERICUNKNOWN,
 	 {0x09, 0x46, 0xf0, 0x05, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_HIPTOP,
+	{OSCAR_CAPABILITY_HIPTOP,
 	 {0x09, 0x46, 0x13, 0x23, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_TALK,
+	{OSCAR_CAPABILITY_TALK,
 	 {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_SENDFILE,
+	{OSCAR_CAPABILITY_SENDFILE,
 	 {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_ICQ_DIRECT,
+	{OSCAR_CAPABILITY_ICQ_DIRECT,
 	 {0x09, 0x46, 0x13, 0x44, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_DIRECTIM,
+	{OSCAR_CAPABILITY_DIRECTIM,
 	 {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_BUDDYICON,
+	{OSCAR_CAPABILITY_BUDDYICON,
 	 {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_ADDINS,
+	{OSCAR_CAPABILITY_ADDINS,
 	 {0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_GETFILE,
+	{OSCAR_CAPABILITY_GETFILE,
 	 {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_ICQSERVERRELAY,
+	{OSCAR_CAPABILITY_ICQSERVERRELAY,
 	 {0x09, 0x46, 0x13, 0x49, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
@@ -148,14 +148,14 @@
 	 * forgot to fix endianness, or they made a typo. It really doesn't
 	 * matter which.
 	 */
-	{AIM_CAPS_GAMES,
+	{OSCAR_CAPABILITY_GAMES,
 	 {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
-	{AIM_CAPS_GAMES2,
+	{OSCAR_CAPABILITY_GAMES2,
 	 {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_SENDBUDDYLIST,
+	{OSCAR_CAPABILITY_SENDBUDDYLIST,
 	 {0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
@@ -168,53 +168,53 @@
 	 * see them as online (previous you could still see them, but they
 	 * couldn't see you.
 	 */
-	{AIM_CAPS_INTEROPERATE,
+	{OSCAR_CAPABILITY_INTEROPERATE,
 	 {0x09, 0x46, 0x13, 0x4d, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_ICQUTF8,
+	{OSCAR_CAPABILITY_ICQUTF8,
 	 {0x09, 0x46, 0x13, 0x4e, 0x4c, 0x7f, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
-	{AIM_CAPS_ICQUTF8OLD,
+	{OSCAR_CAPABILITY_ICQUTF8OLD,
 	 {0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8,
 	  0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf}},
 
 	/*
 	 * Chat is oddball.
 	 */
-	{AIM_CAPS_CHAT,
+	{OSCAR_CAPABILITY_CHAT,
 	 {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1,
 	  0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
 
 	/*
-	{AIM_CAPS_ICQ2GO,
+	{OSCAR_CAPABILITY_ICQ2GO,
 	 {0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 0xbd,
 	  0x9f, 0x79, 0x42, 0x26, 0x09, 0xdf, 0xa2, 0xf3}},
 	*/
 
-	{AIM_CAPS_ICQRTF,
+	{OSCAR_CAPABILITY_ICQRTF,
 	 {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34,
 	  0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92}},
 
 	/* This is added by the servers and it only shows up for ourselves... */
-	{AIM_CAPS_GENERICUNKNOWN,
+	{OSCAR_CAPABILITY_GENERICUNKNOWN,
 	 {0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34,
 	  0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09}},
 
-	{AIM_CAPS_APINFO,
+	{OSCAR_CAPABILITY_APINFO,
 	 {0xaa, 0x4a, 0x32, 0xb5, 0xf8, 0x84, 0x48, 0xc6,
 	  0xa3, 0xd7, 0x8c, 0x50, 0x97, 0x19, 0xfd, 0x5b}},
 
-	{AIM_CAPS_TRILLIANCRYPT,
+	{OSCAR_CAPABILITY_TRILLIANCRYPT,
 	 {0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb,
 	  0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00}},
 
-	{AIM_CAPS_EMPTY,
+	{OSCAR_CAPABILITY_EMPTY,
 	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
 
-	{AIM_CAPS_LAST,
+	{OSCAR_CAPABILITY_LAST,
 	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
 };
@@ -225,18 +225,18 @@
  *
  * @param userinfo Contains the new information for the buddy.
  */
-static void aim_locate_adduserinfo(OscarSession *sess, aim_userinfo_t *userinfo) {
+static void aim_locate_adduserinfo(OscarData *od, aim_userinfo_t *userinfo) {
 	aim_userinfo_t *cur;
-	OscarConnection *conn;
+	FlapConnection *conn;
 	aim_rxcallback_t userfunc;
 
-	cur = aim_locate_finduserinfo(sess, userinfo->sn);
+	cur = aim_locate_finduserinfo(od, userinfo->sn);
 
 	if (cur == NULL) {
 		cur = (aim_userinfo_t *)calloc(1, sizeof(aim_userinfo_t));
 		cur->sn = strdup(userinfo->sn);
-		cur->next = sess->locate.userinfo;
-		sess->locate.userinfo = cur;
+		cur->next = od->locate.userinfo;
+		od->locate.userinfo = cur;
 	}
 
 	cur->warnlevel = userinfo->warnlevel;
@@ -307,51 +307,65 @@
 	 * messages in its buddy list, then it would need to know if a user's
 	 * away message changes.
 	 */
-	conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_LOCATE);
-	if ((userfunc = aim_callhandler(sess, conn, OSCAR_FAMILY_LOCATE, OSCAR_SUBTYPE_LOCATE_GOTINFOBLOCK)))
-		userfunc(sess, NULL, cur);
+	conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE);
+	if ((userfunc = aim_callhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_GOTINFOBLOCK)))
+		userfunc(od, conn, NULL, cur);
 }
 
-faim_export void aim_locate_dorequest(OscarSession *sess) {
-	struct userinfo_node *cur = sess->locate.torequest;
+void aim_locate_dorequest(OscarData *od) {
+	struct userinfo_node *cur = od->locate.torequest;
 
 	if (cur == NULL)
 		return;
 
-	if (sess->locate.waiting_for_response == TRUE)
+	if (od->locate.waiting_for_response == TRUE)
 		return;
 
-	sess->locate.waiting_for_response = TRUE;
-	aim_locate_getinfoshort(sess, cur->sn, 0x00000003);
+	od->locate.waiting_for_response = TRUE;
+	aim_locate_getinfoshort(od, cur->sn, 0x00000003);
 
 	/* Move this node to the "requested" queue */
-	sess->locate.torequest = cur->next;
-	cur->next = sess->locate.requested;
-	sess->locate.requested = cur;
+	od->locate.torequest = cur->next;
+	cur->next = od->locate.requested;
+	od->locate.requested = cur;
+}
+
+static gboolean
+gaim_reqinfo_timeout_cb(void *data)
+{
+	OscarData *od;
+
+	od = data;
+	aim_locate_dorequest(od);
+	od->getinfotimer = 0;
+
+	return FALSE;
 }
 
 /**
  * Remove this screen name from our queue.  If this info was requested
  * by our info request queue, then pop the next element off of the queue.
  *
- * @param sess The aim session.
+ * @param od The aim session.
  * @param sn Screen name of the info we just received.
  * @return True if the request was explicit (client requested the info),
  *         false if the request was implicit (libfaim request the info).
  */
-static int aim_locate_gotuserinfo(OscarSession *sess, const char *sn) {
+static int
+aim_locate_gotuserinfo(OscarData *od, FlapConnection *conn, const char *sn)
+{
 	struct userinfo_node *cur, *del;
 	int was_explicit = TRUE;
 
-	while ((sess->locate.requested != NULL) && (aim_sncmp(sn, sess->locate.requested->sn) == 0)) {
-		del = sess->locate.requested;
-		sess->locate.requested = del->next;
+	while ((od->locate.requested != NULL) && (aim_sncmp(sn, od->locate.requested->sn) == 0)) {
+		del = od->locate.requested;
+		od->locate.requested = del->next;
 		was_explicit = FALSE;
 		free(del->sn);
 		free(del);
 	}
 
-	cur = sess->locate.requested;
+	cur = od->locate.requested;
 	while ((cur != NULL) && (cur->next != NULL)) {
 		if (aim_sncmp(sn, cur->next->sn) == 0) {
 			del = cur->next;
@@ -364,25 +378,26 @@
 	}
 
 	if (!was_explicit) {
-		OscarConnection *conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_LOCATE);
-		aim_rxcallback_t userfunc;
-
-		sess->locate.waiting_for_response = FALSE;
+		od->locate.waiting_for_response = FALSE;
 
-		if ((userfunc = aim_callhandler(sess, conn, OSCAR_FAMILY_LOCATE, OSCAR_SUBTYPE_LOCATE_REQUESTINFOTIMEOUT)))
-			userfunc(sess, NULL);
-		else
-			aim_locate_dorequest(sess);
+		/*
+		 * Wait a little while then call aim_locate_dorequest(od).
+		 * This keeps us from hitting the rate limit due to
+		 * requesting away messages and info too quickly.
+		 */
+		if (od->getinfotimer == 0)
+			od->getinfotimer = gaim_timeout_add(10000,
+					gaim_reqinfo_timeout_cb, od);
 	}
 
 	return was_explicit;
 }
 
-faim_internal void aim_locate_requestuserinfo(OscarSession *sess, const char *sn) {
+void aim_locate_requestuserinfo(OscarData *od, const char *sn) {
 	struct userinfo_node *cur;
 
 	/* Make sure we aren't already requesting info for this buddy */
-	cur = sess->locate.torequest;
+	cur = od->locate.torequest;
 	while (cur != NULL) {
 		if (aim_sncmp(sn, cur->sn) == 0)
 			return;
@@ -392,20 +407,20 @@
 	/* Add a new node to our request queue */
 	cur = (struct userinfo_node *)malloc(sizeof(struct userinfo_node));
 	cur->sn = strdup(sn);
-	cur->next = sess->locate.torequest;
-	sess->locate.torequest = cur;
+	cur->next = od->locate.torequest;
+	od->locate.torequest = cur;
 
 	/* Actually request some info up in this piece */
-	aim_locate_dorequest(sess);
+	aim_locate_dorequest(od);
 }
 
-faim_export aim_userinfo_t *aim_locate_finduserinfo(OscarSession *sess, const char *sn) {
+aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *sn) {
 	aim_userinfo_t *cur = NULL;
 
 	if (sn == NULL)
 		return NULL;
 
-	cur = sess->locate.userinfo;
+	cur = od->locate.userinfo;
 
 	while (cur != NULL) {
 		if (aim_sncmp(cur->sn, sn) == 0)
@@ -416,18 +431,18 @@
 	return NULL;
 }
 
-faim_internal guint32 aim_locate_getcaps(OscarSession *sess, ByteStream *bs, int len)
+guint32 aim_locate_getcaps(OscarData *od, ByteStream *bs, int len)
 {
 	guint32 flags = 0;
 	int offset;
 
-	for (offset = 0; aim_bstream_empty(bs) && (offset < len); offset += 0x10) {
+	for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x10) {
 		guint8 *cap;
 		int i, identified;
 
-		cap = aimbs_getraw(bs, 0x10);
+		cap = byte_stream_getraw(bs, 0x10);
 
-		for (i = 0, identified = 0; !(aim_caps[i].flag & AIM_CAPS_LAST); i++) {
+		for (i = 0, identified = 0; !(aim_caps[i].flag & OSCAR_CAPABILITY_LAST); i++) {
 			if (memcmp(&aim_caps[i].data, cap, 0x10) == 0) {
 				flags |= aim_caps[i].flag;
 				identified++;
@@ -450,18 +465,18 @@
 	return flags;
 }
 
-faim_internal guint32 aim_locate_getcaps_short(OscarSession *sess, ByteStream *bs, int len)
+guint32 aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len)
 {
 	guint32 flags = 0;
 	int offset;
 
-	for (offset = 0; aim_bstream_empty(bs) && (offset < len); offset += 0x02) {
+	for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x02) {
 		guint8 *cap;
 		int i, identified;
 
-		cap = aimbs_getraw(bs, 0x02);
+		cap = byte_stream_getraw(bs, 0x02);
 
-		for (i = 0, identified = 0; !(aim_caps[i].flag & AIM_CAPS_LAST); i++) {
+		for (i = 0, identified = 0; !(aim_caps[i].flag & OSCAR_CAPABILITY_LAST); i++) {
 			if (memcmp(&aim_caps[i].data[2], cap, 0x02) == 0) {
 				flags |= aim_caps[i].flag;
 				identified++;
@@ -478,31 +493,33 @@
 	return flags;
 }
 
-faim_internal int aimbs_putcaps(ByteStream *bs, guint32 caps)
+int byte_stream_putcaps(ByteStream *bs, guint32 caps)
 {
 	int i;
 
 	if (!bs)
 		return -EINVAL;
 
-	for (i = 0; aim_bstream_empty(bs); i++) {
+	for (i = 0; byte_stream_empty(bs); i++) {
 
-		if (aim_caps[i].flag == AIM_CAPS_LAST)
+		if (aim_caps[i].flag == OSCAR_CAPABILITY_LAST)
 			break;
 
 		if (caps & aim_caps[i].flag)
-			aimbs_putraw(bs, aim_caps[i].data, 0x10);
+			byte_stream_putraw(bs, aim_caps[i].data, 0x10);
 
 	}
 
 	return 0;
 }
 
-static void dumptlv(OscarSession *sess, guint16 type, ByteStream *bs, guint8 len)
+#if 0
+static void
+dumptlv(OscarData *od, guint16 type, ByteStream *bs, guint8 len)
 {
 	int i;
 
-	if (!sess || !bs || !len)
+	if (!od || !bs || !len)
 		return;
 
 	gaim_debug_misc("oscar", "userinfo:   type  =0x%04x\n", type);
@@ -512,15 +529,16 @@
 	for (i = 0; i < len; i++) {
 		if ((i % 8) == 0)
 			gaim_debug_misc("oscar", "\nuserinfo:        ");
-		gaim_debug_misc("oscar", "0x%2x ", aimbs_get8(bs));
+		gaim_debug_misc("oscar", "0x%2x ", byte_stream_get8(bs));
 	}
 
 	gaim_debug_misc("oscar", "\n");
 
 	return;
 }
+#endif
 
-faim_internal void aim_info_free(aim_userinfo_t *info)
+void aim_info_free(aim_userinfo_t *info)
 {
 	free(info->sn);
 	free(info->iconcsum);
@@ -536,7 +554,7 @@
  * AIM is fairly regular about providing user info.  This is a generic
  * routine to extract it in its standard form.
  */
-faim_internal int aim_info_extract(OscarSession *sess, ByteStream *bs, aim_userinfo_t *outinfo)
+int aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *outinfo)
 {
 	int curtlv, tlvcnt;
 	guint8 snlen;
@@ -551,19 +569,19 @@
 	 * Screen name.  Stored as an unterminated string prepended with a
 	 * byte containing its length.
 	 */
-	snlen = aimbs_get8(bs);
-	outinfo->sn = aimbs_getstr(bs, snlen);
+	snlen = byte_stream_get8(bs);
+	outinfo->sn = byte_stream_getstr(bs, snlen);
 
 	/*
 	 * Warning Level.  Stored as an unsigned short.
 	 */
-	outinfo->warnlevel = aimbs_get16(bs);
+	outinfo->warnlevel = byte_stream_get16(bs);
 
 	/*
 	 * TLV Count. Unsigned short representing the number of
 	 * Type-Length-Value triples that follow.
 	 */
-	tlvcnt = aimbs_get16(bs);
+	tlvcnt = byte_stream_get16(bs);
 
 	/*
 	 * Parse out the Type-Length-Value triples as they're found.
@@ -572,31 +590,31 @@
 		int endpos;
 		guint16 type, length;
 
-		type = aimbs_get16(bs);
-		length = aimbs_get16(bs);
+		type = byte_stream_get16(bs);
+		length = byte_stream_get16(bs);
 
-		endpos = aim_bstream_curpos(bs) + length;
+		endpos = byte_stream_curpos(bs) + length;
 
 		if (type == 0x0001) {
 			/*
 			 * Type = 0x0001: User flags
-			 * 
+			 *
 			 * Specified as any of the following ORed together:
 			 *      0x0001  Trial (user less than 60days)
 			 *      0x0002  Unknown bit 2
 			 *      0x0004  AOL Main Service user
 			 *      0x0008  Unknown bit 4
-			 *      0x0010  Free (AIM) user 
+			 *      0x0010  Free (AIM) user
 			 *      0x0020  Away
 			 *      0x0400  ActiveBuddy
 			 *
 			 */
-			outinfo->flags = aimbs_get16(bs);
+			outinfo->flags = byte_stream_get16(bs);
 			outinfo->present |= AIM_USERINFO_PRESENT_FLAGS;
 
 		} else if (type == 0x0002) {
 			/*
-			 * Type = 0x0002: Account creation time. 
+			 * Type = 0x0002: Account creation time.
 			 *
 			 * The time/date that the user originally registered for
 			 * the service, stored in time_t format.
@@ -608,36 +626,36 @@
 			 * since".  All these years and I finally found out
 			 * that I got the name wrong.
 			 */
-			outinfo->createtime = aimbs_get32(bs);
+			outinfo->createtime = byte_stream_get32(bs);
 			outinfo->present |= AIM_USERINFO_PRESENT_CREATETIME;
 
 		} else if (type == 0x0003) {
 			/*
 			 * Type = 0x0003: On-Since date.
 			 *
-			 * The time/date that the user started their current 
+			 * The time/date that the user started their current
 			 * session, stored in time_t format.
 			 */
-			outinfo->onlinesince = aimbs_get32(bs);
+			outinfo->onlinesince = byte_stream_get32(bs);
 			outinfo->present |= AIM_USERINFO_PRESENT_ONLINESINCE;
 
 		} else if (type == 0x0004) {
 			/*
 			 * Type = 0x0004: Idle time.
 			 *
-			 * Number of minutes since the user actively used the 
+			 * Number of minutes since the user actively used the
 			 * service.
 			 *
 			 * Note that the client tells the server when to start
-			 * counting idle times, so this may or may not be 
+			 * counting idle times, so this may or may not be
 			 * related to reality.
 			 */
-			outinfo->idletime = aimbs_get16(bs);
+			outinfo->idletime = byte_stream_get16(bs);
 			outinfo->present |= AIM_USERINFO_PRESENT_IDLE;
 
 		} else if (type == 0x0005) {
 			/*
-			 * Type = 0x0005: Member since date. 
+			 * Type = 0x0005: Member since date.
 			 *
 			 * The time/date that the user originally registered for
 			 * the service, stored in time_t format.
@@ -646,18 +664,18 @@
 			 * creation time"), particularly in the self-info.
 			 * And particularly for ICQ?
 			 */
-			outinfo->membersince = aimbs_get32(bs);
+			outinfo->membersince = byte_stream_get32(bs);
 			outinfo->present |= AIM_USERINFO_PRESENT_MEMBERSINCE;
 
 		} else if (type == 0x0006) {
 			/*
 			 * Type = 0x0006: ICQ Online Status
 			 *
-			 * ICQ's Away/DND/etc "enriched" status. Some decoding 
+			 * ICQ's Away/DND/etc "enriched" status. Some decoding
 			 * of values done by Scott <darkagl@pcnet.com>
 			 */
-			aimbs_get16(bs);
-			outinfo->icqinfo.status = aimbs_get16(bs);
+			byte_stream_get16(bs);
+			outinfo->icqinfo.status = byte_stream_get16(bs);
 			outinfo->present |= AIM_USERINFO_PRESENT_ICQEXTSTATUS;
 
 		} else if (type == 0x0008) {
@@ -674,11 +692,11 @@
 			 * ICQ User IP Address.
 			 * Ahh, the joy of ICQ security.
 			 */
-			outinfo->icqinfo.ipaddr = aimbs_get32(bs);
+			outinfo->icqinfo.ipaddr = byte_stream_get32(bs);
 			outinfo->present |= AIM_USERINFO_PRESENT_ICQIPADDR;
 
 		} else if (type == 0x000c) {
-			/* 
+			/*
 			 * Type = 0x000c
 			 *
 			 * random crap containing the IP address,
@@ -686,10 +704,10 @@
 			 *
 			 * Format is:
 			 * 4 bytes - Our IP address, 0xc0 a8 01 2b for 192.168.1.43
-			 * 
+			 *
 			 *
 			 */
-			aimbs_getrawbuf(bs, outinfo->icqinfo.crap, 0x25);
+			byte_stream_getrawbuf(bs, outinfo->icqinfo.crap, 0x25);
 			outinfo->present |= AIM_USERINFO_PRESENT_ICQDATA;
 
 		} else if (type == 0x000d) {
@@ -699,7 +717,7 @@
 			 * OSCAR Capability information.
 			 *
 			 */
-			outinfo->capabilities |= aim_locate_getcaps(sess, bs, length);
+			outinfo->capabilities |= aim_locate_getcaps(od, bs, length);
 			outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;
 
 		} else if (type == 0x000e) {
@@ -715,31 +733,31 @@
 			 * Type = 0x000f: Session Length. (AIM)
 			 * Type = 0x0010: Session Length. (AOL)
 			 *
-			 * The duration, in seconds, of the user's current 
+			 * The duration, in seconds, of the user's current
 			 * session.
 			 *
 			 * Which TLV type this comes in depends on the
 			 * service the user is using (AIM or AOL).
 			 *
 			 */
-			outinfo->sessionlen = aimbs_get32(bs);
+			outinfo->sessionlen = byte_stream_get32(bs);
 			outinfo->present |= AIM_USERINFO_PRESENT_SESSIONLEN;
 
 		} else if (type == 0x0019) {
 			/*
 			 * Type = 0x0019
 			 *
-			 * OSCAR short capability information.  A shortened 
+			 * OSCAR short capability information.  A shortened
 			 * form of the normal capabilities.
 			 */
-			outinfo->capabilities |= aim_locate_getcaps_short(sess, bs, length);
+			outinfo->capabilities |= aim_locate_getcaps_short(od, bs, length);
 			outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;
 
 		} else if (type == 0x001b) {
 			/*
 			 * Type = 0x001a
 			 *
-			 * AOL short capability information.  A shortened 
+			 * AOL short capability information.  A shortened
 			 * form of the normal capabilities.
 			 */
 
@@ -770,42 +788,42 @@
 			 */
 			int type2, number, length2;
 
-			while (aim_bstream_curpos(bs) < endpos) {
-				type2 = aimbs_get16(bs);
-				number = aimbs_get8(bs);
-				length2 = aimbs_get8(bs);
+			while (byte_stream_curpos(bs) < endpos) {
+				type2 = byte_stream_get16(bs);
+				number = byte_stream_get8(bs);
+				length2 = byte_stream_get8(bs);
 
 				switch (type2) {
 					case 0x0000: { /* This is an official buddy icon? */
 						/* This is always 5 bytes of "0x02 01 d2 04 72"? */
-						aim_bstream_advance(bs, length2);
+						byte_stream_advance(bs, length2);
 					} break;
 
 					case 0x0001: { /* A buddy icon checksum */
 						if ((length2 > 0) && ((number == 0x00) || (number == 0x01))) {
 							free(outinfo->iconcsum);
 							outinfo->iconcsumtype = number;
-							outinfo->iconcsum = aimbs_getraw(bs, length2);
+							outinfo->iconcsum = byte_stream_getraw(bs, length2);
 							outinfo->iconcsumlen = length2;
 						} else
-							aim_bstream_advance(bs, length2);
+							byte_stream_advance(bs, length2);
 					} break;
 
 					case 0x0002: { /* A status/available message */
 						free(outinfo->status);
 						free(outinfo->status_encoding);
 						if (length2 >= 4) {
-							outinfo->status_len = aimbs_get16(bs);
-							outinfo->status = aimbs_getstr(bs, outinfo->status_len);
-							if (aimbs_get16(bs) == 0x0001) { /* We have an encoding */
-								aimbs_get16(bs);
-								outinfo->status_encoding = aimbs_getstr(bs, aimbs_get16(bs));
+							outinfo->status_len = byte_stream_get16(bs);
+							outinfo->status = byte_stream_getstr(bs, outinfo->status_len);
+							if (byte_stream_get16(bs) == 0x0001) { /* We have an encoding */
+								byte_stream_get16(bs);
+								outinfo->status_encoding = byte_stream_getstr(bs, byte_stream_get16(bs));
 							} else {
 								/* No explicit encoding, client should use UTF-8 */
 								outinfo->status_encoding = NULL;
 							}
 						} else {
-							aim_bstream_advance(bs, length2);
+							byte_stream_advance(bs, length2);
 							outinfo->status_len = 0;
 							outinfo->status = g_strdup("");
 							outinfo->status_encoding = NULL;
@@ -813,7 +831,7 @@
 					} break;
 
 					default: {
-						aim_bstream_advance(bs, length2);
+						byte_stream_advance(bs, length2);
 					} break;
 				}
 			}
@@ -837,23 +855,25 @@
 
 			/*
 			 * Reaching here indicates that either AOL has
-			 * added yet another TLV for us to deal with, 
+			 * added yet another TLV for us to deal with,
 			 * or the parsing has gone Terribly Wrong.
 			 *
 			 * Either way, inform the owner and attempt
 			 * recovery.
 			 *
 			 */
+#if 0
 			gaim_debug_misc("oscar", "userinfo: **warning: unexpected TLV:\n");
 			gaim_debug_misc("oscar", "userinfo:   sn    =%s\n", outinfo->sn);
-			dumptlv(sess, type, bs, length);
+			dumptlv(od, type, bs, length);
+#endif
 		}
 
 		/* Save ourselves. */
-		aim_bstream_setpos(bs, endpos);
+		byte_stream_setpos(bs, endpos);
 	}
 
-	aim_locate_adduserinfo(sess, outinfo);
+	aim_locate_adduserinfo(od, outinfo);
 
 	return 0;
 }
@@ -861,17 +881,18 @@
 /*
  * Inverse of aim_info_extract()
  */
-faim_internal int aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info)
+int
+aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info)
 {
 	aim_tlvlist_t *tlvlist = NULL;
 
 	if (!bs || !info)
 		return -EINVAL;
 
-	aimbs_put8(bs, strlen(info->sn));
-	aimbs_putstr(bs, info->sn);
+	byte_stream_put8(bs, strlen(info->sn));
+	byte_stream_putstr(bs, info->sn);
 
-	aimbs_put16(bs, info->warnlevel);
+	byte_stream_put16(bs, info->warnlevel);
 
 	if (info->present & AIM_USERINFO_PRESENT_FLAGS)
 		aim_tlvlist_add_16(&tlvlist, 0x0001, info->flags);
@@ -898,7 +919,7 @@
 	if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
 		aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen);
 
-	aimbs_put16(bs, aim_tlvlist_count(&tlvlist));
+	byte_stream_put16(bs, aim_tlvlist_count(&tlvlist));
 	aim_tlvlist_write(bs, &tlvlist);
 	aim_tlvlist_free(&tlvlist);
 
@@ -908,7 +929,8 @@
 /*
  * Subtype 0x0001
  */
-static int error(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -917,7 +939,7 @@
 	char *sn;
 	int was_explicit;
 
-	if (!(snac2 = aim_remsnac(sess, snac->id))) {
+	if (!(snac2 = aim_remsnac(od, snac->id))) {
 		gaim_debug_misc("oscar", "faim: locate.c, error(): received response from unknown request!\n");
 		return 0;
 	}
@@ -932,17 +954,17 @@
 		return 0;
 	}
 
-	reason = aimbs_get16(bs);
+	reason = byte_stream_get16(bs);
 
 	/*
-	 * Remove this screen name from our queue.  If the client requested 
-	 * this buddy's info explicitly, then notify them that we do not have 
+	 * Remove this screen name from our queue.  If the client requested
+	 * this buddy's info explicitly, then notify them that we do not have
 	 * info for this buddy.
 	 */
-	was_explicit = aim_locate_gotuserinfo(sess, sn);
+	was_explicit = aim_locate_gotuserinfo(od, conn, sn);
 	if (was_explicit == TRUE)
-		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-			ret = userfunc(sess, rx, reason, sn);
+		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+			ret = userfunc(od, conn, frame, reason, sn);
 
 	if (snac2)
 		free(snac2->data);
@@ -957,14 +979,15 @@
  * Request Location services rights.
  *
  */
-faim_export int aim_locate_reqrights(OscarSession *sess)
+int
+aim_locate_reqrights(OscarData *od)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_LOCATE)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
 		return -EINVAL;
 
-	return aim_genericreq_n_snacid(sess, conn, OSCAR_FAMILY_LOCATE, OSCAR_SUBTYPE_LOCATE_REQRIGHTS);
+	return aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_REQRIGHTS);
 }
 
 /*
@@ -976,7 +999,8 @@
  *   t(0003)  - short - unknown (value = 10)
  *   t(0004)  - short - unknown (value = 2048) [ICQ only?]
  */
-static int rights(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	aim_tlvlist_t *tlvlist;
 	aim_rxcallback_t userfunc;
@@ -988,8 +1012,8 @@
 	if (aim_tlv_gettlv(tlvlist, 0x0001, 1))
 		maxsiglen = aim_tlv_get16(tlvlist, 0x0001, 1);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, maxsiglen);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, maxsiglen);
 
 	aim_tlvlist_free(&tlvlist);
 
@@ -1016,18 +1040,19 @@
  * obvious equivalent).
  *
  */
-faim_export int aim_locate_setprofile(OscarSession *sess,
+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)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 	char *encoding;
 	static const char defencoding[] = {"text/aolrtf; charset=\"%s\""};
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_LOCATE)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
 		return -EINVAL;
 
 	if (!profile && !awaymsg)
@@ -1041,9 +1066,6 @@
 	if (profile) {
 		/* no + 1 here because of %s */
 		encoding = malloc(strlen(defencoding) + strlen(profile_encoding));
-		if (encoding == NULL) {
-			return -ENOMEM;
-		}
 		snprintf(encoding, strlen(defencoding) + strlen(profile_encoding), defencoding, profile_encoding);
 		aim_tlvlist_add_str(&tl, 0x0001, encoding);
 		aim_tlvlist_add_raw(&tl, 0x0002, profile_len, (const guchar *)profile);
@@ -1061,9 +1083,6 @@
 	if (awaymsg) {
 		if (awaymsg_len) {
 			encoding = malloc(strlen(defencoding) + strlen(awaymsg_encoding));
-			if (encoding == NULL) {
-				return -ENOMEM;
-			}
 			snprintf(encoding, strlen(defencoding) + strlen(awaymsg_encoding), defencoding, awaymsg_encoding);
 			aim_tlvlist_add_str(&tl, 0x0003, encoding);
 			aim_tlvlist_add_raw(&tl, 0x0004, awaymsg_len, (const guchar *)awaymsg);
@@ -1072,16 +1091,15 @@
 			aim_tlvlist_add_noval(&tl, 0x0004);
 	}
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_tlvlist_size(&tl))))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(&tl));
 
-	snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0002, 0x004, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0002, 0x004, 0x0000, snacid);
 
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1089,28 +1107,28 @@
 /*
  * Subtype 0x0004 - Set your client's capabilities.
  */
-faim_export int aim_locate_setcaps(OscarSession *sess, guint32 caps)
+int
+aim_locate_setcaps(OscarData *od, guint32 caps)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_LOCATE)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
 		return -EINVAL;
 
 	aim_tlvlist_add_caps(&tl, 0x0005, caps);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_tlvlist_size(&tl))))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(&tl));
 
-	snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0002, 0x004, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0002, 0x004, 0x0000, snacid);
 
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1124,32 +1142,33 @@
  *        0x0003 - Away message
  *        0x0004 - Capabilities
  */
-faim_export int aim_locate_getinfo(OscarSession *sess, const char *sn, guint16 infotype)
+int
+aim_locate_getinfo(OscarData *od, const char *sn, guint16 infotype)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_LOCATE)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 12+1+strlen(sn))))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 12+1+strlen(sn));
 
-	snacid = aim_cachesnac(sess, 0x0002, 0x0005, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, 0x0002, 0x0005, 0x0000, NULL, 0);
 
-	aim_putsnac(&fr->data, 0x0002, 0x0005, 0x0000, snacid);
-	aimbs_put16(&fr->data, infotype);
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
+	aim_putsnac(&frame->data, 0x0002, 0x0005, 0x0000, snacid);
+	byte_stream_put16(&frame->data, infotype);
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
 /* Subtype 0x0006 */
-static int userinfo(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -1159,7 +1178,7 @@
 	int was_explicit;
 
 	userinfo = (aim_userinfo_t *)malloc(sizeof(aim_userinfo_t));
-	aim_info_extract(sess, bs, userinfo);
+	aim_info_extract(od, bs, userinfo);
 	tlvlist = aim_tlvlist_read(bs);
 
 	/* Profile will be 1 and 2 */
@@ -1181,14 +1200,14 @@
 	/* Caps will be 5 */
 	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) {
 		ByteStream cbs;
-		aim_bstream_init(&cbs, tlv->value, tlv->length);
-		userinfo->capabilities = aim_locate_getcaps(sess, &cbs, tlv->length);
+		byte_stream_init(&cbs, tlv->value, tlv->length);
+		userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length);
 		userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES;
 	}
 	aim_tlvlist_free(&tlvlist);
 
-	aim_locate_adduserinfo(sess, userinfo);
-	userinfo2 = aim_locate_finduserinfo(sess, userinfo->sn);
+	aim_locate_adduserinfo(od, userinfo);
+	userinfo2 = aim_locate_finduserinfo(od, userinfo->sn);
 	aim_info_free(userinfo);
 	free(userinfo);
 
@@ -1197,10 +1216,10 @@
 	 * this buddy's info explicitly, then notify them that we have info
 	 * for this buddy.
 	 */
-	was_explicit = aim_locate_gotuserinfo(sess, userinfo2->sn);
+	was_explicit = aim_locate_gotuserinfo(od, conn, userinfo2->sn);
 	if (was_explicit == TRUE)
-		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-			ret = userfunc(sess, rx, userinfo2);
+		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+			ret = userfunc(od, conn, frame, userinfo2);
 
 	return ret;
 }
@@ -1212,14 +1231,14 @@
  * privacy: 1 to allow searching, 0 to disallow.
  *
  */
-faim_export int aim_locate_setdirinfo(OscarSession *sess, 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)
+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)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_LOCATE)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
 		return -EINVAL;
 
 	aim_tlvlist_add_16(&tl, 0x000a, privacy);
@@ -1246,16 +1265,15 @@
 	if (street)
 		aim_tlvlist_add_str(&tl, 0x0021, street);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_tlvlist_size(&tl))))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(&tl));
 
-	snacid = aim_cachesnac(sess, 0x0002, 0x0009, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, 0x0002, 0x0009, 0x0000, NULL, 0);
 
-	aim_putsnac(&fr->data, 0x0002, 0x0009, 0x0000, snacid);
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_putsnac(&frame->data, 0x0002, 0x0009, 0x0000, snacid);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1263,27 +1281,26 @@
 /*
  * Subtype 0x000b - Huh? What is this?
  */
-faim_export int aim_locate_000b(OscarSession *sess, const char *sn)
+int aim_locate_000b(OscarData *od, const char *sn)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
 		return -EINVAL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_LOCATE)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn));
 
-	snacid = aim_cachesnac(sess, 0x0002, 0x000b, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, 0x0002, 0x000b, 0x0000, NULL, 0);
 
-	aim_putsnac(&fr->data, 0x0002, 0x000b, 0x0000, snacid);
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
+	aim_putsnac(&frame->data, 0x0002, 0x000b, 0x0000, snacid);
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1294,14 +1311,14 @@
  * XXX pass these in better
  *
  */
-faim_export int aim_locate_setinterests(OscarSession *sess, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy)
+int aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_LOCATE)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
 		return -EINVAL;
 
 	/* ?? privacy ?? */
@@ -1318,16 +1335,15 @@
 	if (interest5)
 		aim_tlvlist_add_str(&tl, 0x0000b, interest5);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_tlvlist_size(&tl))))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(&tl));
 
-	snacid = aim_cachesnac(sess, 0x0002, 0x000f, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, 0x0002, 0x000f, 0x0000, NULL, 0);
 
-	aim_putsnac(&fr->data, 0x0002, 0x000f, 0x0000, 0);
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_putsnac(&frame->data, 0x0002, 0x000f, 0x0000, 0);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1344,59 +1360,59 @@
  *        0x00000008 - Certification.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_locate_getinfoshort(OscarSession *sess, const char *sn, guint32 flags)
+int aim_locate_getinfoshort(OscarData *od, const char *sn, guint32 flags)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_LOCATE)) || !sn)
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+1+strlen(sn))))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+4+1+strlen(sn));
 
-	snacid = aim_cachesnac(sess, 0x0002, 0x0015, 0x0000, sn, strlen(sn)+1);
+	snacid = aim_cachesnac(od, 0x0002, 0x0015, 0x0000, sn, strlen(sn)+1);
 
-	aim_putsnac(&fr->data, 0x0002, 0x0015, 0x0000, snacid);
-	aimbs_put32(&fr->data, flags);
-	aimbs_put8(&fr->data, strlen(sn));
-	aimbs_putstr(&fr->data, sn);
+	aim_putsnac(&frame->data, 0x0002, 0x0015, 0x0000, snacid);
+	byte_stream_put32(&frame->data, flags);
+	byte_stream_put8(&frame->data, strlen(sn));
+	byte_stream_putstr(&frame->data, sn);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0001)
-		return error(sess, mod, rx, snac, bs);
+		return error(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0003)
-		return rights(sess, mod, rx, snac, bs);
+		return rights(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0006)
-		return userinfo(sess, mod, rx, snac, bs);
+		return userinfo(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-static void locate_shutdown(OscarSession *sess, aim_module_t *mod)
+static void
+locate_shutdown(OscarData *od, aim_module_t *mod)
 {
 	aim_userinfo_t *del;
 
-	while (sess->locate.userinfo) {
-		del = sess->locate.userinfo;
-		sess->locate.userinfo = sess->locate.userinfo->next;
+	while (od->locate.userinfo) {
+		del = od->locate.userinfo;
+		od->locate.userinfo = od->locate.userinfo->next;
 		aim_info_free(del);
 		free(del);
 	}
 }
 
-faim_internal int locate_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+locate_modfirst(OscarData *od, aim_module_t *mod)
 {
-
-	mod->family = OSCAR_FAMILY_LOCATE;
+	mod->family = SNAC_FAMILY_LOCATE;
 	mod->version = 0x0001;
 	mod->toolid = 0x0110;
 	mod->toolversion = 0x0629;
--- a/src/protocols/oscar/family_odir.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_odir.c	Fri Apr 07 05:10:56 2006 +0000
@@ -33,19 +33,19 @@
  *
  * Search for an AIM screen name based on their email address.
  *
- * @param sess The oscar session.
+ * @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.
  */
-faim_export int aim_odir_email(OscarSession *sess, const char *region, const char *email)
+int aim_odir_email(OscarData *od, const char *region, const char *email)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x000f)) || !region || !email)
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x000f)) || !region || !email)
 		return -EINVAL;
 
 	/* Create a TLV chain, write it to the outgoing frame, then free the chain */
@@ -53,15 +53,14 @@
 	aim_tlvlist_add_16(&tl, 0x000a, 0x0001); /* Type of search */
 	aim_tlvlist_add_str(&tl, 0x0005, email);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_tlvlist_size(&tl))))
-		return -ENOMEM;
-	snacid = aim_cachesnac(sess, 0x000f, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x000f, 0x0002, 0x0000, snacid);
+	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(&tl));
+	snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x000f, 0x0002, 0x0000, snacid);
 
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -73,7 +72,7 @@
  * Search for an AIM screen name based on various info
  * about the person.
  *
- * @param sess The oscar session.
+ * @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.
@@ -87,14 +86,14 @@
  * @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.
  */
-faim_export int aim_odir_name(OscarSession *sess, 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)
+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)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x000f)) || !region)
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x000f)) || !region)
 		return -EINVAL;
 
 	/* Create a TLV chain, write it to the outgoing frame, then free the chain */
@@ -121,15 +120,14 @@
 	if (address)
 		aim_tlvlist_add_str(&tl, 0x0021, address);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_tlvlist_size(&tl))))
-		return -ENOMEM;
-	snacid = aim_cachesnac(sess, 0x000f, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x000f, 0x0002, 0x0000, snacid);
+	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(&tl));
+	snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x000f, 0x0002, 0x0000, snacid);
 
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -138,18 +136,18 @@
 /**
  * Subtype 0x0002 - Submit a User Search Request
  *
- * @param sess The oscar session.
+ * @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.
  */
-faim_export int aim_odir_interest(OscarSession *sess, const char *region, const char *interest)
+int aim_odir_interest(OscarData *od, const char *region, const char *interest)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x000f)) || !region)
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x000f)) || !region)
 		return -EINVAL;
 
 	/* Create a TLV chain, write it to the outgoing frame, then free the chain */
@@ -158,15 +156,14 @@
 	if (interest)
 		aim_tlvlist_add_str(&tl, 0x0001, interest);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_tlvlist_size(&tl))))
-		return -ENOMEM;
-	snacid = aim_cachesnac(sess, 0x000f, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x000f, 0x0002, 0x0000, snacid);
+	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(&tl));
+	snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x000f, 0x0002, 0x0000, snacid);
 
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -176,23 +173,23 @@
  * Subtype 0x0003 - Receive Reply From a User Search
  *
  */
-static int parseresults(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+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 = aimbs_get16(bs); /* Unknown */
-	tmp = aimbs_get16(bs); /* Unknown */
-	aim_bstream_advance(bs, tmp);
+	tmp = byte_stream_get16(bs); /* Unknown */
+	tmp = byte_stream_get16(bs); /* Unknown */
+	byte_stream_advance(bs, tmp);
 
-	numresults = aimbs_get16(bs); /* Number of results to follow */
+	numresults = byte_stream_get16(bs); /* Number of results to follow */
 
 	/* Allocate a linked list, 1 node per result */
 	while (numresults) {
 		struct aim_odir *new;
-		aim_tlvlist_t *tl = aim_tlvlist_readnum(bs, aimbs_get16(bs));
+		aim_tlvlist_t *tl = aim_tlvlist_readnum(bs, byte_stream_get16(bs));
 		new = (struct aim_odir *)malloc(sizeof(struct aim_odir));
 		new->first = aim_tlv_getstr(tl, 0x0001, 1);
 		new->last = aim_tlv_getstr(tl, 0x0002, 1);
@@ -213,8 +210,8 @@
 		numresults--;
 	}
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, results);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, results);
 
 	/* Now free everything from above */
 	while (results) {
@@ -240,18 +237,18 @@
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+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(sess, mod, rx, snac, bs);
+		return parseresults(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int odir_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+odir_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x000f;
 	mod->version = 0x0001;
 	mod->toolid = 0x0010;
--- a/src/protocols/oscar/family_oservice.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_oservice.c	Fri Apr 07 05:10:56 2006 +0000
@@ -28,21 +28,21 @@
 #include "cipher.h"
 
 /* Subtype 0x0002 - Client Online */
-faim_export int aim_clientready(OscarSession *sess, OscarConnection *conn)
+int
+aim_clientready(OscarData *od, FlapConnection *conn)
 {
 	aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
 	struct snacgroup *sg;
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
 	if (!ins)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 1152);
 
-	snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0001, 0x0002, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0001, 0x0002, 0x0000, snacid);
 
 	/*
 	 * Send only the tool versions that the server cares about (that it
@@ -51,16 +51,16 @@
 	for (sg = ins->groups; sg; sg = sg->next) {
 		aim_module_t *mod;
 
-		if ((mod = aim__findmodulebygroup(sess, sg->group))) {
-			aimbs_put16(&fr->data, mod->family);
-			aimbs_put16(&fr->data, mod->version);
-			aimbs_put16(&fr->data, mod->toolid);
-			aimbs_put16(&fr->data, mod->toolversion);
+		if ((mod = aim__findmodulebygroup(od, sg->group))) {
+			byte_stream_put16(&frame->data, mod->family);
+			byte_stream_put16(&frame->data, mod->version);
+			byte_stream_put16(&frame->data, mod->toolid);
+			byte_stream_put16(&frame->data, mod->toolversion);
 		} else
 			gaim_debug_misc("oscar", "aim_clientready: server supports group 0x%04x but we don't!\n", sg->group);
 	}
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -79,18 +79,18 @@
  * shortly after the rate information is acknowledged.
  *
  */
-static int hostonline(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+hostonline(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	guint16 *families;
 	int famcount;
 
 
-	if (!(families = malloc(aim_bstream_empty(bs))))
-		return 0;
+	families = malloc(byte_stream_empty(bs));
 
-	for (famcount = 0; aim_bstream_empty(bs); famcount++) {
-		families[famcount] = aimbs_get16(bs);
-		aim_conn_addgroup(rx->conn, families[famcount]);
+	for (famcount = 0; byte_stream_empty(bs); famcount++) {
+		families[famcount] = byte_stream_get16(bs);
+		flap_connection_addgroup(conn, families[famcount]);
 	}
 
 	free(families);
@@ -104,60 +104,67 @@
 	 * give it.
 	 *
 	 */
-	aim_setversions(sess, rx->conn);
+	aim_setversions(od, conn);
 
 	return 1;
 }
 
 /* Subtype 0x0004 - Service request */
-faim_export int aim_reqservice(OscarSession *sess, OscarConnection *conn, guint16 serviceid)
+int aim_reqservice(OscarData *od, guint16 serviceid)
 {
-	return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid);
+	FlapConnection *conn;
+
+	conn = flap_connection_findbygroup(od, SNAC_FAMILY_BOS);
+
+	return aim_genericreq_s(od, conn, 0x0001, 0x0004, &serviceid);
 }
 
 /*
- * Join a room of name roomname.  This is the first step to joining an 
- * already created room.  It's basically a Service Request for 
- * family 0x000e, with a little added on to specify the exchange and room 
+ * Join a room of name roomname.  This is the first step to joining an
+ * already created room.  It's basically a Service Request for
+ * family 0x000e, with a little added on to specify the exchange and room
  * name.
  */
-faim_export int aim_chat_join(OscarSession *sess, OscarConnection *conn, guint16 exchange, const char *roomname, guint16 instance)
+int
+aim_chat_join(OscarData *od, guint16 exchange, const char *roomname, guint16 instance)
 {
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 	struct chatsnacinfo csi;
 
-	if (!sess || !conn || !roomname || !strlen(roomname))
+	conn = flap_connection_findbygroup(od, SNAC_FAMILY_BOS);
+	if (!od || !conn || !roomname || !strlen(roomname))
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 512);
 
 	memset(&csi, 0, sizeof(csi));
 	csi.exchange = exchange;
 	strncpy(csi.name, roomname, sizeof(csi.name));
 	csi.instance = instance;
 
-	snacid = aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi));
-	aim_putsnac(&fr->data, 0x0001, 0x0004, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi));
+	aim_putsnac(&frame->data, 0x0001, 0x0004, 0x0000, snacid);
 
 	/*
 	 * Requesting service chat (0x000e)
 	 */
-	aimbs_put16(&fr->data, 0x000e);
+	byte_stream_put16(&frame->data, 0x000e);
 
 	aim_tlvlist_add_chatroom(&tl, 0x0001, exchange, roomname, instance);
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
 /* Subtype 0x0005 - Redirect */
-static int redirect(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+redirect(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	struct aim_redirect_data redir;
 	aim_rxcallback_t userfunc;
@@ -182,9 +189,9 @@
 	redir.cookie = (guchar *)aim_tlv_getstr(tlvlist, 0x0006, 1);
 
 	/* Fetch original SNAC so we can get csi if needed */
-	origsnac = aim_remsnac(sess, snac->id);
+	origsnac = aim_remsnac(od, snac->id);
 
-	if ((redir.group == AIM_CONN_TYPE_CHAT) && origsnac) {
+	if ((redir.group == SNAC_FAMILY_CHAT) && origsnac) {
 		struct chatsnacinfo *csi = (struct chatsnacinfo *)origsnac->data;
 
 		redir.chat.exchange = csi->exchange;
@@ -192,8 +199,8 @@
 		redir.chat.instance = csi->instance;
 	}
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, &redir);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, &redir);
 
 	free((void *)redir.ip);
 	free((void *)redir.cookie);
@@ -208,9 +215,10 @@
 }
 
 /* Subtype 0x0006 - Request Rate Information. */
-faim_internal int aim_reqrates(OscarSession *sess, OscarConnection *conn)
+int
+aim_reqrates(OscarData *od, FlapConnection *conn)
 {
-	return aim_genericreq_n_snacid(sess, conn, 0x0001, 0x0006);
+	return aim_genericreq_n_snacid(od, conn, 0x0001, 0x0006);
 }
 
 /*
@@ -219,7 +227,7 @@
  * level, etc), and a set of SNAC family/type pairs associated with
  * it.  The rate classes, their limiting properties, and the definitions
  * of which SNACs are belong to which class, are defined in the
- * Rate Response packet at login to each host.  
+ * Rate Response packet at login to each host.
  *
  * Logically, all rate offenses within one class count against further
  * offenses for other SNACs in the same class (ie, sending messages
@@ -233,10 +241,10 @@
  * members as follows...
  *
  *  Rate class 0x0001:
- *  	- Everything thats not in any of the other classes
+ *	- Everything thats not in any of the other classes
  *
  *  Rate class 0x0002:
- * 	- Buddy list add/remove
+ *	- Buddy list add/remove
  *	- Permit list add/remove
  *	- Deny list add/remove
  *
@@ -252,23 +260,21 @@
  *	- Outgoing chat ICBMs
  *
  * The only other thing of note is that class 5 (chat) has slightly looser
- * limiting properties than class 3 (normal messages).  But thats just a 
+ * limiting properties than class 3 (normal messages).  But thats just a
  * small bit of trivia for you.
  *
  * The last thing that needs to be learned about the rate limiting
  * system is how the actual numbers relate to the passing of time.  This
  * seems to be a big mystery.
- * 
+ *
  */
 
-static void rc_addclass(struct rateclass **head, struct rateclass *inrc)
+static void
+rc_addclass(struct rateclass **head, struct rateclass *inrc)
 {
 	struct rateclass *rc, *rc2;
 
-	if (!(rc = malloc(sizeof(struct rateclass))))
-		return;
-
-	memcpy(rc, inrc, sizeof(struct rateclass));
+	rc = g_memdup(inrc, sizeof(struct rateclass));
 	rc->next = NULL;
 
 	for (rc2 = *head; rc2 && rc2->next; rc2 = rc2->next)
@@ -282,7 +288,8 @@
 	return;
 }
 
-static struct rateclass *rc_findclass(struct rateclass **head, guint16 id)
+static struct rateclass *
+rc_findclass(struct rateclass **head, guint16 id)
 {
 	struct rateclass *rc;
 
@@ -294,14 +301,12 @@
 	return NULL;
 }
 
-static void rc_addpair(struct rateclass *rc, guint16 group, guint16 type)
+static void
+rc_addpair(struct rateclass *rc, guint16 group, guint16 type)
 {
 	struct snacpair *sp, *sp2;
 
-	if (!(sp = malloc(sizeof(struct snacpair))))
-		return;
-	memset(sp, 0, sizeof(struct snacpair));
-
+	sp = g_new0(struct snacpair, 1);
 	sp->group = group;
 	sp->subtype = type;
 	sp->next = NULL;
@@ -318,9 +323,10 @@
 }
 
 /* Subtype 0x0007 - Rate Parameters */
-static int rateresp(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+rateresp(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-	aim_conn_inside_t *ins = (aim_conn_inside_t *)rx->conn->inside;
+	aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
 	guint16 numclasses, i;
 	aim_rxcallback_t userfunc;
 
@@ -328,32 +334,30 @@
 	/*
 	 * First are the parameters for each rate class.
 	 */
-	numclasses = aimbs_get16(bs);
+	numclasses = byte_stream_get16(bs);
 	for (i = 0; i < numclasses; i++) {
 		struct rateclass rc;
 
 		memset(&rc, 0, sizeof(struct rateclass));
 
-		rc.classid = aimbs_get16(bs);
-		rc.windowsize = aimbs_get32(bs);
-		rc.clear = aimbs_get32(bs);
-		rc.alert = aimbs_get32(bs);
-		rc.limit = aimbs_get32(bs);
-		rc.disconnect = aimbs_get32(bs);
-		rc.current = aimbs_get32(bs);
-		rc.max = aimbs_get32(bs);
+		rc.classid = byte_stream_get16(bs);
+		rc.windowsize = byte_stream_get32(bs);
+		rc.clear = byte_stream_get32(bs);
+		rc.alert = byte_stream_get32(bs);
+		rc.limit = byte_stream_get32(bs);
+		rc.disconnect = byte_stream_get32(bs);
+		rc.current = byte_stream_get32(bs);
+		rc.max = byte_stream_get32(bs);
 
 		/*
 		 * The server will send an extra five bytes of parameters
 		 * depending on the version we advertised in 1/17.  If we
 		 * didn't send 1/17 (evil!), then this will crash and you
-		 * die, as it will default to the old version but we have 
-		 * the new version hardcoded here. 
+		 * die, as it will default to the old version but we have
+		 * the new version hardcoded here.
 		 */
 		if (mod->version >= 3)
-			aimbs_getrawbuf(bs, rc.unknown, sizeof(rc.unknown));
-
-		gaim_debug_misc("oscar", "--- Adding rate class %d to connection type %d: window size = %ld, clear = %ld, alert = %ld, limit = %ld, disconnect = %ld, current = %ld, max = %ld\n", rx->conn->type, rc.classid, rc.windowsize, rc.clear, rc.alert, rc.limit, rc.disconnect, rc.current, rc.max);
+			byte_stream_getrawbuf(bs, rc.unknown, sizeof(rc.unknown));
 
 		rc_addclass(&ins->rates, &rc);
 	}
@@ -366,16 +370,16 @@
 		struct rateclass *rc;
 		int j;
 
-		classid = aimbs_get16(bs);
-		count = aimbs_get16(bs);
+		classid = byte_stream_get16(bs);
+		count = byte_stream_get16(bs);
 
 		rc = rc_findclass(&ins->rates, classid);
 
 		for (j = 0; j < count; j++) {
 			guint16 group, subtype;
 
-			group = aimbs_get16(bs);
-			subtype = aimbs_get16(bs);
+			group = byte_stream_get16(bs);
+			subtype = byte_stream_get16(bs);
 
 			if (rc)
 				rc_addpair(rc, group, subtype);
@@ -392,83 +396,84 @@
 	 * Last step in the conn init procedure is to acknowledge that we
 	 * agree to these draconian limitations.
 	 */
-	aim_rates_addparam(sess, rx->conn);
+	aim_rates_addparam(od, conn);
 
 	/*
 	 * Finally, tell the client it's ready to go...
 	 */
-	if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE)))
-		userfunc(sess, rx);
+	if ((userfunc = aim_callhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE)))
+		userfunc(od, conn, frame);
 
 
 	return 1;
 }
 
 /* Subtype 0x0008 - Add Rate Parameter */
-faim_internal int aim_rates_addparam(OscarSession *sess, OscarConnection *conn)
+int
+aim_rates_addparam(OscarData *od, FlapConnection *conn)
 {
 	aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	struct rateclass *rc;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 512);
 
-	snacid = aim_cachesnac(sess, 0x0001, 0x0008, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0001, 0x0008, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0001, 0x0008, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0001, 0x0008, 0x0000, snacid);
 
 	for (rc = ins->rates; rc; rc = rc->next)
-		aimbs_put16(&fr->data, rc->classid);
+		byte_stream_put16(&frame->data, rc->classid);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
 /* Subtype 0x0009 - Delete Rate Parameter */
-faim_internal int aim_rates_delparam(OscarSession *sess, OscarConnection *conn)
+int
+aim_rates_delparam(OscarData *od, FlapConnection *conn)
 {
 	aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	struct rateclass *rc;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 512);
 
-	snacid = aim_cachesnac(sess, 0x0001, 0x0009, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0001, 0x0009, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0001, 0x0009, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0001, 0x0009, 0x0000, snacid);
 
 	for (rc = ins->rates; rc; rc = rc->next)
-		aimbs_put16(&fr->data, rc->classid);
+		byte_stream_put16(&frame->data, rc->classid);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
 /* Subtype 0x000a - Rate Change */
-static int ratechange(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+ratechange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 code, rateclass;
 	guint32 currentavg, maxavg, windowsize, clear, alert, limit, disconnect;
 
-	code = aimbs_get16(bs);
-	rateclass = aimbs_get16(bs);
+	code = byte_stream_get16(bs);
+	rateclass = byte_stream_get16(bs);
 
-	windowsize = aimbs_get32(bs);
-	clear = aimbs_get32(bs);
-	alert = aimbs_get32(bs);
-	limit = aimbs_get32(bs);
-	disconnect = aimbs_get32(bs);
-	currentavg = aimbs_get32(bs);
-	maxavg = aimbs_get32(bs);
+	windowsize = byte_stream_get32(bs);
+	clear = byte_stream_get32(bs);
+	alert = byte_stream_get32(bs);
+	limit = byte_stream_get32(bs);
+	disconnect = byte_stream_get32(bs);
+	currentavg = byte_stream_get32(bs);
+	maxavg = byte_stream_get32(bs);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
 
 	return ret;
 }
@@ -476,10 +481,10 @@
 /*
  * How Migrations work.
  *
- * The server sends a Server Pause message, which the client should respond to 
- * with a Server Pause Ack, which contains the families it needs on this 
- * connection. The server will send a Migration Notice with an IP address, and 
- * then disconnect. Next the client should open the connection and send the 
+ * The server sends a Server Pause message, which the client should respond to
+ * with a Server Pause Ack, which contains the families it needs on this
+ * connection. The server will send a Migration Notice with an IP address, and
+ * then disconnect. Next the client should open the connection and send the
  * cookie.  Repeat the normal login process and pretend this never happened.
  *
  * The Server Pause contains no data.
@@ -487,13 +492,14 @@
  */
 
 /* Subtype 0x000b - Service Pause */
-static int serverpause(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+serverpause(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame);
 
 	return ret;
 }
@@ -509,61 +515,64 @@
  * libfaim can cause.
  *
  */
-faim_export int aim_sendpauseack(OscarSession *sess, OscarConnection *conn)
+int
+aim_sendpauseack(OscarData *od, FlapConnection *conn)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
 	struct snacgroup *sg;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1024)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 1024);
 
-	snacid = aim_cachesnac(sess, 0x0001, 0x000c, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0001, 0x000c, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0001, 0x000c, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0001, 0x000c, 0x0000, snacid);
 
 	/*
-	 * This list should have all the groups that the original 
-	 * Host Online / Server Ready said this host supports.  And 
+	 * 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 (sg = ins->groups; sg; sg = sg->next)
-		aimbs_put16(&fr->data, sg->group);
+		byte_stream_put16(&frame->data, sg->group);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
 /* Subtype 0x000d - Service Resume */
-static int serverresume(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+serverresume(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame);
 
 	return ret;
 }
 
 /* Subtype 0x000e - Request self-info */
-faim_export int aim_reqpersonalinfo(OscarSession *sess, OscarConnection *conn)
+int
+aim_reqpersonalinfo(OscarData *od, FlapConnection *conn)
 {
-	return aim_genericreq_n_snacid(sess, conn, 0x0001, 0x000e);
+	return aim_genericreq_n_snacid(od, conn, 0x0001, 0x000e);
 }
 
 /* Subtype 0x000f - Self User Info */
-static int selfinfo(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+selfinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	aim_userinfo_t userinfo;
 
-	aim_info_extract(sess, bs, &userinfo);
+	aim_info_extract(od, bs, &userinfo);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, &userinfo);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, &userinfo);
 
 	aim_info_free(&userinfo);
 
@@ -571,7 +580,8 @@
 }
 
 /* Subtype 0x0010 - Evil Notification */
-static int evilnotify(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+evilnotify(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -580,13 +590,13 @@
 
 	memset(&userinfo, 0, sizeof(aim_userinfo_t));
 
-	newevil = aimbs_get16(bs);
+	newevil = byte_stream_get16(bs);
 
-	if (aim_bstream_empty(bs))
-		aim_info_extract(sess, bs, &userinfo);
+	if (byte_stream_empty(bs))
+		aim_info_extract(od, bs, &userinfo);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, newevil, &userinfo);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, newevil, &userinfo);
 
 	aim_info_free(&userinfo);
 
@@ -602,25 +612,27 @@
  * call it again with zero when you're back.
  *
  */
-faim_export int aim_srv_setidle(OscarSession *sess, guint32 idletime)
+int
+aim_srv_setidle(OscarData *od, guint32 idletime)
 {
-	OscarConnection *conn;
+	FlapConnection *conn;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_BOS)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_BOS)))
 		return -EINVAL;
 
-	return aim_genericreq_l(sess, conn, 0x0001, 0x0011, &idletime);
+	return aim_genericreq_l(od, conn, 0x0001, 0x0011, &idletime);
 }
 
 /*
  * Subtype 0x0012 - Service Migrate
  *
  * This is the final SNAC sent on the original connection during a migration.
- * It contains the IP and cookie used to connect to the new server, and 
+ * It contains the IP and cookie used to connect to the new server, and
  * optionally a list of the SNAC groups being migrated.
  *
  */
-static int migrate(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+migrate(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	aim_rxcallback_t userfunc;
 	int ret = 0;
@@ -634,17 +646,17 @@
 	 * migration can actually be quite selective about what groups it
 	 * moves to the new server.  When not all the groups for a connection
 	 * are migrated, or they are all migrated but some groups are moved
-	 * to a different server than others, it is called a bifurcated 
+	 * to a different server than others, it is called a bifurcated
 	 * migration.
 	 *
 	 * Let's play dumb and not support that.
 	 *
 	 */
-	groupcount = aimbs_get16(bs);
+	groupcount = byte_stream_get16(bs);
 	for (i = 0; i < groupcount; i++) {
 		guint16 group;
 
-		group = aimbs_get16(bs);
+		group = byte_stream_get16(bs);
 
 		gaim_debug_misc("oscar", "bifurcated migration unsupported -- group 0x%04x\n", group);
 	}
@@ -656,8 +668,8 @@
 
 	cktlv = aim_tlv_gettlv(tl, 0x0006, 1);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, ip, cktlv ? cktlv->value : NULL);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, ip, cktlv ? cktlv->value : NULL);
 
 	aim_tlvlist_free(&tl);
 	free(ip);
@@ -666,7 +678,8 @@
 }
 
 /* Subtype 0x0013 - Message of the Day */
-static int motd(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+motd(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	aim_rxcallback_t userfunc;
 	char *msg = NULL;
@@ -682,20 +695,20 @@
 	 *   2 Advisory upgrade
 	 *   3 System bulletin
 	 *   4 Nothing's wrong ("top o the world" -- normal)
-	 *   5 Lets-break-something. 
+	 *   5 Lets-break-something.
 	 *
 	 */
-	id = aimbs_get16(bs);
+	id = byte_stream_get16(bs);
 
-	/* 
-	 * TLVs follow 
+	/*
+	 * TLVs follow
 	 */
 	tlvlist = aim_tlvlist_read(bs);
 
 	msg = aim_tlv_getstr(tlvlist, 0x000b, 1);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, id, msg);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, id, msg);
 
 	free(msg);
 
@@ -704,7 +717,7 @@
 	return ret;
 }
 
-/* 
+/*
  * Subtype 0x0014 - Set privacy flags
  *
  * Normally 0x03.
@@ -713,93 +726,96 @@
  *  Bit 2:  Allows other AIM users to see how long you've been a member.
  *
  */
-faim_export int aim_bos_setprivacyflags(OscarSession *sess, OscarConnection *conn, guint32 flags)
+int
+aim_bos_setprivacyflags(OscarData *od, FlapConnection *conn, guint32 flags)
 {
-	return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags);
+	return aim_genericreq_l(od, conn, 0x0001, 0x0014, &flags);
 }
 
 /*
  * Subtype 0x0016 - No-op
  *
- * WinAIM sends these every 4min or so to keep the connection alive.  Its not 
+ * 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 3 
- * SNAC as a no-op...
+ * Wha?  No?  Since when?  I think WinAIM sends an empty channel 5
+ * FLAP as a no-op...
  */
-faim_export int aim_nop(OscarSession *sess, OscarConnection *conn)
+int
+aim_nop(OscarData *od, FlapConnection *conn)
 {
-	return aim_genericreq_n(sess, conn, 0x0001, 0x0016);
+	return aim_genericreq_n(od, conn, 0x0001, 0x0016);
 }
 
-/* 
+/*
  * Subtype 0x0017 - Set client versions
  *
- * If you've seen the clientonline/clientready SNAC you're probably 
+ * If you've seen the clientonline/clientready SNAC you're probably
  * wondering what the point of this one is.  And that point seems to be
  * that the versions in the client online SNAC are sent too late for the
  * server to be able to use them to change the protocol for the earlier
- * login packets (client versions are sent right after Host Online is 
+ * login packets (client versions are sent right after Host Online is
  * received, but client online versions aren't sent until quite a bit later).
  * We can see them already making use of this by changing the format of
  * the rate information based on what version of group 1 we advertise here.
  *
  */
-faim_internal int aim_setversions(OscarSession *sess, OscarConnection *conn)
+int
+aim_setversions(OscarData *od, FlapConnection *conn)
 {
 	aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
 	struct snacgroup *sg;
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
 	if (!ins)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 1152);
 
-	snacid = aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0001, 0x0017, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0001, 0x0017, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0001, 0x0017, 0x0000, snacid);
 
 	/*
 	 * Send only the versions that the server cares about (that it
-	 * marked as supporting in the server ready SNAC).  
+	 * marked as supporting in the server ready SNAC).
 	 */
 	for (sg = ins->groups; sg; sg = sg->next) {
 		aim_module_t *mod;
 
-		if ((mod = aim__findmodulebygroup(sess, sg->group))) {
-			aimbs_put16(&fr->data, mod->family);
-			aimbs_put16(&fr->data, mod->version);
+		if ((mod = aim__findmodulebygroup(od, sg->group))) {
+			byte_stream_put16(&frame->data, mod->family);
+			byte_stream_put16(&frame->data, mod->version);
 		} else
 			gaim_debug_misc("oscar", "aim_setversions: server supports group 0x%04x but we don't!\n", sg->group);
 	}
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
 /* Subtype 0x0018 - Host versions */
-static int hostversions(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+hostversions(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int vercount;
 	guint8 *versions;
 
 	/* This is frivolous. (Thank you SmarterChild.) */
-	vercount = aim_bstream_empty(bs)/4;
-	versions = aimbs_getraw(bs, aim_bstream_empty(bs));
+	vercount = byte_stream_empty(bs)/4;
+	versions = byte_stream_getraw(bs, byte_stream_empty(bs));
 	free(versions);
 
 	/*
 	 * Now request rates.
 	 */
-	aim_reqrates(sess, rx->conn);
+	aim_reqrates(od, conn);
 
 	return 1;
 }
 
-/* 
+/*
  * Subtype 0x001e - Set various account settings (mostly ICQ related).
  *
  * These settings are transient, not server-stored (i.e. they only
@@ -814,24 +830,24 @@
  * These are the same TLVs seen in user info.  You can
  * also set 0x0008 and 0x000c.
  */
-faim_export int aim_setextstatus(OscarSession *sess, guint32 status)
+int
+aim_setextstatus(OscarData *od, guint32 status)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
 	guint32 data;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, OSCAR_FAMILY_ICBM)))
+	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
 		return -EINVAL;
 
 	data = AIM_ICQ_STATE_HIDEIP | AIM_ICQ_STATE_DIRECTREQUIREAUTH | status;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 8)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10 + 8);
 
-	snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid);
+	snacid = aim_cachesnac(od, 0x0001, 0x001e, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, 0x0001, 0x001e, 0x0000, snacid);
 
 	aim_tlvlist_add_32(&tl, 0x0006, data);
 #if 0
@@ -839,10 +855,10 @@
 	aim_tlvlist_add_raw(&tl, 0x0011, 0x0005, unknown 0x01 61 10 f6 41);
 	aim_tlvlist_add_16(&tl, 0x0012, unknown 0x00 00);
 #endif
-	aim_tlvlist_write(&fr->data, &tl);
+	aim_tlvlist_write(&frame->data, &tl);
 	aim_tlvlist_free(&tl);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -856,46 +872,45 @@
  * These are the same TLVs seen in user info.  You can
  * also set 0x0008 and 0x000c.
  */
-faim_export int aim_srv_setstatusmsg(OscarSession *sess, const char *msg)
+int
+aim_srv_setstatusmsg(OscarData *od, const char *msg)
 {
-	OscarConnection *conn;
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
+	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
 		return -EINVAL;
 
 	if ((msg != NULL) && *msg != '\0') {
-		if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + strlen(msg) + 8)))
-			return -ENOMEM;
+		frame = flap_frame_new(od, 0x02, 10 + 4 + strlen(msg) + 8);
 
-		snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0);
-		aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid);
+		snacid = aim_cachesnac(od, 0x0001, 0x001e, 0x0000, NULL, 0);
+		aim_putsnac(&frame->data, 0x0001, 0x001e, 0x0000, snacid);
 
-		aimbs_put16(&fr->data, 0x001d); /* userinfo TLV type */
-		aimbs_put16(&fr->data, strlen(msg)+8); /* total length of userinfo TLV data */
-		aimbs_put16(&fr->data, 0x0002);
-		aimbs_put8(&fr->data, 0x04);
-		aimbs_put8(&fr->data, strlen(msg)+4);
-		aimbs_put16(&fr->data, strlen(msg));
-		aimbs_putstr(&fr->data, msg);
-		aimbs_put16(&fr->data, 0x0000);
+		byte_stream_put16(&frame->data, 0x001d); /* userinfo TLV type */
+		byte_stream_put16(&frame->data, strlen(msg)+8); /* total length of userinfo TLV data */
+		byte_stream_put16(&frame->data, 0x0002);
+		byte_stream_put8(&frame->data, 0x04);
+		byte_stream_put8(&frame->data, strlen(msg)+4);
+		byte_stream_put16(&frame->data, strlen(msg));
+		byte_stream_putstr(&frame->data, msg);
+		byte_stream_put16(&frame->data, 0x0000);
 	} else {
-		if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + 8)))
-			return -ENOMEM;
+		frame = flap_frame_new(od, 0x02, 10 + 4 + 8);
 
-		snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0);
-		aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid);
+		snacid = aim_cachesnac(od, 0x0001, 0x001e, 0x0000, NULL, 0);
+		aim_putsnac(&frame->data, 0x0001, 0x001e, 0x0000, snacid);
 
-		aimbs_put16(&fr->data, 0x001d);
-		aimbs_put16(&fr->data, 0x0008);
-		aimbs_put16(&fr->data, 0x0002);
-		aimbs_put16(&fr->data, 0x0404);
-		aimbs_put16(&fr->data, 0x0000);
-		aimbs_put16(&fr->data, 0x0000);
+		byte_stream_put16(&frame->data, 0x001d);
+		byte_stream_put16(&frame->data, 0x0008);
+		byte_stream_put16(&frame->data, 0x0002);
+		byte_stream_put16(&frame->data, 0x0404);
+		byte_stream_put16(&frame->data, 0x0000);
+		byte_stream_put16(&frame->data, 0x0000);
 	}
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -921,14 +936,14 @@
  * If the client does not send any data back, or the data does not match
  * the data that the specific client should have, the client will get the
  * following message from "AOL Instant Messenger":
- *    "You have been disconnected from the AOL Instant Message Service (SM) 
+ *    "You have been disconnected from the AOL Instant Message Service (SM)
  *     for accessing the AOL network using unauthorized software.  You can
- *     download a FREE, fully featured, and authorized client, here 
+ *     download a FREE, fully featured, and authorized client, here
  *     http://www.aol.com/aim/download2.html"
  * The connection is then closed, receiving disconnect code 1, URL
- * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html.  
+ * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html.
  *
- * Note, however, that numerous inconsistencies can cause the above error, 
+ * Note, however, that numerous inconsistencies can cause the above error,
  * not just sending back a bad hash.  Do not immediatly suspect this code
  * if you get disconnected.  AOL and the open/free software community have
  * played this game for a couple years now, generating the above message
@@ -938,7 +953,8 @@
  *
  */
 /* Subtype 0x001f - Client verification */
-static int memrequest(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+memrequest(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
@@ -946,16 +962,16 @@
 	aim_tlvlist_t *list;
 	char *modname;
 
-	offset = aimbs_get32(bs);
-	len = aimbs_get32(bs);
+	offset = byte_stream_get32(bs);
+	len = byte_stream_get32(bs);
 	list = aim_tlvlist_read(bs);
 
 	modname = aim_tlv_getstr(list, 0x0001, 1);
 
 	gaim_debug_info("oscar", "Got memory request for data at 0x%08lx (%d bytes) of requested %s\n", offset, len, modname ? modname : "aim.exe");
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, offset, len, modname);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, offset, len, modname);
 
 	free(modname);
 	aim_tlvlist_free(&list);
@@ -964,25 +980,25 @@
 }
 
 /* Subtype 0x0020 - Client verification reply */
-faim_export int aim_sendmemblock(OscarSession *sess, OscarConnection *conn, guint32 offset, guint32 len, const guint8 *buf, guint8 flag)
+int
+aim_sendmemblock(OscarData *od, FlapConnection *conn, guint32 offset, guint32 len, const guint8 *buf, guint8 flag)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !conn)
+	if (!od || !conn)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+16)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+2+16);
 
-	snacid = aim_cachesnac(sess, 0x0001, 0x0020, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, 0x0001, 0x0020, 0x0000, NULL, 0);
 
-	aim_putsnac(&fr->data, 0x0001, 0x0020, 0x0000, snacid);
-	aimbs_put16(&fr->data, 0x0010); /* md5 is always 16 bytes */
+	aim_putsnac(&frame->data, 0x0001, 0x0020, 0x0000, snacid);
+	byte_stream_put16(&frame->data, 0x0010); /* md5 is always 16 bytes */
 
 	if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && buf && (len == 0x10)) { /* we're getting a hash */
 
-		aimbs_putraw(&fr->data, buf, 0x10);
+		byte_stream_putraw(&frame->data, buf, 0x10);
 
 	} else if (buf && (len > 0)) { /* use input buffer */
 		GaimCipher *cipher;
@@ -996,7 +1012,7 @@
 		gaim_cipher_context_digest(context, 16, digest, NULL);
 		gaim_cipher_context_destroy(context);
 
-		aimbs_putraw(&fr->data, digest, 0x10);
+		byte_stream_putraw(&frame->data, digest, 0x10);
 
 	} else if (len == 0) { /* no length, just hash NULL (buf is optional) */
 		GaimCipher *cipher;
@@ -1015,7 +1031,7 @@
 		gaim_cipher_context_digest(context, 16, digest, NULL);
 		gaim_cipher_context_destroy(context);
 
-		aimbs_putraw(&fr->data, digest, 0x10);
+		byte_stream_putraw(&frame->data, digest, 0x10);
 
 	} else {
 
@@ -1029,30 +1045,30 @@
 		if ((offset == 0x03ffffff) && (len == 0x03ffffff)) {
 
 #if 1 /* with "AnrbnrAqhfzcd" */
-			aimbs_put32(&fr->data, 0x44a95d26);
-			aimbs_put32(&fr->data, 0xd2490423);
-			aimbs_put32(&fr->data, 0x93b8821f);
-			aimbs_put32(&fr->data, 0x51c54b01);
+			byte_stream_put32(&frame->data, 0x44a95d26);
+			byte_stream_put32(&frame->data, 0xd2490423);
+			byte_stream_put32(&frame->data, 0x93b8821f);
+			byte_stream_put32(&frame->data, 0x51c54b01);
 #else /* no filename */
-			aimbs_put32(&fr->data, 0x1df8cbae);
-			aimbs_put32(&fr->data, 0x5523b839);
-			aimbs_put32(&fr->data, 0xa0e10db3);
-			aimbs_put32(&fr->data, 0xa46d3b39);
+			byte_stream_put32(&frame->data, 0x1df8cbae);
+			byte_stream_put32(&frame->data, 0x5523b839);
+			byte_stream_put32(&frame->data, 0xa0e10db3);
+			byte_stream_put32(&frame->data, 0xa46d3b39);
 #endif
 
 		} else if ((offset == 0x00001000) && (len == 0x00000000)) {
 
-			aimbs_put32(&fr->data, 0xd41d8cd9);
-			aimbs_put32(&fr->data, 0x8f00b204);
-			aimbs_put32(&fr->data, 0xe9800998);
-			aimbs_put32(&fr->data, 0xecf8427e);
+			byte_stream_put32(&frame->data, 0xd41d8cd9);
+			byte_stream_put32(&frame->data, 0x8f00b204);
+			byte_stream_put32(&frame->data, 0xe9800998);
+			byte_stream_put32(&frame->data, 0xecf8427e);
 
 		} else
 			gaim_debug_warning("oscar", "sendmemblock: unknown hash request\n");
 
 	}
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -1064,30 +1080,31 @@
  * status messages?  It's also used to tell the client whether or not it
  * needs to upload an SSI buddy icon... who engineers this stuff, anyway?
  */
-static int aim_parse_extstatus(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+aim_parse_extstatus(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 type;
 	guint8 flags, length;
 
-	type = aimbs_get16(bs);
-	flags = aimbs_get8(bs);
-	length = aimbs_get8(bs);
+	type = byte_stream_get16(bs);
+	flags = byte_stream_get8(bs);
+	length = byte_stream_get8(bs);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
 		switch (type) {
 		case 0x0000:
 		case 0x0001: { /* buddy icon checksum */
 			/* not sure what the difference between 1 and 0 is */
-			guint8 *md5 = aimbs_getraw(bs, length);
-			ret = userfunc(sess, rx, type, flags, length, md5);
+			guint8 *md5 = byte_stream_getraw(bs, length);
+			ret = userfunc(od, conn, frame, type, flags, length, md5);
 			free(md5);
 			} break;
 		case 0x0002: { /* available message */
 			/* there is a second length that is just for the message */
-			char *msg = aimbs_getstr(bs, aimbs_get16(bs));
-			ret = userfunc(sess, rx, msg);
+			char *msg = byte_stream_getstr(bs, byte_stream_get16(bs));
+			ret = userfunc(od, conn, frame, msg);
 			free(msg);
 			} break;
 		}
@@ -1096,42 +1113,41 @@
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0003)
-		return hostonline(sess, mod, rx, snac, bs);
+		return hostonline(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0005)
-		return redirect(sess, mod, rx, snac, bs);
+		return redirect(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0007)
-		return rateresp(sess, mod, rx, snac, bs);
+		return rateresp(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x000a)
-		return ratechange(sess, mod, rx, snac, bs);
+		return ratechange(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x000b)
-		return serverpause(sess, mod, rx, snac, bs);
+		return serverpause(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x000d)
-		return serverresume(sess, mod, rx, snac, bs);
+		return serverresume(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x000f)
-		return selfinfo(sess, mod, rx, snac, bs);
+		return selfinfo(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0010)
-		return evilnotify(sess, mod, rx, snac, bs);
+		return evilnotify(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0012)
-		return migrate(sess, mod, rx, snac, bs);
+		return migrate(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0013)
-		return motd(sess, mod, rx, snac, bs);
+		return motd(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0018)
-		return hostversions(sess, mod, rx, snac, bs);
+		return hostversions(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x001f)
-		return memrequest(sess, mod, rx, snac, bs);
+		return memrequest(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0021)
-		return aim_parse_extstatus(sess, mod, rx, snac, bs);
+		return aim_parse_extstatus(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int service_modfirst(OscarSession *sess, aim_module_t *mod)
+int service_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x0001;
 	mod->version = 0x0003;
 	mod->toolid = 0x0110;
--- a/src/protocols/oscar/family_popup.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_popup.c	Fri Apr 07 05:10:56 2006 +0000
@@ -33,7 +33,8 @@
  * The message is probably HTML.
  *
  */
-static int parsepopup(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+parsepopup(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	aim_rxcallback_t userfunc;
 	aim_tlvlist_t *tl;
@@ -49,8 +50,8 @@
 	height = aim_tlv_get16(tl, 0x0004, 1);
 	delay = aim_tlv_get16(tl, 0x0005, 1);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, msg, url, width, height, delay);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, msg, url, width, height, delay);
 
 	aim_tlvlist_free(&tl);
 	free(msg);
@@ -59,18 +60,18 @@
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0002)
-		return parsepopup(sess, mod, rx, snac, bs);
+		return parsepopup(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int popups_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+popups_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x0008;
 	mod->version = 0x0001;
 	mod->toolid = 0x0104;
--- a/src/protocols/oscar/family_stats.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_stats.c	Fri Apr 07 05:10:56 2006 +0000
@@ -25,32 +25,33 @@
 
 #include <oscar.h>
 
-static int reportinterval(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+reportinterval(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 interval;
 
-	interval = aimbs_get16(bs);
+	interval = byte_stream_get16(bs);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, interval);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, interval);
 
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0002)
-		return reportinterval(sess, mod, rx, snac, bs);
+		return reportinterval(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int stats_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+stats_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x000b;
 	mod->version = 0x0001;
 	mod->toolid = 0x0104;
--- a/src/protocols/oscar/family_translate.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_translate.c	Fri Apr 07 05:10:56 2006 +0000
@@ -31,7 +31,7 @@
 
 #include "oscar.h"
 
-faim_internal int translate_modfirst(OscarSession *sess, aim_module_t *mod)
+int translate_modfirst(OscarData *od, aim_module_t *mod)
 {
 
 	mod->family = 0x000c;
--- a/src/protocols/oscar/family_userlookup.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/family_userlookup.c	Fri Apr 07 05:10:56 2006 +0000
@@ -32,20 +32,20 @@
  *
  * XXX can this be integrated with the rest of the error handling?
  */
-static int error(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	aim_snac_t *snac2;
 
 	/* XXX the modules interface should have already retrieved this for us */
-	if (!(snac2 = aim_remsnac(sess, snac->id))) {
+	if (!(snac2 = aim_remsnac(od, snac->id))) {
 		gaim_debug_misc("oscar", "search error: couldn't get a snac for 0x%08lx\n", snac->id);
 		return 0;
 	}
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, snac2->data /* address */);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, snac2->data /* address */);
 
 	/* XXX freesnac()? */
 	if (snac2)
@@ -59,23 +59,25 @@
  * Subtype 0x0002
  *
  */
-faim_export int aim_search_address(OscarSession *sess, OscarConnection *conn, const char *address)
+int aim_search_address(OscarData *od, const char *address)
 {
-	FlapFrame *fr;
+	FlapConnection *conn;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!sess || !conn || !address)
+	conn = flap_connection_findbygroup(od, SNAC_FAMILY_USERLOOKUP);
+
+	if (!od || !conn || !address)
 		return -EINVAL;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+strlen(address))))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+strlen(address));
 
-	snacid = aim_cachesnac(sess, 0x000a, 0x0002, 0x0000, strdup(address), strlen(address)+1);
-	aim_putsnac(&fr->data, 0x000a, 0x0002, 0x0000, snacid);
-	
-	aimbs_putstr(&fr->data, address); 
+	snacid = aim_cachesnac(od, 0x000a, 0x0002, 0x0000, strdup(address), strlen(address)+1);
+	aim_putsnac(&frame->data, 0x000a, 0x0002, 0x0000, snacid);
 
-	aim_tx_enqueue(sess, fr);
+	byte_stream_putstr(&frame->data, address);
+
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -84,7 +86,7 @@
  * Subtype 0x0003
  *
  */
-static int reply(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int reply(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int j = 0, m, ret = 0;
 	aim_tlvlist_t *tlvlist;
@@ -93,29 +95,30 @@
 	aim_snac_t *snac2;
 	char *searchaddr = NULL;
 
-	if ((snac2 = aim_remsnac(sess, snac->id)))
+	if ((snac2 = aim_remsnac(od, snac->id)))
 		searchaddr = (char *)snac2->data;
 
 	tlvlist = aim_tlvlist_read(bs);
 	m = aim_tlvlist_count(&tlvlist);
 
 	/* XXX uhm.
-	 * This is the only place that uses something other than 1 for the 3rd 
+	 * This is the only place that uses something other than 1 for the 3rd
 	 * parameter to aim_tlv_gettlv_whatever().
 	 */
-	while ((cur = aim_tlv_getstr(tlvlist, 0x0001, j+1)) && j < m) {
+	while ((cur = aim_tlv_getstr(tlvlist, 0x0001, j+1)) && j < m)
+	{
 		buf = realloc(buf, (j+1) * (MAXSNLEN+1));
 
 		strncpy(&buf[j * (MAXSNLEN+1)], cur, MAXSNLEN);
 		free(cur);
 
-		j++; 
+		j++;
 	}
 
 	aim_tlvlist_free(&tlvlist);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, searchaddr, j, buf);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, searchaddr, j, buf);
 
 	/* XXX freesnac()? */
 	if (snac2)
@@ -127,20 +130,20 @@
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0001)
-		return error(sess, mod, rx, snac, bs);
+		return error(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0003)
-		return reply(sess, mod, rx, snac, bs);
+		return reply(od, conn, mod, frame, snac, bs);
 
 	return 0;
 }
 
-faim_internal int search_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+search_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0x000a;
 	mod->version = 0x0001;
 	mod->toolid = 0x0110;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/oscar/flap_connection.c	Fri Apr 07 05:10:56 2006 +0000
@@ -0,0 +1,815 @@
+/*
+ * Gaim'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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "oscar.h"
+
+#include "eventloop.h"
+
+#ifndef _WIN32
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#ifdef _WIN32
+#include "win32dep.h"
+#endif
+
+/**
+ * This sends a channel 1 SNAC containing the FLAP version.
+ * The FLAP version is sent by itself at the beginning of every
+ * connection to a FLAP server.  It is always the very first
+ * packet sent by both the server and the client after the SYN,
+ * SYN/ACK, ACK handshake.
+ */
+void
+flap_connection_send_version(OscarData *od, FlapConnection *conn)
+{
+	FlapFrame *frame;
+
+	frame = flap_frame_new(od, 0x01, 4);
+	byte_stream_put32(&frame->data, 0x00000001);
+	flap_connection_send(conn, frame);
+}
+
+/**
+ * This sends a channel 1 SNAC containing the FLAP version and
+ * the authentication cookie.  This is sent when connecting to
+ * any FLAP server after the initial connection to the auth
+ * server.  It is always the very first packet sent by both the
+ * server and the client after the SYN, SYN/ACK, ACK handshake.
+ */
+void
+flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy)
+{
+	FlapFrame *frame;
+	aim_tlvlist_t *tl = NULL;
+
+	frame = flap_frame_new(od, 0x01, 4 + 2 + 2 + length);
+	byte_stream_put32(&frame->data, 0x00000001);
+	aim_tlvlist_add_raw(&tl, 0x0006, length, chipsahoy);
+	aim_tlvlist_write(&frame->data, &tl);
+	aim_tlvlist_free(&tl);
+
+	flap_connection_send(conn, frame);
+}
+
+/**
+ * This sends an empty channel 4 SNAC.  This is sent to signify
+ * that we're logging off.  This shouldn't really be necessary--
+ * usually the AIM server will detect that the TCP connection has
+ * been destroyed--but it's good practice.
+ */
+static void
+flap_connection_send_close(OscarData *od, FlapConnection *conn)
+{
+	FlapFrame *frame;
+
+	frame = flap_frame_new(od, 0x04, 0);
+	flap_connection_send(conn, frame);
+}
+
+/**
+ * This sends an empty channel 5 SNAC.  This is used as a keepalive
+ * packet in FLAP connections.  WinAIM 4.x and higher send these
+ * _every minute_ to keep the connection alive.
+ */
+void
+flap_connection_send_keepalive(OscarData *od, FlapConnection *conn)
+{
+	FlapFrame *frame;
+
+	frame = flap_frame_new(od, 0x05, 0);
+	flap_connection_send(conn, frame);
+
+	/* clean out SNACs over 60sec old */
+	aim_cleansnacs(od, 60);
+}
+
+/**
+ * Allocate a new empty connection structure.
+ *
+ * @param od The oscar session associated with this connection.
+ * @param type Type of connection to create
+ *
+ * @return Returns the new connection structure.
+ */
+FlapConnection *
+flap_connection_new(OscarData *od, int type)
+{
+	FlapConnection *conn;
+
+	conn = g_new0(FlapConnection, 1);
+	conn->od = od;
+	conn->buffer_outgoing = gaim_circ_buffer_new(0);
+	conn->inside = g_new0(aim_conn_inside_t, 1);
+	conn->fd = -1;
+	conn->subtype = -1;
+	conn->type = type;
+
+	od->oscar_connections = g_list_prepend(od->oscar_connections, conn);
+
+	return conn;
+}
+
+/**
+ * Clone a FlapConnection.
+ *
+ * A new connection is allocated, and the values are filled in
+ * appropriately.
+ *
+ * @param od The session containing this connection.
+ * @param src The connection to clone.
+ * @return Returns a pointer to the new FlapConnection, or %NULL on error.
+ */
+FlapConnection *
+flap_connection_clone(OscarData *od, FlapConnection *src)
+{
+	FlapConnection *conn;
+
+	conn = flap_connection_new(od, src->type);
+	conn->fd = src->fd;
+	conn->type = src->type;
+	conn->subtype = src->subtype;
+	conn->seqnum = src->seqnum;
+	conn->internal = src->internal;
+	conn->lastactivity = src->lastactivity;
+
+	if (src->inside != NULL)
+	{
+		/*
+		 * XXX should clone this section as well, but since currently
+		 * this function only gets called for some of that rendezvous
+		 * crap, and not on SNAC connections, its probably okay for
+		 * now.
+		 *
+		 */
+	}
+
+	return conn;
+}
+
+/**
+ * Close (but not free) a connection.
+ *
+ * This leaves everything untouched except for setting the fd
+ * to -1 (used to recognize dead connections).
+ *
+ * @param conn The connection to close.
+ */
+void
+flap_connection_close(OscarData *od, FlapConnection *conn)
+{
+	if (conn->fd == -1)
+		return;
+
+	if (conn->type == SNAC_FAMILY_LOCATE)
+		flap_connection_send_close(od, conn);
+
+	close(conn->fd);
+}
+
+static void
+flap_connection_destroy_snacgroups(struct snacgroup *head)
+{
+	struct snacgroup *sg;
+	for (sg = head; sg; )
+	{
+		struct snacgroup *tmp;
+
+		tmp = sg->next;
+		free(sg);
+		sg = tmp;
+	}
+}
+
+static void
+flap_connection_destroy_rates(struct rateclass *head)
+{
+	struct rateclass *rc;
+
+	for (rc = head; rc; )
+	{
+		struct rateclass *tmp;
+		struct snacpair *sp;
+
+		tmp = rc->next;
+
+		for (sp = rc->members; sp; ) {
+			struct snacpair *tmpsp;
+
+			tmpsp = sp->next;
+			free(sp);
+			sp = tmpsp;
+		}
+		free(rc);
+
+		rc = tmp;
+	}
+}
+
+static gboolean
+flap_connection_destroy_cb(gpointer data)
+{
+	FlapConnection *conn;
+
+	conn = data;
+
+	gaim_debug_info("oscar", "Destroying oscar connection of "
+			"type 0x%04hx\n", conn->type);
+
+	flap_connection_close(conn->od, conn);
+
+	if (conn->watcher_incoming != 0)
+		gaim_input_remove(conn->watcher_incoming);
+	if (conn->watcher_outgoing != 0)
+		gaim_input_remove(conn->watcher_outgoing);
+	g_free(conn->buffer_incoming.data.data);
+	gaim_circ_buffer_destroy(conn->buffer_outgoing);
+
+	/*
+	 * Free conn->internal, if necessary
+	 */
+	if (conn->type == SNAC_FAMILY_CHAT)
+		flap_connection_destroy_chat(conn->od, conn);
+
+	if (conn->inside != NULL)
+	{
+		aim_conn_inside_t *inside = (aim_conn_inside_t *)conn->inside;
+
+		flap_connection_destroy_snacgroups(inside->groups);
+		flap_connection_destroy_rates(inside->rates);
+
+		free(inside);
+	}
+
+	conn->od->oscar_connections = g_list_remove(conn->od->oscar_connections, conn);
+
+	g_free(conn);
+
+	return FALSE;
+}
+
+void
+flap_connection_destroy(FlapConnection *conn)
+{
+	if (conn->destroy_timeout != 0)
+		gaim_timeout_remove(conn->destroy_timeout);
+	flap_connection_destroy_cb(conn);
+}
+
+/**
+ * Schedule Gaim to destroy the given FlapConnection as soon as we
+ * return control back to the program's main loop.  We must do this
+ * if we want to destroy the connection but we are still using it
+ * for some reason.
+ */
+void
+flap_connection_schedule_destroy(FlapConnection *conn)
+{
+	if (conn->destroy_timeout != 0)
+		/* Already taken care of */
+		return;
+
+	gaim_debug_info("oscar", "Scheduling destruction of FLAP "
+			"connection of type 0x%04hx\n", conn->type);
+	conn->destroy_timeout = gaim_timeout_add(0, flap_connection_destroy_cb, conn);
+}
+
+/**
+ * In OSCAR, every connection has a set of SNAC groups associated
+ * with it.  These are the groups that you can send over this connection
+ * without being guaranteed a "Not supported" SNAC error.
+ *
+ * The grand theory of things says that these associations transcend
+ * what libfaim calls "connection types" (conn->type).  You can probably
+ * see the elegance here, but since I want to revel in it for a bit, you
+ * get to hear it all spelled out.
+ *
+ * So let us say that you have your core BOS connection running.  One
+ * of your modules has just given you a SNAC of the group 0x0004 to send
+ * you.  Maybe an IM destined for some twit in Greenland.  So you start
+ * at the top of your connection list, looking for a connection that
+ * claims to support group 0x0004.  You find one.  Why, that neat BOS
+ * connection of yours can do that.  So you send it on its way.
+ *
+ * Now, say, that fellow from Greenland has friends and they all want to
+ * meet up with you in a lame chat room.  This has landed you a SNAC
+ * in the family 0x000e and you have to admit you're a bit lost.  You've
+ * searched your connection list for someone who wants to make your life
+ * easy and deliver this SNAC for you, but there isn't one there.
+ *
+ * Here comes the good bit.  Without even letting anyone know, particularly
+ * the module that decided to send this SNAC, and definitely not that twit
+ * in Greenland, you send out a service request.  In this request, you have
+ * marked the need for a connection supporting group 0x000e.  A few seconds
+ * later, you receive a service redirect with an IP address and a cookie in
+ * it.  Great, you say.  Now I have something to do.  Off you go, making
+ * that connection.  One of the first things you get from this new server
+ * is a message saying that indeed it does support the group you were looking
+ * for.  So you continue and send rate confirmation and all that.
+ *
+ * Then you remember you had that SNAC to send, and now you have a means to
+ * do it, and you do, and everyone is happy.  Except the Greenlander, who is
+ * still stuck in the bitter cold.
+ *
+ * Oh, and this is useful for building the Migration SNACs, too.  In the
+ * future, this may help convince me to implement rate limit mitigation
+ * for real.  We'll see.
+ *
+ * Just to make me look better, I'll say that I've known about this great
+ * scheme for quite some time now.  But I still haven't convinced myself
+ * to make libfaim work that way.  It would take a fair amount of effort,
+ * and probably some client API changes as well.  (Whenever I don't want
+ * to do something, I just say it would change the client API.  Then I
+ * instantly have a couple of supporters of not doing it.)
+ *
+ * Generally, addgroup is only called by the internal handling of the
+ * server ready SNAC.  So if you want to do something before that, you'll
+ * have to be more creative.  That is done rather early, though, so I don't
+ * think you have to worry about it.  Unless you're me.  I care deeply
+ * about such inane things.
+ *
+ */
+void
+flap_connection_addgroup(FlapConnection *conn, guint16 group)
+{
+	aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
+	struct snacgroup *sg;
+
+	sg = g_new0(struct snacgroup, 1);
+
+	gaim_debug_misc("oscar", "Adding group 0x%04x to connection "
+			"of type 0x%04hx\n", group, conn->type);
+	sg->group = group;
+
+	sg->next = ins->groups;
+	ins->groups = sg;
+}
+
+/**
+ * Find a FlapConnection that supports the given oscar
+ * family.
+ *
+ * TODO: This should be implemented to use a hash table.
+ */
+FlapConnection *
+flap_connection_findbygroup(OscarData *od, guint16 group)
+{
+	GList *cur;
+
+	for (cur = od->oscar_connections; cur != NULL; cur = cur->next)
+	{
+		FlapConnection *conn;
+		aim_conn_inside_t *ins;
+		struct snacgroup *sg;
+
+		conn = cur->data;
+		ins = (aim_conn_inside_t *)conn->inside;
+
+		for (sg = ins->groups; sg != NULL; sg = sg->next)
+		{
+			if (sg->group == group)
+				return conn;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * Locates a connection of the specified type in the
+ * specified session.
+ *
+ * TODO: Use flap_connection_findbygroup everywhere and get rid of this.
+ *
+ * @param od The session to search.
+ * @param type The type of connection to look for.
+ *
+ * @return Returns the first connection found of the given target type,
+ *         or NULL if none could be found.
+ */
+FlapConnection *
+flap_connection_getbytype(OscarData *od, int type)
+{
+	GList *cur;
+
+	for (cur = od->oscar_connections; cur != NULL; cur = cur->next)
+	{
+		FlapConnection *conn;
+		conn = cur->data;
+		if ((conn->type == type) && (conn->connected))
+			return conn;
+	}
+
+	return NULL;
+}
+
+FlapConnection *
+flap_connection_getbytype_all(OscarData *od, int type)
+{
+	GList *cur;
+
+	for (cur = od->oscar_connections; cur; cur = cur->next)
+	{
+		FlapConnection *conn;
+		conn = cur->data;
+		if (conn->type == type)
+			return conn;
+	}
+
+	return NULL;
+}
+
+/**
+ * Allocate a new FLAP frame.
+ *
+ * @param channel The FLAP channel.  This is almost always 2.
+ */
+FlapFrame *
+flap_frame_new(OscarData *od, guint16 channel, int datalen)
+{
+	FlapFrame *frame;
+
+	frame = g_new0(FlapFrame, 1);
+	frame->channel = channel;
+
+	if (datalen > 0)
+	{
+		guint8 *data;
+		data = g_malloc(datalen);
+		byte_stream_init(&frame->data, data, datalen);
+	}
+
+	return frame;
+}
+
+/**
+ * Free a FlapFrame
+ *
+ * @param frame The frame to free.
+ * @return -1 on error; 0 on success.
+ */
+static void
+flap_frame_destroy(FlapFrame *frame)
+{
+	free(frame->data.data);
+	free(frame);
+
+	return;
+}
+
+static void
+parse_snac(OscarData *od, FlapConnection *conn, FlapFrame *frame)
+{
+	aim_module_t *cur;
+	aim_modsnac_t snac;
+
+	if (byte_stream_empty(&frame->data) < 10)
+		return;
+
+	snac.family = byte_stream_get16(&frame->data);
+	snac.subtype = byte_stream_get16(&frame->data);
+	snac.flags = byte_stream_get16(&frame->data);
+	snac.id = byte_stream_get32(&frame->data);
+
+	/* SNAC flags are apparently uniform across all SNACs, so we handle them here */
+	if (snac.flags & 0x0001) {
+		/*
+		 * This means the SNAC will be followed by another SNAC with
+		 * related information.  We don't need to do anything about
+		 * this here.
+		 */
+	}
+	if (snac.flags & 0x8000) {
+		/*
+		 * This packet contains the version of the family that this SNAC is
+		 * in.  You get this when your SSI module is version 2 or higher.
+		 * For now we have no need for this, but you could always save
+		 * it as a part of aim_modnsac_t, or something.  The format is...
+		 * 2 byte length of total mini-header (which is 6 bytes), then TLV
+		 * of  type 0x0001, length 0x0002, value is the 2 byte version
+		 * number
+		 */
+		byte_stream_advance(&frame->data, byte_stream_get16(&frame->data));
+	}
+
+	for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {
+
+		if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
+				(cur->family != snac.family))
+			continue;
+
+		if (cur->snachandler(od, conn, cur, frame, &snac, &frame->data))
+			return;
+	}
+}
+
+static void
+parse_fakesnac(OscarData *od, FlapConnection *conn, FlapFrame *frame, guint16 family, guint16 subtype)
+{
+	aim_module_t *cur;
+	aim_modsnac_t snac;
+
+	snac.family = family;
+	snac.subtype = subtype;
+	snac.flags = snac.id = 0;
+
+	for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {
+
+		if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
+				(cur->family != snac.family))
+			continue;
+
+		if (cur->snachandler(od, conn, cur, frame, &snac, &frame->data))
+			return;
+	}
+}
+
+static void
+parse_flap_ch4(OscarData *od, FlapConnection *conn, FlapFrame *frame)
+{
+	aim_tlvlist_t *tlvlist;
+	char *msg = NULL;
+	guint16 code = 0;
+	aim_rxcallback_t userfunc;
+
+	if (byte_stream_empty(&frame->data) == 0) {
+		/* XXX should do something with this */
+		return;
+	}
+
+	/* Used only by the older login protocol */
+	/* XXX remove this special case? */
+	if (conn->type == SNAC_FAMILY_AUTH)
+	{
+		parse_fakesnac(od, conn, frame, 0x0017, 0x0003);
+		return;
+	}
+
+	tlvlist = aim_tlvlist_read(&frame->data);
+
+	if (aim_tlv_gettlv(tlvlist, 0x0009, 1))
+		code = aim_tlv_get16(tlvlist, 0x0009, 1);
+
+	if (aim_tlv_gettlv(tlvlist, 0x000b, 1))
+		msg = aim_tlv_getstr(tlvlist, 0x000b, 1);
+
+	if ((userfunc = aim_callhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
+		userfunc(od, conn, frame, code, msg);
+
+	aim_tlvlist_free(&tlvlist);
+
+	free(msg);
+}
+
+/**
+ * Takes a new incoming FLAP frame and sends it to the appropriate
+ * handler function to be parsed.
+ */
+static void
+parse_flap(OscarData *od, FlapConnection *conn, FlapFrame *frame)
+{
+	if (frame->channel == 0x01) {
+		guint32 flap_version = byte_stream_get32(&frame->data);
+		if (flap_version != 0x00000001)
+		{
+				/* Error! */
+				gaim_debug_warning("oscar", "Expecting FLAP version "
+					"0x00000001 but received FLAP version %08lx.  Closing connection.\n",
+					flap_version);
+				flap_connection_schedule_destroy(conn);
+		}
+		else
+			conn->connected = TRUE;
+
+	} else if (frame->channel == 0x02) {
+		parse_snac(od, conn, frame);
+
+	} else if (frame->channel == 0x04) {
+		parse_flap_ch4(od, conn, frame);
+
+	} else if (frame->channel == 0x05) {
+		/* TODO: Reset our keepalive watchdog? */
+
+	}
+}
+
+/**
+ * Read in all available data on the socket for a given connection.
+ * All complete FLAPs handled immedate after they're received.
+ * Incomplete FLAP data is stored locally and appended to the next
+ * time this callback is triggered.
+ */
+void
+flap_connection_recv_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	FlapConnection *conn;
+	ssize_t read;
+	guint8 header[6];
+
+	conn = data;
+
+	/* Read data until we run out of data and break out of the loop */
+	while (TRUE)
+	{
+		/* Start reading a new FLAP */
+		if (conn->buffer_incoming.data.data == NULL)
+		{
+			/* Peek at the first 6 bytes to get the length */
+			read = recv(conn->fd, &header, 6, MSG_PEEK);
+
+			/* Check if the FLAP server closed the connection */
+			if (read == 0)
+			{
+				/* TODO: Print an error?  Server closed connection. */
+				flap_connection_schedule_destroy(conn);
+				break;
+			}
+
+			/* If there was an error then close the connection */
+			if (read == -1)
+			{
+				if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+					/* No worries */
+					break;
+
+				/* Error! */
+				/* TODO: Print an error?  Lost connection with server. */
+				flap_connection_schedule_destroy(conn);
+				break;
+			}
+
+			/* If we don't even have a complete FLAP header then do nothing */
+			if (read < 6)
+				break;
+
+			/* Read the first 6 bytes (the FLAP header) */
+			read = recv(conn->fd, &header, 6, 0);
+
+			/* All FLAP frames must start with the byte 0x2a */
+			if (aimutil_get8(&header[0]) != 0x2a)
+			{
+				flap_connection_schedule_destroy(conn);
+				break;
+			}
+
+			/* Initialize a new temporary FlapFrame for incoming data */
+			conn->buffer_incoming.channel = aimutil_get8(&header[1]);
+			conn->buffer_incoming.seqnum = aimutil_get16(&header[2]);
+			conn->buffer_incoming.data.len = aimutil_get16(&header[4]);
+			conn->buffer_incoming.data.data = g_new(guint8, conn->buffer_incoming.data.len);
+			conn->buffer_incoming.data.offset = 0;
+		}
+
+		if (conn->buffer_incoming.data.len - conn->buffer_incoming.data.offset)
+		{
+			/* Read data into the temporary FlapFrame until it is complete */
+			read = recv(conn->fd,
+						&conn->buffer_incoming.data.data[conn->buffer_incoming.data.offset],
+						conn->buffer_incoming.data.len - conn->buffer_incoming.data.offset,
+						0);
+
+			/* Check if the FLAP server closed the connection */
+			if (read == 0)
+			{
+				flap_connection_schedule_destroy(conn);
+				break;
+			}
+
+			if (read == -1)
+			{
+				if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+					/* No worries */
+					break;
+
+				/* Error! */
+				/* TODO: Print an error?  Lost connection with server. */
+				flap_connection_schedule_destroy(conn);
+				break;
+			}
+
+			conn->buffer_incoming.data.offset += read;
+			if (conn->buffer_incoming.data.offset < conn->buffer_incoming.data.len)
+				/* Waiting for more data to arrive */
+				break;
+		}
+
+		/* We have a complete FLAP!  Handle it and continue reading */
+		byte_stream_rewind(&conn->buffer_incoming.data);
+		parse_flap(conn->od, conn, &conn->buffer_incoming);
+		conn->lastactivity = time(NULL);
+
+		g_free(conn->buffer_incoming.data.data);
+		conn->buffer_incoming.data.data = NULL;
+	}
+}
+
+static void
+send_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	FlapConnection *conn;
+	int writelen, ret;
+
+	conn = data;
+	writelen = gaim_circ_buffer_get_max_read(conn->buffer_outgoing);
+
+	if (writelen == 0)
+	{
+		gaim_input_remove(conn->watcher_outgoing);
+		conn->watcher_outgoing = 0;
+		return;
+	}
+
+	ret = send(conn->fd, conn->buffer_outgoing->outptr, writelen, 0);
+	if (ret <= 0)
+	{
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			/* No worries */
+			return;
+
+		/* Error! */
+		flap_connection_schedule_destroy(conn);
+		return;
+	}
+
+	gaim_circ_buffer_mark_read(conn->buffer_outgoing, ret);
+}
+
+static void
+flap_connection_send_byte_stream(ByteStream *bs, FlapConnection *conn, size_t count)
+{
+	if (conn == NULL)
+		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 == 0)
+		return;
+
+	/* Add everything to our outgoing buffer */
+	gaim_circ_buffer_append(conn->buffer_outgoing, bs->data, count);
+
+	/* If we haven't already started writing stuff, then start the cycle */
+	if (conn->watcher_outgoing == 0)
+	{
+		conn->watcher_outgoing = gaim_input_add(conn->fd,
+				GAIM_INPUT_WRITE, send_cb, conn);
+		send_cb(conn, conn->fd, 0);
+	}
+}
+
+static void
+sendframe_flap(FlapConnection *conn, FlapFrame *frame)
+{
+	ByteStream bs;
+	int payloadlen, bslen;
+
+	payloadlen = byte_stream_curpos(&frame->data);
+
+	byte_stream_init(&bs, malloc(6 + payloadlen), 6 + payloadlen);
+
+	/* FLAP header */
+	byte_stream_put8(&bs, 0x2a);
+	byte_stream_put8(&bs, frame->channel);
+	byte_stream_put16(&bs, frame->seqnum);
+	byte_stream_put16(&bs, payloadlen);
+
+	/* Payload */
+	byte_stream_rewind(&frame->data);
+	byte_stream_putbs(&bs, &frame->data, payloadlen);
+
+	bslen = byte_stream_curpos(&bs);
+	byte_stream_rewind(&bs);
+	flap_connection_send_byte_stream(&bs, conn, bslen);
+
+	free(bs.data); /* XXX byte_stream_free */
+}
+
+void
+flap_connection_send(FlapConnection *conn, FlapFrame *frame)
+{
+	frame->seqnum = ++(conn->seqnum);
+	sendframe_flap(conn, frame);
+	flap_frame_destroy(frame);
+}
+
--- a/src/protocols/oscar/misc.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/misc.c	Fri Apr 07 05:10:56 2006 +0000
@@ -39,75 +39,75 @@
  * back to the single.  I don't see any advantage to doing it either way.
  *
  */
-faim_internal int aim_genericreq_n(OscarSession *sess, OscarConnection *conn, guint16 family, guint16 subtype)
+int
+aim_genericreq_n(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid = 0x00000000;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10);
 
-	aim_putsnac(&fr->data, family, subtype, 0x0000, snacid);
+	aim_putsnac(&frame->data, family, subtype, 0x0000, snacid);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
-faim_internal int aim_genericreq_n_snacid(OscarSession *sess, OscarConnection *conn, guint16 family, guint16 subtype)
+int
+aim_genericreq_n_snacid(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10);
 
-	snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, family, subtype, 0x0000, snacid);
+	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
+	aim_putsnac(&frame->data, family, subtype, 0x0000, snacid);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
-faim_internal int aim_genericreq_l(OscarSession *sess, OscarConnection *conn, guint16 family, guint16 subtype, guint32 *longdata)
+int
+aim_genericreq_l(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint32 *longdata)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
 	if (!longdata)
-		return aim_genericreq_n(sess, conn, family, subtype);
+		return aim_genericreq_n(od, conn, family, subtype);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+4);
 
-	snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
 
-	aim_putsnac(&fr->data, family, subtype, 0x0000, snacid);
-	aimbs_put32(&fr->data, *longdata);
+	aim_putsnac(&frame->data, family, subtype, 0x0000, snacid);
+	byte_stream_put32(&frame->data, *longdata);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
 
-faim_internal int aim_genericreq_s(OscarSession *sess, OscarConnection *conn, guint16 family, guint16 subtype, guint16 *shortdata)
+int
+aim_genericreq_s(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 *shortdata)
 {
-	FlapFrame *fr;
+	FlapFrame *frame;
 	aim_snacid_t snacid;
 
 	if (!shortdata)
-		return aim_genericreq_n(sess, conn, family, subtype);
+		return aim_genericreq_n(od, conn, family, subtype);
 
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2)))
-		return -ENOMEM;
+	frame = flap_frame_new(od, 0x02, 10+2);
 
-	snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
 
-	aim_putsnac(&fr->data, family, subtype, 0x0000, snacid);
-	aimbs_put16(&fr->data, *shortdata);
+	aim_putsnac(&frame->data, family, subtype, 0x0000, snacid);
+	byte_stream_put16(&frame->data, *shortdata);
 
-	aim_tx_enqueue(sess, fr);
+	flap_connection_send(conn, frame);
 
 	return 0;
 }
@@ -116,20 +116,21 @@
  * Should be generic enough to handle the errors for all groups.
  *
  */
-static int generror(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+generror(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
 	int ret = 0;
 	int error = 0;
 	aim_rxcallback_t userfunc;
 	aim_snac_t *snac2;
 
-	snac2 = aim_remsnac(sess, snac->id);
+	snac2 = aim_remsnac(od, snac->id);
 
-	if (aim_bstream_empty(bs))
-		error = aimbs_get16(bs);
+	if (byte_stream_empty(bs))
+		error = byte_stream_get16(bs);
 
-	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-		ret = userfunc(sess, rx, error, snac2 ? snac2->data : NULL);
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, error, snac2 ? snac2->data : NULL);
 
 	if (snac2)
 		free(snac2->data);
@@ -138,24 +139,24 @@
 	return ret;
 }
 
-static int snachandler(OscarSession *sess, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
+static int
+snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-
 	if (snac->subtype == 0x0001)
-		return generror(sess, mod, rx, snac, bs);
+		return generror(od, conn, mod, frame, snac, bs);
 	else if ((snac->family == 0xffff) && (snac->subtype == 0xffff)) {
 		aim_rxcallback_t userfunc;
 
-		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
-			return userfunc(sess, rx);
+		if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+			return userfunc(od, conn, frame);
 	}
 
 	return 0;
 }
 
-faim_internal int misc_modfirst(OscarSession *sess, aim_module_t *mod)
+int
+misc_modfirst(OscarData *od, aim_module_t *mod)
 {
-
 	mod->family = 0xffff;
 	mod->version = 0x0000;
 	mod->flags = AIM_MODFLAG_MULTIFAMILY;
--- a/src/protocols/oscar/msgcookie.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/msgcookie.c	Fri Apr 07 05:10:56 2006 +0000
@@ -40,30 +40,30 @@
  * ->addtime of the found structure; otherwise adds the given cookie
  * to the cache
  *
- * @param sess session to add to
+ * @param od session to add to
  * @param cookie pointer to struct to append
  * @return returns -1 on error, 0 on append, 1 on update.  the cookie you pass
  *         in may be free'd, so don't count on its value after calling this!
  */
-faim_internal int aim_cachecookie(OscarSession *sess, IcbmCookie *cookie)
+int aim_cachecookie(OscarData *od, IcbmCookie *cookie)
 {
 	IcbmCookie *newcook;
 
-	if (!sess || !cookie)
+	if (!od || !cookie)
 		return -EINVAL;
 
-	newcook = aim_checkcookie(sess, cookie->cookie, cookie->type);
+	newcook = aim_checkcookie(od, cookie->cookie, cookie->type);
 
 	if (newcook == cookie) {
 		newcook->addtime = time(NULL);
 		return 1;
 	} else if (newcook)
-		aim_cookie_free(sess, newcook);
+		aim_cookie_free(od, newcook);
 
 	cookie->addtime = time(NULL);
 
-	cookie->next = sess->msgcookies;
-	sess->msgcookies = cookie;
+	cookie->next = od->msgcookies;
+	od->msgcookies = cookie;
 
 	return 0;
 }
@@ -73,19 +73,19 @@
  *
  * takes a cookie string and a cookie type and finds the cookie struct associated with that duple, removing it from the cookie list ikn the process.
  *
- * @param sess session to grab cookie from
+ * @param od session to grab cookie from
  * @param cookie cookie string to look for
  * @param type cookie type to look for
  * @return if found, returns the struct; if none found (or on error), returns NULL:
  */
-faim_internal IcbmCookie *aim_uncachecookie(OscarSession *sess, guint8 *cookie, int type)
+IcbmCookie *aim_uncachecookie(OscarData *od, guint8 *cookie, int type)
 {
 	IcbmCookie *cur, **prev;
 
-	if (!cookie || !sess->msgcookies)
+	if (!cookie || !od->msgcookies)
 		return NULL;
 
-	for (prev = &sess->msgcookies; (cur = *prev); ) {
+	for (prev = &od->msgcookies; (cur = *prev); ) {
 		if ((cur->type == type) &&
 				(memcmp(cur->cookie, cookie, 8) == 0)) {
 			*prev = cur->next;
@@ -106,15 +106,14 @@
  * @return returns NULL on error, a pointer to the newly-allocated
  *         cookie on success.
  */
-faim_internal IcbmCookie *aim_mkcookie(guint8 *c, int type, void *data)
+IcbmCookie *aim_mkcookie(guint8 *c, int type, void *data)
 {
 	IcbmCookie *cookie;
 
 	if (!c)
 		return NULL;
 
-	if (!(cookie = calloc(1, sizeof(IcbmCookie))))
-		return NULL;
+	cookie = calloc(1, sizeof(IcbmCookie));
 
 	cookie->data = data;
 	cookie->type = type;
@@ -126,21 +125,21 @@
 /**
  * aim_checkcookie - check to see if a cookietuple has been cached
  *
- * @param sess session to check for the cookie in
+ * @param od session to check for the cookie in
  * @param cookie pointer to the cookie string array
  * @param type type of the cookie to look for
  * @return returns a pointer to the cookie struct (still in the list)
  *         on success; returns NULL on error/not found
  */
 
-faim_internal IcbmCookie *aim_checkcookie(OscarSession *sess, const guint8 *cookie, int type)
+IcbmCookie *aim_checkcookie(OscarData *od, const guint8 *cookie, int type)
 {
 	IcbmCookie *cur;
 
-	for (cur = sess->msgcookies; cur; cur = cur->next) {
+	for (cur = od->msgcookies; cur; cur = cur->next) {
 		if ((cur->type == type) &&
 				(memcmp(cur->cookie, cookie, 8) == 0))
-			return cur; 
+			return cur;
 	}
 
 	return NULL;
@@ -150,23 +149,23 @@
  * aim_cookie_free - free an IcbmCookie struct
  *
  * this function removes the cookie *cookie from the list of cookies
- * in sess, and then frees all memory associated with it. including
+ * in od, and then frees all memory associated with it. including
  * its data! if you want to use the private data after calling this,
  * make sure you copy it first.
  *
- * @param sess session to remove the cookie from
+ * @param od session to remove the cookie from
  * @param cookie the address of a pointer to the cookie struct to remove
  * @return returns -1 on error, 0 on success.
  *
  */
-faim_internal int aim_cookie_free(OscarSession *sess, IcbmCookie *cookie)
+int aim_cookie_free(OscarData *od, IcbmCookie *cookie)
 {
 	IcbmCookie *cur, **prev;
 
-	if (!sess || !cookie)
+	if (!od || !cookie)
 		return -EINVAL;
 
-	for (prev = &sess->msgcookies; (cur = *prev); ) {
+	for (prev = &od->msgcookies; (cur = *prev); ) {
 		if (cur == cookie)
 			*prev = cur->next;
 		else
@@ -180,16 +179,16 @@
 }
 
 /* XXX I hate switch */
-faim_internal int aim_msgcookie_gettype(int reqclass)
+int aim_msgcookie_gettype(int type)
 {
 	/* XXX: hokey-assed. needs fixed. */
-	switch(reqclass) {
-	case AIM_CAPS_BUDDYICON: return AIM_COOKIETYPE_OFTICON;
-	case AIM_CAPS_TALK: return AIM_COOKIETYPE_OFTVOICE;
-	case AIM_CAPS_DIRECTIM: return AIM_COOKIETYPE_OFTIMAGE;
-	case AIM_CAPS_CHAT: return AIM_COOKIETYPE_CHAT;
-	case AIM_CAPS_GETFILE: return AIM_COOKIETYPE_OFTGET;
-	case AIM_CAPS_SENDFILE: return AIM_COOKIETYPE_OFTSEND;
+	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;
 	}
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/oscar/odc.c	Fri Apr 07 05:10:56 2006 +0000
@@ -0,0 +1,552 @@
+/*
+ * Gaim'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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* From the oscar PRPL */
+#include "oscar.h"
+#include "peer.h"
+
+/* From Gaim */
+#include "conversation.h"
+#include "imgstore.h"
+#include "util.h"
+
+/**
+ * Free any ODC related data and print a message to the conversation
+ * window based on conn->disconnect_reason.
+ */
+void
+peer_odc_close(PeerConnection *conn)
+{
+	const gchar *tmp;
+
+	if (conn->disconnect_reason == PEER_DISCONNECT_REMOTE_CLOSED)
+	{
+		tmp = _("Remote user closed the connection.");
+	}
+	else if (conn->disconnect_reason == PEER_DISCONNECT_REMOTE_REFUSED)
+	{
+		tmp = _("Remote user declined your request.");
+	}
+	else if (conn->disconnect_reason == PEER_DISCONNECT_LOST_CONNECTION)
+	{
+		tmp = _("Lost connection with remote user for an unknown reason.");
+	}
+	else if (conn->disconnect_reason == PEER_DISCONNECT_INVALID_DATA)
+	{
+		tmp = _("Received invalid data on connection.");
+	}
+	else if (conn->disconnect_reason == PEER_DISCONNECT_COULD_NOT_CONNECT)
+	{
+		tmp = _("Could not establish connection with remote user.");
+	}
+	else
+		/*
+		 * We shouldn't print a message for some disconnect_reasons.
+		 * Like PEER_DISCONNECT_LOCAL_CLOSED.
+		 */
+		tmp = NULL;
+
+	if (tmp != NULL)
+	{
+		GaimAccount *account;
+		GaimConversation *conv;
+
+		account = gaim_connection_get_account(conn->od->gc);
+		conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, conn->sn);
+		gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
+	}
+
+	if (conn->frame != NULL)
+	{
+		OdcFrame *frame;
+		frame = conn->frame;
+		g_free(frame->payload.data);
+		g_free(frame);
+	}
+}
+
+/**
+ * Write the given OdcFrame to a ByteStream and send it out
+ * on the established PeerConnection.
+ */
+static void
+peer_odc_send(PeerConnection *conn, OdcFrame *frame)
+{
+	GaimAccount *account;
+	const char *username;
+	size_t length;
+	ByteStream bs;
+
+	gaim_debug_info("oscar", "Outgoing ODC frame to %s with "
+		"type=0x%04x, flags=0x%04x, payload length=%u\n",
+		conn->sn, frame->type, frame->flags, frame->payload.len);
+
+	account = gaim_connection_get_account(conn->od->gc);
+	username = gaim_account_get_username(account);
+	memcpy(frame->sn, username, strlen(username));
+	memcpy(frame->cookie, conn->cookie, 8);
+
+	length = 76;
+	byte_stream_init(&bs, malloc(length + frame->payload.len),
+			length + frame->payload.len);
+	byte_stream_putraw(&bs, conn->magic, 4);
+	byte_stream_put16(&bs, length);
+	byte_stream_put16(&bs, frame->type);
+	byte_stream_put16(&bs, frame->subtype);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_putraw(&bs, frame->cookie, 8);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put32(&bs, frame->payload.len);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, frame->encoding);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, frame->flags);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_putraw(&bs, frame->sn, 32);
+	byte_stream_putraw(&bs, frame->payload.data, frame->payload.len);
+
+	peer_connection_send(conn, &bs);
+
+	free(bs.data);
+}
+
+/**
+ * Send a very basic ODC frame (which contains the cookie) so that the
+ * remote user can verify that we are the person they were expecting.
+ * If we made an outgoing connection to then remote user, then we send
+ * this immediately.  If the remote user connected to us, then we wait
+ * for the other person to send this to us, then we send one to them.
+ */
+void
+peer_odc_send_cookie(PeerConnection *conn)
+{
+	OdcFrame frame;
+
+	memset(&frame, 0, sizeof(OdcFrame));
+	frame.type = 0x0001;
+	frame.subtype = 0x0006;
+	frame.flags = 0x0060; /* Maybe this means "we're sending the cookie"? */
+
+	peer_odc_send(conn, &frame);
+}
+
+/**
+ * Send client-to-client typing notification over an established direct connection.
+ */
+void
+peer_odc_send_typing(PeerConnection *conn, GaimTypingState typing)
+{
+	OdcFrame frame;
+
+	memset(&frame, 0, sizeof(OdcFrame));
+	frame.type = 0x0001;
+	frame.subtype = 0x0006;
+	if (typing == GAIM_TYPING)
+		frame.flags = 0x0002 | 0x0008;
+	else if (typing == GAIM_TYPED)
+		frame.flags = 0x0002 | 0x0004;
+	else
+		frame.flags = 0x0002;
+
+	peer_odc_send(conn, &frame);
+}
+
+/**
+ * Send client-to-client IM over an established direct connection.
+ * To send a direct IM, call this just like you would aim_send_im.
+ *
+ * @param conn The already-connected ODC connection.
+ * @param msg Null-terminated string to send.
+ * @param len The length of the message to send, including binary data.
+ * @param encoding See the AIM_CHARSET_* defines in oscar.h
+ * @param autoreply TRUE if this is any auto-reply.
+ */
+void
+peer_odc_send_im(PeerConnection *conn, const char *msg, int len, int encoding, gboolean autoreply)
+{
+	OdcFrame frame;
+
+	g_return_if_fail(msg != NULL);
+	g_return_if_fail(len > 0);
+
+	memset(&frame, 0, sizeof(OdcFrame));
+	frame.type = 0x0001;
+	frame.subtype = 0x0006;
+	frame.payload.len = len;
+	frame.encoding = encoding;
+	frame.flags = autoreply;
+	byte_stream_init(&frame.payload, malloc(len), len);
+	byte_stream_putraw(&frame.payload, (guint8 *)msg, len);
+
+	peer_odc_send(conn, &frame);
+
+	g_free(frame.payload.data);
+}
+
+/**
+ * This is called after a direct IM has been received in its entirety.  This
+ * function is passed a long chunk of data which contains the IM with any
+ * data chunks (images) appended to it.
+ *
+ * This function rips out all the data chunks and creates an imgstore for
+ * each one.  In order to do this, it first goes through the IM and takes
+ * out all the IMG tags.  When doing so, it rewrites the original IMG tag
+ * with one compatible with the imgstore Gaim core code. For each one, we
+ * then read in chunks of data from the end of the message and actually
+ * create the img store using the given data.
+ *
+ * For somewhat easy reference, here's a sample message
+ * (without the whitespace and asterisks):
+ *
+ * <HTML><BODY BGCOLOR="#ffffff">
+ *     <FONT LANG="0">
+ *     This is a really stupid picture:<BR>
+ *     <IMG SRC="Sample.jpg" ID="1" WIDTH="283" HEIGHT="212" DATASIZE="9894"><BR>
+ *     Yeah it is<BR>
+ *     Here is another one:<BR>
+ *     <IMG SRC="Soap Bubbles.bmp" ID="2" WIDTH="256" HEIGHT="256" DATASIZE="65978">
+ *     </FONT>
+ * </BODY></HTML>
+ * <BINARY>
+ *     <DATA ID="1" SIZE="9894">datadatadatadata</DATA>
+ *     <DATA ID="2" SIZE="65978">datadatadatadata</DATA>
+ * </BINARY>
+ *
+ * TODO: I think this does bad things when receiving
+ *       multiple images in one IM.
+ */
+static void
+peer_odc_handle_payload(PeerConnection *conn, const char *msg, size_t len, int encoding, gboolean autoreply)
+{
+	OscarData *od;
+	GaimConnection *gc;
+	GaimAccount *account;
+	GaimMessageFlags imflags;
+	gchar *utf8;
+	GString *newmsg;
+	GSList *images;
+	const char *msgend, *binary;
+
+	od = conn->od;
+	gc = od->gc;
+	account = gaim_connection_get_account(gc);
+
+	imflags = 0;
+	newmsg = g_string_new("");
+	images = NULL;
+
+	msgend = msg + len;
+
+	if (autoreply)
+		imflags |= GAIM_MESSAGE_AUTO_RESP;
+
+	/* message has a binary trailer */
+	if ((binary = gaim_strcasestr(msg, "<binary>")))
+	{
+		GData *attribs;
+		const char *tmp, *start, *end, *last = NULL;
+
+		tmp = msg;
+
+		/* for each valid image tag... */
+		while (gaim_markup_find_tag("img", tmp, &start, &end, &attribs))
+		{
+			const char *id, *src, *datasize;
+			const char *data = NULL;
+			char *tag = NULL;
+			size_t size;
+			int imgid = 0;
+
+			/* update the location of the last img tag */
+			last = end;
+
+			/* grab attributes */
+			id       = g_datalist_get_data(&attribs, "id");
+			src      = g_datalist_get_data(&attribs, "src");
+			datasize = g_datalist_get_data(&attribs, "datasize");
+
+			/* if we have id & datasize, build the data tag */
+			if (id && datasize)
+				tag = g_strdup_printf("<data id=\"%s\" size=\"%s\">", id, datasize);
+
+			/* if we have a tag, find the start of the data */
+			if (tag && (data = gaim_strcasestr(binary, tag)))
+				data += strlen(tag);
+
+			g_free(tag);
+
+			/* check the data is here and store it */
+			if (data + (size = atoi(datasize)) <= msgend)
+				imgid = gaim_imgstore_add(data, size, src);
+
+			/* if we have a stored image... */
+			if (imgid) {
+				/* append the message up to the tag */
+				utf8 = gaim_plugin_oscar_decode_im_part(account, conn->sn,
+								encoding, 0x0000, tmp, start - tmp);
+				if (utf8 != NULL) {
+					newmsg = g_string_append(newmsg, utf8);
+					g_free(utf8);
+				}
+
+				/* write the new image tag */
+				g_string_append_printf(newmsg, "<IMG ID=\"%d\">", imgid);
+
+				/* and record the image number */
+				images = g_slist_append(images, GINT_TO_POINTER(imgid));
+			} else {
+				/* otherwise, copy up to the end of the tag */
+				utf8 = gaim_plugin_oscar_decode_im_part(account, conn->sn,
+								encoding, 0x0000, tmp, (end + 1) - tmp);
+				if (utf8 != NULL) {
+					newmsg = g_string_append(newmsg, utf8);
+					g_free(utf8);
+				}
+			}
+
+			/* clear the attribute list */
+			g_datalist_clear(&attribs);
+
+			/* continue from the end of the tag */
+			tmp = end + 1;
+		}
+
+		/* append any remaining message data (without the > :-)) */
+		if (last++ && (last < binary))
+			newmsg = g_string_append_len(newmsg, last, binary - last);
+
+		/* set the flag if we caught any images */
+		if (images)
+			imflags |= GAIM_MESSAGE_IMAGES;
+	} else {
+		utf8 = gaim_plugin_oscar_decode_im_part(account, conn->sn,
+						encoding, 0x0000, msg, len);
+		if (utf8 != NULL) {
+			g_string_append(newmsg, utf8);
+			g_free(utf8);
+		}
+	}
+
+	serv_got_im(gc, conn->sn, newmsg->str, imflags, time(NULL));
+
+	/* free the message */
+	g_string_free(newmsg, TRUE);
+
+	/* unref any images we allocated */
+	if (images) {
+		GSList *tmp;
+		int id;
+
+		for (tmp = images; tmp != NULL; tmp = tmp->next) {
+			id = GPOINTER_TO_INT(tmp->data);
+			gaim_imgstore_unref(id);
+		}
+
+		g_slist_free(images);
+	}
+}
+
+/**
+ * This is a gaim_input_add() watcher callback function for reading
+ * direct IM payload data.  "Payload data" is always an IM and
+ * maybe some embedded images or files or something.  The actual
+ * ODC frame is read using peer_connection_recv_cb().  We temporarily
+ * switch to this watcher callback ONLY to read the payload, and we
+ * switch back once we're done.
+ */
+static void
+peer_odc_recv_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	PeerConnection *conn;
+	OdcFrame *frame;
+	ByteStream *bs;
+	ssize_t read;
+
+	conn = data;
+	frame = conn->frame;
+	bs = &frame->payload;
+
+	/* Read data into the temporary buffer until it is complete */
+	read = recv(conn->fd,
+				&bs->data[bs->offset],
+				bs->len - bs->offset,
+				0);
+
+	/* Check if the remote user closed the connection */
+	if (read == 0)
+	{
+		peer_connection_destroy(conn, PEER_DISCONNECT_REMOTE_CLOSED);
+		return;
+	}
+
+	if (read == -1)
+	{
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			/* No worries */
+			return;
+
+		peer_connection_destroy(conn, PEER_DISCONNECT_LOST_CONNECTION);
+		return;
+	}
+
+	bs->offset += read;
+	if (bs->offset < bs->len)
+		/* Waiting for more data to arrive */
+		return;
+
+	/* We have a complete ODC/OFT frame!  Handle it and continue reading */
+	byte_stream_rewind(bs);
+	peer_odc_handle_payload(conn, (const char *)bs->data,
+			bs->len, frame->encoding, frame->flags & 0x0001);
+	g_free(bs->data);
+	bs->data = NULL;
+	g_free(frame);
+	conn->frame = NULL;
+
+	gaim_input_remove(conn->watcher_incoming);
+	conn->watcher_incoming = gaim_input_add(conn->fd,
+			GAIM_INPUT_READ, peer_connection_recv_cb, conn);
+}
+
+/**
+ * Handle an incoming OdcFrame.  If there is a payload associated
+ * with this frame, then we remove the old watcher and add the
+ * ODC watcher to read in the payload.
+ */
+void
+peer_odc_recv_frame(PeerConnection *conn, ByteStream *bs)
+{
+	GaimConnection *gc;
+	OdcFrame *frame;
+
+	gc = conn->od->gc;
+
+	frame = g_new0(OdcFrame, 1);
+	frame->type = byte_stream_get16(bs);
+	frame->subtype = byte_stream_get16(bs);
+	byte_stream_advance(bs, 2);
+	byte_stream_getrawbuf(bs, frame->cookie, 8);
+	byte_stream_advance(bs, 8);
+	frame->payload.len = byte_stream_get32(bs);
+	frame->encoding = byte_stream_get16(bs);
+	byte_stream_advance(bs, 4);
+	frame->flags = byte_stream_get16(bs);
+	byte_stream_advance(bs, 4);
+	byte_stream_getrawbuf(bs, frame->sn, 32);
+
+	gaim_debug_info("oscar", "Incoming ODC frame from %s with "
+			"type=0x%04x, flags=0x%04x, payload length=%u\n",
+			frame->sn, frame->type, frame->flags, frame->payload.len);
+
+	if (!conn->ready)
+	{
+		/*
+		 * We need to verify the cookie so that we know we are
+		 * connected to our friend and not a malicious middle man.
+		 */
+
+		GaimAccount *account;
+		GaimConversation *conv;
+
+		if (conn->flags & PEER_CONNECTION_FLAG_IS_INCOMING)
+		{
+			if (memcmp(conn->cookie, frame->cookie, 8))
+			{
+				/*
+				 * Oh no!  The user that connected to us did not send
+				 * the correct cookie!  They are not our friend.  Go try
+				 * to accept another connection?
+				 */
+				gaim_debug_info("oscar", "Received an incorrect cookie.  "
+					"Closing connection.\n");
+				peer_connection_destroy(conn, PEER_DISCONNECT_INVALID_DATA);
+				g_free(frame);
+				return;
+			}
+
+			/*
+			 * Ok, we know they are legit.  Now be courteous and
+			 * send them our cookie.  Note: This doesn't seem
+			 * to be necessary, but it also doesn't seem to hurt.
+			 */
+			peer_odc_send_cookie(conn);
+		}
+
+		conn->ready = TRUE;
+
+		/*
+		 * If they connected to us then close the listener socket
+		 * and send them our cookie.
+		 */
+		if (conn->listenerfd != -1)
+		{
+			close(conn->listenerfd);
+			conn->listenerfd = -1;
+		}
+
+		/* Tell the local user that we are connected */
+		account = gaim_connection_get_account(gc);
+		conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, conn->sn);
+		gaim_conversation_write(conv, NULL, _("Direct IM established"),
+				GAIM_MESSAGE_SYSTEM, time(NULL));
+	}
+
+	if ((frame->type != 0x0001) && (frame->subtype != 0x0006))
+	{
+		gaim_debug_info("oscar", "Unknown ODC frame type 0x%04hx, "
+				"subtype 0x%04hx.\n", frame->type, frame->subtype);
+		return;
+	}
+
+	if (frame->flags & 0x0008)
+	{
+		/* I had to leave this. It's just too funny. It reminds me of my sister. */
+		gaim_debug_info("oscar", "ohmigod! %s has started typing "
+			"(DirectIM). He's going to send you a message! "
+			"*squeal*\n", conn->sn);
+		serv_got_typing(gc, conn->sn, 0, GAIM_TYPING);
+	}
+	else if (frame->flags & 0x0004)
+	{
+		serv_got_typing(gc, conn->sn, 0, GAIM_TYPED);
+	}
+	else
+	{
+		serv_got_typing_stopped(gc, conn->sn);
+	}
+
+	if (frame->payload.len > 0)
+	{
+		/* We have payload data!  Switch to the ODC watcher to read it. */
+		frame->payload.data = g_new(guint8, frame->payload.len);
+		frame->payload.offset = 0;
+		conn->frame = frame;
+		gaim_input_remove(conn->watcher_incoming);
+		conn->watcher_incoming = gaim_input_add(conn->fd,
+				GAIM_INPUT_READ, peer_odc_recv_cb, conn);
+		return;
+	}
+
+	g_free(frame);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/oscar/oft.c	Fri Apr 07 05:10:56 2006 +0000
@@ -0,0 +1,602 @@
+/*
+ * Gaim'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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/*
+ * I feel like this is a good place to explain OFT, so I'm going to
+ * do just that.  Each OFT packet has a header type.  I guess this
+ * is pretty similar to the subtype of a SNAC packet.  The type
+ * basically tells the other client the meaning of the OFT packet.
+ * There are two distinct types of file transfer, which I usually
+ * call "sendfile" and "getfile."  Sendfile is when you send a file
+ * to another AIM user.  Getfile is when you share a group of files,
+ * and other users request that you send them the files.
+ *
+ * A typical sendfile file transfer goes like this:
+ *   1) Sender sends a channel 2 ICBM telling the other user that
+ *      we want to send them a file.  At the same time, we open a
+ *      listener socket (this should be done before sending the
+ *      ICBM) on some port, and wait for them to connect to us.
+ *      The ICBM we sent should contain our IP address and the port
+ *      number that we're listening on.
+ *   2) The receiver connects to the sender on the given IP address
+ *      and port.  After the connection is established, the receiver
+ *      sends an ICBM signifying that we are ready and waiting.
+ *   3) The sender sends an OFT PROMPT message over the OFT
+ *      connection.
+ *   4) The receiver of the file sends back an exact copy of this
+ *      OFT packet, except the cookie is filled in with the cookie
+ *      from the ICBM.  I think this might be an attempt to verify
+ *      that the user that is connected is actually the guy that
+ *      we sent the ICBM to.  Oh, I've been calling this the ACK.
+ *   5) The sender starts sending raw data across the connection
+ *      until the entire file has been sent.
+ *   6) The receiver knows the file is finished because the sender
+ *      sent the file size in an earlier OFT packet.  So then the
+ *      receiver sends the DONE thingy (after filling in the
+ *      "received" checksum and size) and closes the connection.
+ */
+
+#include "oscar.h"
+#include "peer.h"
+
+/**
+ * Calculate oft checksum of buffer
+ *
+ * Prevcheck should be 0xFFFF0000 when starting a checksum of a file.  The
+ * checksum is kind of a rolling checksum thing, so each time you get bytes
+ * of a file you just call this puppy and it updates the checksum.  You can
+ * calculate the checksum of an entire file by calling this in a while or a
+ * for loop, or something.
+ *
+ * Thanks to Graham Booker for providing this improved checksum routine,
+ * which is simpler and should be more accurate than Josh Myer's original
+ * code. -- wtm
+ *
+ * This algorithm works every time I have tried it.  The other fails
+ * sometimes.  So, AOL who thought this up?  It has got to be the weirdest
+ * checksum I have ever seen.
+ *
+ * @param buffer Buffer of data to checksum.  Man I'd like to buff her...
+ * @param bufsize Size of buffer.
+ * @param prevchecksum Previous checksum.
+ */
+static guint32
+peer_oft_checksum_chunk(const guint8 *buffer, int bufferlen, guint32 prevchecksum)
+{
+	guint32 checksum, oldchecksum;
+	int i;
+	unsigned short val;
+
+	checksum = (prevchecksum >> 16) & 0xffff;
+	for (i = 0; i < bufferlen; i++)
+	{
+		oldchecksum = checksum;
+		if (i & 1)
+			val = buffer[i];
+		else
+			val = buffer[i] << 8;
+		checksum -= val;
+		/*
+		 * The following appears to be necessary.... It happens
+		 * every once in a while and the checksum doesn't fail.
+		 */
+		if (checksum > oldchecksum)
+			checksum--;
+	}
+	checksum = ((checksum & 0x0000ffff) + (checksum >> 16));
+	checksum = ((checksum & 0x0000ffff) + (checksum >> 16));
+	return checksum << 16;
+}
+
+static guint32
+peer_oft_checksum_file(char *filename)
+{
+	FILE *fd;
+	guint32 checksum = 0xffff0000;
+
+	if ((fd = fopen(filename, "rb")))
+	{
+		int bytes;
+		guint8 buffer[1024];
+
+		while ((bytes = fread(buffer, 1, 1024, fd)) != 0)
+			checksum = peer_oft_checksum_chunk(buffer, bytes, checksum);
+		fclose(fd);
+	}
+
+	return checksum;
+}
+
+/**
+ * Free any OFT related data.
+ */
+void
+peer_oft_close(PeerConnection *conn)
+{
+	/*
+	 * If canceled by local user, and we're receiving a file, and
+	 * we're not connected/ready then send an ICBM cancel message.
+	 */
+	if ((gaim_xfer_get_status(conn->xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) &&
+		!conn->ready)
+	{
+		aim_im_sendch2_cancel(conn);
+	}
+
+	if (conn->sending_data_timer != 0)
+	{
+		gaim_timeout_remove(conn->sending_data_timer);
+		conn->sending_data_timer = 0;
+	}
+}
+
+/**
+ * Write the given OftFrame to a ByteStream and send it out
+ * on the established PeerConnection.
+ */
+static void
+peer_oft_send(PeerConnection *conn, OftFrame *frame)
+{
+	size_t length;
+	ByteStream bs;
+
+	length = 192 + MAX(64, frame->name_length + 1);
+	byte_stream_init(&bs, malloc(length), length);
+	byte_stream_putraw(&bs, conn->magic, 4);
+	byte_stream_put16(&bs, length);
+	byte_stream_put16(&bs, frame->type);
+	byte_stream_putraw(&bs, frame->cookie, 8);
+	byte_stream_put16(&bs, frame->encrypt);
+	byte_stream_put16(&bs, frame->compress);
+	byte_stream_put16(&bs, frame->totfiles);
+	byte_stream_put16(&bs, frame->filesleft);
+	byte_stream_put16(&bs, frame->totparts);
+	byte_stream_put16(&bs, frame->partsleft);
+	byte_stream_put32(&bs, frame->totsize);
+	byte_stream_put32(&bs, frame->size);
+	byte_stream_put32(&bs, frame->modtime);
+	byte_stream_put32(&bs, frame->checksum);
+	byte_stream_put32(&bs, frame->rfrcsum);
+	byte_stream_put32(&bs, frame->rfsize);
+	byte_stream_put32(&bs, frame->cretime);
+	byte_stream_put32(&bs, frame->rfcsum);
+	byte_stream_put32(&bs, frame->nrecvd);
+	byte_stream_put32(&bs, frame->recvcsum);
+	byte_stream_putraw(&bs, frame->idstring, 32);
+	byte_stream_put8(&bs, frame->flags);
+	byte_stream_put8(&bs, frame->lnameoffset);
+	byte_stream_put8(&bs, frame->lsizeoffset);
+	byte_stream_putraw(&bs, frame->dummy, 69);
+	byte_stream_putraw(&bs, frame->macfileinfo, 16);
+	byte_stream_put16(&bs, frame->nencode);
+	byte_stream_put16(&bs, frame->nlanguage);
+	/*
+	 * The name can be more than 64 characters, but if it is less than
+	 * 64 characters it is padded with NULLs.
+	 */
+	byte_stream_putraw(&bs, frame->name, MAX(64, frame->name_length + 1));
+
+	peer_connection_send(conn, &bs);
+
+	free(bs.data);
+}
+
+void
+peer_oft_send_prompt(PeerConnection *conn)
+{
+	conn->xferdata.type = PEER_TYPE_PROMPT;
+	peer_oft_send(conn, &conn->xferdata);
+}
+
+static void
+peer_oft_send_ack(PeerConnection *conn)
+{
+	conn->xferdata.type = PEER_TYPE_ACK;
+
+	/* Fill in the cookie */
+	memcpy(conn->xferdata.cookie, conn->cookie, 8);
+
+	peer_oft_send(conn, &conn->xferdata);
+}
+
+static void
+peer_oft_send_done(PeerConnection *conn)
+{
+	conn->xferdata.type = PEER_TYPE_DONE;
+	conn->xferdata.filesleft = 0;
+	conn->xferdata.partsleft = 0;
+	conn->xferdata.nrecvd = gaim_xfer_get_bytes_sent(conn->xfer);
+	peer_oft_send(conn, &conn->xferdata);
+}
+
+/**
+ * This function exists so that we don't remove the outgoing
+ * data watcher while we're still sending data.  In most cases
+ * any data we're sending will be instantly wisked away to a TCP
+ * buffer maintained by our operating system... but we want to
+ * make sure the core doesn't start sending file data while
+ * we're still sending OFT frame data.  That would be bad.
+ */
+static gboolean
+start_transfer_when_done_sending_data(gpointer data)
+{
+	PeerConnection *conn;
+
+	conn = data;
+
+	if (gaim_circ_buffer_get_max_read(conn->buffer_outgoing) == 0)
+	{
+		conn->sending_data_timer = 0;
+		gaim_input_remove(conn->watcher_incoming);
+		conn->watcher_incoming = 0;
+		conn->xfer->fd = conn->fd;
+		conn->fd = -1;
+		gaim_xfer_start(conn->xfer, conn->xfer->fd, NULL, 0);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/**
+ * This function is similar to the above function, except instead
+ * of starting the xfer it will destroy the connection.  This is
+ * used when you want to send one final message across the peer
+ * connection, and then close everything.
+ */
+static gboolean
+destroy_connection_when_done_sending_data(gpointer data)
+{
+	PeerConnection *conn;
+
+	conn = data;
+
+	if (gaim_circ_buffer_get_max_read(conn->buffer_outgoing) == 0)
+	{
+		conn->sending_data_timer = 0;
+		peer_connection_destroy(conn, conn->disconnect_reason);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/*
+ * This is called when a buddy sends us some file info.  This happens when they
+ * are sending a file to you, and you have just established a connection to them.
+ * You should send them the exact same info except use the real cookie.  We also
+ * get like totally ready to like, receive the file, kay?
+ */
+static void
+peer_oft_recv_frame_prompt(PeerConnection *conn, OftFrame *frame)
+{
+	/* Record the file information and send an ack */
+	memcpy(&conn->xferdata, frame, sizeof(OftFrame));
+	peer_oft_send_ack(conn);
+
+	/* Remove our watchers and use the file transfer watchers in the core */
+	gaim_input_remove(conn->watcher_incoming);
+	conn->watcher_incoming = 0;
+	conn->sending_data_timer = gaim_timeout_add(100,
+			start_transfer_when_done_sending_data, conn);
+}
+
+/**
+ * We are sending a file to someone else.  They have just acknowledged our
+ * prompt, so we want to start sending data like there's no tomorrow.
+ */
+static void
+peer_oft_recv_frame_ack(PeerConnection *conn, OftFrame *frame)
+{
+	if (memcmp(conn->cookie, frame->cookie, 8))
+	{
+		gaim_debug_info("oscar", "Received an incorrect cookie.  "
+				"Closing connection.\n");
+		peer_connection_destroy(conn, PEER_DISCONNECT_INVALID_DATA);
+		return;
+	}
+
+	/* Remove our watchers and use the file transfer watchers in the core */
+	gaim_input_remove(conn->watcher_incoming);
+	conn->watcher_incoming = 0;
+	conn->sending_data_timer = gaim_timeout_add(100,
+			start_transfer_when_done_sending_data, conn);
+}
+
+/*
+ * We just sent a file to someone.  They said they got it and everything,
+ * so we can close our direct connection and what not.
+ */
+static void
+peer_oft_recv_frame_done(PeerConnection *conn, OftFrame *frame)
+{
+	if (frame->nrecvd == frame->size)
+		gaim_xfer_set_completed(conn->xfer, TRUE);
+
+	gaim_input_remove(conn->watcher_incoming);
+	conn->watcher_incoming = 0;
+	conn->xfer->fd = conn->fd;
+	conn->fd = -1;
+	gaim_xfer_end(conn->xfer);
+}
+
+/**
+ * Handle an incoming OftFrame.  If there is a payload associated
+ * with this frame, then we remove the old watcher and add the
+ * OFT watcher to read in the payload.
+ */
+void
+peer_oft_recv_frame(PeerConnection *conn, ByteStream *bs)
+{
+	OftFrame frame;
+
+	frame.type = byte_stream_get16(bs);
+	byte_stream_getrawbuf(bs, frame.cookie, 8);
+	frame.encrypt = byte_stream_get16(bs);
+	frame.compress = byte_stream_get16(bs);
+	frame.totfiles = byte_stream_get16(bs);
+	frame.filesleft = byte_stream_get16(bs);
+	frame.totparts = byte_stream_get16(bs);
+	frame.partsleft = byte_stream_get16(bs);
+	frame.totsize = byte_stream_get32(bs);
+	frame.size = byte_stream_get32(bs);
+	frame.modtime = byte_stream_get32(bs);
+	frame.checksum = byte_stream_get32(bs);
+	frame.rfrcsum = byte_stream_get32(bs);
+	frame.rfsize = byte_stream_get32(bs);
+	frame.cretime = byte_stream_get32(bs);
+	frame.rfcsum = byte_stream_get32(bs);
+	frame.nrecvd = byte_stream_get32(bs);
+	frame.recvcsum = byte_stream_get32(bs);
+	byte_stream_getrawbuf(bs, frame.idstring, 32);
+	frame.flags = byte_stream_get8(bs);
+	frame.lnameoffset = byte_stream_get8(bs);
+	frame.lsizeoffset = byte_stream_get8(bs);
+	byte_stream_getrawbuf(bs, frame.dummy, 69);
+	byte_stream_getrawbuf(bs, frame.macfileinfo, 16);
+	frame.nencode = byte_stream_get16(bs);
+	frame.nlanguage = byte_stream_get16(bs);
+	frame.name_length = bs->len - 186;
+	frame.name = byte_stream_getraw(bs, frame.name_length);
+
+	gaim_debug_info("oscar", "Incoming OFT frame from %s with "
+			"type=0x%04x\n", conn->sn, frame.type);
+
+	/* TODOFT: peer_oft_dirconvert_fromstupid(frame->name); */
+
+	if (frame.type == PEER_TYPE_PROMPT)
+		peer_oft_recv_frame_prompt(conn, &frame);
+	else if (frame.type == PEER_TYPE_ACK)
+		peer_oft_recv_frame_ack(conn, &frame);
+	else if (frame.type == PEER_TYPE_DONE)
+		peer_oft_recv_frame_done(conn, &frame);
+
+	free(frame.name);
+}
+
+/*******************************************************************/
+/* Begin GaimXfer callbacks for use when receiving a file          */
+/*******************************************************************/
+
+void
+peer_oft_recvcb_init(GaimXfer *xfer)
+{
+	PeerConnection *conn;
+
+	conn = xfer->data;
+	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
+	peer_connection_trynext(conn);
+}
+
+void
+peer_oft_recvcb_end(GaimXfer *xfer)
+{
+	PeerConnection *conn;
+
+	conn = xfer->data;
+
+	/* Tell the other person that we've received everything */
+	conn->fd = conn->xfer->fd;
+	conn->xfer->fd = -1;
+	peer_oft_send_done(conn);
+
+	conn->disconnect_reason = PEER_DISCONNECT_DONE;
+	conn->sending_data_timer = gaim_timeout_add(100,
+			destroy_connection_when_done_sending_data, conn);
+}
+
+void
+peer_oft_recvcb_ack_recv(GaimXfer *xfer, const guchar *buffer, size_t size)
+{
+	PeerConnection *conn;
+
+	/* Update our rolling checksum.  Like Walmart, yo. */
+	conn = xfer->data;
+	conn->xferdata.recvcsum = peer_oft_checksum_chunk(buffer,
+			size, conn->xferdata.recvcsum);
+}
+
+/*******************************************************************/
+/* End GaimXfer callbacks for use when receiving a file            */
+/*******************************************************************/
+
+/*******************************************************************/
+/* Begin GaimXfer callbacks for use when sending a file            */
+/*******************************************************************/
+
+void
+peer_oft_sendcb_init(GaimXfer *xfer)
+{
+	PeerConnection *conn;
+
+	conn = xfer->data;
+	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
+
+	/* Keep track of file transfer info */
+	conn->xferdata.totfiles = 1;
+	conn->xferdata.filesleft = 1;
+	conn->xferdata.totparts = 1;
+	conn->xferdata.partsleft = 1;
+	conn->xferdata.totsize = gaim_xfer_get_size(xfer);
+	conn->xferdata.size = gaim_xfer_get_size(xfer);
+	conn->xferdata.checksum = 0xffff0000;
+	conn->xferdata.rfrcsum = 0xffff0000;
+	conn->xferdata.rfcsum = 0xffff0000;
+	conn->xferdata.recvcsum = 0xffff0000;
+	strncpy((gchar *)conn->xferdata.idstring, "OFT_Windows ICBMFT V1.1 32", 31);
+	conn->xferdata.modtime = 0;
+	conn->xferdata.cretime = 0;
+	xfer->filename = g_path_get_basename(xfer->local_filename);
+	conn->xferdata.name = (guchar *)g_strdup(xfer->filename);
+	conn->xferdata.name_length = strlen(xfer->filename);
+
+	/* Calculating the checksum can take a very long time for large files */
+	gaim_debug_info("oscar","calculating file checksum\n");
+	conn->xferdata.checksum = peer_oft_checksum_file(xfer->local_filename);
+	gaim_debug_info("oscar","checksum calculated\n");
+
+	/* Start the connection process */
+	peer_connection_trynext(conn);
+}
+
+/*
+ * AIM file transfers aren't really meant to be thought
+ * of as a transferring just a single file.  The rendezvous
+ * establishes a connection between two computers, and then
+ * those computers can use the same connection for transferring
+ * multiple files.  So we don't want the Gaim core up and closing
+ * the socket all willy-nilly.  We want to do that in the oscar
+ * prpl, whenever one side or the other says they're finished
+ * using the connection.  There might be a better way to intercept
+ * the socket from the core...
+ */
+void
+peer_oft_sendcb_ack(GaimXfer *xfer, const guchar *buffer, size_t size)
+{
+	PeerConnection *conn;
+
+	conn = xfer->data;
+
+	/*
+	 * If we're done sending, intercept the socket from the core ft code
+	 * and wait for the other guy to send the "done" OFT packet.
+	 */
+	if (gaim_xfer_get_bytes_remaining(xfer) <= 0)
+	{
+		gaim_input_remove(xfer->watcher);
+		conn->fd = xfer->fd;
+		xfer->fd = -1;
+		conn->watcher_incoming = gaim_input_add(conn->fd,
+				GAIM_INPUT_READ, peer_connection_recv_cb, conn);
+	}
+}
+
+/*******************************************************************/
+/* End GaimXfer callbacks for use when sending a file              */
+/*******************************************************************/
+
+/*******************************************************************/
+/* Begin GaimXfer callbacks for use when sending and receiving     */
+/*******************************************************************/
+
+void
+peer_oft_cb_generic_cancel(GaimXfer *xfer)
+{
+	PeerConnection *conn;
+
+	conn = xfer->data;
+
+	if (conn == NULL)
+		return;
+
+	peer_connection_destroy(conn, PEER_DISCONNECT_LOCAL_CLOSED);
+}
+
+/*******************************************************************/
+/* End GaimXfer callbacks for use when sending and receiving       */
+/*******************************************************************/
+
+#if 0
+/*
+ * This little area in oscar.c is the nexus of file transfer code,
+ * so I wrote a little explanation of what happens.  I am such a
+ * ninja.
+ *
+ * The series of events for a file send is:
+ *  -Create xfer and call gaim_xfer_request (this happens in oscar_ask_sendfile)
+ *  -User chooses a file and oscar_xfer_init is called.  It establishes a
+ *   listening socket, then asks the remote user to connect to us (and
+ *   gives them the file name, port, IP, etc.)
+ *  -They connect to us and we send them an PEER_TYPE_PROMPT (this happens
+ *   in peer_oft_recv_frame_established)
+ *  -They send us an PEER_TYPE_ACK and then we start sending data
+ *  -When we finish, they send us an PEER_TYPE_DONE and they close the
+ *   connection.
+ *  -We get drunk because file transfer kicks ass.
+ *
+ * The series of events for a file receive is:
+ *  -Create xfer and call gaim_xfer request (this happens in incomingim_chan2)
+ *  -Gaim user selects file to name and location to save file to and
+ *   oscar_xfer_init is called
+ *  -It connects to the remote user using the IP they gave us earlier
+ *  -After connecting, they send us an PEER_TYPE_PROMPT.  In reply, we send
+ *   them an PEER_TYPE_ACK.
+ *  -They begin to send us lots of raw data.
+ *  -When they finish sending data we send an PEER_TYPE_DONE and then close
+ *   the connection.
+ *
+ * Update August 2005:
+ * The series of events for transfers has been seriously complicated by the addition
+ * of transfer redirects and proxied connections. I could throw a whole lot of words
+ * at trying to explain things here, but it probably wouldn't do much good. To get
+ * a better idea of what happens, take a look at the diagrams and documentation
+ * from my Summer of Code project. -- Jonathan Clark
+ */
+
+/**
+ * Convert the directory separator from / (0x2f) to ^A (0x01)
+ *
+ * @param name The filename to convert.
+ */
+static void
+peer_oft_dirconvert_tostupid(char *name)
+{
+	while (name[0]) {
+		if (name[0] == 0x01)
+			name[0] = G_DIR_SEPARATOR;
+		name++;
+	}
+}
+
+/**
+ * Convert the directory separator from ^A (0x01) to / (0x2f)
+ *
+ * @param name The filename to convert.
+ */
+static void
+peer_oft_dirconvert_fromstupid(char *name)
+{
+	while (name[0]) {
+		if (name[0] == G_DIR_SEPARATOR)
+			name[0] = 0x01;
+		name++;
+	}
+}
+#endif
--- a/src/protocols/oscar/oscar.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/oscar.c	Fri Apr 07 05:10:56 2006 +0000
@@ -34,7 +34,6 @@
 #include "conversation.h"
 #include "core.h"
 #include "debug.h"
-#include "ft.h"
 #include "imgstore.h"
 #include "network.h"
 #include "notify.h"
@@ -48,15 +47,15 @@
 #include "oscar.h"
 #include "peer.h"
 
-#define OSCAR_STATUS_ID_INVISIBLE	"invisible"
-#define OSCAR_STATUS_ID_OFFLINE		"offline"
-#define OSCAR_STATUS_ID_AVAILABLE	"available"
-#define OSCAR_STATUS_ID_AWAY		"away"
-#define OSCAR_STATUS_ID_DND		"dnd"
-#define OSCAR_STATUS_ID_NA		"na"
-#define OSCAR_STATUS_ID_OCCUPIED	"occupied"
-#define OSCAR_STATUS_ID_FREE4CHAT	"free4chat"
-#define OSCAR_STATUS_ID_CUSTOM		"custom"
+#define OSCAR_STATUS_ID_INVISIBLE   "invisible"
+#define OSCAR_STATUS_ID_OFFLINE     "offline"
+#define OSCAR_STATUS_ID_AVAILABLE   "available"
+#define OSCAR_STATUS_ID_AWAY        "away"
+#define OSCAR_STATUS_ID_DND         "dnd"
+#define OSCAR_STATUS_ID_NA          "na"
+#define OSCAR_STATUS_ID_OCCUPIED    "occupied"
+#define OSCAR_STATUS_ID_FREE4CHAT   "free4chat"
+#define OSCAR_STATUS_ID_CUSTOM      "custom"
 
 #define AIMHASHDATA "http://gaim.sourceforge.net/aim_data.php3"
 
@@ -67,69 +66,24 @@
 #define OSCAR_DEFAULT_AUTHORIZATION TRUE
 #define OSCAR_DEFAULT_HIDE_IP TRUE
 #define OSCAR_DEFAULT_WEB_AWARE FALSE
-#define OSCAR_DEFAULT_USE_RV_PROXY TRUE
-
-/* Milliseconds each file transfer ip address will be given to make a connection. */
-#define FT_CLIENTIP_TIMEOUT	1000	/* 5000 */
-#define FT_VERIFIEDIP_TIMEOUT	5000	/* 15000 */
-#define FT_REDIR_TIMEOUT	10000	/* 20000 */	/* Time to wait for redirected transfer */
-#define FT_PROXYIP_TIMEOUT	300000	/* 120000 */	/* Time to create a checksum for VERY large files */
-
-static int caps_aim = AIM_CAPS_CHAT | AIM_CAPS_BUDDYICON | AIM_CAPS_DIRECTIM | AIM_CAPS_SENDFILE | AIM_CAPS_INTEROPERATE | AIM_CAPS_ICHAT;
-static int caps_icq = AIM_CAPS_BUDDYICON | AIM_CAPS_DIRECTIM | AIM_CAPS_SENDFILE | AIM_CAPS_ICQUTF8 | AIM_CAPS_INTEROPERATE | AIM_CAPS_ICHAT;
+#define OSCAR_DEFAULT_USE_RV_PROXY FALSE
+
+static int caps_aim = OSCAR_CAPABILITY_CHAT | OSCAR_CAPABILITY_BUDDYICON | OSCAR_CAPABILITY_DIRECTIM | OSCAR_CAPABILITY_SENDFILE | OSCAR_CAPABILITY_INTEROPERATE | OSCAR_CAPABILITY_ICHAT;
+static int caps_icq = OSCAR_CAPABILITY_BUDDYICON | OSCAR_CAPABILITY_DIRECTIM | OSCAR_CAPABILITY_SENDFILE | OSCAR_CAPABILITY_ICQUTF8 | OSCAR_CAPABILITY_INTEROPERATE | OSCAR_CAPABILITY_ICHAT;
 
 static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02};
 static guint8 features_icq[] = {0x01, 0x06};
 static guint8 features_icq_offline[] = {0x01};
 static guint8 ck[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
-typedef struct _OscarData OscarData;
-struct _OscarData {
-	OscarSession *sess;
-	OscarConnection *conn;
-
-	guint cnpa;
-	guint paspa;
-	guint emlpa;
-	guint icopa;
-
-	gboolean iconconnecting;
-	gboolean set_icon;
-
-	GSList *create_rooms;
-
-	gboolean conf;
-	gboolean reqemail;
-	gboolean setemail;
-	char *email;
-	gboolean setnick;
-	char *newsn;
-	gboolean chpass;
-	char *oldp;
-	char *newp;
-
-	GSList *oscar_chats;
-	GSList *direct_ims;
-	GSList *file_transfers;
-	GHashTable *buddyinfo;
-	GSList *requesticon;
-
-	gboolean killme;
-	gboolean icq;
-	guint icontimer;
-	guint getblisttimer;
-	guint getinfotimer;
-	gint timeoffset;
-
-	struct {
-		guint maxwatchers; /* max users who can watch you */
-		guint maxbuddies; /* max users you can watch */
-		guint maxgroups; /* max groups in server list */
-		guint maxpermits; /* max users on permit list */
-		guint maxdenies; /* max users on deny list */
-		guint maxsiglen; /* max size (bytes) of profile */
-		guint maxawaymsglen; /* max size (bytes) of posted away message */
-	} rights;
+typedef struct _NewFlapConnectionData NewFlapConnectionData;
+struct _NewFlapConnectionData
+{
+	GaimConnection *gc;
+	FlapConnection *conn;
+	guint16 cookielen;
+	guint8 *cookie;
+	gpointer data;
 };
 
 struct create_room {
@@ -137,13 +91,13 @@
 	int exchange;
 };
 
-struct chat_connection {
+struct chat_connection
+{
 	char *name;
 	char *show; /* AOL did something funny to us */
 	guint16 exchange;
 	guint16 instance;
-	OscarConnection *conn;
-	int inpa;
+	FlapConnection *conn;
 	int id;
 	GaimConnection *gc; /* i hate this. */
 	GaimConversation *conv; /* bah. */
@@ -151,23 +105,10 @@
 	int maxvis;
 };
 
-struct oscar_direct_im {
-	GaimConnection *gc;
-	char name[80];
-	int watcher;
-	OscarConnection *conn;
-	gboolean connected;
-	gboolean gpc_pend;
-	gboolean killme;
-	gboolean donttryagain;
-};
-
-struct ask_direct {
-	GaimConnection *gc;
-	char *sn;
-	char ip[64];
-	guint8 cookie[8];
-	gboolean donttryagain;
+struct oscar_ask_directim_data
+{
+	OscarData *od;
+	char *who;
 };
 
 /*
@@ -175,7 +116,7 @@
  * Some other info is maintained by locate.c, and I'd like to move
  * the rest of this to libfaim, mostly im.c
  *
- * TODO: I think all of this should use the status API.
+ * TODO: More of this should use the status API.
  */
 struct buddyinfo {
 	gboolean typingnot;
@@ -229,86 +170,62 @@
 static int msgerrreasonlen = 25;
 
 /* All the libfaim->gaim callback functions */
-static int gaim_parse_auth_resp  (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_login      (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_auth_securid_request(OscarSession *, FlapFrame *, ...);
-static int gaim_handle_redirect  (OscarSession *, FlapFrame *, ...);
-static int gaim_info_change      (OscarSession *, FlapFrame *, ...);
-static int gaim_account_confirm  (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_oncoming   (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_offgoing   (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_incoming_im(OscarSession *, FlapFrame *, ...);
-static int gaim_parse_misses     (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_clientauto (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_userinfo   (OscarSession *, FlapFrame *, ...);
-static int gaim_reqinfo_timeout  (OscarSession *, FlapFrame *, ...);
-static int gaim_got_infoblock    (OscarSession *sess, FlapFrame *fr, ...);
-static int gaim_parse_motd       (OscarSession *, FlapFrame *, ...);
-static int gaim_chatnav_info     (OscarSession *, FlapFrame *, ...);
-static int gaim_conv_chat_join        (OscarSession *, FlapFrame *, ...);
-static int gaim_conv_chat_leave       (OscarSession *, FlapFrame *, ...);
-static int gaim_conv_chat_info_update (OscarSession *, FlapFrame *, ...);
-static int gaim_conv_chat_incoming_msg(OscarSession *, FlapFrame *, ...);
-static int gaim_email_parseupdate(OscarSession *, FlapFrame *, ...);
-static int gaim_icon_error       (OscarSession *, FlapFrame *, ...);
-static int gaim_icon_parseicon   (OscarSession *, FlapFrame *, ...);
-static int oscar_icon_req        (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_msgack     (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_ratechange (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_evilnotify (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_searcherror(OscarSession *, FlapFrame *, ...);
-static int gaim_parse_searchreply(OscarSession *, FlapFrame *, ...);
-static int gaim_bosrights        (OscarSession *, FlapFrame *, ...);
-static int gaim_connerr          (OscarSession *, FlapFrame *, ...);
-static int conninitdone_admin    (OscarSession *, FlapFrame *, ...);
-static int conninitdone_bos      (OscarSession *, FlapFrame *, ...);
-static int conninitdone_chatnav  (OscarSession *, FlapFrame *, ...);
-static int conninitdone_chat     (OscarSession *, FlapFrame *, ...);
-static int conninitdone_email    (OscarSession *, FlapFrame *, ...);
-static int conninitdone_icon     (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_msgerr     (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_mtn        (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_locaterights(OscarSession *, FlapFrame *, ...);
-static int gaim_parse_buddyrights(OscarSession *, FlapFrame *, ...);
-static int gaim_parse_locerr     (OscarSession *, FlapFrame *, ...);
-static int gaim_icbm_param_info  (OscarSession *, FlapFrame *, ...);
-static int gaim_parse_genericerr (OscarSession *, FlapFrame *, ...);
-static int gaim_memrequest       (OscarSession *, FlapFrame *, ...);
-static int gaim_selfinfo         (OscarSession *, FlapFrame *, ...);
-static int gaim_offlinemsg       (OscarSession *, FlapFrame *, ...);
-static int gaim_offlinemsgdone   (OscarSession *, FlapFrame *, ...);
-static int gaim_icqalias         (OscarSession *, FlapFrame *, ...);
-static int gaim_icqinfo          (OscarSession *, FlapFrame *, ...);
-static int gaim_popup            (OscarSession *, FlapFrame *, ...);
-
-static int gaim_ssi_parseerr     (OscarSession *, FlapFrame *, ...);
-static int gaim_ssi_parserights  (OscarSession *, FlapFrame *, ...);
-static int gaim_ssi_parselist    (OscarSession *, FlapFrame *, ...);
-static int gaim_ssi_parseack     (OscarSession *, FlapFrame *, ...);
-static int gaim_ssi_parseadd     (OscarSession *, FlapFrame *, ...);
-static int gaim_ssi_authgiven    (OscarSession *, FlapFrame *, ...);
-static int gaim_ssi_authrequest  (OscarSession *, FlapFrame *, ...);
-static int gaim_ssi_authreply    (OscarSession *, FlapFrame *, ...);
-static int gaim_ssi_gotadded     (OscarSession *, FlapFrame *, ...);
-
-/* for DirectIM/image transfer */
-static int gaim_odc_initiate     (OscarSession *, FlapFrame *, ...);
-static int gaim_odc_incoming     (OscarSession *, FlapFrame *, ...);
-static int gaim_odc_typing       (OscarSession *, FlapFrame *, ...);
-static int gaim_odc_update_ui    (OscarSession *, FlapFrame *, ...);
-
-/* for file transfer */
-static int oscar_sendfile_estblsh(OscarSession *, FlapFrame *, ...);
-static int oscar_sendfile_prompt (OscarSession *, FlapFrame *, ...);
-static int oscar_sendfile_ack    (OscarSession *, FlapFrame *, ...);
-static int oscar_sendfile_done   (OscarSession *, FlapFrame *, ...);
+static int gaim_parse_auth_resp  (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_login      (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_auth_securid_request(OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_handle_redirect  (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_info_change      (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_account_confirm  (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_oncoming   (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_offgoing   (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_incoming_im(OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_misses     (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_clientauto (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_userinfo   (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_got_infoblock    (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_motd       (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_chatnav_info     (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_conv_chat_join        (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_conv_chat_leave       (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_conv_chat_info_update (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_conv_chat_incoming_msg(OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_email_parseupdate(OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_icon_error       (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_icon_parseicon   (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int oscar_icon_req        (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_msgack     (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_ratechange (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_evilnotify (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_searcherror(OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_searchreply(OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_bosrights        (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_connerr          (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_msgerr     (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_mtn        (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_locaterights(OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_buddyrights(OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_locerr     (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_icbm_param_info  (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_parse_genericerr (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_memrequest       (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_selfinfo         (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_offlinemsg       (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_offlinemsgdone   (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_icqalias         (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_icqinfo          (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_popup            (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_ssi_parseerr     (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_ssi_parserights  (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_ssi_parselist    (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_ssi_parseack     (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_ssi_parseadd     (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_ssi_authgiven    (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_ssi_authrequest  (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_ssi_authreply    (OscarData *, FlapConnection *, FlapFrame *, ...);
+static int gaim_ssi_gotadded     (OscarData *, FlapConnection *, FlapFrame *, ...);
 
 static gboolean gaim_icon_timerfunc(gpointer data);
-static void oscar_callback(gpointer data, gint source, GaimInputCondition condition);
-static void oscar_xfer_init_recv(GaimXfer *xfer);
-static void oscar_xfer_init_send(GaimXfer *xfer);
-
-static void oscar_direct_im_initiate(GaimConnection *gc, const char *who, const guchar *cookie);
+
 static void recent_buddies_cb(const char *name, GaimPrefType type, gconstpointer value, gpointer data);
 static void oscar_set_info(GaimConnection *gc, const char *info);
 static void oscar_set_info_and_status(GaimAccount *account, gboolean setinfo, const char *rawinfo, gboolean setstatus, GaimStatus *status);
@@ -321,20 +238,24 @@
 	g_free(data);
 }
 
-static void oscar_free_buddyinfo(void *data) {
-	struct buddyinfo *bi = data;
-	g_free(bi);
-}
-
-static guint32 oscar_charset_check(const char *utf8)
+/**
+ * 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;
 
-	/* 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. */
-	while (utf8[i]) {
+	/*
+	 * Can we get away with using our custom encoding?
+	 * TODO: This should actually try using the encoding specified in
+	 *       the account editor.
+	 */
+	while (utf8[i])
+	{
 		if ((unsigned char)utf8[i] > 0x7f) {
 			/* not ASCII! */
 			charset = AIM_CHARSET_CUSTOM;
@@ -342,7 +263,12 @@
 		}
 		i++;
 	}
-	while (utf8[i]) {
+
+	/*
+	 * Must we send this message as UNICODE (in the UCS-2BE 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) {
@@ -360,12 +286,13 @@
 	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.
  */
-static gchar *oscar_encoding_extract(const char *encoding)
+static gchar *
+oscar_encoding_extract(const char *encoding)
 {
 	gchar *ret = NULL;
 	char *begin, *end;
@@ -390,7 +317,7 @@
 	return ret;
 }
 
-static gchar *
+gchar *
 oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen)
 {
 	gchar *utf8 = NULL;
@@ -418,7 +345,7 @@
 	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 to most likely has a buggy client.)"));
+			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);
 	}
@@ -426,7 +353,8 @@
 	return utf8;
 }
 
-static gchar *oscar_utf8_try_convert(GaimAccount *account, const gchar *msg)
+static gchar *
+oscar_utf8_try_convert(GaimAccount *account, const gchar *msg)
 {
 	const char *charset = NULL;
 	char *ret = NULL;
@@ -472,7 +400,7 @@
 	return ret;
 }
 
-/*
+/**
  * This attemps to decode an incoming IM into a UTF8 string.
  *
  * We try decoding using two different character sets.  The charset
@@ -482,7 +410,7 @@
  * able to deal with that crap, then people complain like banshees.
  * charsetstr1 is always set to what the correct encoding should be.
  */
-static gchar *
+gchar *
 gaim_plugin_oscar_decode_im_part(GaimAccount *account, const char *sourcesn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen)
 {
 	gchar *ret = NULL;
@@ -525,7 +453,7 @@
 	return ret;
 }
 
-/*
+/**
  * Figure out what encoding to use when sending a given outgoing message.
  */
 static void
@@ -557,9 +485,9 @@
 	 * as UCS-2BE.
 	 */
 	if ((destsn != NULL) && aim_sn_is_icq(destsn))
-		userinfo = aim_locate_finduserinfo(od->sess, destsn);
-
-	if ((userinfo != NULL) && (userinfo->capabilities & AIM_CAPS_ICQUTF8))
+		userinfo = aim_locate_finduserinfo(od, destsn);
+
+	if ((userinfo != NULL) && (userinfo->capabilities & OSCAR_CAPABILITY_ICQUTF8))
 	{
 		GaimBuddy *b;
 		b = gaim_find_buddy(account, destsn);
@@ -692,78 +620,78 @@
 
 	if (!caps) {
 		return NULL;
-	} else while (bit <= AIM_CAPS_LAST) {
+	} else while (bit <= OSCAR_CAPABILITY_LAST) {
 		if (bit & caps) {
 			switch (bit) {
-			case AIM_CAPS_BUDDYICON:
+			case OSCAR_CAPABILITY_BUDDYICON:
 				tmp = _("Buddy Icon");
 				break;
-			case AIM_CAPS_TALK:
+			case OSCAR_CAPABILITY_TALK:
 				tmp = _("Voice");
 				break;
-			case AIM_CAPS_DIRECTIM:
+			case OSCAR_CAPABILITY_DIRECTIM:
 				tmp = _("AIM Direct IM");
 				break;
-			case AIM_CAPS_CHAT:
+			case OSCAR_CAPABILITY_CHAT:
 				tmp = _("Chat");
 				break;
-			case AIM_CAPS_GETFILE:
+			case OSCAR_CAPABILITY_GETFILE:
 				tmp = _("Get File");
 				break;
-			case AIM_CAPS_SENDFILE:
+			case OSCAR_CAPABILITY_SENDFILE:
 				tmp = _("Send File");
 				break;
-			case AIM_CAPS_GAMES:
-			case AIM_CAPS_GAMES2:
+			case OSCAR_CAPABILITY_GAMES:
+			case OSCAR_CAPABILITY_GAMES2:
 				tmp = _("Games");
 				break;
-			case AIM_CAPS_ADDINS:
+			case OSCAR_CAPABILITY_ADDINS:
 				tmp = _("Add-Ins");
 				break;
-			case AIM_CAPS_SENDBUDDYLIST:
+			case OSCAR_CAPABILITY_SENDBUDDYLIST:
 				tmp = _("Send Buddy List");
 				break;
-			case AIM_CAPS_ICQ_DIRECT:
+			case OSCAR_CAPABILITY_ICQ_DIRECT:
 				tmp = _("ICQ Direct Connect");
 				break;
-			case AIM_CAPS_APINFO:
+			case OSCAR_CAPABILITY_APINFO:
 				tmp = _("AP User");
 				break;
-			case AIM_CAPS_ICQRTF:
+			case OSCAR_CAPABILITY_ICQRTF:
 				tmp = _("ICQ RTF");
 				break;
-			case AIM_CAPS_EMPTY:
+			case OSCAR_CAPABILITY_EMPTY:
 				tmp = _("Nihilist");
 				break;
-			case AIM_CAPS_ICQSERVERRELAY:
+			case OSCAR_CAPABILITY_ICQSERVERRELAY:
 				tmp = _("ICQ Server Relay");
 				break;
-			case AIM_CAPS_ICQUTF8OLD:
+			case OSCAR_CAPABILITY_ICQUTF8OLD:
 				tmp = _("Old ICQ UTF8");
 				break;
-			case AIM_CAPS_TRILLIANCRYPT:
+			case OSCAR_CAPABILITY_TRILLIANCRYPT:
 				tmp = _("Trillian Encryption");
 				break;
-			case AIM_CAPS_ICQUTF8:
+			case OSCAR_CAPABILITY_ICQUTF8:
 				tmp = _("ICQ UTF8");
 				break;
-			case AIM_CAPS_HIPTOP:
+			case OSCAR_CAPABILITY_HIPTOP:
 				tmp = _("Hiptop");
 				break;
-			case AIM_CAPS_SECUREIM:
+			case OSCAR_CAPABILITY_SECUREIM:
 				tmp = _("Security Enabled");
 				break;
-			case AIM_CAPS_VIDEO:
+			case OSCAR_CAPABILITY_VIDEO:
 				tmp = _("Video Chat");
 				break;
 			/* Not actually sure about this one... WinAIM doesn't show anything */
-			case AIM_CAPS_ICHATAV:
+			case OSCAR_CAPABILITY_ICHATAV:
 				tmp = _("iChat AV");
 				break;
-			case AIM_CAPS_LIVEVIDEO:
+			case OSCAR_CAPABILITY_LIVEVIDEO:
 				tmp = _("Live Video");
 				break;
-			case AIM_CAPS_CAMERA:
+			case OSCAR_CAPABILITY_CAMERA:
 				tmp = _("Camera");
 				break;
 			default:
@@ -828,7 +756,7 @@
 		return;
 
 	if (userinfo == NULL)
-		userinfo = aim_locate_finduserinfo(od->sess, b->name);
+		userinfo = aim_locate_finduserinfo(od, b->name);
 
 	if (b == NULL)
 		b = gaim_find_buddy(account, userinfo->sn);
@@ -850,8 +778,8 @@
 									gaim_status_get_name(status));
 			}
 		} else {
-			tmp = aim_ssi_itemlist_findparentname(od->sess->ssi.local, b->name);
-			if (aim_ssi_waitingforauth(od->sess->ssi.local, tmp, b->name))
+			tmp = aim_ssi_itemlist_findparentname(od->ssi.local, b->name);
+			if (aim_ssi_waitingforauth(od->ssi.local, tmp, b->name))
 				oscar_string_append(gc->account, str, newline, _("Status"),
 									_("Not Authorized"));
 			else
@@ -878,7 +806,7 @@
 	}
 
 	if ((b != NULL) && (b->name != NULL) && (g != NULL) && (g->name != NULL)) {
-		tmp = aim_ssi_getcomment(od->sess->ssi.local, g->name, b->name);
+		tmp = aim_ssi_getcomment(od->ssi.local, g->name, b->name);
 		if (tmp != NULL) {
 			char *tmp2 = g_markup_escape_text(tmp, strlen(tmp));
 			g_free(tmp);
@@ -935,7 +863,7 @@
 }
 
 static struct chat_connection *
-find_oscar_chat_by_conn(GaimConnection *gc, OscarConnection *conn)
+find_oscar_chat_by_conn(GaimConnection *gc, FlapConnection *conn)
 {
 	OscarData *od = (OscarData *)gc->proto_data;
 	GSList *cur;
@@ -969,6 +897,14 @@
 }
 
 static void
+oscar_chat_destroy(struct chat_connection *cc)
+{
+	g_free(cc->name);
+	g_free(cc->show);
+	g_free(cc);
+}
+
+static void
 oscar_chat_kill(GaimConnection *gc, struct chat_connection *cc)
 {
 	OscarData *od = (OscarData *)gc->proto_data;
@@ -978,913 +914,297 @@
 
 	/* Destroy the chat_connection */
 	od->oscar_chats = g_slist_remove(od->oscar_chats, cc);
-	if (cc->inpa > 0)
-		gaim_input_remove(cc->inpa);
-	oscar_connection_destroy(od->sess, cc->conn);
-	g_free(cc->name);
-	g_free(cc->show);
-	g_free(cc);
-}
-
-/*****************************************************************************
- * Begin scary direct im stuff
- *****************************************************************************/
-
-static struct oscar_direct_im *oscar_direct_im_find(OscarData *od, const char *who) {
-	GSList *d = od->direct_ims;
-	struct oscar_direct_im *m = NULL;
-
-	while (d) {
-		m = (struct oscar_direct_im *)d->data;
-		if (!aim_sncmp(who, m->name))
-			return m;
-		d = d->next;
-	}
-
-	return NULL;
-}
-
-static void oscar_direct_im_destroy(OscarData *od, struct oscar_direct_im *dim)
-{
-	gaim_debug_info("oscar",
-			"destroying Direct IM for %s.\n", dim->name);
-
-	od->direct_ims = g_slist_remove(od->direct_ims, dim);
-	if (dim->gpc_pend) {
-		dim->killme = TRUE;
-		return;
-	}
-	if (dim->watcher)
-	gaim_input_remove(dim->watcher);
-	if (dim->conn)
-		oscar_connection_destroy(od->sess, dim->conn);
-	g_free(dim);
-}
-
-/* the only difference between this and destroy is this writes a conv message */
-static void oscar_direct_im_disconnect(OscarData *od, struct oscar_direct_im *dim)
-{
-	GaimConversation *conv;
-	char buf[256];
-
-	gaim_debug_info("oscar",
-			"%s disconnected Direct IM.\n", dim->name);
-
-	if (dim->connected)
-		g_snprintf(buf, sizeof buf, _("Direct IM with %s closed"), dim->name);
-	else
-		g_snprintf(buf, sizeof buf, _("Direct IM with %s failed"), dim->name);
-
-	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, dim->name,
-		gaim_connection_get_account(dim->gc));
-
-	if (conv) {
-		gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL));
-	} else {
-		gaim_notify_error(dim->gc, NULL, _("Direct Connect failed"), buf);
-	}
-
-	oscar_direct_im_destroy(od, dim);
-
-	return;
-}
-
-/* oops i made two of these. this one just calls the other one. */
-static void gaim_odc_disconnect(OscarSession *sess, OscarConnection *conn)
-{
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = (OscarData *)gc->proto_data;
-	struct oscar_direct_im *dim;
-	char *sn;
-
-	sn = g_strdup(aim_odc_getsn(conn));
-	dim = oscar_direct_im_find(od, sn);
-	oscar_direct_im_disconnect(od, dim);
-	g_free(sn);
-}
-
-static void destroy_direct_im_request(struct ask_direct *d) {
-	gaim_debug_info("oscar", "Freeing DirectIM prompts.\n");
-
-	g_free(d->sn);
-	g_free(d);
-}
-
-/* this is just a gaim_proxy_connect cb that sets up the rest of the cbs */
-static void oscar_odc_callback(gpointer data, gint source, GaimInputCondition condition) {
-	struct oscar_direct_im *dim = data;
-	GaimConnection *gc = dim->gc;
-	OscarData *od = gc->proto_data;
-	GaimConversation *conv;
-	char buf[256];
-	struct sockaddr name;
-	socklen_t name_len = 1;
-
-	g_return_if_fail(gc != NULL);
-
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(source, F_SETFL, 0);
-
-	dim->gpc_pend = FALSE;
-	if (dim->killme) {
-		oscar_direct_im_destroy(od, dim);
-		return;
-	}
-
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		oscar_direct_im_destroy(od, dim);
-		return;
-	}
-
-	if (source < 0) {
-		if (dim->donttryagain) {
-			oscar_direct_im_disconnect(od, dim);
-			return;
-		} else {
-			guchar cookie[8];
-			char *who = g_strdup(dim->name);
-			const guchar *tmp = aim_odc_getcookie(dim->conn);
-
-			memcpy(cookie, tmp, 8);
-			oscar_direct_im_destroy(od, dim);
-			oscar_direct_im_initiate(gc, who, cookie);
-			gaim_debug_info("oscar", "asking direct im initiator to connect to us\n");
-			g_free(who);
-			return;
-		}
-	}
-
-	dim->conn->fd = source;
-	aim_conn_completeconnect(od->sess, dim->conn);
-	conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, dim->gc->account, dim->name);
-
-	/* This is the best way to see if we're connected or not */
-	/* Is this really needed? */
-	if (getpeername(source, &name, &name_len) == 0) {
-		g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), dim->name);
-		dim->connected = TRUE;
-		gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL));
-		dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn);
-	} else {
-		if (dim->donttryagain) {
-			oscar_direct_im_disconnect(od, dim);
-			return;
-		} else {
-			guchar cookie[8];
-			char *who = g_strdup(dim->name);
-			const guchar *tmp = aim_odc_getcookie(dim->conn);
-
-			memcpy(cookie, tmp, 8);
-			oscar_direct_im_destroy(od, dim);
-			oscar_direct_im_initiate(gc, who, cookie);
-			gaim_debug_info("oscar", "asking direct im initiator to connect to us\n");
-			g_free(who);
-			return;
-		}
-	}
-
-
-}
-
-static void accept_direct_im_request(struct ask_direct *d) {
-	GaimConnection *gc = d->gc;
-	OscarData *od;
-	struct oscar_direct_im *dim;
-	char *host; int port = 5190;
-	int i, rc;
-	char *tmp;
-	GaimConversation *conv;
-
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		destroy_direct_im_request(d);
-		return;
-	}
-
-	od = (OscarData *)gc->proto_data;
-	gaim_debug_info("oscar", "Accepted DirectIM.\n");
-
-	dim = oscar_direct_im_find(od, d->sn);
-	if (dim && dim->connected) {
-		destroy_direct_im_request(d); /* 40 */ /* what does that 40 mean? */
-		gaim_debug_info("oscar", "Wait, we're already connected, ignoring DirectIM.\n");
-		return;
-	}
-	dim = g_new0(struct oscar_direct_im, 1);
-	dim->gc = d->gc;
-	dim->donttryagain = d->donttryagain;
-	g_snprintf(dim->name, sizeof dim->name, "%s", d->sn);
-
-	dim->conn = aim_odc_connect(od->sess, d->sn, NULL, d->cookie);
-	od->direct_ims = g_slist_append(od->direct_ims, dim);
-	if (!dim->conn) {
-		oscar_direct_im_disconnect(od, dim);
-		destroy_direct_im_request(d);
-		return;
-	}
-
-	aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT,
-						PEER_TYPE_DIRECTIMINCOMING, gaim_odc_incoming, 0);
-	aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT,
-						PEER_TYPE_DIRECTIMTYPING, gaim_odc_typing, 0);
-	aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_SPECIAL,
-						AIM_CB_SPECIAL_IMAGETRANSFER, gaim_odc_update_ui, 0);
-
-	gaim_debug_info("oscar", "ip is %s.\n", d->ip);
-	for (i = 0; i < (int)strlen(d->ip); i++) {
-		if (d->ip[i] == ':') {
-			port = atoi(&(d->ip[i+1]));
-			break;
-		}
-	}
-	host = g_strndup(d->ip, i);
-	dim->conn->status |= AIM_CONN_STATUS_INPROGRESS;
-	dim->gpc_pend = TRUE;
-	rc = gaim_proxy_connect(gc->account, host, port, oscar_odc_callback, dim);
-
-	conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, dim->gc->account, d->sn);
-	tmp = g_strdup_printf(_("Attempting to connect to %s at %s:%hu for Direct IM."),
-						  d->sn, host, port);
-	gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
-	g_free(tmp);
-
-	g_free(host);
-	if (rc < 0) {
-		dim->gpc_pend = FALSE;
-		oscar_direct_im_disconnect(od, dim);
-		destroy_direct_im_request(d);
-		return;
-	}
-
-	destroy_direct_im_request(d);
-
-	return;
-}
-
-/*
- * We have just established a socket with the other dude, so set up some handlers.
- */
-static int gaim_odc_initiate(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = (OscarData *)gc->proto_data;
-	GaimConversation *conv;
-	struct oscar_direct_im *dim;
-	char buf[256];
-	char *sn;
-	va_list ap;
-	OscarConnection *newconn, *listenerconn;
-
-	va_start(ap, fr);
-	newconn = va_arg(ap, OscarConnection *);
-	listenerconn = va_arg(ap, OscarConnection *);
-	va_end(ap);
-
-	oscar_connection_destroy(sess, listenerconn);
-
-	sn = g_strdup(aim_odc_getsn(newconn));
-
-	gaim_debug_info("oscar", "DirectIM: initiate success to %s\n", sn);
-	dim = oscar_direct_im_find(od, sn);
-
-	conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, dim->gc->account, sn);
-	gaim_input_remove(dim->watcher);
-	dim->conn = newconn;
-	dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn);
-	dim->connected = TRUE;
-	g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), sn);
-	g_free(sn);
-	gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL));
-
-	aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, PEER_TYPE_DIRECTIMINCOMING, gaim_odc_incoming, 0);
-	aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, PEER_TYPE_DIRECTIMTYPING, gaim_odc_typing, 0);
-	aim_conn_addhandler(sess, newconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER, gaim_odc_update_ui, 0);
-
-	return 1;
-}
-
-/*
- * This is called when each chunk of an image is received.  It can be used to
- * update a progress bar, or to eat lots of dry cat food.  Wet cat food is
- * nasty, you sicko.
- */
-static int gaim_odc_update_ui(OscarSession *sess, FlapFrame *fr, ...) {
-	va_list ap;
-	char *sn;
-	double percent;
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = (OscarData *)gc->proto_data;
-	struct oscar_direct_im *dim;
-
-	va_start(ap, fr);
-	sn = va_arg(ap, char *);
-	percent = va_arg(ap, double);
-	va_end(ap);
-
-	if (!sn || !(dim = oscar_direct_im_find(od, sn)))
-		return 1;
-	if (dim->watcher) {
-		gaim_input_remove(dim->watcher); /* Otherwise, the callback will callback */
-		/* The callback will callback? I don't get how that would happen here. */
-		dim->watcher = 0;
-	}
-
-	dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ,
-								  oscar_callback, dim->conn);
-
-	return 1;
-}
-
-/*
- * This is called after a direct IM has been received in its entirety.  This
- * function is passed a long chunk of data which contains the IM with any
- * data chunks (images) appended to it.
- *
- * This function rips out all the data chunks and creates an imgstore for
- * each one.  In order to do this, it first goes through the IM and takes
- * out all the IMG tags.  When doing so, it rewrites the original IMG tag
- * with one compatible with the imgstore Gaim core code. For each one, we
- * then read in chunks of data from the end of the message and actually
- * create the img store using the given data.
- *
- * For somewhat easy reference, here's a sample message
- * (without the whitespace and asterisks):
- *
- * <HTML><BODY BGCOLOR="#ffffff">
- *     <FONT LANG="0">
- *     This is a really stupid picture:<BR>
- *     <IMG SRC="Sample.jpg" ID="1" WIDTH="283" HEIGHT="212" DATASIZE="9894"><BR>
- *     Yeah it is<BR>
- *     Here is another one:<BR>
- *     <IMG SRC="Soap Bubbles.bmp" ID="2" WIDTH="256" HEIGHT="256" DATASIZE="65978">
- *     </FONT>
- * </BODY></HTML>
- * <BINARY>
- *     <DATA ID="1" SIZE="9894">datadatadatadata</DATA>
- *     <DATA ID="2" SIZE="65978">datadatadatadata</DATA>
- * </BINARY>
- */
-static int gaim_odc_incoming(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	GaimMessageFlags imflags = 0;
-	gchar *utf8;
-	GString *newmsg = g_string_new("");
-	GSList *images = NULL;
-	va_list ap;
-	const char *sn, *msg, *msgend, *binary;
-	size_t len;
-	int encoding, isawaymsg;
-
-	va_start(ap, fr);
-	sn = va_arg(ap, const char *);
-	msg = va_arg(ap, const char *);
-	len = va_arg(ap, size_t);
-	encoding = va_arg(ap, int);
-	isawaymsg = va_arg(ap, int);
-	va_end(ap);
-	msgend = msg + len;
-
-	gaim_debug_info("oscar", "Got DirectIM message from %s\n", sn);
-
-	if (isawaymsg)
-		imflags |= GAIM_MESSAGE_AUTO_RESP;
-
-	/* message has a binary trailer */
-	if ((binary = gaim_strcasestr(msg, "<binary>"))) {
-		GData *attribs;
-		const char *tmp, *start, *end, *last = NULL;
-
-		tmp = msg;
-
-		/* for each valid image tag... */
-		while (gaim_markup_find_tag("img", tmp, &start, &end, &attribs)) {
-			const char *id, *src, *datasize;
-			const char *data = NULL;
-			char *tag = NULL;
-			size_t size;
-			int imgid = 0;
-
-			/* update the location of the last img tag */
-			last = end;
-
-			/* grab attributes */
-			id       = g_datalist_get_data(&attribs, "id");
-			src      = g_datalist_get_data(&attribs, "src");
-			datasize = g_datalist_get_data(&attribs, "datasize");
-
-			/* if we have id & datasize, build the data tag */
-			if (id && datasize)
-				tag = g_strdup_printf("<data id=\"%s\" size=\"%s\">", id, datasize);
-
-			/* if we have a tag, find the start of the data */
-			if (tag && (data = gaim_strcasestr(binary, tag)))
-				data += strlen(tag);
-
-			g_free(tag);
-
-			/* check the data is here and store it */
-			if (data + (size = atoi(datasize)) <= msgend)
-				imgid = gaim_imgstore_add(data, size, src);
-
-			/*
-			 * XXX - The code below contains some calls to oscar_encoding_to_utf8
-			 * The hardcoded "us-ascii" value REALLY needs to be removed.
-			 */
-			/* if we have a stored image... */
-			if (imgid) {
-				/* append the message up to the tag */
-				utf8 = oscar_encoding_to_utf8("us-ascii", tmp, start - tmp);
-				if (utf8 != NULL) {
-					newmsg = g_string_append(newmsg, utf8);
-					g_free(utf8);
-				}
-
-				/* write the new image tag */
-				g_string_append_printf(newmsg, "<IMG ID=\"%d\">", imgid);
-
-				/* and record the image number */
-				images = g_slist_append(images, GINT_TO_POINTER(imgid));
-			} else {
-				/* otherwise, copy up to the end of the tag */
-				utf8 = oscar_encoding_to_utf8("us-ascii", tmp, (end + 1) - tmp);
-				if (utf8 != NULL) {
-					newmsg = g_string_append(newmsg, utf8);
-					g_free(utf8);
-				}
-			}
-
-			/* clear the attribute list */
-			g_datalist_clear(&attribs);
-
-			/* continue from the end of the tag */
-			tmp = end + 1;
-		}
-
-		/* append any remaining message data (without the > :-) */
-		if (last++ && (last < binary))
-			newmsg = g_string_append_len(newmsg, last, binary - last);
-
-		/* set the flag if we caught any images */
-		if (images)
-			imflags |= GAIM_MESSAGE_IMAGES;
-	} else {
-		g_string_append_len(newmsg, msg, len);
-	}
-
-	/* Convert to UTF8 */
-	/* (This hasn't been tested very much) */
-	utf8 = gaim_plugin_oscar_decode_im_part(gc->account, sn, encoding, 0x0000, newmsg->str, len);
-	if (utf8 != NULL) {
-		serv_got_im(gc, sn, utf8, imflags, time(NULL));
-		g_free(utf8);
-	}
-
-	/* free the message */
-	g_string_free(newmsg, TRUE);
-
-	/* unref any images we allocated */
-	if (images) {
-		GSList *tmp;
-		int id;
-
-		for (tmp = images; tmp != NULL; tmp = tmp->next) {
-			id = GPOINTER_TO_INT(tmp->data);
-			gaim_imgstore_unref(id);
-		}
-
-		g_slist_free(images);
-	}
-
-	return 1;
-}
-
-static int gaim_odc_typing(OscarSession *sess, FlapFrame *fr, ...) {
-	va_list ap;
-	char *sn;
-	int typing;
-	GaimConnection *gc = sess->aux_data;
-
-	va_start(ap, fr);
-	sn = va_arg(ap, char *);
-	typing = va_arg(ap, int);
-	va_end(ap);
-
-	if (typing == 0x0002) {
-		/* I had to leave this. It's just too funny. It reminds me of my sister. */
-		gaim_debug_info("oscar",
-				   "ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn);
-		serv_got_typing(gc, sn, 0, GAIM_TYPING);
-	} else if (typing == 0x0001)
-		serv_got_typing(gc, sn, 0, GAIM_TYPED);
-	else
-		serv_got_typing_stopped(gc, sn);
-	return 1;
-}
-
-static int gaim_odc_send_im(OscarSession *sess, OscarConnection *conn, const char *message, GaimMessageFlags imflags) {
-	char *buf;
-	size_t len;
-	int ret;
-	GString *msg = g_string_new("<HTML><BODY>");
-	GString *data = g_string_new("</BODY></HTML><BINARY>");
-	GData *attribs;
-	const char *start, *end, *last;
-	int oscar_id = 0;
-
-	last = message;
-
-	/* for each valid IMG tag... */
-	while (last && *last && gaim_markup_find_tag("img", last, &start, &end, &attribs)) {
-		GaimStoredImage *image = NULL;
-		const char *id;
-
-		if (start - last) {
-			g_string_append_len(msg, last, start - last);
-		}
-
-		id = g_datalist_get_data(&attribs, "id");
-
-		/* ... if it refers to a valid gaim image ... */
-		if (id && (image = gaim_imgstore_get(atoi(id)))) {
-			/* ... append the message from start to the tag ... */
-			unsigned long size = gaim_imgstore_get_size(image);
-			const char *filename = gaim_imgstore_get_filename(image);
-			gpointer imgdata = gaim_imgstore_get_data(image);
-
-			oscar_id++;
-
-			/* ... insert a new img tag with the oscar id ... */
-			if (filename)
-				g_string_append_printf(msg,
-					"<IMG SRC=\"%s\" ID=\"%d\" DATASIZE=\"%lu\">",
-					filename, oscar_id, size);
-			else
-				g_string_append_printf(msg,
-					"<IMG ID=\"%d\" DATASIZE=\"%lu\">",
-					oscar_id, size);
-
-			/* ... and append the data to the binary section ... */
-			g_string_append_printf(data, "<DATA ID=\"%d\" SIZE=\"%lu\">",
-				oscar_id, size);
-			data = g_string_append_len(data, imgdata, size);
-			data = g_string_append(data, "</DATA>");
-		}
-			/* If the tag is invalid, skip it, thus no else here */
-
-		g_datalist_clear(&attribs);
-
-		/* continue from the end of the tag */
-		last = end + 1;
-	}
-
-	/* append any remaining message data (without the > :-) */
-	if (last && *last)
-		msg = g_string_append(msg, last);
-
-	/* if we inserted any images in the binary section, append it */
-	if (oscar_id) {
-		msg = g_string_append_len(msg, data->str, data->len);
-		msg = g_string_append(msg, "</BINARY>");
-	}
-
-	len = msg->len;
-	buf = msg->str;
-	g_string_free(msg, FALSE);
-	g_string_free(data, TRUE);
-
-
-	/* XXX - The last parameter below is the encoding.  Let Paco-Paco do something with it. */
-	if (imflags & GAIM_MESSAGE_AUTO_RESP)
-		ret =  aim_odc_send_im(sess, conn, buf, len, 0, 1);
-	else
-		ret =  aim_odc_send_im(sess, conn, buf, len, 0, 0);
-
-	g_free(buf);
-
-	return ret;
-}
-
-struct ask_do_dir_im {
-	char *who;
-	GaimConnection *gc;
-};
-
-static void oscar_cancel_direct_im(struct ask_do_dir_im *data) {
-	g_free(data->who);
-	g_free(data);
-}
-
-struct dir_im_listen {
-	struct oscar_direct_im *dim;
-	const guchar *cookie;
-};
+	flap_connection_schedule_destroy(cc->conn);
+	oscar_chat_destroy(cc);
+}
 
 static void
-oscar_direct_im_listen_cb(int listenfd, gpointer data) {
-	struct dir_im_listen *dim_l = data;
-	const char *ip;
-	OscarData *od;
-	struct oscar_direct_im *dim = dim_l->dim;
-
-	od = (OscarData *)dim->gc->proto_data;
-
-	/* XXX: shouldn't this be your public IP or something? */
-	ip = gaim_network_get_my_ip(od->conn ? od->conn->fd : -1);
-
-	if (listenfd >= 0)
-		dim->conn = aim_odc_initiate(od->sess, dim->name, listenfd,
-				gaim_network_ip_atoi(ip),
-				gaim_network_get_port_from_fd(listenfd), dim_l->cookie);
-
-	if (dim->conn != NULL) {
-		char *tmp;
-		GaimConversation *conv;
-
-		od->direct_ims = g_slist_append(od->direct_ims, dim);
-		dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ,
-						oscar_callback, dim->conn);
-		aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, PEER_TYPE_DIRECTIM_ESTABLISHED,
-					gaim_odc_initiate, 0);
-
-		conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, dim->gc->account, dim->name);
-		tmp = g_strdup_printf(_("Asking %s to connect to us at %s:%hu for Direct IM."),
-					dim->name, ip, gaim_network_get_port_from_fd(listenfd));
-		gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
-		g_free(tmp);
-	} else {
-		gaim_notify_error(dim->gc, NULL, _("Unable to open Direct IM"), NULL);
-		oscar_direct_im_destroy(od, dim);
-	}
-
-	g_free(dim_l);
-}
-
-/* this function is used to initiate a direct im session with someone.
- * we start listening on a port and send a request. they either connect
- * or send some kind of reply. If they can't connect, they ask us to
- * connect to them, and so we do that.
- *
- * this function will also get called if the other side initiate's a direct
- * im and we try to connect and fail. in that case cookie will not be null.
- *
- * note that cookie is an 8 byte string that isn't NULL terminated
+destroy_new_conn_data(NewFlapConnectionData *new_conn_data)
+{
+	if ((new_conn_data->data != NULL) &&
+		(new_conn_data->conn->type == SNAC_FAMILY_CHAT))
+	{
+		oscar_chat_destroy(new_conn_data->data);
+	}
+	g_free(new_conn_data->cookie);
+	g_free(new_conn_data);
+}
+
+/**
+ * This is the callback function anytime gaim_proxy_connect()
+ * establishes a new TCP connection with an oscar host.  Depending
+ * on the type of host, we do a few different things here.
  */
-static void oscar_direct_im_initiate(GaimConnection *gc, const char *who, const guchar *cookie) {
-	OscarData *od;
-	struct oscar_direct_im *dim;
-	struct dir_im_listen *dim_l;
-
-	od = (OscarData *)gc->proto_data;
-
-	dim = oscar_direct_im_find(od, who);
-	if (dim) {
-		/* TODO: we need to somehow not do this if we're waiting
-		   for the gaim_network_listen_range() call to finish */
-		if (!(dim->connected)) {  /* We'll free the old, unconnected dim, and start over */
-			oscar_direct_im_disconnect(od, dim);
-			gaim_debug_info("oscar",
-					   "Gave up on old direct IM, trying again\n");
-		} else {
-			gaim_notify_error(gc, NULL, "DirectIM already open.", NULL);
-			return;
-		}
-	}
-	dim = g_new0(struct oscar_direct_im, 1);
-	dim->gc = gc;
-	g_snprintf(dim->name, sizeof dim->name, "%s", who);
-
-	dim_l = g_new0(struct dir_im_listen, 1);
-	dim_l->dim = dim;
-	dim_l->cookie = cookie;
-
-	if(!gaim_network_listen_range(5190, 5199, SOCK_STREAM,
-			oscar_direct_im_listen_cb, dim_l)) {
-		gaim_notify_error(gc, NULL, _("Unable to open Direct IM"), NULL);
-		oscar_direct_im_destroy(od, dim);
-		g_free(dim_l);
-	}
-}
-
-static void oscar_direct_im(struct ask_do_dir_im *data) {
-	GaimConnection *gc = data->gc;
-
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		g_free(data->who);
-		g_free(data);
-		return;
-	}
-
-	oscar_direct_im_initiate(gc, data->who, NULL);
-	g_free(data->who);
-	g_free(data);
-}
-
-/* this is the right click menu cb thingy */
-static void oscar_ask_direct_im(GaimBlistNode *node, gpointer ignored) {
-
-	GaimBuddy *buddy;
-	GaimConnection *gc;
-	gchar *buf;
-	struct ask_do_dir_im *data;
-
-	g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (GaimBuddy *) node;
-	gc = gaim_account_get_connection(buddy->account);
-
-	data = g_new0(struct ask_do_dir_im, 1);
-	data->who = g_strdup(buddy->name);
-	data->gc = gc;
-	buf = g_strdup_printf(_("You have selected to open a Direct IM connection with %s."),
-			buddy->name);
-
-	gaim_request_action(gc, NULL, buf,
-			_("Because this reveals your IP address, it "
-			  "may be considered a privacy risk.  Do you "
-			  "wish to continue?"),
-			0, data, 2,
-			_("_Connect"), G_CALLBACK(oscar_direct_im),
-			_("Cancel"), G_CALLBACK(oscar_cancel_direct_im));
-	g_free(buf);
-}
-
-/*****************************************************************************
- * End scary direct im stuff
- *****************************************************************************/
-
 static void
-oscar_callback(gpointer data, gint source, GaimInputCondition condition)
+connection_established_cb(gpointer data, gint source, GaimInputCondition cond)
 {
-	OscarConnection *conn;
-	OscarSession *sess;
+	NewFlapConnectionData *new_conn_data;
 	GaimConnection *gc;
 	OscarData *od;
-
-	conn = (OscarConnection *)data;
-	sess = aim_conn_getsess(conn);
-	gc = sess ? sess->aux_data : NULL;
-
-	if (gc == NULL)
+	FlapConnection *conn;
+
+	new_conn_data = data;
+	gc = new_conn_data->gc;
+
+	if (!g_list_find(gaim_connections_get_all(), gc))
 	{
-		gaim_debug_info("oscar", "oscar callback for closed connection (1).\n");
+		if (source >= 0)
+			close(source);
+		destroy_new_conn_data(new_conn_data);
 		return;
 	}
 
 	od = gc->proto_data;
-	if (od == NULL)
-	{
-		gaim_debug_warning("oscar","NULL od in oscar_callback; conn closed?\n");
-		return;
-	}
-
-	if (!g_list_find(gaim_connections_get_all(), gc))
+	conn = new_conn_data->conn;
+	conn->fd = source;
+
+	if (source < 0)
 	{
-		/* oh boy. this is probably bad. i guess the only thing we
-		 * can really do is return? */
-		gaim_debug_info("oscar",
-				   "oscar callback for closed connection (2).\n");
-		gaim_debug_misc("oscar", "gc = %p\n", gc);
-		return;
-	}
-
-	/* We only care about READ conditions */
-	if (!(condition & GAIM_INPUT_READ))
+		gaim_debug_error("oscar", "unable to connect FLAP server "
+				"of type 0x%04hx\n", conn->type);
+		if (conn->type == SNAC_FAMILY_AUTH)
+			gaim_connection_error(gc, _("Could not connect to authentication server"));
+		if (conn->type == SNAC_FAMILY_LOCATE)
+			gaim_connection_error(gc, _("Could not connect to BOS server"));
+		else /* Maybe we should call this for BOS connections, too? */
+			flap_connection_schedule_destroy(conn);
+		destroy_new_conn_data(new_conn_data);
 		return;
-
-	if (conn->type == AIM_CONN_TYPE_LISTENER) {
-		gaim_debug_info("oscar",
-				   "got information on rendezvous listener\n");
-		if (aim_handlerendconnect(od->sess, conn) < 0) {
-			gaim_debug_error("oscar",
-					   "connection error (rendezvous listener)\n");
-			oscar_connection_destroy(od->sess, conn);
-			/* AAA - Don't we need to gaim_xfer_cancel here? --marv */
-		}
-	} else {
-		if (aim_get_command(od->sess, conn) >= 0) {
-			aim_rxdispatch(od->sess);
-			if (od->killme) {
-				gaim_debug_error("oscar", "Waiting to be destroyed\n");
-				return;
-			}
-		} else {
-			if ((conn->type == AIM_CONN_TYPE_BOS) ||
-				!(aim_getconn_type(od->sess, AIM_CONN_TYPE_BOS)))
-			{
-				gaim_debug_error("oscar", "Major connection error "
-					"(invalid data was received on the oscar TCP stream).\n");
-				gaim_connection_error(gc, _("Disconnected."));
-			} else if (conn->type == AIM_CONN_TYPE_CHAT) {
-				struct chat_connection *cc = find_oscar_chat_by_conn(gc, conn);
-				GaimConversation *conv = gaim_find_chat(gc, cc->id);
-				char *buf;
-				gaim_debug_info("oscar", "Lost connection "
-								"to chat room %s\n", cc->name);
-
-				buf = g_strdup_printf(_("You have lost your connection "
-										"to chat room %s."), cc->name);
-				if (conv != NULL)
-					gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_ERROR, time(NULL));
-				else
-					gaim_notify_error(gc, NULL, buf, NULL);
-				g_free(buf);
-
-				oscar_chat_kill(gc, cc);
-
-			} else if (conn->type == AIM_CONN_TYPE_CHATNAV) {
-				if (od->cnpa > 0)
-					gaim_input_remove(od->cnpa);
-				od->cnpa = 0;
-				gaim_debug_info("oscar",
-						   "removing chatnav input watcher\n");
-				while (od->create_rooms) {
-					struct create_room *cr = od->create_rooms->data;
-					g_free(cr->name);
-					od->create_rooms =
-						g_slist_remove(od->create_rooms, cr);
-					g_free(cr);
-					gaim_notify_error(gc, NULL,
-									  _("Chat is currently unavailable"),
-									  NULL);
-				}
-				gaim_debug_info("oscar","killing rendezvous connection\n");
-				oscar_connection_destroy(od->sess, conn);
-			} else if (conn->type == AIM_CONN_TYPE_AUTH) {
-				if (od->paspa > 0)
-					gaim_input_remove(od->paspa);
-				od->paspa = 0;
-				gaim_debug_info("oscar",
-						   "removing authconn input watcher\n");
-				oscar_connection_destroy(od->sess, conn);
-			} else if (conn->type == AIM_CONN_TYPE_EMAIL) {
-				if (od->emlpa > 0)
-					gaim_input_remove(od->emlpa);
-				od->emlpa = 0;
-				gaim_debug_info("oscar",
-						   "removing email input watcher\n");
-				oscar_connection_destroy(od->sess, conn);
-			} else if (conn->type == AIM_CONN_TYPE_ICON) {
-				if (od->icopa > 0)
-					gaim_input_remove(od->icopa);
-				od->icopa = 0;
-				gaim_debug_info("oscar",
-						   "removing icon input watcher\n");
-				oscar_connection_destroy(od->sess, conn);
-			} else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
-				if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)
-					gaim_odc_disconnect(od->sess, conn);
-				gaim_debug_info("oscar","killing rendezvous connection\n");
-				oscar_connection_destroy(od->sess, conn);
-			} else {
-				gaim_debug_error("oscar",
-						   "holy crap! generic connection error! %hu\n",
-						   conn->type);
-				oscar_connection_destroy(od->sess, conn);
-			}
-		}
-	}
-}
-
-static void oscar_login_connect(gpointer data, gint source, GaimInputCondition cond)
+	}
+
+	gaim_debug_info("oscar", "connected to FLAP server of type 0x%04hx\n",
+			conn->type);
+	conn->watcher_incoming = gaim_input_add(conn->fd,
+			GAIM_INPUT_READ, flap_connection_recv_cb, conn);
+	if (new_conn_data->cookie == NULL)
+		flap_connection_send_version(od, conn);
+	else
+		flap_connection_send_version_with_cookie(od, conn,
+				new_conn_data->cookielen, new_conn_data->cookie);
+
+	if (conn->type == SNAC_FAMILY_AUTH)
+	{
+		GaimAccount *account;
+		account = gaim_connection_get_account(gc);
+		aim_request_login(od, conn, gaim_account_get_username(account));
+		gaim_debug_info("oscar", "Screen name sent, waiting for response\n");
+		gaim_connection_update_progress(gc, _("Screen name sent"), 1, OSCAR_CONNECT_STEPS);
+		ck[1] = 0x65;
+	}
+	else if (conn->type == SNAC_FAMILY_LOCATE)
+	{
+		gaim_connection_update_progress(gc, _("Connection established, cookie sent"), 4, OSCAR_CONNECT_STEPS);
+		ck[4] = 0x61;
+	}
+	else if (conn->type == SNAC_FAMILY_CHAT)
+	{
+		od->oscar_chats = g_slist_append(od->oscar_chats, new_conn_data->data);
+		new_conn_data->data = NULL;
+	}
+
+	destroy_new_conn_data(new_conn_data);
+}
+
+static void
+flap_connection_established_bos(OscarData *od, FlapConnection *conn)
+{
+	GaimConnection *gc = od->gc;
+
+	aim_reqpersonalinfo(od, conn);
+
+	gaim_debug_info("oscar", "ssi: requesting rights and list\n");
+	aim_ssi_reqrights(od);
+	aim_ssi_reqdata(od);
+	if (od->getblisttimer > 0)
+		gaim_timeout_remove(od->getblisttimer);
+	od->getblisttimer = gaim_timeout_add(30000, gaim_ssi_rerequestdata, od);
+
+	aim_locate_reqrights(od);
+	aim_buddylist_reqrights(od, conn);
+	aim_im_reqparams(od);
+	aim_bos_reqrights(od, conn); /* TODO: Don't call this with ssi */
+
+	gaim_connection_update_progress(gc, _("Finalizing connection"), 5, OSCAR_CONNECT_STEPS);
+}
+
+static void
+flap_connection_established_admin(OscarData *od, FlapConnection *conn)
 {
-	GaimConnection *gc = data;
-	OscarData *od;
-	OscarSession *sess;
-	OscarConnection *conn;
-
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		close(source);
-		return;
-	}
-
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(source, F_SETFL, 0);
-
-	od = gc->proto_data;
-	sess = od->sess;
-	conn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH);
-	conn->fd = source;
-
-	if (source < 0) {
-		gaim_connection_error(gc, _("Couldn't connect to host"));
-		return;
-	}
-
-	aim_conn_completeconnect(sess, conn);
-	gc->inpa = gaim_input_add(conn->fd, GAIM_INPUT_READ, oscar_callback, conn);
-	aim_request_login(sess, conn, gaim_account_get_username(gaim_connection_get_account(gc)));
-
-	gaim_debug_info("oscar",
-			   "Screen name sent, waiting for response\n");
-	gaim_connection_update_progress(gc, _("Screen name sent"), 1, OSCAR_CONNECT_STEPS);
-	ck[1] = 0x65;
+	aim_clientready(od, conn);
+	gaim_debug_info("oscar", "connected to admin\n");
+
+	if (od->chpass) {
+		gaim_debug_info("oscar", "changing password\n");
+		aim_admin_changepasswd(od, conn, od->newp, od->oldp);
+		g_free(od->oldp);
+		od->oldp = NULL;
+		g_free(od->newp);
+		od->newp = NULL;
+		od->chpass = FALSE;
+	}
+	if (od->setnick) {
+		gaim_debug_info("oscar", "formatting screen name\n");
+		aim_admin_setnick(od, conn, od->newsn);
+		g_free(od->newsn);
+		od->newsn = NULL;
+		od->setnick = FALSE;
+	}
+	if (od->conf) {
+		gaim_debug_info("oscar", "confirming account\n");
+		aim_admin_reqconfirm(od, conn);
+		od->conf = FALSE;
+	}
+	if (od->reqemail) {
+		gaim_debug_info("oscar", "requesting e-mail address\n");
+		aim_admin_getinfo(od, conn, 0x0011);
+		od->reqemail = FALSE;
+	}
+	if (od->setemail) {
+		gaim_debug_info("oscar", "setting e-mail address\n");
+		aim_admin_setemail(od, conn, od->email);
+		g_free(od->email);
+		od->email = NULL;
+		od->setemail = FALSE;
+	}
+}
+
+static void
+flap_connection_established_chat(OscarData *od, FlapConnection *conn)
+{
+	GaimConnection *gc = od->gc;
+	struct chat_connection *chatcon;
+	static int id = 1;
+
+	aim_clientready(od, conn);
+
+	chatcon = find_oscar_chat_by_conn(gc, conn);
+	chatcon->id = id;
+	chatcon->conv = serv_got_joined_chat(gc, id++, chatcon->show);
+}
+
+static void
+flap_connection_established_chatnav(OscarData *od, FlapConnection *conn)
+{
+	aim_clientready(od, conn);
+	aim_chatnav_reqrights(od, conn);
+}
+
+static void
+flap_connection_established_alert(OscarData *od, FlapConnection *conn)
+{
+	aim_email_sendcookies(od);
+	aim_email_activate(od);
+	aim_clientready(od, conn);
+}
+
+static void
+flap_connection_established_bart(OscarData *od, FlapConnection *conn)
+{
+	GaimConnection *gc = od->gc;
+
+	aim_clientready(od, conn);
+
+	od->iconconnecting = FALSE;
+
+	if (od->icontimer)
+		gaim_timeout_remove(od->icontimer);
+	od->icontimer = gaim_timeout_add(100, gaim_icon_timerfunc, gc);
+}
+
+static int
+flap_connection_established(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
+{
+	gaim_debug_info("oscar", "FLAP connection of type 0x%04hx is "
+			"now fully connected\n", conn->type);
+	if (conn->type == SNAC_FAMILY_LOCATE)
+		flap_connection_established_bos(od, conn);
+	else if (conn->type == SNAC_FAMILY_ADMIN)
+		flap_connection_established_admin(od, conn);
+	else if (conn->type == SNAC_FAMILY_CHAT)
+		flap_connection_established_chat(od, conn);
+	else if (conn->type == SNAC_FAMILY_CHATNAV)
+		flap_connection_established_chatnav(od, conn);
+	else if (conn->type == SNAC_FAMILY_ALERT)
+		flap_connection_established_alert(od, conn);
+	else if (conn->type == SNAC_FAMILY_BART)
+		flap_connection_established_bart(od, conn);
+
+	return 1;
 }
 
 static void
 oscar_login(GaimAccount *account)
 {
-	OscarSession *sess;
-	OscarConnection *conn;
-	GaimConnection *gc = gaim_account_get_connection(account);
-	OscarData *od = gc->proto_data = g_new0(OscarData, 1);
+	GaimConnection *gc;
+	OscarData *od;
+	NewFlapConnectionData *new_conn_data;
+
+	gc = gaim_account_get_connection(account);
+	od = gc->proto_data = oscar_data_new();
+	od->gc = gc;
+
+	oscar_data_addhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0);
+	oscar_data_addhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, flap_connection_established, 0);
+
+	oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0003, gaim_info_change, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0005, gaim_info_change, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0007, gaim_account_confirm, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ALERT, 0x0001, gaim_parse_genericerr, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ALERT, SNAC_SUBTYPE_ALERT_MAILSTATUS, gaim_email_parseupdate, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_AUTH, 0x0003, gaim_parse_auth_resp, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_AUTH, 0x0007, gaim_parse_login, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_REQUEST, gaim_parse_auth_securid_request, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_BART, SNAC_SUBTYPE_BART_ERROR, gaim_icon_error, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_BART, SNAC_SUBTYPE_BART_RESPONSE, gaim_icon_parseicon, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_BOS, 0x0001, gaim_parse_genericerr, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_BOS, 0x0003, gaim_bosrights, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, 0x0001, gaim_parse_genericerr, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_RIGHTSINFO, gaim_parse_buddyrights, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_ONCOMING, gaim_parse_oncoming, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_OFFGOING, gaim_parse_offgoing, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_CHAT, 0x0001, gaim_parse_genericerr, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_USERJOIN, gaim_conv_chat_join, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_USERLEAVE, gaim_conv_chat_leave, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_ROOMINFOUPDATE, gaim_conv_chat_info_update, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_INCOMINGMSG, gaim_conv_chat_incoming_msg, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_CHATNAV, 0x0001, gaim_parse_genericerr, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_CHATNAV, SNAC_SUBTYPE_CHATNAV_INFO, gaim_chatnav_info, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_ERROR, gaim_ssi_parseerr, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RIGHTSINFO, gaim_ssi_parserights, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_LIST, gaim_ssi_parselist, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_NOLIST, gaim_ssi_parselist, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SRVACK, gaim_ssi_parseack, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_ADD, gaim_ssi_parseadd, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTH, gaim_ssi_authgiven, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTHREQ, gaim_ssi_authrequest, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTHREP, gaim_ssi_authreply, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_ADDED, gaim_ssi_gotadded, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, 0x0005, gaim_icbm_param_info, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_INCOMING, gaim_parse_incoming_im, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MISSEDCALL, gaim_parse_misses, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_CLIENTAUTORESP, gaim_parse_clientauto, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_ERROR, gaim_parse_msgerr, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MTN, gaim_parse_mtn, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_ACK, gaim_parse_msgack, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSG, gaim_offlinemsg, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE, gaim_offlinemsgdone, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_ALIAS, gaim_icqalias, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_INFO, gaim_icqinfo, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_RIGHTSINFO, gaim_parse_locaterights, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_USERINFO, gaim_parse_userinfo, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_ERROR, gaim_parse_locerr, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_GOTINFOBLOCK, gaim_got_infoblock, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x0001, gaim_parse_genericerr, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x000f, gaim_selfinfo, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x001f, gaim_memrequest, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x0021, oscar_icon_req,0);
+	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_RATECHANGE, gaim_parse_ratechange, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_REDIRECT, gaim_handle_redirect, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_MOTD, gaim_parse_motd, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_EVIL, gaim_parse_evilnotify, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_POPUP, 0x0002, gaim_popup, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, SNAC_SUBTYPE_USERLOOKUP_ERROR, gaim_parse_searcherror, 0);
+	oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, 0x0003, gaim_parse_searchreply, 0);
 
 	gaim_debug_misc("oscar", "oscar_login: gc = %p\n", gc);
 
@@ -1901,36 +1221,21 @@
 		gc->flags |= GAIM_CONNECTION_HTML;
 		gc->flags |= GAIM_CONNECTION_AUTO_RESP;
 	}
-	od->buddyinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, oscar_free_buddyinfo);
-
-	sess = oscar_session_new();
-	/*
-	 * We need an immediate queue because we don't use a while-loop
-	 * to see if things need to be sent.
-	 */
-	aim_tx_setenqueue(sess, AIM_TX_IMMEDIATE, NULL);
-	od->sess = sess;
-	sess->aux_data = gc;
 
 	/* Connect to core Gaim signals */
 	gaim_prefs_connect_callback(gc, "/plugins/prpl/oscar/recent_buddies", recent_buddies_cb, gc);
 
-	conn = oscar_connection_new(sess, AIM_CONN_TYPE_AUTH);
-	if (conn == NULL) {
-		gaim_debug_error("oscar", "internal connection error\n");
-		gaim_connection_error(gc, _("Unable to login to AIM"));
-		return;
-	}
-
-	aim_conn_addhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0);
-	aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0);
-	aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0);
-	aim_conn_addhandler(sess, conn, OSCAR_FAMILY_AUTH, OSCAR_SUBTYPE_AUTH_SECURID_REQUEST, gaim_parse_auth_securid_request, 0);
-
-	conn->status |= AIM_CONN_STATUS_INPROGRESS;
-	if (gaim_proxy_connect(account, gaim_account_get_string(account, "server", OSCAR_DEFAULT_LOGIN_SERVER),
-			  gaim_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
-			  oscar_login_connect, gc) < 0) {
+	new_conn_data = g_new(NewFlapConnectionData, 1);
+	new_conn_data->gc = gc;
+	new_conn_data->conn = flap_connection_new(od, SNAC_FAMILY_AUTH);
+	new_conn_data->cookielen = 0;
+	new_conn_data->cookie = NULL;
+
+	if (gaim_proxy_connect(account,
+			gaim_account_get_string(account, "server", OSCAR_DEFAULT_LOGIN_SERVER),
+			gaim_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
+			connection_established_cb, new_conn_data) < 0)
+	{
 		gaim_connection_error(gc, _("Couldn't connect to host"));
 		return;
 	}
@@ -1939,34 +1244,23 @@
 	ck[0] = 0x5a;
 }
 
-static void oscar_close(GaimConnection *gc) {
+/* TODO: Move most of this to oscar_data_destroy() */
+static void
+oscar_close(GaimConnection *gc)
+{
 	OscarData *od = (OscarData *)gc->proto_data;
 
-	while (od->oscar_chats) {
-		struct chat_connection *n = od->oscar_chats->data;
-		if (n->inpa > 0)
-			gaim_input_remove(n->inpa);
-		g_free(n->name);
-		g_free(n->show);
-		od->oscar_chats = g_slist_remove(od->oscar_chats, n);
-		g_free(n);
-	}
-	while (od->direct_ims) {
-		struct oscar_direct_im *n = od->direct_ims->data;
-		oscar_direct_im_destroy(od, n);
-	}
-/* BBB */
-	while (od->file_transfers) {
-		GaimXfer *xfer;
-		xfer = (GaimXfer *)od->file_transfers->data;
-		gaim_xfer_cancel_local(xfer);
+	while (od->oscar_chats)
+	{
+		struct chat_connection *cc = od->oscar_chats->data;
+		od->oscar_chats = g_slist_remove(od->oscar_chats, cc);
+		oscar_chat_destroy(cc);
 	}
 	while (od->requesticon) {
-		char *sn = od->requesticon->data;
+		gchar *sn = od->requesticon->data;
 		od->requesticon = g_slist_remove(od->requesticon, sn);
-		free(sn);
-	}
-	g_hash_table_destroy(od->buddyinfo);
+		g_free(sn);
+	}
 	while (od->create_rooms) {
 		struct create_room *cr = od->create_rooms->data;
 		g_free(cr->name);
@@ -1979,16 +1273,6 @@
 		g_free(od->newp);
 	if (od->oldp)
 		g_free(od->oldp);
-	if (gc->inpa > 0)
-		gaim_input_remove(gc->inpa);
-	if (od->cnpa > 0)
-		gaim_input_remove(od->cnpa);
-	if (od->paspa > 0)
-		gaim_input_remove(od->paspa);
-	if (od->emlpa > 0)
-		gaim_input_remove(od->emlpa);
-	if (od->icopa > 0)
-		gaim_input_remove(od->icopa);
 	if (od->icontimer > 0)
 		gaim_timeout_remove(od->icontimer);
 	if (od->getblisttimer > 0)
@@ -1997,894 +1281,19 @@
 		gaim_timeout_remove(od->getinfotimer);
 	gaim_prefs_disconnect_by_handle(gc);
 
-	oscar_session_destroy(od->sess);
-	od->sess = NULL;
-	g_free(gc->proto_data);
+	oscar_data_destroy(od);
 	gc->proto_data = NULL;
 	gaim_debug_info("oscar", "Signed off.\n");
 }
 
-static void oscar_bos_connect(gpointer data, gint source, GaimInputCondition cond) {
-	GaimConnection *gc = data;
-	OscarData *od;
-	OscarSession *sess;
-	OscarConnection *bosconn;
-
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		close(source);
-		return;
-	}
-
-	od = gc->proto_data;
-	sess = od->sess;
-	bosconn = od->conn;
-	bosconn->fd = source;
-
-	if (source < 0) {
-		gaim_connection_error(gc, _("Could Not Connect"));
-		return;
-	}
-
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(source, F_SETFL, 0);
-
-	aim_conn_completeconnect(sess, bosconn);
-	gc->inpa = gaim_input_add(bosconn->fd, GAIM_INPUT_READ, oscar_callback, bosconn);
-
-	gaim_connection_update_progress(gc,
-			_("Connection established, cookie sent"), 4, OSCAR_CONNECT_STEPS);
-	ck[4] = 0x61;
-}
-
-/* BBB */
-/*
- * This little area in oscar.c is the nexus of file transfer code,
- * so I wrote a little explanation of what happens.  I am such a
- * ninja.
- *
- * The series of events for a file send is:
- *  -Create xfer and call gaim_xfer_request (this happens in oscar_ask_sendfile)
- *  -User chooses a file and oscar_xfer_init is called.  It establishes a
- *   listening socket, then asks the remote user to connect to us (and
- *   gives them the file name, port, IP, etc.)
- *  -They connect to us and we send them an PEER_TYPE_PROMPT (this happens
- *   in oscar_sendfile_estblsh)
- *  -They send us an PEER_TYPE_ACK and then we start sending data
- *  -When we finish, they send us an PEER_TYPE_DONE and they close the
- *   connection.
- *  -We get drunk because file transfer kicks ass.
- *
- * The series of events for a file receive is:
- *  -Create xfer and call gaim_xfer request (this happens in incomingim_chan2)
- *  -Gaim user selects file to name and location to save file to and
- *   oscar_xfer_init is called
- *  -It connects to the remote user using the IP they gave us earlier
- *  -After connecting, they send us an PEER_TYPE_PROMPT.  In reply, we send
- *   them an PEER_TYPE_ACK.
- *  -They begin to send us lots of raw data.
- *  -When they finish sending data we send an PEER_TYPE_DONE and then close
- *   the connection.
- *
- * Update August 2005:
- * The series of events for transfers has been seriously complicated by the addition
- * of transfer redirects and proxied connections. I could throw a whole lot of words
- * at trying to explain things here, but it probably wouldn't do much good. To get
- * a better idea of what happens, take a look at the diagrams and documentation
- * from my Summer of Code project. -- Jonathan Clark
- */
-static void oscar_sendfile_connected(gpointer data, gint source, GaimInputCondition condition);
-static void oscar_xfer_proxylogin(gpointer data, gint source, GaimInputCondition condition);
-static void oscar_send_file_request(GaimXfer *xfer);
-
-/*
- * Miscellaneous xfer functions
- */
-static GaimXfer *oscar_find_xfer_by_cookie(GSList *fts, const guint8 *ck)
-{
-	GaimXfer *xfer;
-	PeerConnection *peer_connection;
-
-	while (fts) {
-		xfer = fts->data;
-		peer_connection = xfer->data;
-
-		if (peer_connection && !memcmp(ck, peer_connection->cookie, 8))
-			return xfer;
-
-		fts = g_slist_next(fts);
-	}
-
-	return NULL;
-}
-
-static GaimXfer *oscar_find_xfer_by_conn(GSList *fts, OscarConnection *conn)
-{
-	GaimXfer *xfer;
-	PeerConnection *peer_connection;
-
-	while (fts) {
-		xfer = fts->data;
-		peer_connection = xfer->data;
-
-		if (peer_connection && (conn == peer_connection->conn))
-			return xfer;
-
-		fts = g_slist_next(fts);
-	}
-
-	return NULL;
-}
-
-/*
- * We're done sending/receiving raw data through the connection.
- * If we're the receiver, send an OFT header with the bytes received
- * filled in to indicate this party's over.
- */
-static void oscar_xfer_end(GaimXfer *xfer)
-{
-	PeerConnection *peer_connection = xfer->data;
-	GaimConnection *gc = peer_connection->sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	gaim_debug_info("oscar", "AAA - in oscar_xfer_end\n");
-
-	if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
-		peer_connection->fh.nrecvd = gaim_xfer_get_bytes_sent(xfer);
-		aim_oft_sendheader(peer_connection->sess, PEER_TYPE_DONE, peer_connection);
-	}
-
-	oscar_connection_destroy(peer_connection->sess, peer_connection->conn);
-	aim_oft_destroyinfo(peer_connection);
-	xfer->data = NULL;
-	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
-}
-
-/*
- * xfer functions used when receiving files
- */
-
-/*
- * This is a gaim timeout callback called X milliseconds after a connection is attempted
- * By this point, we've lost faith in the connection method we just tried and want to
- * try something new. Hopefully, that new connection method will be more successful,
- * otherwise, we'll end up here again and again until the connection is successful
- * or we've tried every method... if that happens we just throw our hands up
- * and inform the user of his bad karma.
-*/
-static gboolean oscar_xfer_ip_timeout(gpointer data) {
-	GaimXfer *xfer;
-	GaimAccount *account;
-	PeerConnection *peer_connection;
-	char *msg = NULL;
-
-	gaim_debug_info("oscar","AAA - in oscar_xfer_ip_timeout\n");
-
-	xfer = (GaimXfer*) data;
-	account = gaim_xfer_get_account(xfer);
-	if(xfer->data) {
-		peer_connection = (PeerConnection*) xfer->data;
-
-		/* Check to see if the clientip has produced any results */
-		if(!peer_connection->success) {
-			/* This connection has worn out its welcome. Goodbye. */
-			if(peer_connection->conn) {
-				close(peer_connection->conn->fd);
-				oscar_connection_destroy(peer_connection->sess, peer_connection->conn);
-			}
-
-			if(peer_connection->method == AIM_XFER_DIRECT || peer_connection->method == AIM_XFER_REDIR) {
-				/* If (we're currently using the verified ip)
-				* In case clientip & verifiedip are the same,
-				* we must prevent an infinite loop */
-				if(xfer->remote_ip && peer_connection->verifiedip
-					&& g_ascii_strcasecmp(xfer->remote_ip, peer_connection->verifiedip) == 0
-					&& g_ascii_strcasecmp(peer_connection->clientip, peer_connection->verifiedip) != 0 )
-				{
-					/* The verifiedip timed out */
-					if (peer_connection->method == AIM_XFER_DIRECT && !peer_connection->redir_attempted)
-					{
-						/* clientip & verifiedip failed, request a redirect
-						 * that is, we want the sender to connect to us
-						 *
-						 * Above, we checked if we had previously attempted a connection
-						 * redirect to prevent a conflict with the joscar library
-						 */
-
-						/* Let the user not to lose hope quite yet*/
-						msg = g_strdup_printf(_("Attempting connection redirect..."));
-						gaim_xfer_conversation_write(xfer, msg, FALSE);
-						g_free(msg);
-
-						gaim_timeout_add(FT_REDIR_TIMEOUT,
-							oscar_xfer_ip_timeout, xfer);
-						peer_connection->method = AIM_XFER_REDIR;
-						peer_connection->redir_attempted = TRUE;
-						g_free(peer_connection->proxyip);
-						peer_connection->proxyip = NULL;
-						peer_connection->clientip = g_strdup( gaim_network_get_my_ip(
-							peer_connection->conn ? peer_connection->conn->fd : -1));
-						oscar_xfer_init_send(xfer);
-					} else {
-						/* clientip, verifiedip, and redirect all failed. */
-						gaim_debug_info("oscar",
-							"redirect timed out. requesting stg3 proxy\n");
-
-						/* Kill our listener */
-						gaim_input_remove(xfer->watcher);
-						oscar_connection_destroy(peer_connection->sess, peer_connection->conn);
-
-						/* Instead of failing here, request a stage 3 proxy */
-						g_free(peer_connection->clientip);
-						g_free(peer_connection->verifiedip);
-						peer_connection->clientip = NULL;
-						peer_connection->verifiedip = NULL;
-						peer_connection->port = 0;
-						peer_connection->conn->type = AIM_CONN_TYPE_RENDEZVOUS;
-						peer_connection->method = AIM_XFER_PROXY;
-						peer_connection->stage = AIM_XFER_PROXY_STG3;
-
-						aim_im_sendch2_sendfile_ask(peer_connection->sess, peer_connection);
-					}
-				} else {
-					/* clientip timed out, now try verifiedip */
-					g_free(xfer->remote_ip);
-					xfer->remote_ip = g_strdup(peer_connection->verifiedip);
-					gaim_debug_info("oscar","attempting connection using verifiedip\n");
-					oscar_xfer_init_recv(xfer);
-				}
-			} else if(peer_connection->method == AIM_XFER_PROXY) {
-				/* proxyip timed out
-				 * Yes, it's a bit odd to ask the user to enable proxied file transfers
-				 * when it's a proxied transfer that timed out. It is possible that a
-				 * stage 1 or 2 proxied transfer might work when a stage 3 will not. */
-				msg = g_strdup_printf(_("Transfer of file %s timed out.\n Try enabling proxy servers for file transfers in Accounts -> %s -> Edit Account -> Advanced."),
-					gaim_xfer_get_filename(xfer), gaim_account_get_username(account));
-				gaim_xfer_conversation_write(xfer, msg, TRUE);
-				g_free(msg);
-				gaim_xfer_cancel_local(xfer);
-				if(peer_connection->xfer_reffed) {
-					peer_connection->xfer_reffed = FALSE;
-					gaim_xfer_unref(xfer);
-				}
-			} else {
-				gaim_debug_warning("oscar","unknown xfer method encountered in timout\n");
-			}
-		} else {
-			if(peer_connection->xfer_reffed) {
-				peer_connection->xfer_reffed = FALSE;
-				gaim_xfer_unref(xfer);
-			}
-			gaim_debug_info("oscar","connection successful; timeout off\n");
-		}
-	} else {
-		gaim_debug_info("oscar","transfer already done; nothing to do\n");
-	}
-	return FALSE;
-}
-
-/*
- * Connect to another client or a file transfer proxy server.
- * Though this function has traditionally only been used during file receives,
- * it is now called to make any sort of file transfer connection via gaim_proxy_connect.
- */
-static void oscar_xfer_init_recv(GaimXfer *xfer)
-{
-	PeerConnection *peer_connection;
-	PeerProxyInfo *proxy_info;
-	GaimConnection *gc;
-	OscarData *od;
-	GaimInputFunction nextstop_cb;
-	int rc;
-
-	g_return_if_fail(xfer != NULL);
-	g_return_if_fail(xfer->data != NULL);
-
-	peer_connection = xfer->data;
-	proxy_info = peer_connection->proxy_info;
-	gc = peer_connection->sess->aux_data;
-	od = gc->proto_data;
-
-	gaim_debug_info("oscar", "AAA - in oscar_xfer_init_recv\n");
-
-	/* Start a timer for this ip address
-	 * If the clientip fails, try the verifiedip
-	 * If that fails, wait for the transfer to redirect
-	 * This xfer reference will be released in oscar_xfer_ip_timeout */
-	if(!peer_connection->xfer_reffed) {
-		peer_connection->xfer_reffed = TRUE;
-		gaim_xfer_ref(xfer);
-	}
-
-	if(peer_connection->method != AIM_XFER_PROXY) {
-		/* If (we're currently using the verified ip)
-		 * In case clientip & verifiedip are the same, we must prevent an infinite loop */
-		if(xfer->remote_ip && peer_connection->verifiedip
-			&& g_ascii_strcasecmp(xfer->remote_ip, peer_connection->verifiedip) == 0
-			&& g_ascii_strcasecmp(peer_connection->clientip, peer_connection->verifiedip) != 0 ) {
-			gaim_timeout_add(FT_VERIFIEDIP_TIMEOUT, oscar_xfer_ip_timeout, xfer);
-		} else {
-			gaim_timeout_add(FT_CLIENTIP_TIMEOUT, oscar_xfer_ip_timeout, xfer);
-		}
-	} else {
-		gaim_timeout_add(FT_PROXYIP_TIMEOUT, oscar_xfer_ip_timeout, xfer);
-	}
-	peer_connection->conn = oscar_connection_new(od->sess, AIM_CONN_TYPE_RENDEZVOUS);
-
-	/* If we're routing this transfer through a AOL proxy server, do the special login
-	 * before telling the other client we're ready for action.
-	 * Note, firststop_cb is the first function called after gaim has made a connection
-	 * Also, the connection type is changed until the proxy login is complete */
-	if(peer_connection->method == AIM_XFER_PROXY) {
-		if(proxy_info)
-			proxy_info->conn = peer_connection->conn;
-		else {
-			gaim_debug_warning("oscar","NULL proxy_info\n");
-			gaim_xfer_cancel_local(xfer);
-		}
-		nextstop_cb = oscar_xfer_proxylogin;
-		peer_connection->conn->type = AIM_CONN_TYPE_RENDEZVOUS_PROXY;
-	} else {
-		nextstop_cb = oscar_sendfile_connected;
-	}
-
-	if (peer_connection->conn) {
-		peer_connection->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
-		aim_conn_addhandler(od->sess, peer_connection->conn, AIM_CB_FAM_OFT, PEER_TYPE_PROMPT,
-			oscar_sendfile_prompt, 0);
-		rc = gaim_proxy_connect(gaim_connection_get_account(gc),
-					xfer->remote_ip, xfer->remote_port, nextstop_cb, xfer);
-		if (rc == -1) {
-			gaim_xfer_error(GAIM_XFER_RECEIVE, gaim_xfer_get_account(xfer), xfer->who,
-							_("Unable to establish file descriptor."));
-			gaim_xfer_cancel_local(xfer);
-		}
-	} else {
-		gaim_xfer_error(GAIM_XFER_RECEIVE, gaim_xfer_get_account(xfer), xfer->who,
-						_("Unable to create new connection."));
-		gaim_xfer_cancel_local(xfer);
-		/* Try a different port? Ask them to connect to us? /join #gaim and whine? */
-	}
-}
-
-/*
- * "Never mind. This transfer wasn't such a great idea after all."
- */
-static void oscar_xfer_cancel_recv(GaimXfer *xfer)
-{
-	PeerConnection *peer_connection = xfer->data;
-	GaimConnection *gc = peer_connection->sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	gaim_debug_info("oscar", "AAA - in oscar_xfer_cancel_recv\n");
-
-	if (gaim_xfer_get_status(xfer) != GAIM_XFER_STATUS_CANCEL_REMOTE)
-		aim_im_sendch2_sendfile_cancel(peer_connection->sess, peer_connection);
-
-	if(peer_connection->sess && peer_connection->conn)
-		oscar_connection_destroy(peer_connection->sess, peer_connection->conn);
-	aim_oft_destroyinfo(peer_connection);
-	xfer->data = NULL;
-	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
-}
-
-/*
- * Called after every data packet we receive
- */
-static void oscar_xfer_ack_recv(GaimXfer *xfer, const guchar *buffer, size_t size)
+static int
+gaim_parse_auth_resp(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	PeerConnection *peer_connection = xfer->data;
-
-	/* Update our rolling checksum.  Like Walmart, yo. */
-	peer_connection->fh.recvcsum = aim_oft_checksum_chunk(buffer, size, peer_connection->fh.recvcsum);
-}
-
-/*
- * xfer functions used for proxied file transfers
- */
-
-/*
- * Called by oscar_send_proxylogin_cb when we receive a ready packet
- * BBB
- */
-static void oscar_xfer_proxylogin_ready(GaimXfer *xfer, gint fd) {
-	PeerConnection *peer_connection;
-	PeerProxyInfo *proxy_info;
-
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(fd, F_SETFL, 0);
-
-	gaim_debug_info("oscar","AAA - in oscar_xfer_proxylogin_ready\n");
-	if (!(peer_connection = xfer->data)) {
-		gaim_debug_warning("oscar","NULL peer_connection; aborting\n");
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-	if (!(proxy_info = peer_connection->proxy_info)) {
-		gaim_debug_warning("oscar","NULL proxy_info; aborting\n");
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-
-	/* Remove the rv proxy watcher and put the connection type back the way we found it */
-	gaim_input_remove(xfer->watcher);
-	xfer->watcher = 0;
-	peer_connection->conn->type = AIM_CONN_TYPE_RENDEZVOUS;
-
-	if(peer_connection->send_or_recv == AIM_XFER_SEND) {
-
-		if(peer_connection->stage == AIM_XFER_PROXY_STG2) {
-			aim_im_sendch2_sendfile_accept(peer_connection->sess, peer_connection);
-
-			/* For stage 2, both file headers are filled in */
-			memcpy(&peer_connection->fh.bcookie, peer_connection->cookie, 8);
-		}
-
-		/* The following is taken from oscar_sendfile_estblsh */
-		aim_conn_addhandler(peer_connection->sess, peer_connection->conn, AIM_CB_FAM_OFT, PEER_TYPE_ACK,
-			oscar_sendfile_ack, 0);
-		aim_conn_addhandler(peer_connection->sess, peer_connection->conn, AIM_CB_FAM_OFT, PEER_TYPE_DONE,
-			oscar_sendfile_done, 0);
-		xfer->watcher = gaim_input_add(peer_connection->conn->fd, GAIM_INPUT_READ, oscar_callback,
-			peer_connection->conn);
-
-		/* Inform the other user that we are connected and ready to transfer */
-		aim_oft_sendheader(peer_connection->sess, PEER_TYPE_PROMPT, peer_connection);
-	} else if(peer_connection->send_or_recv == AIM_XFER_RECV) {
-		oscar_sendfile_connected(xfer, fd, GAIM_INPUT_READ);
-	} else {
-		gaim_debug_warning("oscar","no value for send_or_recv; aborting transfer\n");
-		gaim_xfer_cancel_local(xfer);
-	}
-}
-
-/*
- * Called by oscar_sendfile_proxylogin_cb when we receive an ack packet in reply to an init_send
- * BBB
- */
-static void oscar_xfer_proxylogin_ack(GaimXfer *xfer) {
-	PeerConnection *peer_connection;
-	PeerProxyInfo *proxy_info;
-
-	gaim_debug_info("oscar","AAA - in oscar_xfer_proxylogin_ack\n");
-	if (!(peer_connection = xfer->data)) {
-		gaim_debug_warning("oscar","NULL peer_connection; aborting\n");
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-	if (!(proxy_info = peer_connection->proxy_info)) {
-		gaim_debug_warning("oscar","NULL proxy_info; aborting\n");
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-
-	/* Use the proxy "port" we just ACK-quired (hah) so that the proxy will love us */
-	peer_connection->port = proxy_info->port;
-	peer_connection->proxyip = g_strdup(proxy_info->ip);
-	gaim_debug_info("oscar","received client ip and port: %s:%d\n",
-		peer_connection->proxyip, peer_connection->port);
-
-	if(peer_connection->send_or_recv == AIM_XFER_SEND) {
-		oscar_send_file_request(xfer);
-	} else if(peer_connection->send_or_recv == AIM_XFER_RECV) {
-		strncpy(peer_connection->fh.name, xfer->filename, 64);
-		peer_connection->fh.name[63] = '\0';
-		peer_connection->fh.totsize = gaim_xfer_get_size(xfer);
-		peer_connection->fh.size = gaim_xfer_get_size(xfer);
-
-		/* Calculating the checksum can take a very long time for large files */
-		gaim_debug_info("oscar","calculating file checksum\n");
-		peer_connection->fh.checksum = aim_oft_checksum_file(xfer->local_filename);
-		gaim_debug_info("oscar","checksum calculated\n");
-
-		aim_im_sendch2_sendfile_ask(peer_connection->sess, peer_connection);
-	} else {
-		gaim_debug_warning("oscar","no value for send_or_recv; aborting transfer\n");
-		gaim_xfer_cancel_local(xfer);
-	}
-}
-
-/*
- * This is called whenever we receive data while negotiating a rendezvous proxy connection
- * BBB
- */
-static void oscar_xfer_proxylogin_cb(gpointer data, gint source, GaimInputCondition condition) {
-	GaimXfer *xfer;
-	PeerConnection *peer_connection;
-
-	gaim_debug_info("oscar","AAA - in oscar_xfer_proxylogin_cb\n");
-	if (!(xfer = data)) {
-		gaim_debug_warning("oscar","NULL xfer; aborting\n");
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-	if (!(peer_connection = xfer->data)) {
-		gaim_debug_warning("oscar","NULL peer_connection; aborting\n");
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-
-	if( (peer_connection->proxy_info = aim_rv_proxy_read(peer_connection->sess, peer_connection->conn)) ) {
-
-		switch(peer_connection->proxy_info->cmd_type) {
-			case AIM_RV_PROXY_READY:
-				oscar_xfer_proxylogin_ready(xfer, source);
-				free(peer_connection->proxy_info);
-				peer_connection->proxy_info = NULL;
-				break;
-			case AIM_RV_PROXY_ACK:
-				oscar_xfer_proxylogin_ack(xfer);
-				free(peer_connection->proxy_info);
-				peer_connection->proxy_info = NULL;
-				break;
-			case AIM_RV_PROXY_ERROR:
-				gaim_debug_info("oscar","error logging into rendezvous proxy; err code is %x\n",
-					peer_connection->proxy_info->err_code);
-				gaim_input_remove(xfer->watcher);
-				xfer->watcher = 0;
-				free(peer_connection->proxy_info);
-				peer_connection->proxy_info = NULL;
-				gaim_xfer_cancel_remote(xfer);
-				break;
-			/* We should never get here */
-			default:
-				gaim_debug_info("oscar","proxylogin switch defaulted unexpectedly\n");
-		}
-	} else {
-		gaim_debug_info("oscar","could not read rv proxy packet\n");
-	}
-}
-
-/*
- * Called to send necessary login data to a rendezvous proxy server once we're connected
- * Takes xfer is data and fd as source
- */
-static void oscar_xfer_proxylogin(gpointer data, gint source, GaimInputCondition condition)
-{
-	GaimXfer *xfer;
-	PeerConnection *peer_connection;
-	PeerProxyInfo *proxy_info;
-	int err;
-
-	gaim_debug_info("oscar","AAA - in oscar_xfer_proxylogin\n");
-	if (!(xfer = data)) {
-		gaim_debug_warning("oscar","NULL xfer; aborting\n");
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-	if (!(peer_connection = xfer->data)) {
-		gaim_debug_warning("oscar","NULL peer_connection; aborting\n");
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-	if (!(proxy_info = peer_connection->proxy_info)) {
-		gaim_debug_warning("oscar","NULL proxy_info; aborting\n");
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-	if(peer_connection->success) {
-		gaim_debug_info("oscar","connection already successful, ignoring 2nd conn\n");
-		return;
-	}
-
-	xfer->fd = source;
-	peer_connection->conn->fd = source;
-
-	proxy_info->conn = peer_connection->conn;
-	proxy_info->flags = AIM_RV_PROXY_CLIENT_FLAGS;
-	memcpy(proxy_info->cookie, peer_connection->cookie, 8);
-
-	if(peer_connection->send_or_recv == AIM_XFER_SEND) {
-		if(peer_connection->stage == AIM_XFER_PROXY_STG1 || peer_connection->stage == AIM_XFER_PROXY_STG3) {
-			gaim_debug_info("oscar","sending INIT SEND for stage 1/3 rv proxied send\n");
-			if( (err = aim_rv_proxy_init_send(proxy_info)) ) {
-				gaim_xfer_error(GAIM_XFER_SEND, gaim_xfer_get_account(xfer), xfer->who,
-								_("Unable to log into file transfer proxy."));
-				gaim_debug_info("oscar", "error while sending INIT SEND rv proxy packet: %s\n",
-					strerror(err));
-				gaim_xfer_cancel_local(xfer);
-			}
-		} else if(peer_connection->stage == AIM_XFER_PROXY_STG2) {
-			gaim_debug_info("oscar","sending INIT RECV for stage 2 rv proxied send\n");
-			if( (err = aim_rv_proxy_init_recv(proxy_info)) ) {
-				gaim_xfer_error(GAIM_XFER_SEND, gaim_xfer_get_account(xfer), xfer->who,
-								_("Unable to log into file transfer proxy."));
-				gaim_debug_info("oscar", "error while sending INIT RECV rv proxy packet: %s\n",
-					strerror(err));
-				gaim_xfer_cancel_local(xfer);
-			}
-		} else {
-			gaim_debug_warning("oscar","no proxy type specified; aborting transfer\n");
-			gaim_xfer_cancel_local(xfer);
-		}
-	} else if(peer_connection->send_or_recv == AIM_XFER_RECV) {
-		if(peer_connection->stage == AIM_XFER_PROXY_STG2) {
-			gaim_debug_info("oscar","sending INIT SEND for stage 2 rv proxied receive\n");
-			if( (err = aim_rv_proxy_init_send(proxy_info)) ) {
-				gaim_xfer_error(GAIM_XFER_SEND, gaim_xfer_get_account(xfer), xfer->who,
-								_("Unable to log into file transfer proxy."));
-				gaim_debug_info("oscar", "error while sending INIT SEND rv proxy packet: %s\n",
-					strerror(err));
-				gaim_xfer_cancel_local(xfer);
-			}
-		} else if(peer_connection->stage == AIM_XFER_PROXY_STG1
-				|| peer_connection->stage == AIM_XFER_PROXY_STG3) {
-			gaim_debug_info("oscar","sending INIT RECV for stage 1/3 rv proxied receive\n");
-			if( (err = aim_rv_proxy_init_recv(proxy_info)) ) {
-				gaim_xfer_error(GAIM_XFER_SEND, gaim_xfer_get_account(xfer), xfer->who,
-								_("Unable to log into file transfer proxy."));
-				gaim_debug_info("oscar", "error while sending INIT RECV rv proxy packet: %s\n",
-					strerror(err));
-				gaim_xfer_cancel_local(xfer);
-			}
-		} else {
-			gaim_debug_warning("oscar","no proxy type specified; aborting transfer\n");
-			gaim_xfer_cancel_local(xfer);
-		}
-	} else {
-		gaim_debug_warning("oscar","no send_or_recv value specified; aborting\n");
-		gaim_xfer_cancel_local(xfer);
-	}
-	free(proxy_info);
-	peer_connection->proxy_info = NULL;
-
-	xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_xfer_proxylogin_cb, xfer);
-}
-
-
- /*
- * xfer functions used when sending files
- */
-
-/*
- * Send a request to another client notifying them we want to sent a file
- */
-static void oscar_send_file_request(GaimXfer *xfer)
-{
-	PeerConnection *peer_connection = xfer->data;
-	GaimConnection *gc = peer_connection->sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	gaim_debug_info("oscar", "AAA - in oscar_send_file_request\n");
-
-	if (peer_connection->conn) {
-		xfer->filename = g_path_get_basename(xfer->local_filename);
-		strncpy(peer_connection->fh.name, xfer->filename, 64);
-		peer_connection->fh.name[63] = '\0';
-		peer_connection->fh.totsize = gaim_xfer_get_size(xfer);
-		peer_connection->fh.size = gaim_xfer_get_size(xfer);
-
-		/* Calculating the checksum can take a very long time for large files */
-		gaim_debug_info("oscar","calculating file checksum\n");
-		peer_connection->fh.checksum = aim_oft_checksum_file(xfer->local_filename);
-		gaim_debug_info("oscar","checksum calculated\n");
-
-		memcpy(&peer_connection->fh.bcookie, peer_connection->cookie, 8);
-
-		aim_im_sendch2_sendfile_ask(od->sess, peer_connection);
-		aim_conn_addhandler(od->sess, peer_connection->conn, AIM_CB_FAM_OFT,
-			PEER_TYPE_ESTABLISHED, oscar_sendfile_estblsh, 0);
-	} else {
-		gaim_xfer_error(GAIM_XFER_SEND, gaim_xfer_get_account(xfer), xfer->who,
-						_("Unable to establish listener socket or no AOL proxy connection present."));
-		gaim_xfer_cancel_local(xfer);
-	}
-}
-
-static void
-oscar_xfer_init_listen_cb(int listenfd, gpointer data) {
-	GaimXfer *xfer = data;
-	PeerConnection *peer_connection;
-	GaimConnection *gc;
-	OscarData *od;
-
-	/* If the ft was canceled before we get here, don't continue */
-	if(gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) {
-		gaim_xfer_unref(xfer);
-		return;
-	}
-
-	peer_connection = xfer->data;
-	gc = peer_connection->sess->aux_data;
-	od = gc->proto_data;
-
-	if (listenfd < 0) {
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-
-	xfer->local_port = gaim_network_get_port_from_fd(listenfd);
-	peer_connection->port = xfer->local_port;
-	if (aim_sendfile_listen(od->sess, peer_connection, listenfd) != 0) {
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-	gaim_debug_misc("oscar", "port is %hu, ip is %s\n",
-					xfer->local_port, peer_connection->clientip);
-
-	if(peer_connection->conn)
-		xfer->watcher = gaim_input_add(peer_connection->conn->fd, GAIM_INPUT_READ, oscar_callback,
-			peer_connection->conn);
-	else
-		gaim_debug_info("oscar","NULL peer_connection->conn; not adding watcher\n");
-
-	oscar_send_file_request(xfer);
-}
-
-
-/*
- * Opens a listener socket in preparation for sending a file
- * This is not called if we are using a rendezvous proxy server
- */
-static void oscar_xfer_init_send(GaimXfer *xfer)
-{
-	gaim_debug_info("oscar", "AAA - in oscar_xfer_init_send\n");
-
-	gaim_xfer_ref(xfer);
-
-	/* Create a listening socket and an associated libfaim conn */
-	if (!gaim_network_listen_range(5190, 5199, SOCK_STREAM,
-				oscar_xfer_init_listen_cb, xfer)) {
-		gaim_xfer_unref(xfer);
-		gaim_xfer_cancel_local(xfer);
-		return;
-	}
-}
-
-/*
- * "On second thought, you don't deserve this file."
- */
-static void oscar_xfer_cancel_send(GaimXfer *xfer)
-{
-	PeerConnection *peer_connection = xfer->data;
-	GaimConnection *gc = peer_connection->sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	gaim_debug_info("oscar", "AAA - in oscar_xfer_cancel_send\n");
-
-	if (gaim_xfer_get_status(xfer) != GAIM_XFER_STATUS_CANCEL_REMOTE)
-		aim_im_sendch2_sendfile_cancel(peer_connection->sess, peer_connection);
-
-	/* Added a few sanity checks to prevent segfaulting */
-	if(peer_connection) {
-		if(peer_connection->sess && peer_connection->conn)
-			oscar_connection_destroy(peer_connection->sess, peer_connection->conn);
-		aim_oft_destroyinfo(peer_connection);
-	}
-	xfer->data = NULL;
-	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
-}
-
-/*
- * Called when we send some data to the other client
- */
-static void oscar_xfer_ack_send(GaimXfer *xfer, const guchar *buffer, size_t size)
-{
-	PeerConnection *peer_connection = xfer->data;
-
-	/* I'm not sure I like how we do this. --marv
-	 * I do.  AIM file transfers aren't really meant to be thought
-	 * of as a transferring just a single file.  The rendezvous
-	 * establishes a connection between two computers, and then
-	 * those computers can use the same connection for transferring
-	 * multiple files.  So we don't want the Gaim core up and closing
-	 * the socket all willy-nilly.  We want to do that in the oscar
-	 * prpl, whenever one side or the other says they're finished
-	 * using the connection.  There might be a better way to intercept
-	 * the socket from the core, however...  --KingAnt
-	 */
-
-	/*
-	 * If we're done sending, intercept the socket from the core ft code
-	 * and wait for the other guy to send the "done" OFT packet.
-	 */
-	if (gaim_xfer_get_bytes_remaining(xfer) <= 0) {
-		gaim_input_remove(xfer->watcher);
-		xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, peer_connection->conn);
-		xfer->fd = 0;
-		gaim_xfer_set_completed(xfer, TRUE);
-	}
-}
-
-/*
- * Called by the Gaim core to determine whether or not we're allowed to send a file
- * to this user.
- */
-static gboolean oscar_can_receive_file(GaimConnection *gc, const char *who) {
-	OscarData *od = gc->proto_data;
-
-	if (od != NULL) {
-		aim_userinfo_t *userinfo;
-		userinfo = aim_locate_finduserinfo(od->sess, who);
-
-		/*
-		 * Don't allowing sending a file to a user that does not support
-		 * file transfer, and don't allow sending to ourselves.
-		 */
-		if (userinfo && (userinfo->capabilities & AIM_CAPS_SENDFILE) &&
-			aim_sncmp(who, gaim_account_get_username(gaim_connection_get_account(gc))))
-		{
-			return TRUE;
-		}
-
-	}
-
-	return FALSE;
-}
-
-static GaimXfer*
-oscar_new_xfer(GaimConnection *gc, const char *who) {
-	OscarData *od;
-	GaimXfer *xfer;
-	PeerConnection *peer_connection;
-	const char *ip;
-	gboolean use_rv_proxy;
-
-	use_rv_proxy = gaim_account_get_bool(gc->account, "use_rv_proxy", OSCAR_DEFAULT_USE_RV_PROXY);
-	if(use_rv_proxy)
-		gaim_debug_info("oscar","using stage 1 proxied transfer\n");
-
-	od = (OscarData *)gc->proto_data;
-
-	/* You want to send a file to someone else, you're so generous */
-
-	/* Build the file transfer handle */
-	xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who);
-
-	/* Create the oscar-specific data */
-	if (use_rv_proxy) {
-		/* This hostname will be resolved by gaim_proxy_connect */
-		xfer->remote_ip = g_strdup(AIM_RV_PROXY_SERVER_URL);
-		xfer->remote_port = AIM_RV_PROXY_CONNECT_PORT;
-		peer_connection = aim_oft_createinfo(od->sess, NULL /*cookie*/, who, 0 /*ip*/, 0, 0, 0, NULL,
-			AIM_XFER_SEND, AIM_XFER_PROXY, AIM_XFER_PROXY_STG1);
-		peer_connection->proxy_info = aim_rv_proxy_createinfo(peer_connection->sess, NULL, 0);
-		/* We must create a cookie before the request is sent
-		 * so that it can be sent to the proxy */
-		aim_icbm_makecookie(peer_connection->cookie);
-	} else {
-		ip = gaim_network_get_my_ip(od->conn ? od->conn->fd : -1);
-		peer_connection = aim_oft_createinfo(od->sess, NULL, who, ip, 0, 0, 0, NULL,
-			AIM_XFER_SEND, AIM_XFER_DIRECT, AIM_XFER_PROXY_NONE);
-	}
-	xfer->data = peer_connection;
-
-	/* Setup our I/O op functions */
-	if (use_rv_proxy)
-		gaim_xfer_set_init_fnc(xfer, oscar_xfer_init_recv);
-	else
-		gaim_xfer_set_init_fnc(xfer, oscar_xfer_init_send);
-	gaim_xfer_set_end_fnc(xfer, oscar_xfer_end);
-	gaim_xfer_set_cancel_send_fnc(xfer, oscar_xfer_cancel_send);
-	gaim_xfer_set_request_denied_fnc(xfer, oscar_xfer_cancel_send);
-	gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack_send);
-
-	/* Keep track of this transfer for later */
-	od->file_transfers = g_slist_append(od->file_transfers, xfer);
-
-	return xfer;
-}
-
-/*
- * Called by the Gaim core when the user indicates that a file is to be sent to
- * a special someone.
- */
-static void oscar_send_file(GaimConnection *gc, const char *who, const char *file) {
-	GaimXfer *xfer = oscar_new_xfer(gc, who);
-
-	/* Now perform the request */
-	if (file)
-		gaim_xfer_request_accepted(xfer, file);
-	else
-		gaim_xfer_request(xfer);
-}
-
-static int gaim_parse_auth_resp(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
+	GaimConnection *gc = od->gc;
 	GaimAccount *account = gc->account;
-	OscarConnection *bosconn;
 	char *host; int port;
 	int i, rc;
+	NewFlapConnectionData *new_conn_data;
 	va_list ap;
 	struct aim_authresp_info *info;
 
@@ -2937,88 +1346,31 @@
 
 
 	gaim_debug_misc("oscar", "Reg status: %hu\n", info->regstatus);
-
-	if (info->email) {
-		gaim_debug_misc("oscar", "E-mail: %s\n", info->email);
-	} else {
-		gaim_debug_misc("oscar", "E-mail is NULL\n");
-	}
-
+	gaim_debug_misc("oscar", "E-mail: %s\n",
+					(info->email != NULL) ? info->email : "null");
 	gaim_debug_misc("oscar", "BOSIP: %s\n", info->bosip);
 	gaim_debug_info("oscar", "Closing auth connection...\n");
-	oscar_connection_destroy(sess, fr->conn);
-
-	bosconn = oscar_connection_new(sess, AIM_CONN_TYPE_BOS);
-	if (bosconn == NULL) {
-		gaim_connection_error(gc, _("Internal Error"));
-		od->killme = TRUE;
-		return 0;
-	}
-
-	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0);
-	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_bos, 0);
-	aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, gaim_bosrights, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_OSERVICE, OSCAR_SUBTYPE_OSERVICE_REDIRECT, gaim_handle_redirect, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_LOCATE, OSCAR_SUBTYPE_LOCATE_RIGHTSINFO, gaim_parse_locaterights, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_BUDDY, OSCAR_SUBTYPE_BUDDY_RIGHTSINFO, gaim_parse_buddyrights, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_BUDDY, OSCAR_SUBTYPE_BUDDY_ONCOMING, gaim_parse_oncoming, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_BUDDY, OSCAR_SUBTYPE_BUDDY_OFFGOING, gaim_parse_offgoing, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_ICBM, OSCAR_SUBTYPE_ICBM_INCOMING, gaim_parse_incoming_im, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_LOCATE, OSCAR_SUBTYPE_LOCATE_ERROR, gaim_parse_locerr, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_ICBM, OSCAR_SUBTYPE_ICBM_MISSEDCALL, gaim_parse_misses, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_ICBM, OSCAR_SUBTYPE_ICBM_CLIENTAUTORESP, gaim_parse_clientauto, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_OSERVICE, OSCAR_SUBTYPE_OSERVICE_RATECHANGE, gaim_parse_ratechange, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_OSERVICE, OSCAR_SUBTYPE_OSERVICE_EVIL, gaim_parse_evilnotify, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_USERLOOKUP, OSCAR_SUBTYPE_USERLOOKUP_ERROR, gaim_parse_searcherror, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_USERLOOKUP, 0x0003, gaim_parse_searchreply, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_ICBM, OSCAR_SUBTYPE_ICBM_ERROR, gaim_parse_msgerr, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_ICBM, OSCAR_SUBTYPE_ICBM_MTN, gaim_parse_mtn, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_LOCATE, OSCAR_SUBTYPE_LOCATE_USERINFO, gaim_parse_userinfo, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_LOCATE, OSCAR_SUBTYPE_LOCATE_REQUESTINFOTIMEOUT, gaim_reqinfo_timeout, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_LOCATE, OSCAR_SUBTYPE_LOCATE_GOTINFOBLOCK, gaim_got_infoblock, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_ICBM, OSCAR_SUBTYPE_ICBM_ACK, gaim_parse_msgack, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_OSERVICE, OSCAR_SUBTYPE_OSERVICE_MOTD, gaim_parse_motd, 0);
-	aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, gaim_icbm_param_info, 0);
-	aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, gaim_parse_genericerr, 0);
-	aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, gaim_parse_genericerr, 0);
-	aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, gaim_parse_genericerr, 0);
-	aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, gaim_memrequest, 0);
-	aim_conn_addhandler(sess, bosconn, 0x0001, 0x000f, gaim_selfinfo, 0);
-	aim_conn_addhandler(sess, bosconn, 0x0001, 0x0021, oscar_icon_req,0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_ICQ, OSCAR_SUBTYPE_ICQ_OFFLINEMSG, gaim_offlinemsg, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_ICQ, OSCAR_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE, gaim_offlinemsgdone, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_POPUP, 0x0002, gaim_popup, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_ICQ, OSCAR_SUBTYPE_ICQ_ALIAS, gaim_icqalias, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_ICQ, OSCAR_SUBTYPE_ICQ_INFO, gaim_icqinfo, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_ERROR, gaim_ssi_parseerr, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_RIGHTSINFO, gaim_ssi_parserights, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_LIST, gaim_ssi_parselist, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_NOLIST, gaim_ssi_parselist, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_SRVACK, gaim_ssi_parseack, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_ADD, gaim_ssi_parseadd, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_RECVAUTH, gaim_ssi_authgiven, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_RECVAUTHREQ, gaim_ssi_authrequest, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_RECVAUTHREP, gaim_ssi_authreply, 0);
-	aim_conn_addhandler(sess, bosconn, OSCAR_FAMILY_FEEDBAG, OSCAR_SUBTYPE_FEEDBAG_ADDED, gaim_ssi_gotadded, 0);
-
-	od->conn = bosconn;
-	for (i = 0; i < (int)strlen(info->bosip); i++) {
+	flap_connection_schedule_destroy(conn);
+
+	for (i = 0; i < strlen(info->bosip); i++) {
 		if (info->bosip[i] == ':') {
 			port = atoi(&(info->bosip[i+1]));
 			break;
 		}
 	}
 	host = g_strndup(info->bosip, i);
-	bosconn->status |= AIM_CONN_STATUS_INPROGRESS;
-	rc = gaim_proxy_connect(gc->account, host, port, oscar_bos_connect, gc);
+	new_conn_data = g_new(NewFlapConnectionData, 1);
+	new_conn_data->gc = gc;
+	new_conn_data->conn = flap_connection_new(od, SNAC_FAMILY_LOCATE);
+	new_conn_data->cookielen = info->cookielen;
+	new_conn_data->cookie = g_memdup(info->cookie, info->cookielen);
+	rc = gaim_proxy_connect(gc->account, host, port, connection_established_cb, new_conn_data);
 	g_free(host);
 	if (rc < 0) {
 		gaim_connection_error(gc, _("Could Not Connect"));
 		od->killme = TRUE;
 		return 0;
 	}
-	aim_sendcookie(sess, bosconn, info->cookielen, info->cookie);
-	gaim_input_remove(gc->inpa);
 
 	gaim_connection_update_progress(gc, _("Received authorization"), 3, OSCAR_CONNECT_STEPS);
 	ck[3] = 0x64;
@@ -3031,9 +1383,8 @@
 {
 	GaimConnection *gc = user_data;
 	OscarData *od = gc->proto_data;
-	OscarSession *sess = od->sess;
-
-	aim_auth_securid_send(sess, msg);
+
+	aim_auth_securid_send(od, msg);
 }
 
 static void
@@ -3049,9 +1400,9 @@
 }
 
 static int
-gaim_parse_auth_securid_request(OscarSession *sess, FlapFrame *fr, ...)
+gaim_parse_auth_securid_request(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	GaimConnection *gc = sess->aux_data;
+	GaimConnection *gc = od->gc;
 	GaimAccount *account = gaim_connection_get_account(gc);
 	gchar *primary;
 
@@ -3076,7 +1427,7 @@
 	unsigned long len;
 	char *modname;
 	int fd;
-	OscarConnection *conn;
+	FlapConnection *conn;
 	unsigned int inpa;
 };
 
@@ -3118,7 +1469,7 @@
 	gaim_debug_misc(NULL, "\n");
 	gaim_input_remove(pos->inpa);
 	close(pos->fd);
-	aim_sendmemblock(od->sess, pos->conn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH);
+	aim_sendmemblock(od, pos->conn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH);
 	g_free(pos);
 }
 
@@ -3141,9 +1492,6 @@
 		return;
 	}
 
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(source, F_SETFL, 0);
-
 	buf = g_strdup_printf("GET " AIMHASHDATA "?offset=%ld&len=%ld&modname=%s HTTP/1.0\n\n",
 			pos->offset, pos->len, pos->modname ? pos->modname : "");
 	write(pos->fd, buf, strlen(buf));
@@ -3157,7 +1505,7 @@
 /* size of icbmui.ocm, the largest module in AIM 3.5 */
 #define AIM_MAX_FILE_SIZE 98304
 
-int gaim_memrequest(OscarSession *sess, FlapFrame *fr, ...) {
+int gaim_memrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	struct pieceofcrap *pos;
 	guint32 offset, len;
@@ -3174,7 +1522,7 @@
 
 	if (len == 0) {
 		gaim_debug_misc("oscar", "len is 0, hashing NULL\n");
-		aim_sendmemblock(sess, fr->conn, offset, len, NULL,
+		aim_sendmemblock(od, conn, offset, len, NULL,
 				AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
 		return 1;
 	}
@@ -3201,27 +1549,28 @@
 		buf[i++] = (len >> 24) & 0xff;
 		gaim_debug_misc("oscar", "len + offset is invalid, "
 		           "hashing request\n");
-		aim_sendmemblock(sess, command->conn, offset, i, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
+		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 = sess->aux_data;
-	pos->conn = fr->conn;
+	pos->gc = od->gc;
+	pos->conn = conn;
 
 	pos->offset = offset;
 	pos->len = len;
 	pos->modname = modname ? g_strdup(modname) : NULL;
 
-	if (gaim_proxy_connect(pos->gc->account, "gaim.sourceforge.net", 80, straight_to_hell, pos) != 0) {
+	if (gaim_proxy_connect(pos->gc->account, "gaim.sourceforge.net", 80, straight_to_hell, pos) != 0)
+	{
 		char buf[256];
 		if (pos->modname)
 			g_free(pos->modname);
 		g_free(pos);
-		g_snprintf(buf, sizeof(buf), _("You may be disconnected shortly.  You may want to use TOC until "
-			"this is fixed.  Check %s for updates."), GAIM_WEBSITE);
+		g_snprintf(buf, sizeof(buf), _("You may be disconnected shortly.  "
+			"Check %s for updates."), GAIM_WEBSITE);
 		gaim_notify_warning(pos->gc, NULL,
 							_("Gaim was unable to get a valid login hash."),
 							buf);
@@ -3230,18 +1579,23 @@
 	return 1;
 }
 
-static int gaim_parse_login(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	GaimAccount *account = gaim_connection_get_account(gc);
+static int
+gaim_parse_login(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
+{
+	GaimConnection *gc;
+	GaimAccount *account;
 	ClientInfo info = CLIENTINFO_GAIM;
 	va_list ap;
 	char *key;
 
+	gc = od->gc;
+	account = gaim_connection_get_account(gc);
+
 	va_start(ap, fr);
 	key = va_arg(ap, char *);
 	va_end(ap);
 
-	aim_send_login(sess, fr->conn, gaim_account_get_username(account),
+	aim_send_login(od, conn, gaim_account_get_username(account),
 				   gaim_connection_get_password(gc), &info, key);
 
 	gaim_connection_update_progress(gc, _("Password sent"), 2, OSCAR_CONNECT_STEPS);
@@ -3250,396 +1604,69 @@
 	return 1;
 }
 
-static int conninitdone_chat(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	struct chat_connection *chatcon;
-	static int id = 1;
-
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_CHAT, 0x0001, gaim_parse_genericerr, 0);
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_CHAT, OSCAR_SUBTYPE_CHAT_USERJOIN, gaim_conv_chat_join, 0);
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_CHAT, OSCAR_SUBTYPE_CHAT_USERLEAVE, gaim_conv_chat_leave, 0);
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_CHAT, OSCAR_SUBTYPE_CHAT_ROOMINFOUPDATE, gaim_conv_chat_info_update, 0);
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_CHAT, OSCAR_SUBTYPE_CHAT_INCOMINGMSG, gaim_conv_chat_incoming_msg, 0);
-
-	aim_clientready(sess, fr->conn);
-
-	chatcon = find_oscar_chat_by_conn(gc, fr->conn);
-	chatcon->id = id;
-	chatcon->conv = serv_got_joined_chat(gc, id++, chatcon->show);
-
-	return 1;
-}
-
-static int conninitdone_chatnav(OscarSession *sess, FlapFrame *fr, ...) {
-
-	aim_conn_addhandler(sess, fr->conn, 0x000d, 0x0001, gaim_parse_genericerr, 0);
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_CHATNAV, OSCAR_SUBTYPE_CHATNAV_INFO, gaim_chatnav_info, 0);
-
-	aim_clientready(sess, fr->conn);
-
-	aim_chatnav_reqrights(sess, fr->conn);
-
-	return 1;
-}
-
-static int conninitdone_email(OscarSession *sess, FlapFrame *fr, ...) {
-
-	aim_conn_addhandler(sess, fr->conn, 0x0018, 0x0001, gaim_parse_genericerr, 0);
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_ALERT, OSCAR_SUBTYPE_ALERT_MAILSTATUS, gaim_email_parseupdate, 0);
-
-	aim_email_sendcookies(sess);
-	aim_email_activate(sess);
-	aim_clientready(sess, fr->conn);
-
-	return 1;
-}
-
-static int conninitdone_icon(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	aim_conn_addhandler(sess, fr->conn, 0x0018, 0x0001, gaim_parse_genericerr, 0);
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_BART, OSCAR_SUBTYPE_BART_ERROR, gaim_icon_error, 0);
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_BART, OSCAR_SUBTYPE_BART_RESPONSE, gaim_icon_parseicon, 0);
-
-	aim_clientready(sess, fr->conn);
-
-	od->iconconnecting = FALSE;
-
-	if (od->icontimer)
-		gaim_timeout_remove(od->icontimer);
-	od->icontimer = gaim_timeout_add(100, gaim_icon_timerfunc, gc);
-
-	return 1;
-}
-
-static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition cond) {
-	GaimConnection *gc = data;
-	OscarData *od;
-	OscarSession *sess;
-	OscarConnection *tstconn;
-
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		close(source);
-		return;
-	}
-
-	od = gc->proto_data;
-	sess = od->sess;
-	tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_CHATNAV);
-	tstconn->fd = source;
-
-	if (source < 0) {
-		oscar_connection_destroy(sess, tstconn);
-		gaim_debug_error("oscar", "unable to connect to chatnav server\n");
-		return;
-	}
-
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(source, F_SETFL, 0);
-
-	aim_conn_completeconnect(sess, tstconn);
-	od->cnpa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, oscar_callback, tstconn);
-	gaim_debug_info("oscar", "chatnav: connected\n");
-}
-
-static void oscar_auth_connect(gpointer data, gint source, GaimInputCondition cond)
+static int
+gaim_handle_redirect(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	GaimConnection *gc = data;
-	OscarData *od;
-	OscarSession *sess;
-	OscarConnection *tstconn;
-
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		close(source);
-		return;
-	}
-
-	od = gc->proto_data;
-	sess = od->sess;
-	tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH);
-	tstconn->fd = source;
-
-	if (source < 0) {
-		oscar_connection_destroy(sess, tstconn);
-		gaim_debug_error("oscar", "unable to connect to authorizer\n");
-		return;
-	}
-
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(source, F_SETFL, 0);
-
-	aim_conn_completeconnect(sess, tstconn);
-	od->paspa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, oscar_callback, tstconn);
-	gaim_debug_info("oscar", "admin: connected\n");
-}
-
-static void oscar_chat_connect(gpointer data, gint source, GaimInputCondition cond)
-{
-	struct chat_connection *ccon = data;
-	GaimConnection *gc = ccon->gc;
-	OscarData *od;
-	OscarSession *sess;
-	OscarConnection *tstconn;
-
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		close(source);
-		g_free(ccon->show);
-		g_free(ccon->name);
-		g_free(ccon);
-		return;
-	}
-
-	od = gc->proto_data;
-	sess = od->sess;
-	tstconn = ccon->conn;
-	tstconn->fd = source;
-
-	if (source < 0) {
-		oscar_connection_destroy(sess, tstconn);
-		g_free(ccon->show);
-		g_free(ccon->name);
-		g_free(ccon);
-		return;
-	}
-
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(source, F_SETFL, 0);
-
-	aim_conn_completeconnect(sess, ccon->conn);
-	ccon->inpa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, oscar_callback, tstconn);
-	od->oscar_chats = g_slist_append(od->oscar_chats, ccon);
-}
-
-static void oscar_email_connect(gpointer data, gint source, GaimInputCondition cond) {
-	GaimConnection *gc = data;
-	OscarData *od;
-	OscarSession *sess;
-	OscarConnection *tstconn;
-
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		close(source);
-		return;
-	}
-
-	od = gc->proto_data;
-	sess = od->sess;
-	tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_EMAIL);
-	tstconn->fd = source;
-
-	if (source < 0) {
-		oscar_connection_destroy(sess, tstconn);
-		gaim_debug_error("oscar", "unable to connect to email server\n");
-		return;
-	}
-
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(source, F_SETFL, 0);
-
-	aim_conn_completeconnect(sess, tstconn);
-	od->emlpa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, oscar_callback, tstconn);
-	gaim_debug_info("oscar", "email: connected\n");
-}
-
-static void oscar_icon_connect(gpointer data, gint source, GaimInputCondition cond) {
-	GaimConnection *gc = data;
-	OscarData *od;
-	OscarSession *sess;
-	OscarConnection *tstconn;
-
-	if (!g_list_find(gaim_connections_get_all(), gc)) {
-		close(source);
-		return;
-	}
-
-	od = gc->proto_data;
-	sess = od->sess;
-	tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_ICON);
-	tstconn->fd = source;
-
-	if (source < 0) {
-		oscar_connection_destroy(sess, tstconn);
-		gaim_debug_error("oscar", "unable to connect to icon server\n");
-		return;
-	}
-
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(source, F_SETFL, 0);
-
-	aim_conn_completeconnect(sess, tstconn);
-	od->icopa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, oscar_callback, tstconn);
-	gaim_debug_info("oscar", "icon: connected\n");
-}
-
-/* Hrmph. I don't know how to make this look better. --mid */
-static int gaim_handle_redirect(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+	GaimConnection *gc = od->gc;
 	GaimAccount *account = gaim_connection_get_account(gc);
-	OscarConnection *tstconn;
-	int i;
-	char *host;
+	char *host, *separator;
 	int port;
+	NewFlapConnectionData *new_conn_data;
 	va_list ap;
 	struct aim_redirect_data *redir;
 
-	port = gaim_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT);
-
 	va_start(ap, fr);
 	redir = va_arg(ap, struct aim_redirect_data *);
 	va_end(ap);
 
-	for (i = 0; i < (int)strlen(redir->ip); i++) {
-		if (redir->ip[i] == ':') {
-			port = atoi(&(redir->ip[i+1]));
-			break;
-		}
-	}
-	host = g_strndup(redir->ip, i);
-
-	switch(redir->group) {
-	case 0x7: /* Authorizer */
-		gaim_debug_info("oscar", "Reconnecting with authorizor...\n");
-		tstconn = oscar_connection_new(sess, AIM_CONN_TYPE_AUTH);
-		if (tstconn == NULL) {
-			gaim_debug_error("oscar",
-					   "unable to reconnect with authorizer\n");
-			g_free(host);
-			return 1;
-		}
-		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0);
-		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_admin, 0);
-
-		tstconn->status |= AIM_CONN_STATUS_INPROGRESS;
-		if (gaim_proxy_connect(account, host, port, oscar_auth_connect, gc) != 0) {
-			oscar_connection_destroy(sess, tstconn);
-			gaim_debug_error("oscar",
-					   "unable to reconnect with authorizer\n");
-			g_free(host);
-			return 1;
-		}
-		aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
-	break;
-
-	case 0xd: /* ChatNav */
-		tstconn = oscar_connection_new(sess, AIM_CONN_TYPE_CHATNAV);
-		if (tstconn == NULL) {
-			gaim_debug_error("oscar",
-					   "unable to connect to chatnav server\n");
-			g_free(host);
-			return 1;
-		}
-		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0);
-		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chatnav, 0);
-
-		tstconn->status |= AIM_CONN_STATUS_INPROGRESS;
-		if (gaim_proxy_connect(account, host, port, oscar_chatnav_connect, gc) != 0) {
-			oscar_connection_destroy(sess, tstconn);
-			gaim_debug_error("oscar",
-					   "unable to connect to chatnav server\n");
-			g_free(host);
-			return 1;
-		}
-		aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
-	break;
-
-	case 0xe: { /* Chat */
-		struct chat_connection *ccon;
-
-		tstconn = oscar_connection_new(sess, AIM_CONN_TYPE_CHAT);
-		if (tstconn == NULL) {
-			gaim_debug_error("oscar",
-					   "unable to connect to chat server\n");
-			g_free(host);
-			return 1;
-		}
-
-		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0);
-		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
-
-		ccon = g_new0(struct chat_connection, 1);
-		ccon->conn = tstconn;
-		ccon->gc = gc;
-		ccon->name = g_strdup(redir->chat.room);
-		ccon->exchange = redir->chat.exchange;
-		ccon->instance = redir->chat.instance;
-		ccon->show = extract_name(redir->chat.room);
-
-		ccon->conn->status |= AIM_CONN_STATUS_INPROGRESS;
-		if (gaim_proxy_connect(account, host, port, oscar_chat_connect, ccon) != 0) {
-			oscar_connection_destroy(sess, tstconn);
-			gaim_debug_error("oscar",
-					   "unable to connect to chat server\n");
-			g_free(host);
-			g_free(ccon->show);
-			g_free(ccon->name);
-			g_free(ccon);
-			return 1;
-		}
-		aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
-		gaim_debug_info("oscar",
-				   "Connected to chat room %s exchange %hu\n",
-				   ccon->name, ccon->exchange);
-	} break;
-
-	case 0x0010: { /* icon */
-		if (!(tstconn = oscar_connection_new(sess, AIM_CONN_TYPE_ICON))) {
-			gaim_debug_error("oscar",
-					   "unable to connect to icon server\n");
-			g_free(host);
-			return 1;
-		}
-		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0);
-		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_icon, 0);
-
-		tstconn->status |= AIM_CONN_STATUS_INPROGRESS;
-		if (gaim_proxy_connect(account, host, port, oscar_icon_connect, gc) != 0) {
-			oscar_connection_destroy(sess, tstconn);
-			gaim_debug_error("oscar",
-					   "unable to connect to icon server\n");
-			g_free(host);
-			return 1;
-		}
-		aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
-	} break;
-
-	case 0x0018: { /* email */
-		if (!(tstconn = oscar_connection_new(sess, AIM_CONN_TYPE_EMAIL))) {
-			gaim_debug_error("oscar",
-					   "unable to connect to email server\n");
-			g_free(host);
-			return 1;
-		}
-		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0);
-		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_email, 0);
-
-		tstconn->status |= AIM_CONN_STATUS_INPROGRESS;
-		if (gaim_proxy_connect(account, host, port, oscar_email_connect, gc) != 0) {
-			oscar_connection_destroy(sess, tstconn);
-			gaim_debug_error("oscar",
-					   "unable to connect to email server\n");
-			g_free(host);
-			return 1;
-		}
-		aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
-	} break;
-
-	default: /* huh? */
-		gaim_debug_warning("oscar",
-				   "got redirect for unknown service 0x%04hx\n",
-				   redir->group);
-		break;
-	}
-
+	port = gaim_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT);
+	separator = strchr(redir->ip, ':');
+	if (separator != NULL)
+	{
+		host = g_strndup(redir->ip, (int)separator - (int)host);
+		port = atoi(separator + 1);
+	}
+	else
+		host = g_strdup(redir->ip);
+
+	gaim_debug_info("oscar", "Connecting to FLAP server %s:%d of type 0x%04hx\n",
+					host, port, redir->group);
+	new_conn_data = g_new(NewFlapConnectionData, 1);
+	new_conn_data->gc = gc;
+	new_conn_data->conn = flap_connection_new(od, redir->group);
+	new_conn_data->cookielen = redir->cookielen;
+	new_conn_data->cookie = g_memdup(redir->cookie, redir->cookielen);
+	if (new_conn_data->conn->type == SNAC_FAMILY_CHAT)
+	{
+		struct chat_connection *cc;
+		cc = g_new0(struct chat_connection, 1);
+		cc->conn = new_conn_data->conn;
+		cc->gc = gc;
+		cc->name = g_strdup(redir->chat.room);
+		cc->exchange = redir->chat.exchange;
+		cc->instance = redir->chat.instance;
+		cc->show = extract_name(redir->chat.room);
+		new_conn_data->data = cc;
+		gaim_debug_info("oscar", "Connecting to chat room %s exchange %hu\n", cc->name, cc->exchange);
+	}
+
+	if (gaim_proxy_connect(account, host, port, connection_established_cb, new_conn_data) != 0)
+	{
+		flap_connection_schedule_destroy(new_conn_data->conn);
+		gaim_debug_error("oscar", "Unable to connect to FLAP server "
+				"of type 0x%04hx\n", redir->group);
+		destroy_new_conn_data(new_conn_data);
+	}
 	g_free(host);
+
 	return 1;
 }
 
-static int gaim_parse_oncoming(OscarSession *sess, FlapFrame *fr, ...)
+static int gaim_parse_oncoming(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
 	GaimConnection *gc;
 	GaimAccount *account;
 	GaimPresence *presence;
-	OscarData *od;
 	struct buddyinfo *bi;
 	time_t time_idle = 0, signon = 0;
 	int type = 0;
@@ -3650,10 +1677,9 @@
 	va_list ap;
 	aim_userinfo_t *info;
 
-	gc = sess->aux_data;
+	gc = od->gc;
 	account = gaim_connection_get_account(gc);
 	presence = gaim_account_get_presence(account);
-	od = gc->proto_data;
 
 	va_start(ap, fr);
 	info = va_arg(ap, aim_userinfo_t *);
@@ -3797,14 +1823,13 @@
 
 static void gaim_check_comment(OscarData *od, const char *str) {
 	if ((str == NULL) || strcmp(str, (const char *)ck))
-		aim_locate_setcaps(od->sess, caps_aim);
+		aim_locate_setcaps(od, caps_aim);
 	else
-		aim_locate_setcaps(od->sess, caps_aim | AIM_CAPS_SECUREIM);
-}
-
-static int gaim_parse_offgoing(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
+		aim_locate_setcaps(od, caps_aim | OSCAR_CAPABILITY_SECUREIM);
+}
+
+static int gaim_parse_offgoing(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	GaimAccount *account = gaim_connection_get_account(gc);
 	va_list ap;
 	aim_userinfo_t *info;
@@ -3820,250 +1845,8 @@
 	return 1;
 }
 
-/* BBB */
-/*
- * This is called after a remote AIM user has connected to us.
- * If not using a rendezvous proxy, then we want to do some
- * voodoo with the socket file descriptors. Then we always
- * add a callback or two, and then send the PEER_TYPE_PROMPT.
- */
-static int oscar_sendfile_estblsh(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = (OscarData *)gc->proto_data;
-	GaimXfer *xfer;
-	PeerConnection *peer_connection;
-	va_list ap;
-	OscarConnection *conn, *listenerconn;
-
-	gaim_debug_info("oscar", "AAA - in oscar_sendfile_estblsh\n");
-
-	va_start(ap, fr);
-	conn = va_arg(ap, OscarConnection *);
-	listenerconn = va_arg(ap, OscarConnection *);
-	va_end(ap);
-
-	/* Finding by conn will work for proxied connections only
-	 * Finding by listenerconn will work for direct connections only */
-	if (!(xfer = oscar_find_xfer_by_conn(od->file_transfers, conn))) {
-		if(!(xfer = oscar_find_xfer_by_conn(od->file_transfers, listenerconn))) {
-			gaim_debug_warning("oscar","xfer not found via connection\n");
-			return 1;
-		}
-	}
-	if (!(peer_connection = xfer->data)) {
-		gaim_debug_warning("oscar","NULL data\n");
-		return 1;
-	}
-
-	/* Mark connection as success so further connections aren't attempted
-	 * This is important here since some receive file code paths pass through here */
-	peer_connection->success = TRUE;
-
-	if(peer_connection->method != AIM_XFER_PROXY) {
-		/* Stop watching listener conn; watch transfer conn instead */
-		gaim_input_remove(xfer->watcher);
-
-		oscar_connection_destroy(sess, listenerconn);
-
-		peer_connection->conn = conn;
-		xfer->fd = peer_connection->conn->fd;
-	}
-
-	xfer->watcher = gaim_input_add(peer_connection->conn->fd, GAIM_INPUT_READ, oscar_callback, peer_connection->conn);
-
-	if(peer_connection->send_or_recv == AIM_XFER_SEND) {
-		aim_conn_addhandler(peer_connection->sess, peer_connection->conn, AIM_CB_FAM_OFT, PEER_TYPE_ACK,
-			oscar_sendfile_ack, 0);
-		aim_conn_addhandler(peer_connection->sess, peer_connection->conn, AIM_CB_FAM_OFT, PEER_TYPE_DONE,
-			oscar_sendfile_done, 0);
-
-		/* Inform the other user that we are connected and ready to transfer */
-		aim_oft_sendheader(sess, PEER_TYPE_PROMPT, peer_connection);
-	}
-
-	/* For a file send, we'll hopefully end up in oscar_sendfile_ack next
-	 * For a file receive, oscar_sendfile_prompt */
-
-	return 0;
-}
-
-/*
- * This is the gaim callback passed to gaim_proxy_connect when
- * connecting to another AIM user in order to transfer a file
- * Takes xfer as data and fd as source
- * BBB
- */
-static void oscar_sendfile_connected(gpointer data, gint source, GaimInputCondition condition) {
-	GaimXfer *xfer;
-	PeerConnection *peer_connection;
-
-	gaim_debug_info("oscar", "AAA - in oscar_sendfile_connected\n");
-	if (!(xfer = data))
-		return;
-	if (!(peer_connection = xfer->data))
-		return;
-	if(peer_connection->success) {
-		gaim_debug_info("oscar","connection already successful; ignoring 2nd conn\n");
-		return;
-	}
-
-	if (source < 0) {
-		gaim_debug_info("oscar","received fd of %d; aborting transfer\n", source);
-		gaim_xfer_cancel_remote(xfer);
-		return;
-	}
-	peer_connection->success = TRUE; /* Mark this connection as successful before it times out */
-
-	/* XXX:NBIO remove when nonblocking I/O implemented for oscar */
-	fcntl(source, F_SETFL, 0);
-
-	/* We might have already set these in oscar_sendfile_proxylogin, but it won't
-	 * hurt to do it again since it is rather necessary */
-	xfer->fd = source;
-	peer_connection->conn->fd = source;
-
-	aim_conn_completeconnect(peer_connection->sess, peer_connection->conn);
-
-	xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, peer_connection->conn);
-
-	/* Inform the other user that we are connected and accept the transfer
-	 * Except for a stage 2 receive, then we'll be the ones receiving this accept message */
-	if(peer_connection->stage != AIM_XFER_PROXY_STG2)
-		aim_im_sendch2_sendfile_accept(peer_connection->sess, peer_connection);
-
-	/* Don't wait around if this is a redirected send */
-	if(peer_connection->send_or_recv == AIM_XFER_SEND) {
-		/* We should only get here if this is a redirected file send */
-		aim_conn_addhandler(peer_connection->sess, peer_connection->conn, AIM_CB_FAM_OFT, PEER_TYPE_ACK,
-			oscar_sendfile_ack, 0);
-		aim_conn_addhandler(peer_connection->sess, peer_connection->conn, AIM_CB_FAM_OFT, PEER_TYPE_DONE,
-			oscar_sendfile_done, 0);
-
-		/* Inform the other user that we are ready to transfer */
-		aim_oft_sendheader(peer_connection->sess, PEER_TYPE_PROMPT, peer_connection);
-	}
-}
-
-/*
- * This is called when a buddy sends us some file info.  This happens when they
- * are sending a file to you, and you have just established a connection to them.
- * You should send them the exact same info except use the real cookie.  We also
- * get like totally ready to like, receive the file, kay?
- */
-static int oscar_sendfile_prompt(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
-	GaimXfer *xfer;
-	PeerConnection *peer_connection;
-	va_list ap;
-	OscarConnection *conn;
-	guint8 *cookie;
-	PeerFrame *fh;
-
-	gaim_debug_info("oscar", "AAA - in oscar_sendfile_prompt\n");
-
-	va_start(ap, fr);
-	conn = va_arg(ap, OscarConnection *);
-	cookie = va_arg(ap, guint8 *);
-	fh = va_arg(ap, PeerFrame *);
-	va_end(ap);
-
-	if (!(xfer = oscar_find_xfer_by_conn(od->file_transfers, conn)))
-		return 1;
-
-	if (!(peer_connection = xfer->data))
-		return 1;
-
-	/* We want to stop listening with a normal thingy */
-	gaim_input_remove(xfer->watcher);
-	xfer->watcher = 0;
-
-	/* They sent us some information about the file they're sending */
-	memcpy(&peer_connection->fh, fh, sizeof(*fh));
-
-	/* Fill in the cookie */
-	memcpy(&peer_connection->fh.bcookie, peer_connection->cookie, 8);
-
-	/* XXX - convert the name from UTF-8 to UCS-2 if necessary, and pass the encoding to the call below */
-	aim_oft_sendheader(peer_connection->sess, PEER_TYPE_ACK, peer_connection);
-	gaim_xfer_start(xfer, xfer->fd, NULL, 0);
-
-	return 0;
-}
-
-/*
- * We are sending a file to someone else.  They have just acknowledged our
- * prompt, so we want to start sending data like there's no tomorrow.
- */
-static int oscar_sendfile_ack(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
-	GaimXfer *xfer;
-	va_list ap;
-	OscarConnection *conn;
-	guint8 *cookie;
-	PeerFrame *fh;
-
-	gaim_debug_info("oscar", "AAA - in oscar_sendfile_ack\n");
-	va_start(ap, fr);
-	conn = va_arg(ap, OscarConnection *);
-	cookie = va_arg(ap, guint8 *);
-	fh = va_arg(ap, PeerFrame *);
-	va_end(ap);
-
-	if (!(xfer = oscar_find_xfer_by_cookie(od->file_transfers, cookie)))
-		return 1;
-
-	/* We want to stop listening with a normal thingy */
-	gaim_input_remove(xfer->watcher);
-	xfer->watcher = 0;
-
-	gaim_xfer_start(xfer, xfer->fd, NULL, 0);
-
-	return 0;
-}
-
-/*
- * We just sent a file to someone.  They said they got it and everything,
- * so we can close our direct connection and what not.
- */
-static int oscar_sendfile_done(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
-	GaimXfer *xfer;
-	va_list ap;
-	OscarConnection *conn;
-	guint8 *cookie;
-	PeerFrame *fh;
-	PeerConnection *peer_connection;
-
-	gaim_debug_info("oscar", "AAA - in oscar_sendfile_done\n");
-	va_start(ap, fr);
-	conn = va_arg(ap, OscarConnection *);
-	cookie = va_arg(ap, guint8 *);
-	fh = va_arg(ap, PeerFrame *);
-	va_end(ap);
-
-	if (!(xfer = oscar_find_xfer_by_conn(od->file_transfers, conn))) {
-		gaim_debug_warning("oscar","xfer not found\n");
-		return 1;
-	}
-	if(!(peer_connection = xfer->data)) {
-		gaim_debug_warning("oscar","NULL peer_connection\n");
-		return 1;
-	}
-	if(fh->nrecvd == fh->size)
-		gaim_xfer_set_completed(xfer, TRUE);
-
-	xfer->fd = conn->fd;
-	gaim_xfer_end(xfer);
-
-	return 0;
-}
-
-static int incomingim_chan1(OscarSession *sess, OscarConnection *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
+static int incomingim_chan1(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args) {
+	GaimConnection *gc = od->gc;
 	GaimAccount *account = gaim_connection_get_account(gc);
 	GaimMessageFlags flags = 0;
 	struct buddyinfo *bi;
@@ -4121,7 +1904,7 @@
 						   "Sending buddy icon to %s (%d bytes, "
 						   "%lu reported)\n",
 						   userinfo->sn, len, st.st_size);
-				aim_im_sendch2_icon(sess, userinfo->sn, buf, st.st_size,
+				aim_im_sendch2_icon(od, userinfo->sn, buf, st.st_size,
 					st.st_mtime, aimutil_iconsum(buf, st.st_size));
 				fclose(file);
 			} else
@@ -4199,17 +1982,18 @@
 	return 1;
 }
 
-static int incomingim_chan2(OscarSession *sess, OscarConnection *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) {
+static int
+incomingim_chan2(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo, IcbmArgsCh2 *args)
+{
 	GaimConnection *gc;
 	GaimAccount *account;
-	OscarData *od;
 	const char *username = NULL;
 	char *message = NULL;
 
-	g_return_val_if_fail(sess != NULL, 0);
-	g_return_val_if_fail(sess->aux_data != NULL, 0);
-
-	gc = sess->aux_data;
+	g_return_val_if_fail(od != NULL, 0);
+	g_return_val_if_fail(od->gc != NULL, 0);
+
+	gc = od->gc;
 	account = gaim_connection_get_account(gc);
 	od = gc->proto_data;
 	username = gaim_account_get_username(account);
@@ -4217,8 +2001,8 @@
 	if (args == NULL)
 		return 0;
 
-	gaim_debug_misc("oscar", "rendezvous with %s, status is %hu\n",
-					userinfo->sn, args->status);
+	gaim_debug_misc("oscar", "Incoming rendezvous message of type %u, "
+			"user %s, status %hu\n", args->type, userinfo->sn, args->status);
 
 	if (args->msg != NULL)
 	{
@@ -4234,7 +2018,8 @@
 		}
 	}
 
-	if (args->reqclass & AIM_CAPS_CHAT) {
+	if (args->type & OSCAR_CAPABILITY_CHAT)
+	{
 		char *name;
 		GHashTable *components;
 
@@ -4245,8 +2030,10 @@
 		components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
 				g_free);
 		name = extract_name(args->info.chat.roominfo.name);
-		g_hash_table_replace(components, g_strdup("room"), g_strdup(name ? name : args->info.chat.roominfo.name));
-		g_hash_table_replace(components, g_strdup("exchange"), g_strdup_printf("%d", args->info.chat.roominfo.exchange));
+		g_hash_table_replace(components, g_strdup("room"),
+				g_strdup(name ? name : args->info.chat.roominfo.name));
+		g_hash_table_replace(components, g_strdup("exchange"),
+				g_strdup_printf("%d", args->info.chat.roominfo.exchange));
 		serv_got_chat_invite(gc,
 				     name ? name : args->info.chat.roominfo.name,
 				     userinfo->sn,
@@ -4254,322 +2041,83 @@
 				     components);
 		if (name)
 			g_free(name);
-	} else if (args->reqclass & AIM_CAPS_SENDFILE) {
-/* BBB */
-		/* This is the first sendfile request where we need to notify the user that someone
-		 * wants to send a file */
-		if (args->status == AIM_RENDEZVOUS_PROPOSE
-			&& (args->info.sendfile.reqnum == 0x0001)) {
-			/* Someone wants to send a file (or files) to us */
-			GaimXfer *xfer;
-			PeerConnection *peer_connection;
-			PeerProxyInfo *proxy_info = NULL;
-			gboolean use_rv_proxy;
-			int proxy_stage;
-			int xfer_method;
-			const char *proxy_ip = NULL;
-
-			if (!args->cookie || !args->port ||
-			    !args->info.sendfile.filename || !args->info.sendfile.totsize ||
-			    !args->info.sendfile.totfiles || !args->reqclass) {
-				gaim_debug_warning("oscar",
-						   "%s tried to send you a file with incomplete "
-						   "information.\n", userinfo->sn);
-				g_free(message);
-				return 1;
-			}
-
-			if (args->info.sendfile.subtype == AIM_OFT_SUBTYPE_SEND_DIR) {
-				/* last char of the ft req is a star, they are sending us a
-				 * directory -- remove the star and trailing slash so we don't save
-				 * directories that look like 'dirname\*'  -- arl */
-				char *tmp = strrchr(args->info.sendfile.filename, '\\');
-				if (tmp && (tmp[1] == '*')) {
-					tmp[0] = '\0';
-				}
-				gaim_debug_warning("oscar",
-						   "We're receiving a whole directory! What fun! "
-						   "Especially since we don't support that!\n");
-			}
-
-			/* Build the file transfer handle */
-			xfer = gaim_xfer_new(gc->account, GAIM_XFER_RECEIVE, userinfo->sn);
-
-			use_rv_proxy = gaim_account_get_bool(account, "use_rv_proxy", OSCAR_DEFAULT_USE_RV_PROXY);
-
-			if(args->info.sendfile.use_proxy) {
-				/* The sender requested (stage 1) that we use a rendezvous proxy */
-				xfer_method = AIM_XFER_PROXY;
-				proxy_stage = AIM_XFER_PROXY_STG1;
-				gaim_debug_info("oscar","using stage 1 proxy with ip: %s\n",
-					args->proxyip, args->port);
-				xfer->remote_ip = g_strdup(args->proxyip);
-				xfer->remote_port = AIM_RV_PROXY_CONNECT_PORT;
-				proxy_info = aim_rv_proxy_createinfo(od->sess, args->cookie, args->port);
-			} else if(use_rv_proxy) {
-				/* If the local user indicated that a rendezvous proxy is necessary
-				 * start a stage 2 proxied transfer */
-				gaim_debug_info("oscar","using stage 2 proxied transfer\n");
-				xfer_method = AIM_XFER_PROXY;
-				proxy_stage = AIM_XFER_PROXY_STG2;
-				/* This hostname will be resolved by gaim_proxy_connect */
-				xfer->remote_ip = g_strdup(AIM_RV_PROXY_SERVER_URL);
-				xfer->remote_port = AIM_RV_PROXY_CONNECT_PORT;
-				proxy_info = aim_rv_proxy_createinfo(od->sess, args->cookie, 0);
-			} else {
-				/* We are receiving a file directly with no rendezvous proxy */
-				xfer_method = AIM_XFER_DIRECT;
-				proxy_stage = AIM_XFER_PROXY_NONE;
-				xfer->remote_ip = g_strdup(args->clientip);
-				xfer->remote_port = args->port;
-			}
-
-			/* Use UTF8 so that the world will be a happier place */
-			if (g_utf8_validate(args->info.sendfile.filename, -1,
-						NULL)) {
-				gaim_xfer_set_filename(xfer,
-						args->info.sendfile.filename);
-			} else {
-				gchar * utf8_filename = gaim_utf8_salvage(
-						args->info.sendfile.filename);
-				gaim_xfer_set_filename(xfer, utf8_filename);
-				g_free(utf8_filename);
-			}
-
-			gaim_xfer_set_size(xfer, args->info.sendfile.totsize);
-
-			/* Ignore messages that start with <ICQ_COOL_FT> (XML that is sent along
-			 * with ICQ sendfile requests) & <HTML> message that is sent with AOL file
-			 * transfers (Note: this latter message is ignored only if whole message
-			 * is <HTML>, but not if it starts with <HTML> */
-			if(message && ( g_ascii_strncasecmp(message,"<ICQ_COOL_FT>",13) < 0
-				|| g_ascii_strcasecmp(message,"<HTML>") == 0) ) {
-				gaim_debug_info("oscar","Ignoring file transfer message: %s\n", message);
-				g_free(message);
-				message = NULL;
-			}
-			gaim_xfer_set_message(xfer, message);
-
-			/* Create the oscar-specific data */
-			peer_connection = aim_oft_createinfo(od->sess, args->cookie, userinfo->sn, args->clientip,
-				xfer->remote_port, 0, 0, NULL, AIM_XFER_RECV, xfer_method, proxy_stage);
-			if(proxy_stage == AIM_XFER_PROXY_STG2 && proxy_ip) {
-				peer_connection->proxyip = g_strdup(proxy_ip);
-			} else {
-				if (args->proxyip)
-					peer_connection->proxyip = g_strdup(args->proxyip);
-				if (args->verifiedip)
-					peer_connection->verifiedip = g_strdup(args->verifiedip);
+	}
+
+	else if ((args->type & OSCAR_CAPABILITY_SENDFILE) ||
+			 (args->type & OSCAR_CAPABILITY_DIRECTIM))
+	{
+		if (args->status == AIM_RENDEZVOUS_PROPOSE)
+		{
+			peer_connection_got_proposition(od, userinfo->sn, message, args);
+		}
+		else if (args->status == AIM_RENDEZVOUS_CANCEL)
+		{
+			/* The other user canceled a peer request */
+			PeerConnection *conn;
+
+			conn = peer_connection_find_by_cookie(od, userinfo->sn, args->cookie);
+			/*
+			 * If conn is NULL it means we haven't tried to create
+			 * a connection with that user.  They may be trying to
+			 * do something malicious.
+			 */
+			if (conn != NULL)
+			{
+				peer_connection_destroy(conn, PEER_DISCONNECT_REMOTE_CLOSED);
 			}
-			peer_connection->proxy_info = proxy_info;
-			xfer->data = peer_connection;
-
-			 /* Setup our I/O op functions */
-			gaim_xfer_set_init_fnc(xfer, oscar_xfer_init_recv);
-			gaim_xfer_set_end_fnc(xfer, oscar_xfer_end);
-			gaim_xfer_set_request_denied_fnc(xfer, oscar_xfer_cancel_recv);
-			gaim_xfer_set_cancel_recv_fnc(xfer, oscar_xfer_cancel_recv);
-			gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack_recv);
-
-			/* Keep track of this transfer for later */
-			od->file_transfers = g_slist_append(od->file_transfers, xfer);
-
-			/* Now perform the request */
-			gaim_xfer_request(xfer);
-		/* A secondary request has been sent to negotiate the connection method */
-		} else if (args->status == AIM_RENDEZVOUS_PROPOSE && args->info.sendfile.reqnum == 0x0002) {
-			/* We have asked to send a file to someone else, but they sent us a reply request
-			 * asking us to use an alternative method of connecting */
-			GaimXfer *xfer;
-			PeerConnection *peer_connection;
-
-			if ((xfer = oscar_find_xfer_by_cookie(od->file_transfers, args->cookie))) {
-				peer_connection = xfer->data;
-
-				/* Stop the listener connection */
-				gaim_input_remove(xfer->watcher);
-				oscar_connection_destroy(sess, peer_connection->conn); /* This is currently the listener */
-
-				if(args->info.sendfile.use_proxy) {
-					gaim_debug_info("oscar",
-						"received request for stage 2 rv proxy with ip: %s\n",
-						args->proxyip);
-					peer_connection->method = AIM_XFER_PROXY;
-					peer_connection->stage = AIM_XFER_PROXY_STG2;
-
-					peer_connection->proxy_info = aim_rv_proxy_createinfo(peer_connection->sess,
-						args->cookie, args->port);
-					if(args->proxyip) {
-						if(xfer->remote_ip)
-							g_free(xfer->remote_ip);
-						xfer->remote_ip = g_strdup(args->proxyip);
-						xfer->remote_port = AIM_RV_PROXY_CONNECT_PORT;
-						oscar_xfer_init_recv(xfer);
-					} else {
-						gaim_debug_warning("oscar",
-							"stage 2 rv proxy file send: no proxy ip specified\n");
-					}
-				} else if(args->clientip
-						&& g_ascii_strcasecmp(args->clientip,"0.0.0.0") == 0)
+		}
+		else if (args->status == AIM_RENDEZVOUS_CONNECTED)
+		{
+			/* Remote user has accepted our peer request */
+			PeerConnection *conn;
+
+			conn = peer_connection_find_by_cookie(od, userinfo->sn, args->cookie);
+			/*
+			 * If conn is NULL it means we haven't tried to create
+			 * a connection with that user.  They may be trying to
+			 * do something malicious.
+			 */
+			if (conn != NULL)
+			{
+				if (conn->listenerfd != -1)
 				{
-					gaim_debug_warning("oscar",
-						"other client wants us to send stage 3 proxy info\n");
-					peer_connection->method = AIM_XFER_PROXY;
-					peer_connection->stage = AIM_XFER_PROXY_STG3;
-
-					/* Clean useless data from peer_connection */
-					peer_connection->clientip = NULL;
-					peer_connection->verifiedip = NULL;
-
-					/* This hostname will be resolved in gaim_proxy_connect */
-					xfer->remote_ip = g_strdup(AIM_RV_PROXY_SERVER_URL);
-					xfer->remote_port = AIM_RV_PROXY_CONNECT_PORT;
-
-					peer_connection->proxy_info
-						= aim_rv_proxy_createinfo(od->sess, args->cookie, 0);
-					oscar_xfer_init_recv(xfer);
-				} else {
-					gaim_debug_info("oscar","received request to redirect transfer; clientip/verifiedip: %s / %s\n",
-						args->clientip, args->verifiedip);
-					peer_connection->method = AIM_XFER_REDIR;
-					if (args->verifiedip)
-						peer_connection->verifiedip = g_strdup(args->verifiedip);
-					if (args->clientip) {
-						peer_connection->clientip = g_strdup(args->clientip);
-						xfer->remote_ip = g_strdup(args->clientip);
-					}
-					xfer->remote_port = args->port;
-
-					/* This file send will briefly follow file receive codepaths */
-					oscar_xfer_init_recv(xfer);
+					/*
+					 * If they are connecting directly to us then
+					 * continue the peer negotiation by
+					 * accepting connections on our listener port.
+					 */
+					conn->watcher_incoming = gaim_input_add(conn->listenerfd,
+							GAIM_INPUT_READ, peer_connection_listen_cb, conn);
 				}
-			} else {
-				gaim_debug_warning("oscar","received file tranfer reply request: xfer not found\n");
 			}
-		/* A THIRD request has been sent trying to figure out what connection method will be used
-		 * to transfer this file */
-		} else if (args->status == AIM_RENDEZVOUS_PROPOSE && args->info.sendfile.reqnum == 0x0003) {
-			/* We are receiving a file from someone. We sent a request to use a stage 3
-			 * proxy. They did the initial proxy login and have sent us the info in a
-			 * third file transfer request. */
-			GaimXfer *xfer;
-			PeerConnection *peer_connection;
-
-			if ((xfer = oscar_find_xfer_by_cookie(od->file_transfers, args->cookie))) {
-				peer_connection = xfer->data;
-
-				/* We are receiving a file */
-				gaim_debug_info("oscar",
-					"other client sent us stage 3 proxy info\n");
-
-				/* The following pieces of information should already have
-				 * been set in oscar_xfer_ip_timeout, but we'll list them
-				 * again just for clarity. */
-				peer_connection->method = AIM_XFER_PROXY;
-				peer_connection->stage = AIM_XFER_PROXY_STG3;
-
-				peer_connection->proxy_info = aim_rv_proxy_createinfo(peer_connection->sess,
-					args->cookie, args->port);
-				if(args->proxyip) {
-					if(xfer->remote_ip)
-						g_free(xfer->remote_ip);
-					xfer->remote_ip = g_strdup(args->proxyip);
-					xfer->remote_port = AIM_RV_PROXY_CONNECT_PORT;
-					oscar_xfer_init_recv(xfer);
-				} else {
-					gaim_debug_warning("oscar",
-						"stage 3 rv proxy file receive: no proxy ip specified\n");
-				}
-			} else {
-				gaim_debug_warning("oscar","received file tranfer reply request: xfer not found\n");
-			}
-		} else if (args->status == AIM_RENDEZVOUS_CANCEL) {
-			/* The other user wants to cancel a file transfer */
-			GaimXfer *xfer;
-			gaim_debug_info("oscar",
-					   "AAA - File transfer canceled by remote user\n");
-			if ((xfer = oscar_find_xfer_by_cookie(od->file_transfers, args->cookie)))
-				gaim_xfer_cancel_remote(xfer);
-		} else if (args->status == AIM_RENDEZVOUS_ACCEPT) {
-			/*
-			 * This gets sent by the receiver of a file
-			 * as they connect directly to us.  If we don't
-			 * get this, then maybe a third party connected
-			 * to us, and we shouldn't send them anything.
-			 */
-			 gaim_debug_info("oscar",
-				"AAA - received chan 2 AIM_RENDEZVOUS_ACCEPT; ignoring\n");
-		} else {
-			gaim_debug_error("oscar",
-					   "unknown rendezvous status!\n");
 		}
-	} else if (args->reqclass & AIM_CAPS_GETFILE) {
-	} else if (args->reqclass & AIM_CAPS_TALK) {
-	} else if (args->reqclass & AIM_CAPS_BUDDYICON) {
+	}
+
+	else if (args->type & OSCAR_CAPABILITY_GETFILE)
+	{
+	}
+
+	else if (args->type & OSCAR_CAPABILITY_TALK)
+	{
+	}
+
+	else if (args->type & OSCAR_CAPABILITY_BUDDYICON)
+	{
 		gaim_buddy_icons_set_for_user(account, userinfo->sn,
 									  args->info.icon.icon,
 									  args->info.icon.length);
-	} else if (args->reqclass & AIM_CAPS_DIRECTIM) {
-		/* Consider moving all this into a helper func in the direct im block way up there */
-		struct ask_direct *d = g_new0(struct ask_direct, 1);
-		struct oscar_direct_im *dim = oscar_direct_im_find(od, userinfo->sn);
-		char buf[256];
-
-		if (!args->verifiedip) {
-			/* TODO: do something about this, after figuring out what it means */
-			gaim_debug_info("oscar",
-					   "directim kill blocked (%s)\n", userinfo->sn);
-			g_free(message);
-			return 1;
-		}
-
-		gaim_debug_info("oscar",
-				   "%s received direct im request from %s (%s)\n",
-				   username, userinfo->sn, args->verifiedip);
-
-		d->gc = gc;
-		d->sn = g_strdup(userinfo->sn);
-		/* Let's use the clientip here, because I think that's what AIM does.
-		 * Besides, if the clientip is wrong, we'll probably timeout faster,
-		 * and then ask them to connect to us. */
-		/*
-		 * I disagree, let's use the verifiedip.  I think AIM tries the
-		 * verified IP first, then tries the client IP if that fails.  In
-		 * any case, there's a better chance the verified IP will be correct.
-		 * The client IP is what the other person _thinks_ their IP address
-		 * is.  The verified IP is the address that the AIM server sees the
-		 * other person using.
-		 */
-		snprintf(d->ip, sizeof(d->ip), "%s:%d", args->verifiedip, args->port?args->port:5190);
-		memcpy(d->cookie, args->cookie, 8);
-		if (dim && !dim->connected && aim_odc_getcookie(dim->conn) && args->cookie &&
-			(!memcmp(aim_odc_getcookie(dim->conn), args->cookie, 8))) {
-
-			oscar_direct_im_destroy(od, dim);
-			d->donttryagain = TRUE;
-			accept_direct_im_request(d);
-		} else {
-			if (dim && !dim->connected)
-				gaim_debug_warning("oscar", "DirectIM: received direct im request "
-						"while already connected to that buddy!");
-		g_snprintf(buf, sizeof buf, _("%s has just asked to directly connect to %s"), userinfo->sn, username);
-
-		gaim_request_action(gc, NULL, buf,
-							_("This requires a direct connection between "
-							  "the two computers and is necessary for IM "
-							  "Images.  Because your IP address will be "
-							  "revealed, this may be considered a privacy "
-							  "risk."),
-							GAIM_DEFAULT_ACTION_NONE, d, 2,
-							_("_Connect"), G_CALLBACK(accept_direct_im_request),
-							_("Cancel"), G_CALLBACK(destroy_direct_im_request));
-							/* FIXME: we should actually send a packet on cancel */
-		}
-	} else if (args->reqclass & AIM_CAPS_ICQSERVERRELAY) {
-		gaim_debug_error("oscar", "Got an ICQ Server Relay message of type %d\n", args->info.rtfmsg.msgtype);
-	} else {
-		gaim_debug_error("oscar",
-				   "Unknown reqclass %hu\n", args->reqclass);
+	}
+
+	else if (args->type & OSCAR_CAPABILITY_ICQSERVERRELAY)
+	{
+		gaim_debug_error("oscar", "Got an ICQ Server Relay message of "
+				"type %d\n", args->info.rtfmsg.msgtype);
+	}
+
+	else
+	{
+		gaim_debug_error("oscar", "Unknown request class %hu\n",
+				args->type);
 	}
 
 	g_free(message);
@@ -4583,7 +2131,9 @@
  * methods of authorization (SSI and old-school channel 4 ICBM)
  */
 /* When you ask other people for authorization */
-static void gaim_auth_request(struct name_data *data, char *msg) {
+static void
+gaim_auth_request(struct name_data *data, char *msg)
+{
 	GaimConnection *gc = data->gc;
 
 	if (g_list_find(gaim_connections_get_all(), gc)) {
@@ -4594,14 +2144,16 @@
 			gaim_debug_info("oscar",
 					   "ssi: adding buddy %s to group %s\n",
 					   buddy->name, group->name);
-			aim_ssi_sendauthrequest(od->sess, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list."));
-			if (!aim_ssi_itemlist_finditem(od->sess->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY))
-				aim_ssi_addbuddy(od->sess, buddy->name, group->name, gaim_buddy_get_alias_only(buddy), NULL, NULL, 1);
+			aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list."));
+			if (!aim_ssi_itemlist_finditem(od->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY))
+				aim_ssi_addbuddy(od, buddy->name, group->name, gaim_buddy_get_alias_only(buddy), NULL, NULL, 1);
 		}
 	}
 }
 
-static void gaim_auth_request_msgprompt(struct name_data *data) {
+static void
+gaim_auth_request_msgprompt(struct name_data *data)
+{
 	gaim_request_input(data->gc, NULL, _("Authorization Request Message:"),
 					   NULL, _("Please authorize me!"), TRUE, FALSE, NULL,
 					   _("OK"), G_CALLBACK(gaim_auth_request),
@@ -4609,7 +2161,9 @@
 					   data);
 }
 
-static void gaim_auth_dontrequest(struct name_data *data) {
+static void
+gaim_auth_dontrequest(struct name_data *data)
+{
 	GaimConnection *gc = data->gc;
 
 	if (g_list_find(gaim_connections_get_all(), gc)) {
@@ -4622,7 +2176,9 @@
 }
 
 
-static void gaim_auth_sendrequest(GaimConnection *gc, char *name) {
+static void
+gaim_auth_sendrequest(GaimConnection *gc, char *name)
+{
 	struct name_data *data = g_new0(struct name_data, 1);
 	GaimBuddy *buddy;
 	gchar *dialog_msg, *nombre;
@@ -4649,7 +2205,9 @@
 }
 
 
-static void gaim_auth_sendrequest_menu(GaimBlistNode *node, gpointer ignored) {
+static void
+gaim_auth_sendrequest_menu(GaimBlistNode *node, gpointer ignored)
+{
 	GaimBuddy *buddy;
 	GaimConnection *gc;
 
@@ -4661,28 +2219,34 @@
 }
 
 /* When other people ask you for authorization */
-static void gaim_auth_grant(struct name_data *data) {
+static void
+gaim_auth_grant(struct name_data *data)
+{
 	GaimConnection *gc = data->gc;
 
 	if (g_list_find(gaim_connections_get_all(), gc)) {
 		OscarData *od = gc->proto_data;
-		aim_ssi_sendauthreply(od->sess, data->name, 0x01, NULL);
+		aim_ssi_sendauthreply(od, data->name, 0x01, NULL);
 	}
 
 	oscar_free_name_data(data);
 }
 
 /* When other people ask you for authorization */
-static void gaim_auth_dontgrant(struct name_data *data, char *msg) {
+static void
+gaim_auth_dontgrant(struct name_data *data, char *msg)
+{
 	GaimConnection *gc = data->gc;
 
 	if (g_list_find(gaim_connections_get_all(), gc)) {
 		OscarData *od = gc->proto_data;
-		aim_ssi_sendauthreply(od->sess, data->name, 0x00, msg ? msg : _("No reason given."));
-	}
-}
-
-static void gaim_auth_dontgrant_msgprompt(struct name_data *data) {
+		aim_ssi_sendauthreply(od, data->name, 0x00, msg ? msg : _("No reason given."));
+	}
+}
+
+static void
+gaim_auth_dontgrant_msgprompt(struct name_data *data)
+{
 	gaim_request_input(data->gc, NULL, _("Authorization Denied Message:"),
 					   NULL, _("No reason given."), TRUE, FALSE, NULL,
 					   _("OK"), G_CALLBACK(gaim_auth_dontgrant),
@@ -4691,7 +2255,9 @@
 }
 
 /* When someone sends you buddies */
-static void gaim_icq_buddyadd(struct name_data *data) {
+static void
+gaim_icq_buddyadd(struct name_data *data)
+{
 	GaimConnection *gc = data->gc;
 
 	if (g_list_find(gaim_connections_get_all(), gc)) {
@@ -4701,8 +2267,10 @@
 	oscar_free_name_data(data);
 }
 
-static int incomingim_chan4(OscarSession *sess, OscarConnection *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch4_args *args, time_t t) {
-	GaimConnection *gc = sess->aux_data;
+static int
+incomingim_chan4(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch4_args *args, time_t t)
+{
+	GaimConnection *gc = od->gc;
 	GaimAccount *account = gaim_connection_get_account(gc);
 	gchar **msg1, **msg2;
 	int i, numtoks;
@@ -4711,7 +2279,7 @@
 		return 1;
 
 	gaim_debug_info("oscar",
-					"Received a channel 4 message of type 0x%02hhx.\n",
+					"Received a channel 4 message of type 0x%02hx.\n",
 					args->type);
 
 	/*
@@ -4899,7 +2467,7 @@
 	return 1;
 }
 
-static int gaim_parse_incoming_im(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_parse_incoming_im(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	guint16 channel;
 	int ret = 0;
 	aim_userinfo_t *userinfo;
@@ -4913,19 +2481,19 @@
 		case 1: { /* standard message */
 			struct aim_incomingim_ch1_args *args;
 			args = va_arg(ap, struct aim_incomingim_ch1_args *);
-			ret = incomingim_chan1(sess, fr->conn, userinfo, args);
+			ret = incomingim_chan1(od, conn, userinfo, args);
 		} break;
 
 		case 2: { /* rendezvous */
-			struct aim_incomingim_ch2_args *args;
-			args = va_arg(ap, struct aim_incomingim_ch2_args *);
-			ret = incomingim_chan2(sess, fr->conn, userinfo, args);
+			IcbmArgsCh2 *args;
+			args = va_arg(ap, IcbmArgsCh2 *);
+			ret = incomingim_chan2(od, conn, userinfo, args);
 		} break;
 
 		case 4: { /* ICQ */
 			struct aim_incomingim_ch4_args *args;
 			args = va_arg(ap, struct aim_incomingim_ch4_args *);
-			ret = incomingim_chan4(sess, fr->conn, userinfo, args, 0);
+			ret = incomingim_chan4(od, conn, userinfo, args, 0);
 		} break;
 
 		default: {
@@ -4940,8 +2508,8 @@
 	return ret;
 }
 
-static int gaim_parse_misses(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_parse_misses(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	GaimAccount *account = gaim_connection_get_account(gc);
 	char *buf;
 	va_list ap;
@@ -5013,46 +2581,43 @@
 	}
 
 	if (!gaim_conv_present_error(userinfo->sn, account, buf))
-		gaim_notify_error(sess->aux_data, NULL, buf, NULL);
+		gaim_notify_error(od->gc, NULL, buf, NULL);
 	g_free(buf);
 
 	return 1;
 }
 
-static int gaim_parse_clientauto_ch2(OscarSession *sess, const char *who, guint16 reason, const guchar *cookie) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-/* BBB */
-	switch (reason) {
-		case 3: { /* Decline sendfile. */
-			GaimXfer *xfer;
-			struct oscar_direct_im *dim;
-
-			gaim_debug_info("oscar",
-					   "AAA - Other user declined some sort of direct "
-					   "connect attempt (automaticly?)\n");
-			if ((xfer = oscar_find_xfer_by_cookie(od->file_transfers, cookie)))
-				gaim_xfer_cancel_remote(xfer);
-			else if ((dim = oscar_direct_im_find(od, who))) {
-				/* AAA should use find by cookie or something here */
-				oscar_direct_im_disconnect(od, dim);
-			}
-		} break;
-
-		default: {
-			gaim_debug_warning("oscar",
-					   "Received an unknown rendezvous client auto-response "
-					   "from %s.  Type 0x%04hx\n", who, reason);
+static int
+gaim_parse_clientauto_ch2(OscarData *od, const char *who, guint16 reason, const guchar *cookie)
+{
+	if (reason == 0x0003)
+	{
+		/* Rendezvous was refused. */
+		PeerConnection *conn;
+
+		conn = peer_connection_find_by_cookie(od, who, cookie);
+
+		if (conn == NULL)
+		{
+			gaim_debug_info("oscar", "Received a rendezvous cancel message "
+					"for a nonexistant connection from %s.\n", who);
 		}
-
+		else
+		{
+			peer_connection_destroy(conn, PEER_DISCONNECT_REMOTE_REFUSED);
+		}
+	}
+	else
+	{
+		gaim_debug_warning("oscar", "Received an unknown rendezvous "
+				"message from %s.  Type 0x%04hx\n", who, reason);
 	}
 
 	return 0;
 }
 
-static int gaim_parse_clientauto_ch4(OscarSession *sess, char *who, guint16 reason, guint32 state, char *msg) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_parse_clientauto_ch4(OscarData *od, char *who, guint16 reason, guint32 state, char *msg) {
+	GaimConnection *gc = od->gc;
 
 	switch(reason) {
 		case 0x0003: { /* Reply from an ICQ status message request */
@@ -5083,7 +2648,7 @@
 	return 0;
 }
 
-static int gaim_parse_clientauto(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_parse_clientauto(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	guint16 chan, reason;
 	char *who;
@@ -5095,7 +2660,7 @@
 
 	if (chan == 0x0002) { /* File transfer declined */
 		guchar *cookie = va_arg(ap, guchar *);
-		return gaim_parse_clientauto_ch2(sess, who, reason, cookie);
+		return gaim_parse_clientauto_ch2(od, who, reason, cookie);
 	} else if (chan == 0x0004) { /* ICQ message */
 		guint32 state = 0;
 		char *msg = NULL;
@@ -5103,7 +2668,7 @@
 			state = va_arg(ap, guint32);
 			msg = va_arg(ap, char *);
 		}
-		return gaim_parse_clientauto_ch4(sess, who, reason, state, msg);
+		return gaim_parse_clientauto_ch4(od, who, reason, state, msg);
 	}
 
 	va_end(ap);
@@ -5111,7 +2676,7 @@
 	return 1;
 }
 
-static int gaim_parse_genericerr(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_parse_genericerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	guint16 reason;
 	char *m;
@@ -5126,15 +2691,15 @@
 
 	m = g_strdup_printf(_("SNAC threw error: %s\n"),
 			reason < msgerrreasonlen ? _(msgerrreason[reason]) : _("Unknown error"));
-	gaim_notify_error(sess->aux_data, NULL, m, NULL);
+	gaim_notify_error(od->gc, NULL, m, NULL);
 	g_free(m);
 
 	return 1;
 }
 
-static int gaim_parse_msgerr(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-#if 0
+static int gaim_parse_msgerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
+#ifdef TODOFT
 	OscarData *od = gc->proto_data;
 	GaimXfer *xfer;
 #endif
@@ -5151,8 +2716,7 @@
 			   "Message error with data %s and reason %hu\n",
 				(data != NULL ? data : ""), reason);
 
-/* BBB */
-#if 0
+#ifdef TODOFT
 	/* If this was a file transfer request, data is a cookie */
 	if ((xfer = oscar_find_xfer_by_cookie(od->file_transfers, data))) {
 		gaim_xfer_cancel_remote(xfer);
@@ -5165,7 +2729,7 @@
 	if (!gaim_conv_present_error(data, gaim_connection_get_account(gc), buf)) {
 		g_free(buf);
 		buf = g_strdup_printf(_("Unable to send message to %s:"), data ? data : "(unknown)");
-		gaim_notify_error(sess->aux_data, NULL, buf,
+		gaim_notify_error(od->gc, NULL, buf,
 				  (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason."));
 	}
 	g_free(buf);
@@ -5173,8 +2737,8 @@
 	return 1;
 }
 
-static int gaim_parse_mtn(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_parse_mtn(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	va_list ap;
 	guint16 type1, type2;
 	char *sn;
@@ -5210,7 +2774,7 @@
  * We get this error when there was an error in the locate family.  This
  * happens when you request info of someone who is offline.
  */
-static int gaim_parse_locerr(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_parse_locerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	gchar *buf;
 	va_list ap;
 	guint16 reason;
@@ -5225,20 +2789,19 @@
 		return 1;
 
 	buf = g_strdup_printf(_("User information not available: %s"), (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason."));
-	if (!gaim_conv_present_error(destn, gaim_connection_get_account((GaimConnection*)sess->aux_data), buf)) {
+	if (!gaim_conv_present_error(destn, gaim_connection_get_account((GaimConnection*)od->gc), buf)) {
 		g_free(buf);
 		buf = g_strdup_printf(_("User information for %s unavailable:"), destn);
-		gaim_notify_error(sess->aux_data, NULL, buf, (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason."));
+		gaim_notify_error(od->gc, NULL, buf, (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason."));
 	}
 	g_free(buf);
 
 	return 1;
 }
 
-static int gaim_parse_userinfo(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_parse_userinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	GaimAccount *account = gaim_connection_get_account(gc);
-	OscarData *od = gc->proto_data;
 	GString *str;
 	gchar *tmp = NULL, *info_utf8 = NULL, *away_utf8 = NULL;
 	va_list ap;
@@ -5317,9 +2880,9 @@
 	return 1;
 }
 
-static int gaim_got_infoblock(OscarSession *sess, FlapFrame *fr, ...)
+static int gaim_got_infoblock(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	GaimConnection *gc = sess->aux_data;
+	GaimConnection *gc = od->gc;
 	GaimBuddy *b;
 	GaimPresence *presence;
 	GaimStatus *status;
@@ -5356,35 +2919,7 @@
 	return 1;
 }
 
-static gboolean gaim_reqinfo_timeout_cb(void *data)
-{
-	OscarSession *sess = data;
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = (OscarData *)gc->proto_data;
-
-	aim_locate_dorequest(data);
-	od->getinfotimer = 0;
-
-	return FALSE;
-}
-
-static int gaim_reqinfo_timeout(OscarSession *sess, FlapFrame *fr, ...)
-{
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = (OscarData *)gc->proto_data;
-
-	/*
-	 * Wait a little while then call aim_locate_dorequest(sess).  This keeps
-	 * us from hitting the rate limit due to request away messages and info
-	 * too quickly.
-	 */
-	if (od->getinfotimer == 0)
-		od->getinfotimer = gaim_timeout_add(10000, gaim_reqinfo_timeout_cb, sess);
-
-	return 1;
-}
-
-static int gaim_parse_motd(OscarSession *sess, FlapFrame *fr, ...)
+static int gaim_parse_motd(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
 	char *msg;
 	guint16 id;
@@ -5398,17 +2933,15 @@
 	gaim_debug_misc("oscar",
 			   "MOTD: %s (%hu)\n", msg ? msg : "Unknown", id);
 	if (id < 4)
-		gaim_notify_warning(sess->aux_data, NULL,
+		gaim_notify_warning(od->gc, NULL,
 							_("Your AIM connection may be lost."), NULL);
 
 	return 1;
 }
 
-static int gaim_chatnav_info(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_chatnav_info(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	guint16 type;
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = (OscarData *)gc->proto_data;
 
 	va_start(ap, fr);
 	type = (guint16) va_arg(ap, unsigned int);
@@ -5423,8 +2956,7 @@
 			exchangecount = va_arg(ap, int);
 			exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
 
-			gaim_debug_misc("oscar",
-					   "chat info: Chat Rights:\n");
+			gaim_debug_misc("oscar", "chat info: Chat Rights:\n");
 			gaim_debug_misc("oscar",
 					   "chat info: \tMax Concurrent Rooms: %hhd\n", maxrooms);
 			gaim_debug_misc("oscar",
@@ -5437,7 +2969,7 @@
 				struct create_room *cr = od->create_rooms->data;
 				gaim_debug_info("oscar",
 						   "creating room %s\n", cr->name);
-				aim_chatnav_createroom(sess, fr->conn, cr->name, cr->exchange);
+				aim_chatnav_createroom(od, conn, cr->name, cr->exchange);
 				g_free(cr->name);
 				od->create_rooms = g_slist_remove(od->create_rooms, cr);
 				g_free(cr);
@@ -5463,13 +2995,11 @@
 			ck = va_arg(ap, char *);
 
 			gaim_debug_misc("oscar",
-					   "created room: %s %hu %hu %hu %u %hu %hu %hhu %hu %s %s\n",
-					fqcn,
-					exchange, instance, flags,
-					createtime,
+					"created room: %s %hu %hu %hu %u %hu %hu %hhu %hu %s %s\n",
+					fqcn, exchange, instance, flags, createtime,
 					maxmsglen, maxoccupancy, createperms, unknown,
 					name, ck);
-			aim_chat_join(od->sess, od->conn, exchange, ck, instance);
+			aim_chat_join(od, exchange, ck, instance);
 			}
 			break;
 		default:
@@ -5483,11 +3013,11 @@
 	return 1;
 }
 
-static int gaim_conv_chat_join(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_conv_chat_join(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	int count, i;
 	aim_userinfo_t *info;
-	GaimConnection *g = sess->aux_data;
+	GaimConnection *gc = od->gc;
 
 	struct chat_connection *c = NULL;
 
@@ -5496,7 +3026,7 @@
 	info  = va_arg(ap, aim_userinfo_t *);
 	va_end(ap);
 
-	c = find_oscar_chat_by_conn(g, fr->conn);
+	c = find_oscar_chat_by_conn(gc, conn);
 	if (!c)
 		return 1;
 
@@ -5506,11 +3036,11 @@
 	return 1;
 }
 
-static int gaim_conv_chat_leave(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_conv_chat_leave(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	int count, i;
 	aim_userinfo_t *info;
-	GaimConnection *g = sess->aux_data;
+	GaimConnection *gc = od->gc;
 
 	struct chat_connection *c = NULL;
 
@@ -5519,7 +3049,7 @@
 	info  = va_arg(ap, aim_userinfo_t *);
 	va_end(ap);
 
-	c = find_oscar_chat_by_conn(g, fr->conn);
+	c = find_oscar_chat_by_conn(gc, conn);
 	if (!c)
 		return 1;
 
@@ -5529,7 +3059,7 @@
 	return 1;
 }
 
-static int gaim_conv_chat_info_update(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_conv_chat_info_update(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	aim_userinfo_t *userinfo;
 	struct aim_chat_roominfo *roominfo;
@@ -5538,8 +3068,8 @@
 	char *roomdesc;
 	guint16 unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
 	guint32 creationtime;
-	GaimConnection *gc = sess->aux_data;
-	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn);
+	GaimConnection *gc = od->gc;
+	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn);
 
 	va_start(ap, fr);
 	roominfo = va_arg(ap, struct aim_chat_roominfo *);
@@ -5565,9 +3095,9 @@
 	return 1;
 }
 
-static int gaim_conv_chat_incoming_msg(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn);
+static int gaim_conv_chat_incoming_msg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
+	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn);
 	gchar *utf8;
 	va_list ap;
 	aim_userinfo_t *info;
@@ -5592,9 +3122,9 @@
 	return 1;
 }
 
-static int gaim_email_parseupdate(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_email_parseupdate(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
-	GaimConnection *gc = sess->aux_data;
+	GaimConnection *gc = od->gc;
 	struct aim_emailinfo *emailinfo;
 	int havenewmail;
 	char *alertitle, *alerturl;
@@ -5621,16 +3151,14 @@
 	return 1;
 }
 
-static int gaim_icon_error(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
+static int gaim_icon_error(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	char *sn;
 
 	sn = od->requesticon->data;
-	gaim_debug_misc("oscar",
-			   "removing %s from hash table\n", sn);
+	gaim_debug_misc("oscar", "removing %s from hash table\n", sn);
 	od->requesticon = g_slist_remove(od->requesticon, sn);
-	free(sn);
+	g_free(sn);
 
 	if (od->icontimer)
 		gaim_timeout_remove(od->icontimer);
@@ -5639,9 +3167,8 @@
 	return 1;
 }
 
-static int gaim_icon_parseicon(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
+static int gaim_icon_parseicon(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	GSList *cur;
 	va_list ap;
 	char *sn;
@@ -5678,7 +3205,7 @@
 		char *cursn = cur->data;
 		if (!aim_sncmp(cursn, sn)) {
 			od->requesticon = g_slist_remove(od->requesticon, cursn);
-			free(cursn);
+			g_free(cursn);
 			cur = od->requesticon;
 		} else
 			cur = cur->next;
@@ -5695,12 +3222,12 @@
 	GaimConnection *gc = data;
 	OscarData *od = gc->proto_data;
 	aim_userinfo_t *userinfo;
-	OscarConnection *conn;
-
-	conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_ICON);
+	FlapConnection *conn;
+
+	conn = flap_connection_getbytype(od, SNAC_FAMILY_BART);
 	if (!conn) {
 		if (!od->iconconnecting) {
-			aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_ICON);
+			aim_reqservice(od, SNAC_FAMILY_BART);
 			od->iconconnecting = TRUE;
 		}
 		return FALSE;
@@ -5710,7 +3237,7 @@
 		struct stat st;
 		char *iconfile = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(gaim_connection_get_account(gc)));
 		if (iconfile == NULL) {
-			aim_ssi_delicon(od->sess);
+			aim_ssi_delicon(od);
 		} else if (!g_stat(iconfile, &st)) {
 			guchar *buf = g_malloc(st.st_size);
 			FILE *file = g_fopen(iconfile, "rb");
@@ -5720,7 +3247,7 @@
 				fclose(file);
 				gaim_debug_info("oscar",
 					   "Uploading icon to icon server\n");
-				aim_bart_upload(od->sess, buf, st.st_size);
+				aim_bart_upload(od, buf, st.st_size);
 			} else
 				gaim_debug_error("oscar",
 					   "Can't open buddy icon file!\n");
@@ -5739,14 +3266,14 @@
 		return FALSE;
 	}
 
-	userinfo = aim_locate_finduserinfo(od->sess, (char *)od->requesticon->data);
+	userinfo = aim_locate_finduserinfo(od, (char *)od->requesticon->data);
 	if ((userinfo != NULL) && (userinfo->iconcsumlen > 0)) {
-		aim_bart_request(od->sess, od->requesticon->data, userinfo->iconcsumtype, userinfo->iconcsum, userinfo->iconcsumlen);
+		aim_bart_request(od, od->requesticon->data, userinfo->iconcsumtype, userinfo->iconcsum, userinfo->iconcsumlen);
 		return FALSE;
 	} else {
-		char *sn = od->requesticon->data;
+		gchar *sn = od->requesticon->data;
 		od->requesticon = g_slist_remove(od->requesticon, sn);
-		free(sn);
+		g_free(sn);
 	}
 
 	return TRUE;
@@ -5755,7 +3282,7 @@
 /*
  * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option.
  */
-static int gaim_parse_msgack(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_parse_msgack(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	guint16 type;
 	char *sn;
@@ -5770,7 +3297,7 @@
 	return 1;
 }
 
-static int gaim_parse_ratechange(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_parse_ratechange(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	static const char *codes[5] = {
 		"invalid",
 		"change",
@@ -5806,7 +3333,7 @@
 
 	if (code == AIM_RATE_CODE_LIMIT)
 	{
-		gaim_notify_error(sess->aux_data, NULL, _("Rate limiting error."),
+		gaim_notify_error(od->gc, NULL, _("Rate limiting error."),
 						  _("The last action you attempted could not be "
 							"performed because you are over the rate limit. "
 							"Please wait 10 seconds and try again."));
@@ -5815,7 +3342,7 @@
 	return 1;
 }
 
-static int gaim_parse_evilnotify(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_parse_evilnotify(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	guint16 newevil;
 	aim_userinfo_t *userinfo;
@@ -5832,7 +3359,7 @@
 	return 1;
 }
 
-static int gaim_selfinfo(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_selfinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	int warning_level;
 	va_list ap;
 	aim_userinfo_t *info;
@@ -5857,9 +3384,8 @@
 	return 1;
 }
 
-static int gaim_connerr(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
+static int gaim_connerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	va_list ap;
 	guint16 code;
 	char *msg;
@@ -5873,9 +3399,9 @@
 					code, (msg != NULL ? msg : ""));
 
 	g_return_val_if_fail(fr       != NULL, 1);
-	g_return_val_if_fail(fr->conn != NULL, 1);
-
-	if (fr->conn->type == AIM_CONN_TYPE_BOS) {
+	g_return_val_if_fail(conn != NULL, 1);
+
+	if (conn->type == SNAC_FAMILY_LOCATE) {
 		if (code == 0x0001) {
 			gc->wants_to_die = TRUE;
 			gaim_connection_error(gc, _("You have signed on from another location."));
@@ -5883,11 +3409,11 @@
 			gaim_connection_error(gc, _("You have been signed off for an unknown reason."));
 		}
 		od->killme = TRUE;
-	} else if (fr->conn->type == AIM_CONN_TYPE_CHAT) {
+	} else if (conn->type == SNAC_FAMILY_CHAT) {
 		struct chat_connection *cc;
 		GaimConversation *conv;
 
-		cc = find_oscar_chat_by_conn(gc, fr->conn);
+		cc = find_oscar_chat_by_conn(gc, conn);
 		conv = gaim_find_chat(gc, cc->id);
 
 		if (conv != NULL)
@@ -5904,78 +3430,7 @@
 	return 1;
 }
 
-static int conninitdone_bos(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	aim_reqpersonalinfo(sess, fr->conn);
-
-	gaim_debug_info("oscar", "ssi: requesting rights and list\n");
-	aim_ssi_reqrights(sess);
-	aim_ssi_reqdata(sess);
-	if (od->getblisttimer > 0)
-		gaim_timeout_remove(od->getblisttimer);
-	od->getblisttimer = gaim_timeout_add(30000, gaim_ssi_rerequestdata, od->sess);
-
-	aim_locate_reqrights(sess);
-	aim_buddylist_reqrights(sess, fr->conn);
-	aim_im_reqparams(sess);
-	aim_bos_reqrights(sess, fr->conn); /* XXX - Don't call this with ssi */
-
-	gaim_connection_update_progress(gc, _("Finalizing connection"), 5, OSCAR_CONNECT_STEPS);
-
-	return 1;
-}
-
-static int conninitdone_admin(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
-
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_ADMIN, 0x0003, gaim_info_change, 0);
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_ADMIN, 0x0005, gaim_info_change, 0);
-	aim_conn_addhandler(sess, fr->conn, OSCAR_FAMILY_ADMIN, 0x0007, gaim_account_confirm, 0);
-
-	aim_clientready(sess, fr->conn);
-	gaim_debug_info("oscar", "connected to admin\n");
-
-	if (od->chpass) {
-		gaim_debug_info("oscar", "changing password\n");
-		aim_admin_changepasswd(sess, fr->conn, od->newp, od->oldp);
-		g_free(od->oldp);
-		od->oldp = NULL;
-		g_free(od->newp);
-		od->newp = NULL;
-		od->chpass = FALSE;
-	}
-	if (od->setnick) {
-		gaim_debug_info("oscar", "formatting screen name\n");
-		aim_admin_setnick(sess, fr->conn, od->newsn);
-		g_free(od->newsn);
-		od->newsn = NULL;
-		od->setnick = FALSE;
-	}
-	if (od->conf) {
-		gaim_debug_info("oscar", "confirming account\n");
-		aim_admin_reqconfirm(sess, fr->conn);
-		od->conf = FALSE;
-	}
-	if (od->reqemail) {
-		gaim_debug_info("oscar", "requesting email\n");
-		aim_admin_getinfo(sess, fr->conn, 0x0011);
-		od->reqemail = FALSE;
-	}
-	if (od->setemail) {
-		gaim_debug_info("oscar", "setting email\n");
-		aim_admin_setemail(sess, fr->conn, od->email);
-		g_free(od->email);
-		od->email = NULL;
-		od->setemail = FALSE;
-	}
-
-	return 1;
-}
-
-static int gaim_icbm_param_info(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_icbm_param_info(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	struct aim_icbmparameters *params;
 	va_list ap;
 
@@ -5996,16 +3451,15 @@
 	params->maxmsglen = 8000;
 	params->minmsginterval = 0;
 
-	aim_im_setparams(sess, params);
+	aim_im_setparams(od, params);
 
 	return 1;
 }
 
-static int gaim_parse_locaterights(OscarSession *sess, FlapFrame *fr, ...)
+static int gaim_parse_locaterights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	GaimConnection *gc = sess->aux_data;
+	GaimConnection *gc = od->gc;
 	GaimAccount *account = gaim_connection_get_account(gc);
-	OscarData *od = (OscarData *)gc->proto_data;
 	va_list ap;
 	guint16 maxsiglen;
 
@@ -6019,20 +3473,18 @@
 	od->rights.maxsiglen = od->rights.maxawaymsglen = (guint)maxsiglen;
 
 	if (od->icq)
-		aim_locate_setcaps(od->sess, caps_icq);
+		aim_locate_setcaps(od, caps_icq);
 	else
-		aim_locate_setcaps(od->sess, caps_aim);
+		aim_locate_setcaps(od, caps_aim);
 	oscar_set_info_and_status(account, TRUE, account->user_info, TRUE,
 							  gaim_account_get_active_status(account));
 
 	return 1;
 }
 
-static int gaim_parse_buddyrights(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_parse_buddyrights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	guint16 maxbuddies, maxwatchers;
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = (OscarData *)gc->proto_data;
 
 	va_start(ap, fr);
 	maxbuddies = (guint16) va_arg(ap, unsigned int);
@@ -6048,9 +3500,8 @@
 	return 1;
 }
 
-static int gaim_bosrights(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_bosrights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	GaimConnection *gc;
-	OscarData *od;
 	GaimAccount *account;
 	GaimStatus *status;
 	const char *message;
@@ -6058,7 +3509,7 @@
 	va_list ap;
 	guint16 maxpermits, maxdenies;
 
-	gc = sess->aux_data;
+	gc = od->gc;
 	od = (OscarData *)gc->proto_data;
 	account = gaim_connection_get_account(gc);
 
@@ -6077,7 +3528,7 @@
 
 	gaim_debug_info("oscar", "buddy list loaded\n");
 
-	aim_clientready(sess, fr->conn);
+	aim_clientready(od, conn);
 
 	/* Set our available message based on the current status */
 	status = gaim_account_get_active_status(account);
@@ -6086,27 +3537,27 @@
 	else
 		message = NULL;
 	tmp = gaim_markup_strip_html(message);
-	aim_srv_setstatusmsg(sess, tmp);
-	free(tmp);
-
-	aim_srv_setidle(sess, 0);
+	aim_srv_setstatusmsg(od, tmp);
+	g_free(tmp);
+
+	aim_srv_setidle(od, 0);
 
 	if (od->icq) {
-		aim_icq_reqofflinemsgs(sess);
+		aim_icq_reqofflinemsgs(od);
 		oscar_set_extendedstatus(gc);
-		aim_icq_setsecurity(sess,
+		aim_icq_setsecurity(od,
 			gaim_account_get_bool(account, "authorization", OSCAR_DEFAULT_AUTHORIZATION),
 			gaim_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE));
 	}
 
-	aim_reqservice(sess, fr->conn, AIM_CONN_TYPE_CHATNAV);
-	if (sess->authinfo->email)
-		aim_reqservice(sess, fr->conn, AIM_CONN_TYPE_EMAIL);
+	aim_reqservice(od, SNAC_FAMILY_CHATNAV);
+	if (od->authinfo->email != NULL)
+		aim_reqservice(od, SNAC_FAMILY_ALERT);
 
 	return 1;
 }
 
-static int gaim_offlinemsg(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_offlinemsg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	struct aim_icq_offlinemsg *msg;
 	struct aim_incomingim_ch4_args args;
@@ -6124,21 +3575,20 @@
 	args.msglen = msg->msglen;
 	args.msg = msg->msg;
 	t = gaim_time_build(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0);
-	incomingim_chan4(sess, fr->conn, NULL, &args, t);
+	incomingim_chan4(od, conn, NULL, &args, t);
 
 	return 1;
 }
 
-static int gaim_offlinemsgdone(OscarSession *sess, FlapFrame *fr, ...)
+static int gaim_offlinemsgdone(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	aim_icq_ackofflinemsgs(sess);
+	aim_icq_ackofflinemsgs(od);
 	return 1;
 }
 
-static int gaim_icqinfo(OscarSession *sess, FlapFrame *fr, ...)
+static int gaim_icqinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = (OscarData *)gc->proto_data;
+	GaimConnection *gc = od->gc;
 	GaimBuddy *buddy;
 	struct buddyinfo *bi = NULL;
 	gchar who[16];
@@ -6250,9 +3700,9 @@
 	return 1;
 }
 
-static int gaim_icqalias(OscarSession *sess, FlapFrame *fr, ...)
+static int gaim_icqalias(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	GaimConnection *gc = sess->aux_data;
+	GaimConnection *gc = od->gc;
 	GaimAccount *account = gaim_connection_get_account(gc);
 	gchar who[16], *utf8;
 	GaimBuddy *b;
@@ -6275,9 +3725,9 @@
 	return 1;
 }
 
-static int gaim_popup(OscarSession *sess, FlapFrame *fr, ...)
+static int gaim_popup(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	GaimConnection *gc = sess->aux_data;
+	GaimConnection *gc = od->gc;
 	gchar *text;
 	va_list ap;
 	char *msg, *url;
@@ -6304,9 +3754,9 @@
 								 g_list_nth_data(row, 0), NULL, NULL);
 }
 
-static int gaim_parse_searchreply(OscarSession *sess, FlapFrame *fr, ...)
+static int gaim_parse_searchreply(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
-	GaimConnection *gc = sess->aux_data;
+	GaimConnection *gc = od->gc;
 	GaimNotifySearchResults *results;
 	GaimNotifySearchColumn *column;
 	gchar *secondary;
@@ -6337,7 +3787,7 @@
 						 num),
 					email);
 
-	column = gaim_notify_searchresults_column_new(_("Screen Name"));
+	column = gaim_notify_searchresults_column_new(_("Screen name"));
 	gaim_notify_searchresults_column_add(results, column);
 
 	for (i = 0; i < num; i++) {
@@ -6354,7 +3804,7 @@
 	return 1;
 }
 
-static int gaim_parse_searcherror(OscarSession *sess, FlapFrame *fr, ...) {
+static int gaim_parse_searcherror(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	va_list ap;
 	char *email;
 	char *buf;
@@ -6364,14 +3814,14 @@
 	va_end(ap);
 
 	buf = g_strdup_printf(_("No results found for e-mail address %s"), email);
-	gaim_notify_error(sess->aux_data, NULL, buf, NULL);
+	gaim_notify_error(od->gc, NULL, buf, NULL);
 	g_free(buf);
 
 	return 1;
 }
 
-static int gaim_account_confirm(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_account_confirm(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	guint16 status;
 	va_list ap;
 	char msg[256];
@@ -6382,7 +3832,7 @@
 
 	gaim_debug_info("oscar",
 			   "account confirmation returned status 0x%04x (%s)\n", status,
-			status ? "unknown" : "email sent");
+			status ? "unknown" : "e-mail sent");
 	if (!status) {
 		g_snprintf(msg, sizeof(msg), _("You should receive an e-mail asking to confirm %s."),
 				gaim_account_get_username(gaim_connection_get_account(gc)));
@@ -6392,8 +3842,8 @@
 	return 1;
 }
 
-static int gaim_info_change(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_info_change(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	va_list ap;
 	guint16 perms, err;
 	char *url, *sn, *email;
@@ -6463,21 +3913,31 @@
 	return 1;
 }
 
-static void oscar_keepalive(GaimConnection *gc) {
-	OscarData *od = (OscarData *)gc->proto_data;
-	aim_flap_nop(od->sess, od->conn);
-}
-
-static int oscar_send_typing(GaimConnection *gc, const char *name, int typing) {
-	OscarData *od = (OscarData *)gc->proto_data;
-	struct oscar_direct_im *dim = oscar_direct_im_find(od, name);
-	if (dim && dim->connected)
-		if (typing == GAIM_TYPING)
-			aim_odc_send_typing(od->sess, dim->conn, 0x0002);
-		else if (typing == GAIM_TYPED)
-			aim_odc_send_typing(od->sess, dim->conn, 0x0001);
-		else
-			aim_odc_send_typing(od->sess, dim->conn, 0x0000);
+static void
+oscar_keepalive(GaimConnection *gc)
+{
+	OscarData *od;
+	FlapConnection *conn;
+
+	od = (OscarData *)gc->proto_data;
+	conn = flap_connection_getbytype(od, SNAC_FAMILY_LOCATE);
+	if (conn != NULL)
+		flap_connection_send_keepalive(od, conn);
+}
+
+static int
+oscar_send_typing(GaimConnection *gc, const char *name, int typing)
+{
+	OscarData *od;
+	PeerConnection *conn;
+
+	od = (OscarData *)gc->proto_data;
+	conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM);
+
+	if ((conn != NULL) && (conn->ready))
+	{
+		peer_odc_send_typing(conn, typing);
+	}
 	else {
 		/* Don't send if this turkey is in our deny list */
 		GSList *list;
@@ -6486,41 +3946,116 @@
 			struct buddyinfo *bi = g_hash_table_lookup(od->buddyinfo, gaim_normalize(gc->account, name));
 			if (bi && bi->typingnot) {
 				if (typing == GAIM_TYPING)
-					aim_im_sendmtn(od->sess, 0x0001, name, 0x0002);
+					aim_im_sendmtn(od, 0x0001, name, 0x0002);
 				else if (typing == GAIM_TYPED)
-					aim_im_sendmtn(od->sess, 0x0001, name, 0x0001);
+					aim_im_sendmtn(od, 0x0001, name, 0x0001);
 				else
-					aim_im_sendmtn(od->sess, 0x0001, name, 0x0000);
+					aim_im_sendmtn(od, 0x0001, name, 0x0000);
 			}
 		}
 	}
 	return 0;
 }
 
-static int gaim_odc_send_im(OscarSession *, OscarConnection *, const char *, GaimMessageFlags);
-
-static int oscar_send_im(GaimConnection *gc, const char *name, const char *message, GaimMessageFlags imflags) {
-	OscarData *od = (OscarData *)gc->proto_data;
-	GaimAccount *account = gaim_connection_get_account(gc);
-	struct oscar_direct_im *dim = oscar_direct_im_find(od, name);
-	int ret = 0;
-	char *iconfile = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(account));
+/* TODO: Move this into odc.c! */
+static void
+gaim_odc_send_im(PeerConnection *conn, const char *message, GaimMessageFlags imflags)
+{
+	GString *msg = g_string_new("<HTML><BODY>");
+	GString *data = g_string_new("</BODY></HTML><BINARY>");
+	GData *attribs;
+	const char *start, *end, *last;
+	int oscar_id = 0;
+
+	last = message;
+
+	/* for each valid IMG tag... */
+	while (last && *last && gaim_markup_find_tag("img", last, &start, &end, &attribs))
+	{
+		GaimStoredImage *image = NULL;
+		const char *id;
+
+		if (start - last) {
+			g_string_append_len(msg, last, start - last);
+		}
+
+		id = g_datalist_get_data(&attribs, "id");
+
+		/* ... if it refers to a valid gaim image ... */
+		if (id && (image = gaim_imgstore_get(atoi(id)))) {
+			/* ... append the message from start to the tag ... */
+			unsigned long size = gaim_imgstore_get_size(image);
+			const char *filename = gaim_imgstore_get_filename(image);
+			gpointer imgdata = gaim_imgstore_get_data(image);
+
+			oscar_id++;
+
+			/* ... insert a new img tag with the oscar id ... */
+			if (filename)
+				g_string_append_printf(msg,
+					"<IMG SRC=\"%s\" ID=\"%d\" DATASIZE=\"%lu\">",
+					filename, oscar_id, size);
+			else
+				g_string_append_printf(msg,
+					"<IMG ID=\"%d\" DATASIZE=\"%lu\">",
+					oscar_id, size);
+
+			/* ... and append the data to the binary section ... */
+			g_string_append_printf(data, "<DATA ID=\"%d\" SIZE=\"%lu\">",
+				oscar_id, size);
+			data = g_string_append_len(data, imgdata, size);
+			data = g_string_append(data, "</DATA>");
+		}
+			/* If the tag is invalid, skip it, thus no else here */
+
+		g_datalist_clear(&attribs);
+
+		/* continue from the end of the tag */
+		last = end + 1;
+	}
+
+	/* append any remaining message data (without the > :-) ) */
+	if (last && *last)
+		msg = g_string_append(msg, last);
+
+	/* if we inserted any images in the binary section, append it */
+	if (oscar_id) {
+		msg = g_string_append_len(msg, data->str, data->len);
+		msg = g_string_append(msg, "</BINARY>");
+	}
+
+	g_string_free(data, TRUE);
+
+	/* TODO: Deal with the encoding. */
+	peer_odc_send_im(conn, msg->str, msg->len, 0, imflags & GAIM_MESSAGE_AUTO_RESP);
+	g_string_free(msg, TRUE);
+}
+
+static int
+oscar_send_im(GaimConnection *gc, const char *name, const char *message, GaimMessageFlags imflags)
+{
+	OscarData *od;
+	GaimAccount *account;
+	PeerConnection *conn;
+	int ret;
+	char *iconfile;
 	char *tmp1, *tmp2;
 
+	od = (OscarData *)gc->proto_data;
+	account = gaim_connection_get_account(gc);
+	ret = 0;
+	iconfile = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(account));
+
 	if (imflags & GAIM_MESSAGE_AUTO_RESP)
-		/*
-		 * TODO: Do this earlier in the IM-sending chain of events.
-		 *       We should attach to an IM-sending signal and do it
-		 *       there.  As it is currently implemented, encrypted
-		 *       messages are not substituted.
-		 */
 		tmp1 = gaim_str_sub_away_formatters(message, name);
 	else
 		tmp1 = g_strdup(message);
 
-	if (dim && dim->connected) {
+	conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM);
+	if ((conn != NULL) && (conn->ready))
+	{
 		/* If we're directly connected, send a direct IM */
-		ret = gaim_odc_send_im(od->sess, dim->conn, tmp1, imflags);
+		gaim_odc_send_im(conn, tmp1, imflags);
 	} else {
 		struct buddyinfo *bi;
 		struct aim_sendimext_args args;
@@ -6579,7 +4114,7 @@
 			FILE *file = g_fopen(iconfile, "rb");
 			if (file) {
 				guchar *buf = g_malloc(st.st_size);
-				/* XXX - Use g_file_get_contents()? */
+				/* TODO: Use g_file_get_contents()? */
 				fread(buf, 1, st.st_size, file);
 				fclose(file);
 
@@ -6633,7 +4168,7 @@
 		gaim_plugin_oscar_convert_to_best_encoding(gc, name, tmp1, (char **)&args.msg, &args.msglen, &args.charset, &args.charsubset);
 		gaim_debug_info("oscar", "Sending IM, charset=0x%04hx, charsubset=0x%04hx, length=%d\n",
 						args.charset, args.charsubset, args.msglen);
-		ret = aim_im_sendch1_ext(od->sess, &args);
+		ret = aim_im_sendch1_ext(od, &args);
 		g_free((char *)args.msg);
 	}
 
@@ -6649,9 +4184,9 @@
 	OscarData *od = (OscarData *)gc->proto_data;
 
 	if (od->icq && aim_sn_is_icq(name))
-		aim_icq_getallinfo(od->sess, name);
+		aim_icq_getallinfo(od, name);
 	else
-		aim_locate_getinfoshort(od->sess, name, 0x00000003);
+		aim_locate_getinfoshort(od, name, 0x00000003);
 }
 
 #if 0
@@ -6659,14 +4194,14 @@
 			  const char *maiden, const char *city, const char *state, const char *country, int web) {
 	/* XXX - some of these things are wrong, but i'm lazy */
 	OscarData *od = (OscarData *)gc->proto_data;
-	aim_locate_setdirinfo(od->sess, first, middle, last,
+	aim_locate_setdirinfo(od, first, middle, last,
 				maiden, NULL, NULL, city, state, NULL, 0, web);
 }
 #endif
 
 static void oscar_set_idle(GaimConnection *gc, int time) {
 	OscarData *od = (OscarData *)gc->proto_data;
-	aim_srv_setidle(od->sess, time);
+	aim_srv_setidle(od, time);
 }
 
 static
@@ -6737,7 +4272,7 @@
 	else if (!strcmp(status_id, OSCAR_STATUS_ID_CUSTOM))
 		data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY;
 
-	aim_setextstatus(od->sess, data);
+	aim_setextstatus(od, data);
 }
 
 static void
@@ -6816,15 +4351,14 @@
 				char *tmp = g_utf8_find_prev_char(status_text, &status_text[58]);
 				strcpy(tmp, "...");
 			}
+			else
+			{
+				/* User did not specify an available message */
+				status_text = NULL;
+			}
+			aim_srv_setstatusmsg(od, status_text);
+			g_free(status_text);
 		}
-		else
-		{
-			/* User did not specify an available message */
-			status_text = NULL;
-		}
-
-		aim_srv_setstatusmsg(od->sess, status_text);
-		g_free(status_text);
 
 		/* This is needed for us to un-set any previous away message. */
 		away = g_strdup("");
@@ -6853,7 +4387,7 @@
 	if (setstatus)
 		oscar_set_extendedstatus(gc);
 
-	aim_locate_setprofile(od->sess, info_encoding, info, MIN(infolen, od->rights.maxsiglen),
+	aim_locate_setprofile(od, info_encoding, info, MIN(infolen, od->rights.maxsiglen),
 									away_encoding, away, MIN(awaylen, od->rights.maxawaymsglen));
 	g_free(info);
 	g_free(away);
@@ -6875,8 +4409,8 @@
 	else
 		account->perm_deny = GAIM_PRIVACY_DENY_USERS;
 
-	if ((od->sess->ssi.received_data) && (aim_ssi_getpermdeny(od->sess->ssi.local) != account->perm_deny))
-		aim_ssi_setpermdeny(od->sess, account->perm_deny, 0xffffffff);
+	if ((od->ssi.received_data) && (aim_ssi_getpermdeny(od->ssi.local) != account->perm_deny))
+		aim_ssi_setpermdeny(od, account->perm_deny, 0xffffffff);
 
 	oscar_set_extendedstatus(gc);
 }
@@ -6904,7 +4438,7 @@
 static void
 oscar_warn(GaimConnection *gc, const char *name, gboolean anonymous) {
 	OscarData *od = (OscarData *)gc->proto_data;
-	aim_im_warn(od->sess, od->conn, name, anonymous ? AIM_WARN_ANON : 0);
+	aim_im_warn(od, od->conn, name, anonymous ? AIM_WARN_ANON : 0);
 }
 #endif
 
@@ -6925,46 +4459,46 @@
 		return;
 	}
 
-	if ((od->sess->ssi.received_data) && !(aim_ssi_itemlist_finditem(od->sess->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY))) {
+	if ((od->ssi.received_data) && !(aim_ssi_itemlist_finditem(od->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY))) {
 		if (buddy && group) {
 			gaim_debug_info("oscar",
 					   "ssi: adding buddy %s to group %s\n", buddy->name, group->name);
-			aim_ssi_addbuddy(od->sess, buddy->name, group->name, gaim_buddy_get_alias_only(buddy), NULL, NULL, 0);
+			aim_ssi_addbuddy(od, buddy->name, group->name, gaim_buddy_get_alias_only(buddy), NULL, NULL, 0);
 		}
 	}
 
 	/* XXX - Should this be done from AIM accounts, as well? */
 	if (od->icq)
-		aim_icq_getalias(od->sess, buddy->name);
+		aim_icq_getalias(od, buddy->name);
 }
 
 static void oscar_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) {
 	OscarData *od = (OscarData *)gc->proto_data;
 
-	if (od->sess->ssi.received_data) {
+	if (od->ssi.received_data) {
 		gaim_debug_info("oscar",
 				   "ssi: deleting buddy %s from group %s\n", buddy->name, group->name);
-		aim_ssi_delbuddy(od->sess, buddy->name, group->name);
+		aim_ssi_delbuddy(od, buddy->name, group->name);
 	}
 }
 
 static void oscar_move_buddy(GaimConnection *gc, const char *name, const char *old_group, const char *new_group) {
 	OscarData *od = (OscarData *)gc->proto_data;
-	if (od->sess->ssi.received_data && strcmp(old_group, new_group)) {
+	if (od->ssi.received_data && strcmp(old_group, new_group)) {
 		gaim_debug_info("oscar",
 				   "ssi: moving buddy %s from group %s to group %s\n", name, old_group, new_group);
-		aim_ssi_movebuddy(od->sess, old_group, new_group, name);
+		aim_ssi_movebuddy(od, old_group, new_group, name);
 	}
 }
 
 static void oscar_alias_buddy(GaimConnection *gc, const char *name, const char *alias) {
 	OscarData *od = (OscarData *)gc->proto_data;
-	if (od->sess->ssi.received_data) {
-		char *gname = aim_ssi_itemlist_findparentname(od->sess->ssi.local, name);
+	if (od->ssi.received_data) {
+		char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, name);
 		if (gname) {
 			gaim_debug_info("oscar",
 					   "ssi: changing the alias for buddy %s to %s\n", name, alias ? alias : "(none)");
-			aim_ssi_aliasbuddy(od->sess, gname, name, alias);
+			aim_ssi_aliasbuddy(od, gname, name, alias);
 		}
 	}
 }
@@ -6975,8 +4509,8 @@
 static void oscar_rename_group(GaimConnection *gc, const char *old_name, GaimGroup *group, GList *moved_buddies) {
 	OscarData *od = (OscarData *)gc->proto_data;
 
-	if (od->sess->ssi.received_data) {
-		if (aim_ssi_itemlist_finditem(od->sess->ssi.local, group->name, NULL, AIM_SSI_TYPE_GROUP)) {
+	if (od->ssi.received_data) {
+		if (aim_ssi_itemlist_finditem(od->ssi.local, group->name, NULL, AIM_SSI_TYPE_GROUP)) {
 			GList *cur, *groups = NULL;
 			GaimAccount *account = gaim_connection_get_account(gc);
 
@@ -6995,7 +4529,7 @@
 			gaim_debug_info("oscar",
 					   "ssi: moved all buddies from group %s to %s\n", old_name, group->name);
 		} else {
-			aim_ssi_rename_group(od->sess, old_name, group->name);
+			aim_ssi_rename_group(od, old_name, group->name);
 			gaim_debug_info("oscar",
 					   "ssi: renamed group %s to %s\n", old_name, group->name);
 		}
@@ -7003,16 +4537,15 @@
 }
 
 static gboolean gaim_ssi_rerequestdata(gpointer data) {
-	OscarSession *sess = data;
-
-	aim_ssi_reqdata(sess);
+	OscarData *od = data;
+
+	aim_ssi_reqdata(od);
 
 	return TRUE;
 }
 
-static int gaim_ssi_parseerr(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
+static int gaim_ssi_parseerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	va_list ap;
 	guint16 reason;
 
@@ -7027,7 +4560,7 @@
 						  _("Gaim was temporarily unable to retrieve your buddy list from the AIM servers.  Your buddy list is not lost, and will probably become available in a few hours."));
 		if (od->getblisttimer > 0)
 			gaim_timeout_remove(od->getblisttimer);
-		od->getblisttimer = gaim_timeout_add(30000, gaim_ssi_rerequestdata, od->sess);
+		od->getblisttimer = gaim_timeout_add(30000, gaim_ssi_rerequestdata, od);
 	}
 
 	oscar_set_extendedstatus(gc);
@@ -7036,14 +4569,12 @@
 	/* Sending the enable causes other people to be able to see you, and you to see them */
 	/* Make sure your privacy setting/invisibility is set how you want it before this! */
 	gaim_debug_info("oscar", "ssi: activating server-stored buddy list\n");
-	aim_ssi_enable(od->sess);
+	aim_ssi_enable(od);
 
 	return 1;
 }
 
-static int gaim_ssi_parserights(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = (OscarData *)gc->proto_data;
+static int gaim_ssi_parserights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
 	int i;
 	va_list ap;
 	int numtypes;
@@ -7074,10 +4605,9 @@
 	return 1;
 }
 
-static int gaim_ssi_parselist(OscarSession *sess, FlapFrame *fr, ...)
+static int gaim_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
 {
 	GaimConnection *gc;
-	OscarData *od;
 	GaimAccount *account;
 	GaimGroup *g;
 	GaimBuddy *b;
@@ -7088,7 +4618,7 @@
 	struct aim_ssi_item *items;
 	guint32 timestamp;
 
-	gc = sess->aux_data;
+	gc = od->gc;
 	od = gc->proto_data;
 	account = gaim_connection_get_account(gc);
 
@@ -7113,7 +4643,7 @@
 	}
 
 	/* Clean the buddy list */
-	aim_ssi_cleanlist(sess);
+	aim_ssi_cleanlist(od);
 
 	{ /* If not in server list then prune from local list */
 		GaimBlistNode *gnode, *cnode, *bnode;
@@ -7135,7 +4665,7 @@
 							continue;
 						b = (GaimBuddy *)bnode;
 						if (b->account == gc->account) {
-							if (aim_ssi_itemlist_exists(sess->ssi.local, b->name)) {
+							if (aim_ssi_itemlist_exists(od->ssi.local, b->name)) {
 								/* If the buddy is an ICQ user then load his nickname */
 								const char *servernick = gaim_blist_node_get_string((GaimBlistNode*)b, "servernick");
 								char *alias;
@@ -7143,10 +4673,10 @@
 									serv_got_alias(gc, b->name, servernick);
 
 								/* Store local alias on server */
-								alias = aim_ssi_getalias(sess->ssi.local, g->name, b->name);
+								alias = aim_ssi_getalias(od->ssi.local, g->name, b->name);
 								if (!alias && b->alias && strlen(b->alias))
-									aim_ssi_aliasbuddy(sess, g->name, b->name, b->alias);
-								free(alias);
+									aim_ssi_aliasbuddy(od, g->name, b->name, b->alias);
+								g_free(alias);
 							} else {
 								gaim_debug_info("oscar",
 										"ssi: removing buddy %s from local list\n", b->name);
@@ -7171,7 +4701,7 @@
 			while (next != NULL) {
 				cur = next;
 				next = next->next;
-				if (!aim_ssi_itemlist_finditem(sess->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
+				if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
 					gaim_debug_info("oscar",
 							"ssi: removing permit %s from local list\n", (const char *)cur->data);
 					gaim_privacy_permit_remove(account, cur->data, TRUE);
@@ -7185,7 +4715,7 @@
 			while (next != NULL) {
 				cur = next;
 				next = next->next;
-				if (!aim_ssi_itemlist_finditem(sess->ssi.local, NULL, cur->data, AIM_SSI_TYPE_DENY)) {
+				if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_DENY)) {
 					gaim_debug_info("oscar",
 							"ssi: removing deny %s from local list\n", (const char *)cur->data);
 					gaim_privacy_deny_remove(account, cur->data, TRUE);
@@ -7193,25 +4723,25 @@
 			}
 		}
 		/* Presence settings (idle time visibility) */
-		if ((tmp = aim_ssi_getpresence(sess->ssi.local)) != 0xFFFFFFFF)
+		if ((tmp = aim_ssi_getpresence(od->ssi.local)) != 0xFFFFFFFF)
 			if (!(tmp & 0x400))
-				aim_ssi_setpresence(sess, tmp | 0x400);
+				aim_ssi_setpresence(od, tmp | 0x400);
 	} /* end pruning buddies from local list */
 
 	/* Add from server list to local list */
-	for (curitem=sess->ssi.local; curitem; curitem=curitem->next) {
+	for (curitem=od->ssi.local; curitem; curitem=curitem->next) {
 		if ((curitem->name == NULL) || (g_utf8_validate(curitem->name, -1, NULL)))
 		switch (curitem->type) {
 			case 0x0000: { /* Buddy */
 				if (curitem->name) {
-					char *gname = aim_ssi_itemlist_findparentname(sess->ssi.local, curitem->name);
+					char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, curitem->name);
 					char *gname_utf8 = gname ? oscar_utf8_try_convert(gc->account, gname) : NULL;
-					char *alias = aim_ssi_getalias(sess->ssi.local, gname, curitem->name);
+					char *alias = aim_ssi_getalias(od->ssi.local, gname, curitem->name);
 					char *alias_utf8 = alias ? oscar_utf8_try_convert(gc->account, alias) : NULL;
 					b = gaim_find_buddy(gc->account, curitem->name);
 					/* Should gname be freed here? -- elb */
 					/* Not with the current code, but that might be cleaner -- med */
-					free(alias);
+					g_free(alias);
 					if (b) {
 						/* Get server stored alias */
 						if (alias_utf8) {
@@ -7231,9 +4761,9 @@
 						gaim_blist_add_buddy(b, NULL, g, NULL);
 					}
 					if (!aim_sncmp(curitem->name, account->username)) {
-						char *comment = aim_ssi_getcomment(sess->ssi.local, gname, curitem->name);
+						char *comment = aim_ssi_getcomment(od->ssi.local, gname, curitem->name);
 						gaim_check_comment(od, comment);
-						free(comment);
+						g_free(comment);
 					}
 					g_free(gname_utf8);
 					g_free(alias_utf8);
@@ -7272,7 +4802,7 @@
 			case 0x0004: { /* Permit/deny setting */
 				if (curitem->data) {
 					guint8 permdeny;
-					if ((permdeny = aim_ssi_getpermdeny(sess->ssi.local)) && (permdeny != account->perm_deny)) {
+					if ((permdeny = aim_ssi_getpermdeny(od->ssi.local)) && (permdeny != account->perm_deny)) {
 						gaim_debug_info("oscar",
 								   "ssi: changing permdeny from %d to %hhu\n", account->perm_deny, permdeny);
 						account->perm_deny = permdeny;
@@ -7296,13 +4826,13 @@
 	/* Make sure your privacy setting/invisibility is set how you want it before this! */
 	gaim_debug_info("oscar",
 			   "ssi: activating server-stored buddy list\n");
-	aim_ssi_enable(sess);
+	aim_ssi_enable(od);
 
 	return 1;
 }
 
-static int gaim_ssi_parseack(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_ssi_parseack(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	va_list ap;
 	struct aim_ssi_tmp *retval;
 
@@ -7328,7 +4858,7 @@
 			}
 
 			case 0x000e: { /* buddy requires authorization */
-				if ((retval->action == OSCAR_SUBTYPE_FEEDBAG_ADD) && (retval->name))
+				if ((retval->action == SNAC_SUBTYPE_FEEDBAG_ADD) && (retval->name))
 					gaim_auth_sendrequest(gc, retval->name);
 			} break;
 
@@ -7348,8 +4878,8 @@
 	return 1;
 }
 
-static int gaim_ssi_parseadd(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_ssi_parseadd(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	char *gname, *gname_utf8, *alias, *alias_utf8;
 	GaimBuddy *b;
 	GaimGroup *g;
@@ -7365,12 +4895,12 @@
 	if ((type != 0x0000) || (name == NULL))
 		return 1;
 
-	gname = aim_ssi_itemlist_findparentname(sess->ssi.local, name);
+	gname = aim_ssi_itemlist_findparentname(od->ssi.local, name);
 	gname_utf8 = gname ? oscar_utf8_try_convert(gc->account, gname) : NULL;
-	alias = aim_ssi_getalias(sess->ssi.local, gname, name);
+	alias = aim_ssi_getalias(od->ssi.local, gname, name);
 	alias_utf8 = alias ? oscar_utf8_try_convert(gc->account, alias) : NULL;
 	b = gaim_find_buddy(gc->account, name);
-	free(alias);
+	g_free(alias);
 
 	if (b) {
 		/* Get server stored alias */
@@ -7396,8 +4926,8 @@
 	return 1;
 }
 
-static int gaim_ssi_authgiven(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_ssi_authgiven(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	va_list ap;
 	char *sn, *msg;
 	gchar *dialog_msg, *nombre;
@@ -7435,8 +4965,8 @@
 	return 1;
 }
 
-static int gaim_ssi_authrequest(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_ssi_authrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	va_list ap;
 	char *sn;
 	char *msg;
@@ -7488,8 +5018,8 @@
 	return 1;
 }
 
-static int gaim_ssi_authreply(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_ssi_authreply(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	va_list ap;
 	char *sn, *msg;
 	gchar *dialog_msg, *nombre;
@@ -7526,8 +5056,8 @@
 	return 1;
 }
 
-static int gaim_ssi_gotadded(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
+static int gaim_ssi_gotadded(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	va_list ap;
 	char *sn;
 	GaimBuddy *buddy;
@@ -7537,8 +5067,7 @@
 	va_end(ap);
 
 	buddy = gaim_find_buddy(gc->account, sn);
-	gaim_debug_info("oscar",
-			   "ssi: %s added you to their buddy list\n", sn);
+	gaim_debug_info("oscar", "ssi: %s added you to their buddy list\n", sn);
 	gaim_account_notify_added(gc->account, NULL, sn, (buddy ? gaim_buddy_get_alias_only(buddy) : NULL), NULL);
 
 	return 1;
@@ -7578,13 +5107,17 @@
 	return defaults;
 }
 
-static char *oscar_get_chat_name(GHashTable *data) {
+static char *
+oscar_get_chat_name(GHashTable *data)
+{
 	return g_strdup(g_hash_table_lookup(data, "room"));
 }
 
-static void oscar_join_chat(GaimConnection *gc, GHashTable *data) {
+static void
+oscar_join_chat(GaimConnection *gc, GHashTable *data)
+{
 	OscarData *od = (OscarData *)gc->proto_data;
-	OscarConnection *cur;
+	FlapConnection *conn;
 	char *name, *exchange;
 
 	name = g_hash_table_lookup(data, "room");
@@ -7595,33 +5128,33 @@
 		return;
 	}
 
-	gaim_debug_info("oscar",
-			   "Attempting to join chat room %s.\n", name);
-
-	if ((cur = aim_getconn_type(od->sess, AIM_CONN_TYPE_CHATNAV))) {
-		gaim_debug_info("oscar",
-				   "chatnav exists, creating room\n");
-		aim_chatnav_createroom(od->sess, cur, name, atoi(exchange));
+	gaim_debug_info("oscar", "Attempting to join chat room %s.\n", name);
+
+	if ((conn = flap_connection_getbytype(od, SNAC_FAMILY_CHATNAV)))
+	{
+		gaim_debug_info("oscar", "chatnav exists, creating room\n");
+		aim_chatnav_createroom(od, conn, name, atoi(exchange));
 	} else {
 		/* this gets tricky */
 		struct create_room *cr = g_new0(struct create_room, 1);
-		gaim_debug_info("oscar",
-				   "chatnav does not exist, opening chatnav\n");
+		gaim_debug_info("oscar", "chatnav does not exist, opening chatnav\n");
 		cr->exchange = atoi(exchange);
 		cr->name = g_strdup(name);
 		od->create_rooms = g_slist_append(od->create_rooms, cr);
-		aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_CHATNAV);
-	}
-}
-
-static void oscar_chat_invite(GaimConnection *gc, int id, const char *message, const char *name) {
+		aim_reqservice(od, SNAC_FAMILY_CHATNAV);
+	}
+}
+
+static void
+oscar_chat_invite(GaimConnection *gc, int id, const char *message, const char *name)
+{
 	OscarData *od = (OscarData *)gc->proto_data;
 	struct chat_connection *ccon = find_oscar_chat(gc, id);
 
 	if (ccon == NULL)
 		return;
 
-	aim_im_sendch2_chatinvite(od->sess, name, message ? message : "",
+	aim_im_sendch2_chatinvite(od, name, message ? message : "",
 			ccon->exchange, ccon->name, 0x0);
 }
 
@@ -7677,7 +5210,7 @@
 		charsetstr = "unicode-2-0";
 	else if (charset == AIM_CHARSET_CUSTOM)
 		charsetstr = "iso-8859-1";
-	aim_chat_send_im(od->sess, c->conn, 0, buf2, len, charsetstr, "en");
+	aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "en");
 	g_free(buf2);
 
 	return 0;
@@ -7716,7 +5249,7 @@
 	if (gc != NULL)
 		od = gc->proto_data;
 	if (od != NULL)
-		userinfo = aim_locate_finduserinfo(od->sess, b->name);
+		userinfo = aim_locate_finduserinfo(od, b->name);
 
 	presence = gaim_buddy_get_presence(b);
 	status = gaim_presence_get_active_status(presence);
@@ -7724,9 +5257,9 @@
 
 	if (gaim_presence_is_online(presence) == FALSE) {
 		char *gname;
-		if ((b->name) && (od) && (od->sess->ssi.received_data) &&
-			(gname = aim_ssi_itemlist_findparentname(od->sess->ssi.local, b->name)) &&
-			(aim_ssi_waitingforauth(od->sess->ssi.local, gname, b->name))) {
+		if ((b->name) && (od) && (od->ssi.received_data) &&
+			(gname = aim_ssi_itemlist_findparentname(od->ssi.local, b->name)) &&
+			(aim_ssi_waitingforauth(od->ssi.local, gname, b->name))) {
 			emblems[i++] = "notauthorized";
 		} else {
 			emblems[i++] = "offline";
@@ -7762,10 +5295,10 @@
 		if ((i < 4) && userinfo->flags & AIM_FLAG_ACTIVEBUDDY)
 			emblems[i++] = "activebuddy";
 
-		if ((i < 4) && (userinfo->capabilities & AIM_CAPS_HIPTOP))
+		if ((i < 4) && (userinfo->capabilities & OSCAR_CAPABILITY_HIPTOP))
 			emblems[i++] = "hiptop";
 
-		if ((i < 4) && (userinfo->capabilities & AIM_CAPS_SECUREIM))
+		if ((i < 4) && (userinfo->capabilities & OSCAR_CAPABILITY_SECUREIM))
 			emblems[i++] = "secure";
 	}
 
@@ -7778,7 +5311,7 @@
 static void oscar_tooltip_text(GaimBuddy *b, GString *str, gboolean full) {
 	GaimConnection *gc = b->account->gc;
 	OscarData *od = gc->proto_data;
-	aim_userinfo_t *userinfo = aim_locate_finduserinfo(od->sess, b->name);
+	aim_userinfo_t *userinfo = aim_locate_finduserinfo(od, b->name);
 
 	if (GAIM_BUDDY_IS_ONLINE(b)) {
 		GaimPresence *presence;
@@ -7796,8 +5329,9 @@
 		{
 			if (message != NULL)
 			{
-				char *tmp = g_markup_escape_text(message, -1);
 				/* Available status messages are plain text */
+				gchar *tmp;
+				tmp = g_markup_escape_text(message, -1);
 				g_string_append_printf(str, "\n<b>%s:</b> %s", _("Message"), tmp);
 				g_free(tmp);
 			}
@@ -7844,8 +5378,8 @@
 
 	if (!gaim_presence_is_online(presence))
 	{
-		char *gname = aim_ssi_itemlist_findparentname(od->sess->ssi.local, b->name);
-		if (aim_ssi_waitingforauth(od->sess->ssi.local, gname, b->name))
+		char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, b->name);
+		if (aim_ssi_waitingforauth(od->ssi.local, gname, b->name))
 			ret = g_strdup(_("Not Authorized"));
 		else
 			ret = g_strdup(_("Offline"));
@@ -7886,9 +5420,8 @@
 }
 
 
-static int oscar_icon_req(OscarSession *sess, FlapFrame *fr, ...) {
-	GaimConnection *gc = sess->aux_data;
-	OscarData *od = gc->proto_data;
+static int oscar_icon_req(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
+	GaimConnection *gc = od->gc;
 	va_list ap;
 	guint16 type;
 	guint8 flags = 0, length = 0;
@@ -7905,15 +5438,15 @@
 			md5 = va_arg(ap, guchar *);
 
 			if (flags == 0x41) {
-				if (!aim_getconn_type(od->sess, AIM_CONN_TYPE_ICON) && !od->iconconnecting) {
+				if (!flap_connection_getbytype(od, SNAC_FAMILY_BART) && !od->iconconnecting) {
 					od->iconconnecting = TRUE;
 					od->set_icon = TRUE;
-					aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_ICON);
+					aim_reqservice(od, SNAC_FAMILY_BART);
 				} else {
 					struct stat st;
 					char *iconfile = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(gaim_connection_get_account(gc)));
 					if (iconfile == NULL) {
-						aim_ssi_delicon(od->sess);
+						aim_ssi_delicon(od);
 					} else if (!g_stat(iconfile, &st)) {
 						guchar *buf = g_malloc(st.st_size);
 						FILE *file = g_fopen(iconfile, "rb");
@@ -7923,7 +5456,7 @@
 							fclose(file);
 							gaim_debug_info("oscar",
 											"Uploading icon to icon server\n");
-							aim_bart_upload(od->sess, buf, st.st_size);
+							aim_bart_upload(od, buf, st.st_size);
 						} else
 							gaim_debug_error("oscar",
 											 "Can't open buddy icon file!\n");
@@ -7937,9 +5470,9 @@
 			} else if (flags == 0x81) {
 				char *iconfile = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(gaim_connection_get_account(gc)));
 				if (iconfile == NULL)
-					aim_ssi_delicon(od->sess);
+					aim_ssi_delicon(od);
 				else {
-					aim_ssi_seticon(od->sess, md5, length);
+					aim_ssi_seticon(od, md5, length);
 					g_free(iconfile);
 				}
 			}
@@ -7958,25 +5491,25 @@
 	GaimAccount *account = gaim_connection_get_account(gc);
 	OscarData *od = (OscarData *)gc->proto_data;
 
-	if (od->sess->ssi.received_data) {
+	if (od->ssi.received_data) {
 		switch (account->perm_deny) {
 			case GAIM_PRIVACY_ALLOW_ALL:
-				aim_ssi_setpermdeny(od->sess, 0x01, 0xffffffff);
+				aim_ssi_setpermdeny(od, 0x01, 0xffffffff);
 				break;
 			case GAIM_PRIVACY_ALLOW_BUDDYLIST:
-				aim_ssi_setpermdeny(od->sess, 0x05, 0xffffffff);
+				aim_ssi_setpermdeny(od, 0x05, 0xffffffff);
 				break;
 			case GAIM_PRIVACY_ALLOW_USERS:
-				aim_ssi_setpermdeny(od->sess, 0x03, 0xffffffff);
+				aim_ssi_setpermdeny(od, 0x03, 0xffffffff);
 				break;
 			case GAIM_PRIVACY_DENY_ALL:
-				aim_ssi_setpermdeny(od->sess, 0x02, 0xffffffff);
+				aim_ssi_setpermdeny(od, 0x02, 0xffffffff);
 				break;
 			case GAIM_PRIVACY_DENY_USERS:
-				aim_ssi_setpermdeny(od->sess, 0x04, 0xffffffff);
+				aim_ssi_setpermdeny(od, 0x04, 0xffffffff);
 				break;
 			default:
-				aim_ssi_setpermdeny(od->sess, 0x01, 0xffffffff);
+				aim_ssi_setpermdeny(od, 0x01, 0xffffffff);
 				break;
 		}
 	}
@@ -7985,29 +5518,29 @@
 static void oscar_add_permit(GaimConnection *gc, const char *who) {
 	OscarData *od = (OscarData *)gc->proto_data;
 	gaim_debug_info("oscar", "ssi: About to add a permit\n");
-	if (od->sess->ssi.received_data)
-		aim_ssi_addpermit(od->sess, who);
+	if (od->ssi.received_data)
+		aim_ssi_addpermit(od, who);
 }
 
 static void oscar_add_deny(GaimConnection *gc, const char *who) {
 	OscarData *od = (OscarData *)gc->proto_data;
 	gaim_debug_info("oscar", "ssi: About to add a deny\n");
-	if (od->sess->ssi.received_data)
-		aim_ssi_adddeny(od->sess, who);
+	if (od->ssi.received_data)
+		aim_ssi_adddeny(od, who);
 }
 
 static void oscar_rem_permit(GaimConnection *gc, const char *who) {
 	OscarData *od = (OscarData *)gc->proto_data;
 	gaim_debug_info("oscar", "ssi: About to delete a permit\n");
-	if (od->sess->ssi.received_data)
-		aim_ssi_delpermit(od->sess, who);
+	if (od->ssi.received_data)
+		aim_ssi_delpermit(od, who);
 }
 
 static void oscar_rem_deny(GaimConnection *gc, const char *who) {
 	OscarData *od = (OscarData *)gc->proto_data;
 	gaim_debug_info("oscar", "ssi: About to delete a deny\n");
-	if (od->sess->ssi.received_data)
-		aim_ssi_deldeny(od->sess, who);
+	if (od->ssi.received_data)
+		aim_ssi_deldeny(od, who);
 }
 
 static GList *
@@ -8088,7 +5621,7 @@
 		return;
 	}
 
-	aim_ssi_editcomment(od->sess, g->name, data->name, text);
+	aim_ssi_editcomment(od, g->name, data->name, text);
 
 	if (!aim_sncmp(data->name, gc->account->username))
 		gaim_check_comment(od, text);
@@ -8117,7 +5650,7 @@
 
 	if (!(g = gaim_buddy_get_group(buddy)))
 		return;
-	comment = aim_ssi_getcomment(od->sess->ssi.local, g->name, buddy->name);
+	comment = aim_ssi_getcomment(od->ssi.local, g->name, buddy->name);
 	comment_utf8 = comment ? oscar_utf8_try_convert(gc->account, comment) : NULL;
 
 	data->gc = gc;
@@ -8132,10 +5665,58 @@
 					   data);
 	g_free(title);
 
-	free(comment);
+	g_free(comment);
 	g_free(comment_utf8);
 }
 
+static void
+oscar_ask_directim_yes_cb(struct oscar_ask_directim_data *data)
+{
+	peer_connection_propose(data->od, OSCAR_CAPABILITY_DIRECTIM, data->who);
+	g_free(data->who);
+	g_free(data);
+}
+
+static void
+oscar_ask_directim_no_cb(struct oscar_ask_directim_data *data)
+{
+	g_free(data->who);
+	g_free(data);
+}
+
+/* This is called from right-click menu on a buddy node. */
+static void
+oscar_ask_directim(gpointer object, gpointer ignored)
+{
+	GaimBlistNode *node;
+	GaimBuddy *buddy;
+	GaimConnection *gc;
+	gchar *buf;
+	struct oscar_ask_directim_data *data;
+
+	node = object;
+
+	g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node));
+
+	buddy = (GaimBuddy *)node;
+	gc = gaim_account_get_connection(buddy->account);
+
+	data = g_new0(struct oscar_ask_directim_data, 1);
+	data->who = g_strdup(buddy->name);
+	data->od = gc->proto_data;
+	buf = g_strdup_printf(_("You have selected to open a Direct IM connection with %s."),
+			buddy->name);
+
+	gaim_request_action(gc, NULL, buf,
+			_("Because this reveals your IP address, it "
+			  "may be considered a security risk.  Do you "
+			  "wish to continue?"),
+			0, data, 2,
+			_("_Connect"), G_CALLBACK(oscar_ask_directim_yes_cb),
+			_("Cancel"), G_CALLBACK(oscar_ask_directim_no_cb));
+	g_free(buf);
+}
+
 static GList *oscar_buddy_menu(GaimBuddy *buddy) {
 
 	GaimConnection *gc = gaim_account_get_connection(buddy->account);
@@ -8158,19 +5739,22 @@
 #endif
 	} else {
 		aim_userinfo_t *userinfo;
-		userinfo = aim_locate_finduserinfo(od->sess, buddy->name);
-
-		if (userinfo && aim_sncmp(gaim_account_get_username(buddy->account), buddy->name) &&
-				GAIM_BUDDY_IS_ONLINE(buddy)) {
-
-			if (userinfo->capabilities & AIM_CAPS_DIRECTIM) {
+		userinfo = aim_locate_finduserinfo(od, buddy->name);
+
+		if (userinfo &&
+			aim_sncmp(gaim_account_get_username(buddy->account), buddy->name) &&
+			GAIM_BUDDY_IS_ONLINE(buddy))
+		{
+			if (userinfo->capabilities & OSCAR_CAPABILITY_DIRECTIM)
+			{
 				act = gaim_menu_action_new(_("Direct IM"),
-				                           GAIM_CALLBACK(oscar_ask_direct_im),
+				                           GAIM_CALLBACK(oscar_ask_directim),
 				                           NULL, NULL);
 				m = g_list_append(m, act);
 			}
 #if 0
-			if (userinfo->capabilities & AIM_CAPS_GETFILE) {
+			/* TODO: This menu item should be added by the core */
+			if (userinfo->capabilities & OSCAR_CAPABILITY_GETFILE) {
 				act = gaim_menu_action_new(_("Get File"),
 				                           GAIM_CALLBACK(oscar_ask_getfile),
 				                           NULL, NULL);
@@ -8180,9 +5764,9 @@
 		}
 	}
 
-	if (od->sess->ssi.received_data) {
-		char *gname = aim_ssi_itemlist_findparentname(od->sess->ssi.local, buddy->name);
-		if (gname && aim_ssi_waitingforauth(od->sess->ssi.local, gname, buddy->name)) {
+	if (od->ssi.received_data) {
+		char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, buddy->name);
+		if (gname && aim_ssi_waitingforauth(od->ssi.local, gname, buddy->name)) {
 			act = gaim_menu_action_new(_("Re-request Authorization"),
 			                           GAIM_CALLBACK(gaim_auth_sendrequest_menu),
 			                           NULL, NULL);
@@ -8220,7 +5804,7 @@
 	gaim_account_set_bool(account, "web_aware", web_aware);
 
 	oscar_set_extendedstatus(gc);
-	aim_icq_setsecurity(od->sess, auth, web_aware);
+	aim_icq_setsecurity(od, auth, web_aware);
 }
 
 static void
@@ -8257,12 +5841,12 @@
 static void oscar_format_screenname(GaimConnection *gc, const char *nick) {
 	OscarData *od = gc->proto_data;
 	if (!aim_sncmp(gaim_account_get_username(gaim_connection_get_account(gc)), nick)) {
-		if (!aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH)) {
+		if (!flap_connection_getbytype(od, SNAC_FAMILY_ADMIN)) {
 			od->setnick = TRUE;
 			od->newsn = g_strdup(nick);
-			aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_AUTH);
+			aim_reqservice(od, SNAC_FAMILY_ADMIN);
 		} else {
-			aim_admin_setnick(od->sess, aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH), nick);
+			aim_admin_setnick(od, flap_connection_getbytype(od, SNAC_FAMILY_ADMIN), nick);
 		}
 	} else {
 		gaim_notify_error(gc, NULL, _("The new formatting is invalid."),
@@ -8282,15 +5866,19 @@
 
 static void oscar_confirm_account(GaimPluginAction *action)
 {
-	GaimConnection *gc = (GaimConnection *) action->context;
-	OscarData *od = gc->proto_data;
-	OscarConnection *conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH);
-
-	if (conn) {
-		aim_admin_reqconfirm(od->sess, conn);
+	GaimConnection *gc;
+	OscarData *od;
+	FlapConnection *conn;
+
+	gc = (GaimConnection *)action->context;
+	od = gc->proto_data;
+
+	conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
+	if (conn != NULL) {
+		aim_admin_reqconfirm(od, conn);
 	} else {
 		od->conf = TRUE;
-		aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_AUTH);
+		aim_reqservice(od, SNAC_FAMILY_ADMIN);
 	}
 }
 
@@ -8298,27 +5886,27 @@
 {
 	GaimConnection *gc = (GaimConnection *) action->context;
 	OscarData *od = gc->proto_data;
-	OscarConnection *conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH);
+	FlapConnection *conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
 
 	if (conn) {
-		aim_admin_getinfo(od->sess, conn, 0x11);
+		aim_admin_getinfo(od, conn, 0x11);
 	} else {
 		od->reqemail = TRUE;
-		aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_AUTH);
+		aim_reqservice(od, SNAC_FAMILY_ADMIN);
 	}
 }
 
 static void oscar_change_email(GaimConnection *gc, const char *email)
 {
 	OscarData *od = gc->proto_data;
-	OscarConnection *conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH);
+	FlapConnection *conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
 
 	if (conn) {
-		aim_admin_setemail(od->sess, conn, email);
+		aim_admin_setemail(od, conn, email);
 	} else {
 		od->setemail = TRUE;
 		od->email = g_strdup(email);
-		aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_AUTH);
+		aim_reqservice(od, SNAC_FAMILY_ADMIN);
 	}
 }
 
@@ -8353,7 +5941,7 @@
 				GaimBuddy *buddy = (GaimBuddy *)bnode;
 				if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
 					continue;
-				if (buddy->account == gc->account && aim_ssi_waitingforauth(od->sess->ssi.local, group->name, buddy->name)) {
+				if (buddy->account == gc->account && aim_ssi_waitingforauth(od->ssi.local, group->name, buddy->name)) {
 					if (gaim_buddy_get_alias_only(buddy))
 						nombre = g_strdup_printf(" %s (%s)", buddy->name, gaim_buddy_get_alias_only(buddy));
 					else
@@ -8385,7 +5973,7 @@
 {
 	OscarData *od = (OscarData *)gc->proto_data;
 
-	aim_search_address(od->sess, od->conn, email);
+	aim_search_address(od, email);
 }
 
 static void oscar_show_find_email(GaimPluginAction *action)
@@ -8422,7 +6010,7 @@
 {
 	GaimConnection *gc = (GaimConnection *) action->context;
 	OscarData *od = gc->proto_data;
-	gchar *substituted = gaim_strreplace(od->sess->authinfo->chpassurl, "%s", gaim_account_get_username(gaim_connection_get_account(gc)));
+	gchar *substituted = gaim_strreplace(od->authinfo->chpassurl, "%s", gaim_account_get_username(gaim_connection_get_account(gc)));
 	gaim_notify_uri(gc, substituted);
 	g_free(substituted);
 }
@@ -8436,12 +6024,11 @@
 static void oscar_set_icon(GaimConnection *gc, const char *iconfile)
 {
 	OscarData *od = gc->proto_data;
-	OscarSession *sess = od->sess;
 	FILE *file;
 	struct stat st;
 
 	if (iconfile == NULL) {
-		aim_ssi_delicon(od->sess);
+		aim_ssi_delicon(od);
 	} else if (!g_stat(iconfile, &st)) {
 		guchar *buf = g_malloc(st.st_size);
 		file = g_fopen(iconfile, "rb");
@@ -8462,18 +6049,95 @@
 			gaim_cipher_context_digest(context, 16, md5, NULL);
 			gaim_cipher_context_destroy(context);
 
-			aim_ssi_seticon(sess, md5, 16);
+			aim_ssi_seticon(od, md5, 16);
 		} else
 			gaim_debug_error("oscar",
 				   "Can't open buddy icon file!\n");
 		g_free(buf);
 	} else
-		gaim_debug_error("oscar",
-			   "Can't stat buddy icon file!\n");
-}
-
-
-static GList *oscar_actions(GaimPlugin *plugin, gpointer context)
+		gaim_debug_error("oscar", "Can't stat buddy icon file!\n");
+}
+
+/**
+ * Called by the Gaim core to determine whether or not we're
+ * allowed to send a file to this user.
+ */
+static gboolean
+oscar_can_receive_file(GaimConnection *gc, const char *who)
+{
+	OscarData *od;
+	GaimAccount *account;
+
+	od = gc->proto_data;
+	account = gaim_connection_get_account(gc);
+
+	if (od != NULL)
+	{
+		aim_userinfo_t *userinfo;
+		userinfo = aim_locate_finduserinfo(od, who);
+
+		/*
+		 * Don't allowing sending a file to a user that does not support
+		 * file transfer, and don't allow sending to ourselves.
+		 */
+		if ((userinfo != NULL) &&
+			(userinfo->capabilities & OSCAR_CAPABILITY_SENDFILE) &&
+			aim_sncmp(who, gaim_account_get_username(account)))
+		{
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+static GaimXfer *
+oscar_new_xfer(GaimConnection *gc, const char *who)
+{
+	GaimXfer *xfer;
+	OscarData *od;
+	GaimAccount *account;
+	PeerConnection *conn;
+
+	od = gc->proto_data;
+	account = gaim_connection_get_account(gc);
+
+	xfer = gaim_xfer_new(account, GAIM_XFER_SEND, who);
+	gaim_xfer_ref(xfer);
+	gaim_xfer_set_init_fnc(xfer, peer_oft_sendcb_init);
+	gaim_xfer_set_cancel_send_fnc(xfer, peer_oft_cb_generic_cancel);
+	gaim_xfer_set_request_denied_fnc(xfer, peer_oft_cb_generic_cancel);
+	gaim_xfer_set_ack_fnc(xfer, peer_oft_sendcb_ack);
+
+	conn = peer_connection_new(od, OSCAR_CAPABILITY_SENDFILE, who);
+	conn->flags |= PEER_CONNECTION_FLAG_INITIATED_BY_ME;
+	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
+	aim_icbm_makecookie(conn->cookie);
+	conn->xfer = xfer;
+	xfer->data = conn;
+
+	return xfer;
+}
+
+/*
+ * Called by the Gaim core when the user indicates that a
+ * file is to be sent to a special someone.
+ */
+static void
+oscar_send_file(GaimConnection *gc, const char *who, const char *file)
+{
+	GaimXfer *xfer;
+
+	xfer = oscar_new_xfer(gc, who);
+
+	if (file != NULL)
+		gaim_xfer_request_accepted(xfer, file);
+	else
+		gaim_xfer_request(xfer);
+}
+
+static GList *
+oscar_actions(GaimPlugin *plugin, gpointer context)
 {
 	GaimConnection *gc = (GaimConnection *) context;
 	OscarData *od = gc->proto_data;
@@ -8495,7 +6159,7 @@
 			oscar_change_pass);
 	m = g_list_append(m, act);
 
-	if (od->sess->authinfo->chpassurl != NULL)
+	if (od->authinfo->chpassurl != NULL)
 	{
 		act = gaim_plugin_action_new(_("Change Password (URL)"),
 				oscar_show_chpassurl);
@@ -8526,11 +6190,11 @@
 				oscar_confirm_account);
 		m = g_list_append(m, act);
 
-		act = gaim_plugin_action_new(_("Display Currently Registered Address"),
+		act = gaim_plugin_action_new(_("Display Currently Registered E-Mail Address"),
 				oscar_show_email);
 		m = g_list_append(m, act);
 
-		act = gaim_plugin_action_new(_("Change Currently Registered Address..."),
+		act = gaim_plugin_action_new(_("Change Currently Registered E-Mail Address..."),
 				oscar_show_change_email);
 		m = g_list_append(m, act);
 	}
@@ -8543,7 +6207,7 @@
 
 	m = g_list_append(m, NULL);
 
-	act = gaim_plugin_action_new(_("Search for Buddy by E-Mail..."),
+	act = gaim_plugin_action_new(_("Search for Buddy by E-Mail Address..."),
 			oscar_show_find_email);
 	m = g_list_append(m, act);
 
@@ -8561,29 +6225,37 @@
 	OscarData *od = gc->proto_data;
 
 	if (od->icq) {
-		aim_icq_changepasswd(od->sess, new);
+		aim_icq_changepasswd(od, new);
 	} else {
-		OscarConnection *conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH);
+		FlapConnection *conn;
+		conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
 		if (conn) {
-			aim_admin_changepasswd(od->sess, conn, new, old);
+			aim_admin_changepasswd(od, conn, new, old);
 		} else {
 			od->chpass = TRUE;
 			od->oldp = g_strdup(old);
 			od->newp = g_strdup(new);
-			aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_AUTH);
+			aim_reqservice(od, SNAC_FAMILY_ADMIN);
 		}
 	}
 }
 
-static void oscar_convo_closed(GaimConnection *gc, const char *who)
+static void
+oscar_convo_closed(GaimConnection *gc, const char *who)
 {
-	OscarData *od = gc->proto_data;
-	struct oscar_direct_im *dim = oscar_direct_im_find(od, who);
-
-	if (!dim)
-		return;
-
-	oscar_direct_im_destroy(od, dim);
+	OscarData *od;
+	PeerConnection *conn;
+
+	od = gc->proto_data;
+	conn = peer_connection_find_by_type(od, who, OSCAR_CAPABILITY_DIRECTIM);
+
+	if (conn != NULL)
+	{
+		if (!conn->ready)
+			aim_im_sendch2_cancel(conn);
+
+		peer_connection_destroy(conn, PEER_DISCONNECT_LOCAL_CLOSED);
+	}
 }
 
 static void
@@ -8592,19 +6264,26 @@
 {
 	GaimConnection *gc = data;
 	OscarData *od = gc->proto_data;
-	OscarSession *sess = od->sess;
 	guint32 presence;
 
-	presence = aim_ssi_getpresence(sess->ssi.local);
+	presence = aim_ssi_getpresence(od->ssi.local);
 
 	if (value) {
 		presence &= ~AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES;
-		aim_ssi_setpresence(sess, presence);
+		aim_ssi_setpresence(od, presence);
 	} else {
 		presence |= AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES;
-		aim_ssi_setpresence(sess, presence);
-	}
-}
+		aim_ssi_setpresence(od, presence);
+	}
+}
+
+#ifdef USE_PRPL_PREFERENCES
+	ppref = gaim_plugin_pref_new_with_name_and_label("/plugins/prpl/oscar/recent_buddies", _("Use recent buddies group"));
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_name_and_label("/plugins/prpl/oscar/show_idle", _("Show how long you have been idle"));
+	gaim_plugin_pref_frame_add(frame, ppref);
+#endif
 
 static const char *
 oscar_normalize(const GaimAccount *account, const char *str)
@@ -8633,7 +6312,8 @@
 	return buf;
 }
 
-static gboolean oscar_offline_message(const GaimBuddy *buddy)
+static gboolean
+oscar_offline_message(const GaimBuddy *buddy)
 {
 	OscarData *od;
 	GaimAccount *account;
@@ -8756,8 +6436,9 @@
 	option = gaim_account_option_string_new(_("Encoding"), "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
+	/* TODO: Need to somehow invert this */
 	option = gaim_account_option_bool_new(
-		_("Use AIM/ICQ proxy server\n(slower, but usually works)"), "use_rv_proxy",
+		_("Always use AIM/ICQ proxy server\n(slower, but does not reveal your IP address)"), "use_rv_proxy",
 		OSCAR_DEFAULT_USE_RV_PROXY);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
@@ -8765,7 +6446,6 @@
 	gaim_prefs_add_none("/plugins/prpl/oscar");
 	gaim_prefs_add_bool("/plugins/prpl/oscar/recent_buddies", FALSE);
 	gaim_prefs_add_bool("/plugins/prpl/oscar/show_idle", FALSE);
-
 	gaim_prefs_remove("/plugins/prpl/oscar/use_rv_proxy");
 }
 
--- a/src/protocols/oscar/oscar.h	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/oscar.h	Fri Apr 07 05:10:56 2006 +0000
@@ -30,6 +30,7 @@
 #define _OSCAR_H_
 
 #include "debug.h"
+#include "eventloop.h"
 #include "gaim_buffer.h"
 #include "internal.h"
 
@@ -56,41 +57,19 @@
 typedef struct _ClientInfo         ClientInfo;
 typedef struct _FlapFrame          FlapFrame;
 typedef struct _IcbmCookie         IcbmCookie;
-typedef struct _OscarConnection    OscarConnection;
-typedef struct _OscarSession       OscarSession;
+typedef struct _FlapConnection     FlapConnection;
+typedef struct _OscarData          OscarData;
+typedef struct _IcbmArgsCh2        IcbmArgsCh2;
 
 typedef guint32 aim_snacid_t;
 typedef guint16 flap_seqnum_t;
 
-#include "peer.h"
 #include "snactypes.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define WIN32_STATIC
-#if defined(_WIN32) && !defined(WIN32_STATIC)
-/*
- * For a win32 DLL, we define WIN32_INDLL if this file
- * is included while compiling the DLL. If it's not
- * defined (it's included in a client app), the symbols
- * will be imported instead of exported.
- */
-#ifdef WIN32_INDLL
-#define faim_export __declspec(dllexport)
-#else
-#define faim_export __declspec(dllimport)
-#endif /* WIN32_INDLL */
-#define faim_internal
-#else
-/*
- * Nothing normally needed for unix...
- */
-#define faim_export
-#define faim_internal
-#endif
-
 #define FAIM_SNAC_HASH_SIZE 16
 
 /*
@@ -113,7 +92,7 @@
  * send any more than 1kb.  Amaze all your windows friends
  * with utterly oversized instant messages!
  *
- * XXX: the real limit is the total SNAC size at 8192. Fix this.
+ * TODO: the real limit is the total SNAC size at 8192. Fix this.
  *
  */
 #define MAXMSGLEN 7987
@@ -306,103 +285,38 @@
 #define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_5_1_3036
 #define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQ_5_45_3777
 
-/*
- * These could be arbitrary, but its easier to use the actual AIM values
- */
-#define AIM_CONN_TYPE_BOS		0x0002
-#define AIM_CONN_TYPE_ADS		0x0005
-#define AIM_CONN_TYPE_AUTH		0x0007
-#define AIM_CONN_TYPE_CHATNAV	0x000d
-#define AIM_CONN_TYPE_CHAT		0x000e
-#define AIM_CONN_TYPE_SEARCH	0x000f
-#define AIM_CONN_TYPE_ICON		0x0010
-#define AIM_CONN_TYPE_EMAIL		0x0018
-
-/* they start getting arbitrary for rendezvous stuff =) */
-#define AIM_CONN_TYPE_RENDEZVOUS_PROXY	0xfffd /* these speak a strange language */
-#define AIM_CONN_TYPE_RENDEZVOUS	0xfffe /* these do not speak FLAP! */
-#define AIM_CONN_TYPE_LISTENER		0xffff /* socket waiting for accept() */
-
-/* Command types for doing a rendezvous proxy login
- * Thanks to Keith Lea and the Joust project for documenting these commands well */
-#define AIM_RV_PROXY_PACKETVER_DFLT	0x044a
-#define AIM_RV_PROXY_ERROR		0x0001
-#define AIM_RV_PROXY_INIT_SEND		0x0002 /* First command sent when creating a connection */
-#define AIM_RV_PROXY_INIT_RECV		0x0004 /* First command sent when receiving existing connection */
-#define AIM_RV_PROXY_ACK		0x0003
-#define AIM_RV_PROXY_READY		0x0005
-
-/* Number of bytes expected in each of the above packets, including the 2 bytes specifying length */
-#define AIM_RV_PROXY_ERROR_LEN		14
-#define AIM_RV_PROXY_INIT_SEND_LEN	55
-#define AIM_RV_PROXY_INIT_RECV_LEN	57
-#define AIM_RV_PROXY_ACK_LEN		18
-#define AIM_RV_PROXY_READY_LEN		12
-#define AIM_RV_PROXY_HDR_LEN		12	/* Bytes in just the header alone */
-
-/* Default values for unknown/unused values in rendezvous proxy negotiation packets */
-#define AIM_RV_PROXY_SERVER_FLAGS	0x0220		/* Default flags sent by proxy server */
-#define AIM_RV_PROXY_CLIENT_FLAGS	0x0000		/* Default flags sent by client */
-#define AIM_RV_PROXY_UNKNOWNA_DFLT	0x00000000	/* Default value for an unknown block */
-#define AIM_RV_PROXY_SERVER_URL		"ars.oscar.aol.com"
-#define AIM_RV_PROXY_CONNECT_PORT	5190		/* The port we should always connect to */
-
-/* What is the purpose of this transfer? (Who will end up with a new file?)
- * These values are used in peer_connection->send_or_recv */
-#define AIM_XFER_SEND			0x0001
-#define AIM_XFER_RECV			0x0002
-
-/* Via what method is the data getting routed?
- * These values are used in peer_connection->method */
-#define AIM_XFER_DIRECT			0x0001	/* Direct connection; receiver connects to sender */
-#define AIM_XFER_REDIR			0x0002	/* Redirected connection; sender connects to receiver */
-#define AIM_XFER_PROXY			0x0003	/* Proxied connection */
-
-/* Who requested the proxy?
- * The difference between a stage 2 and stage 3 proxied transfer is that the receiver does the
- * initial login for a stage 2, but the sender must do it for a stage 3.
- * These values are used in peer_connection->stage */
-#define AIM_XFER_PROXY_NONE		0x0001
-#define AIM_XFER_PROXY_STG1		0x0002	/* Sender requested a proxy be used (stage1) */
-#define AIM_XFER_PROXY_STG2		0x0003	/* Receiver requested a proxy be used (stage2) */
-#define AIM_XFER_PROXY_STG3		0x0004	/* Receiver requested a proxy be used (stage3) */
-
-/*
- * Subtypes, we need these for OFT stuff.
- */
-#define AIM_CONN_SUBTYPE_OFT_DIRECTIM	0x0001
-#define AIM_CONN_SUBTYPE_OFT_GETFILE	0x0002
-#define AIM_CONN_SUBTYPE_OFT_SENDFILE	0x0003
-#define AIM_CONN_SUBTYPE_OFT_BUDDYICON	0x0004
-#define AIM_CONN_SUBTYPE_OFT_VOICE	0x0005
-
-/*
- * Status values returned from aim_conn_new().  ORed together.
- */
-#define AIM_CONN_STATUS_READY		0x0001
-#define AIM_CONN_STATUS_INTERNALERR	0x0002
-#define AIM_CONN_STATUS_RESOLVERR	0x0040
-#define AIM_CONN_STATUS_CONNERR		0x0080
-#define AIM_CONN_STATUS_INPROGRESS	0x0100
-
-#define AIM_FRAMETYPE_FLAP		0x0000
-#define AIM_FRAMETYPE_OFT		0x0001
-
-struct _OscarConnection
+typedef enum
 {
-	int fd;
-	GaimCircBuffer *buffer_outgoing;
-	guint16 type;
-	guint16 subtype;
-	flap_seqnum_t seqnum;
-	guint32 status;
-	void *internal; /* internal conn-specific libfaim data */
-	time_t lastactivity; /* time of last transmit */
-	void *handlerlist;
-	OscarSession *sessv; /* pointer to parent session */
-	void *inside; /* only accessible from inside libfaim */
-	struct _OscarConnection *next;
-};
+	OSCAR_CAPABILITY_BUDDYICON            = 0x00000001,
+	OSCAR_CAPABILITY_TALK                 = 0x00000002,
+	OSCAR_CAPABILITY_DIRECTIM             = 0x00000004,
+	OSCAR_CAPABILITY_CHAT                 = 0x00000008,
+	OSCAR_CAPABILITY_GETFILE              = 0x00000010,
+	OSCAR_CAPABILITY_SENDFILE             = 0x00000020,
+	OSCAR_CAPABILITY_GAMES                = 0x00000040,
+	OSCAR_CAPABILITY_ADDINS               = 0x00000080,
+	OSCAR_CAPABILITY_SENDBUDDYLIST        = 0x00000100,
+	OSCAR_CAPABILITY_GAMES2               = 0x00000200,
+	OSCAR_CAPABILITY_ICQ_DIRECT           = 0x00000400,
+	OSCAR_CAPABILITY_APINFO               = 0x00000800,
+	OSCAR_CAPABILITY_ICQRTF               = 0x00001000,
+	OSCAR_CAPABILITY_EMPTY                = 0x00002000,
+	OSCAR_CAPABILITY_ICQSERVERRELAY       = 0x00004000,
+	OSCAR_CAPABILITY_ICQUTF8OLD           = 0x00008000,
+	OSCAR_CAPABILITY_TRILLIANCRYPT        = 0x00010000,
+	OSCAR_CAPABILITY_ICQUTF8              = 0x00020000,
+	OSCAR_CAPABILITY_INTEROPERATE         = 0x00040000,
+	OSCAR_CAPABILITY_ICHAT                = 0x00080000,
+	OSCAR_CAPABILITY_HIPTOP               = 0x00100000,
+	OSCAR_CAPABILITY_SECUREIM             = 0x00200000,
+	OSCAR_CAPABILITY_SMS                  = 0x00400000,
+	OSCAR_CAPABILITY_GENERICUNKNOWN       = 0x00800000,
+	OSCAR_CAPABILITY_VIDEO                = 0x01000000,
+	OSCAR_CAPABILITY_ICHATAV              = 0x02000000,
+	OSCAR_CAPABILITY_LIVEVIDEO            = 0x04000000,
+	OSCAR_CAPABILITY_CAMERA               = 0x08000000,
+	OSCAR_CAPABILITY_LAST                 = 0x10000000
+} OscarCapability;
 
 /*
  * Byte Stream type. Sort of.
@@ -427,22 +341,30 @@
 
 struct _FlapFrame
 {
-	guint8 hdrtype; /* defines which piece of the union to use */
-	union {
-		struct {
-			guint8 channel;
-			flap_seqnum_t seqnum;
-		} flap;
-		struct {
-			guint8 magic[4];	/* ODC2 or OFT2 */
-			guint16 hdrlen;
-			guint16 type;
-		} rend;
-	} hdr;
-	ByteStream data;		/* payload stream */
-	OscarConnection *conn;		/* the connection it came in on/is going out on */
-	guint8 handled;			/* 0 = new, !0 = been handled */
-	struct _FlapFrame *next;
+	guint8 channel;
+	flap_seqnum_t seqnum;
+	ByteStream data;        /* payload stream */
+};
+
+struct _FlapConnection
+{
+	OscarData *od;              /**< Pointer to parent session. */
+	int fd;
+	time_t lastactivity;             /**< Time of last transmit. */
+	gboolean connected;
+	guint destroy_timeout;
+
+	FlapFrame buffer_incoming;
+	GaimCircBuffer *buffer_outgoing;
+	guint watcher_incoming;
+	guint watcher_outgoing;
+
+	guint16 type;
+	guint16 subtype;
+	flap_seqnum_t seqnum;
+	guint32 status;
+	void *internal; /* internal conn-specific libfaim data */
+	void *inside; /* only accessible from inside libfaim */
 };
 
 struct _IcbmCookie
@@ -454,67 +376,76 @@
 	struct _IcbmCookie *next;
 };
 
+#include "peer.h"
+
 /*
  * AIM Session: The main client-data interface.
  *
  */
-struct _OscarSession
+struct _OscarData
 {
+	gboolean iconconnecting;
+	gboolean set_icon;
+
+	GSList *create_rooms;
+
+	gboolean conf;
+	gboolean reqemail;
+	gboolean setemail;
+	char *email;
+	gboolean setnick;
+	char *newsn;
+	gboolean chpass;
+	char *oldp;
+	char *newp;
+
+	GSList *oscar_chats;
+	GHashTable *buddyinfo;
+	GSList *requesticon;
+
+	gboolean killme;
+	gboolean icq;
+	guint icontimer;
+	guint getblisttimer;
+	guint getinfotimer;
+	gint timeoffset;
+
+	struct {
+		guint maxwatchers; /* max users who can watch you */
+		guint maxbuddies; /* max users you can watch */
+		guint maxgroups; /* max groups in server list */
+		guint maxpermits; /* max users on permit list */
+		guint maxdenies; /* max users on deny list */
+		guint maxsiglen; /* max size (bytes) of profile */
+		guint maxawaymsglen; /* max size (bytes) of posted away message */
+	} rights;
 
 	/* ---- Client Accessible ------------------------ */
 
 	/* Our screen name. */
+	/* TODO: Get rid of this and use gaim_account_get_username() everywhere? */
 	char sn[MAXSNLEN+1];
 
-	/*
-	 * Pointer to anything the client wants to
-	 * explicitly associate with this session.
-	 *
-	 * This is for use in the callbacks mainly. In any
-	 * callback, you can access this with sess->aux_data.
-	 *
-	 */
-	void *aux_data;
+	GaimConnection *gc;
 
 	/* ---- Internal Use Only ------------------------ */
 
-	/*
-	 * Transmit/receive queues.
-	 *
-	 * These are only used when you don't use your own lowlevel
-	 * I/O.  I don't suggest that you use libfaim's internal I/O.
-	 * Its really bad and the API/event model is quirky at best.
-	 *
-	 */
-	FlapFrame *queue_outgoing;
-	FlapFrame *queue_incoming;
-
-	/*
-	 * Tx Enqueuing function.
-	 *
-	 * This is how you override the transmit direction of libfaim's
-	 * internal I/O.  This function will be called whenever it needs
-	 * to send something.
-	 *
-	 */
-	int (*tx_enqueue)(OscarSession *, FlapFrame *);
-
 	void *modlistv;
 
-	struct {
-		char server[128];
-		char username[128];
-		char password[128];
-	} socksproxy;
-
 	/*
 	 * Outstanding snac handling
 	 *
-	 * XXX: Should these be per-connection? -mid
+	 * TODO: Should these be per-connection? -mid
 	 */
 	void *snac_hash[FAIM_SNAC_HASH_SIZE];
 	aim_snacid_t snacid_next;
 
+	/*
+	 * TODO: Data specific to a certain family should go into a
+	 *       hashtable and the core parts of libfaim shouldn't
+	 *       need to know about them.
+	 */
+
 	IcbmCookie *msgcookies;
 	struct aim_icq_info *icq_info;
 	struct aim_authresp_info *authinfo;
@@ -538,7 +469,10 @@
 		int waiting_for_ack;
 	} ssi;
 
-	/** A linked list containing OscarConnections. */
+	/* TODO: Implement this as a HashTable for HUGE speed improvement! */
+	GList *handlerlist;
+
+	/** A linked list containing FlapConnections. */
 	GList *oscar_connections;
 
 	/** A linked list containing PeerConnections. */
@@ -546,40 +480,22 @@
 };
 
 /* Valid for calling aim_icq_setstatus() and for aim_userinfo_t->icqinfo.status */
-#define AIM_ICQ_STATE_NORMAL		0x00000000
-#define AIM_ICQ_STATE_AWAY		0x00000001
-#define AIM_ICQ_STATE_DND		0x00000002
-#define AIM_ICQ_STATE_OUT		0x00000004
-#define AIM_ICQ_STATE_BUSY		0x00000010
-#define AIM_ICQ_STATE_CHAT		0x00000020
-#define AIM_ICQ_STATE_INVISIBLE		0x00000100
-#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
+#define AIM_ICQ_STATE_NORMAL            0x00000000
+#define AIM_ICQ_STATE_AWAY              0x00000001
+#define AIM_ICQ_STATE_DND               0x00000002
+#define AIM_ICQ_STATE_OUT               0x00000004
+#define AIM_ICQ_STATE_BUSY              0x00000010
+#define AIM_ICQ_STATE_CHAT              0x00000020
+#define AIM_ICQ_STATE_INVISIBLE         0x00000100
+#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
 
-/*
- * Get command from connections
- *
- * aim_get_commmand() is the libfaim lowlevel I/O in the receive direction.
- * XXX Make this easily overridable.
- *
- */
-faim_export int aim_get_command(OscarSession *, OscarConnection *);
-
-/*
- * Dispatch commands that are in the rx queue.
- */
-faim_export void aim_rxdispatch(OscarSession *);
-
-faim_export int aim_debugconn_sendconnect(OscarSession *sess, OscarConnection *conn);
-
-void oscar_connection_destroy(OscarSession *sess, OscarConnection *deadconn);
-
-typedef int (*aim_rxcallback_t)(OscarSession *, FlapFrame *, ...);
+typedef int (*aim_rxcallback_t)(OscarData *od, FlapConnection *conn, FlapFrame *frame, ...);
 
 
 /* family_auth.c */
@@ -613,50 +529,47 @@
 	const char *ip;
 	guint16 cookielen;
 	const guint8 *cookie;
-	struct { /* group == AIM_CONN_TYPE_CHAT */
+	struct { /* group == SNAC_FAMILY_CHAT */
 		guint16 exchange;
 		const char *room;
 		guint16 instance;
 	} chat;
 };
 
-faim_export int aim_clientready(OscarSession *sess, OscarConnection *conn);
-faim_export int aim_sendflapver(OscarSession *sess, OscarConnection *conn);
-faim_export int aim_request_login(OscarSession *sess, OscarConnection *conn, const char *sn);
-faim_export int aim_send_login(OscarSession *, OscarConnection *, const char *, const char *, ClientInfo *, const char *key);
-/* 0x000b */ faim_export int aim_auth_securid_send(OscarSession *sess, const char *securid);
+int aim_clientready(OscarData *od, FlapConnection *conn);
+int aim_request_login(OscarData *od, FlapConnection *conn, const char *sn);
+int aim_send_login(OscarData *, FlapConnection *, const char *, const char *, ClientInfo *, const char *key);
+/* 0x000b */ int aim_auth_securid_send(OscarData *od, const char *securid);
 
-faim_export void aim_purge_rxqueue(OscarSession *);
-faim_export void aim_cleansnacs(OscarSession *, int maxage);
+void aim_cleansnacs(OscarData *, int maxage);
 
-#define AIM_TX_QUEUED    0 /* default */
-#define AIM_TX_IMMEDIATE 1
-faim_export int aim_tx_setenqueue(OscarSession *sess, int what, int (*func)(OscarSession *, FlapFrame *));
-
-faim_export int aim_tx_flushqueue(OscarSession *);
+int oscar_data_addhandler(OscarData *od, guint16 family, guint16 type, aim_rxcallback_t newhandler, guint16 flags);
+void aim_clearhandlers(OscarData *od);
 
-faim_export int aim_conn_addhandler(OscarSession *, OscarConnection *conn, guint16 family, guint16 type, aim_rxcallback_t newhandler, guint16 flags);
-faim_export int aim_clearhandlers(OscarConnection *conn);
+/* flap_connection.c */
+FlapConnection *flap_connection_new(OscarData *, int type);
+void flap_connection_addgroup(FlapConnection *conn, guint16 group);
+void flap_connection_close(OscarData *od, FlapConnection *conn);
+void flap_connection_destroy(FlapConnection *conn);
+void flap_connection_schedule_destroy(FlapConnection *conn);
+FlapConnection *flap_connection_findbygroup(OscarData *od, guint16 group);
+FlapConnection *flap_connection_getbytype(OscarData *, int type);
+FlapConnection *flap_connection_getbytype_all(OscarData *, int type);
+void flap_connection_recv_cb(gpointer data, gint source, GaimInputCondition cond);
+FlapConnection *flap_connection_clone(OscarData *od, FlapConnection *src);
+void flap_connection_send(FlapConnection *conn, FlapFrame *frame);
+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_keepalive(OscarData *od, FlapConnection *conn);
+FlapFrame *flap_frame_new(OscarData *od, guint16 channel, int datalen);
 
-faim_export OscarConnection *aim_conn_findbygroup(OscarSession *sess, guint16 group);
-faim_export OscarSession *aim_conn_getsess(OscarConnection *conn);
-void oscar_connection_destroy(OscarSession *sess, OscarConnection *conn);
-faim_export void aim_conn_close(OscarSession *sess, OscarConnection *conn);
-faim_export OscarConnection *oscar_connection_new(OscarSession *, int type);
-faim_export int aim_conn_isready(OscarConnection *);
-faim_export int aim_conn_setstatus(OscarConnection *, int);
-faim_export int aim_conn_completeconnect(OscarSession *sess, OscarConnection *conn);
-faim_export int aim_conn_isconnecting(OscarConnection *conn);
 
-OscarSession *oscar_session_new(void);
-void oscar_session_destroy(OscarSession *);
-
-faim_export OscarConnection *aim_getconn_type(OscarSession *, int type);
-faim_export OscarConnection *aim_getconn_type_all(OscarSession *, int type);
+OscarData *oscar_data_new(void);
+void oscar_data_destroy(OscarData *);
 
 /* 0x0001 - family_oservice.c */
-faim_export int aim_srv_setstatusmsg(OscarSession *sess, const char *msg);
-faim_export int aim_srv_setidle(OscarSession *sess, guint32 idletime);
+int aim_srv_setstatusmsg(OscarData *od, const char *msg);
+int aim_srv_setidle(OscarData *od, guint32 idletime);
 
 /* misc.c */
 
@@ -670,29 +583,28 @@
 
 #define AIM_WARN_ANON                     0x01
 
-faim_export int aim_sendpauseack(OscarSession *sess, OscarConnection *conn);
-faim_export int aim_nop(OscarSession *, OscarConnection *);
-faim_export int aim_flap_nop(OscarSession *sess, OscarConnection *conn);
-faim_export int aim_bos_changevisibility(OscarSession *, OscarConnection *, int, const char *);
-faim_export int aim_bos_setgroupperm(OscarSession *, OscarConnection *, guint32 mask);
-faim_export int aim_bos_setprivacyflags(OscarSession *, OscarConnection *, guint32);
-faim_export int aim_reqpersonalinfo(OscarSession *, OscarConnection *);
-faim_export int aim_reqservice(OscarSession *, OscarConnection *, guint16);
-faim_export int aim_bos_reqrights(OscarSession *, OscarConnection *);
-faim_export int aim_setextstatus(OscarSession *sess, guint32 status);
+int aim_sendpauseack(OscarData *od, FlapConnection *conn);
+int aim_nop(OscarData *, FlapConnection *);
+int aim_bos_changevisibility(OscarData *, FlapConnection *, int, const char *);
+int aim_bos_setgroupperm(OscarData *, FlapConnection *, guint32 mask);
+int aim_bos_setprivacyflags(OscarData *, FlapConnection *, guint32);
+int aim_reqpersonalinfo(OscarData *, FlapConnection *);
+int aim_reqservice(OscarData *, guint16);
+int aim_bos_reqrights(OscarData *, FlapConnection *);
+int aim_setextstatus(OscarData *od, guint32 status);
 
 #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
-faim_export guint16 aim_im_fingerprint(const guint8 *msghdr, int len);
+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
-faim_export int aim_ads_requestads(OscarSession *sess, OscarConnection *conn);
+int aim_ads_requestads(OscarData *od, FlapConnection *conn);
 
 
 
@@ -778,11 +690,11 @@
 	aim_mpmsg_section_t *parts;
 } aim_mpmsg_t;
 
-faim_export int aim_mpmsg_init(OscarSession *sess, aim_mpmsg_t *mpm);
-faim_export int aim_mpmsg_addraw(OscarSession *sess, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, const gchar *data, guint16 datalen);
-faim_export int aim_mpmsg_addascii(OscarSession *sess, aim_mpmsg_t *mpm, const char *ascii);
-faim_export int aim_mpmsg_addunicode(OscarSession *sess, aim_mpmsg_t *mpm, const guint16 *unicode, guint16 unicodelen);
-faim_export void aim_mpmsg_free(OscarSession *sess, aim_mpmsg_t *mpm);
+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().
@@ -872,24 +784,26 @@
 };
 
 /* Valid values for channel 2 args->status */
-#define AIM_RENDEZVOUS_PROPOSE	0x0000
-#define AIM_RENDEZVOUS_CANCEL	0x0001
-#define AIM_RENDEZVOUS_ACCEPT	0x0002
+#define AIM_RENDEZVOUS_PROPOSE   0x0000
+#define AIM_RENDEZVOUS_CANCEL    0x0001
+#define AIM_RENDEZVOUS_CONNECTED 0x0002
 
-struct aim_incomingim_ch2_args
+struct _IcbmArgsCh2
 {
 	guint16 status;
 	guchar cookie[8];
-	int reqclass;
+	int type; /* One of the OSCAR_CAPABILITY_ constants */
 	const char *proxyip;
 	const char *clientip;
 	const char *verifiedip;
 	guint16 port;
+	gboolean use_proxy;
 	guint16 errorcode;
 	const char *msg; /* invite message or file description */
 	guint16 msglen;
 	const char *encoding;
 	const char *language;
+	guint16 requestnumber;
 	union {
 		struct {
 			guint32 checksum;
@@ -911,9 +825,6 @@
 			guint16 totfiles;
 			guint32 totsize;
 			char *filename;
-			/* reqnum: 0x0001 usually; 0x0002 = reply request for stage 2 proxy transfer */
-			guint16 reqnum;
-			guint8 use_proxy; /* Did the user request that we use a rv proxy? */
 		} sendfile;
 	} info;
 	void *destructor; /* used internally only */
@@ -934,43 +845,49 @@
 };
 
 /* SNAC sending functions */
-/* 0x0002 */ faim_export int aim_im_setparams(OscarSession *sess, struct aim_icbmparameters *params);
-/* 0x0004 */ faim_export int aim_im_reqparams(OscarSession *sess);
-/* 0x0006 */ faim_export int aim_im_sendch1_ext(OscarSession *sess, struct aim_sendimext_args *args);
-/* 0x0006 */ faim_export int aim_im_sendch1(OscarSession *, const char *destsn, guint16 flags, const char *msg);
-/* 0x0006 */ faim_export int aim_im_sendch2_chatinvite(OscarSession *sess, const char *sn, const char *msg, guint16 exchange, const char *roomname, guint16 instance);
-/* 0x0006 */ faim_export int aim_im_sendch2_icon(OscarSession *sess, const char *sn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum);
-/* 0x0006 */ faim_export int aim_im_sendch2_rtfmsg(OscarSession *sess, struct aim_sendrtfmsg_args *args);
-/* 0x0006 */ faim_export int aim_im_sendch2_odcrequest(OscarSession *sess, guchar *cookie, gboolean usecookie, const char *sn, const guint8 *ip, guint16 port);
-/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_ask(OscarSession *sess, PeerConnection *peer_connection);
-/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_accept(OscarSession *sess, PeerConnection *info);
-/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_cancel(OscarSession *sess, PeerConnection *peer_connection);
-/* 0x0006 */ faim_export int aim_im_sendch2_geticqaway(OscarSession *sess, const char *sn, int type);
-/* 0x0006 */ faim_export int aim_im_sendch4(OscarSession *sess, const char *sn, guint16 type, const char *message);
-/* 0x0008 */ faim_export int aim_im_warn(OscarSession *sess, OscarConnection *conn, const char *destsn, guint32 flags);
-/* 0x000b */ faim_export int aim_im_denytransfer(OscarSession *sess, const char *sender, const guchar *cookie, guint16 code);
-/* 0x0014 */ faim_export int aim_im_sendmtn(OscarSession *sess, guint16 type1, const char *sn, guint16 type2);
-faim_export void aim_icbm_makecookie(guchar* cookie);
+/* 0x0002 */ int aim_im_setparams(OscarData *od, struct aim_icbmparameters *params);
+/* 0x0004 */ int aim_im_reqparams(OscarData *od);
+/* 0x0006 */ int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args);
+/* 0x0006 */ int aim_im_sendch1(OscarData *, const char *destsn, guint16 flags, const char *msg);
+/* 0x0006 */ int aim_im_sendch2_chatinvite(OscarData *od, const char *sn, const char *msg, guint16 exchange, const char *roomname, guint16 instance);
+/* 0x0006 */ int aim_im_sendch2_icon(OscarData *od, const char *sn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum);
+/* 0x0006 */ int aim_im_sendch2_rtfmsg(OscarData *od, struct aim_sendrtfmsg_args *args);
+
+/* 0x0006 */ void aim_im_sendch2_cancel(PeerConnection *peer_conn);
+/* 0x0006 */ void aim_im_sendch2_connected(PeerConnection *peer_conn);
+/* 0x0006 */ void aim_im_sendch2_odc_requestdirect(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 port, guint16 requestnumber);
+/* 0x0006 */ void aim_im_sendch2_odc_requestproxy(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 pin, guint16 requestnumber);
+/* 0x0006 */ void aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles);
+/* 0x0006 */ void aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles);
+
+/* 0x0006 */ int aim_im_sendch2_geticqaway(OscarData *od, const char *sn, int type);
+/* 0x0006 */ int aim_im_sendch4(OscarData *od, const char *sn, guint16 type, const char *message);
+/* 0x0008 */ int aim_im_warn(OscarData *od, FlapConnection *conn, const char *destsn, guint32 flags);
+/* 0x000b */ int aim_im_denytransfer(OscarData *od, const char *sn, const guchar *cookie, guint16 code);
+/* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 type1, const char *sn, guint16 type2);
+void aim_icbm_makecookie(guchar* cookie);
+gchar *oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen);
+gchar *gaim_plugin_oscar_decode_im_part(GaimAccount *account, const char *sourcesn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen);
 
 
 /* 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_UNKNOWN200		0x0200
-#define AIM_FLAG_ACTIVEBUDDY	0x0400
-#define AIM_FLAG_UNKNOWN800		0x0800
-#define AIM_FLAG_ABINTERNAL		0x1000
-#define AIM_FLAG_ALLUSERS		0x001f
+#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_UNKNOWN200      0x0200
+#define AIM_FLAG_ACTIVEBUDDY     0x0400
+#define AIM_FLAG_UNKNOWN800      0x0800
+#define AIM_FLAG_ABINTERNAL      0x1000
+#define AIM_FLAG_ALLUSERS        0x001f
 
 #define AIM_USERINFO_PRESENT_FLAGS        0x00000001
 #define AIM_USERINFO_PRESENT_MEMBERSINCE  0x00000002
@@ -1026,40 +943,10 @@
 	struct aim_userinfo_s *next;
 } aim_userinfo_t;
 
-#define AIM_CAPS_BUDDYICON		0x00000001
-#define AIM_CAPS_TALK			0x00000002
-#define AIM_CAPS_DIRECTIM		0x00000004
-#define AIM_CAPS_CHAT			0x00000008
-#define AIM_CAPS_GETFILE		0x00000010
-#define AIM_CAPS_SENDFILE		0x00000020
-#define AIM_CAPS_GAMES			0x00000040
-#define AIM_CAPS_ADDINS			0x00000080
-#define AIM_CAPS_SENDBUDDYLIST	0x00000100
-#define AIM_CAPS_GAMES2			0x00000200
-#define AIM_CAPS_ICQ_DIRECT		0x00000400
-#define AIM_CAPS_APINFO			0x00000800
-#define AIM_CAPS_ICQRTF			0x00001000
-#define AIM_CAPS_EMPTY			0x00002000
-#define AIM_CAPS_ICQSERVERRELAY	0x00004000
-#define AIM_CAPS_ICQUTF8OLD		0x00008000
-#define AIM_CAPS_TRILLIANCRYPT	0x00010000
-#define AIM_CAPS_ICQUTF8		0x00020000
-#define AIM_CAPS_INTEROPERATE	0x00040000
-#define AIM_CAPS_ICHAT			0x00080000
-#define AIM_CAPS_HIPTOP			0x00100000
-#define AIM_CAPS_SECUREIM		0x00200000
-#define AIM_CAPS_SMS			0x00400000
-#define AIM_CAPS_GENERICUNKNOWN	0x00800000
-#define AIM_CAPS_VIDEO			0x01000000
-#define AIM_CAPS_ICHATAV		0x02000000
-#define AIM_CAPS_LIVEVIDEO		0x04000000
-#define AIM_CAPS_CAMERA			0x08000000
-#define AIM_CAPS_LAST			0x10000000
-
 #define AIM_SENDMEMBLOCK_FLAG_ISREQUEST  0
 #define AIM_SENDMEMBLOCK_FLAG_ISHASH     1
 
-faim_export int aim_sendmemblock(OscarSession *sess, OscarConnection *conn, guint32 offset, guint32 len, const guint8 *buf, guint8 flag);
+int aim_sendmemblock(OscarData *od, FlapConnection *conn, guint32 offset, guint32 len, const guint8 *buf, guint8 flag);
 
 struct aim_invite_priv
 {
@@ -1086,32 +973,37 @@
 #define AIM_COOKIETYPE_OFTIMAGE 0x14
 #define AIM_COOKIETYPE_OFTICON  0x15
 
-faim_export aim_userinfo_t *aim_locate_finduserinfo(OscarSession *sess, const char *sn);
-faim_export void aim_locate_dorequest(OscarSession *sess);
+aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *sn);
+void aim_locate_dorequest(OscarData *od);
 
-/* 0x0002 */ faim_export int aim_locate_reqrights(OscarSession *sess);
-/* 0x0004 */ faim_export int aim_locate_setcaps(OscarSession *sess, guint32 caps);
-/* 0x0004 */ faim_export int aim_locate_setprofile(OscarSession *sess, const char *profile_encoding, const gchar *profile, const int profile_len, const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len);
-/* 0x0005 */ faim_export int aim_locate_getinfo(OscarSession *sess, const char *, guint16);
-/* 0x0009 */ faim_export int aim_locate_setdirinfo(OscarSession *sess, 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 */ faim_export int aim_locate_000b(OscarSession *sess, const char *sn);
-/* 0x000f */ faim_export int aim_locate_setinterests(OscarSession *sess, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy);
-/* 0x0015 */ faim_export int aim_locate_getinfoshort(OscarSession *sess, const char *sn, guint32 flags);
+/* 0x0002 */ int aim_locate_reqrights(OscarData *od);
+/* 0x0004 */ int aim_locate_setcaps(OscarData *od, guint32 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 *sn);
+/* 0x000f */ int aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy);
+/* 0x0015 */ int aim_locate_getinfoshort(OscarData *od, const char *sn, guint32 flags);
+
+void aim_locate_requestuserinfo(OscarData *od, const char *sn);
+guint32 aim_locate_getcaps(OscarData *od, ByteStream *bs, int len);
+guint32 aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len);
+void aim_info_free(aim_userinfo_t *);
+int aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *);
+int aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info);
 
 
 
 /* 0x0003 - family_buddy.c */
-/* 0x0002 */ faim_export int aim_buddylist_reqrights(OscarSession *, OscarConnection *);
-/* 0x0004 */ faim_export int aim_buddylist_set(OscarSession *, OscarConnection *, const char *);
-/* 0x0004 */ faim_export int aim_buddylist_addbuddy(OscarSession *, OscarConnection *, const char *);
-/* 0x0005 */ faim_export int aim_buddylist_removebuddy(OscarSession *, OscarConnection *, const char *);
-/* 0x000b */ faim_export int aim_buddylist_oncoming(OscarSession *sess, OscarConnection *conn, aim_userinfo_t *info);
-/* 0x000c */ faim_export int aim_buddylist_offgoing(OscarSession *sess, OscarConnection *conn, const char *sn);
+/* 0x0002 */ int 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 */
-faim_export int aim_search_address(OscarSession *, OscarConnection *, const char *);
+int aim_search_address(OscarData *, const char *);
 
 
 
@@ -1136,16 +1028,16 @@
 
 #define AIM_CHATFLAGS_NOREFLECT 0x0001
 #define AIM_CHATFLAGS_AWAY      0x0002
-faim_export int aim_chat_send_im(OscarSession *sess, OscarConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language);
-faim_export int aim_chat_join(OscarSession *sess, OscarConnection *conn, guint16 exchange, const char *roomname, guint16 instance);
-faim_export int aim_chat_attachname(OscarConnection *conn, guint16 exchange, const char *roomname, guint16 instance);
-faim_export char *aim_chat_getname(OscarConnection *conn);
-faim_export OscarConnection *aim_chat_getconn(OscarSession *, const char *name);
+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);
 
-faim_export int aim_chatnav_reqrights(OscarSession *sess, OscarConnection *conn);
+int aim_chatnav_reqrights(OscarData *od, FlapConnection *conn);
 
-faim_export int aim_chatnav_createroom(OscarSession *sess, OscarConnection *conn, const char *name, guint16 exchange);
-faim_export int aim_chat_leaveroom(OscarSession *sess, const char *name);
+int aim_chatnav_createroom(OscarData *od, FlapConnection *conn, const char *name, guint16 exchange);
+int aim_chat_leaveroom(OscarData *od, const char *name);
 
 
 
@@ -1169,15 +1061,15 @@
 	struct aim_odir *next;
 };
 
-faim_export int aim_odir_email(OscarSession *, const char *, const char *);
-faim_export int aim_odir_name(OscarSession *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *);
-faim_export int aim_odir_interest(OscarSession *, const char *, const char *);
+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 */
-faim_export int aim_bart_upload(OscarSession *sess, const guint8 *icon, guint16 iconlen);
-faim_export int aim_bart_request(OscarSession *sess, const char *sn, guint8 iconcsumtype, const guint8 *iconstr, guint16 iconstrlen);
+int aim_bart_upload(OscarData *od, const guint8 *icon, guint16 iconlen);
+int aim_bart_request(OscarData *od, const char *sn, guint8 iconcsumtype, const guint8 *iconstr, guint16 iconstrlen);
 
 
 
@@ -1221,45 +1113,45 @@
 };
 
 /* These build the actual SNACs and queue them to be sent */
-/* 0x0002 */ faim_export int aim_ssi_reqrights(OscarSession *sess);
-/* 0x0004 */ faim_export int aim_ssi_reqdata(OscarSession *sess);
-/* 0x0005 */ faim_export int aim_ssi_reqifchanged(OscarSession *sess, time_t localstamp, guint16 localrev);
-/* 0x0007 */ faim_export int aim_ssi_enable(OscarSession *sess);
-/* 0x0008 */ faim_export int aim_ssi_addmoddel(OscarSession *sess);
-/* 0x0011 */ faim_export int aim_ssi_modbegin(OscarSession *sess);
-/* 0x0012 */ faim_export int aim_ssi_modend(OscarSession *sess);
-/* 0x0014 */ faim_export int aim_ssi_sendauth(OscarSession *sess, char *sn, char *msg);
-/* 0x0018 */ faim_export int aim_ssi_sendauthrequest(OscarSession *sess, char *sn, const char *msg);
-/* 0x001a */ faim_export int aim_ssi_sendauthreply(OscarSession *sess, char *sn, guint8 reply, const char *msg);
+/* 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);
+/* 0x0008 */ int aim_ssi_addmoddel(OscarData *od);
+/* 0x0011 */ int aim_ssi_modbegin(OscarData *od);
+/* 0x0012 */ int aim_ssi_modend(OscarData *od);
+/* 0x0014 */ int aim_ssi_sendauth(OscarData *od, char *sn, char *msg);
+/* 0x0018 */ int aim_ssi_sendauthrequest(OscarData *od, char *sn, const char *msg);
+/* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, char *sn, guint8 reply, const char *msg);
 
 /* Client functions for retrieving SSI data */
-faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid);
-faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, guint16 type);
-faim_export struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn);
-faim_export char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn);
-faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list);
-faim_export guint32 aim_ssi_getpresence(struct aim_ssi_item *list);
-faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn);
-faim_export char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *sn);
-faim_export int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn);
+struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid);
+struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, guint16 type);
+struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn);
+char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn);
+int aim_ssi_getpermdeny(struct aim_ssi_item *list);
+guint32 aim_ssi_getpresence(struct aim_ssi_item *list);
+char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn);
+char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *sn);
+int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn);
 
 /* Client functions for changing SSI data */
-faim_export int aim_ssi_addbuddy(OscarSession *sess, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth);
-faim_export int aim_ssi_addpermit(OscarSession *sess, const char *name);
-faim_export int aim_ssi_adddeny(OscarSession *sess, const char *name);
-faim_export int aim_ssi_delbuddy(OscarSession *sess, const char *name, const char *group);
-faim_export int aim_ssi_delpermit(OscarSession *sess, const char *name);
-faim_export int aim_ssi_deldeny(OscarSession *sess, const char *name);
-faim_export int aim_ssi_movebuddy(OscarSession *sess, const char *oldgn, const char *newgn, const char *sn);
-faim_export int aim_ssi_aliasbuddy(OscarSession *sess, const char *gn, const char *sn, const char *alias);
-faim_export int aim_ssi_editcomment(OscarSession *sess, const char *gn, const char *sn, const char *alias);
-faim_export int aim_ssi_rename_group(OscarSession *sess, const char *oldgn, const char *newgn);
-faim_export int aim_ssi_cleanlist(OscarSession *sess);
-faim_export int aim_ssi_deletelist(OscarSession *sess);
-faim_export int aim_ssi_setpermdeny(OscarSession *sess, guint8 permdeny, guint32 vismask);
-faim_export int aim_ssi_setpresence(OscarSession *sess, guint32 presence);
-faim_export int aim_ssi_seticon(OscarSession *sess, guint8 *iconsum, guint16 iconsumlen);
-faim_export int aim_ssi_delicon(OscarSession *sess);
+int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth);
+int aim_ssi_addpermit(OscarData *od, const char *name);
+int aim_ssi_adddeny(OscarData *od, const char *name);
+int aim_ssi_delbuddy(OscarData *od, const char *name, const char *group);
+int aim_ssi_delpermit(OscarData *od, const char *name);
+int aim_ssi_deldeny(OscarData *od, const char *name);
+int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *sn);
+int aim_ssi_aliasbuddy(OscarData *od, const char *gn, const char *sn, const char *alias);
+int aim_ssi_editcomment(OscarData *od, const char *gn, const char *sn, const char *alias);
+int aim_ssi_rename_group(OscarData *od, const char *oldgn, const char *newgn);
+int aim_ssi_cleanlist(OscarData *od);
+int aim_ssi_deletelist(OscarData *od);
+int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny, guint32 vismask);
+int aim_ssi_setpresence(OscarData *od, guint32 presence);
+int aim_ssi_seticon(OscarData *od, guint8 *iconsum, guint16 iconsumlen);
+int aim_ssi_delicon(OscarData *od);
 
 
 
@@ -1345,23 +1237,23 @@
 	struct aim_icq_info *next;
 };
 
-faim_export int aim_icq_reqofflinemsgs(OscarSession *sess);
-faim_export int aim_icq_ackofflinemsgs(OscarSession *sess);
-faim_export int aim_icq_setsecurity(OscarSession *sess, gboolean auth_required, gboolean webaware);
-faim_export int aim_icq_changepasswd(OscarSession *sess, const char *passwd);
-faim_export int aim_icq_getsimpleinfo(OscarSession *sess, const char *uin);
-faim_export int aim_icq_getalias(OscarSession *sess, const char *uin);
-faim_export int aim_icq_getallinfo(OscarSession *sess, const char *uin);
+int aim_icq_reqofflinemsgs(OscarData *od);
+int aim_icq_ackofflinemsgs(OscarData *od);
+int aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware);
+int aim_icq_changepasswd(OscarData *od, const char *passwd);
+int aim_icq_getsimpleinfo(OscarData *od, const char *uin);
+int aim_icq_getalias(OscarData *od, const char *uin);
+int aim_icq_getallinfo(OscarData *od, const char *uin);
 
 
 
 /* 0x0017 - family_auth.c */
-faim_export int aim_sendcookie(OscarSession *, OscarConnection *, const guint16 length, const guint8 *);
-faim_export int aim_admin_changepasswd(OscarSession *, OscarConnection *, const char *newpw, const char *curpw);
-faim_export int aim_admin_reqconfirm(OscarSession *sess, OscarConnection *conn);
-faim_export int aim_admin_getinfo(OscarSession *sess, OscarConnection *conn, guint16 info);
-faim_export int aim_admin_setemail(OscarSession *sess, OscarConnection *conn, const char *newemail);
-faim_export int aim_admin_setnick(OscarSession *sess, OscarConnection *conn, const char *newnick);
+void aim_sendcookie(OscarData *, FlapConnection *, const guint16 length, const guint8 *);
+int aim_admin_changepasswd(OscarData *, FlapConnection *, const char *newpw, const char *curpw);
+int aim_admin_reqconfirm(OscarData *od, FlapConnection *conn);
+int aim_admin_getinfo(OscarData *od, FlapConnection *conn, guint16 info);
+int aim_admin_setemail(OscarData *od, FlapConnection *conn, const char *newemail);
+int aim_admin_setnick(OscarData *od, FlapConnection *conn, const char *newnick);
 
 
 
@@ -1378,8 +1270,8 @@
 	struct aim_emailinfo *next;
 };
 
-faim_export int aim_email_sendcookies(OscarSession *sess);
-faim_export int aim_email_activate(OscarSession *sess);
+int aim_email_sendcookies(OscarData *od);
+int aim_email_activate(OscarData *od);
 
 
 
@@ -1401,55 +1293,49 @@
 } aim_tlvlist_t;
 
 /* TLV handling functions */
-faim_internal aim_tlv_t *aim_tlv_gettlv(aim_tlvlist_t *list, guint16 type, const int nth);
-faim_internal int aim_tlv_getlength(aim_tlvlist_t *list, guint16 type, const int nth);
-faim_internal char *aim_tlv_getstr(aim_tlvlist_t *list, const guint16 type, const int nth);
-faim_internal guint8 aim_tlv_get8(aim_tlvlist_t *list, const guint16 type, const int nth);
-faim_internal guint16 aim_tlv_get16(aim_tlvlist_t *list, const guint16 type, const int nth);
-faim_internal guint32 aim_tlv_get32(aim_tlvlist_t *list, const guint16 type, const int nth);
+aim_tlv_t *aim_tlv_gettlv(aim_tlvlist_t *list, guint16 type, const int nth);
+int aim_tlv_getlength(aim_tlvlist_t *list, guint16 type, const int nth);
+char *aim_tlv_getstr(aim_tlvlist_t *list, const guint16 type, const int nth);
+guint8 aim_tlv_get8(aim_tlvlist_t *list, const guint16 type, const int nth);
+guint16 aim_tlv_get16(aim_tlvlist_t *list, const guint16 type, const int nth);
+guint32 aim_tlv_get32(aim_tlvlist_t *list, const guint16 type, const int nth);
 
 /* TLV list handling functions */
-faim_internal aim_tlvlist_t *aim_tlvlist_read(ByteStream *bs);
-faim_internal aim_tlvlist_t *aim_tlvlist_readnum(ByteStream *bs, guint16 num);
-faim_internal aim_tlvlist_t *aim_tlvlist_readlen(ByteStream *bs, guint16 len);
-faim_internal aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig);
+aim_tlvlist_t *aim_tlvlist_read(ByteStream *bs);
+aim_tlvlist_t *aim_tlvlist_readnum(ByteStream *bs, guint16 num);
+aim_tlvlist_t *aim_tlvlist_readlen(ByteStream *bs, guint16 len);
+aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig);
 
-faim_internal int aim_tlvlist_count(aim_tlvlist_t **list);
-faim_internal int aim_tlvlist_size(aim_tlvlist_t **list);
-faim_internal int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two);
-faim_internal int aim_tlvlist_write(ByteStream *bs, aim_tlvlist_t **list);
-faim_internal void aim_tlvlist_free(aim_tlvlist_t **list);
+int aim_tlvlist_count(aim_tlvlist_t **list);
+int aim_tlvlist_size(aim_tlvlist_t **list);
+int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two);
+int aim_tlvlist_write(ByteStream *bs, aim_tlvlist_t **list);
+void aim_tlvlist_free(aim_tlvlist_t **list);
 
-faim_internal int aim_tlvlist_add_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value);
-faim_internal int aim_tlvlist_add_noval(aim_tlvlist_t **list, const guint16 type);
-faim_internal int aim_tlvlist_add_8(aim_tlvlist_t **list, const guint16 type, const guint8 value);
-faim_internal int aim_tlvlist_add_16(aim_tlvlist_t **list, const guint16 type, const guint16 value);
-faim_internal int aim_tlvlist_add_32(aim_tlvlist_t **list, const guint16 type, const guint32 value);
-faim_internal int aim_tlvlist_add_str(aim_tlvlist_t **list, const guint16 type, const char *value);
-faim_internal int aim_tlvlist_add_caps(aim_tlvlist_t **list, const guint16 type, const guint32 caps);
-faim_internal int aim_tlvlist_add_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *userinfo);
-faim_internal int aim_tlvlist_add_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance);
-faim_internal int aim_tlvlist_add_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl);
+int aim_tlvlist_add_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value);
+int aim_tlvlist_add_noval(aim_tlvlist_t **list, const guint16 type);
+int aim_tlvlist_add_8(aim_tlvlist_t **list, const guint16 type, const guint8 value);
+int aim_tlvlist_add_16(aim_tlvlist_t **list, const guint16 type, const guint16 value);
+int aim_tlvlist_add_32(aim_tlvlist_t **list, const guint16 type, const guint32 value);
+int aim_tlvlist_add_str(aim_tlvlist_t **list, const guint16 type, const char *value);
+int aim_tlvlist_add_caps(aim_tlvlist_t **list, const guint16 type, const guint32 caps);
+int aim_tlvlist_add_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *userinfo);
+int aim_tlvlist_add_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance);
+int aim_tlvlist_add_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl);
 
-faim_internal int aim_tlvlist_replace_raw(aim_tlvlist_t **list, const guint16 type, const guint16 lenth, const guint8 *value);
-faim_internal int aim_tlvlist_replace_str(aim_tlvlist_t **list, const guint16 type, const char *str);
-faim_internal int aim_tlvlist_replace_noval(aim_tlvlist_t **list, const guint16 type);
-faim_internal int aim_tlvlist_replace_8(aim_tlvlist_t **list, const guint16 type, const guint8 value);
-faim_internal int aim_tlvlist_replace_16(aim_tlvlist_t **list, const guint16 type, const guint16 value);
-faim_internal int aim_tlvlist_replace_32(aim_tlvlist_t **list, const guint16 type, const guint32 value);
+int aim_tlvlist_replace_raw(aim_tlvlist_t **list, const guint16 type, const guint16 lenth, const guint8 *value);
+int aim_tlvlist_replace_str(aim_tlvlist_t **list, const guint16 type, const char *str);
+int aim_tlvlist_replace_noval(aim_tlvlist_t **list, const guint16 type);
+int aim_tlvlist_replace_8(aim_tlvlist_t **list, const guint16 type, const guint8 value);
+int aim_tlvlist_replace_16(aim_tlvlist_t **list, const guint16 type, const guint16 value);
+int aim_tlvlist_replace_32(aim_tlvlist_t **list, const guint16 type, const guint32 value);
 
-faim_internal void aim_tlvlist_remove(aim_tlvlist_t **list, const guint16 type);
+void aim_tlvlist_remove(aim_tlvlist_t **list, const guint16 type);
 
 
 
 /* util.c */
-/*
- * These are really ugly.  You'd think this was LISP.  I wish it was.
- *
- * XXX With the advent of bstream's, these should be removed to enforce
- * their use.
- *
- */
+/* These are really ugly.  You'd think this was LISP.  I wish it was. */
 #define aimutil_put8(buf, data) ((*(buf) = (guint8)(data)&0xff),1)
 #define aimutil_get8(buf) ((*(buf))&0xff)
 #define aimutil_put16(buf, data) ( \
@@ -1495,18 +1381,193 @@
 		(((*((buf)+2)) << 16) & 0x00ff0000) + \
 		(((*((buf)+3)) << 24) & 0xff000000))
 
-faim_export guint16 aimutil_iconsum(const guint8 *buf, int buflen);
-faim_export int aimutil_tokslen(char *toSearch, int theindex, char dl);
-faim_export int aimutil_itemcnt(char *toSearch, char dl);
-faim_export char *aimutil_itemindex(char *toSearch, int theindex, char dl);
+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);
+
+int aim_snvalid(const char *sn);
+int aim_sn_is_icq(const char *sn);
+int aim_sn_is_sms(const char *sn);
+int aim_snlen(const char *sn);
+int aim_sncmp(const char *sn1, const char *sn2);
+
+
+
+
+typedef struct {
+	guint16 family;
+	guint16 subtype;
+	guint16 flags;
+	guint32 id;
+} aim_modsnac_t;
+
+#define AIM_MODULENAME_MAXLEN 16
+#define AIM_MODFLAG_MULTIFAMILY 0x0001
+typedef struct aim_module_s
+{
+	guint16 family;
+	guint16 version;
+	guint16 toolid;
+	guint16 toolversion;
+	guint16 flags;
+	char name[AIM_MODULENAME_MAXLEN+1];
+	int (*snachandler)(OscarData *od, FlapConnection *conn, struct aim_module_s *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs);
+	void (*shutdown)(OscarData *od, struct aim_module_s *mod);
+	void *priv;
+	struct aim_module_s *next;
+} aim_module_t;
+
+int aim__registermodule(OscarData *od, int (*modfirst)(OscarData *, aim_module_t *));
+void aim__shutdownmodules(OscarData *od);
+aim_module_t *aim__findmodulebygroup(OscarData *od, guint16 group);
+aim_module_t *aim__findmodule(OscarData *od, const char *name);
+
+int admin_modfirst(OscarData *od, aim_module_t *mod);
+int buddylist_modfirst(OscarData *od, aim_module_t *mod);
+int bos_modfirst(OscarData *od, aim_module_t *mod);
+int search_modfirst(OscarData *od, aim_module_t *mod);
+int stats_modfirst(OscarData *od, aim_module_t *mod);
+int auth_modfirst(OscarData *od, aim_module_t *mod);
+int msg_modfirst(OscarData *od, aim_module_t *mod);
+int misc_modfirst(OscarData *od, aim_module_t *mod);
+int chatnav_modfirst(OscarData *od, aim_module_t *mod);
+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);
+int email_modfirst(OscarData *od, aim_module_t *mod);
+
+int aim_genericreq_n(OscarData *, FlapConnection *conn, guint16 family, guint16 subtype);
+int aim_genericreq_n_snacid(OscarData *, FlapConnection *conn, guint16 family, guint16 subtype);
+int aim_genericreq_l(OscarData *, FlapConnection *conn, guint16 family, guint16 subtype, guint32 *);
+int aim_genericreq_s(OscarData *, FlapConnection *conn, guint16 family, guint16 subtype, guint16 *);
 
-faim_export int aim_snvalid(const char *sn);
-faim_export int aim_sn_is_icq(const char *sn);
-faim_export int aim_sn_is_sms(const char *sn);
-faim_export int aim_snlen(const char *sn);
-faim_export int aim_sncmp(const char *sn1, const char *sn2);
+/* bstream.c */
+int byte_stream_init(ByteStream *bs, guint8 *data, int len);
+int byte_stream_empty(ByteStream *bs);
+int byte_stream_curpos(ByteStream *bs);
+int byte_stream_setpos(ByteStream *bs, unsigned int off);
+void byte_stream_rewind(ByteStream *bs);
+int byte_stream_advance(ByteStream *bs, int n);
+guint8 byte_stream_get8(ByteStream *bs);
+guint16 byte_stream_get16(ByteStream *bs);
+guint32 byte_stream_get32(ByteStream *bs);
+guint8 byte_stream_getle8(ByteStream *bs);
+guint16 byte_stream_getle16(ByteStream *bs);
+guint32 byte_stream_getle32(ByteStream *bs);
+int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int len);
+guint8 *byte_stream_getraw(ByteStream *bs, int len);
+char *byte_stream_getstr(ByteStream *bs, int len);
+int byte_stream_put8(ByteStream *bs, guint8 v);
+int byte_stream_put16(ByteStream *bs, guint16 v);
+int byte_stream_put32(ByteStream *bs, guint32 v);
+int byte_stream_putle8(ByteStream *bs, guint8 v);
+int byte_stream_putle16(ByteStream *bs, guint16 v);
+int byte_stream_putle32(ByteStream *bs, guint32 v);
+int byte_stream_putraw(ByteStream *bs, const guint8 *v, int len);
+int byte_stream_putstr(ByteStream *bs, const char *str);
+int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int len);
+int byte_stream_putcaps(ByteStream *bs, guint32 caps);
+
+/* rxhandlers.c */
+aim_rxcallback_t aim_callhandler(OscarData *od, guint16 family, guint16 type);
+
+/*
+ * Generic SNAC structure.  Rarely if ever used.
+ */
+typedef struct aim_snac_s {
+	aim_snacid_t id;
+	guint16 family;
+	guint16 type;
+	guint16 flags;
+	void *data;
+	time_t issuetime;
+	struct aim_snac_s *next;
+} aim_snac_t;
+
+/* snac.c */
+void aim_initsnachash(OscarData *od);
+aim_snacid_t aim_newsnac(OscarData *, aim_snac_t *newsnac);
+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);
+int aim_putsnac(ByteStream *, guint16 family, guint16 type, guint16 flags, aim_snacid_t id);
+
+struct chatsnacinfo {
+	guint16 exchange;
+	char name[128];
+	guint16 instance;
+};
 
-#include "oscar_internal.h"
+/*
+ * In SNACland, the terms 'family' and 'group' are synonymous -- the former
+ * is my term, the latter is AOL's.
+ */
+struct snacgroup {
+	guint16 group;
+	struct snacgroup *next;
+};
+
+struct snacpair {
+	guint16 group;
+	guint16 subtype;
+	struct snacpair *next;
+};
+
+struct rateclass {
+	guint16 classid;
+	guint32 windowsize;
+	guint32 clear;
+	guint32 alert;
+	guint32 limit;
+	guint32 disconnect;
+	guint32 current;
+	guint32 max;
+	guint8 unknown[5]; /* only present in versions >= 3 */
+	struct snacpair *members;
+	struct rateclass *next;
+};
+
+/*
+ * This is inside every connection.  But it is a void * to anything
+ * outside of libfaim.  It should remain that way.  It's called data
+ * abstraction.  Maybe you've heard of it.  (Probably not if you're a
+ * libfaim user.)
+ *
+ */
+typedef struct aim_conn_inside_s {
+	struct snacgroup *groups;
+	struct rateclass *rates;
+} aim_conn_inside_t;
+
+int aim_cachecookie(OscarData *od, IcbmCookie *cookie);
+IcbmCookie *aim_uncachecookie(OscarData *od, guint8 *cookie, int type);
+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(int type);
+int aim_cookie_free(OscarData *od, IcbmCookie *cookie);
+
+int aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo);
+
+void flap_connection_destroy_chat(OscarData *od, FlapConnection *conn);
+
+/* These are all handled internally now. */
+int aim_setversions(OscarData *od, FlapConnection *conn);
+int aim_reqrates(OscarData *, FlapConnection *);
+int aim_rates_addparam(OscarData *, FlapConnection *);
+int aim_rates_delparam(OscarData *, FlapConnection *);
+
+
+
+
 
 #ifdef __cplusplus
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/oscar/oscar_data.c	Fri Apr 07 05:10:56 2006 +0000
@@ -0,0 +1,158 @@
+/*
+ * Gaim'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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "oscar.h"
+
+typedef struct _SnacHandler SnacHandler;
+
+struct _SnacHandler
+{
+	guint16 family;
+	guint16 type;
+	aim_rxcallback_t handler;
+	guint16 flags;
+};
+
+static void
+oscar_free_buddyinfo(void *data)
+{
+	struct buddyinfo *bi = data;
+	g_free(bi);
+}
+
+/**
+ * Allocates a new OscarData and initializes it with default values.
+ */
+OscarData *
+oscar_data_new(void)
+{
+	OscarData *od;
+
+	od = g_new0(OscarData, 1);
+
+	aim_initsnachash(od);
+	od->snacid_next = 0x00000001;
+	od->buddyinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, oscar_free_buddyinfo);
+
+	/*
+	 * Register all the modules for this session...
+	 */
+	aim__registermodule(od, misc_modfirst); /* load the catch-all first */
+	aim__registermodule(od, service_modfirst);
+	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);
+	/* missing 0x14 */
+	aim__registermodule(od, icq_modfirst);
+	/* missing 0x16 */
+	aim__registermodule(od, auth_modfirst);
+	aim__registermodule(od, email_modfirst);
+
+	return od;
+}
+
+/**
+ * Logoff and deallocate a session.
+ *
+ * @param od Session to kill
+ */
+void
+oscar_data_destroy(OscarData *od)
+{
+	aim_cleansnacs(od, -1);
+
+	while (od->oscar_connections != NULL)
+		flap_connection_destroy(od->oscar_connections->data);
+
+	while (od->peer_connections != NULL)
+		peer_connection_destroy(od->peer_connections->data,
+				PEER_DISCONNECT_LOCAL_CLOSED);
+
+	if (od->handlerlist != NULL)
+		aim_clearhandlers(od);
+
+	aim__shutdownmodules(od);
+
+	g_hash_table_destroy(od->buddyinfo);
+
+	g_free(od);
+}
+
+int oscar_data_addhandler(OscarData *od, guint16 family, guint16 type, aim_rxcallback_t newhandler, guint16 flags)
+{
+	SnacHandler *snac_handler;
+
+	gaim_debug_misc("oscar", "Adding handler for %04x/%04x\n", family, type);
+
+	snac_handler = g_new0(SnacHandler, 1);
+
+	snac_handler->family = family;
+	snac_handler->type = type;
+	snac_handler->flags = flags;
+	snac_handler->handler = newhandler;
+
+	od->handlerlist = g_list_prepend(od->handlerlist, snac_handler);
+
+	return 0;
+}
+
+void
+aim_clearhandlers(OscarData *od)
+{
+	SnacHandler *snac_handler;
+
+	while (od->handlerlist != NULL)
+	{
+		snac_handler = od->handlerlist->data;
+		od->handlerlist = g_list_remove(od->handlerlist, snac_handler);
+		g_free(snac_handler);
+	}
+	od->handlerlist = NULL;
+}
+
+aim_rxcallback_t
+aim_callhandler(OscarData *od, guint16 family, guint16 type)
+{
+	GList *cur;
+	SnacHandler *snac_handler;
+
+	for (cur = od->handlerlist; cur != NULL; cur = cur->next)
+	{
+		snac_handler = cur->data;
+		if ((snac_handler->family == family) && (snac_handler->type == type))
+			return snac_handler->handler;
+	}
+
+	return NULL;
+}
--- a/src/protocols/oscar/oscar_internal.h	Fri Apr 07 01:05:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,227 +0,0 @@
-/*
- * Gaim'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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/*
- * oscar_internal.h -- prototypes/structs for the guts of libfaim
- *
- */
-
-#ifndef _OSCAR_INTERNAL_H_
-#define _OSCAR_INTERNAL_H_
-
-typedef struct {
-	guint16 family;
-	guint16 subtype;
-	guint16 flags;
-	guint32 id;
-} aim_modsnac_t;
-
-#define AIM_MODULENAME_MAXLEN 16
-#define AIM_MODFLAG_MULTIFAMILY 0x0001
-typedef struct aim_module_s {
-	guint16 family;
-	guint16 version;
-	guint16 toolid;
-	guint16 toolversion;
-	guint16 flags;
-	char name[AIM_MODULENAME_MAXLEN+1];
-	int (*snachandler)(OscarSession *sess, struct aim_module_s *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs);
-
-	void (*shutdown)(OscarSession *sess, struct aim_module_s *mod);
-	void *priv;
-	struct aim_module_s *next;
-} aim_module_t;
-
-faim_internal int aim__registermodule(OscarSession *sess, int (*modfirst)(OscarSession *, aim_module_t *));
-faim_internal void aim__shutdownmodules(OscarSession *sess);
-faim_internal aim_module_t *aim__findmodulebygroup(OscarSession *sess, guint16 group);
-faim_internal aim_module_t *aim__findmodule(OscarSession *sess, const char *name);
-
-faim_internal int admin_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int buddylist_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int bos_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int search_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int stats_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int auth_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int msg_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int misc_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int chatnav_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int chat_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int locate_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int service_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int invite_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int translate_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int popups_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int adverts_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int odir_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int bart_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int ssi_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int icq_modfirst(OscarSession *sess, aim_module_t *mod);
-faim_internal int email_modfirst(OscarSession *sess, aim_module_t *mod);
-
-faim_internal int aim_genericreq_n(OscarSession *, OscarConnection *conn, guint16 family, guint16 subtype);
-faim_internal int aim_genericreq_n_snacid(OscarSession *, OscarConnection *conn, guint16 family, guint16 subtype);
-faim_internal int aim_genericreq_l(OscarSession *, OscarConnection *conn, guint16 family, guint16 subtype, guint32 *);
-faim_internal int aim_genericreq_s(OscarSession *, OscarConnection *conn, guint16 family, guint16 subtype, guint16 *);
-
-/* bstream.c */
-faim_internal int aim_bstream_init(ByteStream *bs, guint8 *data, int len);
-faim_internal int aim_bstream_empty(ByteStream *bs);
-faim_internal int aim_bstream_curpos(ByteStream *bs);
-faim_internal int aim_bstream_setpos(ByteStream *bs, unsigned int off);
-faim_internal void aim_bstream_rewind(ByteStream *bs);
-faim_internal int aim_bstream_advance(ByteStream *bs, int n);
-faim_internal guint8 aimbs_get8(ByteStream *bs);
-faim_internal guint16 aimbs_get16(ByteStream *bs);
-faim_internal guint32 aimbs_get32(ByteStream *bs);
-faim_internal guint8 aimbs_getle8(ByteStream *bs);
-faim_internal guint16 aimbs_getle16(ByteStream *bs);
-faim_internal guint32 aimbs_getle32(ByteStream *bs);
-faim_internal int aimbs_getrawbuf(ByteStream *bs, guint8 *buf, int len);
-faim_internal guint8 *aimbs_getraw(ByteStream *bs, int len);
-faim_internal char *aimbs_getstr(ByteStream *bs, int len);
-faim_internal int aimbs_put8(ByteStream *bs, guint8 v);
-faim_internal int aimbs_put16(ByteStream *bs, guint16 v);
-faim_internal int aimbs_put32(ByteStream *bs, guint32 v);
-faim_internal int aimbs_putle8(ByteStream *bs, guint8 v);
-faim_internal int aimbs_putle16(ByteStream *bs, guint16 v);
-faim_internal int aimbs_putle32(ByteStream *bs, guint32 v);
-faim_internal int aimbs_putraw(ByteStream *bs, const guint8 *v, int len);
-faim_internal int aimbs_putstr(ByteStream *bs, const char *str);
-faim_internal int aimbs_putbs(ByteStream *bs, ByteStream *srcbs, int len);
-faim_internal int aimbs_putcaps(ByteStream *bs, guint32 caps);
-
-/* conn.c */
-faim_internal OscarConnection *aim_cloneconn(OscarSession *sess, OscarConnection *src);
-
-/* rxhandlers.c */
-faim_internal aim_rxcallback_t aim_callhandler(OscarSession *sess, OscarConnection *conn, guint16 family, guint16 type);
-faim_internal int aim_callhandler_noparam(OscarSession *sess, OscarConnection *conn, guint16 family, guint16 type, FlapFrame *ptr);
-faim_internal int aim_parse_unknown(OscarSession *, FlapFrame *, ...);
-faim_internal void aim_clonehandlers(OscarSession *sess, OscarConnection *dest, OscarConnection *src);
-
-/* rxqueue.c */
-faim_internal int aim_recv(int fd, void *buf, size_t count);
-faim_internal int aim_bstream_recv(ByteStream *bs, int fd, size_t count);
-faim_internal void aim_rxqueue_cleanbyconn(OscarSession *sess, OscarConnection *conn);
-faim_internal void aim_frame_destroy(FlapFrame *);
-
-/* txqueue.c */
-faim_internal FlapFrame *flap_frame_new(OscarSession *sess, OscarConnection *conn, guint8 framing, guint16 chan, int datalen);
-faim_internal int aim_tx_enqueue(OscarSession *, FlapFrame *);
-faim_internal int aim_bstream_send(ByteStream *bs, OscarConnection *conn, size_t count);
-faim_internal void aim_tx_cleanqueue(OscarSession *, OscarConnection *);
-
-/*
- * Generic SNAC structure.  Rarely if ever used.
- */
-typedef struct aim_snac_s {
-	aim_snacid_t id;
-	guint16 family;
-	guint16 type;
-	guint16 flags;
-	void *data;
-	time_t issuetime;
-	struct aim_snac_s *next;
-} aim_snac_t;
-
-/* snac.c */
-faim_internal void aim_initsnachash(OscarSession *sess);
-faim_internal aim_snacid_t aim_newsnac(OscarSession *, aim_snac_t *newsnac);
-faim_internal aim_snacid_t aim_cachesnac(OscarSession *sess, const guint16 family, const guint16 type, const guint16 flags, const void *data, const int datalen);
-faim_internal aim_snac_t *aim_remsnac(OscarSession *, aim_snacid_t id);
-faim_internal int aim_putsnac(ByteStream *, guint16 family, guint16 type, guint16 flags, aim_snacid_t id);
-
-struct chatsnacinfo {
-	guint16 exchange;
-	char name[128];
-	guint16 instance;
-};
-
-/*
- * In SNACland, the terms 'family' and 'group' are synonymous -- the former
- * is my term, the latter is AOL's.
- */
-struct snacgroup {
-	guint16 group;
-	struct snacgroup *next;
-};
-
-struct snacpair {
-	guint16 group;
-	guint16 subtype;
-	struct snacpair *next;
-};
-
-struct rateclass {
-	guint16 classid;
-	guint32 windowsize;
-	guint32 clear;
-	guint32 alert;
-	guint32 limit;
-	guint32 disconnect;
-	guint32 current;
-	guint32 max;
-	guint8 unknown[5]; /* only present in versions >= 3 */
-	struct snacpair *members;
-	struct rateclass *next;
-};
-
-/*
- * This is inside every connection.  But it is a void * to anything
- * outside of libfaim.  It should remain that way.  It's called data
- * abstraction.  Maybe you've heard of it.  (Probably not if you're a
- * libfaim user.)
- *
- */
-typedef struct aim_conn_inside_s {
-	struct snacgroup *groups;
-	struct rateclass *rates;
-} aim_conn_inside_t;
-
-faim_internal void aim_conn_addgroup(OscarConnection *conn, guint16 group);
-
-faim_internal int aim_cachecookie(OscarSession *sess, IcbmCookie *cookie);
-faim_internal IcbmCookie *aim_uncachecookie(OscarSession *sess, guint8 *cookie, int type);
-faim_internal IcbmCookie *aim_mkcookie(guint8 *, int, void *);
-faim_internal IcbmCookie *aim_checkcookie(OscarSession *, const unsigned char *, const int);
-faim_internal int aim_freecookie(OscarSession *sess, IcbmCookie *cookie);
-faim_internal int aim_msgcookie_gettype(int reqclass);
-faim_internal int aim_cookie_free(OscarSession *sess, IcbmCookie *cookie);
-
-/* 0x0002 - locate.c */
-faim_internal void aim_locate_requestuserinfo(OscarSession *sess, const char *sn);
-faim_internal guint32 aim_locate_getcaps(OscarSession *sess, ByteStream *bs, int len);
-faim_internal guint32 aim_locate_getcaps_short(OscarSession *sess, ByteStream *bs, int len);
-faim_internal void aim_info_free(aim_userinfo_t *);
-faim_internal int aim_info_extract(OscarSession *sess, ByteStream *bs, aim_userinfo_t *);
-faim_internal int aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info);
-
-faim_internal int aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo);
-
-faim_internal void oscar_connection_destroy_chat(OscarSession *sess, OscarConnection *conn);
-
-/* These are all handled internally now. */
-faim_internal int aim_setversions(OscarSession *sess, OscarConnection *conn);
-faim_internal int aim_reqrates(OscarSession *, OscarConnection *);
-faim_internal int aim_rates_addparam(OscarSession *, OscarConnection *);
-faim_internal int aim_rates_delparam(OscarSession *, OscarConnection *);
-
-#endif /* _OSCAR_INTERNAL_H_ */
--- a/src/protocols/oscar/peer.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/peer.c	Fri Apr 07 05:10:56 2006 +0000
@@ -19,59 +19,33 @@
 */
 
 /*
- * Oscar File transfer (OFT) and Oscar Direct Connect (ODC).
- * (ODC is also referred to as DirectIM and IM Image.)
- *
- * There are a few static helper functions at the top, then
- * ODC stuff, then ft stuff.
- *
- * I feel like this is a good place to explain OFT, so I'm going to
- * do just that.  Each OFT packet has a header type.  I guess this
- * is pretty similar to the subtype of a SNAC packet.  The type
- * basically tells the other client the meaning of the OFT packet.
- * There are two distinct types of file transfer, which I usually
- * call "sendfile" and "getfile."  Sendfile is when you send a file
- * to another AIM user.  Getfile is when you share a group of files,
- * and other users request that you send them the files.
- *
- * A typical sendfile file transfer goes like this:
- *   1) Sender sends a channel 2 ICBM telling the other user that
- *      we want to send them a file.  At the same time, we open a
- *      listener socket (this should be done before sending the
- *      ICBM) on some port, and wait for them to connect to us.
- *      The ICBM we sent should contain our IP address and the port
- *      number that we're listening on.
- *   2) The receiver connects to the sender on the given IP address
- *      and port.  After the connection is established, the receiver
- *      sends an ICBM signifying that we are ready and waiting.
- *   3) The sender sends an OFT PROMPT message over the OFT
- *      connection.
- *   4) The receiver of the file sends back an exact copy of this
- *      OFT packet, except the cookie is filled in with the cookie
- *      from the ICBM.  I think this might be an attempt to verify
- *      that the user that is connected is actually the guy that
- *      we sent the ICBM to.  Oh, I've been calling this the ACK.
- *   5) The sender starts sending raw data across the connection
- *      until the entire file has been sent.
- *   6) The receiver knows the file is finished because the sender
- *      sent the file size in an earlier OFT packet.  So then the
- *      receiver sends the DONE thingy (after filling in the
- *      "received" checksum and size) and closes the connection.
+ * Functions dealing with peer connections.  This includes the code
+ * used to establish a peer connection for both Oscar File transfer
+ * (OFT) and Oscar Direct Connect (ODC).  (ODC is also referred to
+ * as DirectIM and IM Image.)
  */
 
 #ifdef HAVE_CONFIG_H
 #include  <config.h>
 #endif
 
+/* From the oscar PRPL */
 #include "oscar.h"
 #include "peer.h"
 
+/* From Gaim */
+#include "conversation.h"
+#include "ft.h"
+#include "network.h"
+#include "notify.h"
+#include "request.h"
+#include "util.h"
+
 #ifndef _WIN32
 #include <stdio.h>
 #include <netdb.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
-#include <sys/utsname.h> /* for aim_odc_initiate */
 #include <arpa/inet.h> /* for inet_ntoa */
 #include <limits.h> /* for UINT_MAX */
 #endif
@@ -94,1152 +68,929 @@
 #define PF_INET6 PF_INET
 #endif
 
-struct aim_odc_intdata {
-	guint8 cookie[8];
-	char sn[MAXSNLEN+1];
-	char ip[22];
-};
-
-/**
- * Convert the directory separator from / (0x2f) to ^A (0x01)
- *
- * @param name The filename to convert.
- */
-static void
-aim_oft_dirconvert_tostupid(char *name)
-{
-	while (name[0]) {
-		if (name[0] == 0x01)
-			name[0] = G_DIR_SEPARATOR;
-		name++;
-	}
-}
-
-/**
- * Convert the directory separator from ^A (0x01) to / (0x2f)
- *
- * @param name The filename to convert.
- */
-static void
-aim_oft_dirconvert_fromstupid(char *name)
-{
-	while (name[0]) {
-		if (name[0] == G_DIR_SEPARATOR)
-			name[0] = 0x01;
-		name++;
-	}
-}
-
-/**
- * Calculate oft checksum of buffer
- *
- * Prevcheck should be 0xFFFF0000 when starting a checksum of a file.  The
- * checksum is kind of a rolling checksum thing, so each time you get bytes
- * of a file you just call this puppy and it updates the checksum.  You can
- * calculate the checksum of an entire file by calling this in a while or a
- * for loop, or something.
- *
- * Thanks to Graham Booker for providing this improved checksum routine,
- * which is simpler and should be more accurate than Josh Myer's original
- * code. -- wtm
- *
- * This algorithm works every time I have tried it.  The other fails
- * sometimes.  So, AOL who thought this up?  It has got to be the weirdest
- * checksum I have ever seen.
- *
- * @param buffer Buffer of data to checksum.  Man I'd like to buff her...
- * @param bufsize Size of buffer.
- * @param prevcheck Previous checksum.
- */
-guint32
-aim_oft_checksum_chunk(const guint8 *buffer, int bufferlen, guint32 prevcheck)
-{
-	guint32 check = (prevcheck >> 16) & 0xffff, oldcheck;
-	int i;
-	unsigned short val;
-
-	for (i=0; i<bufferlen; i++) {
-		oldcheck = check;
-		if (i&1)
-			val = buffer[i];
-		else
-			val = buffer[i] << 8;
-		check -= val;
-		/*
-		 * The following appears to be necessary.... It happens
-		 * every once in a while and the checksum doesn't fail.
-		 */
-		if (check > oldcheck)
-			check--;
-	}
-	check = ((check & 0x0000ffff) + (check >> 16));
-	check = ((check & 0x0000ffff) + (check >> 16));
-	return check << 16;
-}
-
-guint32
-aim_oft_checksum_file(char *filename)
-{
-	FILE *fd;
-	guint32 checksum = 0xffff0000;
-
-	if ((fd = fopen(filename, "rb"))) {
-		int bytes;
-		guint8 buffer[1024];
-
-		while ((bytes = fread(buffer, 1, 1024, fd)))
-			checksum = aim_oft_checksum_chunk(buffer, bytes, checksum);
-		fclose(fd);
-	}
-
-	return checksum;
-}
-
-/**
- * After establishing a listening socket, this is called to accept a connection.  It
- * clones the conn used by the listener, and passes both of these to a signal handler.
- * The signal handler should close the listener conn and keep track of the new conn,
- * since this is what is used for file transfers and what not.
- *
- * @param sess The session.
- * @param cur The conn the incoming connection is on.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int
-aim_handlerendconnect(OscarSession *sess, OscarConnection *cur)
-{
-	int acceptfd = 0;
-	struct sockaddr addr;
-	socklen_t addrlen = sizeof(addr);
-	int ret = 0;
-	OscarConnection *newconn;
-	char ip[20];
-	unsigned short port;
-
-	if ((acceptfd = accept(cur->fd, &addr, &addrlen)) == -1)
-		return 0; /* not an error */
-
-	if ((addr.sa_family != PF_INET) && (addr.sa_family != PF_INET6)) {
-		close(acceptfd);
-		aim_conn_close(sess, cur);
-		return -1;
-	}
-
-	strncpy(ip, inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr), sizeof(ip));
-	port = ntohs(((struct sockaddr_in *)&addr)->sin_port);
-
-	if (!(newconn = aim_cloneconn(sess, cur))) {
-		close(acceptfd);
-		aim_conn_close(sess, cur);
-		return -ENOMEM;
-	}
-
-	newconn->type = AIM_CONN_TYPE_RENDEZVOUS;
-	newconn->fd = acceptfd;
-
-	if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
-		aim_rxcallback_t userfunc;
-		struct aim_odc_intdata *priv;
-
-		priv = (struct aim_odc_intdata *)(newconn->internal = cur->internal);
-		cur->internal = NULL;
-		snprintf(priv->ip, sizeof(priv->ip), "%s:%hu", ip, port);
-
-		if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, PEER_TYPE_DIRECTIM_ESTABLISHED)))
-			ret = userfunc(sess, NULL, newconn, cur);
-
-	} else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
-	} else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
-		aim_rxcallback_t userfunc;
-
-		if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, PEER_TYPE_ESTABLISHED)))
-			ret = userfunc(sess, NULL, newconn, cur);
-
-	} else {
-		gaim_debug_warning("oscar", "Got a connection on a listener that's not rendezvous.  Closing connection.\n");
-		aim_conn_close(sess, newconn);
-		ret = -1;
-	}
-
-	return ret;
-}
-
-/**
- * Send client-to-client typing notification over an established direct connection.
- *
- * @param sess The session.
- * @param conn The already-connected ODC connection.
- * @param typing If 0x0002, sends a "typing" message, 0x0001 sends "typed," and
- *        0x0000 sends "stopped."
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int
-aim_odc_send_typing(OscarSession *sess, OscarConnection *conn, int typing)
-{
-	struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal;
-	FlapFrame *fr;
-	ByteStream *hdrbs;
-	guint8 *hdr;
-	int hdrlen = 0x44;
-
-	if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
-		return -EINVAL;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0001, 0)))
-		return -ENOMEM;
-	memcpy(fr->hdr.rend.magic, "ODC2", 4);
-	fr->hdr.rend.hdrlen = hdrlen + 8;
-
-	if (!(hdr = calloc(1, hdrlen))) {
-		aim_frame_destroy(fr);
-		return -ENOMEM;
-	}
-
-	hdrbs = &(fr->data);
-	aim_bstream_init(hdrbs, hdr, hdrlen);
-
-	aimbs_put16(hdrbs, 0x0006);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_putraw(hdrbs, intdata->cookie, 8);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put32(hdrbs, 0x00000000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-
-	if (typing == 0x0002)
-		aimbs_put16(hdrbs, 0x0002 | 0x0008);
-	else if (typing == 0x0001)
-		aimbs_put16(hdrbs, 0x0002 | 0x0004);
-	else
-		aimbs_put16(hdrbs, 0x0002);
-
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_putstr(hdrbs, sess->sn);
-
-	aim_bstream_setpos(hdrbs, 52); /* bleeehh */
-
-	aimbs_put8(hdrbs, 0x00);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put8(hdrbs, 0x00);
-
-	/* end of hdr */
-
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
-}
-
-/**
- * Send client-to-client IM over an established direct connection.
- * Call this just like you would aim_send_im, to send a directim.
- *
- * @param sess The session.
- * @param conn The already-connected ODC connection.
- * @param msg Null-terminated string to send.
- * @param len The length of the message to send, including binary data.
- * @param encoding See the AIM_CHARSET_* defines in oscar.h
- * @param isawaymsg 0 if this is not an auto-response, 1 if it is.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int
-aim_odc_send_im(OscarSession *sess, OscarConnection *conn, const char *msg, int len, int encoding, int isawaymsg)
-{
-	FlapFrame *fr;
-	ByteStream *hdrbs;
-	struct aim_odc_intdata *intdata = (struct aim_odc_intdata *)conn->internal;
-	int hdrlen = 0x44;
-	guint8 *hdr;
-
-	if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !msg)
-		return -EINVAL;
-
-	if (!(fr = flap_frame_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0)))
-		return -ENOMEM;
-
-	memcpy(fr->hdr.rend.magic, "ODC2", 4);
-	fr->hdr.rend.hdrlen = hdrlen + 8;
-
-	if (!(hdr = calloc(1, hdrlen + len))) {
-		aim_frame_destroy(fr);
-		return -ENOMEM;
-	}
-
-	hdrbs = &(fr->data);
-	aim_bstream_init(hdrbs, hdr, hdrlen + len);
-
-	aimbs_put16(hdrbs, 0x0006);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_putraw(hdrbs, intdata->cookie, 8);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put32(hdrbs, len);
-	aimbs_put16(hdrbs, encoding);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-
-	/* flags - used for typing notification and to mark if this is an away message */
-	aimbs_put16(hdrbs, 0x0000 | isawaymsg);
-
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_putstr(hdrbs, sess->sn);
-
-	aim_bstream_setpos(hdrbs, 52); /* bleeehh */
-
-	aimbs_put8(hdrbs, 0x00);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put8(hdrbs, 0x00);
-
-	/* end of hdr2 */
-
-#if 0 /* XXX - this is how you send buddy icon info... */
-	aimbs_put16(hdrbs, 0x0008);
-	aimbs_put16(hdrbs, 0x000c);
-	aimbs_put16(hdrbs, 0x0000);
-	aimbs_put16(hdrbs, 0x1466);
-	aimbs_put16(hdrbs, 0x0001);
-	aimbs_put16(hdrbs, 0x2e0f);
-	aimbs_put16(hdrbs, 0x393e);
-	aimbs_put16(hdrbs, 0xcac8);
-#endif
-	aimbs_putraw(hdrbs, (guchar *)msg, len);
-
-	aim_tx_enqueue(sess, fr);
-
-	return 0;
-}
-
-/**
- * Get the screen name of the peer of a direct connection.
- *
- * @param conn The ODC connection.
- * @return The screen name of the dude, or NULL if there was an anomaly.
- */
-const char *
-aim_odc_getsn(OscarConnection *conn)
-{
-	struct aim_odc_intdata *intdata;
-
-	if (!conn || !conn->internal)
-		return NULL;
-
-	if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) ||
-			(conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM))
-		return NULL;
-
-	intdata = (struct aim_odc_intdata *)conn->internal;
-
-	return intdata->sn;
-}
-
-/**
- * Get the cookie of a direct connection.
- *
- * @param conn The ODC connection.
- * @return The cookie, an 8 byte unterminated string, or NULL if there was an anomaly.
- */
-const guchar *
-aim_odc_getcookie(OscarConnection *conn)
-{
-	struct aim_odc_intdata *intdata;
-
-	if (!conn || !conn->internal)
-		return NULL;
-
-	intdata = (struct aim_odc_intdata *)conn->internal;
-
-	return intdata->cookie;
-}
-
-/**
- * Find the conn of a direct connection with the given buddy.
- *
- * @param sess The session.
- * @param sn The screen name of the buddy whose direct connection you want to find.
- * @return The conn for the direct connection with the given buddy, or NULL if no
- *         connection was found.
- */
-OscarConnection *
-aim_odc_getconn(OscarSession *sess, const char *sn)
+PeerConnection *
+peer_connection_find_by_type(OscarData *od, const char *sn, OscarCapability type)
 {
 	GList *cur;
-	struct aim_odc_intdata *intdata;
+	PeerConnection *conn;
 
-	if (!sess || !sn || !strlen(sn))
-		return NULL;
-
-	for (cur = sess->oscar_connections; cur; cur = cur->next)
+	for (cur = od->peer_connections; cur != NULL; cur = cur->next)
 	{
-		OscarConnection *conn;
 		conn = cur->data;
-		if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) && (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) {
-			intdata = conn->internal;
-			if (!aim_sncmp(intdata->sn, sn))
-				return conn;
-		}
+		if ((conn->type == type) && !aim_sncmp(conn->sn, sn))
+			return conn;
 	}
 
 	return NULL;
 }
 
 /**
- * For those times when we want to open up the direct connection channel ourselves.
- *
- * You'll want to set up some kind of watcher on this socket.
- * When the state changes, call aim_handlerendconnection with
- * the connection returned by this.  aim_handlerendconnection
- * will accept the pending connection and stop listening.
- *
- * @param sess The session
- * @param sn The screen name to connect to.
- * @return The new connection.
+ * @param cookie This must be exactly 8 characters.
  */
-OscarConnection *
-aim_odc_initiate(OscarSession *sess, const char *sn, int listenfd,
-                 const guint8 *localip, guint16 port, const guint8 *mycookie)
+PeerConnection *
+peer_connection_find_by_cookie(OscarData *od, const char *sn, const guchar *cookie)
+{
+	GList *cur;
+	PeerConnection *conn;
+
+	for (cur = od->peer_connections; cur != NULL; cur = cur->next)
+	{
+		conn = cur->data;
+		if (!memcmp(conn->cookie, cookie, 8) && !aim_sncmp(conn->sn, sn))
+			return conn;
+	}
+
+	return NULL;
+}
+
+PeerConnection *
+peer_connection_new(OscarData *od, OscarCapability type, const char *sn)
 {
-	OscarConnection *newconn;
-	IcbmCookie *cookie;
-	struct aim_odc_intdata *priv;
-	guint8 ck[8];
+	PeerConnection *conn;
+	GaimAccount *account;
+
+	account = gaim_connection_get_account(od->gc);
+
+	conn = g_new0(PeerConnection, 1);
+	conn->od = od;
+	conn->type = type;
+	conn->sn = g_strdup(sn);
+	conn->buffer_outgoing = gaim_circ_buffer_new(0);
+	conn->listenerfd = -1;
+	conn->fd = -1;
+	conn->lastactivity = time(NULL);
+	conn->use_proxy |= gaim_account_get_bool(account, "use_rv_proxy", FALSE);
 
-	if (!localip)
-		return NULL;
+	if (type == OSCAR_CAPABILITY_DIRECTIM)
+		memcpy(conn->magic, "ODC2", 4);
+	else if (type == OSCAR_CAPABILITY_SENDFILE)
+		memcpy(conn->magic, "OFT2", 4);
+
+	od->peer_connections = g_list_prepend(od->peer_connections, conn);
+
+	return conn;
+}
+
+static void
+peer_connection_close(PeerConnection *conn)
+{
+	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
+		peer_odc_close(conn);
+	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
+		peer_oft_close(conn);
 
-	if (mycookie) {
-		memcpy(ck, mycookie, 8);
-		aim_im_sendch2_odcrequest(sess, ck, TRUE, sn, localip, port);
-	} else
-		aim_im_sendch2_odcrequest(sess, ck, FALSE, sn, localip, port);
+	if (conn->watcher_incoming != 0)
+	{
+		gaim_input_remove(conn->watcher_incoming);
+		conn->watcher_incoming = 0;
+	}
+	if (conn->watcher_outgoing != 0)
+	{
+		gaim_input_remove(conn->watcher_outgoing);
+		conn->watcher_outgoing = 0;
+	}
+	if (conn->listenerfd != -1)
+	{
+		close(conn->listenerfd);
+		conn->listenerfd = -1;
+	}
+	if (conn->fd != -1)
+	{
+		close(conn->fd);
+		conn->fd = -1;
+	}
 
-	cookie = (IcbmCookie *)calloc(1, sizeof(IcbmCookie));
-	memcpy(cookie->cookie, ck, 8);
-	cookie->type = AIM_COOKIETYPE_OFTIM;
+	g_free(conn->buffer_incoming.data);
+	conn->buffer_incoming.data = NULL;
+	conn->buffer_incoming.len = 0;
+	conn->buffer_incoming.offset = 0;
+
+	gaim_circ_buffer_destroy(conn->buffer_outgoing);
+	conn->buffer_outgoing = gaim_circ_buffer_new(0);
 
-	/* this one is for the cookie */
-	priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata));
+	conn->flags &= ~PEER_CONNECTION_FLAG_IS_INCOMING;
+}
+
+static gboolean
+peer_connection_destroy_cb(gpointer data)
+{
+	PeerConnection *conn;
+
+	conn = data;
+
+	gaim_request_close_with_handle(conn);
+
+	peer_connection_close(conn);
 
-	memcpy(priv->cookie, ck, 8);
-	strncpy(priv->sn, sn, sizeof(priv->sn));
-	cookie->data = priv;
-	aim_cachecookie(sess, cookie);
-
-	/* XXX - switch to aim_cloneconn()? */
-	if (!(newconn = oscar_connection_new(sess, AIM_CONN_TYPE_LISTENER))) {
-		close(listenfd);
-		return NULL;
+	if (conn->xfer != NULL)
+	{
+		GaimXferStatusType status;
+		conn->xfer->data = NULL;
+		status = gaim_xfer_get_status(conn->xfer);
+		if ((status != GAIM_XFER_STATUS_DONE) &&
+			(status != GAIM_XFER_STATUS_CANCEL_LOCAL) &&
+			(status != GAIM_XFER_STATUS_CANCEL_REMOTE))
+		{
+			if ((conn->disconnect_reason == PEER_DISCONNECT_REMOTE_CLOSED) ||
+				(conn->disconnect_reason == PEER_DISCONNECT_REMOTE_REFUSED))
+				gaim_xfer_cancel_remote(conn->xfer);
+			else
+				gaim_xfer_cancel_local(conn->xfer);
+		}
+		gaim_xfer_unref(conn->xfer);
+		conn->xfer = NULL;
 	}
 
-	/* this one is for the conn */
-	priv = (struct aim_odc_intdata *)calloc(1, sizeof(struct aim_odc_intdata));
+	g_free(conn->proxyip);
+	g_free(conn->clientip);
+	g_free(conn->verifiedip);
+	gaim_circ_buffer_destroy(conn->buffer_outgoing);
 
-	memcpy(priv->cookie, ck, 8);
-	strncpy(priv->sn, sn, sizeof(priv->sn));
+	conn->od->peer_connections = g_list_remove(conn->od->peer_connections, conn);
+
+	g_free(conn);
+
+	return FALSE;
+}
 
-	newconn->fd = listenfd;
-	newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
-	newconn->internal = priv;
-	newconn->lastactivity = time(NULL);
+void
+peer_connection_destroy(PeerConnection *conn, PeerDisconnectReason reason)
+{
+	conn->disconnect_reason = reason;
+	if (conn->destroy_timeout != 0)
+		gaim_timeout_remove(conn->destroy_timeout);
+	peer_connection_destroy_cb(conn);
+}
 
-	return newconn;
+void
+peer_connection_schedule_destroy(PeerConnection *conn, PeerDisconnectReason reason)
+{
+	if (conn->destroy_timeout != 0)
+		/* Already taken care of */
+		return;
+
+	gaim_debug_info("oscar", "Scheduling destruction of peer connection\n");
+	conn->disconnect_reason = reason;
+	conn->destroy_timeout = gaim_timeout_add(0, peer_connection_destroy_cb, conn);
 }
 
+/*******************************************************************/
+/* Begin code for receiving data on a peer connection                */
+/*******************************************************************/
+
 /**
- * Connect directly to the given buddy for directim.
- *
- * This is a wrapper for oscar_connection_new.
- *
- * If addr is NULL, the socket is not created, but the connection is
- * allocated and setup to connect.
+ * This should be used to read ODC and OFT framing info.  It should
+ * NOT be used to read the payload sent across the connection (IMs,
+ * file data, etc), and it should NOT be used to read proxy negotiation
+ * headers.
  *
- * @param sess The Godly session.
- * @param sn The screen name we're connecting to.  I hope it's a girl...
- * @param addr Address to connect to.
- * @return The new connection.
+ * Unlike flap_connection_recv_cb(), this only reads one frame at a
+ * time.  This is done so that the watcher can be changed during the
+ * handling of the frame.  If the watcher is changed then this
+ * function will not read in any more data.  This happens when
+ * reading the payload of a direct IM frame, or when we're
+ * receiving a file from the remote user.  Once the data has been
+ * read, the watcher will be switched back to this function to
+ * continue reading the next frame.
  */
-OscarConnection *
-aim_odc_connect(OscarSession *sess, const char *sn, const char *addr, const guint8 *cookie)
+void
+peer_connection_recv_cb(gpointer data, gint source, GaimInputCondition cond)
 {
-	OscarConnection *newconn;
-	struct aim_odc_intdata *intdata;
+	PeerConnection *conn;
+	ssize_t read;
+	guint8 header[6];
+
+	conn = data;
+
+	/* Start reading a new ODC/OFT frame */
+	if (conn->buffer_incoming.data == NULL)
+	{
+		/* Peek at the first 6 bytes to get the length */
+		read = recv(conn->fd, &header, 6, MSG_PEEK);
 
-	if (!sess || !sn)
-		return NULL;
+		/* Check if the remote user closed the connection */
+		if (read == 0)
+		{
+			peer_connection_destroy(conn, PEER_DISCONNECT_REMOTE_CLOSED);
+			return;
+		}
+
+		/* If there was an error then close the connection */
+		if (read == -1)
+		{
+			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+				/* No worries */
+				return;
 
-	if (!(intdata = calloc(1, sizeof(struct aim_odc_intdata))))
-		return NULL;
-	memcpy(intdata->cookie, cookie, 8);
-	strncpy(intdata->sn, sn, sizeof(intdata->sn));
-	if (addr)
-		strncpy(intdata->ip, addr, sizeof(intdata->ip));
+			peer_connection_destroy(conn, PEER_DISCONNECT_LOST_CONNECTION);
+			return;
+		}
+
+		conn->lastactivity = time(NULL);
+
+		/* If we don't even have the first 6 bytes then do nothing */
+		if (read < 6)
+			return;
+
+		/* Read the first 6 bytes (magic string and frame length) */
+		read = recv(conn->fd, &header, 6, 0);
 
-	/* XXX - verify that non-blocking connects actually work */
-	if (!(newconn = oscar_connection_new(sess, AIM_CONN_TYPE_RENDEZVOUS))) {
-		free(intdata);
-		return NULL;
+		/* All ODC/OFT frames must start with a magic string */
+		if (memcmp(conn->magic, header, 4))
+		{
+			gaim_debug_warning("oscar", "Expecting magic string to "
+				"be %c%c%c%c but received magic string %c%c%c%c.  "
+				"Closing connection.\n",
+				conn->magic[0], conn->magic[1], conn->magic[2],
+				conn->magic[3], header[0], header[1], header[2], header[3]);
+			peer_connection_destroy(conn, PEER_DISCONNECT_INVALID_DATA);
+			return;
+		}
+
+		/* Initialize a new temporary ByteStream for incoming data */
+		conn->buffer_incoming.len = aimutil_get16(&header[4]) - 6;
+		conn->buffer_incoming.data = g_new(guint8, conn->buffer_incoming.len);
+		conn->buffer_incoming.offset = 0;
 	}
 
-	newconn->internal = intdata;
-	newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
+	/* Read data into the temporary buffer until it is complete */
+	read = recv(conn->fd,
+				&conn->buffer_incoming.data[conn->buffer_incoming.offset],
+				conn->buffer_incoming.len - conn->buffer_incoming.offset,
+				0);
+
+	/* Check if the remote user closed the connection */
+	if (read == 0)
+	{
+		peer_connection_destroy(conn, PEER_DISCONNECT_REMOTE_CLOSED);
+		return;
+	}
+
+	if (read == -1)
+	{
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			/* No worries */
+			return;
+
+		peer_connection_destroy(conn, PEER_DISCONNECT_LOST_CONNECTION);
+		return;
+	}
+
+	conn->lastactivity = time(NULL);
+	conn->buffer_incoming.offset += read;
+	if (conn->buffer_incoming.offset < conn->buffer_incoming.len)
+		/* Waiting for more data to arrive */
+		return;
+
+	/* We have a complete ODC/OFT frame!  Handle it and continue reading */
+	byte_stream_rewind(&conn->buffer_incoming);
+	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
+	{
+		peer_odc_recv_frame(conn, &conn->buffer_incoming);
+	}
+	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
+	{
+		peer_oft_recv_frame(conn, &conn->buffer_incoming);
+	}
+	g_free(conn->buffer_incoming.data);
+	conn->buffer_incoming.data = NULL;
+}
 
-	return newconn;
+/*******************************************************************/
+/* End code for receiving data on a peer connection                */
+/*******************************************************************/
+
+/*******************************************************************/
+/* Begin code for sending data on a peer connection                */
+/*******************************************************************/
+
+static void
+send_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	PeerConnection *conn;
+	gsize writelen;
+	ssize_t wrotelen;
+
+	conn = data;
+	writelen = gaim_circ_buffer_get_max_read(conn->buffer_outgoing);
+
+	if (writelen == 0)
+	{
+		gaim_input_remove(conn->watcher_outgoing);
+		conn->watcher_outgoing = 0;
+		return;
+	}
+
+	wrotelen = send(conn->fd, conn->buffer_outgoing->outptr, writelen, 0);
+	if (wrotelen <= 0)
+	{
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			/* No worries */
+			return;
+
+		if (conn->ready)
+			peer_connection_schedule_destroy(conn, PEER_DISCONNECT_LOST_CONNECTION);
+		else
+		{
+			/*
+			 * This could happen when unable to send a negotiation
+			 * frame to a peer proxy server.
+			 */
+			peer_connection_trynext(conn);
+		}
+		return;
+	}
+
+	gaim_circ_buffer_mark_read(conn->buffer_outgoing, wrotelen);
+	conn->lastactivity = time(NULL);
 }
 
 /**
- * Sometimes you just don't know with these kinds of people.
- *
- * @param sess The session.
- * @param conn The ODC connection of the incoming data.
- * @param frr The frame allocated for the incoming data.
- * @param bs It stands for "bologna sandwich."
- * @return Return 0 if no errors, otherwise return the error number.
+ * This should be called by OFT/ODC code to send a standard OFT or ODC
+ * frame across the peer connection along with some payload data.  Or
+ * maybe a file.  Anything, really.
  */
-static int
-handlehdr_odc(OscarSession *sess, OscarConnection *conn, FlapFrame *frr, ByteStream *bs)
+void
+peer_connection_send(PeerConnection *conn, ByteStream *bs)
 {
-	FlapFrame fr;
-	int ret = 0;
-	aim_rxcallback_t userfunc;
-	guint32 payloadlength;
-	guint16 flags, encoding;
-	char *snptr = NULL;
+	/* Add everything to our outgoing buffer */
+	gaim_circ_buffer_append(conn->buffer_outgoing, bs->data, bs->len);
 
-	fr.conn = conn;
+	/* If we haven't already started writing stuff, then start the cycle */
+	if (conn->watcher_outgoing == 0)
+	{
+		conn->watcher_outgoing = gaim_input_add(conn->fd,
+				GAIM_INPUT_WRITE, send_cb, conn);
+		send_cb(conn, conn->fd, 0);
+	}
+}
+
+/*******************************************************************/
+/* End code for sending data on a peer connection                  */
+/*******************************************************************/
 
-	/* AAA - ugly */
-	aim_bstream_setpos(bs, 20);
-	payloadlength = aimbs_get32(bs);
+/*******************************************************************/
+/* Begin code for establishing a peer connection                   */
+/*******************************************************************/
 
-	aim_bstream_setpos(bs, 24);
-	encoding = aimbs_get16(bs);
-
-	aim_bstream_setpos(bs, 30);
-	flags = aimbs_get16(bs);
+void
+peer_connection_finalize_connection(PeerConnection *conn)
+{
+	conn->watcher_incoming = gaim_input_add(conn->fd,
+			GAIM_INPUT_READ, peer_connection_recv_cb, conn);
 
-	aim_bstream_setpos(bs, 36);
-	/* XXX - create an aimbs_getnullstr function? */
-	snptr = aimbs_getstr(bs, 32); /* Next 32 bytes contain the sn, padded with null chars */
-
-	gaim_debug_misc("oscar", "faim: OFT frame: handlehdr_odc: %04x / %04x / %s\n", payloadlength, flags, snptr);
-
-	if (flags & 0x0008) {
-		if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, PEER_TYPE_DIRECTIMTYPING)))
-			ret = userfunc(sess, &fr, snptr, 2);
-	} else if (flags & 0x0004) {
-		if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, PEER_TYPE_DIRECTIMTYPING)))
-			ret = userfunc(sess, &fr, snptr, 1);
-	} else {
-		if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, PEER_TYPE_DIRECTIMTYPING)))
-			ret = userfunc(sess, &fr, snptr, 0);
+	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
+	{
+		/*
+		 * If we are connecting to them then send our cookie so they
+		 * can verify who we are.  Note: This doesn't seem to be
+		 * necessary, but it also doesn't seem to hurt.
+		 */
+		if (!(conn->flags & PEER_CONNECTION_FLAG_IS_INCOMING))
+			peer_odc_send_cookie(conn);
+	}
+	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
+	{
+		if (gaim_xfer_get_type(conn->xfer) == GAIM_XFER_SEND)
+		{
+			peer_oft_send_prompt(conn);
+		}
 	}
 
-	if ((payloadlength != 0) && (payloadlength != UINT_MAX)) {
-		char *msg;
-		int recvd = 0;
-		int i, isawaymsg;
-
-		isawaymsg = flags & 0x0001;
-
-		if (!(msg = calloc(1, payloadlength+1))) {
-			free(snptr);
-			return -ENOMEM;
-		}
-
-		while (payloadlength - recvd) {
-			if (payloadlength - recvd >= 1024)
-				i = aim_recv(conn->fd, &msg[recvd], 1024);
-			else
-				i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd);
-			if (i <= 0) {
-				free(msg);
-				free(snptr);
-				return -1;
-			}
-			recvd = recvd + i;
-			if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER)))
-				ret = userfunc(sess, &fr, snptr, (double)recvd / payloadlength);
-		}
-
-		if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, PEER_TYPE_DIRECTIMINCOMING)))
-			ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding, isawaymsg);
-
-		free(msg);
-	}
-
-	free(snptr);
-
-	return ret;
-}
-
-PeerConnection *
-aim_oft_createinfo(OscarSession *sess, const guint8 *cookie, const char *sn, const char *ip, guint16 port, guint32 size, guint32 modtime, char *filename, int send_or_recv, int method, int stage)
-{
-	PeerConnection *new;
-
-	if (!sess)
-		return NULL;
-
-	if (!(new = (PeerConnection *)calloc(1, sizeof(PeerConnection))))
-		return NULL;
-
-	new->sess = sess;
-	if (cookie)
-		memcpy(new->cookie, cookie, 8);
-	else
-		aim_icbm_makecookie(new->cookie);
-	if (ip)
-		new->clientip = strdup(ip);
-	else
-		new->clientip = NULL;
-	if (sn)
-		new->sn = strdup(sn);
-	else
-		new->sn = NULL;
-	new->method = method;
-	new->send_or_recv = send_or_recv;
-	new->stage = stage;
-	new->port = port;
-	new->xfer_reffed = FALSE;
-	new->success = FALSE;
-	new->fh.totfiles = 1;
-	new->fh.filesleft = 1;
-	new->fh.totparts = 1;
-	new->fh.partsleft = 1;
-	new->fh.totsize = size;
-	new->fh.size = size;
-	new->fh.modtime = modtime;
-	new->fh.checksum = 0xffff0000;
-	new->fh.rfrcsum = 0xffff0000;
-	new->fh.rfcsum = 0xffff0000;
-	new->fh.recvcsum = 0xffff0000;
-	strncpy(new->fh.idstring, "OFT_Windows ICBMFT V1.1 32", 31);
-	if (filename) {
-		strncpy(new->fh.name, filename, 63);
-		new->fh.name[63] = '\0';
-	}
-
-	sess->peer_connections = g_list_prepend(sess->peer_connections, new);
-
-	return new;
-}
-
-PeerProxyInfo *aim_rv_proxy_createinfo(OscarSession *sess, const guint8 *cookie,
-	guint16 port)
-{
-	PeerProxyInfo *proxy_info;
-
-	if (!(proxy_info = (PeerProxyInfo*)calloc(1, sizeof(PeerProxyInfo))))
-		return NULL;
-
-	proxy_info->sess = sess;
-	proxy_info->port = port;
-	proxy_info->packet_ver = AIM_RV_PROXY_PACKETVER_DFLT;
-	proxy_info->unknownA = AIM_RV_PROXY_UNKNOWNA_DFLT;
-
-	if (cookie)
-		memcpy(proxy_info->cookie, cookie, 8);
-
-	return proxy_info;
+	/*
+	 * Tell the remote user that we're connected (which may also imply
+	 * that we've accepted their request).
+	 */
+	if (!(conn->flags & PEER_CONNECTION_FLAG_IS_INCOMING))
+		aim_im_sendch2_connected(conn);
 }
 
 /**
- * Remove the given PeerConnection from the PeerConnection linked list, and
- * then free its memory.
- *
- * @param sess The session.
- * @param peer_connection The PeerConnection that we're destroying.
- * @return Return 0 if no errors, otherwise return the error number.
+ * We tried to make an outgoing connection to a remote user.  It
+ * either connected or failed to connect.
  */
-int
-aim_oft_destroyinfo(PeerConnection *peer_connection)
+static void
+peer_connection_established_cb(gpointer data, gint source, GaimInputCondition cond)
 {
-	OscarSession *sess;
-
-	if (!peer_connection || !(sess = peer_connection->sess))
-		return -EINVAL;
-
-	sess->peer_connections = g_list_remove(sess->peer_connections, peer_connection);
-
-	free(peer_connection->sn);
-	free(peer_connection->proxyip);
-	free(peer_connection->clientip);
-	free(peer_connection->verifiedip);
-	free(peer_connection);
+	NewPeerConnectionData *new_conn_data;
+	GaimConnection *gc;
+	PeerConnection *conn;
 
-	return 0;
-}
+	new_conn_data = data;
+	gc = new_conn_data->gc;
+	conn = new_conn_data->conn;
+	g_free(new_conn_data);
 
-/**
- * Creates a listener socket so the other dude can connect to us.
- *
- * You'll want to set up some kind of watcher on this socket.
- * When the state changes, call aim_handlerendconnection with
- * the connection returned by this.  aim_handlerendconnection
- * will accept the pending connection and stop listening.
- *
- * @param sess The session.
- * @param peer_connection File transfer information associated with this
- *        connection.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int
-aim_sendfile_listen(OscarSession *sess, PeerConnection *peer_connection, int listenfd)
-{
-	if (!peer_connection)
-		return -EINVAL;
-
-	if (!(peer_connection->conn = oscar_connection_new(sess, AIM_CONN_TYPE_LISTENER))) {
-		close(listenfd);
-		return -ENOMEM;
+	if (!g_list_find(gaim_connections_get_all(), gc))
+	{
+		if (source >= 0)
+			close(source);
+		return;
 	}
 
-	peer_connection->conn->fd = listenfd;
-	peer_connection->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
-	peer_connection->conn->lastactivity = time(NULL);
-
-	return 0;
-}
-
-/**
- * Extract an &aim_fileheader_t from the given buffer.
- *
- * @param bs The should be from an incoming rendezvous packet.
- * @return A pointer to new struct on success, or NULL on error.
- */
-static PeerFrame *
-aim_oft_getheader(ByteStream *bs)
-{
-	PeerFrame *fh;
-
-	if (!(fh = calloc(1, sizeof(PeerFrame))))
-		return NULL;
+	if (source < 0)
+	{
+		peer_connection_trynext(conn);
+		return;
+	}
 
-	/* The bstream should be positioned after the hdrtype. */
-	aimbs_getrawbuf(bs, fh->bcookie, 8);
-	fh->encrypt = aimbs_get16(bs);
-	fh->compress = aimbs_get16(bs);
-	fh->totfiles = aimbs_get16(bs);
-	fh->filesleft = aimbs_get16(bs);
-	fh->totparts = aimbs_get16(bs);
-	fh->partsleft = aimbs_get16(bs);
-	fh->totsize = aimbs_get32(bs);
-	fh->size = aimbs_get32(bs);
-	fh->modtime = aimbs_get32(bs);
-	fh->checksum = aimbs_get32(bs);
-	fh->rfrcsum = aimbs_get32(bs);
-	fh->rfsize = aimbs_get32(bs);
-	fh->cretime = aimbs_get32(bs);
-	fh->rfcsum = aimbs_get32(bs);
-	fh->nrecvd = aimbs_get32(bs);
-	fh->recvcsum = aimbs_get32(bs);
-	aimbs_getrawbuf(bs, (guchar *)fh->idstring, 32);
-	fh->flags = aimbs_get8(bs);
-	fh->lnameoffset = aimbs_get8(bs);
-	fh->lsizeoffset = aimbs_get8(bs);
-	aimbs_getrawbuf(bs, (guchar *)fh->dummy, 69);
-	aimbs_getrawbuf(bs, (guchar *)fh->macfileinfo, 16);
-	fh->nencode = aimbs_get16(bs);
-	fh->nlanguage = aimbs_get16(bs);
-	aimbs_getrawbuf(bs, (guchar *)fh->name, 64); /* XXX - filenames longer than 64B */
-	fh->name[63] = '\0';
+	conn->fd = source;
 
-	return fh;
+	peer_connection_finalize_connection(conn);
 }
 
 /**
- * Fills a buffer with network-order fh data
+ * This is the watcher callback for any listening socket that is
+ * waiting for a peer to connect.  When a peer connects we set the
+ * input watcher to start reading data from the peer.
  *
- * @param bs A bstream to fill -- automatically initialized
- * @param fh A PeerFrame to get data from.
- * @return Return non-zero on error.
+ * To make sure that the connection is with the intended person and
+ * not with a malicious middle man, we don't send anything until we've
+ * received a peer frame from the remote user and have verified that
+ * the cookie in the peer frame matches the cookie that was exchanged
+ * in the channel 2 ICBM.
  */
-static int
-aim_oft_buildheader(ByteStream *bs, PeerFrame *fh)
+void
+peer_connection_listen_cb(gpointer data, gint source, GaimInputCondition cond)
 {
-	guint8 *hdr;
+	PeerConnection *conn;
+	OscarData *od;
+	GaimConnection *gc;
+	GaimAccount *account;
+	struct sockaddr addr;
+	socklen_t addrlen = sizeof(addr);
 
-	if (!bs || !fh)
-		return -EINVAL;
-
-	if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8)))
-		return -ENOMEM;
+	conn = data;
+	od = conn->od;
+	gc = od->gc;
+	account = gaim_connection_get_account(gc);
 
-	aim_bstream_init(bs, hdr, 0x100 - 8);
-	aimbs_putraw(bs, fh->bcookie, 8);
-	aimbs_put16(bs, fh->encrypt);
-	aimbs_put16(bs, fh->compress);
-	aimbs_put16(bs, fh->totfiles);
-	aimbs_put16(bs, fh->filesleft);
-	aimbs_put16(bs, fh->totparts);
-	aimbs_put16(bs, fh->partsleft);
-	aimbs_put32(bs, fh->totsize);
-	aimbs_put32(bs, fh->size);
-	aimbs_put32(bs, fh->modtime);
-	aimbs_put32(bs, fh->checksum);
-	aimbs_put32(bs, fh->rfrcsum);
-	aimbs_put32(bs, fh->rfsize);
-	aimbs_put32(bs, fh->cretime);
-	aimbs_put32(bs, fh->rfcsum);
-	aimbs_put32(bs, fh->nrecvd);
-	aimbs_put32(bs, fh->recvcsum);
-	aimbs_putraw(bs, (guchar *)fh->idstring, 32);
-	aimbs_put8(bs, fh->flags);
-	aimbs_put8(bs, fh->lnameoffset);
-	aimbs_put8(bs, fh->lsizeoffset);
-	aimbs_putraw(bs, (guchar *)fh->dummy, 69);
-	aimbs_putraw(bs, (guchar *)fh->macfileinfo, 16);
-	aimbs_put16(bs, fh->nencode);
-	aimbs_put16(bs, fh->nlanguage);
-	aimbs_putraw(bs, (guchar *)fh->name, 64); /* XXX - filenames longer than 64B */
+	gaim_debug_info("oscar", "Accepting connection on listener socket.\n");
+
+	conn->fd = accept(conn->listenerfd, &addr, &addrlen);
+	if (conn->fd == -1)
+	{
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			/* No connection yet--no worries */
+			/* TODO: Hmm, but they SHOULD be connected if we're here, right? */
+			return;
 
-	return 0;
+		peer_connection_trynext(conn);
+		return;
+	}
+
+	if ((addr.sa_family != PF_INET) && (addr.sa_family != PF_INET6))
+	{
+		/* Invalid connection type?!  Continue waiting. */
+		close(conn->fd);
+		return;
+	}
+
+	fcntl(conn->fd, F_SETFL, O_NONBLOCK);
+	gaim_input_remove(conn->watcher_incoming);
+
+	peer_connection_finalize_connection(conn);
 }
 
 /**
- * Create an OFT packet based on the given information, and send it on its merry way.
- *
- * @param sess The session.
- * @param type The subtype of the OFT packet we're sending.
- * @param peer_connection The PeerConnection with the connection and OFT
- *        info we're sending.
- * @return Return 0 if no errors, otherwise return the error number.
+ * We've just opened a listener socket, so we send the remote
+ * user an ICBM and ask them to connect to us.
  */
-int aim_oft_sendheader(OscarSession *sess, guint16 type, PeerConnection *peer_connection)
+static void
+peer_connection_establish_listener_cb(int listenerfd, gpointer data)
 {
-	FlapFrame *fr;
-
-	if (!sess || !peer_connection || !peer_connection->conn || (peer_connection->conn->type != AIM_CONN_TYPE_RENDEZVOUS))
-		return -EINVAL;
+	NewPeerConnectionData *new_conn_data;
+	PeerConnection *conn;
+	OscarData *od;
+	GaimConnection *gc;
+	GaimAccount *account;
+	GaimConversation *conv;
+	char *tmp;
+	FlapConnection *bos_conn;
+	const char *listener_ip;
+	unsigned short listener_port;
 
-#if 0
-	/*
-	 * If you are receiving a file, the cookie should be null, if you are sending a
-	 * file, the cookie should be the same as the one used in the ICBM negotiation
-	 * SNACs.
-	 */
-	fh->lnameoffset = 0x1a;
-	fh->lsizeoffset = 0x10;
+	new_conn_data = data;
+	gc = new_conn_data->gc;
+	conn = new_conn_data->conn;
+	g_free(new_conn_data);
 
-	/* These should be the same as charset and charsubset in ICBMs */
-	fh->nencode = 0x0000;
-	fh->nlanguage = 0x0000;
-#endif
-
-	aim_oft_dirconvert_tostupid(peer_connection->fh.name);
-
-	if (!(fr = flap_frame_new(sess, peer_connection->conn, AIM_FRAMETYPE_OFT, type, 0)))
-		return -ENOMEM;
-
-	if (aim_oft_buildheader(&fr->data, &peer_connection->fh) == -1) {
-		aim_frame_destroy(fr);
-		return -ENOMEM;
+	if (!g_list_find(gaim_connections_get_all(), gc))
+	{
+		if (listenerfd != -1)
+			close(listenerfd);
+		return;
 	}
 
-	memcpy(fr->hdr.rend.magic, "OFT2", 4);
-	fr->hdr.rend.hdrlen = aim_bstream_curpos(&fr->data) + 8;
+	if (listenerfd == -1)
+	{
+		/* Could not open listener socket */
+		peer_connection_trynext(conn);
+		return;
+	}
+
+	od = conn->od;
+	account = gaim_connection_get_account(gc);
+	conn->listenerfd = listenerfd;
 
-	aim_tx_enqueue(sess, fr);
+	/* Send the "please connect to me!" ICBM */
+	bos_conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
+	listener_ip = gaim_network_get_my_ip(bos_conn->fd);
+	listener_port = gaim_network_get_port_from_fd(conn->listenerfd);
+	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
+	{
+		aim_im_sendch2_odc_requestdirect(od,
+				conn->cookie, conn->sn, gaim_network_ip_atoi(listener_ip),
+				listener_port, ++conn->lastrequestnumber);
 
-	return 0;
+		/* Print a message to a local conversation window */
+		conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, conn->sn);
+		tmp = g_strdup_printf(_("Asking %s to connect to us at %s:%hu for "
+				"Direct IM."), conn->sn, listener_ip, listener_port);
+		gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
+		g_free(tmp);
+	}
+	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
+	{
+		aim_im_sendch2_sendfile_requestdirect(od,
+				conn->cookie, conn->sn,
+				gaim_network_ip_atoi(listener_ip),
+				listener_port, ++conn->lastrequestnumber,
+				(const gchar *)conn->xferdata.name,
+				conn->xferdata.size, conn->xferdata.totfiles);
+	}
 }
 
 /**
- * Create a rendezvous "init recv" packet and send it on its merry way.
- * This is the first packet sent to the proxy server by the second client
- * involved in this rendezvous proxy session.
- *
- * @param sess The session.
- * @param proxy_info Changable pieces of data for this packet
- * @return Return 0 if no errors, otherwise return the error number.
+ * Try to establish the given PeerConnection using a defined
+ * sequence of steps.
  */
-int
-aim_rv_proxy_init_recv(PeerProxyInfo *proxy_info)
+void
+peer_connection_trynext(PeerConnection *conn)
 {
-#if 0
-	aim_tlvlist_t *tlvlist_sendfile;
-#endif
-	ByteStream bs;
-	guint8 *bs_raw;
-	guint16 packet_len;
-	guint8 sn_len;
-	int err;
+	NewPeerConnectionData *new_conn_data;
+	GaimAccount *account;
 
-	err = 0;
+	new_conn_data = g_new(NewPeerConnectionData, 1);
+	new_conn_data->gc = conn->od->gc;
+	new_conn_data->conn = conn;
+
+	account = gaim_connection_get_account(new_conn_data->gc);
 
-	if (!proxy_info)
-		return -EINVAL;
+	/*
+	 * Close any remnants of a previous failed connection attempt.
+	 */
+	peer_connection_close(conn);
 
-	sn_len = strlen(proxy_info->sess->sn);
-	packet_len = 2 + 2	/* packet_len, packet_ver */
-		+ 2 + 4		/* cmd_type,  unknownA */
-		+ 2		/* flags */
-		+ 1 + sn_len	/* Length/value pair for screenname */
-		+ 8		/* ICBM Cookie */
-		+ 2		/* port */
-		+ 2 + 2 + 16;	/* TLV for Filesend capability block */
+	/*
+	 * 1. Attempt to connect to the remote user using their verifiedip.
+	 */
+	if (!(conn->flags & PEER_CONNECTION_FLAG_TRIED_VERIFIEDIP) &&
+		(conn->verifiedip != NULL) && (conn->port != 0) && (!conn->use_proxy))
+	{
+		conn->flags |= PEER_CONNECTION_FLAG_TRIED_VERIFIEDIP;
 
-	if (!(bs_raw = malloc(packet_len)))
-		return -ENOMEM;
+		if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
+		{
+			gchar *tmp;
+			GaimConversation *conv;
+			tmp = g_strdup_printf(_("Attempting to connect to %s:%hu."),
+					conn->verifiedip, conn->port);
+			conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, conn->sn);
+			gaim_conversation_write(conv, NULL, tmp,
+					GAIM_MESSAGE_SYSTEM, time(NULL));
+			g_free(tmp);
+		}
 
-	aim_bstream_init(&bs, bs_raw, packet_len);
-	aimbs_put16(&bs, packet_len - 2); /* Length includes only packets after length marker */
-	aimbs_put16(&bs, proxy_info->packet_ver);
-	aimbs_put16(&bs, AIM_RV_PROXY_INIT_RECV);
-	aimbs_put32(&bs, proxy_info->unknownA);
-	aimbs_put16(&bs, proxy_info->flags);
-	aimbs_put8(&bs, sn_len);
-	aimbs_putraw(&bs, (const guchar *)proxy_info->sess->sn, sn_len);
-	aimbs_put16(&bs, proxy_info->port);
-	aimbs_putraw(&bs, proxy_info->cookie, 8);
+		if (gaim_proxy_connect(account, conn->verifiedip, conn->port,
+				peer_connection_established_cb, new_conn_data) == 0)
+		{
+			/* Connecting... */
+			return;
+		}
+	}
 
-	aimbs_put16(&bs, 0x0001);		/* Type */
-	aimbs_put16(&bs, 16);			/* Length */
-	aimbs_putcaps(&bs, AIM_CAPS_SENDFILE);	/* Value */
-
+	/*
+	 * 2. Attempt to connect to the remote user using their clientip.
+	 */
+	if (!(conn->flags & PEER_CONNECTION_FLAG_TRIED_CLIENTIP) &&
+		(conn->clientip != NULL) && (conn->port != 0) && (!conn->use_proxy))
+	{
+		conn->flags |= PEER_CONNECTION_FLAG_TRIED_CLIENTIP;
 
-#if 0
-	/* TODO: Use built-in TLV */
-	aim_tlvlist_add_caps(&tlvlist_sendfile, 0x0001, AIM_CAPS_SENDFILE);
-	aim_tlvlist_write(&bs, &tlvlist_sendfile);
-#endif
-
-	aim_bstream_rewind(&bs);
-	if (aim_bstream_send(&bs, proxy_info->conn, packet_len) != packet_len)
-		err = errno;
-	proxy_info->conn->lastactivity = time(NULL);
-
-#if 0
-	aim_tlvlist_free(tlvlist_sendfile);
-#endif
-	free(bs_raw);
+		if (strcmp(conn->verifiedip, conn->clientip))
+		{
+			if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
+			{
+				gchar *tmp;
+				GaimConversation *conv;
+				tmp = g_strdup_printf(_("Attempting to connect to %s:%hu."),
+						conn->clientip, conn->port);
+				conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, conn->sn);
+				gaim_conversation_write(conv, NULL, tmp,
+						GAIM_MESSAGE_SYSTEM, time(NULL));
+				g_free(tmp);
+			}
 
-	return err;
-}
-
+			if (gaim_proxy_connect(account, conn->clientip, conn->port,
+					peer_connection_established_cb, new_conn_data) == 0)
+			{
+				/* Connecting... */
+				return;
+			}
+		}
+	}
 
-/**
- * Create a rendezvous "init send" packet and send it on its merry way.
- * This is the first packet sent to the proxy server by the client
- * first indicating that this will be a proxied connection
- *
- * @param sess The session.
- * @param proxy_info Changable pieces of data for this packet
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int
-aim_rv_proxy_init_send(PeerProxyInfo *proxy_info)
-{
-#if 0
-	aim_tlvlist_t *tlvlist_sendfile;
-#endif
-	ByteStream bs;
-	guint8 *bs_raw;
-	guint16 packet_len;
-	guint8 sn_len;
-	int err;
+	/*
+	 * 3. Attempt to have the remote user connect to us (using both
+	 *    our verifiedip and our clientip).
+	 */
+	if (!(conn->flags & PEER_CONNECTION_FLAG_TRIED_INCOMING) &&
+		(!conn->use_proxy))
+	{
+		conn->flags |= PEER_CONNECTION_FLAG_TRIED_INCOMING;
 
-	err = 0;
+		/*
+		 * Remote user is connecting to us, so we'll need to verify
+		 * that the user who connected is our friend.
+		 */
+		conn->flags |= PEER_CONNECTION_FLAG_IS_INCOMING;
 
-	if (!proxy_info)
-		return -EINVAL;
+		if (gaim_network_listen_range(5190, 5290, SOCK_STREAM,
+				peer_connection_establish_listener_cb, new_conn_data))
+		{
+			/* Opening listener socket... */
+			return;
+		}
+	}
 
-	sn_len = strlen(proxy_info->sess->sn);
-	packet_len = 2 + 2	/* packet_len, packet_ver */
-		+ 2 + 4		/* cmd_type,  unknownA */
-		+ 2		/* flags */
-		+ 1 + sn_len	/* Length/value pair for screenname */
-		+ 8		/* ICBM Cookie */
-		+ 2 + 2 + 16;	/* TLV for Filesend capability block */
+	/*
+	 * 4. Attempt to have both users connect to an intermediate proxy
+	 *    server.
+	 */
+	if (!(conn->flags & PEER_CONNECTION_FLAG_TRIED_PROXY))
+	{
+		conn->flags |= PEER_CONNECTION_FLAG_TRIED_PROXY;
 
-	if (!(bs_raw = malloc(packet_len)))
-		return -ENOMEM;
-
-	aim_bstream_init(&bs, bs_raw, packet_len);
-	aimbs_put16(&bs, packet_len - 2); /* Length includes only packets after length marker */
-	aimbs_put16(&bs, proxy_info->packet_ver);
-	aimbs_put16(&bs, AIM_RV_PROXY_INIT_SEND);
-	aimbs_put32(&bs, proxy_info->unknownA);
-	aimbs_put16(&bs, proxy_info->flags);
-	aimbs_put8(&bs, sn_len);
-	aimbs_putraw(&bs, (const guchar *)proxy_info->sess->sn, sn_len);
-	aimbs_putraw(&bs, proxy_info->cookie, 8);
+		/*
+		 * If we initiate the proxy connection, then the remote user
+		 * could be anyone, so we need to verify that the user who
+		 * connected is our friend.
+		 */
+		if (!conn->use_proxy)
+			conn->flags |= PEER_CONNECTION_FLAG_IS_INCOMING;
 
-	aimbs_put16(&bs, 0x0001);		/* Type */
-	aimbs_put16(&bs, 16);			/* Length */
-	aimbs_putcaps(&bs, AIM_CAPS_SENDFILE);	/* Value */
-
-	/* TODO: Use built-in TLV */
-#if 0
-	aim_tlvlist_add_caps(&tlvlist_sendfile, 0x0001, AIM_CAPS_SENDFILE);
-	aim_tlvlist_write(&bs, &tlvlist_sendfile);
-#endif
+		if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
+		{
+			gchar *tmp;
+			GaimConversation *conv;
+			tmp = g_strdup_printf(_("Attempting to connect via proxy server."));
+			conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, conn->sn);
+			gaim_conversation_write(conv, NULL, tmp,
+					GAIM_MESSAGE_SYSTEM, time(NULL));
+			g_free(tmp);
+		}
 
-	aim_bstream_rewind(&bs);
-	if (aim_bstream_send(&bs, proxy_info->conn, packet_len) != packet_len)
-		err = errno;
-	proxy_info->conn->lastactivity = time(NULL);
+		if (gaim_proxy_connect(account,
+				(conn->proxyip != NULL) ? conn->proxyip : PEER_PROXY_SERVER,
+				PEER_PROXY_PORT,
+				peer_proxy_connection_established_cb, new_conn_data) == 0)
+		{
+			/* Connecting... */
+			return;
+		}
+	}
 
-#if 0
-	aim_tlvlist_free(tlvlist_sendfile);
-#endif
-	free(bs_raw);
+	g_free(new_conn_data);
 
-	return err;
+	/* Give up! */
+	peer_connection_destroy(conn, PEER_DISCONNECT_COULD_NOT_CONNECT);
 }
 
 /**
- * Handle incoming data on a rendezvous connection.  This is analogous to the
- * consumesnac function in rxhandlers.c, and I really think this should probably
- * be in rxhandlers.c as well, but I haven't finished cleaning everything up yet.
- *
- * @param sess The session.
- * @param fr The frame allocated for the incoming data.
- * @return Return 0 if the packet was handled correctly, otherwise return the
- *         error number.
+ * Initiate a peer connection with someone.
  */
-int
-aim_rxdispatch_rendezvous(OscarSession *sess, FlapFrame *fr)
+void
+peer_connection_propose(OscarData *od, OscarCapability type, const char *sn)
 {
-	OscarConnection *conn = fr->conn;
-	int ret = 1;
+	PeerConnection *conn;
+	GaimAccount *account;
+
+	account = gaim_connection_get_account(od->gc);
 
-	if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
-		if (fr->hdr.rend.type == 0x0001)
-			ret = handlehdr_odc(sess, conn, fr, &fr->data);
-		else
-			gaim_debug_info("oscar", "ODC directim frame unknown, type is %04x\n", fr->hdr.rend.type);
+	if (type == OSCAR_CAPABILITY_DIRECTIM)
+	{
+		conn = peer_connection_find_by_type(od, sn, type);
+		if (conn != NULL)
+		{
+			if (conn->ready)
+			{
+				GaimConversation *conv;
 
-	} else {
-		aim_rxcallback_t userfunc;
-		PeerFrame *header = aim_oft_getheader(&fr->data);
-		aim_oft_dirconvert_fromstupid(header->name); /* XXX - This should be client-side */
+				gaim_debug_info("oscar", "Already have a direct IM "
+						"session with %s.\n", sn);
+				account = gaim_connection_get_account(od->gc);
+				conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM,
+						sn, account);
+				if (conv != NULL)
+					gaim_conversation_present(conv);
+				return;
+			}
 
-		if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, fr->hdr.rend.type)))
-			ret = userfunc(sess, fr, conn, header->bcookie, header);
-
-		free(header);
+			/* Cancel the old connection and try again */
+			peer_connection_destroy(conn, PEER_DISCONNECT_RETRYING);
+		}
 	}
 
-	if (ret == -1)
-		aim_conn_close(sess, conn);
+	conn = peer_connection_new(od, type, sn);
+	conn->flags |= PEER_CONNECTION_FLAG_INITIATED_BY_ME;
+	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
+	aim_icbm_makecookie(conn->cookie);
+
+	peer_connection_trynext(conn);
+}
+
+/**
+ * Someone else wants to establish a peer connection with us,
+ * and we said yes.
+ */
+static void
+peer_connection_got_proposition_yes_cb(gpointer data, gint id)
+{
+	PeerConnection *conn;
+
+	conn = data;
 
-	return ret;
+	conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
+	peer_connection_trynext(conn);
+}
+
+/**
+ * Someone else wants to establish a peer connection with us,
+ * and we said no.
+ *
+ * "Well, one time my friend asked me if I wanted to play the
+ *  piccolo.  But I said no."
+ */
+static void
+peer_connection_got_proposition_no_cb(gpointer data, gint id)
+{
+	PeerConnection *conn;
+
+	conn = data;
+
+	aim_im_denytransfer(conn->od, conn->sn, conn->cookie,
+			AIM_TRANSFER_DENY_DECLINE);
+	peer_connection_destroy(conn, PEER_DISCONNECT_LOCAL_CLOSED);
 }
 
 /**
- * Handle incoming data on a rendezvous proxy connection.  This is similar to
- * aim_rxdispatch_rendezvous above and should probably be kept with that function.
- *
- * @param sess The session.
- * @param fr The frame allocated for the incoming data.
- * @return Return 0 if the packet was handled correctly, otherwise return the
- *         error number.
+ * Someone else wants to establish a peer connection with us.
  */
-PeerProxyInfo *
-aim_rv_proxy_read(OscarSession *sess, OscarConnection *conn)
+void
+peer_connection_got_proposition(OscarData *od, const gchar *sn, const gchar *message, IcbmArgsCh2 *args)
 {
-	ByteStream bs_hdr;
-	guint8 hdr_buf[AIM_RV_PROXY_HDR_LEN];
-	ByteStream bs_body; /* The body (everything but the header) of the packet */
-	guint8 *body_buf = NULL;
-	guint8 body_len;
+	GaimConnection *gc;
+	GaimAccount *account;
+	PeerConnection *conn;
+	gchar *buf;
+
+	gc = od->gc;
+	account = gaim_connection_get_account(gc);
 
-	char str_ip[30] = {""};
-	guint8 ip_temp[4];
+	/*
+	 * If we have a connection with this same cookie then they are
+	 * probably just telling us they weren't able to connect to us
+	 * and we should try connecting to them, instead.  Or they want
+	 * to go through a proxy.
+	 */
+	conn = peer_connection_find_by_cookie(od, sn, args->cookie);
+	if ((conn != NULL) && (conn->type == args->type))
+	{
+		gaim_debug_info("oscar", "Remote user wants to try a "
+				"different connection method\n");
+		g_free(conn->proxyip);
+		g_free(conn->clientip);
+		g_free(conn->verifiedip);
+		if (args->use_proxy)
+			conn->proxyip = g_strdup(args->proxyip);
+		else
+			conn->proxyip = NULL;
+		conn->verifiedip = g_strdup(args->verifiedip);
+		conn->clientip = g_strdup(args->clientip);
+		conn->port = args->port;
+		conn->use_proxy |= args->use_proxy;
+		conn->lastrequestnumber++;
+		peer_connection_trynext(conn);
+		return;
+	}
 
-	guint16 len;
-	PeerProxyInfo *proxy_info;
+	/* If this is a direct IM, then close any existing session */
+	if (args->type == OSCAR_CAPABILITY_DIRECTIM)
+	{
+		conn = peer_connection_find_by_type(od, sn, args->type);
+		if (conn != NULL)
+		{
+			/* Close the old direct IM and start a new one */
+			gaim_debug_info("oscar", "Received new direct IM request "
+				"from %s.  Destroying old connection.\n", sn);
+			peer_connection_destroy(conn, PEER_DISCONNECT_REMOTE_CLOSED);
+		}
+	}
 
-	if(!(proxy_info = malloc(sizeof(PeerProxyInfo))))
-		return NULL;
+	/* Check for proper arguments */
+	if (args->type == OSCAR_CAPABILITY_SENDFILE)
+	{
+		if ((args->info.sendfile.filename == NULL) ||
+			(args->info.sendfile.totsize == 0) ||
+			(args->info.sendfile.totfiles == 0))
+		{
+			gaim_debug_warning("oscar",
+					"%s tried to send you a file with incomplete "
+					"information.\n", sn);
+			return;
+		}
+	}
 
-	aim_bstream_init(&bs_hdr, hdr_buf, AIM_RV_PROXY_HDR_LEN);
-	if (aim_bstream_recv(&bs_hdr, conn->fd, AIM_RV_PROXY_HDR_LEN) == AIM_RV_PROXY_HDR_LEN) {
-		aim_bstream_rewind(&bs_hdr);
-		len = aimbs_get16(&bs_hdr);
-		proxy_info->packet_ver = aimbs_get16(&bs_hdr);
-		proxy_info->cmd_type = aimbs_get16(&bs_hdr);
-		proxy_info->unknownA = aimbs_get32(&bs_hdr);
-		proxy_info->flags = aimbs_get16(&bs_hdr);
-		if(proxy_info->cmd_type == AIM_RV_PROXY_READY) {
-			/* Do a little victory dance
-			 * A ready packet contains no additional information */
-		} else if(proxy_info->cmd_type == AIM_RV_PROXY_ERROR) {
-			if(len == AIM_RV_PROXY_ERROR_LEN - 2) {
-				body_len = AIM_RV_PROXY_ERROR_LEN - AIM_RV_PROXY_HDR_LEN;
-				body_buf = malloc(body_len);
-				aim_bstream_init(&bs_body, body_buf, body_len);
-				if (aim_bstream_recv(&bs_body, conn->fd, body_len) == body_len) {
-					aim_bstream_rewind(&bs_body);
-					proxy_info->err_code = aimbs_get16(&bs_body);
-				} else {
-					gaim_debug_warning("oscar","error reading rv proxy error packet\n");
-					aim_conn_close(sess, conn);
-					free(proxy_info);
-					proxy_info = NULL;
-				}
-			} else {
-				gaim_debug_warning("oscar","invalid length for proxy error packet\n");
-				free(proxy_info);
-				proxy_info = NULL;
-			}
-		} else if(proxy_info->cmd_type == AIM_RV_PROXY_ACK) {
-			if(len == AIM_RV_PROXY_ACK_LEN - 2) {
-				body_len = AIM_RV_PROXY_ACK_LEN - AIM_RV_PROXY_HDR_LEN;
-				body_buf = malloc(body_len);
-				aim_bstream_init(&bs_body, body_buf, body_len);
-				if (aim_bstream_recv(&bs_body, conn->fd, body_len) == body_len) {
-					int i;
-					aim_bstream_rewind(&bs_body);
-					proxy_info->port = aimbs_get16(&bs_body);
-					for(i=0; i<4; i++)
-						ip_temp[i] = aimbs_get8(&bs_body);
-					snprintf(str_ip, sizeof(str_ip), "%hhu.%hhu.%hhu.%hhu",
-						ip_temp[0], ip_temp[1],
-						ip_temp[2], ip_temp[3]);
-					proxy_info->ip = strdup(str_ip);
-				} else {
-					gaim_debug_warning("oscar","error reading rv proxy error packet\n");
-					aim_conn_close(sess, conn);
-					free(proxy_info);
-					proxy_info = NULL;
-				}
-			} else {
-				gaim_debug_warning("oscar","invalid length for proxy error packet\n");
-				free(proxy_info);
-				proxy_info = NULL;
-			}
-		} else {
-			gaim_debug_warning("oscar","unknown type for aim rendezvous proxy packet\n");
+	conn = peer_connection_new(od, args->type, sn);
+	memcpy(conn->cookie, args->cookie, 8);
+	if (args->use_proxy)
+		conn->proxyip = g_strdup(args->proxyip);
+	conn->clientip = g_strdup(args->clientip);
+	conn->verifiedip = g_strdup(args->verifiedip);
+	conn->port = args->port;
+	conn->use_proxy |= args->use_proxy;
+	conn->lastrequestnumber++;
+
+	if (args->type == OSCAR_CAPABILITY_DIRECTIM)
+	{
+		buf = g_strdup_printf(_("%s has just asked to directly connect to %s"),
+				sn, gaim_account_get_username(account));
+
+		gaim_request_action(conn, NULL, buf,
+						_("This requires a direct connection between "
+						  "the two computers and is necessary for IM "
+						  "Images.  Because your IP address will be "
+						  "revealed, this may be considered a privacy "
+						  "risk."),
+						GAIM_DEFAULT_ACTION_NONE, conn, 2,
+						_("_Connect"), G_CALLBACK(peer_connection_got_proposition_yes_cb),
+						_("Cancel"), G_CALLBACK(peer_connection_got_proposition_no_cb));
+	}
+	else if (args->type == OSCAR_CAPABILITY_SENDFILE)
+	{
+		gchar *filename;
+
+		conn->xfer = gaim_xfer_new(account, GAIM_XFER_RECEIVE, sn);
+		conn->xfer->data = conn;
+		gaim_xfer_ref(conn->xfer);
+		gaim_xfer_set_size(conn->xfer, args->info.sendfile.totsize);
+
+		/* Set the file name */
+		if (g_utf8_validate(args->info.sendfile.filename, -1, NULL))
+			filename = g_strdup(args->info.sendfile.filename);
+		else
+			filename = gaim_utf8_salvage(args->info.sendfile.filename);
+
+		if (args->info.sendfile.subtype == AIM_OFT_SUBTYPE_SEND_DIR)
+		{
+			/*
+			 * If they are sending us a directory then the last character
+			 * of the file name will be an asterisk.  We don't want to
+			 * save stuff to a directory named "*" so we remove the
+			 * asterisk from the file name.
+			 */
+			char *tmp = strrchr(filename, '\\');
+			if ((tmp != NULL) && (tmp[1] == '*'))
+				tmp[0] = '\0';
 		}
-	} else {
-		gaim_debug_warning("oscar","error reading header of rv proxy packet\n");
-		aim_conn_close(sess, conn);
-		free(proxy_info);
-		proxy_info = NULL;
+		gaim_xfer_set_filename(conn->xfer, filename);
+		g_free(filename);
+
+		/*
+		 * Set the message (unless this is the dummy message from an
+		 * ICQ client or an empty message from an AIM client.
+		 * TODO: Maybe we should strip HTML and then see if strlen>0?
+		 */
+		if ((message != NULL) &&
+			(g_ascii_strncasecmp(message, "<ICQ_COOL_FT>", 13) != 0) &&
+			(g_ascii_strcasecmp(message, "<HTML>") != 0))
+		{
+			gaim_xfer_set_message(conn->xfer, message);
+		}
+
+		/* Setup our I/O op functions */
+		gaim_xfer_set_init_fnc(conn->xfer, peer_oft_recvcb_init);
+		gaim_xfer_set_end_fnc(conn->xfer, peer_oft_recvcb_end);
+		gaim_xfer_set_request_denied_fnc(conn->xfer, peer_oft_cb_generic_cancel);
+		gaim_xfer_set_cancel_recv_fnc(conn->xfer, peer_oft_cb_generic_cancel);
+		gaim_xfer_set_ack_fnc(conn->xfer, peer_oft_recvcb_ack_recv);
+
+		/* Now perform the request */
+		gaim_xfer_request(conn->xfer);
 	}
-	if(body_buf) {
-		free(body_buf);
-		body_buf = NULL;
-	}
-	return proxy_info;
 }
+
+/*******************************************************************/
+/* End code for establishing a peer connection                     */
+/*******************************************************************/
--- a/src/protocols/oscar/peer.h	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/peer.h	Fri Apr 07 05:10:56 2006 +0000
@@ -19,55 +19,92 @@
 */
 
 /*
- * OFT Services
- *
- * For all of the above #defines, the number is the subtype
- * of the SNAC.  For OFT #defines, the number is the
- * "hdrtype" which comes after the magic string and OFT
- * packet length.
- *
- * I'm pretty sure the ODC ones are arbitrary right now,
- * that should be changed.
+ * OFT and ODC Services
  */
 
 #ifndef _PEER_H_
 #define _PEER_H_
 
-typedef struct _PeerConnection     PeerConnection;
-typedef struct _PeerFrame          PeerFrame;
-typedef struct _PeerProxyInfo      PeerProxyInfo;
+#include "ft.h"
 
-#define AIM_CB_FAM_OFT 0xfffe /* OFT/Rvous */
+typedef struct _OdcFrame              OdcFrame;
+typedef struct _OftFrame              OftFrame;
+typedef struct _ProxyFrame            ProxyFrame;
+typedef struct _NewPeerConnectionData NewPeerConnectionData;
+typedef struct _PeerConnection        PeerConnection;
 
-#define PEER_TYPE_DIRECTIMCONNECTREQ 0x0001	/* connect request -- actually an OSCAR CAP */
-#define PEER_TYPE_DIRECTIMINCOMING 0x0002
-#define PEER_TYPE_DIRECTIMDISCONNECT 0x0003
-#define PEER_TYPE_DIRECTIMTYPING 0x0004
-#define PEER_TYPE_DIRECTIM_ESTABLISHED 0x0005
+typedef enum
+{
+	PEER_DISCONNECT_DONE,
+	PEER_DISCONNECT_LOCAL_CLOSED,
+	PEER_DISCONNECT_REMOTE_CLOSED,
+	PEER_DISCONNECT_REMOTE_REFUSED,
+	PEER_DISCONNECT_LOST_CONNECTION,
+	PEER_DISCONNECT_INVALID_DATA,
+	PEER_DISCONNECT_COULD_NOT_CONNECT,
+	PEER_DISCONNECT_RETRYING
+} PeerDisconnectReason;
 
-#define PEER_TYPE_PROMPT 0x0101		/* "I am going to send you this file, is that ok?" */
-#define PEER_TYPE_RESUMESOMETHING 0x0106	/* I really don't know */
-#define PEER_TYPE_ACK 0x0202			/* "Yes, it is ok for you to send me that file" */
-#define PEER_TYPE_DONE 0x0204			/* "I received that file with no problems, thanks a bunch" */
-#define PEER_TYPE_RESUME 0x0205		/* Resume transferring, sent by whoever paused? */
-#define PEER_TYPE_RESUMEACK 0x0207		/* Not really sure */
+#define PEER_CONNECTION_FLAG_INITIATED_BY_ME  0x0001
+#define PEER_CONNECTION_FLAG_APPROVED         0x0002
+#define PEER_CONNECTION_FLAG_TRIED_VERIFIEDIP 0x0004
+#define PEER_CONNECTION_FLAG_TRIED_CLIENTIP   0x0008
+#define PEER_CONNECTION_FLAG_TRIED_INCOMING   0x0010
+#define PEER_CONNECTION_FLAG_TRIED_PROXY      0x0020
+#define PEER_CONNECTION_FLAG_IS_INCOMING      0x0040
+
+#define PEER_TYPE_PROMPT 0x0101 /* "I am going to send you this file, is that ok?" */
+#define PEER_TYPE_RESUMESOMETHING 0x0106 /* I really don't know */
+#define PEER_TYPE_ACK 0x0202 /* "Yes, it is ok for you to send me that file" */
+#define PEER_TYPE_DONE 0x0204 /* "I received that file with no problems, thanks a bunch" */
+#define PEER_TYPE_RESUME 0x0205 /* Resume transferring, sent by whoever paused? */
+#define PEER_TYPE_RESUMEACK 0x0207 /* Not really sure */
 
 #define PEER_TYPE_GETFILE_REQUESTLISTING 0x1108 /* "I have a listing.txt file, do you want it?" */
 #define PEER_TYPE_GETFILE_RECEIVELISTING 0x1209 /* "Yes, please send me your listing.txt file" */
 #define PEER_TYPE_GETFILE_RECEIVEDLISTING 0x120a /* received corrupt listing.txt file? I'm just guessing about this one... */
-#define PEER_TYPE_GETFILE_ACKLISTING 0x120b	/* "I received the listing.txt file successfully" */
-#define PEER_TYPE_GETFILE_REQUESTFILE 0x120c	/* "Please send me this file" */
+#define PEER_TYPE_GETFILE_ACKLISTING 0x120b /* "I received the listing.txt file successfully" */
+#define PEER_TYPE_GETFILE_REQUESTFILE 0x120c /* "Please send me this file" */
 
-#define PEER_TYPE_ESTABLISHED 0xFFFF		/* connection to buddy initiated */
+/*
+ * For peer proxying
+ */
+#define PEER_PROXY_SERVER         "ars.oscar.aol.com"
+#define PEER_PROXY_PORT           5190   /* The port we should always connect to */
+#define PEER_PROXY_PACKET_VERSION 0x044a
 
-struct _PeerFrame
+/* Thanks to Keith Lea and the Joust project for documenting these */
+#define PEER_PROXY_TYPE_ERROR   0x0001
+#define PEER_PROXY_TYPE_CREATE  0x0002
+#define PEER_PROXY_TYPE_CREATED 0x0003
+#define PEER_PROXY_TYPE_JOIN    0x0004
+#define PEER_PROXY_TYPE_READY   0x0005
+
+struct _OdcFrame
 {
-#if 0
-	char magic[4];           /* 0 */
-	guint16 length;          /* 4 */
+	/* guchar magic[4]; */        /* 0 */
+	/* guint16 length; */         /* 4 */
+	guint16 type;                 /* 6 */
+	guint16 subtype;              /* 8 */
+	/* Unknown */                 /* 10 */
+	guchar cookie[8];		      /* 12 */
+	/* Unknown */
+	/* guint32 payloadlength; */  /* 28 */
+	guint16 encoding;             /* 32 */
+	/* Unknown */
+	guint16 flags;                /* 38 */
+	/* Unknown */
+	guchar sn[32];                /* 44 */
+	/* Unknown */
+	ByteStream payload;           /* 76 */
+};
+
+struct _OftFrame
+{
+	/* guchar magic[4]; */   /* 0 */
+	/* guint16 length; */    /* 4 */
 	guint16 type;            /* 6 */
-#endif
-	guchar bcookie[8];       /* 8 */
+	guchar cookie[8];        /* 8 */
 	guint16 encrypt;         /* 16 */
 	guint16 compress;        /* 18 */
 	guint16 totfiles;        /* 20 */
@@ -84,88 +121,162 @@
 	guint32 rfcsum;          /* 56 */
 	guint32 nrecvd;          /* 60 */
 	guint32 recvcsum;        /* 64 */
-	char idstring[32];       /* 68 */
+	guchar idstring[32];     /* 68 */
 	guint8 flags;            /* 100 */
 	guint8 lnameoffset;      /* 101 */
 	guint8 lsizeoffset;      /* 102 */
-	char dummy[69];          /* 103 */
-	char macfileinfo[16];    /* 172 */
+	guchar dummy[69];        /* 103 */
+	guchar macfileinfo[16];  /* 172 */
 	guint16 nencode;         /* 188 */
 	guint16 nlanguage;       /* 190 */
-	char name[64];           /* 192 */
+	guchar *name;            /* 192 */
+	size_t name_length;
 	/* Payload? */           /* 256 */
 };
 
-struct _PeerProxyInfo {
-	guint16 packet_ver;
-	guint16 cmd_type;
-	guint16 flags;
-	char* ip; /* IP address sent along with this packet */
-	guint16 port; /* This is NOT the port we should use to connect. Always connect to 5190 */
-	guchar cookie[8];
-	guint32 unknownA;
-	guint16 err_code; /* Valid only for cmd_type of AIM_RV_PROXY_ERROR */
-	OscarConnection *conn;
-	OscarSession *sess;
+struct _ProxyFrame
+{
+	/* guint16 length; */    /* 0 */
+	guint16 version;         /* 2 */
+	guint16 type;            /* 4 */
+	guint32 unknown;         /* 6 */
+	guint16 flags;           /* 10 */
+	ByteStream payload;      /* 12 */
 };
 
-struct _PeerConnection {
-	guchar cookie[8];
-	char *sn;
-	char *proxyip;
-	char *clientip;
-	char *verifiedip;
-	guint16 port;
-
-	int send_or_recv; /* Send or receive */
-	int method; /* What method is being used to transfer this file? DIRECT, REDIR, or PROXY */
-	int stage; /* At what stage was a proxy requested? NONE, STG1, STG2*/
-	int xfer_reffed; /* There are many timers, but we should only ref the xfer once */
-	int redir_attempted; /* Have we previously attempted to redirect the connection? */
-	guint32 res_bytes; /* The bytes already received for resuming a transfer */
-
-	OscarConnection *conn;
-	OscarSession *sess;
-	int success; /* Was the connection successful? Used for timing out the transfer. */
-	PeerFrame fh;
-	PeerProxyInfo *proxy_info;
+struct _NewPeerConnectionData
+{
+	GaimConnection *gc;
+	PeerConnection *conn;
 };
 
-int aim_handlerendconnect(OscarSession *sess, OscarConnection *cur);
-int aim_rxdispatch_rendezvous(OscarSession *sess, FlapFrame *fr);
+struct _PeerConnection
+{
+	OscarData *od;
+	OscarCapability type;
+	char *sn;
+	guchar magic[4];
+	guchar cookie[8];
+	guint16 lastrequestnumber;
+
+	gboolean ready;
+	int flags;                       /**< Bitmask of PEER_CONNECTION_FLAG_ */
+	time_t lastactivity;             /**< Time of last transmit. */
+	guint destroy_timeout;
+	PeerDisconnectReason disconnect_reason;
+
+	/**
+	 * A pointer to either an OdcFrame or an OftFrame.
+	 */
+	gpointer frame;
+
+	/**
+	 * This is only used while the remote user is attempting to
+	 * connect to us.
+	 */
+	int listenerfd;
+	int fd;
 
-/*
- * OFT
- */
-int aim_sendfile_listen(OscarSession *sess, PeerConnection *peer_connection, int listenfd);
-int aim_oft_sendheader(OscarSession *sess, guint16 type, PeerConnection *peer_connection);
-guint32 aim_oft_checksum_chunk(const guint8 *buffer, int bufferlen, guint32 prevcheck);
-guint32 aim_oft_checksum_file(char *filename);
-int aim_oft_sendheader(OscarSession *sess, guint16 type, PeerConnection *peer_connection);
-PeerConnection *aim_oft_createinfo(OscarSession *sess, const guchar *cookie, const char *sn,
-	const char *ip, guint16 port, guint32 size, guint32 modtime, char *filename, int send_or_recv,
-	int method, int stage);
-int aim_oft_destroyinfo(PeerConnection *peer_connection);
+	guint watcher_incoming;
+	guint watcher_outgoing;
+
+	ByteStream buffer_incoming;
+	GaimCircBuffer *buffer_outgoing;
+
+	/**
+	 * IP address of the proxy server, if applicable.
+	 */
+	gchar *proxyip;
+
+	/**
+	 * IP address of the remote user from THEIR point of view.
+	 */
+	gchar *clientip;
+
+	/**
+	 * IP address of the remote user from the oscar server's
+	 * point of view.
+	 */
+	gchar *verifiedip;
+
+	guint16 port;
+	gboolean use_proxy;
+
+	/* TODOFT */
+	GaimXfer *xfer;
+	OftFrame xferdata;
+	guint sending_data_timer;
+};
 
 /*
- * ODC
+ * For all peer connections
+ */
+
+/**
+ * Create a new PeerConnection structure and initialize it with some
+ * sane defaults.
+ *
+ * @param type The type of the peer connection.  One of
+ *        OSCAR_CAPABILITY_DIRECTIM or OSCAR_CAPABILITY_SENDFILE.
  */
-int aim_odc_send_typing(OscarSession *sess, OscarConnection *conn, int typing);
-int aim_odc_send_im(OscarSession *sess, OscarConnection *conn, const char *msg, int len, int encoding, int isawaymsg);
-const char *aim_odc_getsn(OscarConnection *conn);
-const guchar *aim_odc_getcookie(OscarConnection *conn);
-OscarConnection *aim_odc_getconn(OscarSession *sess, const char *sn);
-OscarConnection *aim_odc_initiate(OscarSession *sess, const char *sn, int listenfd,
-                                         const guint8 *localip, guint16 port, const guchar *mycookie);
-OscarConnection *aim_odc_connect(OscarSession *sess, const char *sn, const char *addr, const guchar *cookie);
+PeerConnection *peer_connection_new(OscarData *od, OscarCapability type, const char *sn);
+
+void peer_connection_destroy(PeerConnection *conn, PeerDisconnectReason reason);
+void peer_connection_schedule_destroy(PeerConnection *conn, PeerDisconnectReason reason);
+PeerConnection *peer_connection_find_by_type(OscarData *od, const char *sn, OscarCapability type);
+PeerConnection *peer_connection_find_by_cookie(OscarData *od, const char *sn, const guchar *cookie);
+
+void peer_connection_listen_cb(gpointer data, gint source, GaimInputCondition cond);
+void peer_connection_recv_cb(gpointer data, gint source, GaimInputCondition cond);
+void peer_connection_send(PeerConnection *conn, ByteStream *bs);
+
+void peer_connection_trynext(PeerConnection *conn);
+void peer_connection_finalize_connection(PeerConnection *conn);
+void peer_connection_propose(OscarData *od, OscarCapability type, const char *sn);
+void peer_connection_got_proposition(OscarData *od, const gchar *sn, const gchar *message, IcbmArgsCh2 *args);
+
+/*
+ * For ODC
+ */
+void peer_odc_close(PeerConnection *conn);
+void peer_odc_recv_frame(PeerConnection *conn, ByteStream *bs);
+void peer_odc_send_cookie(PeerConnection *conn);
+void peer_odc_send_typing(PeerConnection *conn, GaimTypingState typing);
+void peer_odc_send_im(PeerConnection *conn, const char *msg, int len, int encoding, gboolean autoreply);
 
 /*
- * Rendezvous proxy
+ * For OFT
  */
-PeerProxyInfo *aim_rv_proxy_createinfo(OscarSession *sess, const guchar *cookie, guint16 port);
-int aim_rv_proxy_init_recv(PeerProxyInfo *proxy_info);
-int aim_rv_proxy_init_send(PeerProxyInfo *proxy_info);
+void peer_oft_close(PeerConnection *conn);
+void peer_oft_recv_frame(PeerConnection *conn, ByteStream *bs);
+void peer_oft_send_prompt(PeerConnection *conn);
+
+/* Xfer callbacks for receiving a file */
+void peer_oft_recvcb_init(GaimXfer *xfer);
+void peer_oft_recvcb_end(GaimXfer *xfer);
+void peer_oft_recvcb_ack_recv(GaimXfer *xfer, const guchar *buffer, size_t size);
+
+/* Xfer callbacks for sending a file */
+void peer_oft_sendcb_init(GaimXfer *xfer);
+void peer_oft_sendcb_ack(GaimXfer *xfer, const guchar *buffer, size_t size);
+
+/* Xfer callbacks for both sending and receiving */
+void peer_oft_cb_generic_cancel(GaimXfer *xfer);
 
-PeerProxyInfo *aim_rv_proxy_read(OscarSession *sess, OscarConnection *conn);
+/*
+ * For peer proxying
+ */
+void peer_proxy_connection_established_cb(gpointer data, gint source, GaimInputCondition cond);
+
+#if 0
+int peer_oft_sendheader(OscarData *od, guint16 type, PeerConnection *peer_connection);
+guint32 peer_oft_checksum_chunk(const guint8 *buffer, int bufferlen, guint32 prevcheck);
+guint32 peer_oft_checksum_file(char *filename);
+int peer_oft_sendheader(OscarData *od, guint16 type, PeerConnection *peer_connection);
+PeerConnection *peer_oft_createinfo(OscarData *od, const guchar *cookie, const char *sn,
+	const char *ip, guint16 port, guint32 size, guint32 modtime, char *filename, int send_or_recv,
+	int method, int stage);
+int peer_oft_destroyinfo(PeerConnection *peer_connection);
+#endif
 
 #endif /* _PEER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/oscar/peer_proxy.c	Fri Apr 07 05:10:56 2006 +0000
@@ -0,0 +1,362 @@
+/*
+ * Gaim'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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifdef HAVE_CONFIG_H
+#include  <config.h>
+#endif
+
+#include "oscar.h"
+#include "peer.h"
+
+static void
+peer_proxy_send(PeerConnection *conn, ProxyFrame *frame)
+{
+	size_t length;
+	ByteStream bs;
+
+	gaim_debug_info("oscar", "Outgoing peer proxy frame with "
+			"type=0x%04hx, unknown=0x%08x, "
+			"flags=0x%04hx, and payload length=%hd\n",
+			frame->type, frame->unknown,
+			frame->flags, frame->payload.len);
+
+	length = 12 + frame->payload.len;
+	byte_stream_init(&bs, malloc(length), length);
+	byte_stream_put16(&bs, length - 2);
+	byte_stream_put16(&bs, PEER_PROXY_PACKET_VERSION);
+	byte_stream_put16(&bs, frame->type);
+	byte_stream_put32(&bs, frame->unknown);
+	byte_stream_put16(&bs, frame->flags);
+	byte_stream_putraw(&bs, frame->payload.data, frame->payload.len);
+
+	peer_connection_send(conn, &bs);
+
+	free(bs.data);
+}
+
+/**
+ * Create a rendezvous "init send" packet and send it on its merry way.
+ * This is the first packet sent to the proxy server by the first client
+ * to indicate that this will be a proxied connection
+ *
+ * @param conn The peer connection.
+ */
+static void
+peer_proxy_send_create_new_conn(PeerConnection *conn)
+{
+	ProxyFrame frame;
+	GaimAccount *account;
+	const gchar *sn;
+	guint8 sn_length;
+	size_t length;
+
+	memset(&frame, 0, sizeof(ProxyFrame));
+	frame.type = PEER_PROXY_TYPE_CREATE;
+	frame.flags = 0x0000;
+
+	account = gaim_connection_get_account(conn->od->gc);
+	sn = gaim_account_get_username(account);
+	sn_length = strlen(sn);
+	length = 1 + sn_length + 8 + 20;
+	byte_stream_init(&frame.payload, malloc(length), length);
+	byte_stream_put8(&frame.payload, sn_length);
+	byte_stream_putraw(&frame.payload, (const guint8 *)sn, sn_length);
+	byte_stream_putraw(&frame.payload, conn->cookie, 8);
+
+	byte_stream_put16(&frame.payload, 0x0001); /* Type */
+	byte_stream_put16(&frame.payload, 16); /* Length */
+	byte_stream_putcaps(&frame.payload, conn->type); /* Value */
+
+	peer_proxy_send(conn, &frame);
+}
+
+/**
+ * Create a rendezvous "init recv" packet and send it on its merry way.
+ * This is the first packet sent to the proxy server by the second client
+ * involved in this rendezvous proxy session.
+ *
+ * @param conn The peer connection.
+ * @param pin The 2 byte PIN sent to us by the other user.  This acts
+ *        as our passcode when establishing the proxy session.
+ */
+static void
+peer_proxy_send_join_existing_conn(PeerConnection *conn, guint16 pin)
+{
+	ProxyFrame frame;
+	GaimAccount *account;
+	const gchar *sn;
+	guint8 sn_length;
+	size_t length;
+
+	memset(&frame, 0, sizeof(ProxyFrame));
+	frame.type = PEER_PROXY_TYPE_JOIN;
+	frame.flags = 0x0000;
+
+	account = gaim_connection_get_account(conn->od->gc);
+	sn = gaim_account_get_username(account);
+	sn_length = strlen(sn);
+	length = 1 + sn_length + 2 + 8 + 20;
+	byte_stream_init(&frame.payload, malloc(length), length);
+	byte_stream_put8(&frame.payload, sn_length);
+	byte_stream_putraw(&frame.payload, (const guint8 *)sn, sn_length);
+	byte_stream_put16(&frame.payload, pin);
+	byte_stream_putraw(&frame.payload, conn->cookie, 8);
+
+	byte_stream_put16(&frame.payload, 0x0001); /* Type */
+	byte_stream_put16(&frame.payload, 16); /* Length */
+	byte_stream_putcaps(&frame.payload, conn->type); /* Value */
+
+	peer_proxy_send(conn, &frame);
+}
+
+/**
+ * Handle an incoming peer proxy negotiation frame.
+ */
+static void
+peer_proxy_recv_frame(PeerConnection *conn, ProxyFrame *frame)
+{
+	gaim_debug_info("oscar", "Incoming peer proxy frame with "
+			"type=0x%04hx, unknown=0x%08x, "
+			"flags=0x%04hx, and payload length=%hd\n", frame->type,
+			frame->unknown, frame->flags, frame->payload.len);
+
+	if (frame->type == PEER_PROXY_TYPE_CREATED)
+	{
+		/*
+		 * Read in 2 byte port then 4 byte IP and tell the
+		 * remote user to connect to it by sending an ICBM.
+		 */
+		guint16 pin;
+		int i;
+		guint8 ip[4];
+
+		pin = byte_stream_get16(&frame->payload);
+		for (i = 0; i < 4; i++)
+			ip[i] = byte_stream_get8(&frame->payload);
+		if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
+			aim_im_sendch2_odc_requestproxy(conn->od,
+					conn->cookie,
+					conn->sn, ip, pin, ++conn->lastrequestnumber);
+		else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
+		{
+			aim_im_sendch2_sendfile_requestproxy(conn->od,
+					conn->cookie, conn->sn,
+					ip, pin, ++conn->lastrequestnumber,
+					(const gchar *)conn->xferdata.name,
+					conn->xferdata.size, conn->xferdata.totfiles);
+		}
+	}
+	else if (frame->type == PEER_PROXY_TYPE_READY)
+	{
+		gaim_input_remove(conn->watcher_incoming);
+		conn->watcher_incoming = 0;
+
+		peer_connection_finalize_connection(conn);
+	}
+	else if (frame->type == PEER_PROXY_TYPE_ERROR)
+	{
+		if (byte_stream_empty(&frame->payload) >= 2)
+		{
+			guint16 error;
+			const char *msg;
+			error = byte_stream_get16(&frame->payload);
+			if (error == 0x000d)
+				msg = "bad request";
+			else if (error == 0x0010)
+				msg = "initial request timed out";
+			else if (error == 0x001a)
+				msg ="accept period timed out";
+			else
+				msg = "unknown reason";
+			gaim_debug_info("oscar", "Proxy negotiation failed with "
+					"error 0x%04hx: %s\n", error, msg);
+		}
+		else
+		{
+			gaim_debug_warning("oscar", "Proxy negotiation failed with "
+					"an unknown error\n");
+		}
+		peer_connection_trynext(conn);
+	}
+	else
+	{
+		gaim_debug_warning("oscar", "Unknown peer proxy frame type 0x%04hx.\n",
+				frame->type);
+	}
+}
+
+static void
+peer_proxy_connection_recv_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	PeerConnection *conn;
+	ssize_t read;
+	guint8 header[12];
+	ProxyFrame *frame;
+
+	conn = data;
+	frame = conn->frame;
+
+	/* Start reading a new proxy frame */
+	if (frame == NULL)
+	{
+		/* Peek at the first 12 bytes to get the length */
+		read = recv(conn->fd, &header, 12, MSG_PEEK);
+
+		/* Check if the proxy server closed the connection */
+		if (read == 0)
+		{
+			gaim_debug_info("oscar", "Peer proxy server closed connection\n");
+			peer_connection_trynext(conn);
+			return;
+		}
+
+		/* If there was an error then close the connection */
+		if (read == -1)
+		{
+			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+				/* No worries */
+				return;
+
+			gaim_debug_info("oscar", "Lost connection with peer proxy server\n");
+			peer_connection_trynext(conn);
+			return;
+		}
+
+		conn->lastactivity = time(NULL);
+
+		/* If we don't even have the first 12 bytes then do nothing */
+		if (read < 12)
+			return;
+
+		/* Read the first 12 bytes (frame length and header) */
+		read = recv(conn->fd, &header, 12, 0);
+
+		/* We only support a specific version of the proxy protocol */
+		if (aimutil_get16(&header[2]) != PEER_PROXY_PACKET_VERSION)
+		{
+			gaim_debug_warning("oscar", "Expected peer proxy protocol "
+				"version %u but received version %u.  Closing "
+				"connection.\n", PEER_PROXY_PACKET_VERSION,
+				aimutil_get16(&header[2]));
+			peer_connection_trynext(conn);
+			return;
+		}
+
+		/* Initialize a new temporary ProxyFrame for incoming data */
+		frame = g_new0(ProxyFrame, 1);
+		frame->payload.len = aimutil_get16(&header[0]) - 10;
+		frame->version = aimutil_get16(&header[2]);
+		frame->type = aimutil_get16(&header[4]);
+		frame->unknown = aimutil_get16(&header[6]);
+		frame->flags = aimutil_get16(&header[10]);
+		if (frame->payload.len > 0)
+			frame->payload.data = g_new(guint8, frame->payload.len);
+		conn->frame = frame;
+	}
+
+	/* If this frame has a payload then attempt to read it */
+	if (frame->payload.len - frame->payload.offset > 0)
+	{
+		/* Read data into the temporary buffer until it is complete */
+		read = recv(conn->fd,
+					&frame->payload.data[frame->payload.offset],
+					frame->payload.len - frame->payload.offset,
+					0);
+
+		/* Check if the proxy server closed the connection */
+		if (read == 0)
+		{
+			gaim_debug_info("oscar", "Peer proxy server closed connection\n");
+			g_free(frame->payload.data);
+			g_free(frame);
+			conn->frame = NULL;
+			peer_connection_trynext(conn);
+			return;
+		}
+
+		if (read == -1)
+		{
+			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+				/* No worries */
+				return;
+
+			gaim_debug_info("oscar", "Lost connection with peer proxy server\n");
+			g_free(frame->payload.data);
+			g_free(frame);
+			conn->frame = NULL;
+			peer_connection_trynext(conn);
+			return;
+		}
+	}
+
+	conn->lastactivity = time(NULL);
+	frame->payload.offset += read;
+	if (frame->payload.offset < frame->payload.len)
+		/* Waiting for more data to arrive */
+		return;
+
+	/* We have a complete proxy frame!  Handle it and continue reading */
+	conn->frame = NULL;
+	byte_stream_rewind(&frame->payload);
+	peer_proxy_recv_frame(conn, frame);
+	g_free(frame->payload.data);
+	g_free(frame);
+}
+
+/**
+ * We tried to make an outgoing connection to a proxy server.  It
+ * either connected or failed to connect.
+ */
+void
+peer_proxy_connection_established_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	NewPeerConnectionData *new_conn_data;
+	GaimConnection *gc;
+	PeerConnection *conn;
+
+	new_conn_data = data;
+	gc = new_conn_data->gc;
+	conn = new_conn_data->conn;
+	g_free(new_conn_data);
+
+	if (!g_list_find(gaim_connections_get_all(), gc))
+	{
+		if (source >= 0)
+			close(source);
+		return;
+	}
+
+	if (source < 0)
+	{
+		peer_connection_trynext(conn);
+		return;
+	}
+
+	conn->fd = source;
+	conn->watcher_incoming = gaim_input_add(conn->fd,
+			GAIM_INPUT_READ, peer_proxy_connection_recv_cb, conn);
+
+	if (conn->proxyip != NULL)
+		/* Connect to the session created by the remote user */
+		peer_proxy_send_join_existing_conn(conn, conn->port);
+	else
+		/* Create a new session */
+		peer_proxy_send_create_new_conn(conn);
+}
--- a/src/protocols/oscar/rxhandlers.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/rxhandlers.c	Fri Apr 07 05:10:56 2006 +0000
@@ -18,31 +18,14 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-/*
- * rxhandlers.c
- *
- * This file contains most all of the incoming packet handlers, along
- * with aim_rxdispatch(), the Rx dispatcher.  Queue/list management is
- * actually done in aim_rxqueue.c.
- *
- */
-
 #include "oscar.h"
 #include "peer.h"
 
-struct aim_rxcblist_s {
-	guint16 family;
-	guint16 type;
-	aim_rxcallback_t handler;
-	guint16 flags;
-	struct aim_rxcblist_s *next;
-};
-
-faim_internal aim_module_t *aim__findmodulebygroup(OscarSession *sess, guint16 group)
+aim_module_t *aim__findmodulebygroup(OscarData *od, guint16 group)
 {
 	aim_module_t *cur;
 
-	for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
+	for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {
 		if (cur->family == group)
 			return cur;
 	}
@@ -50,11 +33,11 @@
 	return NULL;
 }
 
-faim_internal aim_module_t *aim__findmodule(OscarSession *sess, const char *name)
+aim_module_t *aim__findmodule(OscarData *od, const char *name)
 {
 	aim_module_t *cur;
 
-	for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
+	for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {
 		if (strcmp(name, cur->name) == 0)
 			return cur;
 	}
@@ -62,171 +45,63 @@
 	return NULL;
 }
 
-faim_internal int aim__registermodule(OscarSession *sess, int (*modfirst)(OscarSession *, aim_module_t *))
+int aim__registermodule(OscarData *od, int (*modfirst)(OscarData *, aim_module_t *))
 {
 	aim_module_t *mod;
 
-	if (!sess || !modfirst)
+	if (!od || !modfirst)
 		return -1;
 
-	if (!(mod = malloc(sizeof(aim_module_t))))
-		return -1;
-	memset(mod, 0, sizeof(aim_module_t));
+	mod = g_new0(aim_module_t, 1);
 
-	if (modfirst(sess, mod) == -1) {
+	if (modfirst(od, mod) == -1) {
 		free(mod);
 		return -1;
 	}
 
-	if (aim__findmodule(sess, mod->name)) {
+	if (aim__findmodule(od, mod->name)) {
 		if (mod->shutdown)
-			mod->shutdown(sess, mod);
+			mod->shutdown(od, mod);
 		free(mod);
 		return -1;
 	}
 
-	mod->next = (aim_module_t *)sess->modlistv;
-	sess->modlistv = mod;
+	mod->next = (aim_module_t *)od->modlistv;
+	od->modlistv = mod;
 
 	gaim_debug_misc("oscar", "registered module %s (family 0x%04x, version = 0x%04x, tool 0x%04x, tool version 0x%04x)\n", mod->name, mod->family, mod->version, mod->toolid, mod->toolversion);
 
 	return 0;
 }
 
-faim_internal void aim__shutdownmodules(OscarSession *sess)
+void aim__shutdownmodules(OscarData *od)
 {
 	aim_module_t *cur;
 
-	for (cur = (aim_module_t *)sess->modlistv; cur; ) {
+	for (cur = (aim_module_t *)od->modlistv; cur; ) {
 		aim_module_t *tmp;
 
 		tmp = cur->next;
 
 		if (cur->shutdown)
-			cur->shutdown(sess, cur);
+			cur->shutdown(od, cur);
 
 		free(cur);
 
 		cur = tmp;
 	}
 
-	sess->modlistv = NULL;
+	od->modlistv = NULL;
 
 	return;
 }
 
-static int consumesnac(OscarSession *sess, FlapFrame *rx)
-{
-	aim_module_t *cur;
-	aim_modsnac_t snac;
-
-	if (aim_bstream_empty(&rx->data) < 10)
-		return 0;
-
-	snac.family = aimbs_get16(&rx->data);
-	snac.subtype = aimbs_get16(&rx->data);
-	snac.flags = aimbs_get16(&rx->data);
-	snac.id = aimbs_get32(&rx->data);
-
-	/* SNAC flags are apparently uniform across all SNACs, so we handle them here */
-	if (snac.flags & 0x0001) {
-		/*
-		 * This means the SNAC will be followed by another SNAC with 
-		 * related information.  We don't need to do anything about 
-		 * this here.
-		 */
-	}
-	if (snac.flags & 0x8000) {
-		/*
-		 * This packet contains the version of the family that this SNAC is 
-		 * in.  You get this when your SSI module is version 2 or higher.  
-		 * For now we have no need for this, but you could always save 
-		 * it as a part of aim_modnsac_t, or something.  The format is...
-		 * 2 byte length of total mini-header (which is 6 bytes), then TLV 
-		 * of  type 0x0001, length 0x0002, value is the 2 byte version 
-		 * number
-		 */
-		aim_bstream_advance(&rx->data, aimbs_get16(&rx->data));
-	}
-
-	for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
-
-		if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
-				(cur->family != snac.family))
-			continue;
-
-		if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
-			return 1;
-
-	}
-
-	return 0;
-}
-
-static int consumenonsnac(OscarSession *sess, FlapFrame *rx, guint16 family, guint16 subtype)
-{
-	aim_module_t *cur;
-	aim_modsnac_t snac;
-
-	snac.family = family;
-	snac.subtype = subtype;
-	snac.flags = snac.id = 0;
-
-	for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
-
-		if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
-				(cur->family != snac.family))
-			continue;
-
-		if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
-			return 1;
-
-	}
-
-	return 0;
-}
-
-static int negchan_middle(OscarSession *sess, FlapFrame *fr)
-{
-	aim_tlvlist_t *tlvlist;
-	char *msg = NULL;
-	guint16 code = 0;
-	aim_rxcallback_t userfunc;
-	int ret = 1;
-
-	if (aim_bstream_empty(&fr->data) == 0) {
-		/* XXX should do something with this */
-		return 1;
-	}
-
-	/* Used only by the older login protocol */
-	/* XXX remove this special case? */
-	if (fr->conn->type == AIM_CONN_TYPE_AUTH)
-		return consumenonsnac(sess, fr, 0x0017, 0x0003);
-
-	tlvlist = aim_tlvlist_read(&fr->data);
-
-	if (aim_tlv_gettlv(tlvlist, 0x0009, 1))
-		code = aim_tlv_get16(tlvlist, 0x0009, 1);
-
-	if (aim_tlv_gettlv(tlvlist, 0x000b, 1))
-		msg = aim_tlv_getstr(tlvlist, 0x000b, 1);
-
-	if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
-		ret = userfunc(sess, fr, code, msg);
-
-	aim_tlvlist_free(&tlvlist);
-
-	free(msg);
-
-	return ret;
-}
-
+#if 0
 /*
  * Bleck functions get called when there's no non-bleck functions
  * around to cleanup the mess...
  */
-static int bleck(OscarSession *sess, FlapFrame *frame, ...)
+static int bleck(OscarData *od, FlapFrame *frame, ...)
 {
 	guint16 family, subtype;
 	guint16 maxf, maxs;
@@ -240,13 +115,13 @@
 		"FLAP NOP"
 	};
 	static const int maxchannels = 5;
-	
+
 	/* XXX: this is ugly. and big just for debugging. */
 	static const char *literals[14][25] = {
-		{"Invalid", 
+		{"Invalid",
 		 NULL
 		},
-		{"General", 
+		{"General",
 		 "Invalid",
 		 "Error",
 		 "Client Ready",
@@ -271,60 +146,60 @@
 		 "Well Known URL",
 		 "NOP"
 		},
-		{"Location", 
+		{"Location",
 		 "Invalid",
 		 "Error",
 		 "Request Rights",
-		 "Rights Information", 
-		 "Set user information", 
-		 "Request User Information", 
-		 "User Information", 
+		 "Rights Information",
+		 "Set user information",
+		 "Request User Information",
+		 "User Information",
 		 "Watcher Sub Request",
 		 "Watcher Notification"
 		},
-		{"Buddy List Management", 
-		 "Invalid", 
-		 "Error", 
+		{"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", 
+		 "Add Buddy",
+		 "Remove Buddy",
+		 "Watcher List Query",
+		 "Watcher List Response",
+		 "Watcher SubRequest",
+		 "Watcher Notification",
+		 "Reject Notification",
+		 "Oncoming Buddy",
 		 "Offgoing Buddy"
 		},
-		{"Messeging", 
+		{"Messeging",
 		 "Invalid",
-		 "Error", 
+		 "Error",
 		 "Add ICBM Parameter",
-		 "Remove ICBM Parameter", 
+		 "Remove ICBM Parameter",
 		 "Request Parameter Information",
 		 "Parameter Information",
-		 "Outgoing Message", 
+		 "Outgoing Message",
 		 "Incoming Message",
 		 "Evil Request",
-		 "Evil Reply", 
+		 "Evil Reply",
 		 "Missed Calls",
-		 "Message Error", 
+		 "Message Error",
 		 "Host Ack"
 		},
-		{"Advertisements", 
-		 "Invalid", 
-		 "Error", 
+		{"Advertisements",
+		 "Invalid",
+		 "Error",
 		 "Request Ad",
 		 "Ad Data (GIFs)"
 		},
-		{"Invitation / Client-to-Client", 
+		{"Invitation / Client-to-Client",
 		 "Invalid",
 		 "Error",
 		 "Invite a Friend",
 		 "Invitation Ack"
 		},
-		{"Administrative", 
+		{"Administrative",
 		 "Invalid",
 		 "Error",
 		 "Information Request",
@@ -336,12 +211,12 @@
 		 "Account Delete Request",
 		 "Account Delete Reply"
 		},
-		{"Popups", 
+		{"Popups",
 		 "Invalid",
 		 "Error",
 		 "Display Popup"
 		},
-		{"BOS", 
+		{"BOS",
 		 "Invalid",
 		 "Error",
 		 "Request Rights",
@@ -353,25 +228,25 @@
 		 "Delete deny list entries",
 		 "Server Error"
 		},
-		{"User Lookup", 
+		{"User Lookup",
 		 "Invalid",
 		 "Error",
 		 "Search Request",
 		 "Search Response"
 		},
-		{"Stats", 
+		{"Stats",
 		 "Invalid",
 		 "Error",
 		 "Set minimum report interval",
 		 "Report Events"
 		},
-		{"Translate", 
+		{"Translate",
 		 "Invalid",
 		 "Error",
 		 "Translate Request",
 		 "Translate Reply",
 		},
-		{"Chat Navigation", 
+		{"Chat Navigation",
 		 "Invalid",
 		 "Error",
 		 "Request rights",
@@ -379,10 +254,10 @@
 		 "Request Room Information",
 		 "Request Occupant List",
 		 "Search for Room",
-		 "Outgoing Message", 
+		 "Outgoing Message",
 		 "Incoming Message",
-		 "Evil Request", 
-		 "Evil Reply", 
+		 "Evil Request",
+		 "Evil Reply",
 		 "Chat Error",
 		}
 	};
@@ -390,207 +265,24 @@
 	maxf = sizeof(literals) / sizeof(literals[0]);
 	maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
 
-	if (frame->hdr.flap.channel == 0x02) {
+	if (frame->channel == 0x02) {
+
+		family = byte_stream_get16(&frame->data);
+		subtype = byte_stream_get16(&frame->data);
 
-		family = aimbs_get16(&frame->data);
-		subtype = aimbs_get16(&frame->data);
-		
 		if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
-			gaim_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->hdr.flap.channel], family, subtype, literals[family][subtype+1]);
+			gaim_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->channel], family, subtype, literals[family][subtype+1]);
 		else
-			gaim_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->hdr.flap.channel], family, subtype);
+			gaim_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->channel], family, subtype);
 	} else {
 
-		if (frame->hdr.flap.channel <= maxchannels)
-			gaim_debug_misc("oscar", "bleck: channel %s (0x%02x)\n", channels[frame->hdr.flap.channel], frame->hdr.flap.channel);
+		if (frame->channel <= maxchannels)
+			gaim_debug_misc("oscar", "bleck: channel %s (0x%02x)\n", channels[frame->channel], frame->channel);
 		else
-			gaim_debug_misc("oscar", "bleck: unknown channel 0x%02x\n", frame->hdr.flap.channel);
+			gaim_debug_misc("oscar", "bleck: unknown channel 0x%02x\n", frame->channel);
 
 	}
-		
-	return 1;
-}
-
-faim_export int aim_conn_addhandler(OscarSession *sess, OscarConnection *conn, guint16 family, guint16 type, aim_rxcallback_t newhandler, guint16 flags)
-{
-	struct aim_rxcblist_s *newcb;
-
-	if (!conn)
-		return -1;
-
-	gaim_debug_misc("oscar", "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
-
-	if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s))))
-		return -1;
-
-	newcb->family = family;
-	newcb->type = type;
-	newcb->flags = flags;
-	newcb->handler = newhandler ? newhandler : bleck;
-	newcb->next = NULL;
-
-	if (!conn->handlerlist)
-		conn->handlerlist = (void *)newcb;
-	else {
-		struct aim_rxcblist_s *cur;
-
-		for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next)
-			;
-		cur->next = newcb;
-	}
-
-	return 0;
-}
-
-faim_export int aim_clearhandlers(OscarConnection *conn)
-{
-	struct aim_rxcblist_s *cur;
-
-	if (!conn)
-		return -1;
-
-	for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) {
-		struct aim_rxcblist_s *tmp;
-
-		tmp = cur->next;
-		free(cur);
-		cur = tmp;
-	}
-	conn->handlerlist = NULL;
-
-	return 0;
-}
-
-faim_internal aim_rxcallback_t aim_callhandler(OscarSession *sess, OscarConnection *conn, guint16 family, guint16 type)
-{
-	struct aim_rxcblist_s *cur;
-
-	if (!conn)
-		return NULL;
-
-	/* gaim_debug_misc("oscar", "aim_callhandler: calling for %04x/%04x\n", family, type); */
-
-	for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) {
-		if ((cur->family == family) && (cur->type == type))
-			return cur->handler;
-	}
-
-	return NULL;
-}
-
-faim_internal void aim_clonehandlers(OscarSession *sess, OscarConnection *dest, OscarConnection *src)
-{
-	struct aim_rxcblist_s *cur;
-
-	for (cur = (struct aim_rxcblist_s *)src->handlerlist; cur; cur = cur->next) {
-		aim_conn_addhandler(sess, dest, cur->family, cur->type,
-						cur->handler, cur->flags);
-	}
-
-	return;
-}
-
-faim_internal int aim_callhandler_noparam(OscarSession *sess, OscarConnection *conn,guint16 family, guint16 type, FlapFrame *ptr)
-{
-	aim_rxcallback_t userfunc;
-
-	if ((userfunc = aim_callhandler(sess, conn, family, type)))
-		return userfunc(sess, ptr);
-
-	return 1; /* XXX */
-}
-
-/*
- * aim_rxdispatch()
- *
- * Basically, heres what this should do:
- *   1) Determine correct packet handler for this packet
- *   2) Mark the packet handled (so it can be dequeued in purge_queue())
- *   3) Send the packet to the packet handler
- *   4) Go to next packet in the queue and start over
- *   5) When done, run purge_queue() to purge handled commands
- *
- * TODO: Clean up.
- * TODO: More support for mid-level handlers.
- * TODO: Allow for NULL handlers.
- *
- */
-faim_export void aim_rxdispatch(OscarSession *sess)
-{
-	int i;
-	FlapFrame *cur;
-
-	for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) {
-
-		/*
-		 * XXX: This is still fairly ugly.
-		 */
-
-		if (cur->handled)
-			continue;
-
-		if (cur->hdrtype == AIM_FRAMETYPE_FLAP) {
-			if (cur->hdr.flap.channel == 0x01) {
-				cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
-				continue;
-
-			} else if (cur->hdr.flap.channel == 0x02) {
-				if ((cur->handled = consumesnac(sess, cur)))
-					continue;
-
-			} else if (cur->hdr.flap.channel == 0x04) {
-				cur->handled = negchan_middle(sess, cur);
-				continue;
-
-			} else if (cur->hdr.flap.channel == 0x05) {
-
-			}
-
-		} else if (cur->hdrtype == AIM_FRAMETYPE_OFT) {
-			if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
-				aim_rxdispatch_rendezvous(sess, cur);
-				cur->handled = 1;
-				continue;
-
-			} else if (cur->conn->type == AIM_CONN_TYPE_LISTENER) {
-				/* not possible */
-				gaim_debug_misc("oscar", "rxdispatch called on LISTENER connection!\n");
-				cur->handled = 1;
-				continue;
-			}
-		}
-
-		if (!cur->handled) {
-			consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */
-			cur->handled = 1;
-		}
-	}
-
-	/*
-	 * This doesn't have to be called here.  It could easily be done
-	 * by a separate thread or something. It's an administrative operation,
-	 * and can take a while. Though the less you call it the less memory
-	 * you'll have :)
-	 */
-	aim_purge_rxqueue(sess);
-
-	return;
-}
-
-faim_internal int aim_parse_unknown(OscarSession *sess, FlapFrame *frame, ...)
-{
-	int i;
-
-	gaim_debug_misc("oscar", "\nRecieved unknown packet:");
-
-	for (i = 0; aim_bstream_empty(&frame->data); i++) {
-		if ((i % 8) == 0)
-			gaim_debug_misc("oscar", "\n\t");
-
-		gaim_debug_misc("oscar", "0x%2x ", aimbs_get8(&frame->data));
-	}
-
-	gaim_debug_misc("oscar", "\n\n");
 
 	return 1;
 }
+#endif
--- a/src/protocols/oscar/rxqueue.c	Fri Apr 07 01:05:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,299 +0,0 @@
-/*
- * Gaim'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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/*
- * This file contains the management routines for the receive
- * (incoming packet) queue.  The actual packet handlers are in
- * rxhandlers.c.
- */
-
-#include "oscar.h"
-
-#ifndef _WIN32
-#include <sys/socket.h>
-#endif
-
-/*
- *
- */
-faim_internal int aim_recv(int fd, void *buf, size_t count)
-{
-	int left, cur;
-
-	for (cur = 0, left = count; left; ) {
-		int ret;
-
-		ret = recv(fd, ((unsigned char *)buf)+cur, left, 0);
-
-		/* Of course EOF is an error, only morons disagree with that. */
-		if (ret <= 0)
-			return -1;
-
-		cur += ret;
-		left -= ret;
-	}
-
-	return cur;
-}
-
-/*
- * Read into a byte stream.  Will not read more than count, but may read
- * less if there is not enough room in the stream buffer.
- */
-faim_internal int aim_bstream_recv(ByteStream *bs, int fd, size_t count)
-{
-	int red = 0;
-
-	if (!bs || (fd < 0))
-		return -1;
-
-	if (count > (bs->len - bs->offset))
-		count = bs->len - bs->offset; /* truncate to remaining space */
-
-	if (count) {
-
-		red = aim_recv(fd, bs->data + bs->offset, count);
-
-		if (red <= 0)
-			return -1;
-	}
-
-	bs->offset += red;
-
-	return red;
-}
-
-/**
- * Free an FlapFrame
- *
- * @param frame The frame to free.
- * @return -1 on error; 0 on success.
- */
-faim_internal void aim_frame_destroy(FlapFrame *frame)
-{
-
-	free(frame->data.data); /* XXX aim_bstream_free */
-	free(frame);
-
-	return;
-}
-
-/*
- * Read a FLAP header from conn into fr, and return the number of
- * bytes in the payload.
- *
- * @return -1 on error, otherwise return the length of the payload.
- */
-static int aim_get_command_flap(OscarSession *sess, OscarConnection *conn, FlapFrame *fr)
-{
-	guint8 hdr_raw[6];
-	ByteStream hdr;
-
-	fr->hdrtype = AIM_FRAMETYPE_FLAP;
-
-	/*
-	 * Read FLAP header.  Six bytes total.
-	 *
-	 *   Byte # | Description
-	 *   -------|-------------
-	 *    0x00  | Always 0x2a
-	 *    0x01  | Channel number, usually "2."  "1" is used during login,
-	 *          |   4 is used during logoff.
-	 *    0x02  | Sequence number, 2 bytes.
-	 *    0x04  | Number of data bytes that follow, 2 bytes.
-	 */
-	aim_bstream_init(&hdr, hdr_raw, sizeof(hdr_raw));
-	if (aim_bstream_recv(&hdr, conn->fd, 6) < 6) {
-		aim_conn_close(sess, conn);
-		return -1;
-	}
-
-	aim_bstream_rewind(&hdr);
-
-	/*
-	 * This shouldn't happen unless the socket breaks, the server breaks,
-	 * or we break.  We must handle it just in case.
-	 */
-	if (aimbs_get8(&hdr) != 0x2a) {
-		gaim_debug_misc("oscar", "Invalid FLAP frame received on FLAP connection!");
-		aim_conn_close(sess, conn);
-		return -1;
-	}
-
-	fr->hdr.flap.channel = aimbs_get8(&hdr);
-	fr->hdr.flap.seqnum = aimbs_get16(&hdr);
-
-	return aimbs_get16(&hdr);
-}
-
-/*
- * Read a rendezvous header from conn into fr, and return the number of
- * bytes in the payload.
- *
- * @return -1 on error, otherwise return the length of the payload.
- */
-static int aim_get_command_rendezvous(OscarSession *sess, OscarConnection *conn, FlapFrame *fr)
-{
-	guint8 hdr_raw[8];
-	ByteStream hdr;
-
-	fr->hdrtype = AIM_FRAMETYPE_OFT;
-
-	/*
-	 * Read rendezvous header
-	 */
-	aim_bstream_init(&hdr, hdr_raw, sizeof(hdr_raw));
-	if (aim_bstream_recv(&hdr, conn->fd, 8) < 8) {
-		aim_conn_close(sess, conn);
-		return -1;
-	}
-
-	aim_bstream_rewind(&hdr);
-
-	aimbs_getrawbuf(&hdr, fr->hdr.rend.magic, 4);
-	fr->hdr.rend.hdrlen = aimbs_get16(&hdr);
-	fr->hdr.rend.type = aimbs_get16(&hdr);
-
-	return fr->hdr.rend.hdrlen - 8;
-}
-
-/*
- * Grab a single command sequence off the socket, and enqueue it in
- * the incoming event queue in a separate struct.
- *
- * @return 0 on success, otherwise return the error number.
- *         "Success" doesn't mean we have new data, it just means
- *         the connection isn't dead.
- */
-faim_export int aim_get_command(OscarSession *sess, OscarConnection *conn)
-{
-	FlapFrame *fr;
-	int payloadlen;
-
-	if (!sess || !conn)
-		return -EINVAL;
-
-	if (conn->fd == -1)
-		return -1; /* it's an aim_conn_close()'d connection */
-
-	/* If stdin is closed, then zero becomes a valid fd
-	if (conn->fd < 3)
-		return -1;
-	*/
-
-	if (conn->status & AIM_CONN_STATUS_INPROGRESS)
-		return aim_conn_completeconnect(sess, conn);
-
-	if (!(fr = (FlapFrame *)calloc(sizeof(FlapFrame), 1)))
-		return -ENOMEM;
-
-	/*
-	 * Rendezvous (client to client) connections do not speak FLAP, so this
-	 * function will break on them.
-	 */
-	if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)
-		payloadlen = aim_get_command_rendezvous(sess, conn, fr);
-	else if (conn->type == AIM_CONN_TYPE_LISTENER) {
-		gaim_debug_misc("oscar", "AIM_CONN_TYPE_LISTENER on fd %d\n", conn->fd);
-		free(fr);
-		return -1;
-	} else
-		payloadlen = aim_get_command_flap(sess, conn, fr);
-
-	if (payloadlen < 0) {
-		free(fr);
-		return -1;
-	}
-
-	if (payloadlen > 0) {
-		guint8 *payload = NULL;
-
-		if (!(payload = (guint8 *) malloc(payloadlen))) {
-			aim_frame_destroy(fr);
-			return -1;
-		}
-
-		aim_bstream_init(&fr->data, payload, payloadlen);
-
-		/* read the payload */
-		if (aim_bstream_recv(&fr->data, conn->fd, payloadlen) < payloadlen) {
-			aim_frame_destroy(fr); /* free's payload */
-			aim_conn_close(sess, conn);
-			return -1;
-		}
-	} else
-		aim_bstream_init(&fr->data, NULL, 0);
-
-	aim_bstream_rewind(&fr->data);
-
-	fr->conn = conn;
-
-	/* Enqueue this puppy */
-	fr->next = NULL;  /* this will always be at the bottom */
-	if (sess->queue_incoming == NULL)
-		sess->queue_incoming = fr;
-	else {
-		FlapFrame *cur;
-		for (cur = sess->queue_incoming; cur->next; cur = cur->next);
-		cur->next = fr;
-	}
-
-	fr->conn->lastactivity = time(NULL);
-
-	return 0;
-}
-
-/*
- * Purge receive queue of all handled commands (->handled==1).
- *
- */
-faim_export void aim_purge_rxqueue(OscarSession *sess)
-{
-	FlapFrame *cur, **prev;
-
-	for (prev = &sess->queue_incoming; (cur = *prev); ) {
-		if (cur->handled) {
-			*prev = cur->next;
-			aim_frame_destroy(cur);
-		} else
-			prev = &cur->next;
-	}
-
-	return;
-}
-
-/*
- * Since aim_get_command will oscar_connection_destroy dead connections, we need
- * to clean up the rxqueue of unprocessed connections on that socket.
- *
- * XXX: this is something that was handled better in the old connection
- * handling method, but eh.
- */
-faim_internal void aim_rxqueue_cleanbyconn(OscarSession *sess, OscarConnection *conn)
-{
-	FlapFrame *currx;
-
-	for (currx = sess->queue_incoming; currx; currx = currx->next) {
-		if ((!currx->handled) && (currx->conn == conn))
-			currx->handled = 1;
-	}
-
-	return;
-}
--- a/src/protocols/oscar/session.c	Fri Apr 07 01:05:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Gaim'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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include "oscar.h"
-
-/**
- * Allocates a new OscarSession and initializes it with default values.
- */
-OscarSession *
-oscar_session_new(void)
-{
-	OscarSession *sess;
-
-	sess = g_new0(OscarSession, 1);
-
-	aim_initsnachash(sess);
-	sess->snacid_next = 0x00000001;
-
-	/*
-	 * This must always be set.  Default to the queue-based
-	 * version for back-compatibility.
-	 */
-	aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL);
-
-	/*
-	 * Register all the modules for this session...
-	 */
-	aim__registermodule(sess, misc_modfirst); /* load the catch-all first */
-	aim__registermodule(sess, service_modfirst);
-	aim__registermodule(sess, locate_modfirst);
-	aim__registermodule(sess, buddylist_modfirst);
-	aim__registermodule(sess, msg_modfirst);
-	aim__registermodule(sess, adverts_modfirst);
-	aim__registermodule(sess, invite_modfirst);
-	aim__registermodule(sess, admin_modfirst);
-	aim__registermodule(sess, popups_modfirst);
-	aim__registermodule(sess, bos_modfirst);
-	aim__registermodule(sess, search_modfirst);
-	aim__registermodule(sess, stats_modfirst);
-	aim__registermodule(sess, translate_modfirst);
-	aim__registermodule(sess, chatnav_modfirst);
-	aim__registermodule(sess, chat_modfirst);
-	aim__registermodule(sess, odir_modfirst);
-	aim__registermodule(sess, bart_modfirst);
-	/* missing 0x11 - 0x12 */
-	aim__registermodule(sess, ssi_modfirst);
-	/* missing 0x14 */
-	aim__registermodule(sess, icq_modfirst);
-	/* missing 0x16 */
-	aim__registermodule(sess, auth_modfirst);
-	aim__registermodule(sess, email_modfirst);
-
-	return sess;
-}
-
-/**
- * Logoff and deallocate a session.
- *
- * @param sess Session to kill
- */
-void
-oscar_session_destroy(OscarSession *sess)
-{
-	aim_cleansnacs(sess, -1);
-
-	while (sess->oscar_connections != NULL)
-		oscar_connection_destroy(sess, sess->oscar_connections->data);
-
-	aim__shutdownmodules(sess);
-
-	g_free(sess);
-}
--- a/src/protocols/oscar/snac.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/snac.c	Fri Apr 07 05:10:56 2006 +0000
@@ -37,21 +37,21 @@
 /*
  * Called from oscar_session_new() to initialize the hash.
  */
-faim_internal void aim_initsnachash(OscarSession *sess)
+void aim_initsnachash(OscarData *od)
 {
 	int i;
 
 	for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++)
-		sess->snac_hash[i] = NULL;
+		od->snac_hash[i] = NULL;
 
 	return;
 }
 
-faim_internal aim_snacid_t aim_cachesnac(OscarSession *sess, const guint16 family, const guint16 type, const guint16 flags, const void *data, const int datalen)
+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 snac;
 
-	snac.id = sess->snacid_next++;
+	snac.id = od->snacid_next++;
 	snac.family = family;
 	snac.type = type;
 	snac.flags = flags;
@@ -63,14 +63,14 @@
 	} else
 		snac.data = NULL;
 
-	return aim_newsnac(sess, &snac);
+	return aim_newsnac(od, &snac);
 }
 
 /*
  * Clones the passed snac structure and caches it in the
  * list/hash.
  */
-faim_internal aim_snacid_t aim_newsnac(OscarSession *sess, aim_snac_t *newsnac)
+aim_snacid_t aim_newsnac(OscarData *od, aim_snac_t *newsnac)
 {
 	aim_snac_t *snac;
 	int index;
@@ -85,27 +85,27 @@
 
 	index = snac->id % FAIM_SNAC_HASH_SIZE;
 
-	snac->next = (aim_snac_t *)sess->snac_hash[index];
-	sess->snac_hash[index] = (void *)snac;
+	snac->next = (aim_snac_t *)od->snac_hash[index];
+	od->snac_hash[index] = (void *)snac;
 
 	return snac->id;
 }
 
 /*
- * Finds a snac structure with the passed SNAC ID, 
+ * Finds a snac structure with the passed SNAC ID,
  * removes it from the list/hash, and returns a pointer to it.
  *
  * The returned structure must be freed by the caller.
  *
  */
-faim_internal aim_snac_t *aim_remsnac(OscarSession *sess, aim_snacid_t id) 
+aim_snac_t *aim_remsnac(OscarData *od, aim_snacid_t id)
 {
 	aim_snac_t *cur, **prev;
 	int index;
 
 	index = id % FAIM_SNAC_HASH_SIZE;
 
-	for (prev = (aim_snac_t **)&sess->snac_hash[index]; (cur = *prev); ) {
+	for (prev = (aim_snac_t **)&od->snac_hash[index]; (cur = *prev); ) {
 		if (cur->id == id) {
 			*prev = cur->next;
 			if (cur->flags & AIM_SNACFLAGS_DESTRUCTOR) {
@@ -127,7 +127,7 @@
  * maxage is the _minimum_ age in seconds to keep SNACs.
  *
  */
-faim_export void aim_cleansnacs(OscarSession *sess, int maxage)
+void aim_cleansnacs(OscarData *od, int maxage)
 {
 	int i;
 
@@ -135,12 +135,12 @@
 		aim_snac_t *cur, **prev;
 		time_t curtime;
 
-		if (!sess->snac_hash[i])
+		if (!od->snac_hash[i])
 			continue;
 
 		curtime = time(NULL); /* done here in case we waited for the lock */
 
-		for (prev = (aim_snac_t **)&sess->snac_hash[i]; (cur = *prev); ) {
+		for (prev = (aim_snac_t **)&od->snac_hash[i]; (cur = *prev); ) {
 			if ((curtime - cur->issuetime) > maxage) {
 
 				*prev = cur->next;
@@ -155,13 +155,13 @@
 	return;
 }
 
-faim_internal int aim_putsnac(ByteStream *bs, guint16 family, guint16 subtype, guint16 flags, aim_snacid_t snacid)
+int aim_putsnac(ByteStream *bs, guint16 family, guint16 subtype, guint16 flags, aim_snacid_t snacid)
 {
 
-	aimbs_put16(bs, family);
-	aimbs_put16(bs, subtype);
-	aimbs_put16(bs, flags);
-	aimbs_put32(bs, snacid);
+	byte_stream_put16(bs, family);
+	byte_stream_put16(bs, subtype);
+	byte_stream_put16(bs, flags);
+	byte_stream_put32(bs, snacid);
 
 	return 10;
 }
--- a/src/protocols/oscar/snactypes.h	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/snactypes.h	Fri Apr 07 05:10:56 2006 +0000
@@ -28,26 +28,26 @@
 /*
  * SNAC Families.
  */
-#define OSCAR_FAMILY_OSERVICE   0x0001
-#define OSCAR_FAMILY_LOCATE     0x0002
-#define OSCAR_FAMILY_BUDDY      0x0003
-#define OSCAR_FAMILY_ICBM       0x0004
-#define OSCAR_FAMILY_ADVERT     0x0005
-#define OSCAR_FAMILY_INVITE     0x0006
-#define OSCAR_FAMILY_ADMIN      0x0007
-#define OSCAR_FAMILY_POPUP      0x0008
-#define OSCAR_FAMILY_BOS        0x0009
-#define OSCAR_FAMILY_USERLOOKUP 0x000a
-#define OSCAR_FAMILY_STATS      0x000b
-#define OSCAR_FAMILY_TRANSLATE  0x000c
-#define OSCAR_FAMILY_CHATNAV    0x000d
-#define OSCAR_FAMILY_CHAT       0x000e
-#define OSCAR_FAMILY_ODIR       0x000f
-#define OSCAR_FAMILY_BART       0x0010
-#define OSCAR_FAMILY_FEEDBAG    0x0013
-#define OSCAR_FAMILY_ICQ        0x0015
-#define OSCAR_FAMILY_AUTH       0x0017
-#define OSCAR_FAMILY_ALERT      0x0018
+#define SNAC_FAMILY_OSERVICE   0x0001
+#define SNAC_FAMILY_LOCATE     0x0002
+#define SNAC_FAMILY_BUDDY      0x0003
+#define SNAC_FAMILY_ICBM       0x0004
+#define SNAC_FAMILY_ADVERT     0x0005
+#define SNAC_FAMILY_INVITE     0x0006
+#define SNAC_FAMILY_ADMIN      0x0007
+#define SNAC_FAMILY_POPUP      0x0008
+#define SNAC_FAMILY_BOS        0x0009
+#define SNAC_FAMILY_USERLOOKUP 0x000a
+#define SNAC_FAMILY_STATS      0x000b
+#define SNAC_FAMILY_TRANSLATE  0x000c
+#define SNAC_FAMILY_CHATNAV    0x000d
+#define SNAC_FAMILY_CHAT       0x000e
+#define SNAC_FAMILY_ODIR       0x000f
+#define SNAC_FAMILY_BART       0x0010
+#define SNAC_FAMILY_FEEDBAG    0x0013
+#define SNAC_FAMILY_ICQ        0x0015
+#define SNAC_FAMILY_AUTH       0x0017
+#define SNAC_FAMILY_ALERT      0x0018
 
 #define AIM_CB_FAM_SPECIAL 0xffff /* Internal libfaim use */
 
@@ -63,191 +63,190 @@
 /*
  * SNAC Family: General.
  */
-#define OSCAR_SUBTYPE_OSERVICE_ERROR 0x0001
-#define OSCAR_SUBTYPE_OSERVICE_CLIENTREADY 0x0002
-#define OSCAR_SUBTYPE_OSERVICE_SERVERREADY 0x0003
-#define OSCAR_SUBTYPE_OSERVICE_SERVICEREQ 0x0004
-#define OSCAR_SUBTYPE_OSERVICE_REDIRECT 0x0005
-#define OSCAR_SUBTYPE_OSERVICE_RATEINFOREQ 0x0006
-#define OSCAR_SUBTYPE_OSERVICE_RATEINFO 0x0007
-#define OSCAR_SUBTYPE_OSERVICE_RATEINFOACK 0x0008
-#define OSCAR_SUBTYPE_OSERVICE_RATECHANGE 0x000a
-#define OSCAR_SUBTYPE_OSERVICE_SERVERPAUSE 0x000b
-#define OSCAR_SUBTYPE_OSERVICE_SERVERRESUME 0x000d
-#define OSCAR_SUBTYPE_OSERVICE_REQSELFINFO 0x000e
-#define OSCAR_SUBTYPE_OSERVICE_SELFINFO 0x000f
-#define OSCAR_SUBTYPE_OSERVICE_EVIL 0x0010
-#define OSCAR_SUBTYPE_OSERVICE_SETIDLE 0x0011
-#define OSCAR_SUBTYPE_OSERVICE_MIGRATIONREQ 0x0012
-#define OSCAR_SUBTYPE_OSERVICE_MOTD 0x0013
-#define OSCAR_SUBTYPE_OSERVICE_SETPRIVFLAGS 0x0014
-#define OSCAR_SUBTYPE_OSERVICE_WELLKNOWNURL 0x0015
-#define OSCAR_SUBTYPE_OSERVICE_NOP 0x0016
-#define OSCAR_SUBTYPE_OSERVICE_DEFAULT 0xffff
+#define SNAC_SUBTYPE_OSERVICE_ERROR 0x0001
+#define SNAC_SUBTYPE_OSERVICE_CLIENTREADY 0x0002
+#define SNAC_SUBTYPE_OSERVICE_SERVERREADY 0x0003
+#define SNAC_SUBTYPE_OSERVICE_SERVICEREQ 0x0004
+#define SNAC_SUBTYPE_OSERVICE_REDIRECT 0x0005
+#define SNAC_SUBTYPE_OSERVICE_RATEINFOREQ 0x0006
+#define SNAC_SUBTYPE_OSERVICE_RATEINFO 0x0007
+#define SNAC_SUBTYPE_OSERVICE_RATEINFOACK 0x0008
+#define SNAC_SUBTYPE_OSERVICE_RATECHANGE 0x000a
+#define SNAC_SUBTYPE_OSERVICE_SERVERPAUSE 0x000b
+#define SNAC_SUBTYPE_OSERVICE_SERVERRESUME 0x000d
+#define SNAC_SUBTYPE_OSERVICE_REQSELFINFO 0x000e
+#define SNAC_SUBTYPE_OSERVICE_SELFINFO 0x000f
+#define SNAC_SUBTYPE_OSERVICE_EVIL 0x0010
+#define SNAC_SUBTYPE_OSERVICE_SETIDLE 0x0011
+#define SNAC_SUBTYPE_OSERVICE_MIGRATIONREQ 0x0012
+#define SNAC_SUBTYPE_OSERVICE_MOTD 0x0013
+#define SNAC_SUBTYPE_OSERVICE_SETPRIVFLAGS 0x0014
+#define SNAC_SUBTYPE_OSERVICE_WELLKNOWNURL 0x0015
+#define SNAC_SUBTYPE_OSERVICE_NOP 0x0016
+#define SNAC_SUBTYPE_OSERVICE_DEFAULT 0xffff
 
 /*
  * SNAC Family: Location Services.
  */
-#define OSCAR_SUBTYPE_LOCATE_ERROR 0x0001
-#define OSCAR_SUBTYPE_LOCATE_REQRIGHTS 0x0002
-#define OSCAR_SUBTYPE_LOCATE_RIGHTSINFO 0x0003
-#define OSCAR_SUBTYPE_LOCATE_SETUSERINFO 0x0004
-#define OSCAR_SUBTYPE_LOCATE_REQUSERINFO 0x0005
-#define OSCAR_SUBTYPE_LOCATE_USERINFO 0x0006
-#define OSCAR_SUBTYPE_LOCATE_WATCHERSUBREQ 0x0007
-#define OSCAR_SUBTYPE_LOCATE_WATCHERNOT 0x0008
-#define OSCAR_SUBTYPE_LOCATE_GOTINFOBLOCK 0xfffd
-#define OSCAR_SUBTYPE_LOCATE_REQUESTINFOTIMEOUT 0xfffe
-#define OSCAR_SUBTYPE_LOCATE_DEFAULT 0xffff
+#define SNAC_SUBTYPE_LOCATE_ERROR 0x0001
+#define SNAC_SUBTYPE_LOCATE_REQRIGHTS 0x0002
+#define SNAC_SUBTYPE_LOCATE_RIGHTSINFO 0x0003
+#define SNAC_SUBTYPE_LOCATE_SETUSERINFO 0x0004
+#define SNAC_SUBTYPE_LOCATE_REQUSERINFO 0x0005
+#define SNAC_SUBTYPE_LOCATE_USERINFO 0x0006
+#define SNAC_SUBTYPE_LOCATE_WATCHERSUBREQ 0x0007
+#define SNAC_SUBTYPE_LOCATE_WATCHERNOT 0x0008
+#define SNAC_SUBTYPE_LOCATE_GOTINFOBLOCK 0xfffd
+#define SNAC_SUBTYPE_LOCATE_DEFAULT 0xffff
 
 /*
  * SNAC Family: Buddy List Management Services.
  */
-#define OSCAR_SUBTYPE_BUDDY_ERROR 0x0001
-#define OSCAR_SUBTYPE_BUDDY_REQRIGHTS 0x0002
-#define OSCAR_SUBTYPE_BUDDY_RIGHTSINFO 0x0003
-#define OSCAR_SUBTYPE_BUDDY_ADDBUDDY 0x0004
-#define OSCAR_SUBTYPE_BUDDY_REMBUDDY 0x0005
-#define OSCAR_SUBTYPE_BUDDY_REJECT 0x000a
-#define OSCAR_SUBTYPE_BUDDY_ONCOMING 0x000b
-#define OSCAR_SUBTYPE_BUDDY_OFFGOING 0x000c
-#define OSCAR_SUBTYPE_BUDDY_DEFAULT 0xffff
+#define SNAC_SUBTYPE_BUDDY_ERROR 0x0001
+#define SNAC_SUBTYPE_BUDDY_REQRIGHTS 0x0002
+#define SNAC_SUBTYPE_BUDDY_RIGHTSINFO 0x0003
+#define SNAC_SUBTYPE_BUDDY_ADDBUDDY 0x0004
+#define SNAC_SUBTYPE_BUDDY_REMBUDDY 0x0005
+#define SNAC_SUBTYPE_BUDDY_REJECT 0x000a
+#define SNAC_SUBTYPE_BUDDY_ONCOMING 0x000b
+#define SNAC_SUBTYPE_BUDDY_OFFGOING 0x000c
+#define SNAC_SUBTYPE_BUDDY_DEFAULT 0xffff
 
 /*
  * SNAC Family: Messaging Services.
  */
-#define OSCAR_SUBTYPE_ICBM_ERROR 0x0001
-#define OSCAR_SUBTYPE_ICBM_PARAMINFO 0x0005
-#define OSCAR_SUBTYPE_ICBM_INCOMING 0x0007
-#define OSCAR_SUBTYPE_ICBM_EVIL 0x0009
-#define OSCAR_SUBTYPE_ICBM_MISSEDCALL 0x000a
-#define OSCAR_SUBTYPE_ICBM_CLIENTAUTORESP 0x000b
-#define OSCAR_SUBTYPE_ICBM_ACK 0x000c
-#define OSCAR_SUBTYPE_ICBM_MTN 0x0014
-#define OSCAR_SUBTYPE_ICBM_DEFAULT 0xffff
+#define SNAC_SUBTYPE_ICBM_ERROR 0x0001
+#define SNAC_SUBTYPE_ICBM_PARAMINFO 0x0005
+#define SNAC_SUBTYPE_ICBM_INCOMING 0x0007
+#define SNAC_SUBTYPE_ICBM_EVIL 0x0009
+#define SNAC_SUBTYPE_ICBM_MISSEDCALL 0x000a
+#define SNAC_SUBTYPE_ICBM_CLIENTAUTORESP 0x000b
+#define SNAC_SUBTYPE_ICBM_ACK 0x000c
+#define SNAC_SUBTYPE_ICBM_MTN 0x0014
+#define SNAC_SUBTYPE_ICBM_DEFAULT 0xffff
 
 /*
  * SNAC Family: Advertisement Services
  */
-#define OSCAR_SUBTYPE_ADVERT_ERROR 0x0001
-#define OSCAR_SUBTYPE_ADVERT_DEFAULT 0xffff
+#define SNAC_SUBTYPE_ADVERT_ERROR 0x0001
+#define SNAC_SUBTYPE_ADVERT_DEFAULT 0xffff
 
 /*
  * SNAC Family: Invitation Services.
  */
-#define OSCAR_SUBTYPE_INVITE_ERROR 0x0001
-#define OSCAR_SUBTYPE_INVITE_DEFAULT 0xffff
+#define SNAC_SUBTYPE_INVITE_ERROR 0x0001
+#define SNAC_SUBTYPE_INVITE_DEFAULT 0xffff
 
 /*
  * SNAC Family: Administrative Services.
  */
-#define OSCAR_SUBTYPE_ADMIN_ERROR 0x0001
-#define OSCAR_SUBTYPE_ADMIN_INFOCHANGE_REPLY 0x0005
-#define OSCAR_SUBTYPE_ADMIN_DEFAULT 0xffff
+#define SNAC_SUBTYPE_ADMIN_ERROR 0x0001
+#define SNAC_SUBTYPE_ADMIN_INFOCHANGE_REPLY 0x0005
+#define SNAC_SUBTYPE_ADMIN_DEFAULT 0xffff
 
 /*
  * SNAC Family: Popup Messages
  */
-#define OSCAR_SUBTYPE_POPUP_ERROR 0x0001
-#define OSCAR_SUBTYPE_POPUP_DEFAULT 0xffff
+#define SNAC_SUBTYPE_POPUP_ERROR 0x0001
+#define SNAC_SUBTYPE_POPUP_DEFAULT 0xffff
 
 /*
  * SNAC Family: Misc BOS Services.
  */
-#define OSCAR_SUBTYPE_BOS_ERROR 0x0001
-#define OSCAR_SUBTYPE_BOS_RIGHTSQUERY 0x0002
-#define OSCAR_SUBTYPE_BOS_RIGHTS 0x0003
-#define OSCAR_SUBTYPE_BOS_DEFAULT 0xffff
+#define SNAC_SUBTYPE_BOS_ERROR 0x0001
+#define SNAC_SUBTYPE_BOS_RIGHTSQUERY 0x0002
+#define SNAC_SUBTYPE_BOS_RIGHTS 0x0003
+#define SNAC_SUBTYPE_BOS_DEFAULT 0xffff
 
 /*
  * SNAC Family: User Lookup Services
  */
-#define OSCAR_SUBTYPE_USERLOOKUP_ERROR 0x0001
-#define OSCAR_SUBTYPE_USERLOOKUP_DEFAULT 0xffff
+#define SNAC_SUBTYPE_USERLOOKUP_ERROR 0x0001
+#define SNAC_SUBTYPE_USERLOOKUP_DEFAULT 0xffff
 
 /*
  * SNAC Family: User Status Services
  */
-#define OSCAR_SUBTYPE_STATS_ERROR 0x0001
-#define OSCAR_SUBTYPE_STATS_SETREPORTINTERVAL 0x0002
-#define OSCAR_SUBTYPE_STATS_REPORTACK 0x0004
-#define OSCAR_SUBTYPE_STATS_DEFAULT 0xffff
+#define SNAC_SUBTYPE_STATS_ERROR 0x0001
+#define SNAC_SUBTYPE_STATS_SETREPORTINTERVAL 0x0002
+#define SNAC_SUBTYPE_STATS_REPORTACK 0x0004
+#define SNAC_SUBTYPE_STATS_DEFAULT 0xffff
 
 /*
  * SNAC Family: Translation Services
  */
-#define OSCAR_SUBTYPE_TRANSLATE_ERROR 0x0001
-#define OSCAR_SUBTYPE_TRANSLATE_DEFAULT 0xffff
+#define SNAC_SUBTYPE_TRANSLATE_ERROR 0x0001
+#define SNAC_SUBTYPE_TRANSLATE_DEFAULT 0xffff
 
 /*
  * SNAC Family: Chat Navigation Services
  */
-#define OSCAR_SUBTYPE_CHATNAV_ERROR 0x0001
-#define OSCAR_SUBTYPE_CHATNAV_CREATE 0x0008
-#define OSCAR_SUBTYPE_CHATNAV_INFO 0x0009
-#define OSCAR_SUBTYPE_CHATNAV_DEFAULT 0xffff
+#define SNAC_SUBTYPE_CHATNAV_ERROR 0x0001
+#define SNAC_SUBTYPE_CHATNAV_CREATE 0x0008
+#define SNAC_SUBTYPE_CHATNAV_INFO 0x0009
+#define SNAC_SUBTYPE_CHATNAV_DEFAULT 0xffff
 
 /*
  * SNAC Family: Chat Services
  */
-#define OSCAR_SUBTYPE_CHAT_ERROR 0x0001
-#define OSCAR_SUBTYPE_CHAT_ROOMINFOUPDATE 0x0002
-#define OSCAR_SUBTYPE_CHAT_USERJOIN 0x0003
-#define OSCAR_SUBTYPE_CHAT_USERLEAVE 0x0004
-#define OSCAR_SUBTYPE_CHAT_OUTGOINGMSG 0x0005
-#define OSCAR_SUBTYPE_CHAT_INCOMINGMSG 0x0006
-#define OSCAR_SUBTYPE_CHAT_DEFAULT 0xffff
+#define SNAC_SUBTYPE_CHAT_ERROR 0x0001
+#define SNAC_SUBTYPE_CHAT_ROOMINFOUPDATE 0x0002
+#define SNAC_SUBTYPE_CHAT_USERJOIN 0x0003
+#define SNAC_SUBTYPE_CHAT_USERLEAVE 0x0004
+#define SNAC_SUBTYPE_CHAT_OUTGOINGMSG 0x0005
+#define SNAC_SUBTYPE_CHAT_INCOMINGMSG 0x0006
+#define SNAC_SUBTYPE_CHAT_DEFAULT 0xffff
 
 /*
  * SNAC Family: "New" Search
  */
-#define OSCAR_SUBTYPE_ODIR_ERROR 0x0001
-#define OSCAR_SUBTYPE_ODIR_SEARCH 0x0002
-#define OSCAR_SUBTYPE_ODIR_RESULTS 0x0003
+#define SNAC_SUBTYPE_ODIR_ERROR 0x0001
+#define SNAC_SUBTYPE_ODIR_SEARCH 0x0002
+#define SNAC_SUBTYPE_ODIR_RESULTS 0x0003
 
 /*
  * SNAC Family: Buddy icons
  */
-#define OSCAR_SUBTYPE_BART_ERROR 0x0001
-#define OSCAR_SUBTYPE_BART_REQUEST 0x0004
-#define OSCAR_SUBTYPE_BART_RESPONSE 0x0005
+#define SNAC_SUBTYPE_BART_ERROR 0x0001
+#define SNAC_SUBTYPE_BART_REQUEST 0x0004
+#define SNAC_SUBTYPE_BART_RESPONSE 0x0005
 
 /*
  * SNAC Family: Server-Stored Buddy Lists
  */
-#define OSCAR_SUBTYPE_FEEDBAG_ERROR 0x0001
-#define OSCAR_SUBTYPE_FEEDBAG_REQRIGHTS 0x0002
-#define OSCAR_SUBTYPE_FEEDBAG_RIGHTSINFO 0x0003
-#define OSCAR_SUBTYPE_FEEDBAG_REQDATA 0x0004
-#define OSCAR_SUBTYPE_FEEDBAG_REQIFCHANGED 0x0005
-#define OSCAR_SUBTYPE_FEEDBAG_LIST 0x0006
-#define OSCAR_SUBTYPE_FEEDBAG_ACTIVATE 0x0007
-#define OSCAR_SUBTYPE_FEEDBAG_ADD 0x0008
-#define OSCAR_SUBTYPE_FEEDBAG_MOD 0x0009
-#define OSCAR_SUBTYPE_FEEDBAG_DEL 0x000A
-#define OSCAR_SUBTYPE_FEEDBAG_SRVACK 0x000E
-#define OSCAR_SUBTYPE_FEEDBAG_NOLIST 0x000F
-#define OSCAR_SUBTYPE_FEEDBAG_EDITSTART 0x0011
-#define OSCAR_SUBTYPE_FEEDBAG_EDITSTOP 0x0012
-#define OSCAR_SUBTYPE_FEEDBAG_SENDAUTH 0x0014
-#define OSCAR_SUBTYPE_FEEDBAG_RECVAUTH 0x0015
-#define OSCAR_SUBTYPE_FEEDBAG_SENDAUTHREQ 0x0018
-#define OSCAR_SUBTYPE_FEEDBAG_RECVAUTHREQ 0x0019
-#define OSCAR_SUBTYPE_FEEDBAG_SENDAUTHREP 0x001a
-#define OSCAR_SUBTYPE_FEEDBAG_RECVAUTHREP 0x001b
-#define OSCAR_SUBTYPE_FEEDBAG_ADDED 0x001c
+#define SNAC_SUBTYPE_FEEDBAG_ERROR 0x0001
+#define SNAC_SUBTYPE_FEEDBAG_REQRIGHTS 0x0002
+#define SNAC_SUBTYPE_FEEDBAG_RIGHTSINFO 0x0003
+#define SNAC_SUBTYPE_FEEDBAG_REQDATA 0x0004
+#define SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED 0x0005
+#define SNAC_SUBTYPE_FEEDBAG_LIST 0x0006
+#define SNAC_SUBTYPE_FEEDBAG_ACTIVATE 0x0007
+#define SNAC_SUBTYPE_FEEDBAG_ADD 0x0008
+#define SNAC_SUBTYPE_FEEDBAG_MOD 0x0009
+#define SNAC_SUBTYPE_FEEDBAG_DEL 0x000A
+#define SNAC_SUBTYPE_FEEDBAG_SRVACK 0x000E
+#define SNAC_SUBTYPE_FEEDBAG_NOLIST 0x000F
+#define SNAC_SUBTYPE_FEEDBAG_EDITSTART 0x0011
+#define SNAC_SUBTYPE_FEEDBAG_EDITSTOP 0x0012
+#define SNAC_SUBTYPE_FEEDBAG_SENDAUTH 0x0014
+#define SNAC_SUBTYPE_FEEDBAG_RECVAUTH 0x0015
+#define SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ 0x0018
+#define SNAC_SUBTYPE_FEEDBAG_RECVAUTHREQ 0x0019
+#define SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP 0x001a
+#define SNAC_SUBTYPE_FEEDBAG_RECVAUTHREP 0x001b
+#define SNAC_SUBTYPE_FEEDBAG_ADDED 0x001c
 
 /*
  * SNAC Family: ICQ
  *
  * Most of these are actually special.
  */
-#define OSCAR_SUBTYPE_ICQ_ERROR 0x0001
-#define OSCAR_SUBTYPE_ICQ_OFFLINEMSG 0x00f0
-#define OSCAR_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE 0x00f1
-#define OSCAR_SUBTYPE_ICQ_INFO 0x00f2
-#define OSCAR_SUBTYPE_ICQ_ALIAS 0x00f3
-#define OSCAR_SUBTYPE_ICQ_DEFAULT 0xffff
+#define SNAC_SUBTYPE_ICQ_ERROR 0x0001
+#define SNAC_SUBTYPE_ICQ_OFFLINEMSG 0x00f0
+#define SNAC_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE 0x00f1
+#define SNAC_SUBTYPE_ICQ_INFO 0x00f2
+#define SNAC_SUBTYPE_ICQ_ALIAS 0x00f3
+#define SNAC_SUBTYPE_ICQ_DEFAULT 0xffff
 
 /*
  * SNAC Family: Authorizer
@@ -255,13 +254,13 @@
  * Used only in protocol versions three and above.
  *
  */
-#define OSCAR_SUBTYPE_AUTH_ERROR 0x0001
-#define OSCAR_SUBTYPE_AUTH_LOGINREQEST 0x0002
-#define OSCAR_SUBTYPE_AUTH_LOGINRESPONSE 0x0003
-#define OSCAR_SUBTYPE_AUTH_AUTHREQ 0x0006
-#define OSCAR_SUBTYPE_AUTH_AUTHRESPONSE 0x0007
-#define OSCAR_SUBTYPE_AUTH_SECURID_REQUEST 0x000a
-#define OSCAR_SUBTYPE_AUTH_SECURID_RESPONSE 0x000b
+#define SNAC_SUBTYPE_AUTH_ERROR 0x0001
+#define SNAC_SUBTYPE_AUTH_LOGINREQEST 0x0002
+#define SNAC_SUBTYPE_AUTH_LOGINRESPONSE 0x0003
+#define SNAC_SUBTYPE_AUTH_AUTHREQ 0x0006
+#define SNAC_SUBTYPE_AUTH_AUTHRESPONSE 0x0007
+#define SNAC_SUBTYPE_AUTH_SECURID_REQUEST 0x000a
+#define SNAC_SUBTYPE_AUTH_SECURID_RESPONSE 0x000b
 
 /*
  * SNAC Family: Email
@@ -270,10 +269,10 @@
  * associated with your screen name.
  *
  */
-#define OSCAR_SUBTYPE_ALERT_ERROR 0x0001
-#define OSCAR_SUBTYPE_ALERT_SENDCOOKIES 0x0006
-#define OSCAR_SUBTYPE_ALERT_MAILSTATUS 0x0007
-#define OSCAR_SUBTYPE_ALERT_INIT 0x0016
+#define SNAC_SUBTYPE_ALERT_ERROR 0x0001
+#define SNAC_SUBTYPE_ALERT_SENDCOOKIES 0x0006
+#define SNAC_SUBTYPE_ALERT_MAILSTATUS 0x0007
+#define SNAC_SUBTYPE_ALERT_INIT 0x0016
 
 /*
  * SNAC Family: Internal Messages
@@ -284,9 +283,7 @@
  *
  */
 #define AIM_CB_SPECIAL_CONNERR 0x0003
-#define AIM_CB_SPECIAL_FLAPVER 0x0005
 #define AIM_CB_SPECIAL_CONNINITDONE 0x0006
-#define AIM_CB_SPECIAL_IMAGETRANSFER 0x0007
 
 /* SNAC flags */
 #define AIM_SNACFLAGS_DESTRUCTOR 0x0001
--- a/src/protocols/oscar/tlv.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/tlv.c	Fri Apr 07 05:10:56 2006 +0000
@@ -21,12 +21,12 @@
 
 #include "oscar.h"
 
-static aim_tlv_t *createtlv(guint16 type, guint16 length, guint8 *value)
+static aim_tlv_t *
+createtlv(guint16 type, guint16 length, guint8 *value)
 {
 	aim_tlv_t *ret;
 
-	if (!(ret = (aim_tlv_t *)malloc(sizeof(aim_tlv_t))))
-		return NULL;
+	ret = g_new(aim_tlv_t, 1);
 	ret->type = type;
 	ret->length = length;
 	ret->value = value;
@@ -34,7 +34,8 @@
 	return ret;
 }
 
-static void freetlv(aim_tlv_t **oldtlv)
+static void
+freetlv(aim_tlv_t **oldtlv)
 {
 
 	if (!oldtlv || !*oldtlv)
@@ -56,7 +57,7 @@
  * be called to free the dynamic substructures.
  *
  * XXX There should be a flag setable here to have the tlvlist contain
- * bstream references, so that at least the ->value portion of each 
+ * bstream references, so that at least the ->value portion of each
  * element doesn't need to be malloc/memcpy'd.  This could prove to be
  * just as efficient as the in-place TLV parsing used in a couple places
  * in libfaim.
@@ -64,21 +65,21 @@
  * @param bs Input bstream
  * @return Return the TLV chain read
  */
-faim_internal aim_tlvlist_t *aim_tlvlist_read(ByteStream *bs)
+aim_tlvlist_t *aim_tlvlist_read(ByteStream *bs)
 {
 	aim_tlvlist_t *list = NULL, *cur;
 
-	while (aim_bstream_empty(bs) > 0) {
+	while (byte_stream_empty(bs) > 0) {
 		guint16 type, length;
 
-		type = aimbs_get16(bs);
-		length = aimbs_get16(bs);
+		type = byte_stream_get16(bs);
+		length = byte_stream_get16(bs);
 
 #if 0 /* temporarily disabled until I know if they're still doing it or not */
 		/*
 		 * 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 
+		 * 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)
@@ -91,27 +92,15 @@
 #endif
 		else {
 
-			if (length > aim_bstream_empty(bs)) {
-				aim_tlvlist_free(&list);
-				return NULL;
-			}
-
-			cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t));
-			if (!cur) {
+			if (length > byte_stream_empty(bs)) {
 				aim_tlvlist_free(&list);
 				return NULL;
 			}
 
-			memset(cur, 0, sizeof(aim_tlvlist_t));
-
+			cur = g_new0(aim_tlvlist_t, 1);
 			cur->tlv = createtlv(type, length, NULL);
-			if (!cur->tlv) {
-				free(cur);
-				aim_tlvlist_free(&list);
-				return NULL;
-			}
 			if (cur->tlv->length > 0) {
-				cur->tlv->value = aimbs_getraw(bs, length);
+				cur->tlv->value = byte_stream_getraw(bs, length);
 				if (!cur->tlv->value) {
 					freetlv(&cur->tlv);
 					free(cur);
@@ -137,49 +126,37 @@
  * be called to free the dynamic substructures.
  *
  * XXX There should be a flag setable here to have the tlvlist contain
- * bstream references, so that at least the ->value portion of each 
+ * bstream references, so that at least the ->value portion of each
  * element doesn't need to be malloc/memcpy'd.  This could prove to be
  * just as efficient as the in-place TLV parsing used in a couple places
  * in libfaim.
  *
  * @param bs Input bstream
- * @param num The max number of TLVs that will be read, or -1 if unlimited.  
- *        There are a number of places where you want to read in a tlvchain, 
- *        but the chain is not at the end of the SNAC, and the chain is 
+ * @param num The max number of TLVs that will be read, or -1 if unlimited.
+ *        There are a number of places where you want to read in a tlvchain,
+ *        but the chain is not at the end of the SNAC, and the chain is
  *        preceded by the number of TLVs.  So you can limit that with this.
  * @return Return the TLV chain read
  */
-faim_internal aim_tlvlist_t *aim_tlvlist_readnum(ByteStream *bs, guint16 num)
+aim_tlvlist_t *aim_tlvlist_readnum(ByteStream *bs, guint16 num)
 {
 	aim_tlvlist_t *list = NULL, *cur;
 
-	while ((aim_bstream_empty(bs) > 0) && (num != 0)) {
+	while ((byte_stream_empty(bs) > 0) && (num != 0)) {
 		guint16 type, length;
 
-		type = aimbs_get16(bs);
-		length = aimbs_get16(bs);
+		type = byte_stream_get16(bs);
+		length = byte_stream_get16(bs);
 
-		if (length > aim_bstream_empty(bs)) {
+		if (length > byte_stream_empty(bs)) {
 			aim_tlvlist_free(&list);
 			return NULL;
 		}
 
-		cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t));
-		if (!cur) {
-			aim_tlvlist_free(&list);
-			return NULL;
-		}
-
-		memset(cur, 0, sizeof(aim_tlvlist_t));
-
+		cur = g_new0(aim_tlvlist_t, 1);
 		cur->tlv = createtlv(type, length, NULL);
-		if (!cur->tlv) {
-			free(cur);
-			aim_tlvlist_free(&list);
-			return NULL;
-		}
 		if (cur->tlv->length > 0) {
-			cur->tlv->value = aimbs_getraw(bs, length);
+			cur->tlv->value = byte_stream_getraw(bs, length);
 			if (!cur->tlv->value) {
 				freetlv(&cur->tlv);
 				free(cur);
@@ -206,49 +183,37 @@
  * be called to free the dynamic substructures.
  *
  * XXX There should be a flag setable here to have the tlvlist contain
- * bstream references, so that at least the ->value portion of each 
+ * bstream references, so that at least the ->value portion of each
  * element doesn't need to be malloc/memcpy'd.  This could prove to be
  * just as efficient as the in-place TLV parsing used in a couple places
  * in libfaim.
  *
  * @param bs Input bstream
  * @param len The max length in bytes that will be read.
- *        There are a number of places where you want to read in a tlvchain, 
- *        but the chain is not at the end of the SNAC, and the chain is 
+ *        There are a number of places where you want to read in a tlvchain,
+ *        but the chain is not at the end of the SNAC, and the chain is
  *        preceded by the length of the TLVs.  So you can limit that with this.
  * @return Return the TLV chain read
  */
-faim_internal aim_tlvlist_t *aim_tlvlist_readlen(ByteStream *bs, guint16 len)
+aim_tlvlist_t *aim_tlvlist_readlen(ByteStream *bs, guint16 len)
 {
 	aim_tlvlist_t *list = NULL, *cur;
 
-	while ((aim_bstream_empty(bs) > 0) && (len > 0)) {
+	while ((byte_stream_empty(bs) > 0) && (len > 0)) {
 		guint16 type, length;
 
-		type = aimbs_get16(bs);
-		length = aimbs_get16(bs);
+		type = byte_stream_get16(bs);
+		length = byte_stream_get16(bs);
 
-		if (length > aim_bstream_empty(bs)) {
+		if (length > byte_stream_empty(bs)) {
 			aim_tlvlist_free(&list);
 			return NULL;
 		}
 
-		cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t));
-		if (!cur) {
-			aim_tlvlist_free(&list);
-			return NULL;
-		}
-
-		memset(cur, 0, sizeof(aim_tlvlist_t));
-
+		cur = g_new0(aim_tlvlist_t, 1);
 		cur->tlv = createtlv(type, length, NULL);
-		if (!cur->tlv) {
-			free(cur);
-			aim_tlvlist_free(&list);
-			return NULL;
-		}
 		if (cur->tlv->length > 0) {
-			cur->tlv->value = aimbs_getraw(bs, length);
+			cur->tlv->value = byte_stream_getraw(bs, length);
 			if (!cur->tlv->value) {
 				freetlv(&cur->tlv);
 				free(cur);
@@ -272,7 +237,7 @@
  * @param orig The TLV chain you want to make a copy of.
  * @return A newly allocated TLV chain.
  */
-faim_internal aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig)
+aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig)
 {
 	aim_tlvlist_t *new = NULL;
 
@@ -285,22 +250,22 @@
 }
 
 /*
- * Compare two TLV lists for equality.  This probably is not the most 
+ * Compare two TLV lists for equality.  This probably is not the most
  * efficient way to do this.
  *
  * @param one One of the TLV chains to compare.
  * @param two The other TLV chain to compare.
  * @return Return 0 if the lists are the same, return 1 if they are different.
  */
-faim_internal int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two)
+int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two)
 {
 	ByteStream bs1, bs2;
 
 	if (aim_tlvlist_size(&one) != aim_tlvlist_size(&two))
 		return 1;
 
-	aim_bstream_init(&bs1, ((guint8 *)malloc(aim_tlvlist_size(&one)*sizeof(guint8))), aim_tlvlist_size(&one));
-	aim_bstream_init(&bs2, ((guint8 *)malloc(aim_tlvlist_size(&two)*sizeof(guint8))), aim_tlvlist_size(&two));
+	byte_stream_init(&bs1, ((guint8 *)malloc(aim_tlvlist_size(&one)*sizeof(guint8))), aim_tlvlist_size(&one));
+	byte_stream_init(&bs2, ((guint8 *)malloc(aim_tlvlist_size(&two)*sizeof(guint8))), aim_tlvlist_size(&two));
 
 	aim_tlvlist_write(&bs1, &one);
 	aim_tlvlist_write(&bs2, &two);
@@ -326,7 +291,7 @@
  *
  * @param list Chain to be freed
  */
-faim_internal void aim_tlvlist_free(aim_tlvlist_t **list)
+void aim_tlvlist_free(aim_tlvlist_t **list)
 {
 	aim_tlvlist_t *cur;
 
@@ -354,7 +319,7 @@
  * @param list Chain to be counted.
  * @return The number of TLVs stored in the passed chain.
  */
-faim_internal int aim_tlvlist_count(aim_tlvlist_t **list)
+int aim_tlvlist_count(aim_tlvlist_t **list)
 {
 	aim_tlvlist_t *cur;
 	int count;
@@ -372,10 +337,10 @@
  * Count the number of bytes in a TLV chain.
  *
  * @param list Chain to be sized
- * @return The number of bytes that would be needed to 
+ * @return The number of bytes that would be needed to
  *         write the passed TLV chain to a data buffer.
  */
-faim_internal int aim_tlvlist_size(aim_tlvlist_t **list)
+int aim_tlvlist_size(aim_tlvlist_t **list)
 {
 	aim_tlvlist_t *cur;
 	int size;
@@ -399,25 +364,17 @@
  * @param value String to add.
  * @return The size of the value added.
  */
-faim_internal int aim_tlvlist_add_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value)
+int aim_tlvlist_add_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value)
 {
 	aim_tlvlist_t *newtlv, *cur;
 
 	if (list == NULL)
 		return 0;
 
-	if (!(newtlv = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t))))
-		return 0;
-	memset(newtlv, 0x00, sizeof(aim_tlvlist_t));
-
-	if (!(newtlv->tlv = createtlv(type, length, NULL))) {
-		free(newtlv);
-		return 0;
-	}
-	if (newtlv->tlv->length > 0) {
-		newtlv->tlv->value = (guint8 *)malloc(newtlv->tlv->length);
-		memcpy(newtlv->tlv->value, value, newtlv->tlv->length);
-	}
+	newtlv = g_new0(aim_tlvlist_t, 1);
+	newtlv->tlv = createtlv(type, length, NULL);
+	if (newtlv->tlv->length > 0)
+		newtlv->tlv->value = g_memdup(value, length);
 
 	if (!*list)
 		*list = newtlv;
@@ -438,7 +395,7 @@
  * @param value Value to add.
  * @return The size of the value added.
  */
-faim_internal int aim_tlvlist_add_8(aim_tlvlist_t **list, const guint16 type, const guint8 value)
+int aim_tlvlist_add_8(aim_tlvlist_t **list, const guint16 type, const guint8 value)
 {
 	guint8 v8[1];
 
@@ -455,7 +412,7 @@
  * @param value Value to add.
  * @return The size of the value added.
  */
-faim_internal int aim_tlvlist_add_16(aim_tlvlist_t **list, const guint16 type, const guint16 value)
+int aim_tlvlist_add_16(aim_tlvlist_t **list, const guint16 type, const guint16 value)
 {
 	guint8 v16[2];
 
@@ -472,7 +429,7 @@
  * @param value Value to add.
  * @return The size of the value added.
  */
-faim_internal int aim_tlvlist_add_32(aim_tlvlist_t **list, const guint16 type, const guint32 value)
+int aim_tlvlist_add_32(aim_tlvlist_t **list, const guint16 type, const guint32 value)
 {
 	guint8 v32[4];
 
@@ -489,7 +446,7 @@
  * @param value Value to add.
  * @return The size of the value added.
  */
-faim_internal int aim_tlvlist_add_str(aim_tlvlist_t **list, const guint16 type, const char *value)
+int aim_tlvlist_add_str(aim_tlvlist_t **list, const guint16 type, const char *value)
 {
 	return aim_tlvlist_add_raw(list, type, strlen(value), (guint8 *)value);
 }
@@ -498,19 +455,19 @@
  * 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:
  *
- *     %AIM_CAPS_BUDDYICON   Supports Buddy Icons
- *     %AIM_CAPS_TALK        Supports Voice Chat
- *     %AIM_CAPS_IMIMAGE     Supports DirectIM/IMImage
- *     %AIM_CAPS_CHAT        Supports Chat
- *     %AIM_CAPS_GETFILE     Supports Get File functions
- *     %AIM_CAPS_SENDFILE    Supports Send File functions
+ *     %OSCAR_CAPABILITY_BUDDYICON   Supports Buddy Icons
+ *     %OSCAR_CAPABILITY_TALK        Supports Voice Chat
+ *     %OSCAR_CAPABILITY_IMIMAGE     Supports DirectIM/IMImage
+ *     %OSCAR_CAPABILITY_CHAT        Supports Chat
+ *     %OSCAR_CAPABILITY_GETFILE     Supports Get File functions
+ *     %OSCAR_CAPABILITY_SENDFILE    Supports Send File functions
  *
  * @param list Destination chain
  * @param type TLV type to add
  * @param caps Bitfield of capability flags to send
  * @return The size of the value added.
  */
-faim_internal int aim_tlvlist_add_caps(aim_tlvlist_t **list, const guint16 type, const guint32 caps)
+int aim_tlvlist_add_caps(aim_tlvlist_t **list, const guint16 type, const guint32 caps)
 {
 	guint8 buf[16*16]; /* XXX icky fixed length buffer */
 	ByteStream bs;
@@ -518,11 +475,11 @@
 	if (!caps)
 		return 0; /* nothing there anyway */
 
-	aim_bstream_init(&bs, buf, sizeof(buf));
+	byte_stream_init(&bs, buf, sizeof(buf));
 
-	aimbs_putcaps(&bs, caps);
+	byte_stream_putcaps(&bs, caps);
 
-	return aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf);
+	return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), buf);
 }
 
 /**
@@ -532,16 +489,16 @@
  * @param type TLV type to add.
  * @return The size of the value added.
  */
-faim_internal int aim_tlvlist_add_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *userinfo)
+int aim_tlvlist_add_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *userinfo)
 {
 	guint8 buf[1024]; /* bleh */
 	ByteStream bs;
 
-	aim_bstream_init(&bs, buf, sizeof(buf));
+	byte_stream_init(&bs, buf, sizeof(buf));
 
 	aim_putuserinfo(&bs, userinfo);
 
-	return aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf);
+	return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), buf);
 }
 
 /**
@@ -553,7 +510,7 @@
  * @param instance The instance.
  * @return The size of the value added.
  */
-faim_internal int aim_tlvlist_add_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance)
+int aim_tlvlist_add_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance)
 {
 	guint8 *buf;
 	int len;
@@ -561,17 +518,15 @@
 
 	len = 2 + 1 + strlen(roomname) + 2;
 
-	if (!(buf = malloc(len)))
-		return 0;
-
-	aim_bstream_init(&bs, buf, len);
+	buf = malloc(len);
+	byte_stream_init(&bs, buf, len);
 
-	aimbs_put16(&bs, exchange);
-	aimbs_put8(&bs, strlen(roomname));
-	aimbs_putstr(&bs, roomname);
-	aimbs_put16(&bs, instance);
+	byte_stream_put16(&bs, exchange);
+	byte_stream_put8(&bs, strlen(roomname));
+	byte_stream_putstr(&bs, roomname);
+	byte_stream_put16(&bs, instance);
 
-	len = aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf);
+	len = aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), buf);
 
 	free(buf);
 
@@ -585,7 +540,7 @@
  * @param type TLV type to add.
  * @return The size of the value added.
  */
-faim_internal int aim_tlvlist_add_noval(aim_tlvlist_t **list, const guint16 type)
+int aim_tlvlist_add_noval(aim_tlvlist_t **list, const guint16 type)
 {
 	return aim_tlvlist_add_raw(list, type, 0, NULL);
 }
@@ -596,7 +551,7 @@
  * made to this.
  *
  * XXX should probably support sublists for real.
- * 
+ *
  * This is so neat.
  *
  * @param list Destination chain.
@@ -606,7 +561,7 @@
  *         0 is returned if there was an error or if the destination
  *         TLV chain has length 0.
  */
-faim_internal int aim_tlvlist_add_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl)
+int aim_tlvlist_add_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl)
 {
 	guint8 *buf;
 	int buflen;
@@ -617,14 +572,13 @@
 	if (buflen <= 0)
 		return 0;
 
-	if (!(buf = malloc(buflen)))
-		return 0;
+	buf = malloc(buflen);
 
-	aim_bstream_init(&bs, buf, buflen);
+	byte_stream_init(&bs, buf, buflen);
 
 	aim_tlvlist_write(&bs, tl);
 
-	aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf);
+	aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), buf);
 
 	free(buf);
 
@@ -632,8 +586,8 @@
 }
 
 /**
- * Substitute a TLV of a given type with a new TLV of the same type.  If 
- * you attempt to replace a TLV that does not exist, this function will 
+ * Substitute a TLV of a given type with a new TLV of the same type.  If
+ * you attempt to replace a TLV that does not exist, this function will
  * just add a new TLV as if you called aim_tlvlist_add_raw().
  *
  * @param list Desination chain (%NULL pointer if empty).
@@ -642,7 +596,7 @@
  * @param value String to add.
  * @return The length of the TLV.
  */
-faim_internal int aim_tlvlist_replace_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value)
+int aim_tlvlist_replace_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value)
 {
 	aim_tlvlist_t *cur;
 
@@ -656,8 +610,7 @@
 	free(cur->tlv->value);
 	cur->tlv->length = length;
 	if (cur->tlv->length > 0) {
-		cur->tlv->value = (guint8 *)malloc(cur->tlv->length);
-		memcpy(cur->tlv->value, value, cur->tlv->length);
+		cur->tlv->value = g_memdup(value, length);
 	} else
 		cur->tlv->value = NULL;
 
@@ -674,7 +627,7 @@
  * @param str String to add.
  * @return The length of the TLV.
  */
-faim_internal int aim_tlvlist_replace_str(aim_tlvlist_t **list, const guint16 type, const char *str)
+int aim_tlvlist_replace_str(aim_tlvlist_t **list, const guint16 type, const char *str)
 {
 	return aim_tlvlist_replace_raw(list, type, strlen(str), (const guchar *)str);
 }
@@ -688,7 +641,7 @@
  * @param type TLV type.
  * @return The length of the TLV.
  */
-faim_internal int aim_tlvlist_replace_noval(aim_tlvlist_t **list, const guint16 type)
+int aim_tlvlist_replace_noval(aim_tlvlist_t **list, const guint16 type)
 {
 	return aim_tlvlist_replace_raw(list, type, 0, NULL);
 }
@@ -703,7 +656,7 @@
  * @param value 8 bit value to add.
  * @return The length of the TLV.
  */
-faim_internal int aim_tlvlist_replace_8(aim_tlvlist_t **list, const guint16 type, const guint8 value)
+int aim_tlvlist_replace_8(aim_tlvlist_t **list, const guint16 type, const guint8 value)
 {
 	guint8 v8[1];
 
@@ -713,8 +666,8 @@
 }
 
 /**
- * Substitute a TLV of a given type with a new TLV of the same type.  If 
- * you attempt to replace a TLV that does not exist, this function will 
+ * Substitute a TLV of a given type with a new TLV of the same type.  If
+ * you attempt to replace a TLV that does not exist, this function will
  * just add a new TLV as if you called aim_tlvlist_add_raw().
  *
  * @param list Desination chain (%NULL pointer if empty).
@@ -722,7 +675,7 @@
  * @param value 32 bit value to add.
  * @return The length of the TLV.
  */
-faim_internal int aim_tlvlist_replace_32(aim_tlvlist_t **list, const guint16 type, const guint32 value)
+int aim_tlvlist_replace_32(aim_tlvlist_t **list, const guint16 type, const guint32 value)
 {
 	guint8 v32[4];
 
@@ -732,13 +685,13 @@
 }
 
 /**
- * Remove a TLV of a given type.  If you attempt to remove a TLV that 
+ * Remove a TLV of a given type.  If you attempt to remove a TLV that
  * does not exist, nothing happens.
  *
  * @param list Desination chain (%NULL pointer if empty).
  * @param type TLV type.
  */
-faim_internal void aim_tlvlist_remove(aim_tlvlist_t **list, const guint16 type)
+void aim_tlvlist_remove(aim_tlvlist_t **list, const guint16 type)
 {
 	aim_tlvlist_t *del;
 
@@ -768,17 +721,17 @@
  * Write a TLV chain into a data buffer.
  *
  * Copies a TLV chain into a raw data buffer, writing only the number
- * of bytes specified. This operation does not free the chain; 
+ * of bytes specified. This operation does not free the chain;
  * aim_tlvlist_free() must still be called to free up the memory used
  * by the chain structures.
  *
- * XXX clean this up, make better use of bstreams 
+ * XXX clean this up, make better use of bstreams
  *
  * @param bs Input bstream
  * @param list Source TLV chain
  * @return Return 0 if the destination bstream is too small.
  */
-faim_internal int aim_tlvlist_write(ByteStream *bs, aim_tlvlist_t **list)
+int aim_tlvlist_write(ByteStream *bs, aim_tlvlist_t **list)
 {
 	int goodbuflen;
 	aim_tlvlist_t *cur;
@@ -786,15 +739,15 @@
 	/* do an initial run to test total length */
 	goodbuflen = aim_tlvlist_size(list);
 
-	if (goodbuflen > aim_bstream_empty(bs))
+	if (goodbuflen > byte_stream_empty(bs))
 		return 0; /* not enough buffer */
 
 	/* do the real write-out */
 	for (cur = *list; cur; cur = cur->next) {
-		aimbs_put16(bs, cur->tlv->type);
-		aimbs_put16(bs, cur->tlv->length);
+		byte_stream_put16(bs, cur->tlv->type);
+		byte_stream_put16(bs, cur->tlv->length);
 		if (cur->tlv->length)
-			aimbs_putraw(bs, cur->tlv->value, cur->tlv->length);
+			byte_stream_putraw(bs, cur->tlv->value, cur->tlv->length);
 	}
 
 	return 1; /* XXX this is a nonsensical return */
@@ -804,7 +757,7 @@
 /**
  * Grab the Nth TLV of type type in the TLV list list.
  *
- * Returns a pointer to an aim_tlv_t of the specified type; 
+ * Returns a pointer to an aim_tlv_t of the specified type;
  * %NULL on error.  The @nth parameter is specified starting at %1.
  * In most cases, there will be no more than one TLV of any type
  * in a chain.
@@ -814,7 +767,7 @@
  * @param nth Index of TLV of type to get.
  * @return The TLV you were looking for, or NULL if one could not be found.
  */
-faim_internal aim_tlv_t *aim_tlv_gettlv(aim_tlvlist_t *list, const guint16 type, const int nth)
+aim_tlv_t *aim_tlv_gettlv(aim_tlvlist_t *list, const guint16 type, const int nth)
 {
 	aim_tlvlist_t *cur;
 	int i;
@@ -840,7 +793,7 @@
  * @return The length of the data in this TLV, or -1 if the TLV could not be
  *         found.  Unless -1 is returned, this value will be 2 bytes.
  */
-faim_internal int aim_tlv_getlength(aim_tlvlist_t *list, const guint16 type, const int nth)
+int aim_tlv_getlength(aim_tlvlist_t *list, const guint16 type, const int nth)
 {
 	aim_tlvlist_t *cur;
 	int i;
@@ -867,32 +820,32 @@
  *         not be found.  This is a dynamic buffer and must be freed by the
  *         caller.
  */
-faim_internal char *aim_tlv_getstr(aim_tlvlist_t *list, const guint16 type, const int nth)
+char *aim_tlv_getstr(aim_tlvlist_t *list, const guint16 type, const int nth)
 {
 	aim_tlv_t *tlv;
-	char *newstr;
+	char *ret;
 
 	if (!(tlv = aim_tlv_gettlv(list, type, nth)))
 		return NULL;
 
-	newstr = (char *) malloc(tlv->length + 1);
-	memcpy(newstr, tlv->value, tlv->length);
-	newstr[tlv->length] = '\0';
+	ret = malloc(tlv->length + 1);
+	memcpy(ret, tlv->value, tlv->length);
+	ret[tlv->length] = '\0';
 
-	return newstr;
+	return ret;
 }
 
 /**
- * Retrieve the data from the nth TLV in the given TLV chain as an 8bit 
+ * Retrieve the data from the nth TLV in the given TLV chain as an 8bit
  * integer.
  *
  * @param list Source TLV chain.
  * @param type TLV type to search for.
  * @param nth Index of TLV to return.
- * @return The value the TLV you were looking for, or 0 if one could 
+ * @return The value the TLV you were looking for, or 0 if one could
  *         not be found.
  */
-faim_internal guint8 aim_tlv_get8(aim_tlvlist_t *list, const guint16 type, const int nth)
+guint8 aim_tlv_get8(aim_tlvlist_t *list, const guint16 type, const int nth)
 {
 	aim_tlv_t *tlv;
 
@@ -902,16 +855,16 @@
 }
 
 /**
- * Retrieve the data from the nth TLV in the given TLV chain as a 16bit 
+ * Retrieve the data from the nth TLV in the given TLV chain as a 16bit
  * integer.
  *
  * @param list Source TLV chain.
  * @param type TLV type to search for.
  * @param nth Index of TLV to return.
- * @return The value the TLV you were looking for, or 0 if one could 
+ * @return The value the TLV you were looking for, or 0 if one could
  *         not be found.
  */
-faim_internal guint16 aim_tlv_get16(aim_tlvlist_t *list, const guint16 type, const int nth)
+guint16 aim_tlv_get16(aim_tlvlist_t *list, const guint16 type, const int nth)
 {
 	aim_tlv_t *tlv;
 
@@ -921,16 +874,16 @@
 }
 
 /**
- * Retrieve the data from the nth TLV in the given TLV chain as a 32bit 
+ * Retrieve the data from the nth TLV in the given TLV chain as a 32bit
  * integer.
  *
  * @param list Source TLV chain.
  * @param type TLV type to search for.
  * @param nth Index of TLV to return.
- * @return The value the TLV you were looking for, or 0 if one could 
+ * @return The value the TLV you were looking for, or 0 if one could
  *         not be found.
  */
-faim_internal guint32 aim_tlv_get32(aim_tlvlist_t *list, const guint16 type, const int nth)
+guint32 aim_tlv_get32(aim_tlvlist_t *list, const guint16 type, const int nth)
 {
 	aim_tlv_t *tlv;
 
--- a/src/protocols/oscar/txqueue.c	Fri Apr 07 01:05:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,423 +0,0 @@
-/*
- * Gaim'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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/*
- * txqueue.c
- *
- * Herein lies all the management routines for the transmit (Tx) queue.
- *
- */
-
-#include "oscar.h"
-#include "peer.h"
-
-#ifndef _WIN32
-#include <sys/socket.h>
-#else
-#include "win32dep.h"
-#endif
-
-/*
- * Allocate a new tx frame.
- *
- * This is more for looks than anything else.
- *
- * Right now, that is.  If/when we implement a pool of transmit
- * frames, this will become the request-an-unused-frame part.
- *
- * framing = AIM_FRAMETYPE_OFT/FLAP
- * chan = channel for FLAP, hdrtype for OFT
- *
- */
-FlapFrame *
-flap_frame_new(OscarSession *sess, OscarConnection *conn, guint8 framing, guint16 chan, int datalen)
-{
-	FlapFrame *fr;
-
-	if (!sess || !conn) {
-		gaim_debug_misc("oscar", "flap_frame_new: No session or no connection specified!\n");
-		return NULL;
-	}
-
-	/* For sanity... */
-	if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) || (conn->type == AIM_CONN_TYPE_LISTENER)) {
-		if (framing != AIM_FRAMETYPE_OFT) {
-			gaim_debug_misc("oscar", "flap_frame_new: attempted to allocate inappropriate frame type for rendezvous connection\n");
-			return NULL;
-		}
-	} else {
-		if (framing != AIM_FRAMETYPE_FLAP) {
-			gaim_debug_misc("oscar", "flap_frame_new: attempted to allocate inappropriate frame type for FLAP connection\n");
-			return NULL;
-		}
-	}
-
-	fr = g_new0(FlapFrame, 1);
-	fr->conn = conn;
-	fr->hdrtype = framing;
-	if (fr->hdrtype == AIM_FRAMETYPE_FLAP)
-		fr->hdr.flap.channel = chan;
-	else if (fr->hdrtype == AIM_FRAMETYPE_OFT)
-		fr->hdr.rend.type = chan;
-	else
-		gaim_debug_misc("oscar", "tx_new: unknown framing\n");
-
-	if (datalen > 0) {
-		guint8 *data;
-		data = malloc(datalen);
-		aim_bstream_init(&fr->data, data, datalen);
-	}
-
-	return fr;
-}
-
-static int
-aim_send(int fd, const void *buf, size_t count)
-{
-	int left, cur;
-
-	for (cur = 0, left = count; left; ) {
-		int ret;
-
-		ret = send(fd, ((unsigned char *)buf)+cur, left, 0);
-
-		if (ret == -1)
-			return -1;
-		else if (ret == 0)
-			return cur;
-
-		cur += ret;
-		left -= ret;
-	}
-
-	return cur;
-}
-
-int
-aim_bstream_send(ByteStream *bs, OscarConnection *conn, size_t count)
-{
-	int wrote = 0;
-
-	if (!bs || !conn)
-		return -EINVAL;
-
-	/* Make sure we don't send past the end of the bs */
-	if (count > aim_bstream_empty(bs))
-		count = aim_bstream_empty(bs); /* truncate to remaining space */
-
-	if (count) {
-		/*
-		 * I need to rewrite this. "Updating the UI" doesn't make sense. The program is
-		 * blocked and the UI can't redraw. We're blocking all of Gaim. We need to set
-		 * up an actual txqueue and a GAIM_INPUT_WRITE callback and only write when we
-		 * can. Why is this file called txqueue anyway? Lets rename it to txblock.
-		 */
-		if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) &&
-		    (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)) {
-			const char *sn = aim_odc_getsn(conn);
-			aim_rxcallback_t userfunc;
-
-			while (count - wrote > 1024) {
-				int ret;
-
-				ret = aim_send(conn->fd, bs->data + bs->offset + wrote, 1024);
-				if (ret > 0)
-					wrote += ret;
-				if (ret < 0)
-					return -1;
-				if ((userfunc=aim_callhandler(conn->sessv, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER)))
-					userfunc(conn->sessv, NULL, sn, count-wrote>1024 ? ((double)wrote / count) : 1);
-			}
-		}
-
-		if (count - wrote) {
-			wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, count - wrote);
-		}
-	}
-
-	bs->offset += wrote;
-
-	return wrote;
-}
-
-static int
-sendframe_flap(OscarSession *sess, FlapFrame *fr)
-{
-	ByteStream bs;
-	guint8 *bs_raw;
-	int payloadlen, err = 0, bslen;
-
-	payloadlen = aim_bstream_curpos(&fr->data);
-
-	bs_raw = malloc(6 + payloadlen);
-
-	aim_bstream_init(&bs, bs_raw, 6 + payloadlen);
-
-	/* FLAP header */
-	aimbs_put8(&bs, 0x2a);
-	aimbs_put8(&bs, fr->hdr.flap.channel);
-	aimbs_put16(&bs, fr->hdr.flap.seqnum);
-	aimbs_put16(&bs, payloadlen);
-
-	/* payload */
-	aim_bstream_rewind(&fr->data);
-	aimbs_putbs(&bs, &fr->data, payloadlen);
-
-	bslen = aim_bstream_curpos(&bs);
-	aim_bstream_rewind(&bs);
-	if (aim_bstream_send(&bs, fr->conn, bslen) != bslen)
-		err = -errno;
-
-	free(bs_raw); /* XXX aim_bstream_free */
-
-	fr->handled = 1;
-	fr->conn->lastactivity = time(NULL);
-
-	return err;
-}
-
-static int
-sendframe_rendezvous(OscarSession *sess, FlapFrame *fr)
-{
-	ByteStream bs;
-	guint8 *bs_raw;
-	int payloadlen, err = 0, bslen;
-
-	payloadlen = aim_bstream_curpos(&fr->data);
-
-	bs_raw = malloc(8 + payloadlen);
-
-	aim_bstream_init(&bs, bs_raw, 8 + payloadlen);
-
-	/* Rendezvous header */
-	aimbs_putraw(&bs, fr->hdr.rend.magic, 4);
-	aimbs_put16(&bs, fr->hdr.rend.hdrlen);
-	aimbs_put16(&bs, fr->hdr.rend.type);
-
-	/* payload */
-	aim_bstream_rewind(&fr->data);
-	aimbs_putbs(&bs, &fr->data, payloadlen);
-
-	bslen = aim_bstream_curpos(&bs);
-	aim_bstream_rewind(&bs);
-	if (aim_bstream_send(&bs, fr->conn, bslen) != bslen)
-		err = -errno;
-
-	free(bs_raw); /* XXX aim_bstream_free */
-
-	fr->handled = 1;
-	fr->conn->lastactivity = time(NULL);
-
-	return err;
-}
-
-static int
-aim_tx_sendframe(OscarSession *sess, FlapFrame *fr)
-{
-	if (fr->hdrtype == AIM_FRAMETYPE_FLAP)
-		return sendframe_flap(sess, fr);
-	else if (fr->hdrtype == AIM_FRAMETYPE_OFT)
-		return sendframe_rendezvous(sess, fr);
-
-	return -1;
-}
-
-/*
- * This is responsible for removing sent commands from the transmit
- * queue. This is not a required operation, but it of course helps
- * reduce memory footprint at run time!
- */
-static void
-aim_tx_purgequeue(OscarSession *sess)
-{
-	FlapFrame *cur, **prev;
-
-	for (prev = &sess->queue_outgoing; (cur = *prev); ) {
-		if (cur->handled) {
-			*prev = cur->next;
-			aim_frame_destroy(cur);
-		} else
-			prev = &cur->next;
-	}
-
-	return;
-}
-
-int
-aim_tx_flushqueue(OscarSession *sess)
-{
-	FlapFrame *cur;
-
-	for (cur = sess->queue_outgoing; cur; cur = cur->next) {
-
-		if (cur->handled)
-			continue; /* already been sent */
-
-		if (cur->conn && (cur->conn->status & AIM_CONN_STATUS_INPROGRESS))
-			continue;
-
-		/* XXX this should call the custom "queuing" function!! */
-		aim_tx_sendframe(sess, cur);
-	}
-
-	/* purge sent commands from queue */
-	aim_tx_purgequeue(sess);
-
-	return 0;
-}
-
-/**
- * Get rid of packets waiting for tx on a dying conn.  For now this
- * simply marks all packets as sent and lets them disappear without
- * warning.
- *
- * @param sess A session.
- * @param conn Connection that's dying.
- */
-void
-aim_tx_cleanqueue(OscarSession *sess, OscarConnection *conn)
-{
-	FlapFrame *cur;
-
-	for (cur = sess->queue_outgoing; cur; cur = cur->next) {
-		if (cur->conn == conn)
-			cur->handled = 1;
-	}
-
-	return;
-}
-
-/*
- * This increments the tx command count, and returns the seqnum
- * that should be stamped on the next FLAP packet sent.  This is
- * normally called during the final step of packet preparation
- * before enqueuement (in aim_tx_enqueue()).
- */
-static flap_seqnum_t
-aim_get_next_txseqnum(OscarConnection *conn)
-{
-	flap_seqnum_t ret;
-
-	ret = ++conn->seqnum;
-
-	return ret;
-}
-
-/*
- * The overall purpose here is to enqueue the passed in command struct
- * into the outgoing (tx) queue.  Basically...
- *   1) Make a scope-irrelevant copy of the struct
- *   3) Mark as not-sent-yet
- *   4) Enqueue the struct into the list
- *   6) Return
- *
- * Note that this is only used when doing queue-based transmitting;
- * that is, when sess->tx_enqueue is set to &aim_tx_enqueue__queuebased.
- *
- */
-static int
-aim_tx_enqueue__queuebased(OscarSession *sess, FlapFrame *fr)
-{
-
-	if (!fr->conn) {
-		gaim_debug_warning("oscar", "aim_tx_enqueue: enqueueing packet with no connecetion\n");
-		fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
-	}
-
-	if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
-		/* assign seqnum -- XXX should really not assign until hardxmit */
-		fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
-	}
-
-	fr->handled = 0; /* not sent yet */
-
-	/* see overhead note in aim_rxqueue counterpart */
-	if (!sess->queue_outgoing)
-		sess->queue_outgoing = fr;
-	else {
-		FlapFrame *cur;
-		for (cur = sess->queue_outgoing; cur->next; cur = cur->next);
-		cur->next = fr;
-	}
-
-	return 0;
-}
-
-/*
- * Parallel to aim_tx_enqueue__queuebased, however, this bypasses
- * the whole queue mess when you want immediate writes to happen.
- *
- * Basically the same as its __queuebased couterpart, however
- * instead of doing a list append, it just calls aim_tx_sendframe()
- * right here.
- *
- */
-static int
-aim_tx_enqueue__immediate(OscarSession *sess, FlapFrame *fr)
-{
-	int ret;
-
-	if (!fr->conn) {
-		gaim_debug_error("oscar", "aim_tx_enqueue: packet has no connection\n");
-		aim_frame_destroy(fr);
-		return 0;
-	}
-
-	if (fr->hdrtype == AIM_FRAMETYPE_FLAP)
-		fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
-
-	fr->handled = 0; /* not sent yet */
-
-	ret = aim_tx_sendframe(sess, fr);
-
-	aim_frame_destroy(fr);
-
-	return ret;
-}
-
-int
-aim_tx_setenqueue(OscarSession *sess, int what, int (*func)(OscarSession *, FlapFrame *))
-{
-
-	if (what == AIM_TX_QUEUED)
-		sess->tx_enqueue = &aim_tx_enqueue__queuebased;
-	else if (what == AIM_TX_IMMEDIATE)
-		sess->tx_enqueue = &aim_tx_enqueue__immediate;
-	else
-		return -EINVAL; /* unknown action */
-
-	return 0;
-}
-
-int
-aim_tx_enqueue(OscarSession *sess, FlapFrame *fr)
-{
-	/*
-	 * If we want to send on a connection that is in progress, we have to force
-	 * them to use the queue based version. Otherwise, use whatever they
-	 * want.
-	 */
-	if (fr && fr->conn &&
-			(fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) {
-		return aim_tx_enqueue__queuebased(sess, fr);
-	}
-
-	return (*sess->tx_enqueue)(sess, fr);
-}
--- a/src/protocols/oscar/util.c	Fri Apr 07 01:05:48 2006 +0000
+++ b/src/protocols/oscar/util.c	Fri Apr 07 05:10:56 2006 +0000
@@ -37,7 +37,7 @@
  *   -- DMP.
  *
  */
-faim_export int aimutil_tokslen(char *toSearch, int theindex, char dl)
+int aimutil_tokslen(char *toSearch, int theindex, char dl)
 {
 	int curCount = 1;
 	char *next;
@@ -61,7 +61,7 @@
 	return toReturn;
 }
 
-faim_export int aimutil_itemcnt(char *toSearch, char dl)
+int aimutil_itemcnt(char *toSearch, char dl)
 {
 	int curCount;
 	char *next;
@@ -78,7 +78,7 @@
 	return curCount;
 }
 
-faim_export char *aimutil_itemindex(char *toSearch, int theindex, char dl)
+char *aimutil_itemindex(char *toSearch, int theindex, char dl)
 {
 	int curCount;
 	char *next;
@@ -122,7 +122,7 @@
  * Calculate the checksum of a given icon.
  *
  */
-faim_export guint16 aimutil_iconsum(const guint8 *buf, int buflen)
+guint16 aimutil_iconsum(const guint8 *buf, int buflen)
 {
 	guint32 sum;
 	int i;
@@ -201,7 +201,7 @@
  *
  * @return 1 if the screen name is valid, 0 if not.
  */
-faim_export int aim_snvalid(const char *sn)
+int aim_snvalid(const char *sn)
 {
 	if ((sn == NULL) || (*sn == '\0'))
 		return 0;
@@ -224,7 +224,7 @@
  * @return 1 if the screen name is an ICQ screen name.  Otherwise 0
  *         is returned.
  */
-faim_export int aim_sn_is_icq(const char *sn)
+int aim_sn_is_icq(const char *sn)
 {
 	if (isalpha(sn[0]))
 		return 0;
@@ -239,7 +239,7 @@
  * @return 1 if the screen name is an SMS number.  Otherwise 0
  *         is returned.
  */
-faim_export int aim_sn_is_sms(const char *sn)
+int aim_sn_is_sms(const char *sn)
 {
 	if (sn[0] != '+')
 		return 0;
@@ -254,7 +254,7 @@
 * return is equal to that of strlen().
 *
 */
-faim_export int aim_snlen(const char *sn)
+int aim_snlen(const char *sn)
 {
 	int i = 0;
 
@@ -283,7 +283,7 @@
 *     non-0 if different
 *
 */
-faim_export int aim_sncmp(const char *sn1, const char *sn2)
+int aim_sncmp(const char *sn1, const char *sn2)
 {
 
 	if ((sn1 == NULL) || (sn2 == NULL))