diff src/protocols/oscar/im.c @ 11369:ab0fa7cd61cc

[gaim-migrate @ 13593] Bring all the changes to OSCAR file transfers from oldstatus to HEAD. Add documentation resulting from my Summer of Code project to CVS including the original editable files (in OpenOffice.org 2.0 format). committer: Tailor Script <tailor@pidgin.im>
author Jonathan Clark <ardentlygnarly>
date Tue, 30 Aug 2005 05:21:58 +0000
parents bcd7bd6a42dd
children 48244c196228
line wrap: on
line diff
--- a/src/protocols/oscar/im.c	Tue Aug 30 05:21:30 2005 +0000
+++ b/src/protocols/oscar/im.c	Tue Aug 30 05:21:58 2005 +0000
@@ -83,11 +83,11 @@
 		fu8_t data[10];
 	} fingerprints[] = {
 		/* AOL Mobile Communicator, WinAIM 1.0.414 */
-		{ AIM_CLIENTTYPE_MC,
+		{ AIM_CLIENTTYPE_MC, 
 		  3, {0x01, 0x01, 0x01}},
 
 		/* WinAIM 2.0.847, 2.1.1187, 3.0.1464, 4.3.2229, 4.4.2286 */
-		{ AIM_CLIENTTYPE_WINAIM,
+		{ AIM_CLIENTTYPE_WINAIM, 
 		  3, {0x01, 0x01, 0x02}},
 
 		/* WinAIM 4.1.2010, libfaim */
@@ -144,10 +144,10 @@
 	aimbs_put16(&fr->data, 0x0000);
 
 	/* These are all read-write */
-	aimbs_put32(&fr->data, params->flags);
+	aimbs_put32(&fr->data, params->flags); 
 	aimbs_put16(&fr->data, params->maxmsglen);
-	aimbs_put16(&fr->data, params->maxsenderwarn);
-	aimbs_put16(&fr->data, params->maxrecverwarn);
+	aimbs_put16(&fr->data, params->maxsenderwarn); 
+	aimbs_put16(&fr->data, params->maxrecverwarn); 
 	aimbs_put32(&fr->data, params->minmsginterval);
 
 	aim_tx_enqueue(sess, fr);
@@ -184,7 +184,7 @@
 	params.maxsenderwarn = aimbs_get16(bs);
 	params.maxrecverwarn = aimbs_get16(bs);
 	params.minmsginterval = aimbs_get32(bs);
-
+	
 	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
 		return userfunc(sess, rx, &params);
 
@@ -282,7 +282,7 @@
 	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128)))
 		return -ENOMEM;
 
-	/* XXX - should be optional */
+	/* XXX - should be optional */	
 	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1);
 	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
 
@@ -432,7 +432,7 @@
 	fu8_t *hdr;
 	int hdrlen;
 	aim_bstream_t hdrbs;
-
+	
 	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
 		return -EINVAL;
 
@@ -490,7 +490,7 @@
 	aim_tlvlist_add_str(&itl, 0x000c, msg);
 	aim_tlvlist_add_chatroom(&itl, 0x2711, exchange, roomname, instance);
 	aim_tlvlist_write(&hdrbs, &itl);
-
+	
 	aim_tlvlist_add_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr);
 
 	aim_tlvlist_write(&fr->data, &otl);
@@ -498,7 +498,7 @@
 	free(hdr);
 	aim_tlvlist_free(&itl);
 	aim_tlvlist_free(&otl);
-
+	
 	aim_tx_enqueue(sess, fr);
 
 	return 0;
@@ -731,7 +731,7 @@
 	aim_tlvlist_add_raw(&itl, 0x0003, 4, ip);
 	aim_tlvlist_add_16(&itl, 0x0005, port);
 	aim_tlvlist_add_noval(&itl, 0x000f);
-
+	
 	aim_tlvlist_write(&hdrbs, &itl);
 
 	aim_tlvlist_add_raw(&tl, 0x0005, aim_bstream_curpos(&hdrbs), hdr);
@@ -747,6 +747,22 @@
 	return 0;
 }
 
+/*
+ * Extracted from aim_im_sendch2_sendfile_ask
+ * Generates a random ICBM cookie in a character array of length 8
+ * and copies it into the variable passed as cookie
+ */
+faim_export void aim_im_makecookie(char* cookie) {
+	int i;
+	char gen_cookie[8];
+	
+	/* XXX - Should be like "21CBF95" and null terminated */
+	for (i = 0; i < 7; i++)
+		gen_cookie[i] = 0x30 + ((fu8_t)rand() % 10);
+	gen_cookie[7] = '\0';
+	memcpy(cookie, gen_cookie, 8);
+}
+
 /**
  * Subtype 0x0006 - Send an "I want to send you this file" message
  *
@@ -757,55 +773,112 @@
 	aim_frame_t *fr;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl=NULL, *subtl=NULL;
-	int i;
 
 	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)) || !oft_info)
 		return -EINVAL;
 
-	/* XXX - Should be like "21CBF95" and null terminated */
-	for (i = 0; i < 7; i++)
-		oft_info->cookie[i] = 0x30 + ((fu8_t)rand() % 10);
-	oft_info->cookie[7] = '\0';
+	/* The cookie must already have been generated by this point */
 
 	{ /* Create the subTLV chain */
 		fu8_t *buf;
 		int buflen;
 		aim_bstream_t bs;
-
-		aim_tlvlist_add_16(&subtl, 0x000a, 0x0001);
-		aim_tlvlist_add_noval(&subtl, 0x000f);
+		fu8_t ip[4];
+		fu8_t ip_comp[4]; /* The bitwise complement of the ip */
+		char *nexttoken;
+		int i;
+
+		/* In a stage 2 proxied transfer & a transfer redirect, we send a second "reply request"
+		 * Being the second request for this transfer, its request number is 2
+		 * You can fill in the blank for a stage 3's request number... */
+		if( (oft_info->send_or_recv == AIM_XFER_RECV && oft_info->stage == AIM_XFER_PROXY_STG2)
+			|| (oft_info->send_or_recv == AIM_XFER_RECV
+				&& oft_info->stage == AIM_XFER_PROXY_STG3)
+			|| oft_info->method == AIM_XFER_REDIR)
+			aim_tlvlist_add_16(&subtl, 0x000a, 0x0002);
+		else if(oft_info->send_or_recv == AIM_XFER_SEND && oft_info->stage == AIM_XFER_PROXY_STG3)
+			aim_tlvlist_add_16(&subtl, 0x000a, 0x0003);
+		else
+			aim_tlvlist_add_16(&subtl, 0x000a, 0x0001);
+			
+		/* This is usually necessary, but ruins a redirect and a stg3 proxy request */
+		if(!(oft_info->send_or_recv == AIM_XFER_RECV
+			&& (oft_info->method == AIM_XFER_REDIR || oft_info->stage == AIM_XFER_PROXY_STG3))) {
+			aim_tlvlist_add_noval(&subtl, 0x000f);
+		}
+		
+		/* If the following is ever enabled, ensure that it is not sent with a receive redirect
+		 * or stage 3 proxy redirect for a file receive (same conditions for sending 0x000f above) */
 /*		aim_tlvlist_add_raw(&subtl, 0x000e, 2, "en");
 		aim_tlvlist_add_raw(&subtl, 0x000d, 8, "us-ascii");
 		aim_tlvlist_add_raw(&subtl, 0x000c, 24, "Please accept this file."); */
 		/* XXX - Change oft_info->clientip to an array of 4 bytes */
 		if (oft_info->clientip) {
-			fu8_t ip[4];
-			char *nexttoken;
-			int i = 0;
+			i = 0;
 			nexttoken = strtok(oft_info->clientip, ".");
 			while (nexttoken && i<4) {
 				ip[i] = atoi(nexttoken);
+				ip_comp[i] = ~ip[i];
 				nexttoken = strtok(NULL, ".");
 				i++;
 			}
+			
+			/* If there is no proxyip, we must fill it in with the clientip */
+			if(!oft_info->proxyip) {
+				aim_tlvlist_add_raw(&subtl, 0x0002, 4, ip);
+				aim_tlvlist_add_raw(&subtl, 0x0016, 4, ip_comp); /* check? value */
+			}
+			
 			aim_tlvlist_add_raw(&subtl, 0x0003, 4, ip);
 		}
-		aim_tlvlist_add_16(&subtl, 0x0005, oft_info->port);
-
-		/* TLV t(2711) */
-		buflen = 2+2+4+strlen(oft_info->fh.name)+1;
-		buf = malloc(buflen);
-		aim_bstream_init(&bs, buf, buflen);
-		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 - NULL terminated, for some odd reason */
-		aimbs_putstr(&bs, oft_info->fh.name);
-		aimbs_put8(&bs, 0x00);
-
-		aim_tlvlist_add_raw(&subtl, 0x2711, bs.len, bs.data);
-		free(buf);
+		
+		/* Don't send the proxyip & accompanying info during a receive redirect or stg3 proxy request */
+		if(!(oft_info->send_or_recv == AIM_XFER_RECV
+			&& (oft_info->method == AIM_XFER_REDIR || oft_info->stage == AIM_XFER_PROXY_STG3))) {
+			if (oft_info->proxyip) { /* Generate the proxyip */
+				i = 0;
+				nexttoken = strtok(oft_info->proxyip, ".");
+				while (nexttoken && i<4) {
+					ip[i] = atoi(nexttoken);
+					ip_comp[i] = ~ip[i];
+					nexttoken = strtok(NULL, ".");
+					i++;
+				}
+				aim_tlvlist_add_raw(&subtl, 0x0002, 4, ip);
+				/* This zero-length TLV specifies a proxy will be used */
+				aim_tlvlist_add_noval(&subtl, 0x0010);
+				
+				/* Proxied transfers fail without this next (check?) value */
+				aim_tlvlist_add_raw(&subtl, 0x0016, 4, ip_comp);
+			}
+		}
+		
+		/* Don't send the port & its check during a stage 3 proxy request */
+		if(!(oft_info->send_or_recv == AIM_XFER_RECV && oft_info->stage == AIM_XFER_PROXY_STG3)) {
+			aim_tlvlist_add_16(&subtl, 0x0005, oft_info->port);
+			
+			/* Check value? Bitwise complement of the port */
+			aim_tlvlist_add_16(&subtl, 0x0017, ~(oft_info->port));
+		}
+
+		/* winAIM gets mad at us if we send too much info during a send redirect or stg3 proxy request */
+		if(!(oft_info->send_or_recv == AIM_XFER_RECV
+			&& (oft_info->method == AIM_XFER_REDIR || oft_info->stage == AIM_XFER_PROXY_STG3))) {
+			/* TLV t(2711) */
+			buflen = 2+2+4+strlen(oft_info->fh.name)+1;
+			buf = malloc(buflen);
+			aim_bstream_init(&bs, buf, buflen);
+			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 - NULL terminated, for some odd reason */
+			aimbs_putstr(&bs, oft_info->fh.name);
+			aimbs_put8(&bs, 0x00);
+	
+			aim_tlvlist_add_raw(&subtl, 0x2711, bs.len, bs.data);
+			free(buf);
+		}
 	}
 
 	{ /* Create the main TLV chain */
@@ -1143,7 +1216,7 @@
 		flag1 = aimbs_get16(&mbs);
 		flag2 = aimbs_get16(&mbs);
 
-		msg = aimbs_getraw(&mbs, msglen);
+		msg = aimbs_getstr(&mbs, msglen);
 	}
 
 	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
@@ -1202,8 +1275,8 @@
 
 static int mpmsg_addsection(aim_session_t *sess, aim_mpmsg_t *mpm, fu16_t charset, fu16_t charsubset, gchar *data, fu16_t datalen)
 {
-	aim_mpmsg_section_t *sec;
-
+	aim_mpmsg_section_t *sec; 
+	
 	if (!(sec = malloc(sizeof(aim_mpmsg_section_t))))
 		return -1;
 
@@ -1249,7 +1322,7 @@
 {
 	gchar *dup;
 
-	if (!(dup = strdup(ascii)))
+	if (!(dup = strdup(ascii))) 
 		return -1;
 
 	if (mpmsg_addsection(sess, mpm, 0x0000, 0x0000, dup, strlen(ascii)) == -1) {
@@ -1279,7 +1352,7 @@
 		free(buf);
 		return -1;
 	}
-
+	
 	return 0;
 }
 
@@ -1289,13 +1362,13 @@
 
 	for (cur = mpm->parts; cur; ) {
 		aim_mpmsg_section_t *tmp;
-
+		
 		tmp = cur->next;
 		free(cur->data);
 		free(cur);
 		cur = tmp;
 	}
-
+	
 	mpm->numparts = 0;
 	mpm->parts = NULL;
 
@@ -1733,6 +1806,9 @@
 		/* There is sometimes more after the null-terminated filename, 
 		 * but I'm unsure of its format. */
 		/* I don't believe him. */
+		/* There is sometimes a null byte inside a unicode filename,
+		 * but as far as I can tell the filename is the last
+		 * piece of data that will be in this message. --Jonathan */
 	}
 
 	return;
@@ -1847,8 +1923,15 @@
 	 * 0x0002 - "I will accept this file from you"
 	 * 0x0002 - Also used in ICQ Lite Beta 4.0 URLs
 	 */
+	 /*
+	  * This is what I call the request number of the file transfer
+	  * 0x0001 - Initial file transfer request for no proxy or stage 1 proxy
+	  * 0x0002 - "Reply request" for a stage 2 proxy (receiver wants to use proxy)
+	  * 0x0003 - A third request has been sent; applies only to stage 3 proxied transfers
+	  * -- Jonathan
+	  */
 	if (aim_tlv_gettlv(list2, 0x000a, 1))
-		;
+		args.info.sendfile.reqnum = aim_tlv_get16(list2, 0x000a, 1);
 
 	/*
 	 * Error code.
@@ -1869,7 +1952,7 @@
 	 */
 	if (aim_tlv_gettlv(list2, 0x000d, 1))
 		args.encoding = aim_tlv_getstr(list2, 0x000d, 1);
-
+	
 	/*
 	 * Language.
 	 */
@@ -1882,16 +1965,18 @@
 	 * Maybe means we should connect directly to transfer the file?
 	 * Also used in ICQ Lite Beta 4.0 URLs.  Also empty.
 	 */
+	 /* I don't think this indicates a direct transfer; this flag is
+	  * also present in a stage 1 proxied file send request -- Jonathan */
 	if (aim_tlv_gettlv(list2, 0x000f, 1))
 		;
 
 	/*
-	 * Unknown -- no value
-	 *
-	 * Maybe means we should proxy the file transfer through an AIM server?
+	 * Flag meaning we should proxy the file transfer through an AIM server
 	 */
 	if (aim_tlv_gettlv(list2, 0x0010, 1))
-		;
+		args.info.sendfile.use_proxy = TRUE;
+	else
+		args.info.sendfile.use_proxy = FALSE;
 
 	if (strlen(proxyip))
 		args.proxyip = (char *)proxyip;
@@ -2100,7 +2185,7 @@
 	snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, sn, strlen(sn)+1);
 	aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid);
 
-	aimbs_put16(&fr->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000);
+	aimbs_put16(&fr->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000); 
 	aimbs_put8(&fr->data, strlen(sn));
 	aimbs_putstr(&fr->data, sn);
 
@@ -2117,7 +2202,7 @@
 	fu16_t channel, nummissed, reason;
 	aim_userinfo_t userinfo;
 
-	while (aim_bstream_empty(bs)) {
+	while (aim_bstream_empty(bs)) {	
 
 		channel = aimbs_get16(bs);
 		aim_info_extract(sess, bs, &userinfo);
@@ -2140,7 +2225,7 @@
  *    AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support"
  *    AIM_TRANSFER_DENY_DECLINE -- "client has declined transfer"
  *    AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers"
- *
+ * 
  */
 faim_export int aim_im_denytransfer(aim_session_t *sess, const char *sender, const fu8_t *cookie, fu16_t code)
 {
@@ -2148,7 +2233,7 @@
 	aim_frame_t *fr;
 	aim_snacid_t snacid;
 	aim_tlvlist_t *tl = NULL;
-
+	
 	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
 		return -EINVAL;
 
@@ -2157,7 +2242,7 @@
 
 	snacid = aim_cachesnac(sess, 0x0004, 0x000b, 0x0000, NULL, 0);
 	aim_putsnac(&fr->data, 0x0004, 0x000b, 0x0000, snacid);
-
+	
 	aimbs_putraw(&fr->data, cookie, 8);
 
 	aimbs_put16(&fr->data, 0x0002); /* channel */