diff src/protocols/oscar/oscar.c @ 2246:933346315b9b

[gaim-migrate @ 2256] heh. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sun, 09 Sep 2001 10:07:14 +0000
parents 5d8b6100a9cc
children cef6d4e81aec
line wrap: on
line diff
--- a/src/protocols/oscar/oscar.c	Sun Sep 09 06:33:54 2001 +0000
+++ b/src/protocols/oscar/oscar.c	Sun Sep 09 10:07:14 2001 +0000
@@ -60,8 +60,8 @@
 		       AIM_CAPS_IMIMAGE;
 
 struct oscar_data {
-	struct aim_session_t *sess;
-	struct aim_conn_t *conn;
+	aim_session_t *sess;
+	aim_conn_t *conn;
 
 	guint cnpa;
 	guint paspa;
@@ -85,9 +85,9 @@
 struct chat_connection {
 	char *name;
 	char *show; /* AOL did something funny to us */
-	int exchange;
+	fu16_t exchange; /* XXX should have instance here too */
 	int fd; /* this is redundant since we have the conn below */
-	struct aim_conn_t *conn;
+	aim_conn_t *conn;
 	int inpa;
 	int id;
 	struct gaim_connection *gc; /* i hate this. */
@@ -100,13 +100,14 @@
 	struct gaim_connection *gc;
 	char name[80];
 	int watcher;
-	struct aim_conn_t *conn;
+	aim_conn_t *conn;
 };
 
 struct ask_direct {
 	struct gaim_connection *gc;
 	char *sn;
-	struct aim_directim_priv *priv;
+	char ip[64];
+	fu8_t cookie[8];
 };
 
 struct icon_req {
@@ -117,7 +118,7 @@
 	gboolean request;
 };
 
-static struct direct_im *find_direct_im(struct oscar_data *od, char *who) {
+static struct direct_im *find_direct_im(struct oscar_data *od, const char *who) {
 	GSList *d = od->direct_ims;
 	char *n = g_strdup(normalize(who));
 	struct direct_im *m = NULL;
@@ -176,7 +177,7 @@
 }
 
 static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc,
-							struct aim_conn_t *conn) {
+							aim_conn_t *conn) {
 	GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
 	struct chat_connection *c = NULL;
 
@@ -191,42 +192,41 @@
 	return c;
 }
 
-static int gaim_parse_auth_resp  (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_login      (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_server_ready     (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_handle_redirect  (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_info_change      (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_account_confirm  (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_oncoming   (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_offgoing   (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_misses     (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_user_info  (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_motd       (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_chatnav_info     (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_chat_join        (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_chat_leave       (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_chat_info_update (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_chat_incoming_msg(struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_msgack     (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_ratechange (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_evilnotify (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_searcherror(struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_searchreply(struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_bosrights        (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_rateresp         (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_reportinterval   (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_msgerr     (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_buddyrights(struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_locerr     (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_icbm_param_info  (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_parse_genericerr (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_memrequest       (struct aim_session_t *, struct command_rx_struct *, ...);
-
-static int gaim_directim_initiate  (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_directim_incoming  (struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_directim_disconnect(struct aim_session_t *, struct command_rx_struct *, ...);
-static int gaim_directim_typing    (struct aim_session_t *, struct command_rx_struct *, ...);
+static int gaim_parse_auth_resp  (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_login      (aim_session_t *, aim_frame_t *, ...);
+static int gaim_handle_redirect  (aim_session_t *, aim_frame_t *, ...);
+static int gaim_info_change      (aim_session_t *, aim_frame_t *, ...);
+static int gaim_account_confirm  (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_oncoming   (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_offgoing   (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_incoming_im(aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_misses     (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_user_info  (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_motd       (aim_session_t *, aim_frame_t *, ...);
+static int gaim_chatnav_info     (aim_session_t *, aim_frame_t *, ...);
+static int gaim_chat_join        (aim_session_t *, aim_frame_t *, ...);
+static int gaim_chat_leave       (aim_session_t *, aim_frame_t *, ...);
+static int gaim_chat_info_update (aim_session_t *, aim_frame_t *, ...);
+static int gaim_chat_incoming_msg(aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_msgack     (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_ratechange (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_evilnotify (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_searcherror(aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_searchreply(aim_session_t *, aim_frame_t *, ...);
+static int gaim_bosrights        (aim_session_t *, aim_frame_t *, ...);
+static int rateresp_bos     (aim_session_t *, aim_frame_t *, ...);
+static int rateresp_auth    (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_msgerr     (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_buddyrights(aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_locerr     (aim_session_t *, aim_frame_t *, ...);
+static int gaim_icbm_param_info  (aim_session_t *, aim_frame_t *, ...);
+static int gaim_parse_genericerr (aim_session_t *, aim_frame_t *, ...);
+static int gaim_memrequest       (aim_session_t *,  aim_frame_t*, ...);
+static int server_ready_bos      (aim_session_t *,  aim_frame_t*, ...);
+
+static int gaim_directim_initiate  (aim_session_t *, aim_frame_t *, ...);
+static int gaim_directim_incoming  (aim_session_t *, aim_frame_t *, ...);
+static int gaim_directim_typing    (aim_session_t *, aim_frame_t *, ...);
 
 static char *msgerrreason[] = {
 	"Invalid error",
@@ -257,10 +257,36 @@
 };
 static int msgerrreasonlen = 25;
 
+static void gaim_directim_disconnect(aim_session_t *sess, aim_conn_t *conn) {
+	struct gaim_connection *gc = sess->aux_data;
+	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
+	struct conversation *cnv;
+	struct direct_im *dim;
+	char *sn;
+	char buf[256];
+
+	sn = g_strdup(aim_directim_getsn(conn));
+
+	debug_printf("%s disconnected Direct IM.\n", sn);
+
+	dim = find_direct_im(od, sn);
+	od->direct_ims = g_slist_remove(od->direct_ims, dim);
+	gaim_input_remove(dim->watcher);
+
+	g_snprintf(buf, sizeof buf, _("Direct IM with %s closed"), sn);
+	if ((cnv = find_conversation(sn)))
+		write_to_conv(cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL));
+
+	g_free(dim); /* I guess? I don't see it anywhere else... -- mid */
+	g_free(sn);
+
+	return;
+}
+
 static void oscar_callback(gpointer data, gint source,
 				GaimInputCondition condition) {
-	struct aim_conn_t *conn = (struct aim_conn_t *)data;
-	struct aim_session_t *sess = aim_conn_getsess(conn);
+	aim_conn_t *conn = (aim_conn_t *)data;
+	aim_session_t *sess = aim_conn_getsess(conn);
 	struct gaim_connection *gc = sess ? sess->aux_data : NULL;
 	struct oscar_data *odata;
 
@@ -284,6 +310,7 @@
 			debug_printf("got information on rendezvous\n");
 			if (aim_handlerendconnect(odata->sess, conn) < 0) {
 				debug_printf(_("connection error (rend)\n"));
+				aim_conn_kill(odata->sess, &conn);
 			}
 		} else {
 			if (aim_get_command(odata->sess, conn) >= 0) {
@@ -328,8 +355,12 @@
 					debug_printf("removing authconn input watcher\n");
 					aim_conn_kill(odata->sess, &conn);
 				} else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
-					debug_printf("No handler for rendezvous disconnect (%d).\n",
-							source);
+					if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)
+						gaim_directim_disconnect(odata->sess, conn);
+					else {
+						debug_printf("No handler for rendezvous disconnect (%d).\n",
+								source);
+					}
 					aim_conn_kill(odata->sess, &conn);
 				} else {
 					debug_printf("holy crap! generic connection error! %d\n",
@@ -341,7 +372,7 @@
 	}
 }
 
-static void oscar_debug(struct aim_session_t *sess, int level, const char *format, va_list va) {
+static void oscar_debug(aim_session_t *sess, int level, const char *format, va_list va) {
 	char *s = g_strdup_vprintf(format, va);
 	char buf[256];
 	char *t;
@@ -360,8 +391,8 @@
 {
 	struct gaim_connection *gc = data;
 	struct oscar_data *odata;
-	struct aim_session_t *sess;
-	struct aim_conn_t *conn;
+	aim_session_t *sess;
+	aim_conn_t *conn;
 
 	if (!g_slist_find(connections, gc)) {
 		close(source);
@@ -385,8 +416,8 @@
 }
 
 static void oscar_login(struct aim_user *user) {
-	struct aim_session_t *sess;
-	struct aim_conn_t *conn;
+	aim_session_t *sess;
+	aim_conn_t *conn;
 	char buf[256];
 	struct gaim_connection *gc = new_gaim_conn(user);
 	struct oscar_data *odata = gc->proto_data = g_new0(struct oscar_data, 1);
@@ -394,7 +425,7 @@
 
 	debug_printf(_("Logging in %s\n"), user->username);
 
-	sess = g_new0(struct aim_session_t, 1);
+	sess = g_new0(aim_session_t, 1);
 
 	aim_session_init(sess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 0);
 	aim_setdebuggingcb(sess, oscar_debug);
@@ -476,8 +507,8 @@
 static void oscar_bos_connect(gpointer data, gint source, GaimInputCondition cond) {
 	struct gaim_connection *gc = data;
 	struct oscar_data *odata;
-	struct aim_session_t *sess;
-	struct aim_conn_t *bosconn;
+	aim_session_t *sess;
+	aim_conn_t *bosconn;
 
 	if (!g_slist_find(connections, gc)) {
 		close(source);
@@ -500,12 +531,11 @@
 	set_login_progress(gc, 4, _("Connection established, cookie sent"));
 }
 
-int gaim_parse_auth_resp(struct aim_session_t *sess,
-			 struct command_rx_struct *command, ...) {
+static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	struct aim_conn_t *bosconn = NULL;
+	aim_conn_t *bosconn = NULL;
 	char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL;
-	unsigned char *cookie = NULL;
+	fu8_t *cookie = NULL;
 	int errorcode = 0, regstatus = 0;
 	int latestbuild = 0, latestbetabuild = 0;
 	char *latestrelease = NULL, *latestbeta = NULL;
@@ -520,7 +550,7 @@
 	port = user->proto_opt[USEROPT_AUTHPORT][0] ?
 		atoi(user->proto_opt[USEROPT_AUTHPORT]) : FAIM_LOGIN_PORT,
 
-	va_start(ap, command);
+	va_start(ap, fr);
 	sn = va_arg(ap, char *);
 	errorcode = va_arg(ap, int);
 	errurl = va_arg(ap, char *);
@@ -589,7 +619,7 @@
 		debug_printf("Latest WinAIM released version %s, build %d, at %s (%s)\n",
 				latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo);
 	debug_printf("Closing auth connection...\n");
-	aim_conn_kill(sess, &command->conn);
+	aim_conn_kill(sess, &fr->conn);
 
 	bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, NULL);
 	if (bosconn == NULL) {
@@ -599,12 +629,11 @@
 	}
 
 	aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, gaim_bosrights, 0);
-	aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, gaim_rateresp, 0); /* rate info */
+	aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, rateresp_bos, 0); /* rate info */
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0);
-	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, gaim_server_ready, 0);
+	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, server_ready_bos, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, gaim_handle_redirect, 0);
-	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, gaim_reportinterval, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, gaim_parse_buddyrights, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, gaim_parse_oncoming, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, gaim_parse_offgoing, 0);
@@ -652,7 +681,7 @@
 	unsigned long len;
 	char *modname;
 	int fd;
-	struct aim_conn_t *conn;
+	aim_conn_t *conn;
 	unsigned int inpa;
 };
 
@@ -719,24 +748,23 @@
 /* size of icbmui.ocm, the largest module in AIM 3.5 */
 #define AIM_MAX_FILE_SIZE 98304
 
-int gaim_memrequest(struct aim_session_t *sess,
-		    struct command_rx_struct *command, ...) {
+int gaim_memrequest(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
 	struct pieceofcrap *pos;
-	unsigned long offset, len;
+	fu32_t offset, len;
 	char *modname;
 	int fd;
 
-	va_start(ap, command);
-	offset = va_arg(ap, unsigned long);
-	len = va_arg(ap, unsigned long);
+	va_start(ap, fr);
+	offset = (fu32_t)va_arg(ap, unsigned long);
+	len = (fu32_t)va_arg(ap, unsigned long);
 	modname = va_arg(ap, char *);
 	va_end(ap);
 
 	debug_printf("offset: %d, len: %d, file: %s\n", offset, len, modname ? modname : "aim.exe");
 	if (len == 0) {
 		debug_printf("len is 0, hashing NULL\n");
-		aim_sendmemblock(sess, command->conn, offset, len, NULL,
+		aim_sendmemblock(sess, fr->conn, offset, len, NULL,
 				AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
 		return 1;
 	}
@@ -769,7 +797,7 @@
 
 	pos = g_new0(struct pieceofcrap, 1);
 	pos->gc = sess->aux_data;
-	pos->conn = command->conn;
+	pos->conn = fr->conn;
 
 	pos->offset = offset;
 	pos->len = len;
@@ -788,8 +816,7 @@
 	return 1;
 }
 
-int gaim_parse_login(struct aim_session_t *sess,
-		     struct command_rx_struct *command, ...) {
+static int gaim_parse_login(aim_session_t *sess, aim_frame_t *fr, ...) {
 #if 0
 	struct client_info_s info = {"gaim", 4, 1, 2010, "us", "en", 0x0004, 0x0000, 0x04b};
 #else
@@ -799,84 +826,87 @@
 	va_list ap;
 	struct gaim_connection *gc = sess->aux_data;
 
-	va_start(ap, command);
+	va_start(ap, fr);
 	key = va_arg(ap, char *);
 	va_end(ap);
 
-	aim_send_login(sess, command->conn, gc->username, gc->password, &info, key);
+	aim_send_login(sess, fr->conn, gc->username, gc->password, &info, key);
+
 	return 1;
 }
 
-int gaim_server_ready(struct aim_session_t *sess,
-		      struct command_rx_struct *command, ...) {
-	static int id = 1;
+static int server_ready_auth(aim_session_t *sess, aim_frame_t *fr, ...) {
 	struct gaim_connection *gc = sess->aux_data;
 	struct oscar_data *od = gc->proto_data;
-	struct chat_connection *chatcon;
-	switch (command->conn->type) {
-	case AIM_CONN_TYPE_AUTH:
-		aim_auth_setversions(sess, command->conn);
-		aim_bos_reqrate(sess, command->conn);
-		debug_printf("done with AUTH ServerReady\n");
-		if (od->chpass) {
-			debug_printf("changing password\n");
-			aim_auth_changepasswd(sess, command->conn, od->newp, od->oldp);
-			g_free(od->oldp);
-			g_free(od->newp);
-			od->chpass = FALSE;
-		}
-		if (od->conf) {
-			debug_printf("confirming account\n");
-			aim_auth_reqconfirm(sess, command->conn);
-			od->conf = FALSE;
-		}
-		if (od->reqemail) {
-			debug_printf("requesting email\n");
-			aim_auth_getinfo(sess, command->conn, 0x0011);
-			od->reqemail = FALSE;
-		}
-		break;
-	case AIM_CONN_TYPE_BOS:
-		aim_setversions(sess, command->conn);
-		aim_bos_reqrate(sess, command->conn); /* request rate info */
-		debug_printf("done with BOS ServerReady\n");
-		break;
-	case AIM_CONN_TYPE_CHATNAV:
-		debug_printf("chatnav: got server ready\n");
-		aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, gaim_chatnav_info, 0);
-		aim_bos_reqrate(sess, command->conn);
-		aim_bos_ackrateresp(sess, command->conn);
-		aim_chatnav_clientready(sess, command->conn);
-		aim_chatnav_reqrights(sess, command->conn);
-		break;
-	case AIM_CONN_TYPE_CHAT:
-		debug_printf("chat: got server ready\n");
-		aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, gaim_chat_join, 0);
-		aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, gaim_chat_leave, 0);
-		aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, gaim_chat_info_update, 0);
-		aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, gaim_chat_incoming_msg, 0);
-		aim_bos_reqrate(sess, command->conn);
-		aim_bos_ackrateresp(sess, command->conn);
-		aim_chat_clientready(sess, command->conn);
-		chatcon = find_oscar_chat_by_conn(gc, command->conn);
-		chatcon->id = id;
-		chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show);
-		break;
-	case AIM_CONN_TYPE_RENDEZVOUS:
-		break;
-	default: /* huh? */
-		debug_printf("server ready: got unexpected connection type %04x\n", command->conn->type);
-		break;
+
+	aim_auth_setversions(sess, fr->conn);
+	aim_bos_reqrate(sess, fr->conn);
+	debug_printf("done with AUTH ServerReady\n");
+	if (od->chpass) {
+		debug_printf("changing password\n");
+		aim_auth_changepasswd(sess, fr->conn, od->newp, od->oldp);
+		g_free(od->oldp);
+		g_free(od->newp);
+		od->chpass = FALSE;
 	}
+	if (od->conf) {
+		debug_printf("confirming account\n");
+		aim_auth_reqconfirm(sess, fr->conn);
+		od->conf = FALSE;
+	}
+	if (od->reqemail) {
+		debug_printf("requesting email\n");
+		aim_auth_getinfo(sess, fr->conn, 0x0011);
+		od->reqemail = FALSE;
+	}
+
+	return 1;
+}
+
+static int server_ready_bos(aim_session_t *sess, aim_frame_t *fr, ...) {
+	aim_setversions(sess, fr->conn);
+	aim_bos_reqrate(sess, fr->conn); /* request rate info */
+	debug_printf("done with BOS ServerReady\n");
+
 	return 1;
 }
 
-static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition cond)
-{
+static int server_ready_chatnav(aim_session_t *sess, aim_frame_t *fr, ...) {
+	debug_printf("chatnav: got server ready\n");
+	aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, gaim_chatnav_info, 0);
+	aim_bos_reqrate(sess, fr->conn);
+	aim_bos_ackrateresp(sess, fr->conn);
+	aim_chatnav_clientready(sess, fr->conn);
+	aim_chatnav_reqrights(sess, fr->conn);
+
+	return 1;
+}
+
+static int server_ready_chat(aim_session_t *sess, aim_frame_t *fr, ...) {
+	struct gaim_connection *gc = sess->aux_data;
+	struct chat_connection *chatcon;
+	static int id = 1;
+
+	debug_printf("chat: got server ready\n");
+	aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, gaim_chat_join, 0);
+	aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, gaim_chat_leave, 0);
+	aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, gaim_chat_info_update, 0);
+	aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, gaim_chat_incoming_msg, 0);
+	aim_bos_reqrate(sess, fr->conn);
+	aim_bos_ackrateresp(sess, fr->conn);
+	aim_chat_clientready(sess, fr->conn);
+	chatcon = find_oscar_chat_by_conn(gc, fr->conn);
+	chatcon->id = id;
+	chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show);
+
+	return 1;
+}
+
+static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition cond) {
 	struct gaim_connection *gc = data;
 	struct oscar_data *odata;
-	struct aim_session_t *sess;
-	struct aim_conn_t *tstconn;
+	aim_session_t *sess;
+	aim_conn_t *tstconn;
 
 	if (!g_slist_find(connections, gc)) {
 		close(source);
@@ -895,7 +925,7 @@
 
 	aim_conn_completeconnect(sess, tstconn);
 	odata->cnpa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ,
-				oscar_callback, tstconn);
+					oscar_callback, tstconn);
 	debug_printf("chatnav: connected\n");
 }
 
@@ -903,8 +933,8 @@
 {
 	struct gaim_connection *gc = data;
 	struct oscar_data *odata;
-	struct aim_session_t *sess;
-	struct aim_conn_t *tstconn;
+	aim_session_t *sess;
+	aim_conn_t *tstconn;
 
 	if (!g_slist_find(connections, gc)) {
 		close(source);
@@ -932,8 +962,8 @@
 	struct chat_connection *ccon = data;
 	struct gaim_connection *gc = ccon->gc;
 	struct oscar_data *odata;
-	struct aim_session_t *sess;
-	struct aim_conn_t *tstconn;
+	aim_session_t *sess;
+	aim_conn_t *tstconn;
 
 	if (!g_slist_find(connections, gc)) {
 		close(source);
@@ -963,15 +993,15 @@
 	aim_chat_attachname(tstconn, ccon->name);
 }
 
-int gaim_handle_redirect(struct aim_session_t *sess,
-			 struct command_rx_struct *command, ...) {
+/* Hrmph. I don't know how to make this look better. --mid */
+static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	int serviceid;
+	fu16_t serviceid;
 	char *ip;
-	unsigned char *cookie;
+	fu8_t *cookie;
 	struct gaim_connection *gc = sess->aux_data;
 	struct aim_user *user = gc->user;
-	struct aim_conn_t *tstconn;
+	aim_conn_t *tstconn;
 	int i;
 	char *host;
 	int port;
@@ -979,10 +1009,10 @@
 	port = user->proto_opt[USEROPT_AUTHPORT][0] ?
 		atoi(user->proto_opt[USEROPT_AUTHPORT]) : FAIM_LOGIN_PORT,
 
-	va_start(ap, command);
-	serviceid = va_arg(ap, int);
-	ip        = va_arg(ap, char *);
-	cookie    = va_arg(ap, unsigned char *);
+	va_start(ap, fr);
+	serviceid = (fu16_t)va_arg(ap, unsigned int);
+	ip = va_arg(ap, char *);
+	cookie = (fu8_t *)va_arg(ap, unsigned char *);
 
 	for (i = 0; i < (int)strlen(ip); i++) {
 		if (ip[i] == ':') {
@@ -1001,8 +1031,8 @@
 			g_free(host);
 			return 1;
 		}
-		aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0);
-		aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, gaim_rateresp, 0);
+		aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, server_ready_auth, 0);
+		aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, rateresp_auth, 0);
 		aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, gaim_info_change, 0);
 		aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, gaim_info_change, 0);
 		aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, gaim_account_confirm, 0);
@@ -1024,7 +1054,7 @@
 			g_free(host);
 			return 1;
 		}
-		aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0);
+		aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, server_ready_chatnav, 0);
 
 		tstconn->status |= AIM_CONN_STATUS_INPROGRESS;
 		tstconn->fd = proxy_connect(host, port, oscar_chatnav_connect, gc);
@@ -1038,9 +1068,13 @@
 		break;
 	case 0xe: /* Chat */
 		{
-		char *roomname = va_arg(ap, char *);
-		int exchange = va_arg(ap, int);
+		char *roomname;
+		fu16_t exchange;
 		struct chat_connection *ccon;
+
+		roomname = va_arg(ap, char *);
+		exchange = (fu16_t)va_arg(ap, unsigned int);
+
 		tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, NULL);
 		if (tstconn == NULL) {
 			debug_printf("unable to connect to chat server\n");
@@ -1048,7 +1082,7 @@
 			return 1;
 		}
 
-		aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0);
+		aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, server_ready_chat, 0);
 		ccon = g_new0(struct chat_connection, 1);
 		ccon->conn = tstconn;
 		ccon->gc = gc;
@@ -1083,15 +1117,14 @@
 	return 1;
 }
 
-int gaim_parse_oncoming(struct aim_session_t *sess,
-			struct command_rx_struct *command, ...) {
+static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) {
 	struct aim_userinfo_s *info;
 	time_t time_idle;
 	int type = 0;
 	struct gaim_connection *gc = sess->aux_data;
 
 	va_list ap;
-	va_start(ap, command);
+	va_start(ap, fr);
 	info = va_arg(ap, struct aim_userinfo_s *);
 	va_end(ap);
 
@@ -1118,13 +1151,12 @@
 	return 1;
 }
 
-int gaim_parse_offgoing(struct aim_session_t *sess,
-			struct command_rx_struct *command, ...) {
+static int gaim_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...) {
 	struct aim_userinfo_s *info;
 	va_list ap;
 	struct gaim_connection *gc = sess->aux_data;
 
-	va_start(ap, command);
+	va_start(ap, fr);
 	info = va_arg(ap, struct aim_userinfo_s *);
 	va_end(ap);
 
@@ -1157,8 +1189,12 @@
 		return;
 	}
 
+	if (dim->conn->fd != source)
+		dim->conn->fd = source;
+
 	aim_conn_completeconnect(od->sess, dim->conn);
-	if (!(cnv = find_conversation(dim->name))) cnv = new_conversation(dim->name);
+	if (!(cnv = find_conversation(dim->name))) 
+		cnv = new_conversation(dim->name);
 	g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), dim->name);
 	write_to_conv(cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL));
 
@@ -1186,27 +1222,25 @@
 	dim->gc = d->gc;
 	g_snprintf(dim->name, sizeof dim->name, "%s", d->sn);
 
-	if ((dim->conn = aim_newconn(od->sess, AIM_CONN_TYPE_RENDEZVOUS, NULL)) == NULL) {
+	dim->conn = aim_directim_connect(od->sess, d->sn, NULL, d->cookie);
+	if (!dim->conn) {
 		g_free(dim);
 		cancel_direct_im(w, d);
 		return TRUE;
 	}
-	dim->conn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM;
-	dim->conn->priv = d->priv;
+
 	aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING,
 				gaim_directim_incoming, 0);
-	aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT,
-				gaim_directim_disconnect, 0);
 	aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING,
 				gaim_directim_typing, 0);
 
-	for (i = 0; i < (int)strlen(d->priv->ip); i++) {
-		if (d->priv->ip[i] == ':') {
-			port = atoi(&(d->priv->ip[i+1]));
+	for (i = 0; i < (int)strlen(d->ip); i++) {
+		if (d->ip[i] == ':') {
+			port = atoi(&(d->ip[i+1]));
 			break;
 		}
 	}
-	host = g_strndup(d->priv->ip, i);
+	host = g_strndup(d->ip, i);
 	dim->conn->status |= AIM_CONN_STATUS_INPROGRESS;
 	dim->conn->fd = proxy_connect(host, port, oscar_directim_callback, dim);
 	g_free(host);
@@ -1222,151 +1256,169 @@
 	return TRUE;
 }
 
-int gaim_parse_incoming_im(struct aim_session_t *sess,
-			   struct command_rx_struct *command, ...) {
-	int channel;
+static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch1_args *args) {
+	char *tmp = g_malloc(BUF_LONG);
+	struct gaim_connection *gc = sess->aux_data;
+
+	if (args->icbmflags & AIM_IMFLAGS_HASICON) {
+		struct oscar_data *od = gc->proto_data;
+		struct icon_req *ir = NULL;
+		GSList *h = od->hasicons;
+		char *who = normalize(userinfo->sn);
+		debug_printf("%s has an icon\n", userinfo->sn);
+		while (h) {
+			ir = h->data;
+			if (!strcmp(ir->user, who))
+				break;
+			h = h->next;
+		}
+		if (!h) {
+			ir = g_new0(struct icon_req, 1);
+			ir->user = g_strdup(who);
+			od->hasicons = g_slist_append(od->hasicons, ir);
+		}
+		if ((args->iconlen != ir->length) ||
+		    (args->iconsum != ir->checksum) ||
+		    (args->iconstamp != ir->timestamp))
+			ir->request = TRUE;
+		ir->length = args->iconlen;
+		ir->checksum = args->iconsum;
+		ir->timestamp = args->iconstamp;
+	}
+
+	if (gc->iconfile && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)) {
+		FILE *file;
+		struct stat st;
+
+		if (!stat(gc->iconfile, &st)) {
+			char *buf = g_malloc(st.st_size);
+			file = fopen(gc->iconfile, "r");
+			if (file) {
+				fread(buf, 1, st.st_size, file);
+				aim_send_icon(sess, conn, userinfo->sn, buf, st.st_size,
+					      st.st_mtime, aim_iconsum(buf, st.st_size));
+				fclose(file);
+			}
+			g_free(buf);
+		}
+	}
+
+	/*
+	 * Quickly convert it to eight bit format, replacing 
+	 * non-ASCII UNICODE characters with their equivelent 
+	 * HTML entity.
+	 */
+	if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
+		int i;
+		
+		for (i = 0, tmp[0] = '\0'; i < args->msglen; i += 2) {
+			unsigned short uni;
+			
+			uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
+
+			if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
+				
+				g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "%c", uni);
+				
+			} else { /* something else, do UNICODE entity */
+				g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "&#%04x;", uni);
+			}
+		}
+	} else
+		g_snprintf(tmp, BUF_LONG, "%s", args->msg);
+
+	serv_got_im(gc, userinfo->sn, tmp, args->icbmflags & AIM_IMFLAGS_AWAY, time(NULL));
+	g_free(tmp);
+
+	return 1;
+}
+
+static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args) {
+	struct gaim_connection *gc = sess->aux_data;
+
+	if (args->reqclass & AIM_CAPS_CHAT) {
+		char *name = extract_name(args->info.chat.roominfo.name);
+		int *exch = g_new0(int, 1);
+		GList *m = NULL;
+		m = g_list_append(m, g_strdup(name ? name : args->info.chat.roominfo.name));
+		*exch = args->info.chat.roominfo.exchange;
+		m = g_list_append(m, exch);
+		serv_got_chat_invite(gc,
+				     name ? name : args->info.chat.roominfo.name,
+				     userinfo->sn,
+				     args->info.chat.msg,
+				     m);
+		if (name)
+			g_free(name);
+	} else if (args->reqclass & AIM_CAPS_SENDFILE) {
+	} else if (args->reqclass & AIM_CAPS_GETFILE) {
+	} else if (args->reqclass & AIM_CAPS_VOICE) {
+	} else if (args->reqclass & AIM_CAPS_BUDDYICON) {
+		set_icon_data(gc, normalize(userinfo->sn), args->info.icon.icon,
+				args->info.icon.length);
+	} else if (args->reqclass & AIM_CAPS_IMIMAGE) {
+		struct ask_direct *d = g_new0(struct ask_direct, 1);
+		char buf[256];
+
+		debug_printf("%s received direct im request from %s (%s)\n",
+				gc->username, userinfo->sn, args->info.imimage.ip);
+
+		d->gc = gc;
+		d->sn = g_strdup(userinfo->sn);
+		strncpy(d->ip, args->info.imimage.ip, sizeof(d->ip));
+		memcpy(d->cookie, args->cookie, 8);
+		g_snprintf(buf, sizeof buf, "%s has just asked to directly connect to %s.",
+				userinfo->sn, gc->username);
+		do_ask_dialog(buf, d, accept_direct_im, cancel_direct_im);
+	} else {
+		debug_printf("Unknown reqclass %d\n", args->reqclass);
+	}
+
+	return 1;
+}
+
+
+static int gaim_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...) {
+	int channel, ret = 0;
 	struct aim_userinfo_s *userinfo;
 	va_list ap;
-	struct gaim_connection *gc = sess->aux_data;
-
-	va_start(ap, command);
+
+	va_start(ap, fr);
 	channel = va_arg(ap, int);
 	userinfo = va_arg(ap, struct aim_userinfo_s *);
 
 	/* channel 1: standard message */
 	if (channel == 1) {
-		char *tmp = g_malloc(BUF_LONG);
 		struct aim_incomingim_ch1_args *args;
 
 		args = va_arg(ap, struct aim_incomingim_ch1_args *);
-		va_end(ap);
-
-		if (args->icbmflags & AIM_IMFLAGS_HASICON) {
-			struct oscar_data *od = gc->proto_data;
-			struct icon_req *ir = NULL;
-			GSList *h = od->hasicons;
-			char *who = normalize(userinfo->sn);
-			debug_printf("%s has an icon\n", userinfo->sn);
-			while (h) {
-				ir = h->data;
-				if (!strcmp(ir->user, who))
-					break;
-				h = h->next;
-			}
-			if (!h) {
-				ir = g_new0(struct icon_req, 1);
-				ir->user = g_strdup(who);
-				od->hasicons = g_slist_append(od->hasicons, ir);
-			}
-			if ((args->iconlength != ir->length) ||
-			    (args->iconchecksum != ir->checksum) ||
-			    (args->iconstamp != ir->timestamp))
-				ir->request = TRUE;
-			ir->length = args->iconlength;
-			ir->checksum = args->iconchecksum;
-			ir->timestamp = args->iconstamp;
-		}
-
-		if (gc->iconfile && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)) {
-			FILE *file;
-			struct stat st;
-
-			if (!stat(gc->iconfile, &st)) {
-				char *buf = g_malloc(st.st_size);
-				file = fopen(gc->iconfile, "r");
-				if (file) {
-					fread(buf, 1, st.st_size, file);
-					aim_send_icon(sess, command->conn, userinfo->sn, buf, st.st_size,
-						      st.st_mtime, aim_iconsum(buf, st.st_size));
-					fclose(file);
-				}
-				g_free(buf);
-			}
-		}
-
-		/*
-		 * Quickly convert it to eight bit format, replacing 
-		 * non-ASCII UNICODE characters with their equivelent 
-		 * HTML entity.
-		 */
-		if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
-			int i;
-			
-			for (i = 0, tmp[0] = '\0'; i < args->msglen; i += 2) {
-				unsigned short uni;
-				
-				uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
-
-				if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
-					
-					g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "%c", uni);
-					
-				} else { /* something else, do UNICODE entity */
-					g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "&#%04x;", uni);
-				}
-			}
-		} else
-			g_snprintf(tmp, BUF_LONG, "%s", args->msg);
-
-		serv_got_im(gc, userinfo->sn, tmp, args->icbmflags & AIM_IMFLAGS_AWAY, time(NULL));
-		g_free(tmp);
+
+		ret = incomingim_chan1(sess, fr->conn, userinfo, args);
+
 	} else if (channel == 2) {
 		struct aim_incomingim_ch2_args *args;
+
 		args = va_arg(ap, struct aim_incomingim_ch2_args *);
-		va_end(ap);
-		if (args->reqclass & AIM_CAPS_CHAT) {
-			char *name = extract_name(args->info.chat.roominfo.name);
-			int *exch = g_new0(int, 1);
-			GList *m = NULL;
-			m = g_list_append(m, g_strdup(name ? name : args->info.chat.roominfo.name));
-			*exch = args->info.chat.roominfo.exchange;
-			m = g_list_append(m, exch);
-			serv_got_chat_invite(gc,
-					     name ? name : args->info.chat.roominfo.name,
-					     userinfo->sn,
-					     args->info.chat.msg,
-					     m);
-			if (name)
-				g_free(name);
-		} else if (args->reqclass & AIM_CAPS_SENDFILE) {
-		} else if (args->reqclass & AIM_CAPS_GETFILE) {
-		} else if (args->reqclass & AIM_CAPS_VOICE) {
-		} else if (args->reqclass & AIM_CAPS_BUDDYICON) {
-			set_icon_data(gc, normalize(userinfo->sn), args->info.icon.icon,
-					args->info.icon.length);
-		} else if (args->reqclass & AIM_CAPS_IMIMAGE) {
-			struct ask_direct *d = g_new0(struct ask_direct, 1);
-			char buf[256];
-
-			debug_printf("%s received direct im request from %s (%s)\n",
-					gc->username, userinfo->sn, args->info.directim->ip);
-
-			d->gc = gc;
-			d->sn = g_strdup(userinfo->sn);
-			d->priv = args->info.directim;
-			g_snprintf(buf, sizeof buf, "%s has just asked to directly connect to %s.",
-					userinfo->sn, gc->username);
-			do_ask_dialog(buf, d, accept_direct_im, cancel_direct_im);
-		} else {
-			debug_printf("Unknown reqclass %d\n", args->reqclass);
-		}
+
+		ret = incomingim_chan2(sess, fr->conn, userinfo, args);
 	}
 
-	return 1;
+	va_end(ap);
+
+	return ret;
 }
 
-int gaim_parse_misses(struct aim_session_t *sess,
-		      struct command_rx_struct *command, ...) {
+static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	unsigned short chan, nummissed, reason;
+	fu16_t chan, nummissed, reason;
 	struct aim_userinfo_s *userinfo;
 	char buf[1024];
 
-	va_start(ap, command);
-	chan = (unsigned short)va_arg(ap, unsigned int);
+	va_start(ap, fr);
+	chan = (fu16_t)va_arg(ap, unsigned int);
 	userinfo = va_arg(ap, struct aim_userinfo_s *);
-	nummissed = (unsigned short)va_arg(ap, unsigned int);
-	reason = (unsigned short)va_arg(ap, unsigned int);
+	nummissed = (fu16_t)va_arg(ap, unsigned int);
+	reason = (fu16_t)va_arg(ap, unsigned int);
 	va_end(ap);
 
 	switch(reason) {
@@ -1431,12 +1483,12 @@
 	return 1;
 }
 
-int gaim_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+static int gaim_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	unsigned short reason;
-
-	va_start(ap, command);
-	reason = va_arg(ap, int);
+	fu16_t reason;
+
+	va_start(ap, fr);
+	reason = (fu16_t)va_arg(ap, unsigned int);
 	va_end(ap);
 
 	debug_printf("snac threw error (reason 0x%04x: %s\n", reason,
@@ -1445,15 +1497,14 @@
 	return 1;
 }
 
-int gaim_parse_msgerr(struct aim_session_t *sess,
-		      struct command_rx_struct *command, ...) {
+static int gaim_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
 	char *destn;
-	unsigned short reason;
+	fu16_t reason;
 	char buf[1024];
 
-	va_start(ap, command);
-	reason = (unsigned short)va_arg(ap, unsigned int);
+	va_start(ap, fr);
+	reason = (fu16_t)va_arg(ap, unsigned int);
 	destn = va_arg(ap, char *);
 	va_end(ap);
 
@@ -1464,15 +1515,14 @@
 	return 1;
 }
 
-int gaim_parse_locerr(struct aim_session_t *sess,
-		      struct command_rx_struct *command, ...) {
+static int gaim_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
 	char *destn;
-	unsigned short reason;
+	fu16_t reason;
 	char buf[1024];
 
-	va_start(ap, command);
-	reason = (unsigned short)va_arg(ap, unsigned int);
+	va_start(ap, fr);
+	reason = (fu16_t)va_arg(ap, unsigned int);
 	destn = va_arg(ap, char *);
 	va_end(ap);
 
@@ -1493,22 +1543,21 @@
 	return buf;
 }
 
-int gaim_parse_user_info(struct aim_session_t *sess,
-			 struct command_rx_struct *command, ...) {
+static int gaim_parse_user_info(aim_session_t *sess, aim_frame_t *fr, ...) {
 	struct aim_userinfo_s *info;
 	char *prof_enc = NULL, *prof = NULL;
-	unsigned short infotype;
+	fu16_t infotype;
 	char buf[BUF_LONG];
 	char legend[BUF_LONG];
 	struct gaim_connection *gc = sess->aux_data;
 	va_list ap;
 	char *asc;
 
-	va_start(ap, command);
+	va_start(ap, fr);
 	info = va_arg(ap, struct aim_userinfo_s *);
 	prof_enc = va_arg(ap, char *);
 	prof = va_arg(ap, char *);
-	infotype = (unsigned short)va_arg(ap, unsigned int);
+	infotype = (fu16_t)va_arg(ap, unsigned int);
 	va_end(ap);
 
 	if (info->membersince)
@@ -1549,22 +1598,21 @@
 	return 1;
 }
 
-int gaim_parse_motd(struct aim_session_t *sess,
-		    struct command_rx_struct *command, ...) {
+static int gaim_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...) {
 	char *msg;
-	unsigned short id;
+	fu16_t id;
 	va_list ap;
 	char buildbuf[150];
 
-	va_start(ap, command);
-	id  = (unsigned short)va_arg(ap, unsigned int);
+	va_start(ap, fr);
+	id  = (fu16_t)va_arg(ap, unsigned int);
 	msg = va_arg(ap, char *);
 	va_end(ap);
 
 	aim_getbuildstring(buildbuf, sizeof(buildbuf));
 
 	debug_printf("MOTD: %s (%d)\n", msg ? msg : "Unknown", id);
-	debug_printf("Gaim %s / Libfaim %s\n", VERSION, buildbuf);
+	debug_printf("Gaim %s / libfaim %s\n", VERSION, buildbuf);
 	if (id < 4)
 		do_error_dialog(_("Your connection may be lost."),
 				_("AOL error"));
@@ -1572,23 +1620,22 @@
 	return 1;
 }
 
-int gaim_chatnav_info(struct aim_session_t *sess,
-		      struct command_rx_struct *command, ...) {
+static int gaim_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	unsigned short type;
+	fu16_t type;
 	struct gaim_connection *gc = sess->aux_data;
 	struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
 
-	va_start(ap, command);
-	type = (unsigned short)va_arg(ap, unsigned int);
+	va_start(ap, fr);
+	type = (fu16_t)va_arg(ap, unsigned int);
 
 	switch(type) {
 		case 0x0002: {
-			int maxrooms;
+			fu8_t maxrooms;
 			struct aim_chat_exchangeinfo *exchanges;
-			int exchangecount, i = 0;
-
-			maxrooms = (unsigned char)va_arg(ap, unsigned int);
+			int exchangecount, i;
+
+			maxrooms = (fu8_t)va_arg(ap, unsigned int);
 			exchangecount = va_arg(ap, int);
 			exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
 			va_end(ap);
@@ -1596,11 +1643,11 @@
 			debug_printf("chat info: Chat Rights:\n");
 			debug_printf("chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
 			debug_printf("chat info: \tExchange List: (%d total)\n", exchangecount);
-			while (i < exchangecount)
-				debug_printf("chat info: \t\t%d\n", exchanges[i++].number);
+			for (i = 0; i < exchangecount; i++)
+				debug_printf("chat info: \t\t%d\n", exchanges[i].number);
 			if (odata->create_exchange) {
 				debug_printf("creating room %s\n", odata->create_name);
-				aim_chatnav_createroom(sess, command->conn, odata->create_name,
+				aim_chatnav_createroom(sess, fr->conn, odata->create_name,
 						odata->create_exchange);
 				odata->create_exchange = 0;
 				g_free(odata->create_name);
@@ -1610,19 +1657,19 @@
 			break;
 		case 0x0008: {
 			char *fqcn, *name, *ck;
-			unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
-			unsigned char createperms;
-			unsigned long createtime;
+			fu16_t instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
+			fu8_t createperms;
+			fu32_t createtime;
 
 			fqcn = va_arg(ap, char *);
-			instance = (unsigned short)va_arg(ap, unsigned int);
-			exchange = (unsigned short)va_arg(ap, unsigned int);
-			flags = (unsigned short)va_arg(ap, unsigned int);
-			createtime = va_arg(ap, unsigned long);
-			maxmsglen = (unsigned short)va_arg(ap, unsigned int);
-			maxoccupancy = (unsigned short)va_arg(ap, unsigned int);
-			createperms = (unsigned char)va_arg(ap, int);
-			unknown = (unsigned short)va_arg(ap, unsigned int);
+			instance = (fu16_t)va_arg(ap, unsigned int);
+			exchange = (fu16_t)va_arg(ap, unsigned int);
+			flags = (fu16_t)va_arg(ap, unsigned int);
+			createtime = va_arg(ap, fu32_t);
+			maxmsglen = (fu16_t)va_arg(ap, unsigned int);
+			maxoccupancy = (fu16_t)va_arg(ap, unsigned int);
+			createperms = (fu8_t)va_arg(ap, int);
+			unknown = (fu16_t)va_arg(ap, unsigned int);
 			name = va_arg(ap, char *);
 			ck = va_arg(ap, char *);
 			va_end(ap);
@@ -1633,7 +1680,7 @@
 					createtime,
 					maxmsglen, maxoccupancy, createperms, unknown,
 					name, ck);
-			aim_chat_join(odata->sess, odata->conn, exchange, ck);
+			aim_chat_join(odata->sess, odata->conn, exchange, ck, instance);
 			}
 			break;
 		default:
@@ -1644,79 +1691,76 @@
 	return 1;
 }
 
-int gaim_chat_join(struct aim_session_t *sess,
-		   struct command_rx_struct *command, ...) {
+static int gaim_chat_join(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	int count, i = 0;
+	int count, i;
 	struct aim_userinfo_s *info;
 	struct gaim_connection *g = sess->aux_data;
 
 	struct chat_connection *c = NULL;
 
-	va_start(ap, command);
+	va_start(ap, fr);
 	count = va_arg(ap, int);
 	info  = va_arg(ap, struct aim_userinfo_s *);
 	va_end(ap);
 
-	c = find_oscar_chat_by_conn(g, command->conn);
+	c = find_oscar_chat_by_conn(g, fr->conn);
 	if (!c)
 		return 1;
 
-	while (i < count)
-		add_chat_buddy(c->cnv, info[i++].sn);
+	for (i = 0; i < count; i++)
+		add_chat_buddy(c->cnv, info[i].sn);
 
 	return 1;
 }
 
-int gaim_chat_leave(struct aim_session_t *sess,
-		    struct command_rx_struct *command, ...) {
+static int gaim_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	int count, i = 0;
+	int count, i;
 	struct aim_userinfo_s *info;
 	struct gaim_connection *g = sess->aux_data;
 
 	struct chat_connection *c = NULL;
 
-	va_start(ap, command);
+	va_start(ap, fr);
 	count = va_arg(ap, int);
 	info  = va_arg(ap, struct aim_userinfo_s *);
 	va_end(ap);
 
-	c = find_oscar_chat_by_conn(g, command->conn);
+	c = find_oscar_chat_by_conn(g, fr->conn);
 	if (!c)
 		return 1;
 
-	while (i < count)
-		remove_chat_buddy(c->cnv, info[i++].sn);
+	for (i = 0; i < count; i++)
+		remove_chat_buddy(c->cnv, info[i].sn);
 
 	return 1;
 }
 
-int gaim_chat_info_update(struct aim_session_t *sess,
-			  struct command_rx_struct *command, ...) {
+static int gaim_chat_info_update(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
 	struct aim_userinfo_s *userinfo;
 	struct aim_chat_roominfo *roominfo;
 	char *roomname;
 	int usercount;
 	char *roomdesc;
-	unsigned short unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
-	unsigned long creationtime;
+	fu16_t unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
+	fu32_t creationtime;
 	struct gaim_connection *gc = sess->aux_data;
-	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, command->conn);
-
-	va_start(ap, command);
+	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn);
+
+	va_start(ap, fr);
 	roominfo = va_arg(ap, struct aim_chat_roominfo *);
 	roomname = va_arg(ap, char *);
 	usercount= va_arg(ap, int);
 	userinfo = va_arg(ap, struct aim_userinfo_s *);
 	roomdesc = va_arg(ap, char *);
-	unknown_c9 = va_arg(ap, int);
-	creationtime = va_arg(ap, unsigned long);
-	maxmsglen = va_arg(ap, int);
-	unknown_d2 = va_arg(ap, int);
-	unknown_d5 = va_arg(ap, int);
-	maxvisiblemsglen = va_arg(ap, int);
+	unknown_c9 = (fu16_t)va_arg(ap, int);
+	creationtime = (fu32_t)va_arg(ap, unsigned long);
+	maxmsglen = (fu16_t)va_arg(ap, int);
+	unknown_d2 = (fu16_t)va_arg(ap, int);
+	unknown_d5 = (fu16_t)va_arg(ap, int);
+	maxvisiblemsglen = (fu16_t)va_arg(ap, int);
 	va_end(ap);
 
 	debug_printf("inside chat_info_update (maxmsglen = %d, maxvislen = %d)\n",
@@ -1728,16 +1772,15 @@
 	return 1;
 }
 
-int gaim_chat_incoming_msg(struct aim_session_t *sess,
-			   struct command_rx_struct *command, ...) {
+static int gaim_chat_incoming_msg(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
 	struct aim_userinfo_s *info;
 	char *msg;
 	struct gaim_connection *gc = sess->aux_data;
-	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, command->conn);
+	struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn);
 	char *tmp;
 
-	va_start(ap, command);
+	va_start(ap, fr);
 	info = va_arg(ap, struct aim_userinfo_s *);
 	msg  = va_arg(ap, char *);
 
@@ -1749,16 +1792,16 @@
 	return 1;
 }
 
- /*
-  * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option.
-  */
-int gaim_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+/*
+ * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option.
+ */
+static int gaim_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	unsigned short type;
-	char *sn = NULL;
-
-	va_start(ap, command);
-	type = (unsigned short)va_arg(ap, unsigned int);
+	fu16_t type;
+	char *sn;
+
+	va_start(ap, fr);
+	type = (fu16_t)va_arg(ap, unsigned int);
 	sn = va_arg(ap, char *);
 	va_end(ap);
 
@@ -1767,27 +1810,28 @@
 	return 1;
 }
 
-int gaim_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
-	static char *codes[5] = {"invalid",
-				 "change",
-				 "warning",
-				 "limit",
-				 "limit cleared"};
+static int gaim_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...) {
+	static const char *codes[5] = {
+		"invalid",
+		 "change",
+		 "warning",
+		 "limit",
+		 "limit cleared",
+	};
 	va_list ap;
-	int code;
-	unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
-	unsigned long currentavg, maxavg;
-
-	va_start(ap, command); 
-	code = va_arg(ap, int);
-	rateclass= va_arg(ap, int);
-	windowsize = va_arg(ap, unsigned long);
-	clear = va_arg(ap, unsigned long);
-	alert = va_arg(ap, unsigned long);
-	limit = va_arg(ap, unsigned long);
-	disconnect = va_arg(ap, unsigned long);
-	currentavg = va_arg(ap, unsigned long);
-	maxavg = va_arg(ap, unsigned long);
+	fu16_t code, rateclass;
+	fu32_t windowsize, clear, alert, limit, disconnect, currentavg, maxavg;
+
+	va_start(ap, fr); 
+	code = (fu16_t)va_arg(ap, unsigned int);
+	rateclass= (fu16_t)va_arg(ap, unsigned int);
+	windowsize = (fu32_t)va_arg(ap, unsigned long);
+	clear = (fu32_t)va_arg(ap, unsigned long);
+	alert = (fu32_t)va_arg(ap, unsigned long);
+	limit = (fu32_t)va_arg(ap, unsigned long);
+	disconnect = (fu32_t)va_arg(ap, unsigned long);
+	currentavg = (fu32_t)va_arg(ap, unsigned long);
+	maxavg = (fu32_t)va_arg(ap, unsigned long);
 	va_end(ap);
 
 	debug_printf("rate %s (paramid 0x%04lx): curavg = %ld, maxavg = %ld, alert at %ld, "
@@ -1799,28 +1843,29 @@
 		     limit, disconnect,
 		     windowsize);
 
+	/* XXX fix these values */
 	if (code == AIM_RATE_CODE_CHANGE) {
 		if (currentavg >= clear)
-			aim_conn_setlatency(command->conn, 0);
+			aim_conn_setlatency(fr->conn, 0);
 	} else if (code == AIM_RATE_CODE_WARNING) {
-		aim_conn_setlatency(command->conn, windowsize/4);
+		aim_conn_setlatency(fr->conn, windowsize/4);
 	} else if (code == AIM_RATE_CODE_LIMIT) {
-		aim_conn_setlatency(command->conn, windowsize/2);
+		aim_conn_setlatency(fr->conn, windowsize/2);
 	} else if (code == AIM_RATE_CODE_CLEARLIMIT) {
-		aim_conn_setlatency(command->conn, 0);
+		aim_conn_setlatency(fr->conn, 0);
 	}
 
 	return 1;
 }
 
-int gaim_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+static int gaim_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	int newevil;
+	fu16_t newevil;
 	struct aim_userinfo_s *userinfo;
 	struct gaim_connection *gc = sess->aux_data;
 
-	va_start(ap, command);
-	newevil = va_arg(ap, int);
+	va_start(ap, fr);
+	newevil = (fu16_t)va_arg(ap, unsigned int);
 	userinfo = va_arg(ap, struct aim_userinfo_s *);
 	va_end(ap);
 
@@ -1829,51 +1874,46 @@
 	return 1;
 }
 
-int gaim_rateresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+static int rateresp_bos(aim_session_t *sess, aim_frame_t *fr, ...) {
 	struct gaim_connection *gc = sess->aux_data;
-	switch (command->conn->type) {
-	case AIM_CONN_TYPE_BOS:
-		aim_bos_ackrateresp(sess, command->conn);
-		aim_bos_reqpersonalinfo(sess, command->conn);
-		aim_bos_reqlocaterights(sess, command->conn);
-		aim_bos_setprofile(sess, command->conn, gc->user->user_info, NULL, gaim_caps);
-		aim_bos_reqbuddyrights(sess, command->conn);
-
-		account_online(gc);
-		serv_finish_login(gc);
-
-		if (bud_list_cache_exists(gc))
-			do_import(NULL, gc);
-
-		debug_printf("buddy list loaded\n");
-
-		aim_reqicbmparams(sess, command->conn);
-
-		aim_bos_reqrights(sess, command->conn);
-		aim_bos_setgroupperm(sess, command->conn, AIM_FLAG_ALLUSERS);
-		aim_bos_setprivacyflags(sess, command->conn, AIM_PRIVFLAGS_ALLOWIDLE |
-							     AIM_PRIVFLAGS_ALLOWMEMBERSINCE);
-
-		break;
-	case AIM_CONN_TYPE_AUTH:
-		aim_bos_ackrateresp(sess, command->conn);
-		aim_auth_clientready(sess, command->conn);
-		debug_printf("connected to auth (admin)\n");
-		break;
-	default:
-		debug_printf("got rate response for unhandled connection type %04x\n",
-				command->conn->type);
-		break;
-	}
+
+	aim_bos_ackrateresp(sess, fr->conn);
+	aim_bos_reqpersonalinfo(sess, fr->conn);
+	aim_bos_reqlocaterights(sess, fr->conn);
+	aim_bos_setprofile(sess, fr->conn, gc->user->user_info, NULL, gaim_caps);
+	aim_bos_reqbuddyrights(sess, fr->conn);
+
+	account_online(gc);
+	serv_finish_login(gc);
+
+	if (bud_list_cache_exists(gc))
+		do_import(NULL, gc);
+
+	debug_printf("buddy list loaded\n");
+
+	aim_reqicbmparams(sess, fr->conn);
+
+	aim_bos_reqrights(sess, fr->conn);
+	aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS);
+	aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE |
+						     AIM_PRIVFLAGS_ALLOWMEMBERSINCE);
 
 	return 1;
 }
 
-int gaim_icbm_param_info(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+static int rateresp_auth(aim_session_t *sess, aim_frame_t *fr, ...) {
+	aim_bos_ackrateresp(sess, fr->conn);
+	aim_auth_clientready(sess, fr->conn);
+	debug_printf("connected to auth (admin)\n");
+
+	return 1;
+}
+
+static int gaim_icbm_param_info(aim_session_t *sess, aim_frame_t *fr, ...) {
 	struct aim_icbmparameters *params;
 	va_list ap;
 
-	va_start(ap, command);
+	va_start(ap, fr);
 	params = va_arg(ap, struct aim_icbmparameters *);
 	va_end(ap);
 
@@ -1883,36 +1923,23 @@
 			((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0,
 			params->minmsginterval);
 
+	/* Maybe senderwarn and recverwarn should be user preferences... */
 	params->maxmsglen = 8000;
 	params->minmsginterval = 0;
 
-	aim_seticbmparam(sess, command->conn, params);
+	aim_seticbmparam(sess, fr->conn, params);
 
 	return 1;
 }
 
-int gaim_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+/* XXX this is frivelous... do you really want to know this info? */
+static int gaim_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	unsigned short interval = 0;
-
-	va_start(ap, command);
-	interval = va_arg(ap, int);
-	va_end(ap);
-
-	debug_printf("minimum report interval: %d (seconds?)\n", interval);
-
-	aim_reqicbmparams(sess, command->conn);
-
-	return 1;
-}
-
-int gaim_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
-	va_list ap;
-	unsigned short maxbuddies, maxwatchers;
-
-	va_start(ap, command);
-	maxbuddies = (unsigned short)va_arg(ap, unsigned int);
-	maxwatchers = (unsigned short)va_arg(ap, unsigned int);
+	fu16_t maxbuddies, maxwatchers;
+
+	va_start(ap, fr);
+	maxbuddies = (fu16_t)va_arg(ap, unsigned int);
+	maxwatchers = (fu16_t)va_arg(ap, unsigned int);
 	va_end(ap);
 
 	debug_printf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers);
@@ -1920,32 +1947,32 @@
 	return 1;
 }
 
-int gaim_bosrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
-	unsigned short maxpermits, maxdenies;
+static int gaim_bosrights(aim_session_t *sess, aim_frame_t *fr, ...) {
+	fu16_t maxpermits, maxdenies;
 	va_list ap;
 
-	va_start(ap, command);
-	maxpermits = (unsigned short)va_arg(ap, unsigned int);
-	maxdenies = (unsigned short)va_arg(ap, unsigned int);
+	va_start(ap, fr);
+	maxpermits = (fu16_t)va_arg(ap, unsigned int);
+	maxdenies = (fu16_t)va_arg(ap, unsigned int);
 	va_end(ap);
 
 	debug_printf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies);
 
-	aim_bos_clientready(sess, command->conn);
-
-	aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV);
+	aim_bos_clientready(sess, fr->conn);
+
+	aim_bos_reqservice(sess, fr->conn, AIM_CONN_TYPE_CHATNAV);
 
 	return 1;
 }
 
-int gaim_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+static int gaim_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
 	char *address, *SNs;
 	int i, num;
 	char *buf;
 	int at = 0, len;
 
-	va_start(ap, command);
+	va_start(ap, fr);
 	address = va_arg(ap, char *);
 	num = va_arg(ap, int);
 	SNs = va_arg(ap, char *);
@@ -1962,12 +1989,12 @@
 	return 1;
 }
 
-int gaim_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+static int gaim_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
 	char *address;
 	char buf[BUF_LONG];
 
-	va_start(ap, command);
+	va_start(ap, fr);
 	address = va_arg(ap, char *);
 	va_end(ap);
 
@@ -1977,14 +2004,14 @@
 	return 1;
 }
 
-int gaim_account_confirm(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
-	int status;
+static int gaim_account_confirm(aim_session_t *sess, aim_frame_t *fr, ...) {
+	fu16_t status;
 	va_list ap;
 	char msg[256];
 	struct gaim_connection *gc = sess->aux_data;
 
-	va_start(ap, command);
-	status = va_arg(ap, int); /* status code of confirmation request */
+	va_start(ap, fr);
+	status = (fu16_t)va_arg(ap, unsigned int); /* status code of confirmation request */
 	va_end(ap);
 
 	debug_printf("account confirmation returned status 0x%04x (%s)\n", status,
@@ -1998,25 +2025,23 @@
 	return 1;
 }
 
-int gaim_info_change(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
-	unsigned short change = 0;
-	int perms, type, length, str;
+static int gaim_info_change(aim_session_t *sess, aim_frame_t *fr, ...) {
+	int change, str;
+	fu16_t perms, type, length;
 	char *val;
 	va_list ap;
 	char buf[BUF_LONG];
 	struct gaim_connection *gc = sess->aux_data;
 
-	va_start(ap, command);
-	perms = va_arg(ap, int);
-	type = va_arg(ap, int);
-	length = va_arg(ap, int);
+	va_start(ap, fr);
+	change = va_arg(ap, int);
+	perms = (fu16_t)va_arg(ap, unsigned int);
+	type = (fu16_t)va_arg(ap, unsigned int);
+	length = (fu16_t)va_arg(ap, unsigned int);
 	val = va_arg(ap, char *);
 	str = va_arg(ap, int);
 	va_end(ap);
 
-	if (aimutil_get16(command->data+2) == 0x0005)
-		change = 1;
-
 	debug_printf("info%s: perms = %d, type = %x, length = %d, val = %s\n",
 			change ? " change" : "", perms, type, length, str ? val : "(not string)");
 
@@ -2047,15 +2072,13 @@
 			return aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_AWAY, message);
 		else {
 			struct aim_sendimext_args args;
-
-			int flags = AIM_IMFLAGS_ACK;
-
 			GSList *h = odata->hasicons;
 			struct icon_req *ir = NULL;
 			char *who = normalize(name);
-
 			struct stat st;
 
+			args.flags = AIM_IMFLAGS_ACK;
+
 			while (h) {
 				ir = h->data;
 				if (ir->request && !strcmp(who, ir->user))
@@ -2064,7 +2087,7 @@
 			}
 			if (h) {
 				ir->request = FALSE;
-				flags |= AIM_IMFLAGS_BUDDYREQ;
+				args.flags |= AIM_IMFLAGS_BUDDYREQ;
 				debug_printf("sending buddy icon request with message\n");
 			}
 
@@ -2078,7 +2101,7 @@
 					args.iconsum   = aim_iconsum(buf, st.st_size);
 					args.iconstamp = st.st_mtime;
 
-					flags |= AIM_IMFLAGS_HASICON;
+					args.flags |= AIM_IMFLAGS_HASICON;
 
 					fclose(file);
 					g_free(buf);
@@ -2088,7 +2111,6 @@
 			args.destsn = name;
 			args.msg    = message;
 			args.msglen = strlen(message);
-			args.flags  = flags;
 
 			return aim_send_im_ext(odata->sess, odata->conn, &args);
 		}
@@ -2205,7 +2227,7 @@
 
 static void oscar_join_chat(struct gaim_connection *g, GList *data) {
 	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
-	struct aim_conn_t *cur = NULL;
+	aim_conn_t *cur;
 	char *name;
 	int *exchange;
 
@@ -2347,112 +2369,74 @@
 	return NULL;
 }
 
-static int gaim_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+static int gaim_directim_initiate(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
 	struct gaim_connection *gc = sess->aux_data;
 	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
-	struct aim_directim_priv *priv;
-	struct aim_conn_t *newconn;
+	aim_conn_t *newconn, *listenerconn;
 	struct conversation *cnv;
 	struct direct_im *dim;
 	char buf[256];
-
-	va_start(ap, command);
-	newconn = va_arg(ap, struct aim_conn_t *);
+	char *sn;
+
+	va_start(ap, fr);
+	newconn = va_arg(ap, aim_conn_t *);
+	listenerconn = va_arg(ap, aim_conn_t *);
 	va_end(ap);
 
-	priv = (struct aim_directim_priv *)newconn->priv;
-
-	debug_printf("DirectIM: initiate success to %s\n", priv->sn);
-	dim = find_direct_im(od, priv->sn);
-
-	if (!(cnv = find_conversation(priv->sn)))
-		cnv = new_conversation(priv->sn);
+	aim_conn_close(listenerconn);
+	aim_conn_kill(sess, &listenerconn);
+
+	sn = g_strdup(aim_directim_getsn(newconn));
+
+	debug_printf("DirectIM: initiate success to %s\n", sn);
+	dim = find_direct_im(od, sn);
+
+	if (!(cnv = find_conversation(sn)))
+		cnv = new_conversation(sn);
 	gaim_input_remove(dim->watcher);
 	dim->conn = newconn;
 	dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ,
 					oscar_callback, dim->conn);
-	g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), priv->sn);
+	g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), sn);
+	g_free(sn);
 	write_to_conv(cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL));
 
 	aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING,
 				gaim_directim_incoming, 0);
-	aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT,
-				gaim_directim_disconnect, 0);
 	aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING,
 				gaim_directim_typing, 0);
 
 	return 1;
 }
 
-static int gaim_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+static int gaim_directim_incoming(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	char *msg = NULL;
-	struct aim_conn_t *conn;
-	struct aim_directim_priv *priv;
+	char *msg, *sn;
 	struct gaim_connection *gc = sess->aux_data;
 
-	va_start(ap, command);
-	conn = va_arg(ap, struct aim_conn_t *);
+	va_start(ap, fr);
+	sn = va_arg(ap, char *);
 	msg = va_arg(ap, char *);
 	va_end(ap);
 
-	if (!(priv = conn->priv)) {
-		return -1;
-	}
-
-	debug_printf("Got DirectIM message from %s\n", priv->sn);
-
-	serv_got_im(gc, priv->sn, msg, 0, time((time_t)NULL));
+	debug_printf("Got DirectIM message from %s\n", sn);
+
+	serv_got_im(gc, sn, msg, 0, time((time_t)NULL));
 
 	return 1;
 }
 
-static int gaim_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+static int gaim_directim_typing(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
-	struct aim_conn_t *conn;
 	char *sn;
-	struct gaim_connection *gc = sess->aux_data;
-	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
-	struct conversation *cnv;
-	struct direct_im *dim;
-	char buf[256];
-
-	va_start(ap, command);
-	conn = va_arg(ap, struct aim_conn_t *);
+
+	va_start(ap, fr);
 	sn = va_arg(ap, char *);
 	va_end(ap);
 
-	debug_printf("%s disconnected Direct IM.\n", sn);
-
-	dim = find_direct_im(od, sn);
-	od->direct_ims = g_slist_remove(od->direct_ims, dim);
-	gaim_input_remove(dim->watcher);
-
-	g_snprintf(buf, sizeof buf, _("Direct IM with %s closed"), sn);
-	if ((cnv = find_conversation(sn)) != NULL)
-		write_to_conv(cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL));
-
-	aim_conn_kill(sess, &conn);
-
-	return 1;
-}
-
-static int gaim_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
-	va_list ap;
-	struct aim_conn_t *conn;
-	struct aim_directim_priv *priv;
-
-	va_start(ap, command);
-	conn = va_arg(ap, struct aim_conn_t *);
-	va_end(ap);
-
-	if (!(priv = conn->priv)) {
-		return -1;
-	}
-
 	/* I had to leave this. It's just too funny. It reminds me of my sister. */
-	debug_printf("ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", priv->sn);
+	debug_printf("ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn);
 
 	return 1;
 }
@@ -2480,7 +2464,7 @@
 	dim->gc = gc;
 	g_snprintf(dim->name, sizeof dim->name, "%s", data->who);
 
-	dim->conn = aim_directim_initiate(od->sess, od->conn, NULL, data->who);
+	dim->conn = aim_directim_initiate(od->sess, od->conn, data->who);
 	if (dim->conn != NULL) {
 		od->direct_ims = g_slist_append(od->direct_ims, dim);
 		dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ,
@@ -2617,7 +2601,7 @@
 static void oscar_do_action(struct gaim_connection *gc, char *act)
 {
 	struct oscar_data *od = gc->proto_data;
-	struct aim_conn_t *conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH);
+	aim_conn_t *conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH);
 
 	if (!strcmp(act, "Set User Info")) {
 		show_set_info(gc);
@@ -2673,6 +2657,20 @@
 	}
 }
 
+static void oscar_convo_closed(struct gaim_connection *gc, char *who)
+{
+	struct oscar_data *od = gc->proto_data;
+	struct direct_im *dim = find_direct_im(od, who);
+
+	if (!dim)
+		return;
+
+	od->direct_ims = g_slist_remove(od->direct_ims, dim);
+	gaim_input_remove(dim->watcher);
+	aim_conn_kill(od->sess, &dim->conn);
+	g_free(dim);
+}
+
 static struct prpl *my_protocol = NULL;
 
 void oscar_init(struct prpl *ret) {
@@ -2713,6 +2711,7 @@
 	ret->chat_whisper = NULL;
 	ret->chat_send = oscar_chat_send;
 	ret->keepalive = oscar_keepalive;
+	ret->convo_closed = oscar_convo_closed;
 
 	my_protocol = ret;
 }