diff src/protocols/oscar/ft.c @ 3952:07283934dedd

[gaim-migrate @ 4133] Ok, big commit with little functionality change. Most of it is me shuffling crap around because I'm one of them neat freaks. Lots of general code cleanup too. I'm trying to move to that whole "one-family-per-file" thing. The details... I added libfaim support for aim's new search family, 0x000f. I only tested this briefly, so if anyone uses it for anything, be aware that it could be buggy. I'll add oscar support sometime. Advantages of this family are... when you search for someone, you get the directory info for that person. So like, first name, middle name, last name, maiden name, city, state, country, zip, address, interests, nickname, and maybe some other stuff. Basically all the info that they've set in their directory info thing. Info. Oh, and I'm calling it "new search" because seach was already taken, and cookie monster ate my right brain. The reason I didn't add support to oscar.c... the new search family requires making a connection to another server. While moving stuff around I realized that I didn't really like how new connections are made. It's kind of sloppy. I'm thinking it would be nice to have an outgoing queue for each type of connection, and then let the client queue messages as much as they want. Then, if libfaim sees that there is a message for a certain type of connection, and there is no open connection of that type, it will connect, and then flush the queue when the connection is made. This seems a lot cleaner, but it also seems like a pain in the ass. I should do ssi for icq first, anyway :-) Also, I think it would be neat if there was an ICBM file that handled channels 1 through 4. Then im.c and chat.c could pass the ICBM part to the icbm stuff and it could get parsed there. im.c is really huge right now. I applied a patch from Graham Booker that paves the way for unicode in direct IMs. Thanks Graham. Now we just need Paco-Paco to git a little free time and write a patch for this. http://sourceforge.net/tracker/index.php?func=detail&aid=633589&group_id=235&atid=300235 I applied 2 patches from Will Mahan dealing with file transfer/oft/rendezous/whatever. Here's some info on them, from The Man himself: Patch 1 "Currently the Rendezvous code is rather messy; this patch attempts to bring it up to speed with the rest of the Oscar prpl. Its changes include: * Rewrite several ft.c functions to use bstreams. Apparently the code in question was written before bstreams were implemented. * Handle incoming Rendezvous packets through the rxqueue like FLAP packets, rather than handling them as a special case as soon as they are received. This takes advantage of the bstream cleanup to unify some code and simplify the aim_frame_t struct. * Change some names used to try to clarify the distinction between OFT, which refers specifically to file transfer, and Rendezvous, which encompasses OFT as well as other types of client-to-client connections." Patch 2 "* Add some comments I inadvertently left out of my last patch. * Fix a double-free that occurs when connections time out. * Correct a bug causing filenames to be truncated by 4 characters on some clients. * Preserve directory structure when sending multiple files. * Handle (throw away) resource forks sent by Mac clients." I also changed all indents to tabs in ft.c. And split all the bstream stuff from rxqueue.c and put it in bstream.c. It really is a separate thing. Especially since it can be used for outgoing connections. Also, I was going to look over the whole patch tonight to make sure it's all good, but it's like 6000 lines, so, uh, I'll do it later. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Wed, 13 Nov 2002 07:01:37 +0000
parents 765769211688
children 7ec84d1954fd
line wrap: on
line diff
--- a/src/protocols/oscar/ft.c	Tue Nov 12 03:40:19 2002 +0000
+++ b/src/protocols/oscar/ft.c	Wed Nov 13 07:01:37 2002 +0000
@@ -18,6 +18,7 @@
 #include <arpa/inet.h> /* for inet_ntoa */
 #endif
 
+/* XXX - I really don't think this should include gaim.h */
 #include "gaim.h"
 
 #ifdef _WIN32
@@ -45,8 +46,9 @@
 };
 
 static int listenestablish(fu16_t portnum);
-static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr);
-static const char *oft_basename(const char *name);
+static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs);
+static void oft_dirconvert(char *name);
+static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh);
  
 /**
  * aim_handlerendconnect - call this to accept OFT connections and set up the required structures
@@ -145,59 +147,60 @@
  */
 faim_export int aim_send_typing(aim_session_t *sess, aim_conn_t *conn, int typing)
 {
-	
-struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
+	struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
 	aim_frame_t *fr;
-	aim_bstream_t hdrbs; /* XXX this should be within aim_frame_t */
+	aim_bstream_t *hdrbs;
+	fu8_t *hdr;
+	int hdrlen = 0x44;
 
-	if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 
-		return -EINVAL; 
+	if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS))
+		return -EINVAL;
 
 	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, 0)))
-	       return -ENOMEM;	
+		return -ENOMEM;
+	memcpy(fr->hdr.rend.magic, "ODC2", 4);
+	fr->hdr.rend.hdrlen = hdrlen;
 
-	memcpy(fr->hdr.oft.magic, "ODC2", 4);
-	
-	fr->hdr.oft.hdr2len = 0x44;
-	
-	if (!(fr->hdr.oft.hdr2 = calloc(1, fr->hdr.oft.hdr2len))) { 
+	if (!(hdr = calloc(1, hdrlen))) {
 		aim_frame_destroy(fr);
 		return -ENOMEM;
 	}
-	
-	aim_bstream_init(&hdrbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len);
+
+	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);
+	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);
 
 	/* flags -- 0x000e for "started typing", 0x0002 for "stopped typing */
-	aimbs_put16(&hdrbs, ( typing ? 0x000e : 0x0002));
+	aimbs_put16(hdrbs, ( typing ? 0x000e : 0x0002));
 
-	aimbs_put16(&hdrbs, 0x0000);
-	aimbs_put16(&hdrbs, 0x0000);
-	aimbs_putraw(&hdrbs, sess->sn, strlen(sess->sn));
+	aimbs_put16(hdrbs, 0x0000);
+	aimbs_put16(hdrbs, 0x0000);
+	aimbs_putraw(hdrbs, sess->sn, strlen(sess->sn));
 	
-	aim_bstream_setpos(&hdrbs, 52); /* bleeehh */
+	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);
+	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 */
+	/* end of hdr */
 
 	aim_tx_enqueue(sess, fr);
 
@@ -208,17 +211,20 @@
  * aim_send_im_direct - send IM client-to-client over established connection
  * @sess: session to conn
  * @conn: directim connection
- * @msg:  null-terminated string to send. 
- * len:   The length of the message to send, including binary data.
+ * @msg: null-terminated string to send. 
+ * @len: The length of the message to send, including binary data.
+ * @encoding: 0 for ascii, 2 for Unicode, 3 for ISO 8859-1
  * 
  * Call this just like you would aim_send_im, to send a directim. You
  * _must_ have previously established the directim connection.
  */
-faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len)
+faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg, int len, int encoding)
 {
 	struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal;
 	aim_frame_t *fr;
-	aim_bstream_t hdrbs; /* XXX this should be within aim_frame_t */
+	aim_bstream_t *hdrbs;
+	int hdrlen = 0x44;
+	fu8_t *hdr;
 
 	if (!sess || !conn || !msg || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) 
 		return -EINVAL; 
@@ -226,46 +232,47 @@
 	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, len)))
 		return -ENOMEM;	
 
-	memcpy(fr->hdr.oft.magic, "ODC2", 4);
+	memcpy(fr->hdr.rend.magic, "ODC2", 4);
+	fr->hdr.rend.hdrlen = hdrlen;
 	
-	fr->hdr.oft.hdr2len = 0x44;
-	
-	if (!(fr->hdr.oft.hdr2 = calloc(1, fr->hdr.oft.hdr2len))) { 
+	if (!(hdr = calloc(1, hdrlen + len))) {
 		aim_frame_destroy(fr);
 		return -ENOMEM;
 	}
-	
-	aim_bstream_init(&hdrbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len);
-	
-	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, 0x0000);
-	aimbs_put16(&hdrbs, 0x0000);
-	aimbs_put16(&hdrbs, 0x0000);
+
+	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 -- 0x000e for "started typing", 0x0002 for "stopped typing, 0x0000 for message */
-	aimbs_put16(&hdrbs, 0x0000);
-	
-	aimbs_put16(&hdrbs, 0x0000);
-	aimbs_put16(&hdrbs, 0x0000);
-	aimbs_putraw(&hdrbs, sess->sn, strlen(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_put16(hdrbs, 0x0000);
+
+	aimbs_put16(hdrbs, 0x0000);
+	aimbs_put16(hdrbs, 0x0000);
+	aimbs_putraw(hdrbs, sess->sn, strlen(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 */
 	
@@ -279,7 +286,7 @@
 	i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e);
 	i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8);
 #endif
-	aimbs_putraw(&fr->data, msg, len);
+	aimbs_putraw(hdrbs, msg, len);
 	
 	aim_tx_enqueue(sess, fr);
 	
@@ -391,8 +398,7 @@
 	if ((listenfd = listenestablish(port)) == -1)
 		return NULL;
 
-	aim_request_sendfile(sess, destsn, oft_basename(filename),
-			numfiles, totsize, localip, port, ck);
+	aim_request_sendfile(sess, destsn, filename, numfiles, totsize, localip, port, ck);
 
 	cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t));
 	memcpy(cookie->cookie, ck, 8);
@@ -432,41 +438,41 @@
 /**
  * unsigned int aim_oft_listener_clean - close up old listeners
  * @sess: session to clean up in
- * @age: maximum age in seconds 
+ * @age: maximum age in seconds
  *
  * returns number closed, -1 on error.
  */
-faim_export unsigned int aim_oft_listener_clean(aim_session_t *sess,
-		time_t age) 
-{ 
-  aim_conn_t *cur;
-  time_t now;
-  unsigned int hit = 0;
-  
-  if (!sess)
-    return -1;
-  now = time(NULL);
-  for(cur = sess->connlist;cur; cur = cur->next)
-    if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { 
-      if (cur->lastactivity < (now - age) ) { 
-	aim_conn_close(cur);
-	hit++;
-      }
-    } 
-  return hit;
-} 
-#endif 
+faim_export unsigned int aim_oft_listener_clean(aim_session_t *sess, time_t age)
+{
+	aim_conn_t *cur;
+	time_t now;
+	unsigned int hit = 0;
+
+	if (!sess)
+		return -1;
+	now = time(NULL);
+
+	for(cur = sess->connlist;cur; cur = cur->next)
+		if (cur->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
+			if (cur->lastactivity < (now - age) ) {
+				aim_conn_close(cur);
+				hit++;
+			}
+		}
+	return hit;
+}
+#endif
 
 faim_export const char *aim_directim_getsn(aim_conn_t *conn)
 {
 	struct aim_directim_intdata *intdata;
 
 	if (!conn)
-	       return NULL;
+		return NULL;
 
 	if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || 
 			(conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM))
-	       return NULL;
+		return NULL;
 
 	if (!conn->internal)
 		return NULL;
@@ -525,7 +531,7 @@
 /**
  * aim_directim_getconn - find a directim conn for buddy name
  * @sess: your session,
- * @name: the name to get,  
+ * @name: the name to get,
  *
  * returns conn for directim with name, %NULL if none found. 
  *
@@ -560,7 +566,7 @@
  * @cookie: the cookie used
  * @ip: the ip to connect to
  * @port: the port to use
- * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE)  
+ * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE)
  *
  * @listingfiles: number of files to share
  * @listingtotsize: total size of shared files
@@ -571,214 +577,209 @@
  *
  * XXX this should take a struct.
  */
-faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, 
-						  aim_conn_t *conn, 
-						  const char *sn, const fu8_t *cookie, 
-						  const fu8_t *ip, 
-						  fu16_t port,
-						  fu16_t rendid,
-						  ...)
+faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn,
+						const fu8_t *cookie, const fu8_t *ip, 
+						fu16_t port, fu16_t rendid, ...)
 {
-  aim_frame_t *newpacket;
-  aim_conn_t *newconn;
-  struct aim_filetransfer_priv *priv;
-  int i;
-  char addr[21];
+	aim_frame_t *newpacket;
+	aim_conn_t *newconn;
+	struct aim_filetransfer_priv *priv;
+	int i;
+	char addr[21];
 
-  if (!sess || !conn || !sn || !cookie || !ip) {
-    return NULL;
-  }
+	if (!sess || !conn || !sn || !cookie || !ip) {
+		return NULL;
+	}
+
+	/* OSCAR CAP accept packet */
 
-  /* OSCAR CAP accept packet */
-  
+	if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
+		return NULL;
+	}
 
-  if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
-	  return NULL;
-  }
-  
-  aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
+	aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
+
+	for (i = 0; i < 8; i++)
+		aimbs_put8(&newpacket->data, cookie[i]);
 
-  for (i = 0; i < 8; i++)
-    aimbs_put8(&newpacket->data, cookie[i]);
+	aimbs_put16(&newpacket->data, 0x0002);
+	aimbs_put8(&newpacket->data, strlen(sn));
+	aimbs_putraw(&newpacket->data, sn, strlen(sn));
+	aimbs_put16(&newpacket->data, 0x0005);
+	aimbs_put16(&newpacket->data, 0x001a);
+	aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_ACCEPT);
 
-  aimbs_put16(&newpacket->data, 0x0002);
-  aimbs_put8(&newpacket->data, strlen(sn));
-  aimbs_putraw(&newpacket->data, sn, strlen(sn));
-  aimbs_put16(&newpacket->data, 0x0005);
-  aimbs_put16(&newpacket->data, 0x001a);
-  aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_ACCEPT);
+	for (i = 0; i < 8; i++) /* yes, again... */
+		aimbs_put8(&newpacket->data, cookie[i]);
 
-  for (i = 0; i < 8; i++) /* yes, again... */
-    aimbs_put8(&newpacket->data, cookie[i]);
+	aim_putcap(&newpacket->data, rendid);
+	aim_tx_enqueue(sess, newpacket);
 
-  aim_putcap(&newpacket->data, rendid);
-  aim_tx_enqueue(sess, newpacket);
+	snprintf(addr, sizeof(addr), "%s:%d", ip, port);
+	newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr);
 
+	if (newconn->status & AIM_CONN_STATUS_CONNERR) {
+		return NULL;
+	}
 
-  snprintf(addr, sizeof(addr), "%s:%d", ip, port);
-  newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr);
- 
-  if (newconn->status & AIM_CONN_STATUS_CONNERR) {
-	  return NULL;
-  }
+	if (!newconn || (newconn->fd == -1)) {
+		perror("aim_newconn");
+	faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0);
+		return newconn;
+	}
 
-  if (!newconn || (newconn->fd == -1)) {
-    perror("aim_newconn");
-    faimdprintf(sess, 2, "could not connect to %s (fd: %i)\n", ip, newconn?newconn->fd:0);
-    return newconn;
-  }
-
-  priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
+	priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv));
 
-  memcpy(priv->cookie, cookie, 8);
-  priv->state = 0;
-  strncpy(priv->sn, sn, MAXSNLEN);
-  strncpy(priv->ip, ip, sizeof(priv->ip));
-  newconn->internal = (void *)priv;
+	memcpy(priv->cookie, cookie, 8);
+	priv->state = 0;
+	strncpy(priv->sn, sn, MAXSNLEN);
+	strncpy(priv->ip, ip, sizeof(priv->ip));
+	newconn->internal = (void *)priv;
 
-  faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd);
+	faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd);
+
+	if (rendid == AIM_CAPS_GETFILE) {
+		return NULL; /* This should never happen for now. -- wtm */
 
-  if (rendid == AIM_CAPS_GETFILE) {
-    return NULL; /* This should never happen for now. -- wtm */
 #if 0
-    struct aim_fileheader_t *fh;
-    aim_frame_t *newoft;
-    aim_msgcookie_t *cachedcook;
-    /* XXX take the following parameters	  fu16_t listingfiles, 
-						  fu16_t listingtotsize, 
-						  fu16_t listingsize, 
-						  fu32_t listingchecksum,  */
+	struct aim_fileheader_t *fh;
+	aim_frame_t *newoft;
+	aim_msgcookie_t *cachedcook;
+	/* XXX take the following parameters	fu16_t listingfiles, 
+						fu16_t listingtotsize, 
+						fu16_t listingsize, 
+						fu32_t listingchecksum, */
 
-    newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
+	newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
+
+	faimdprintf(sess, 2, "faim: getfile request accept\n");
 
-      faimdprintf(sess, 2, "faim: getfile request accept\n");
-
-      if (!(newoft = aim_tx_new(sess, newconn, AIM_FRAMETYPE_OFT, 0x1108, 0))) { 
-	faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
-	/* XXX: conn leak here */
-	return NULL;
-      } 
+	if (!(newoft = aim_tx_new(sess, newconn, AIM_FRAMETYPE_OFT, 0x1108, 0))) { 
+		faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
+		/* XXX: conn leak here */
+		return NULL;
+	} 
 
-      memcpy(newoft->hdr.oft.magic, "OFT2", 4);
-      newoft->hdr.oft.hdr2len = 0x100 - 8;
+	memcpy(newoft->hdr.oft.magic, "OFT2", 4);
+	newoft->hdr.oft.hdr2len = 0x100 - 8;
 
-      if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) {
-	/* XXX: conn leak here */
-	perror("calloc");
-	return NULL;
-      }
+	if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t)))) {
+		/* XXX: conn leak here */
+		perror("calloc");
+		return NULL;
+	}
 
-      fh->encrypt = 0x0000;
-      fh->compress = 0x0000;
-      fh->totfiles = listingfiles;
-      fh->filesleft = listingfiles;      /* is this right -- total parts and parts left?*/
-      fh->totparts = 0x0001;
-      fh->partsleft = 0x0001;
-      fh->totsize = listingtotsize;
-      fh->size = listingsize;      /* ls -l listing.txt */
-      fh->modtime = (int)time(NULL); /* we'll go with current time for now */
-      fh->checksum = listingchecksum;
-      fh->rfcsum = 0x00000000;
-      fh->rfsize = 0x00000000;
-      fh->cretime = 0x00000000;
-      fh->rfcsum = 0x00000000;
-      fh->nrecvd = 0x00000000;
-      fh->recvcsum = 0x00000000;
-      memset(fh->idstring, 0, sizeof(fh->idstring));
-      strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
-      fh->flags = 0x02;
-      fh->lnameoffset = 0x1a;
-      fh->lsizeoffset = 0x10;
-      memset(fh->dummy, 0, sizeof(fh->dummy));
-      memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
+	fh->encrypt = 0x0000;
+	fh->compress = 0x0000;
+	fh->totfiles = listingfiles;
+	fh->filesleft = listingfiles; /* is this right -- total parts and parts left?*/
+	fh->totparts = 0x0001;
+	fh->partsleft = 0x0001;
+	fh->totsize = listingtotsize;
+	fh->size = listingsize; /* ls -l listing.txt */
+	fh->modtime = (int)time(NULL); /* we'll go with current time for now */
+	fh->checksum = listingchecksum;
+	fh->rfcsum = 0x00000000;
+	fh->rfsize = 0x00000000;
+	fh->cretime = 0x00000000;
+	fh->rfcsum = 0x00000000;
+	fh->nrecvd = 0x00000000;
+	fh->recvcsum = 0x00000000;
+	memset(fh->idstring, 0, sizeof(fh->idstring));
+	strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
+	fh->flags = 0x02;
+	fh->lnameoffset = 0x1a;
+	fh->lsizeoffset = 0x10;
+	memset(fh->dummy, 0, sizeof(fh->dummy));
+	memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
 
-      /* we need to figure out these encodings for filenames */
-      fh->nencode = 0x0000;
-      fh->nlanguage = 0x0000;
-      memset(fh->name, 0, sizeof(fh->name));
-      strncpy(fh->name, "listing.txt", sizeof(fh->name));
+	/* we need to figure out these encodings for filenames */
+	fh->nencode = 0x0000;
+	fh->nlanguage = 0x0000;
+	memset(fh->name, 0, sizeof(fh->name));
+	strncpy(fh->name, "listing.txt", sizeof(fh->name));
 
-      if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 
-	aim_frame_destroy(newoft);
-	/* XXX: conn leak */
-	perror("calloc (1)");
-	return NULL;
-      } 
+	if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
+		aim_frame_destroy(newoft);
+		/* XXX: conn leak */
+		perror("calloc (1)");
+		return NULL;
+	}
 
-      memcpy(fh->bcookie, cookie, 8);
+	memcpy(fh->bcookie, cookie, 8);
 
-      if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh)))
-	faimdprintf(sess, 1, "eek, bh fail!\n");
+	if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh)))
+		faimdprintf(sess, 1, "eek, bh fail!\n");
+
+	aim_tx_enqueue(sess, newoft);
 
-      aim_tx_enqueue(sess, newoft);
-   
-      if (!(cachedcook = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)))) { 
-	faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n");
-	/* XXX: more cleanup, conn leak */
-	perror("calloc (2)");
-	return NULL;
-      }
+	if (!(cachedcook = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)))) { 
+		faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n");
+		/* XXX: more cleanup, conn leak */
+		perror("calloc (2)");
+		return NULL;
+	}
+
+	memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t));
+	memcpy(cachedcook->cookie, cookie, 8);
 
-      memcpy(&(priv->fh), fh, sizeof(struct aim_fileheader_t));
-      memcpy(cachedcook->cookie, cookie, 8);
+	cachedcook->type = AIM_COOKIETYPE_OFTGET;
+	/* XXX doesn't priv need to be copied so we don't
+	 * double free? -- wtm
+	 */
+	cachedcook->data = (void *)priv;
 
-      cachedcook->type = AIM_COOKIETYPE_OFTGET;
-      /* XXX doesn't priv need to be copied so we don't
-       * double free? -- wtm
-       */
-      cachedcook->data = (void *)priv;
+	if (aim_cachecookie(sess, cachedcook) == -1)
+		faimdprintf(sess, 1, "faim: ERROR caching message cookie\n");
 
-      if (aim_cachecookie(sess, cachedcook) == -1)
-	faimdprintf(sess, 1, "faim: ERROR caching message cookie\n");
-
-      free(fh);     
+	free(fh);
 #endif
 
-  } else if (rendid == AIM_CAPS_SENDFILE)  {
-      newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
-      priv->fh.recvcsum = 0xffff0000;
-  } else {
-    return NULL;
-  }
+	} else if (rendid == AIM_CAPS_SENDFILE) {
+		newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
+		priv->fh.recvcsum = 0xffff0000;
+	} else {
+		return NULL;
+	}
 
-  return newconn;
+	return newconn;
 }
 
 /* conn is a BOS connection over which to send the cancel msg */
 faim_export int aim_canceltransfer(aim_session_t *sess, aim_conn_t *conn,
 		const char *cookie, const char *sn, int rendid)
 {
-  aim_frame_t *newpacket;
-  int i;
+	aim_frame_t *newpacket;
+	int i;
 
-  if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
-	  return 1;
-  }
-  
-  aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
+	if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) {
+		return 1;
+	}
 
-  for (i = 0; i < 8; i++)
-    aimbs_put8(&newpacket->data, cookie[i]);
+	aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next);
+
+	for (i = 0; i < 8; i++)
+		aimbs_put8(&newpacket->data, cookie[i]);
 
-  aimbs_put16(&newpacket->data, 0x0002);
-  aimbs_put8(&newpacket->data, strlen(sn));
-  aimbs_putraw(&newpacket->data, sn, strlen(sn));
-  aimbs_put16(&newpacket->data, 0x0005);
-  aimbs_put16(&newpacket->data, 0x001a);
-  aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_CANCEL);
+	aimbs_put16(&newpacket->data, 0x0002);
+	aimbs_put8(&newpacket->data, strlen(sn));
+	aimbs_putraw(&newpacket->data, sn, strlen(sn));
+	aimbs_put16(&newpacket->data, 0x0005);
+	aimbs_put16(&newpacket->data, 0x001a);
+	aimbs_put16(&newpacket->data, AIM_RENDEZVOUS_CANCEL);
 
-  for (i = 0; i < 8; i++) 
-    aimbs_put8(&newpacket->data, cookie[i]);
- 
-  aim_putcap(&newpacket->data, rendid);
-  aim_tx_enqueue(sess, newpacket);
+	for (i = 0; i < 8; i++)
+		aimbs_put8(&newpacket->data, cookie[i]);
 
-  return 0;
+	aim_putcap(&newpacket->data, rendid);
+	aim_tx_enqueue(sess, newpacket);
+
+	return 0;
 }
 
 /**
  * aim_getlisting(FILE *file) -- get an aim_fileheader_t for a given FILE*
- *  @file is an opened listing file
+ * @file is an opened listing file
  * 
  * returns a pointer to the filled-in fileheader_t
  *
@@ -790,115 +791,115 @@
 {
 	return NULL;
 #if 0
-  struct aim_fileheader_t *fh;
-  u_long totsize = 0, size = 0, checksum = 0xffff0000;
-  short totfiles = 0;
-  char *linebuf, sizebuf[9];
-  
-  int linelength = 1024;
+	struct aim_fileheader_t *fh;
+	u_long totsize = 0, size = 0, checksum = 0xffff0000;
+	short totfiles = 0;
+	char *linebuf, sizebuf[9];
+	int linelength = 1024;
 
-  /* XXX: if we have a line longer than 1024chars, God help us. */
-  if ( (linebuf = (char *)calloc(1, linelength)) == NULL ) {
-    faimdprintf(sess, 2, "linebuf calloc failed\n");
-    return NULL;
-  }  
+	/* XXX: if we have a line longer than 1024chars, God help us. */
+	if ((linebuf = (char *)calloc(1, linelength)) == NULL ) {
+		faimdprintf(sess, 2, "linebuf calloc failed\n");
+		return NULL;
+	}
 
-  if (fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */
-    perror("getlisting END1 fseek:");
-    faimdprintf(sess, 2, "getlising fseek END1 error\n");
-  }
+	if (fseek(file, 0, SEEK_END) == -1) { /* use this for sanity check */
+		perror("getlisting END1 fseek:");
+		faimdprintf(sess, 2, "getlising fseek END1 error\n");
+	}
 
-  if ((size = ftell(file)) == -1) {
-    perror("getlisting END1 getpos:");
-    faimdprintf(sess, 2, "getlising getpos END1 error\n");
-  }
+	if ((size = ftell(file)) == -1) {
+		perror("getlisting END1 getpos:");
+		faimdprintf(sess, 2, "getlising getpos END1 error\n");
+	}
 
-  if (fseek(file, 0, SEEK_SET) != 0) {
-    perror("getlesting fseek(SET):");
-    faimdprintf(sess, 2, "faim: getlisting: couldn't seek to beginning of listing file\n");
-  }
+	if (fseek(file, 0, SEEK_SET) != 0) {
+		perror("getlesting fseek(SET):");
+		faimdprintf(sess, 2, "faim: getlisting: couldn't seek to beginning of listing file\n");
+	}
+
+	memset(linebuf, 0, linelength);
 
-  memset(linebuf, 0, linelength);
-
-  size = 0;
+	size = 0;
 
-  while(fgets(linebuf,  linelength, file)) {
-    totfiles++;
-    memset(sizebuf, 0, 9);
+	while(fgets(linebuf, linelength, file)) {
+		totfiles++;
+		memset(sizebuf, 0, 9);
+
+		size += strlen(linebuf);
 
-    size += strlen(linebuf);
-    
-    if (strlen(linebuf) < 23) {
-      faimdprintf(sess, 2, "line \"%s\" too short. skipping\n", linebuf);
-      continue;
-    }
-    if (linebuf[strlen(linebuf)-1] != '\n') {
-      faimdprintf(sess, 2, "faim: OFT: getlisting -- hit EOF or line too long!\n");
-    }
+		if (strlen(linebuf) < 23) {
+			faimdprintf(sess, 2, "line \"%s\" too short. skipping\n", linebuf);
+			continue;
+		}
 
-    memcpy(sizebuf, linebuf+17, 8);
+		if (linebuf[strlen(linebuf)-1] != '\n') {
+			faimdprintf(sess, 2, "faim: OFT: getlisting -- hit EOF or line too long!\n");
+		}
 
-    totsize += strtol(sizebuf, NULL, 10);
-    memset(linebuf, 0, linelength);
-  }   
+		memcpy(sizebuf, linebuf+17, 8);
+
+		totsize += strtol(sizebuf, NULL, 10);
+		memset(linebuf, 0, linelength);
+	}
 
-  if (fseek(file, 0, SEEK_SET) == -1) {
-    perror("getlisting END2 fseek:");
-    faimdprintf(sess, 2, "getlising fseek END2 error\n");
-  }  
+	if (fseek(file, 0, SEEK_SET) == -1) {
+		perror("getlisting END2 fseek:");
+		faimdprintf(sess, 2, "getlising fseek END2 error\n");
+	}
 
-  free(linebuf);
+	free(linebuf);
 
-  /* we're going to ignore checksumming the data for now -- that
-   * requires walking the whole listing.txt. it should probably be
-   * done at register time and cached, but, eh. */  
+	/* we're going to ignore checksumming the data for now -- that
+	 * requires walking the whole listing.txt. it should probably be
+	 * done at register time and cached, but, eh. */
 
-  if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
-    return NULL;
+	if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
+		return NULL;
 
-  fh->encrypt     = 0x0000;
-  fh->compress    = 0x0000; 
-  fh->totfiles    = totfiles;
-  fh->filesleft   = totfiles; /* is this right ?*/
-  fh->totparts    = 0x0001;
-  fh->partsleft   = 0x0001;
-  fh->totsize     = totsize;
-  fh->size        = size; /* ls -l listing.txt */
-  fh->modtime     = (int)time(NULL); /* we'll go with current time for now */
-  fh->checksum    = checksum; /* XXX: checksum ! */
-  fh->rfcsum      = 0x00000000;
-  fh->rfsize      = 0x00000000;
-  fh->cretime     = 0x00000000;
-  fh->rfcsum      = 0x00000000;
-  fh->nrecvd      = 0x00000000;
-  fh->recvcsum    = 0x00000000;
+	fh->encrypt = 0x0000;
+	fh->compress = 0x0000;
+	fh->totfiles = totfiles;
+	fh->filesleft = totfiles; /* is this right? */
+	fh->totparts = 0x0001;
+	fh->partsleft = 0x0001;
+	fh->totsize = totsize;
+	fh->size = size; /* ls -l listing.txt */
+	fh->modtime = (int)time(NULL); /* we'll go with current time for now */
+	fh->checksum = checksum; /* XXX: checksum ! */
+	fh->rfcsum = 0x00000000;
+	fh->rfsize = 0x00000000;
+	fh->cretime = 0x00000000;
+	fh->rfcsum = 0x00000000;
+	fh->nrecvd = 0x00000000;
+	fh->recvcsum = 0x00000000;
 
-  /*  memset(fh->idstring, 0, sizeof(fh->idstring)); */
-  memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
-  memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring));
+	/* memset(fh->idstring, 0, sizeof(fh->idstring)); */
+	memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
+	memset(fh->idstring+strlen(fh->idstring), 0, sizeof(fh->idstring)-strlen(fh->idstring));
 
-  fh->flags       = 0x02;
-  fh->lnameoffset = 0x1a;
-  fh->lsizeoffset = 0x10;
+	fh->flags = 0x02;
+	fh->lnameoffset = 0x1a;
+	fh->lsizeoffset = 0x10;
 
-  /*  memset(fh->dummy, 0, sizeof(fh->dummy)); */
-  memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
+	/* memset(fh->dummy, 0, sizeof(fh->dummy)); */
+	memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
 
-  fh->nencode     = 0x0000; /* we need to figure out these encodings for filenames */
-  fh->nlanguage   = 0x0000;
+	fh->nencode = 0x0000; /* we need to figure out these encodings for filenames */
+	fh->nlanguage = 0x0000;
 
-  /*  memset(fh->name, 0, sizeof(fh->name)); */
-  strncpy(fh->name, "listing.txt", sizeof(fh->name));
-  memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name));
+	/* memset(fh->name, 0, sizeof(fh->name)); */
+	strncpy(fh->name, "listing.txt", sizeof(fh->name));
+	memset(fh->name+strlen(fh->name), 0, 64-strlen(fh->name));
 
-  faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name))));
-  return fh;
+	faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name))));
+	return fh;
 #endif
 }
 
 /**
  * aim_listenestablish - create a listening socket on a port.
- * @portnum: the port number to bind to.  
+ * @portnum: the port number to bind to.
  *
  * you need to call accept() when it's connected. returns your fd 
  *
@@ -925,7 +926,7 @@
 	} 
 	ressave = res;
 	do { 
-		listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);    
+		listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
 		if (listenfd < 0)
 			continue;
 		setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
@@ -1146,39 +1147,47 @@
 	return;
 }
 
-static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
+static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
 {
 	aim_frame_t fr;
 	aim_rxcallback_t userfunc;
 	fu32_t payloadlength;
-	fu16_t flags;
+	fu16_t flags, encoding;
 	char *snptr = NULL;
 
 	fr.conn = conn;
 
-	payloadlength = aimutil_get32(hdr+22);
-	flags = aimutil_get16(hdr+32);
-	snptr = (char *)hdr+38;
+	/* XXX ugly */
+	aim_bstream_setpos(bs, 20);
+	payloadlength = aimbs_get32(bs);
+
+	aim_bstream_setpos(bs, 24);
+	encoding = aimbs_get16(bs);
+
+	aim_bstream_setpos(bs, 30);
+	flags = aimbs_get16(bs);
+
+	aim_bstream_setpos(bs, 36);
+	/* XXX -create an aimbs_getnullstr function? */
+	snptr = aimbs_getstr(bs, MAXSNLEN);
 
 	faimdprintf(sess, 2, "faim: OFT frame: handlehdr_directim: %04x / %04x / %s\n", payloadlength, flags, snptr);
 
-	if (flags == 0x000e) { 
+	if (flags & 0x0002) {
 		int ret = 0;
 
-		if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
-			ret = userfunc(sess, &fr, snptr, 1);
+		if (flags == 0x000c) {
+			if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
+				ret = userfunc(sess, &fr, snptr, 1);
+			return ret;
+		}
 
-		return ret;
-	
-	} else if (flags == 0x0002) {
-		int ret = 0;
-		
 		if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)))
 			ret = userfunc(sess, &fr, snptr, 0);
 
 		return ret;
 
-	} else if ((flags == 0x0000) && payloadlength) { 
+	} else if (((flags & 0x000f) == 0x0000) && payloadlength) {
 		char *msg, *msg2;
 		int ret = 0;
 		int recvd = 0;
@@ -1204,7 +1213,7 @@
 		}
 		
 		if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) )
-			ret = userfunc(sess, &fr, snptr, msg, payloadlength);
+			ret = userfunc(sess, &fr, snptr, msg, payloadlength, encoding);
 
 		free(msg);
 
@@ -1244,7 +1253,7 @@
 	if(aim_cachecookie(sess, cook) == -1) {
 		faimdprintf(sess, 1, "error caching cookie\n");
 		return -1;
-	}     
+	}
 
 	if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x1209, 0))) {
 		aim_conn_close(conn);
@@ -1284,7 +1293,7 @@
 	fh = aim_oft_getfh(hdr);
 
 	if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET)))
-		faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n",  AIM_COOKIETYPE_OFTGET, fh->bcookie);
+		faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", AIM_COOKIETYPE_OFTGET, fh->bcookie);
 
 	ft = cook->data;
 
@@ -1453,14 +1462,14 @@
  * it.  We send back a similar header to confirm, then we're ready to
  * start reading the raw data.
  */
-static int handlehdr_sendfile_sending(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
+static int handlehdr_sendfile_sending(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
 {
 	struct aim_filetransfer_priv *ft;
 	struct aim_fileheader_t *fh;
 	aim_frame_t *newoft;
 	aim_rxcallback_t userfunc;
 
-	fh = aim_oft_getfh(hdr);
+	fh = aim_oft_getfh(bs);
 
 	/* We receive a null cookie for the first file; we must fill
 	 * it in to authenticate ourselves. -- wtm
@@ -1476,22 +1485,24 @@
 		return -1;
 	}
 
-	memcpy(newoft->hdr.oft.magic, "OFT2", 4);
-
-	newoft->hdr.oft.hdr2len = 0x100 - 8;
-
-	if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) {
-		aim_frame_destroy(newoft);
+	if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
 		return -1;
 	}
-
-	if (!aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2,
-				&(ft->fh))) {
-		return -1;
-	}
+	memcpy(newoft->hdr.rend.magic, "OFT2", 4);
+	newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
 
 	aim_tx_enqueue(sess, newoft);
 
+	/*
+	 * Throw away the resource fork, in case we are receiving from a Mac.
+	 */
+	if (ft->fh.rfsize) {
+		char *buf = malloc(ft->fh.rfsize);
+		if (!buf)
+			return -1;
+		aim_recv(conn->fd, buf, ft->fh.rfsize);
+	}
+
 	if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEFILEREQ)) == NULL)
 		return 1;
 
@@ -1511,60 +1522,56 @@
 /* 
  * These were originally described by Josh Myer:
  * http://www.geocrawler.com/archives/3/896/2000/9/0/4291064/
+ * XXX this doesn't actualy work yet
  * -- wtm
  */
-static int handlehdr_sendfile_resume(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) {
-  aim_frame_t *newoft;
-  aim_msgcookie_t *cook;
-  struct aim_fileheader_t *fh;
-  struct aim_filetransfer_priv *ft;
-	
-  fh = aim_oft_getfh(hdr);
-  if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
-	  free(fh);
-	  return -1;
-  }
-  ft = (struct aim_filetransfer_priv *)cook->data;
+static int handlehdr_sendfile_resume(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) {
+	aim_frame_t *newoft;
+	aim_msgcookie_t *cook;
+	struct aim_fileheader_t *fh;
+	struct aim_filetransfer_priv *ft;
+
+	fh = aim_oft_getfh(bs);
+	if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
+		free(fh);
+		return -1;
+	}
+	ft = (struct aim_filetransfer_priv *)cook->data;
 
-  ft->fh.nrecvd = fh->nrecvd;
-  ft->fh.recvcsum = fh->recvcsum;
-  strncpy(ft->fh.name, fh->name, sizeof(ft->fh.name));
-  if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0106, 0))) {
-    faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
-    free(fh);
-    return -1;
-  }
-  memcpy(newoft->hdr.oft.magic, "OFT2", 4);
-  newoft->hdr.oft.hdr2len = 0x100 - 8;
+	ft->fh.nrecvd = fh->nrecvd;
+	ft->fh.recvcsum = fh->recvcsum;
+	strncpy(ft->fh.name, fh->name, sizeof(ft->fh.name));
+	if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0106, 0))) {
+		faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
+		free(fh);
+		return -1;
+	}
 
-  if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) {
-    aim_frame_destroy(newoft);
-    return -1;
-  }
+	if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
+		aim_frame_destroy(newoft);
+		free(fh);
+		return -1;
+	}
+	memcpy(newoft->hdr.rend.magic, "OFT2", 4);
+	newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
 
-  if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) {
-    aim_frame_destroy(newoft);
-    free(fh);
-    return -1;
-  }
+	aim_tx_enqueue(sess, newoft);
+	free(fh);
 
-  aim_tx_enqueue(sess, newoft);
-  free(fh);
-
-  return 0;
+	return 0;
 }
 
 /* We are sending a file, and the buddy sent us this header indicating
  * that he or she is ready for the raw data.
  */
-static int handlehdr_sendfile_recv(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) {
+static int handlehdr_sendfile_recv(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs) {
 	struct aim_fileheader_t *fh;
 	aim_msgcookie_t *cook;
 	int ret = 1;
 	struct aim_filetransfer_priv *ft;
 	aim_rxcallback_t userfunc;
 	
-	fh = aim_oft_getfh(hdr);
+	fh = aim_oft_getfh(bs);
 	if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
 		free(fh);
 		return -1;
@@ -1613,14 +1620,14 @@
 /* We just sent the raw data of a file, and the buddy sent us back this
  * header indicating that the transfer is complete.
  */
-static int handlehdr_sendfile_finish(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr)
+static int handlehdr_sendfile_finish(aim_session_t *sess, aim_conn_t *conn, aim_bstream_t *bs)
 {
 	struct aim_fileheader_t *fh;
 	aim_msgcookie_t *cook;
 	aim_rxcallback_t userfunc;
 
-	fh = aim_oft_getfh(hdr);
-  
+	fh = aim_oft_getfh(bs);
+
 	if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTSEND))) {
 		free(fh);
 		return -1;
@@ -1652,107 +1659,67 @@
 	return -1;
 }
 
-/**
- * aim_get_command_rendezvous - OFT equivalent of aim_get_command
- * @sess: session to work on
- * @conn: conn to pull data from 
- *
- * this reads and handles data from conn->fd. currently a little rough
- * around the edges
- */
-faim_internal int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn)
+faim_internal int aim_rxdispatch_rendezvous(aim_session_t *sess, aim_frame_t *fr)
 {
-	fu8_t hdrbuf1[6];
-	fu8_t *hdr = NULL;
-	int hdrlen, hdrtype;
+	aim_conn_t *conn = fr->conn;
+	aim_bstream_t *bs = &fr->data;
 	int ret = -1;
 
-
 	if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
 		/* This should never happen. -- wtm */
 		return getcommand_getfile(sess, conn);
-	}
 
-	memset(hdrbuf1, 0, sizeof(hdrbuf1));
-
-	if (aim_recv(conn->fd, hdrbuf1, 6) < 6) {
-		faimdprintf(sess, 2, "faim: rend: read error (fd: %i)\n", conn->fd);
-		aim_conn_close(conn);
-		return -1;
-	}
-
-	hdrlen = aimutil_get16(hdrbuf1+4);
-	hdrlen -= 6;
-
-	hdr = malloc(hdrlen);
-	if (!hdr) {
-		aim_conn_close(conn);
-		return -1;
-	}
-
-	if (aim_recv(conn->fd, hdr, hdrlen) < hdrlen) {
-		faimdprintf(sess, 2, "faim: rend: read2 error on %d (%d)\n", conn->fd, hdrlen);
-		free(hdr);
-		aim_conn_close(conn);
-		return -1;
-	}
-
-	hdrtype = aimutil_get16(hdr);
-
-	if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
-		switch(hdrtype) {
+	} else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) {
+		switch(fr->hdr.rend.type) {
 			case AIM_OFT_PROTO_OFFER:
-				ret = handlehdr_sendfile_sending(sess, conn,
-						hdr);
+				ret = handlehdr_sendfile_sending(sess, conn, bs);
 				break;
 			case AIM_OFT_PROTO_RESUME:
-				ret = handlehdr_sendfile_resume(sess,
-						conn, hdr);
+				ret = handlehdr_sendfile_resume(sess, conn, bs);
 				break;
 			case AIM_OFT_PROTO_RESUMEACCEPT: /* like _ACCEPT */;
 			case AIM_OFT_PROTO_ACCEPT:
-				ret = handlehdr_sendfile_recv(sess, conn, hdr);
+				ret = handlehdr_sendfile_recv(sess, conn, bs);
 				break;
 			case AIM_OFT_PROTO_ACK:
-				ret = handlehdr_sendfile_finish(sess, conn, hdr);
+				ret = handlehdr_sendfile_finish(sess, conn, bs);
 				break;
 			default:
-				faimdprintf(sess, 2, "faim: OFT frame: uknown type %04x\n", hdrtype);
+				faimdprintf(sess, 2, "faim: OFT frame: uknown type %04x\n", fr->hdr.rend.type);
 				ret = -1;
 				break;
 		}
-		free(hdr);
-		if (ret == -1)
-			aim_conn_close(conn);
-		return ret;
-	}
 
-	if (hdrtype == 0x0001)
-		ret = handlehdr_directim(sess, conn, hdr);
-
-	/* This _really_ shouldn't happen. :) -- wtm */
+	} else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
+		if (fr->hdr.rend.type == 0x0001)
+			ret = handlehdr_directim(sess, conn, bs);
+		else
+			faimdprintf(sess, 0, "faim: DIM frame: unknown type %04x\n", fr->hdr.rend.type);
 
-	else if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */
-		ret = handlehdr_getfile_listing(sess, conn, hdr);
-	else if (hdrtype == 0x1209) /* get file listing ack rx->tx */
-		ret = handlehdr_getfile_listing2(sess, conn, hdr);
-	else if (hdrtype == 0x120b) /* get file listing rx confirm */
-		ret = handlehdr_getfile_listing3(sess, conn, hdr);
-	else if (hdrtype == 0x120c) /* getfile request */
-		ret = handlehdr_getfile_request(sess, conn, hdr);
-	else if (hdrtype == 0x0101) /* getfile sending data */
-		ret = handlehdr_getfile_sending(sess, conn, hdr);
-	else if (hdrtype == 0x0202) /* getfile recv data */
-		ret = handlehdr_getfile_recv(sess, conn, hdr);
-	else if (hdrtype == 0x0204) /* getfile finished */
-		ret = handlehdr_getfile_finish(sess, conn, hdr);
-	else {
-		faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype);
-		ret = -1;
+	} else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) {
+		/* This _really_ shouldn't happen. :) -- wtm */
+		char *hdr = NULL;
+		int hdrtype = fr->hdr.rend.type;
+		if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */
+			ret = handlehdr_getfile_listing(sess, conn, hdr);
+		else if (hdrtype == 0x1209) /* get file listing ack rx->tx */
+			ret = handlehdr_getfile_listing2(sess, conn, hdr);
+		else if (hdrtype == 0x120b) /* get file listing rx confirm */
+			ret = handlehdr_getfile_listing3(sess, conn, hdr);
+		else if (hdrtype == 0x120c) /* getfile request */
+			ret = handlehdr_getfile_request(sess, conn, hdr);
+		else if (hdrtype == 0x0101) /* getfile sending data */
+			ret = handlehdr_getfile_sending(sess, conn, hdr);
+		else if (hdrtype == 0x0202) /* getfile recv data */
+			ret = handlehdr_getfile_recv(sess, conn, hdr);
+		else if (hdrtype == 0x0204) /* getfile finished */
+			ret = handlehdr_getfile_finish(sess, conn, hdr);
+		else {
+			faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype);
+			ret = -1;
+		}
 	}
 	
-	free(hdr);
-
 	if (ret == -1)
 		aim_conn_close(conn);
 
@@ -1761,73 +1728,47 @@
 
 /**
  * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr.
- * @hdr: buffer to extract header from  
+ * @bs: bstream to extract header from
  *
- * returns pointer to new struct on success; %NULL on error.  
+ * returns pointer to new struct on success; %NULL on error.
  *
  */
-static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr) 
+static struct aim_fileheader_t *aim_oft_getfh(aim_bstream_t *bs)
 {
-  struct aim_fileheader_t *fh;
-  int i, j;
-  if (!(fh = calloc(1, sizeof(struct aim_fileheader_t))))
-    return NULL;
-  
-  /* [0] and [1] are the type. we can ignore those here. */
-  i = 2;
-  for(j = 0; j < 8; j++, i++)
-    fh->bcookie[j] = hdr[i];
-  fh->encrypt = aimutil_get16(hdr+i);
-  i += 2;
-  fh->compress = aimutil_get16(hdr+i);
-  i += 2;
-  fh->totfiles = aimutil_get16(hdr+i);
-  i += 2;
-  fh->filesleft = aimutil_get16(hdr+i);
-  i += 2;
-  fh->totparts = aimutil_get16(hdr+i);
-  i += 2;
-  fh->partsleft = aimutil_get16(hdr+i);
-  i += 2;
-  fh->totsize = aimutil_get32(hdr+i);
-  i += 4;
-  fh->size = aimutil_get32(hdr+i);
-  i += 4;
-  fh->modtime = aimutil_get32(hdr+i);
-  i += 4;
-  fh->checksum = aimutil_get32(hdr+i);
-  i += 4;
-  fh->rfrcsum = aimutil_get32(hdr+i);
-  i += 4;
-  fh->rfsize = aimutil_get32(hdr+i);
-  i += 4;
-  fh->cretime = aimutil_get32(hdr+i);
-  i += 4;
-  fh->rfcsum = aimutil_get32(hdr+i);
-  i += 4;
-  fh->nrecvd = aimutil_get32(hdr+i);
-  i += 4;
-  fh->recvcsum = aimutil_get32(hdr+i);
-  i += 4;
-  memcpy(fh->idstring, hdr+i, 32);
-  i += 32;
-  fh->flags = aimutil_get8(hdr+i);
-  i += 1;
-  fh->lnameoffset = aimutil_get8(hdr+i);
-  i += 1;
-  fh->lsizeoffset = aimutil_get8(hdr+i);
-  i += 1;
-  memcpy(fh->dummy, hdr+i, 69);
-  i += 69;
-  memcpy(fh->macfileinfo, hdr+i, 16);
-  i += 16;
-  fh->nencode = aimutil_get16(hdr+i);
-  i += 2;
-  fh->nlanguage = aimutil_get16(hdr+i);
-  i += 2;
-  memcpy(fh->name, hdr+i, 64);
-  i += 64;
-  return fh;
+	struct aim_fileheader_t *fh;
+
+	if (!(fh = calloc(1, sizeof(struct aim_fileheader_t))))
+		return NULL;
+
+	/* 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_get16(bs);
+	fh->rfcsum = aimbs_get16(bs);
+	fh->nrecvd = aimbs_get16(bs);
+	fh->recvcsum = aimbs_get16(bs);
+	aimbs_getrawbuf(bs, fh->idstring, 32);
+	fh->flags = aimbs_get8(bs);
+	fh->lnameoffset = aimbs_get8(bs);
+	fh->lsizeoffset = aimbs_get8(bs);
+	aimbs_getrawbuf(bs, fh->dummy, 69);
+	aimbs_getrawbuf(bs, fh->macfileinfo, 16);
+	fh->nencode = aimbs_get16(bs);
+	fh->nlanguage = aimbs_get16(bs);
+	aimbs_getrawbuf(bs, fh->name, 64); /* XXX */
+
+	return fh;
 } 
 
 /**
@@ -1844,33 +1785,33 @@
  *
  * Thanks to Graham Booker for providing this improved checksum
  * routine, which is simpler and should be more accurate than Josh
- * Meyer's original code. -- wtm
+ * Myer's original code. -- wtm
  *
  * This algorithim 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.
  */
 faim_export fu32_t aim_oft_checksum(const unsigned char *buffer, int bufferlen, int prevcheck) {
-    fu32_t 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 follownig 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;
+	fu32_t 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 follownig 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;
 }
 
 faim_export fu32_t aim_update_checksum(aim_session_t *sess, aim_conn_t *conn,
@@ -1885,54 +1826,56 @@
 
 /**
  * aim_oft_buildheader - fills a buffer with network-order fh data
- * @dest: buffer to fill -- pre-alloced
- * @fh: fh to get data from  
+ * @bs: bstream to fill -- automatically initialized
+ * @fh: fh to get data from
  *
- * returns length written; -1 on error.
- * DOES NOT DO BOUNDS CHECKING!
+ * returns -1 on error.
  *
  */
-faim_export int aim_oft_buildheader(unsigned char *dest, struct aim_fileheader_t *fh) 
+static int aim_oft_buildheader(aim_bstream_t *bs, struct aim_fileheader_t *fh)
 { 
-  int i, curbyte;
-  if (!dest || !fh)
-    return -1;
-  curbyte = 0;
-  for(i = 0; i < 8; i++) 
-    curbyte += aimutil_put8(dest+curbyte, fh->bcookie[i]);
-  curbyte += aimutil_put16(dest+curbyte, fh->encrypt);
-  curbyte += aimutil_put16(dest+curbyte, fh->compress);
-  curbyte += aimutil_put16(dest+curbyte, fh->totfiles);
-  curbyte += aimutil_put16(dest+curbyte, fh->filesleft);
-  curbyte += aimutil_put16(dest+curbyte, fh->totparts);
-  curbyte += aimutil_put16(dest+curbyte, fh->partsleft);
-  curbyte += aimutil_put32(dest+curbyte, fh->totsize);
-  curbyte += aimutil_put32(dest+curbyte, fh->size);
-  curbyte += aimutil_put32(dest+curbyte, fh->modtime);
-  curbyte += aimutil_put32(dest+curbyte, fh->checksum);
-  curbyte += aimutil_put32(dest+curbyte, fh->rfrcsum);
-  curbyte += aimutil_put32(dest+curbyte, fh->rfsize);
-  curbyte += aimutil_put32(dest+curbyte, fh->cretime);
-  curbyte += aimutil_put32(dest+curbyte, fh->rfcsum);
-  curbyte += aimutil_put32(dest+curbyte, fh->nrecvd);
-  curbyte += aimutil_put32(dest+curbyte, fh->recvcsum);
-  memcpy(dest+curbyte, fh->idstring, 32);
-  curbyte += 32;
-  curbyte += aimutil_put8(dest+curbyte, fh->flags);
-  curbyte += aimutil_put8(dest+curbyte, fh->lnameoffset);
-  curbyte += aimutil_put8(dest+curbyte, fh->lsizeoffset);
-  memcpy(dest+curbyte, fh->dummy, 69);
-  curbyte += 69;
-  memcpy(dest+curbyte, fh->macfileinfo, 16);
-  curbyte += 16;
-  curbyte += aimutil_put16(dest+curbyte, fh->nencode);
-  curbyte += aimutil_put16(dest+curbyte, fh->nlanguage);
-  memset(dest+curbyte, 0x00, 64);
-  memcpy(dest+curbyte, fh->name, 64);
+	fu8_t *hdr;
+
+	if (!bs || !fh)
+		return -1;
+
+
+
+
+	if (!(hdr = (unsigned char *)calloc(1, 0x100 - 8))) {
+		return -1;
+	}
+	aim_bstream_init(bs, hdr, 0x100 - 8);
 
-  /* XXX: Filenames longer than 64B  */
-  curbyte += 64;
-  return curbyte;
+	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, fh->idstring, 32);
+	aimbs_put8(bs, fh->flags);
+	aimbs_put8(bs, fh->lnameoffset);
+	aimbs_put8(bs, fh->lsizeoffset);
+	aimbs_putraw(bs, fh->dummy, 69);
+	aimbs_putraw(bs, fh->macfileinfo, 16);
+	aimbs_put16(bs, fh->nencode);
+	aimbs_put16(bs, fh->nlanguage);
+	aimbs_putraw(bs, fh->name, 64);
+
+	/* XXX: Filenames longer than 64B */
+	return 0;
 }
 
 /**
@@ -1947,143 +1890,143 @@
 { 
 	return NULL;
 #if 0
-  struct command_tx_struct *newpacket;
-  struct aim_conn_t *newconn;
-  struct aim_filetransfer_priv *priv;
-  struct aim_msgcookie_t *cookie;
-  int curbyte, i, listenfd;
-  short port = 4443;
-  struct hostent *hptr;
-  struct utsname myname;
-  char cap[16];
-  char d[4];
- 
-  /* Open our socket */
+	struct command_tx_struct *newpacket;
+	struct aim_conn_t *newconn;
+	struct aim_filetransfer_priv *priv;
+	struct aim_msgcookie_t *cookie;
+	int curbyte, i, listenfd;
+	short port = 4443;
+	struct hostent *hptr;
+	struct utsname myname;
+	char cap[16];
+	char d[4];
 
-  if ( (listenfd = aim_listenestablish(port)) == -1)
-    return NULL;
+	/* Open our socket */
+
+	if ( (listenfd = aim_listenestablish(port)) == -1)
+		return NULL;
 
-  /* get our local IP */
+	/* get our local IP */
 
-  if (uname(&myname) < 0)
-    return NULL;
-  if ( (hptr = gethostbyname(myname.nodename)) == NULL)
-    return NULL;
-  memcpy(&d, hptr->h_addr_list[0], 4);
+	if (uname(&myname) < 0)
+		return NULL;
+	if ( (hptr = gethostbyname(myname.nodename)) == NULL)
+		return NULL;
+	memcpy(&d, hptr->h_addr_list[0], 4);
 
-  aim_putcap(cap, 16, AIM_CAPS_GETFILE);
+	aim_putcap(cap, 16, AIM_CAPS_GETFILE);
 
-  /* create the OSCAR packet */
+	/* create the OSCAR packet */
 
-  if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x42)))
-    return NULL;
-  newpacket->lock = 1;
+	if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x42)))
+		return NULL;
+	newpacket->lock = 1;
 
-  /* lock struct */
-  curbyte = 0;
-  curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
+	/* lock struct */
+	curbyte = 0;
+	curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
 
-  /* XXX: check the cookie before commiting to using it */
+	/* XXX: check the cookie before commiting to using it */
 
-  /* Generate a random message cookie
-   * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */
-  for (i=0; i<7; i++) 
-    curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10));
+	/* Generate a random message cookie
+	 * This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */
+	for (i=0; i<7; i++) 
+		curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) random() % 10));
 
-  curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
+	curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
 
-  /* grab all the data for cookie caching. */
+	/* grab all the data for cookie caching. */
  
-  if (!(cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t))))
-    return NULL;
-  memcpy(cookie->cookie, newpacket->data+curbyte-8, 8);
-  cookie->type = AIM_COOKIETYPE_OFTGET;
+	if (!(cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t))))
+		return NULL;
+	memcpy(cookie->cookie, newpacket->data+curbyte-8, 8);
+	cookie->type = AIM_COOKIETYPE_OFTGET;
 
-  if (!(priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv))))
-    return NULL;
-  memcpy(priv->cookie, cookie, 8);
-  memcpy(priv->sn, destsn, sizeof(priv->sn));
-  memcpy(priv->fh.name, "listing.txt", strlen("listing.txt"));
-  priv->state = 1;
+	if (!(priv = (struct aim_filetransfer_priv *)calloc(1, sizeof(struct aim_filetransfer_priv))))
+		return NULL;
+	memcpy(priv->cookie, cookie, 8);
+	memcpy(priv->sn, destsn, sizeof(priv->sn));
+	memcpy(priv->fh.name, "listing.txt", strlen("listing.txt"));
+	priv->state = 1;
 
-  cookie->data = priv;
+	cookie->data = priv;
 
-  aim_cachecookie(sess, cookie);
+	aim_cachecookie(sess, cookie);
 
-  /* Channel ID */
-  curbyte += aimutil_put16(newpacket->data+curbyte,0x0002);
+	/* Channel ID */
+	curbyte += aimutil_put16(newpacket->data+curbyte,0x0002);
 
-  /* Destination SN (prepended with byte length) */
-  curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn));
-  curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn));
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
+	/* Destination SN (prepended with byte length) */
+	curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn));
+	curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn));
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
 
-  /* enTLV start */
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042);
+	/* enTLV start */
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0042);
 
-  /* Flag data / ICBM Parameters? */
-  curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
-  curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
+	/* Flag data / ICBM Parameters? */
+	curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
+	curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
 
-  /* Cookie */
-  curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8);
+	/* Cookie */
+	curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8);
 
-  /* Capability String */
-  curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10);
+	/* Capability String */
+	curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10);
 
-  /* 000a/0002 : 0001 */
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
+	/* 000a/0002 : 0001 */
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a);
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
 
-  /* 0003/0004: IP address */
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
-  for(i = 0; i < 4; i++)
-    curbyte += aimutil_put8(newpacket->data+curbyte, d[i]);
+	/* 0003/0004: IP address */
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004);
+	for (i = 0; i < 4; i++)
+	curbyte += aimutil_put8(newpacket->data+curbyte, d[i]);
 
-  /* already in network byte order  */
+	/* already in network byte order */
  
-  /* 0005/0002: Port */
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
-  curbyte += aimutil_put16(newpacket->data+curbyte, port);
+	/* 0005/0002: Port */
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
+	curbyte += aimutil_put16(newpacket->data+curbyte, port);
 
-  /* 000f/0000: ?? */
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
+	/* 000f/0000: ?? */
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
 
-  /* 2711/000c: ?? */
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711);
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c);
-  curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001);
+	/* 2711/000c: ?? */
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711);
+	curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c);
+	curbyte += aimutil_put32(newpacket->data+curbyte, 0x00120001);
 
-  for(i = 0; i < 0x000c - 4; i++)
-    curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
+	for (i = 0; i < 0x000c - 4; i++)
+		curbyte += aimutil_put8(newpacket->data+curbyte, 0x00);
 
-  newpacket->commandlen = curbyte;
-  newpacket->lock = 0;
-  aim_tx_enqueue(sess, newpacket);
+	newpacket->commandlen = curbyte;
+	newpacket->lock = 0;
+	aim_tx_enqueue(sess, newpacket);
 
-  /* allocate and set up our connection */
+	/* allocate and set up our connection */
 
-  i = fcntl(listenfd, F_GETFL, 0);
-  fcntl(listenfd, F_SETFL, i | O_NONBLOCK);
-  newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL);
+	i = fcntl(listenfd, F_GETFL, 0);
+	fcntl(listenfd, F_SETFL, i | O_NONBLOCK);
+	newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL);
 
-  if (!newconn){ 
-    perror("aim_newconn");
-    return NULL;
-  }
+	if (!newconn){ 
+		perror("aim_newconn");
+		return NULL;
+	}
 
-  newconn->fd = listenfd;
-  newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
-  newconn->internal = priv;
-  faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
+	newconn->fd = listenfd;
+	newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE;
+	newconn->internal = priv;
+	faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
 
-  return newconn;
+	return newconn;
 #endif
 }
  
@@ -2100,41 +2043,41 @@
 #if 0
 faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size)
 {
-  aim_frame_t *newoft;
-  struct aim_filetransfer_priv *ft;
-  if (!sess || !conn || !conn->priv || !name)
-    return -1;
+	aim_frame_t *newoft;
+	struct aim_filetransfer_priv *ft;
+	if (!sess || !conn || !conn->priv || !name)
+		return -1;
 
-  if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120c, 0))) {
-    faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
-    return -1;
-  }
-  memcpy(newoft->hdr.oft.magic, "OFT2", 4);
-  newoft->hdr.oft.hdr2len = 0x100 - 8;
+	if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120c, 0))) {
+		faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
+		return -1;
+	}
+	memcpy(newoft->hdr.oft.magic, "OFT2", 4);
+	newoft->hdr.oft.hdr2len = 0x100 - 8;
 
-  ft = (struct aim_filetransfer_priv *)conn->priv;
-  ft->fh.filesleft = 1;
-  ft->fh.totfiles = 1;
-  ft->fh.totparts = 1;
-  ft->fh.partsleft = 1;
-  ft->fh.totsize = size;
-  ft->fh.size = size;
-  ft->fh.checksum = 0;
-  memcpy(ft->fh.name, name, strlen(name));
-  memset(ft->fh.name+strlen(name), 0, 1);
+	ft = (struct aim_filetransfer_priv *)conn->priv;
+	ft->fh.filesleft = 1;
+	ft->fh.totfiles = 1;
+	ft->fh.totparts = 1;
+	ft->fh.partsleft = 1;
+	ft->fh.totsize = size;
+	ft->fh.size = size;
+	ft->fh.checksum = 0;
+	memcpy(ft->fh.name, name, strlen(name));
+	memset(ft->fh.name+strlen(name), 0, 1);
 
-  if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) {
-    aim_frame_destroy(newoft);
-    return -1;
-  }
+	if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) {
+		aim_frame_destroy(newoft);
+		return -1;
+	}
 
-  if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) {
-    aim_frame_destroy(newoft);
-    return -1;
-  }
+	if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) {
+		aim_frame_destroy(newoft);
+		return -1;
+	}
 
-  aim_tx_enqueue(sess, newoft);
-  return 0;
+	aim_tx_enqueue(sess, newoft);
+	return 0;
 }
 #endif
 
@@ -2143,111 +2086,104 @@
  */
 faim_export int aim_oft_sendfile_request(aim_session_t *sess, aim_conn_t *conn, const char *filename, int filesdone, int numfiles, int size, int totsize)
 {
-  aim_frame_t *newoft;
-  aim_msgcookie_t *cook;
-  struct aim_filetransfer_priv *ft = (struct aim_filetransfer_priv *)conn->internal;
-  struct aim_fileheader_t *fh;
+	aim_frame_t *newoft;
+	aim_msgcookie_t *cook;
+	struct aim_filetransfer_priv *ft = (struct aim_filetransfer_priv *)conn->internal;
+	struct aim_fileheader_t *fh;
 
-  if (!sess || !conn || !filename)
-    return -1;
+	if (!sess || !conn || !filename)
+		return -1;
 
-  if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
-    return -1;
+	if (!(fh = (struct aim_fileheader_t*)calloc(1, sizeof(struct aim_fileheader_t))))
+		return -1;
 
 #ifdef DUMB_OFT_CHECKSUM
-  /* Yes, we are supposed to checksum the whole file before sending, and
-   * yes, it's dumb.  This is the only way to get some clients (such as
-   * Mac AIM v4.5.163) to successfully complete the transfer.  With
-   * the WinAIM clients, we seem to be able to get away with just
-   * setting the checksum to zero.
-   * -- wtm
-   */
-  {
-    int fd = open(filename, O_RDONLY);
-    if (fd >= 0) {
-       int bytes;
-       char buf[1024];
-       fh->checksum = 0xffff0000;
-       while ((bytes = read(fd, buf, 1024)) > 0) {
-         fh->checksum = aim_oft_checksum(buf, bytes, fh->checksum);
-       }
-    }
-    close(fd);
-  }
+	/* Yes, we are supposed to checksum the whole file before sending, and
+	 * yes, it's dumb.  This is the only way to get some clients (such as
+	 * Mac AIM v4.5.163) to successfully complete the transfer.  With
+	 * the WinAIM clients, we seem to be able to get away with just
+	 * setting the checksum to zero.
+	 * -- wtm
+	 */
+	{
+		int fd = open(filename, O_RDONLY);
+		if (fd >= 0) {
+			int bytes;
+			char buf[1024];
+			fh->checksum = 0xffff0000;
+			while ((bytes = aim_recv(fd, buf, 1024)) > 0) {
+				fh->checksum = aim_oft_checksum(buf, bytes, fh->checksum);
+			}
+		}
+		close(fd);
+	}
 #else
-  fh->checksum    = 0x00000000;
+	fh->checksum = 0x00000000;
 #endif
-
-  fh->encrypt     = 0x0000;
-  fh->compress    = 0x0000; 
-  fh->totfiles    = numfiles;
-  fh->filesleft   = numfiles - filesdone;
-  fh->totparts    = 0x0001;
-  fh->partsleft   = 0x0001;
-  fh->totsize     = totsize;
-  fh->size        = size;
-  fh->modtime     = (int)time(NULL); /* we'll go with current time for now */
-  /* fh->checksum set above */
-  fh->rfcsum      = 0x00000000;
-  fh->rfsize      = 0x00000000;
-  fh->cretime     = 0x00000000;
-  fh->rfcsum      = 0x00000000;
-  fh->nrecvd      = 0x00000000; /* always zero initially */
-  fh->recvcsum    = 0x00000000; /* ditto */
-
-  strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
-  fh->flags = 0x02;
-  fh->lnameoffset = 0x1a;
-  fh->lsizeoffset = 0x10;
-  memset(fh->dummy, 0, sizeof(fh->dummy));
-  memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
+	fh->encrypt = 0x0000;
+	fh->compress = 0x0000;
+	fh->totfiles = numfiles;
+	fh->filesleft = numfiles - filesdone;
+	fh->totparts = 0x0001;
+	fh->partsleft = 0x0001;
+	fh->totsize = totsize; /* set to 0x0002 sending Mac resource forks */
+	fh->size = size;
+	fh->modtime = (int)time(NULL); /* we'll go with current time for now */
+	/* fh->checksum set above */
+	fh->rfcsum = 0x00000000;
+	fh->rfsize = 0x00000000;
+	fh->cretime = 0x00000000;
+	fh->rfcsum = 0x00000000;
+	fh->nrecvd = 0x00000000; /* always zero initially */
+	fh->recvcsum= 0x00000000; /* ditto */
 
-  /* we need to figure out these encodings for filenames */
-  fh->nencode = 0x0000;
-  fh->nlanguage = 0x0000;
-
-  /* Don't "show full pathname to buddy", just because it is
-   * non-portable. -- wtm 
-   */
-  strncpy(fh->name, oft_basename(filename), sizeof(fh->name));
+	strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
+	fh->flags = 0x02;
+	fh->lnameoffset = 0x1a;
+	fh->lsizeoffset = 0x10;
+	memset(fh->dummy, 0, sizeof(fh->dummy));
+	memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
 
-  /* XXX we should normally send a null cookie here, and make
-   * the receiver fill it in for authentication -- wtm
-   */
-  memcpy(fh->bcookie, ft->cookie, 8);
+	/* apparently 0 is ASCII, 2 is UCS-2 */
+	/* it is likely that 3 is ISO 8859-1 */
+	fh->nencode = 0x0000;
+	fh->nlanguage = 0x0000;
 
-  if (!(cook = aim_checkcookie(sess, ft->cookie, AIM_COOKIETYPE_OFTSEND))) {
-    return -1;
-  }
+	/* Convert the directory separator to ^A for portability. */
+	strncpy(fh->name, filename, sizeof(fh->name));
+	oft_dirconvert(fh->name);
 
-  /* Update both headers to be safe. */
-  memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
-  memcpy(&(((struct aim_filetransfer_priv *)cook->data)->fh), fh,
-		  sizeof(struct aim_fileheader_t));
+	/* XXX we should normally send a null cookie here, and make
+	 * the receiver fill it in for authentication -- wtm
+	 */
+	memcpy(fh->bcookie, ft->cookie, 8);
 
-  if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_OFFER, 0))) {
-    faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
-    free(fh);
-    return -1;
-  }
-  memcpy(newoft->hdr.oft.magic, "OFT2", 4);
-  newoft->hdr.oft.hdr2len = 0x100 - 8;
+	if (!(cook = aim_checkcookie(sess, ft->cookie, AIM_COOKIETYPE_OFTSEND))) {
+		return -1;
+	}
+
+	/* Update both headers to be safe. */
+	memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t));
+	memcpy(&(((struct aim_filetransfer_priv *)cook->data)->fh), fh, sizeof(struct aim_fileheader_t));
 
-  if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) {
-    aim_frame_destroy(newoft);
-    free(fh);
-    return -1;
-  }
+	if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_OFFER, 0))) {
+		faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
+		free(fh);
+		return -1;
+	}
 
-  if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, fh))) {
-    aim_frame_destroy(newoft);
-    free(fh);
-    return -1;
-  }
+	if (aim_oft_buildheader(&newoft->data, fh) == -1) {
+		aim_frame_destroy(newoft);
+		free(fh);
+		return -1;
+	}
 
-  aim_tx_enqueue(sess, newoft);
-  free(fh);
-  return 0;
+	memcpy(newoft->hdr.rend.magic, "OFT2", 4);
+	newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
+
+	aim_tx_enqueue(sess, newoft);
+	free(fh);
+	return 0;
 }
  
 /**
@@ -2263,39 +2199,39 @@
 {
 	return -EINVAL;
 #if 0
-  struct command_tx_struct *newoft;
-  struct aim_filetransfer_priv *ft;
+	struct command_tx_struct *newoft;
+	struct aim_filetransfer_priv *ft;
 
-  if (!sess || !conn || !conn->priv)
-    return -1;
+	if (!sess || !conn || !conn->priv)
+		return -1;
 
-  if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) {
-    faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
-    return -1;
-  } 
+	if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) {
+		faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
+	return -1;
+	} 
 
-  newoft->lock = 1;
+	newoft->lock = 1;
 
-  memcpy(newoft->hdr.oft.magic, "OFT2", 4);
-  newoft->hdr.oft.hdr2len = 0x100-8;
+	memcpy(newoft->hdr.oft.magic, "OFT2", 4);
+	newoft->hdr.oft.hdr2len = 0x100-8;
 
- if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 
-   newoft->lock = 0;
-   aim_frame_destroy(newoft);
-   return -1;
- }
+	if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { 
+		newoft->lock = 0;
+		aim_frame_destroy(newoft);
+		return -1;
+	}
 
- ft = (struct aim_filetransfer_priv *)conn->priv;
+	ft = (struct aim_filetransfer_priv *)conn->priv;
 
- if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
-   newoft->lock = 0;
-   aim_frame_destroy(newoft);
-   return -1;
- }
+	if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
+		newoft->lock = 0;
+		aim_frame_destroy(newoft);
+		return -1;
+	}
 
- newoft->lock = 0;
- aim_tx_enqueue(sess, newoft);
- return 0;
+	newoft->lock = 0;
+	aim_tx_enqueue(sess, newoft);
+	return 0;
 #endif
 }
  
@@ -2309,43 +2245,38 @@
  */
 faim_export int aim_oft_end(aim_session_t *sess, aim_conn_t *conn)
 {
-  aim_frame_t *newoft;
-  struct aim_filetransfer_priv *ft;
-  
-  if (!sess || !conn || !conn->internal)
-    return -1;
+	aim_frame_t *newoft;
+	struct aim_filetransfer_priv *ft;
+
+	if (!sess || !conn || !conn->internal)
+		return -1;
+
+	if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACK, 0))) {
+		faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
+		return -1;
+	}
 
-  if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, AIM_OFT_PROTO_ACK, 0))) {
-    faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n");
-    return -1;
-  }
-  
-  memcpy(newoft->hdr.oft.magic, "OFT2", 4);
-  newoft->hdr.oft.hdr2len = 0x100 - 8;
-  
-  if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) {
-    aim_frame_destroy(newoft);
-    return -1;
-  }
-  
-  ft = (struct aim_filetransfer_priv *)conn->internal;
-  ft->state = 4; /* no longer wanting data */
-  ft->fh.flags = 0x21;
-  
-  if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) {
-    aim_frame_destroy(newoft);
-    return -1;
-  }
-  
-  aim_tx_enqueue(sess, newoft);
-  
-  return 0;
+	ft = (struct aim_filetransfer_priv *)conn->internal;
+	ft->state = 4; /* no longer wanting data */
+	ft->fh.flags = 0x21;
+
+	if (aim_oft_buildheader(&(newoft->data), &(ft->fh)) == -1) {
+		aim_frame_destroy(newoft);
+		return -1;
+	}
+	memcpy(newoft->hdr.rend.magic, "OFT2", 4);
+	newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
+
+	aim_tx_enqueue(sess, newoft);
+
+	return 0;
 }
 
-/* Portability.  Yuck. */
-static const char *oft_basename(const char *name) {
-	const char *r = strrchr(name, G_DIR_SEPARATOR);
-	r = r ? r + 1 : name;
-	return r;
+/*
+ * Convert the directory separator to ^A, which seems to be AOL's attempt at portability.
+ */
+static void oft_dirconvert(char *name) {
+	char *c = name;
+	while ((c = strchr(c, G_DIR_SEPARATOR)))
+		*c = 0x01;
 }
-