changeset 5146:ac9ca88d4b25

[gaim-migrate @ 5510] I guess I'm gonna go ahead and commit this... I don't think there's any real functionality change. AIM file transfer might work a little better, I guess. I probably fixed a bug or two. Like, filenames>64 characters won't cause infinite loopage. Changed AIM file transfer a bit with the following two goals: -Move some code from oscar.c to libfaim. Should make it easier for 3rd parties to use libfaim for file transfer. -Allow for easier code reuse with "get file" (in the works) committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Thu, 17 Apr 2003 03:28:21 +0000
parents fc09679bffbe
children 6d68d9edf5ae
files src/ft.c src/protocols/oscar/aim.h src/protocols/oscar/ft.c src/protocols/oscar/im.c src/protocols/oscar/oscar.c
diffstat 5 files changed, 289 insertions(+), 370 deletions(-) [+]
line wrap: on
line diff
--- a/src/ft.c	Thu Apr 17 01:20:22 2003 +0000
+++ b/src/ft.c	Thu Apr 17 03:28:21 2003 +0000
@@ -63,10 +63,8 @@
 	if (xfer == NULL)
 		return;
 
-	if (!xfer->completed) {
+	if (!xfer->completed)
 		gaim_xfer_cancel_local(xfer);
-		return;
-	}
 
 	ui_ops = gaim_xfer_get_ui_ops(xfer);
 
--- a/src/protocols/oscar/aim.h	Thu Apr 17 01:20:22 2003 +0000
+++ b/src/protocols/oscar/aim.h	Thu Apr 17 03:28:21 2003 +0000
@@ -836,9 +836,9 @@
 /* 0x0006 */ faim_export int aim_im_sendch2_icon(aim_session_t *sess, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum);
 /* 0x0006 */ faim_export int aim_im_sendch2_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args);
 /* 0x0006 */ faim_export int aim_im_sendch2_odcrequest(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port);
-/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_ask(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port, const char *filename, fu16_t numfiles, fu32_t totsize);
-/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_accept(aim_session_t *sess, const fu8_t *cookie, const char *sn, fu16_t rendid);
-/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_cancel(aim_session_t *sess, const fu8_t *cookie, const char *sn, fu16_t rendid);
+/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_ask(aim_session_t *sess, struct aim_oft_info *oft_info);
+/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_accept(aim_session_t *sess, struct aim_oft_info *info);
+/* 0x0006 */ faim_export int aim_im_sendch2_sendfile_cancel(aim_session_t *sess, struct aim_oft_info *oft_info);
 /* 0x0006 */ faim_export int aim_im_sendch2_geticqaway(aim_session_t *sess, const char *sn, int type);
 /* 0x0006 */ faim_export int aim_im_sendch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message);
 /* 0x0008 */ faim_export int aim_im_warn(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags);
@@ -885,7 +885,13 @@
 
 struct aim_oft_info {
 	char cookie[8];
-	char ip[30];
+	char *sn;
+	char *proxyip;
+	char *clientip;
+	char *verifiedip;
+	fu16_t port;
+	aim_conn_t *conn;
+	aim_session_t *sess;
 	struct aim_fileheader_t fh;
 	struct aim_oft_info *next;
 };
@@ -899,14 +905,15 @@
 faim_export aim_conn_t *aim_odc_getconn(aim_session_t *sess, const char *sn);
 faim_export aim_conn_t *aim_odc_initiate(aim_session_t *sess, const char *sn);
 faim_export aim_conn_t *aim_odc_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie);
-faim_export struct aim_oft_info *aim_oft_createnewheader(fu8_t *cookie, char *ip, fu32_t size, fu32_t modtime, char *filename);
-faim_export aim_conn_t *aim_sendfile_listen(aim_session_t *sess, const fu8_t *cookie, const fu8_t *ip, fu16_t port);
-faim_export int aim_oft_sendheader(aim_session_t *sess, aim_conn_t *conn, fu16_t type, const fu8_t *cookie, const char *filename, fu16_t filesdone, fu16_t numfiles, fu32_t size, fu32_t totsize, fu32_t modtime, fu32_t checksum, fu8_t flags, fu32_t bytesreceived, fu32_t recvcsum);
+
+faim_export struct aim_oft_info *aim_oft_createinfo(aim_session_t *sess, const fu8_t *cookie, const char *sn, const char *ip, fu16_t port, fu32_t size, fu32_t modtime, char *filename);
+faim_export int aim_oft_destroyinfo(struct aim_oft_info *oft_info);
+faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info);
+faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info);
 
 
 
 /* info.c */
-/* info.c */
 /*
  * AIM User Info, Standard Form.
  */
--- a/src/protocols/oscar/ft.c	Thu Apr 17 01:20:22 2003 +0000
+++ b/src/protocols/oscar/ft.c	Thu Apr 17 03:28:21 2003 +0000
@@ -23,7 +23,7 @@
  *      number that we're listening on.
  *   2) The receiver connects to the sender on the given IP address 
  *      and port.  After the connection is established, the receiver 
- *      sends another ICBM signifying that we are ready and waiting.
+ *      sends an ICBM signifying that we are ready and waiting.
  *   3) The sender sends an OFT PROMPT message over the OFT 
  *      connection.
  *   4) The receiver of the file sends back an exact copy of this 
@@ -35,7 +35,8 @@
  *      until the entire file has been sent.
  *   6) The receiver knows the file is finished because the sender 
  *      sent the file size in an earlier OFT packet.  So then the 
- *      receiver sends the DONE thingy and closes the connection.
+ *      receiver sends the DONE thingy (after filling in the 
+ *      "received" checksum and size) and closes the connection.
  */
 
 #define FAIM_INTERNAL
@@ -521,9 +522,6 @@
  * will accept the pending connection and stop listening.
  *
  * @param sess The session
- * @param conn The BOS conn.
- * @param priv A dummy priv value (we'll let it get filled in later)
- *             (if you pass a %NULL, we alloc one).
  * @param sn The screen name to connect to.
  * @return The new connection.
  */
@@ -598,9 +596,8 @@
 	if (!sess || !sn)
 		return NULL;
 
-	if (!(intdata = malloc(sizeof(struct aim_odc_intdata))))
+	if (!(intdata = calloc(1, sizeof(struct aim_odc_intdata))))
 		return NULL;
-	memset(intdata, 0, sizeof(struct aim_odc_intdata));
 	memcpy(intdata->cookie, cookie, 8);
 	strncpy(intdata->sn, sn, sizeof(intdata->sn));
 	if (addr)
@@ -703,6 +700,78 @@
 	return ret;
 }
 
+faim_export struct aim_oft_info *aim_oft_createinfo(aim_session_t *sess, const fu8_t *cookie, const char *sn, const char *ip, fu16_t port, fu32_t size, fu32_t modtime, char *filename)
+{
+	struct aim_oft_info *new;
+
+	if (!sess)
+		return NULL;
+
+	if (!(new = (struct aim_oft_info *)calloc(1, sizeof(struct aim_oft_info))))
+		return NULL;
+
+	new->sess = sess;
+	if (cookie)
+		memcpy(new->cookie, cookie, 8);
+	if (ip)
+		new->clientip = strdup(ip);
+	if (sn)
+		new->sn = strdup(sn);
+	new->port = port;
+	new->fh.totfiles = 1;
+	new->fh.filesleft = 1;
+	new->fh.totparts = 1;
+	new->fh.partsleft = 1;
+	new->fh.totsize = size;
+	new->fh.size = size;
+	new->fh.modtime = modtime;
+	new->fh.checksum = 0xffff0000;
+	new->fh.rfrcsum = 0xffff0000;
+	new->fh.rfcsum = 0xffff0000;
+	new->fh.recvcsum = 0xffff0000;
+	strncpy(new->fh.idstring, "OFT_Windows ICBMFT V1.1 32", 31);
+	if (filename)
+		strncpy(new->fh.name, filename, 63);
+
+	new->next = sess->oft_info;
+	sess->oft_info = new;
+
+	return new;
+}
+
+/**
+ * Remove the given oft_info struct from the oft_info linked list, and 
+ * then free its memory.
+ *
+ * @param sess The session.
+ * @param oft_info The aim_oft_info struct that we're destroying.
+ * @return Return 0 if no errors, otherwise return the error number.
+ */
+faim_export int aim_oft_destroyinfo(struct aim_oft_info *oft_info)
+{
+	aim_session_t *sess;
+
+	if (!oft_info || !(sess = oft_info->sess))
+		return -EINVAL;
+
+	if (sess->oft_info && (sess->oft_info == oft_info)) {
+		sess->oft_info = sess->oft_info->next;
+	} else {
+		struct aim_oft_info *cur;
+		for (cur=sess->oft_info; (cur->next && (cur->next!=oft_info)); cur=cur->next);
+		if (cur->next)
+			cur->next = cur->next->next;
+	}
+
+	free(oft_info->sn);
+	free(oft_info->proxyip);
+	free(oft_info->clientip);
+	free(oft_info->verifiedip);
+	free(oft_info);
+
+	return 0;
+}
+
 /**
  * Creates a listener socket so the other dude can connect to us.
  *
@@ -712,30 +781,30 @@
  * will accept the pending connection and stop listening.
  *
  * @param sess The session.
- * @param cookie This better be Mrs. Fields or I'm going to be pissed.
- * @param ip Should be 4 bytes,  each byte is 1 quartet of the IP address.
- * @param port Ye olde port number to listen on.
- * @return Return the new conn if everything went as planned.  Otherwise, 
- *         return NULL.
+ * @param oft_info File transfer information associated with this 
+ *        connection.
+ * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export aim_conn_t *aim_sendfile_listen(aim_session_t *sess, const fu8_t *cookie, const fu8_t *ip, fu16_t port)
+faim_export int aim_sendfile_listen(aim_session_t *sess, struct aim_oft_info *oft_info)
 {
-	aim_conn_t *newconn;
 	int listenfd;
 
-	if ((listenfd = listenestablish(port)) == -1)
-		return NULL;
+	if (!oft_info)
+		return -EINVAL;
 
-	if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) {
+	if ((listenfd = listenestablish(oft_info->port)) == -1)
+		return 1;
+
+	if (!(oft_info->conn = aim_newconn(sess, AIM_CONN_TYPE_LISTENER, NULL))) {
 		close(listenfd);
-		return NULL;
+		return -ENOMEM;
 	}
 
-	newconn->fd = listenfd;
-	newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
-	newconn->lastactivity = time(NULL);
+	oft_info->conn->fd = listenfd;
+	oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
+	oft_info->conn->lastactivity = time(NULL);
 
-	return newconn;
+	return 0;
 }
 
 /**
@@ -830,110 +899,52 @@
 	return 0;
 }
 
-faim_export struct aim_oft_info *aim_oft_createnewheader(fu8_t *cookie, char *ip, fu32_t size, fu32_t modtime, char *filename)
-{
-	struct aim_oft_info *new;
-
-	if (!(new = (struct aim_oft_info *)calloc(1, sizeof(struct aim_oft_info))))
-		return NULL;
-
-	if (cookie && (sizeof(cookie) == 8)) {
-		memcpy(new->cookie, cookie, 8);
-		memcpy(new->fh.bcookie, cookie, 8);
-	}
-	if (ip)
-		strncpy(new->ip, ip, 30);
-	new->fh.filesleft = 0;
-	new->fh.totparts = 1;
-	new->fh.partsleft = 1;
-	new->fh.totsize = size;
-	new->fh.size = size;
-	new->fh.modtime = modtime;
-	strcpy(new->fh.idstring, "OFT_Windows ICBMFT V1.1 32");
-	if (filename)
-		strncpy(new->fh.name, filename, 64);
-
-	return new;
-}
-
 /**
  * Create an OFT packet based on the given information, and send it on its merry way.
  *
  * @param sess The session.
- * @param conn The already-connected OFT connection.
- * @param cookie The cookie associated with this file transfer.
- * @param filename The filename.
- * @param filesdone Number of files already transferred.
- * @param numfiles Total number of files.
- * @param size Size in bytes of this file.
- * @param totsize Size in bytes of all files combined.
- * @param checksum Funky checksum of this file.
- * @param flags Any flags you want, baby.  Send 0x21 when sending the 
- *        "AIM_CB_OFT_DONE" message, and "0x02" for everything else.
+ * @param type The subtype of the OFT packet we're sending.
+ * @param oft_info The aim_oft_info struct with the connection and OFT 
+ *        info we're sending.
  * @return Return 0 if no errors, otherwise return the error number.
  */
-faim_export int aim_oft_sendheader(aim_session_t *sess, aim_conn_t *conn, fu16_t type, const fu8_t *cookie, const char *filename, fu16_t filesdone, fu16_t numfiles, fu32_t size, fu32_t totsize, fu32_t modtime, fu32_t checksum, fu8_t flags, fu32_t bytesreceived, fu32_t recvcsum)
+faim_export int aim_oft_sendheader(aim_session_t *sess, fu16_t type, struct aim_oft_info *oft_info)
 {
-	aim_frame_t *newoft;
-	struct aim_fileheader_t *fh;
+	aim_frame_t *fr;
 
-	if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !filename)
+	if (!sess || !oft_info || !oft_info->conn || (oft_info->conn->type != AIM_CONN_TYPE_RENDEZVOUS))
 		return -EINVAL;
 
-	if (!(fh = (struct aim_fileheader_t *)calloc(1, sizeof(struct aim_fileheader_t))))
-		return -ENOMEM;
-
+#if 0
 	/*
 	 * If you are receiving a file, the cookie should be null, if you are sending a 
 	 * file, the cookie should be the same as the one used in the ICBM negotiation 
 	 * SNACs.
 	 */
-	if (cookie)
-		memcpy(fh->bcookie, cookie, 8);
-	fh->totfiles = numfiles;
-	fh->filesleft = numfiles - filesdone;
-	fh->totparts = 0x0001; /* set to 0x0002 sending Mac resource forks */
-	fh->partsleft = 0x0001;
-	fh->totsize = totsize;
-	fh->size = size;
-	fh->modtime = modtime;
-	fh->checksum = checksum;
-	fh->nrecvd = bytesreceived;
-	fh->recvcsum = recvcsum;
-
-	strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring));
-	fh->flags = flags;
 	fh->lnameoffset = 0x1a;
 	fh->lsizeoffset = 0x10;
-	memset(fh->dummy, 0, sizeof(fh->dummy));
-	memset(fh->macfileinfo, 0, sizeof(fh->macfileinfo));
 
 	/* apparently 0 is ASCII, 2 is UCS-2 */
 	/* it is likely that 3 is ISO 8859-1 */
 	/* I think "nlanguage" might be the same thing as "subenc" in im.c */
 	fh->nencode = 0x0000;
 	fh->nlanguage = 0x0000;
+#endif
 
-	strncpy(fh->name, filename, sizeof(fh->name));
-	aim_oft_dirconvert_tostupid(fh->name);
+	aim_oft_dirconvert_tostupid(oft_info->fh.name);
 
-	if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, type, 0))) {
-		free(fh);
+	if (!(fr = aim_tx_new(sess, oft_info->conn, AIM_FRAMETYPE_OFT, type, 0)))
+		return -ENOMEM;
+
+	if (aim_oft_buildheader(&fr->data, &oft_info->fh) == -1) {
+		aim_frame_destroy(fr);
 		return -ENOMEM;
 	}
 
-	if (aim_oft_buildheader(&newoft->data, fh) == -1) {
-		aim_frame_destroy(newoft);
-		free(fh);
-		return -ENOMEM;
-	}
+	memcpy(fr->hdr.rend.magic, "OFT2", 4);
+	fr->hdr.rend.hdrlen = aim_bstream_curpos(&fr->data);
 
-	memcpy(newoft->hdr.rend.magic, "OFT2", 4);
-	newoft->hdr.rend.hdrlen = aim_bstream_curpos(&newoft->data);
-
-	aim_tx_enqueue(sess, newoft);
-
-	free(fh);
+	aim_tx_enqueue(sess, fr);
 
 	return 0;
 }
--- a/src/protocols/oscar/im.c	Thu Apr 17 01:20:22 2003 +0000
+++ b/src/protocols/oscar/im.c	Thu Apr 17 03:28:21 2003 +0000
@@ -667,28 +667,21 @@
  * Subtype 0x0006 - Send an "I want to send you this file" message
  *
  */
-faim_export int aim_im_sendch2_sendfile_ask(aim_session_t *sess, fu8_t *cookie, const char *sn, const fu8_t *ip, fu16_t port, const char *filename, fu16_t numfiles, fu32_t totsize)
+faim_export int aim_im_sendch2_sendfile_ask(aim_session_t *sess, struct aim_oft_info *oft_info)
 {
 	aim_conn_t *conn;
 	aim_frame_t *fr;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl=NULL, *subtl=NULL;
-	fu8_t *ck;
 	int i;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
-		return -EINVAL;
-
-	if (!sn || !filename)
+	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info)
 		return -EINVAL;
 
 	/* XXX - Should be like "21CBF95" and null terminated */
-	ck = (fu8_t *)malloc(8*sizeof(fu8_t));
 	for (i = 0; i < 7; i++)
-		ck[i] = 0x30 + ((fu8_t)rand() % 10);
-	ck[7] = '\0';
-	if (cookie)
-		memcpy(cookie, ck, 8);
+		oft_info->cookie[i] = 0x30 + ((fu8_t)rand() % 10);
+	oft_info->cookie[7] = '\0';
 
 	{ /* Create the subTLV chain */
 		fu8_t *buf;
@@ -700,22 +693,31 @@
 /*		aim_addtlvtochain_raw(&subtl, 0x000e, 2, "en");
 		aim_addtlvtochain_raw(&subtl, 0x000d, 8, "us-ascii");
 		aim_addtlvtochain_raw(&subtl, 0x000c, 24, "Please accept this file."); */
-		if (ip[0])
+		if (oft_info->clientip) {
+			fu8_t ip[4];
+			char *nexttoken;
+			int i = 0;
+			nexttoken = strtok(oft_info->clientip, ".");
+			while (nexttoken && i<4) {
+				ip[i] = atoi(nexttoken);
+				nexttoken = strtok(NULL, ".");
+				i++;
+			}
 			aim_addtlvtochain_raw(&subtl, 0x0003, 4, ip);
-		aim_addtlvtochain16(&subtl, 0x0005, port);
+		}
+		aim_addtlvtochain16(&subtl, 0x0005, oft_info->port);
 
 		/* TLV t(2711) */
-		buflen = 2+2+4+63;
+		buflen = 2+2+4+strlen(oft_info->fh.name)+1;
 		buf = malloc(buflen);
 		aim_bstream_init(&bs, buf, buflen);
-		aimbs_put16(&bs, (numfiles > 1) ? 0x0002 : 0x0001);
-		aimbs_put16(&bs, numfiles);
-		aimbs_put32(&bs, totsize);
+		aimbs_put16(&bs, (oft_info->fh.totfiles > 1) ? 0x0002 : 0x0001);
+		aimbs_put16(&bs, oft_info->fh.totfiles);
+		aimbs_put32(&bs, oft_info->fh.totsize);
 
-		/* Filename is a fixed size of 63 bytes, so pad with 0's */
-		aimbs_putraw(&bs, filename, strlen(filename));
-		for (i=0; i<(63-strlen(filename)); i++)
-			aimbs_put8(&bs, 0x00);
+		/* Filename - NULL terminated, for some odd reason */
+		aimbs_putraw(&bs, oft_info->fh.name, strlen(oft_info->fh.name));
+		aimbs_put8(&bs, 0x00);
 
 		aim_addtlvtochain_raw(&subtl, 0x2711, bs.len, bs.data);
 		free(buf);
@@ -731,7 +733,7 @@
 		buf = malloc(buflen);
 		aim_bstream_init(&bs, buf, buflen);
 		aimbs_put16(&bs, AIM_RENDEZVOUS_PROPOSE);
-		aimbs_putraw(&bs, ck, 8);
+		aimbs_putraw(&bs, oft_info->cookie, 8);
 		aim_putcap(&bs, AIM_CAPS_SENDFILE);
 		aim_writetlvchain(&bs, &subtl);
 		aim_freetlvchain(&subtl);
@@ -742,14 +744,14 @@
 		aim_addtlvtochain_noval(&tl, 0x0003);
 	}
 
-	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(sn) + aim_sizetlvchain(&tl))))
+	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(oft_info->sn) + aim_sizetlvchain(&tl))))
 		return -ENOMEM;
 
-	snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, ck, sizeof(ck));
+	snacid = aim_cachesnac(sess, 0x0004, 0x0006, AIM_SNACFLAGS_DESTRUCTOR, oft_info->cookie, sizeof(oft_info->cookie));
 	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, ck, 0x0002, sn);
+	aim_im_puticbm(&fr->data, oft_info->cookie, 0x0002, oft_info->sn);
 
 	/* All that crap from above (the 0x0005 TLV and the 0x0003 TLV) */
 	aim_writetlvchain(&fr->data, &tl);
@@ -765,29 +767,29 @@
  *
  * @param rendid Capability type (AIM_CAPS_GETFILE or AIM_CAPS_SENDFILE)
  */
-faim_export int aim_im_sendch2_sendfile_accept(aim_session_t *sess, const fu8_t *cookie, const char *sn, fu16_t rendid)
+faim_export int aim_im_sendch2_sendfile_accept(aim_session_t *sess, struct aim_oft_info *oft_info)
 {
 	aim_conn_t *conn;
 	aim_frame_t *fr;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !cookie || !sn)
+	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info)
 		return -EINVAL;
 
-	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(sn) + 4+2+8+16)))
+	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(oft_info->sn) + 4+2+8+16)))
 		return -ENOMEM;
 
 	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&fr->data, oft_info->cookie, 0x0002, oft_info->sn);
 
 	aimbs_put16(&fr->data, 0x0005);
 	aimbs_put16(&fr->data, 0x001a);
 	aimbs_put16(&fr->data, AIM_RENDEZVOUS_ACCEPT);
-	aimbs_putraw(&fr->data, cookie, 8);
-	aim_putcap(&fr->data, rendid);
+	aimbs_putraw(&fr->data, oft_info->cookie, 8);
+	aim_putcap(&fr->data, AIM_CAPS_SENDFILE);
 
 	aim_tx_enqueue(sess, fr);
 
@@ -798,29 +800,29 @@
  * Subtype 0x0006 - Send a "cancel this file transfer" message?
  *
  */
-faim_export int aim_im_sendch2_sendfile_cancel(aim_session_t *sess, const fu8_t *cookie, const char *sn, fu16_t rendid)
+faim_export int aim_im_sendch2_sendfile_cancel(aim_session_t *sess, struct aim_oft_info *oft_info)
 {
 	aim_conn_t *conn;
 	aim_frame_t *fr;
 	aim_snacid_t snacid;
 
-	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !cookie || !sn)
+	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info)
 		return -EINVAL;
 
-	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(sn) + 4+2+8+16)))
+	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 11+strlen(oft_info->sn) + 4+2+8+16)))
 		return -ENOMEM;
 
 	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&fr->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&fr->data, oft_info->cookie, 0x0002, oft_info->sn);
 
 	aimbs_put16(&fr->data, 0x0005);
 	aimbs_put16(&fr->data, 0x001a);
 	aimbs_put16(&fr->data, AIM_RENDEZVOUS_CANCEL);
-	aimbs_putraw(&fr->data, cookie, 8);
-	aim_putcap(&fr->data, rendid);
+	aimbs_putraw(&fr->data, oft_info->cookie, 8);
+	aim_putcap(&fr->data, AIM_CAPS_SENDFILE);
 
 	aim_tx_enqueue(sess, fr);
 
@@ -1769,6 +1771,8 @@
 
 	/*
 	 * Unknown -- no value
+	 *
+	 * Maybe means we should connect directly to transfer the file?
 	 */
 	if (aim_gettlv(list2, 0x000f, 1))
 		;
--- a/src/protocols/oscar/oscar.c	Thu Apr 17 01:20:22 2003 +0000
+++ b/src/protocols/oscar/oscar.c	Thu Apr 17 03:28:21 2003 +0000
@@ -160,19 +160,6 @@
 	fu8_t cookie[8];
 };
 
-/* BBB */
-struct oscar_xfer_data {
-	fu8_t cookie[8];
-	gchar *proxyip;
-	gchar *clientip;
-	gchar *verifiedip;
-	fu32_t modtime;
-	fu32_t checksum;
-	aim_conn_t *conn;
-	struct gaim_xfer *xfer;
-	struct gaim_connection *gc;
-};
-
 /* Various PRPL-specific buddy info that we want to keep track of */
 struct buddyinfo {
 	time_t signon;
@@ -820,64 +807,46 @@
 static void oscar_sendfile_connected(gpointer data, gint source, GaimInputCondition condition);
 
 /* XXX - This function is pretty ugly */
-static void
-oscar_xfer_init(struct gaim_xfer *xfer)
+static void oscar_xfer_init(struct gaim_xfer *xfer)
 {
-	struct gaim_connection *gc;
-	struct oscar_data *od;
-	struct oscar_xfer_data *xfer_data;
-
-	debug_printf("in oscar_xfer_init\n");
-	if (!(xfer_data = xfer->data))
-		return;
-	if (!(gc = xfer_data->gc))
-		return;
-	if (!(od = gc->proto_data))
-		return;
+	struct aim_oft_info *oft_info = xfer->data;
+	struct gaim_connection *gc = oft_info->sess->aux_data;
+	struct oscar_data *od = gc->proto_data;
 
 	if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) {
 		int i;
-		char ip[4];
-		gchar **ipsplit;
-
-		if (xfer->local_ip) {
-			ipsplit = g_strsplit(xfer->local_ip, ".", 4);
-			for (i=0; ipsplit[i]; i++)
-				ip[i] = atoi(ipsplit[i]);
-			g_strfreev(ipsplit);
-		} else {
-			memset(ip, 0x00, 4);
-		}
 
 		xfer->filename = g_path_get_basename(xfer->local_filename);
-		xfer_data->checksum = aim_oft_checksum_file(xfer->local_filename);
+		strncpy(oft_info->fh.name, xfer->filename, 64);
+		oft_info->fh.totsize = gaim_xfer_get_size(xfer);
+		oft_info->fh.size = gaim_xfer_get_size(xfer);
+		oft_info->fh.checksum = aim_oft_checksum_file(xfer->local_filename);
 
 		/*
-		 * First try the port specified earlier (5190).  If that fails, try a 
-		 * few random ports.  Maybe we need a way to tell libfaim to listen 
-		 * for multiple connections on one listener socket.
+		 * First try the port specified earlier (5190).  If that fails, 
+		 * increment by 1 and try again.
 		 */
-		xfer_data->conn = aim_sendfile_listen(od->sess, xfer_data->cookie, ip, xfer->local_port);
-		for (i=0; (i<5 && !xfer_data->conn); i++) {
-			xfer->local_port = (rand() % (65535-1024)) + 1024;
-			xfer_data->conn = aim_sendfile_listen(od->sess, xfer_data->cookie, ip, xfer->local_port);
+		aim_sendfile_listen(od->sess, oft_info);
+		for (i=0; (i<5 && !oft_info->conn); i++) {
+			xfer->local_port = oft_info->port = oft_info->port + 1;
+			aim_sendfile_listen(od->sess, oft_info);
 		}
-		debug_printf("port is %d, ip is %hhd.%hhd.%hhd.%hhd\n", xfer->local_port, ip[0], ip[1], ip[2], ip[3]);
-		if (xfer_data->conn) {
-			xfer->watcher = gaim_input_add(xfer_data->conn->fd, GAIM_INPUT_READ, oscar_callback, xfer_data->conn);
-			aim_im_sendch2_sendfile_ask(od->sess, xfer_data->cookie, xfer->who, ip, xfer->local_port, xfer->filename, 1, xfer->size);
-			aim_conn_addhandler(od->sess, xfer_data->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED, oscar_sendfile_estblsh, 0);
+		debug_printf("port is %d, ip is %s\n", xfer->local_port, oft_info->clientip);
+		if (oft_info->conn) {
+			xfer->watcher = gaim_input_add(oft_info->conn->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
+			aim_im_sendch2_sendfile_ask(od->sess, oft_info);
+			aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED, oscar_sendfile_estblsh, 0);
 		} else {
 			do_error_dialog(_("File Transfer Aborted"), _("Unable to establish listener socket."), GAIM_ERROR);
 			/* XXX - The below line causes a crash because the transfer is canceled before the "Ok" callback on the file selection thing exists, I think */
 			/* gaim_xfer_cancel_remote(xfer); */
 		}
 	} else if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
-		xfer_data->conn = aim_newconn(od->sess, AIM_CONN_TYPE_RENDEZVOUS, NULL);
-		if (xfer_data->conn) {
-			xfer_data->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
-			aim_conn_addhandler(od->sess, xfer_data->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_PROMPT, oscar_sendfile_prompt, 0);
-			xfer_data->conn->fd = xfer->fd = proxy_connect(gc->account, xfer->remote_ip, xfer->remote_port, oscar_sendfile_connected, xfer);
+		oft_info->conn = aim_newconn(od->sess, AIM_CONN_TYPE_RENDEZVOUS, NULL);
+		if (oft_info->conn) {
+			oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE;
+			aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_PROMPT, oscar_sendfile_prompt, 0);
+			oft_info->conn->fd = xfer->fd = proxy_connect(gc->account, xfer->remote_ip, xfer->remote_port, oscar_sendfile_connected, xfer);
 			if (xfer->fd == -1) {
 				do_error_dialog(_("File Transfer Aborted"), _("Unable to establish file descriptor."), GAIM_ERROR);
 				/* gaim_xfer_cancel_remote(xfer); */
@@ -891,123 +860,67 @@
 	}
 }
 
-static void
-oscar_xfer_start(struct gaim_xfer *xfer)
+static void oscar_xfer_start(struct gaim_xfer *xfer)
 {
-/*	struct gaim_connection *gc;
-	struct oscar_data *od;
-	struct oscar_xfer_data *xfer_data;
-
-	if (!(xfer_data = xfer->data))
-		return;
-	if (!(gc = xfer_data->gc))
-		return;
-	if (!(od = gc->proto_data))
-		return;
-
-	od = xfer_data->od;
-*/
+
 	debug_printf("AAA - in oscar_xfer_start\n");
-
 	/* I'm pretty sure we don't need to do jack here.  Nor Jill. */
 }
 
-static void
-oscar_xfer_end(struct gaim_xfer *xfer)
+static void oscar_xfer_end(struct gaim_xfer *xfer)
 {
-	struct gaim_connection *gc;
-	struct oscar_data *od;
-	struct oscar_xfer_data *xfer_data;
+	struct aim_oft_info *oft_info = xfer->data;
+	struct gaim_connection *gc = oft_info->sess->aux_data;
+	struct oscar_data *od = gc->proto_data;
 
 	debug_printf("AAA - in oscar_xfer_end\n");
-	if (!(xfer_data = xfer->data))
-		return;
-
-	if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE)
-		aim_oft_sendheader(xfer_data->conn->sessv, xfer_data->conn, AIM_CB_OFT_DONE, xfer_data->cookie, xfer->filename, 1, 1, xfer->size, xfer->size, xfer_data->modtime, xfer_data->checksum, 0x02, xfer->size, xfer_data->checksum);
-
-	g_free(xfer_data->proxyip);
-	g_free(xfer_data->clientip);
-	g_free(xfer_data->verifiedip);
-
-	if ((gc = xfer_data->gc)) {
-		if ((od = gc->proto_data))
-			od->file_transfers = g_slist_remove(od->file_transfers, xfer);
-	}
-
-	g_free(xfer_data);
+
+	if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
+		oft_info->fh.nrecvd = gaim_xfer_get_bytes_sent(xfer);
+		aim_oft_sendheader(oft_info->sess, AIM_CB_OFT_DONE, oft_info);
+	}
+
+	aim_conn_kill(oft_info->sess, &oft_info->conn);
+	aim_oft_destroyinfo(oft_info);
 	xfer->data = NULL;
+	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
 }
 
-static void
-oscar_xfer_cancel_send(struct gaim_xfer *xfer)
+static void oscar_xfer_cancel_send(struct gaim_xfer *xfer)
 {
-	struct gaim_connection *gc;
-	struct oscar_data *od;
-	struct oscar_xfer_data *xfer_data;
-	aim_conn_t *conn;
+	struct aim_oft_info *oft_info = xfer->data;
+	struct gaim_connection *gc = oft_info->sess->aux_data;
+	struct oscar_data *od = gc->proto_data;
 
 	debug_printf("AAA - in oscar_xfer_cancel_send\n");
-	if (!(xfer_data = xfer->data))
-		return;
-
-	if ((conn = xfer_data->conn)) {
-		aim_session_t *sess;
-		if ((sess = conn->sessv))
-			if (xfer_data->cookie && xfer->who)
-				aim_im_sendch2_sendfile_cancel(sess, xfer_data->cookie, xfer->who, AIM_CAPS_SENDFILE);
-	}
-
-	g_free(xfer_data->proxyip);
-	g_free(xfer_data->clientip);
-	g_free(xfer_data->verifiedip);
-
-	if ((gc = xfer_data->gc))
-		if ((od = gc->proto_data))
-			od->file_transfers = g_slist_remove(od->file_transfers, xfer);
-
-	g_free(xfer_data);
+
+	aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info);
+
+	aim_conn_kill(oft_info->sess, &oft_info->conn);
+	aim_oft_destroyinfo(oft_info);
 	xfer->data = NULL;
+	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
 }
 
-static void
-oscar_xfer_cancel_recv(struct gaim_xfer *xfer)
+static void oscar_xfer_cancel_recv(struct gaim_xfer *xfer)
 {
-	struct gaim_connection *gc;
-	struct oscar_data *od;
-	struct oscar_xfer_data *xfer_data;
-	aim_conn_t *conn;
+	struct aim_oft_info *oft_info = xfer->data;
+	struct gaim_connection *gc = oft_info->sess->aux_data;
+	struct oscar_data *od = gc->proto_data;
 
 	debug_printf("AAA - in oscar_xfer_cancel_recv\n");
-	if (!(xfer_data = xfer->data))
-		return;
-
-	if ((conn = xfer_data->conn)) {
-		aim_session_t *sess;
-		if ((sess = conn->sessv))
-			if (xfer_data->cookie && xfer->who)
-				aim_im_sendch2_sendfile_cancel(sess, xfer_data->cookie, xfer->who, AIM_CAPS_SENDFILE);
-	}
-
-	g_free(xfer_data->proxyip);
-	g_free(xfer_data->clientip);
-	g_free(xfer_data->verifiedip);
-
-	if ((gc = xfer_data->gc))
-		if ((od = gc->proto_data))
-			od->file_transfers = g_slist_remove(od->file_transfers, xfer);
-
-	g_free(xfer_data);
+
+	aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info);
+
+	aim_conn_kill(oft_info->sess, &oft_info->conn);
+	aim_oft_destroyinfo(oft_info);
 	xfer->data = NULL;
+	od->file_transfers = g_slist_remove(od->file_transfers, xfer);
 }
 
-static void
-oscar_xfer_ack(struct gaim_xfer *xfer, const char *buffer, size_t size)
+static void oscar_xfer_ack(struct gaim_xfer *xfer, const char *buffer, size_t size)
 {
-	struct oscar_xfer_data *xfer_data;
-
-	if (!(xfer_data = xfer->data))
-		return;
+	struct aim_oft_info *oft_info = xfer->data;
 
 	if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) {
 		/*
@@ -1016,27 +929,26 @@
 		 */
 		if (gaim_xfer_get_bytes_remaining(xfer) <= 0) {
 			gaim_input_remove(xfer->watcher);
-			xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, xfer_data->conn);
+			xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
 			xfer->fd = 0;
 			gaim_xfer_set_completed(xfer, TRUE);
 		}
 	} else if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
-		/* Update our rolling checksum */
-		/* xfer_data->checksum = aim_oft_checksum_chunk(buffer, size, xfer_data->checksum); */
+		/* Update our rolling checksum.  Like Walmart, yo. */
+		oft_info->fh.recvcsum = aim_oft_checksum_chunk(buffer, size, oft_info->fh.recvcsum);
 	}
 }
 
-static struct gaim_xfer *
-oscar_find_xfer_by_cookie(GSList *fts, const char *ck)
+static struct gaim_xfer *oscar_find_xfer_by_cookie(GSList *fts, const char *ck)
 {
 	struct gaim_xfer *xfer;
-	struct oscar_xfer_data *data;
+	struct aim_oft_info *oft_info;
 
 	while (fts) {
 		xfer = fts->data;
-		data = xfer->data;
-
-		if (data && !strcmp(data->cookie, ck))
+		oft_info = xfer->data;
+
+		if (oft_info && !strcmp(ck, oft_info->cookie))
 			return xfer;
 
 		fts = g_slist_next(fts);
@@ -1045,17 +957,16 @@
 	return NULL;
 }
 
-static struct gaim_xfer *
-oscar_find_xfer_by_conn(GSList *fts, aim_conn_t *conn)
+static struct gaim_xfer *oscar_find_xfer_by_conn(GSList *fts, aim_conn_t *conn)
 {
 	struct gaim_xfer *xfer;
-	struct oscar_xfer_data *data;
+	struct aim_oft_info *oft_info;
 
 	while (fts) {
 		xfer = fts->data;
-		data = xfer->data;
-
-		if (data && (conn == data->conn))
+		oft_info = xfer->data;
+
+		if (oft_info && (conn == oft_info->conn))
 			return xfer;
 
 		fts = g_slist_next(fts);
@@ -1066,28 +977,22 @@
 
 static void oscar_ask_sendfile(struct gaim_connection *gc, const char *destsn) {
 	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
+	struct gaim_xfer *xfer;
+	struct aim_oft_info *oft_info;
+	aim_conn_t *conn;
 
 	/* You want to send a file to someone else, you're so generous */
-	struct gaim_xfer *xfer;
-	struct oscar_xfer_data *xfer_data;
-
-	/* Create the oscar-specific data */
-	xfer_data = g_malloc0(sizeof(struct oscar_xfer_data));
-	xfer_data->gc = gc;
 
 	/* Build the file transfer handle */
 	xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, destsn);
-	xfer_data->xfer = xfer;
-	xfer->data = xfer_data;
-
-	/* Set the info about the incoming file */
-	if (od && od->sess) {
-		aim_conn_t *conn;
-		if ((conn = aim_conn_findbygroup(od->sess, 0x0004)))
-			xfer->local_ip = gaim_getip_from_fd(conn->fd);
-	}
+	if ((conn = aim_conn_findbygroup(od->sess, 0x0004)))
+		xfer->local_ip = gaim_getip_from_fd(conn->fd);
 	xfer->local_port = 5190;
 
+	/* Create the oscar-specific data */
+	oft_info = aim_oft_createinfo(od->sess, NULL, destsn, xfer->local_ip, xfer->local_port, 0, 0, NULL);
+	xfer->data = oft_info;
+
 	 /* Setup our I/O op functions */
 	gaim_xfer_set_init_fnc(xfer, oscar_xfer_init);
 	gaim_xfer_set_start_fnc(xfer, oscar_xfer_start);
@@ -1937,7 +1842,7 @@
 	struct gaim_connection *gc = sess->aux_data;
 	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
 	struct gaim_xfer *xfer;
-	struct oscar_xfer_data *xfer_data;
+	struct aim_oft_info *oft_info;
 	va_list ap;
 	aim_conn_t *conn, *listenerconn;
 
@@ -1950,22 +1855,22 @@
 	if (!(xfer = oscar_find_xfer_by_conn(od->file_transfers, listenerconn)))
 		return 1;
 
-	if (!(xfer_data = xfer->data))
+	if (!(oft_info = xfer->data))
 		return 1;
 
 	/* Stop watching listener conn; watch transfer conn instead */
 	gaim_input_remove(xfer->watcher);
 	aim_conn_kill(sess, &listenerconn);
 
-	xfer_data->conn = conn;
-	xfer->fd = xfer_data->conn->fd;
-
-	aim_conn_addhandler(sess, xfer_data->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_ACK, oscar_sendfile_ack, 0);
-	aim_conn_addhandler(sess, xfer_data->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DONE, oscar_sendfile_done, 0);
-	xfer->watcher = gaim_input_add(xfer_data->conn->fd, GAIM_INPUT_READ, oscar_callback, xfer_data->conn);
+	oft_info->conn = conn;
+	xfer->fd = oft_info->conn->fd;
+
+	aim_conn_addhandler(sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_ACK, oscar_sendfile_ack, 0);
+	aim_conn_addhandler(sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DONE, oscar_sendfile_done, 0);
+	xfer->watcher = gaim_input_add(oft_info->conn->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
 
 	/* Inform the other user that we are connected and ready to transfer */
-	aim_oft_sendheader(sess, xfer_data->conn, AIM_CB_OFT_PROMPT, NULL, xfer->filename, 0, 1,  xfer->size, xfer->size, time(NULL), xfer_data->checksum, 0x02, 0, 0);
+	aim_oft_sendheader(sess, AIM_CB_OFT_PROMPT, oft_info);
 
 	return 0;
 }
@@ -1975,28 +1880,25 @@
  * user in order to transfer a file.
  */
 static void oscar_sendfile_connected(gpointer data, gint source, GaimInputCondition condition) {
-	struct gaim_connection *gc;
 	struct gaim_xfer *xfer;
-	struct oscar_xfer_data *xfer_data;
+	struct aim_oft_info *oft_info;
 
 	debug_printf("AAA - in oscar_sendfile_connected\n");
 	if (!(xfer = data))
 		return;
-	if (!(xfer_data = xfer->data))
-		return;
-	if (!(gc = xfer_data->gc))
+	if (!(oft_info = xfer->data))
 		return;
 	if (source < 0)
 		return;
 
 	xfer->fd = source;
-	xfer_data->conn->fd = source;
-
-	aim_conn_completeconnect(xfer_data->conn->sessv, xfer_data->conn);
-	xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, xfer_data->conn);
+	oft_info->conn->fd = source;
+
+	aim_conn_completeconnect(oft_info->sess, oft_info->conn);
+	xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn);
 
 	/* Inform the other user that we are connected and ready to transfer */
-	aim_im_sendch2_sendfile_accept(xfer_data->conn->sessv, xfer_data->cookie, xfer->who, AIM_CAPS_SENDFILE);
+	aim_im_sendch2_sendfile_accept(oft_info->sess, oft_info);
 
 	return;
 }
@@ -2011,7 +1913,7 @@
 	struct gaim_connection *gc = sess->aux_data;
 	struct oscar_data *od = gc->proto_data;
 	struct gaim_xfer *xfer;
-	struct oscar_xfer_data *xfer_data;
+	struct aim_oft_info *oft_info;
 	va_list ap;
 	aim_conn_t *conn;
 	fu8_t *cookie;
@@ -2027,19 +1929,21 @@
 	if (!(xfer = oscar_find_xfer_by_conn(od->file_transfers, conn)))
 		return 1;
 
-	if (!(xfer_data = xfer->data))
+	if (!(oft_info = xfer->data))
 		return 1;
 
-	/* Jot down some data we'll need later */
-	xfer_data->modtime = fh->modtime;
-	xfer_data->checksum = fh->checksum;
-
 	/* We want to stop listening with a normal thingy */
 	gaim_input_remove(xfer->watcher);
 	xfer->watcher = 0;
 
+	/* They sent us some information about the file they're sending */
+	memcpy(&oft_info->fh, fh, sizeof(*fh));
+
+	/* Fill in the cookie */
+	memcpy(&oft_info->fh.bcookie, oft_info->cookie, 8);
+
 	/* XXX - convert the name from UTF-8 to UCS-2 if necessary, and pass the encoding to the call below */
-	aim_oft_sendheader(xfer_data->conn->sessv, xfer_data->conn, AIM_CB_OFT_ACK, xfer_data->cookie, xfer->filename, 0, 1, xfer->size, xfer->size, fh->modtime, fh->checksum, 0x02, 0, 0);
+	aim_oft_sendheader(oft_info->sess, AIM_CB_OFT_ACK, oft_info);
 	gaim_xfer_start(xfer, xfer->fd, NULL, 0);
 
 	return 0;
@@ -2301,12 +2205,14 @@
 		if (args->status == AIM_RENDEZVOUS_PROPOSE) {
 			/* Someone wants to send a file (or files) to us */
 			struct gaim_xfer *xfer;
-			struct oscar_xfer_data *xfer_data;
-
-			if (!args->cookie || !args->verifiedip || !args->port ||
-			    !args->info.sendfile.filename || !args->info.sendfile.totsize ||
+			struct aim_oft_info *oft_info;
+
+			if (!args->cookie || !args->port || !args->verifiedip || 
+			    !args->info.sendfile.filename || !args->info.sendfile.totsize || 
 			    !args->info.sendfile.totfiles || !args->reqclass) {
 				debug_printf("%s tried to send you a file with incomplete information.\n", userinfo->sn);
+				if (args->proxyip)
+					debug_printf("IP for a proxy server was given.  Gaim does not support this yet.\n");
 				return 1;
 			}
 
@@ -2320,27 +2226,20 @@
 				}
 			}
 
-			/* Setup the oscar-specific transfer xfer_data */
-			xfer_data = g_malloc0(sizeof(struct oscar_xfer_data));
-			xfer_data->gc = gc;
-			memcpy(xfer_data->cookie, args->cookie, 8);
-
 			/* Build the file transfer handle */
 			xfer = gaim_xfer_new(gc->account, GAIM_XFER_RECEIVE, userinfo->sn);
-			xfer_data->xfer = xfer;
-			xfer->data = xfer_data;
-
-			/* Set the info about the incoming file */
+			xfer->remote_ip = g_strdup(args->clientip);
+			xfer->remote_port = args->port;
 			gaim_xfer_set_filename(xfer, args->info.sendfile.filename);
 			gaim_xfer_set_size(xfer, args->info.sendfile.totsize);
-			xfer->remote_port = args->port;
-			xfer->remote_ip = g_strdup(args->verifiedip);
+
+			/* Create the oscar-specific data */
+			oft_info = aim_oft_createinfo(od->sess, args->cookie, userinfo->sn, xfer->remote_ip, xfer->remote_port, 0, 0, NULL);
 			if (args->proxyip)
-				xfer_data->proxyip = g_strdup(args->proxyip);
-			if (args->clientip)
-				xfer_data->clientip = g_strdup(args->clientip);
+				oft_info->proxyip = g_strdup(args->proxyip);
 			if (args->verifiedip)
-				xfer_data->verifiedip = g_strdup(args->verifiedip);
+				oft_info->verifiedip = g_strdup(args->verifiedip);
+			xfer->data = oft_info;
 
 			 /* Setup our I/O op functions */
 			gaim_xfer_set_init_fnc(xfer, oscar_xfer_init);
@@ -4703,12 +4602,12 @@
 					} else {
 						struct group *g;
 						buddy = gaim_buddy_new(gc->account, curitem->name, alias_utf8);
-						
+
 						if (!(g = gaim_find_group(gname_utf8 ? gname_utf8 : _("Orphans")))) {
 							g = gaim_group_new(gname_utf8 ? gname_utf8 : _("Orphans"));
 							gaim_blist_add_group(g, NULL);
 						}
-						
+
 						debug_printf("ssi: adding buddy %s to group %s to local list\n", curitem->name, gname_utf8 ? gname_utf8 : _("Orphans"));
 						gaim_blist_add_buddy(buddy, g, NULL);
 						export = TRUE;