Exemplo n.º 1
0
static void
flap_connection_send_byte_stream(ByteStream *bs, FlapConnection *conn, size_t count)
{
	if (conn == NULL)
		return;

	/* Make sure we don't send past the end of the bs */
	if (count > byte_stream_empty(bs))
		count = byte_stream_empty(bs); /* truncate to remaining space */

	if (count == 0)
		return;

	/* Add everything to our outgoing buffer */
	purple_circ_buffer_append(conn->buffer_outgoing, bs->data, count);

	/* If we haven't already started writing stuff, then start the cycle */
	if (conn->watcher_outgoing == 0)
	{
		if (conn->gsc) {
			conn->watcher_outgoing = purple_input_add(conn->gsc->fd,
					PURPLE_INPUT_WRITE, send_cb, conn);
			send_cb(conn, -1, 0);
		} else if (conn->fd >= 0) {
			conn->watcher_outgoing = purple_input_add(conn->fd,
					PURPLE_INPUT_WRITE, send_cb, conn);
			send_cb(conn, -1, 0);
		}
	}
}
Exemplo n.º 2
0
int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int len)
{

	if (byte_stream_empty(srcbs) < len)
		return 0; /* XXX throw exception (underrun) */

	if (byte_stream_empty(bs) < len)
		return 0; /* XXX throw exception (overflow) */

	memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len);
	bs->offset += len;
	srcbs->offset += len;

	return len;
}
Exemplo n.º 3
0
guint32
aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len)
{
	guint32 flags = 0;
	int offset;

	for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x02) {
		guint8 *cap;
		int i, identified;

		cap = byte_stream_getraw(bs, 0x02);

		for (i = 0, identified = 0; !(aim_caps[i].flag & OSCAR_CAPABILITY_LAST); i++) {
			if (memcmp(&aim_caps[i].data[2], cap, 0x02) == 0) {
				flags |= aim_caps[i].flag;
				identified++;
				break; /* should only match once... */
			}
		}

		if (!identified)
			purple_debug_misc("oscar", "unknown short capability: {%02x%02x}\n", cap[0], cap[1]);

		g_free(cap);
	}

	return flags;
}
Exemplo n.º 4
0
int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int len)
{

	if (byte_stream_empty(bs) < len)
		return 0;

	byte_stream_getrawbuf_nocheck(bs, buf, len);
	return len;
}
Exemplo n.º 5
0
guint32 byte_stream_getle32(ByteStream *bs)
{

	if (byte_stream_empty(bs) < 4)
		return 0; /* XXX throw an exception */

	bs->offset += 4;

	return aimutil_getle32(bs->data + bs->offset - 4);
}
Exemplo n.º 6
0
int byte_stream_putle16(ByteStream *bs, guint16 v)
{

	if (byte_stream_empty(bs) < 2)
		return 0; /* XXX throw an exception */

	bs->offset += aimutil_putle16(bs->data + bs->offset, v);

	return 2;
}
Exemplo n.º 7
0
int byte_stream_putle32(ByteStream *bs, guint32 v)
{

	if (byte_stream_empty(bs) < 4)
		return 0; /* XXX throw an exception */

	bs->offset += aimutil_putle32(bs->data + bs->offset, v);

	return 1;
}
Exemplo n.º 8
0
/*
 * N can be negative, which can be used for going backwards
 * in a bstream.  I'm not sure if libfaim actually does
 * this anywhere...
 */
int byte_stream_advance(ByteStream *bs, int n)
{

	if ((byte_stream_curpos(bs) + n < 0) || (byte_stream_empty(bs) < n))
		return 0; /* XXX throw an exception */

	bs->offset += n;

	return n;
}
Exemplo n.º 9
0
guint16 byte_stream_getle16(ByteStream *bs)
{

	if (byte_stream_empty(bs) < 2)
		return 0; /* XXX throw an exception */

	bs->offset += 2;

	return aimutil_getle16(bs->data + bs->offset - 2);
}
Exemplo n.º 10
0
guint8 byte_stream_get8(ByteStream *bs)
{

	if (byte_stream_empty(bs) < 1)
		return 0; /* XXX throw an exception */

	bs->offset++;

	return aimutil_get8(bs->data + bs->offset - 1);
}
Exemplo n.º 11
0
int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int len)
{

	if (byte_stream_empty(bs) < len)
		return 0;

	memcpy(buf, bs->data + bs->offset, len);
	bs->offset += len;

	return len;
}
Exemplo n.º 12
0
int byte_stream_putraw(ByteStream *bs, const guint8 *v, int len)
{

	if (byte_stream_empty(bs) < len)
		return 0; /* XXX throw an exception */

	memcpy(bs->data + bs->offset, v, len);
	bs->offset += len;

	return len;
}
Exemplo n.º 13
0
/**
 * Read a TLV chain from a buffer.
 *
 * Reads and parses a series of TLV patterns from a data buffer; the
 * returned structure is manipulatable with the rest of the TLV
 * routines.  When done with a TLV chain, aim_tlvlist_free() should
 * be called to free the dynamic substructures.
 *
 * TODO: There should be a flag setable here to have the tlvlist contain
 * bstream references, so that at least the ->value portion of each
 * element doesn't need to be malloc/memcpy'd.  This could prove to be
 * just as efficient as the in-place TLV parsing used in a couple places
 * in libfaim.
 *
 * @param bs Input bstream
 * @return Return the TLV chain read
 */
GSList *aim_tlvlist_read(ByteStream *bs)
{
	GSList *list = NULL;

	while (byte_stream_empty(bs) > 0) {
		list = aim_tlv_read(list, bs);
		if (list == NULL)
			return NULL;
	}

	return g_slist_reverse(list);
}
Exemplo n.º 14
0
guint8 *byte_stream_getraw(ByteStream *bs, int len)
{
	guint8 *ob;

	if (byte_stream_empty(bs) < len)
		return NULL;

	ob = g_malloc(len);

	byte_stream_getrawbuf_nocheck(bs, ob, len);

	return ob;
}
Exemplo n.º 15
0
/**
 * Read a TLV chain from a buffer.
 *
 * Reads and parses a series of TLV patterns from a data buffer; the
 * returned structure is manipulatable with the rest of the TLV
 * routines.  When done with a TLV chain, aim_tlvlist_free() should
 * be called to free the dynamic substructures.
 *
 * TODO: There should be a flag setable here to have the tlvlist contain
 * bstream references, so that at least the ->value portion of each
 * element doesn't need to be malloc/memcpy'd.  This could prove to be
 * just as efficient as the in-place TLV parsing used in a couple places
 * in libfaim.
 *
 * @param bs Input bstream
 * @param num The max number of TLVs that will be read, or -1 if unlimited.
 *        There are a number of places where you want to read in a tlvchain,
 *        but the chain is not at the end of the SNAC, and the chain is
 *        preceded by the number of TLVs.  So you can limit that with this.
 * @return Return the TLV chain read
 */
GSList *aim_tlvlist_readnum(ByteStream *bs, guint16 num)
{
	GSList *list = NULL;

	while ((byte_stream_empty(bs) > 0) && (num != 0)) {
		list = aim_tlv_read(list, bs);
		if (list == NULL)
			return NULL;
		num--;
	}

	return g_slist_reverse(list);
}
Exemplo n.º 16
0
/**
 * Read a TLV chain from a buffer.
 *
 * Reads and parses a series of TLV patterns from a data buffer; the
 * returned structure is manipulatable with the rest of the TLV
 * routines.  When done with a TLV chain, aim_tlvlist_free() should
 * be called to free the dynamic substructures.
 *
 * TODO: There should be a flag setable here to have the tlvlist contain
 * bstream references, so that at least the ->value portion of each
 * element doesn't need to be malloc/memcpy'd.  This could prove to be
 * just as efficient as the in-place TLV parsing used in a couple places
 * in libfaim.
 *
 * @param bs Input bstream
 * @param len The max length in bytes that will be read.
 *        There are a number of places where you want to read in a tlvchain,
 *        but the chain is not at the end of the SNAC, and the chain is
 *        preceded by the length of the TLVs.  So you can limit that with this.
 * @return Return the TLV chain read
 */
GSList *aim_tlvlist_readlen(ByteStream *bs, guint16 len)
{
	GSList *list = NULL;

	while ((byte_stream_empty(bs) > 0) && (len > 0)) {
		list = aim_tlv_read(list, bs);
		if (list == NULL)
			return NULL;

		len -= 2 + 2 + ((aim_tlv_t *)list->data)->length;
	}

	return g_slist_reverse(list);
}
Exemplo n.º 17
0
char *byte_stream_getstr(ByteStream *bs, int len)
{
	char *ob;

	if (byte_stream_empty(bs) < len)
		return NULL;

	ob = g_malloc(len + 1);

	byte_stream_getrawbuf_nocheck(bs, (guint8 *)ob, len);

	ob[len] = '\0';

	return ob;
}
Exemplo n.º 18
0
static GSList *
aim_tlv_read(GSList *list, ByteStream *bs)
{
	guint16 type, length;
	aim_tlv_t *tlv;

	type = byte_stream_get16(bs);
	length = byte_stream_get16(bs);

#if 0
	/*
	 * This code hasn't been needed in years.  It's been commented
	 * out since 2003, at the latest.  It seems likely that it was
	 * just a bug in their server code that has since been fixed.
	 * In any case, here's the orignal comment, kept for historical
	 * purposes:
	 *
	 * Okay, so now AOL has decided that any TLV of
	 * type 0x0013 can only be two bytes, despite
	 * what the actual given length is.  So here
	 * we dump any invalid TLVs of that sort.  Hopefully
	 * there's no special cases to this special case.
	 *   - mid (30jun2000)
	 */
	if ((type == 0x0013) && (length != 0x0002)) {
		length = 0x0002;
		return list;
	}
#endif
	if (length > byte_stream_empty(bs)) {
		aim_tlvlist_free(list);
		return NULL;
	}

	tlv = createtlv(type, length, NULL);
	if (tlv->length > 0) {
		tlv->value = byte_stream_getraw(bs, length);
		if (!tlv->value) {
			freetlv(tlv);
			aim_tlvlist_free(list);
			return NULL;
		}
	}

	return g_slist_prepend(list, tlv);
}
Exemplo n.º 19
0
static void
parse_snac(OscarData *od, FlapConnection *conn, FlapFrame *frame)
{
	aim_module_t *cur;
	aim_modsnac_t snac;

	if (byte_stream_empty(&frame->data) < 10)
		return;

	snac.family = byte_stream_get16(&frame->data);
	snac.subtype = byte_stream_get16(&frame->data);
	snac.flags = byte_stream_get16(&frame->data);
	snac.id = byte_stream_get32(&frame->data);

	/* SNAC flags are apparently uniform across all SNACs, so we handle them here */
	if (snac.flags & 0x0001) {
		/*
		 * This means the SNAC will be followed by another SNAC with
		 * related information.  We don't need to do anything about
		 * this here.
		 */
	}
	if (snac.flags & 0x8000) {
		/*
		 * This packet contains the version of the family that this SNAC is
		 * in.  You get this when your SSI module is version 2 or higher.
		 * For now we have no need for this, but you could always save
		 * it as a part of aim_modnsac_t, or something.  The format is...
		 * 2 byte length of total mini-header (which is 6 bytes), then TLV
		 * of  type 0x0001, length 0x0002, value is the 2 byte version
		 * number
		 */
		byte_stream_advance(&frame->data, byte_stream_get16(&frame->data));
	}

	for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {

		if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
				(cur->family != snac.family))
			continue;

		if (cur->snachandler(od, conn, cur, frame, &snac, &frame->data))
			return;
	}
}
Exemplo n.º 20
0
int
byte_stream_putcaps(ByteStream *bs, guint32 caps)
{
	int i;

	if (!bs)
		return -EINVAL;

	for (i = 0; byte_stream_empty(bs); i++) {

		if (aim_caps[i].flag == OSCAR_CAPABILITY_LAST)
			break;

		if (caps & aim_caps[i].flag)
			byte_stream_putraw(bs, aim_caps[i].data, 0x10);

	}

	return 0;
}
Exemplo n.º 21
0
static void
parse_flap_ch4(OscarData *od, FlapConnection *conn, FlapFrame *frame)
{
	GSList *tlvlist;
	char *msg = NULL;

	if (byte_stream_empty(&frame->data) == 0) {
		/* XXX should do something with this */
		return;
	}

	/* An ICQ account is logging in */
	if (conn->type == SNAC_FAMILY_AUTH)
	{
		parse_fakesnac(od, conn, frame, 0x0017, 0x0003);
		return;
	}

	tlvlist = aim_tlvlist_read(&frame->data);

	if (aim_tlv_gettlv(tlvlist, 0x0009, 1))
		conn->disconnect_code = aim_tlv_get16(tlvlist, 0x0009, 1);

	if (aim_tlv_gettlv(tlvlist, 0x000b, 1))
		msg = aim_tlv_getstr(tlvlist, 0x000b, 1);

	/*
	 * The server ended this FLAP connnection, so let's be nice and
	 * close the physical TCP connection
	 */
	flap_connection_schedule_destroy(conn,
			OSCAR_DISCONNECT_REMOTE_CLOSED, msg);

	aim_tlvlist_free(tlvlist);

	g_free(msg);
}
Exemplo n.º 22
0
/*
 * AIM is fairly regular about providing user info.  This is a generic
 * routine to extract it in its standard form.
 */
int
aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *outinfo)
{
	int curtlv, tlvcnt;
	guint8 bnlen;

	if (!bs || !outinfo)
		return -EINVAL;

	/* Clear out old data first */
	memset(outinfo, 0x00, sizeof(aim_userinfo_t));

	/*
	 * Username.  Stored as an unterminated string prepended with a
	 * byte containing its length.
	 */
	bnlen = byte_stream_get8(bs);
	outinfo->bn = byte_stream_getstr(bs, bnlen);

	/*
	 * Warning Level.  Stored as an unsigned short.
	 */
	outinfo->warnlevel = byte_stream_get16(bs);

	/*
	 * TLV Count. Unsigned short representing the number of
	 * Type-Length-Value triples that follow.
	 */
	tlvcnt = byte_stream_get16(bs);

	/*
	 * Parse out the Type-Length-Value triples as they're found.
	 */
	for (curtlv = 0; curtlv < tlvcnt; curtlv++) {
		guint16 type, length;
		int endpos;

		type = byte_stream_get16(bs);
		length = byte_stream_get16(bs);

		endpos = byte_stream_curpos(bs) + MIN(length, byte_stream_empty(bs));

		if (type == 0x0001) {
			/*
			 * User flags
			 *
			 * Specified as any of the following ORed together:
			 *      0x0001  Unconfirmed account
			 *      0x0002  Unknown bit 2
			 *      0x0004  AOL Main Service user
			 *      0x0008  Unknown bit 4
			 *      0x0010  Free (AIM) user
			 *      0x0020  Away
			 *      0x0040  ICQ user (AIM bit also set)
			 *      0x0080  Mobile device
			 *      0x0400  Bot (like ActiveBuddy)
			 */
			outinfo->flags = byte_stream_get16(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_FLAGS;

		} else if (type == 0x0002) {
			/*
			 * Account creation time
			 *
			 * The time/date that the user originally registered for
			 * the service, stored in time_t format.
			 *
			 * I'm not sure how this differs from type 5 ("member
			 * since").
			 *
			 * Note: This is the field formerly known as "member
			 * since".  All these years and I finally found out
			 * that I got the name wrong.
			 */
			outinfo->createtime = byte_stream_get32(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_CREATETIME;

		} else if (type == 0x0003) {
			/*
			 * On-Since date
			 *
			 * The time/date that the user started their current
			 * session, stored in time_t format.
			 */
			outinfo->onlinesince = byte_stream_get32(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_ONLINESINCE;

		} else if (type == 0x0004) {
			/*
			 * Idle time
			 *
			 * Number of minutes since the user actively used the
			 * service.
			 *
			 * Note that the client tells the server when to start
			 * counting idle times, so this may or may not be
			 * related to reality.
			 */
			outinfo->idletime = byte_stream_get16(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_IDLE;

		} else if (type == 0x0005) {
			/*
			 * Member since date
			 *
			 * The time/date that the user originally registered for
			 * the service, stored in time_t format.
			 *
			 * This is sometimes sent instead of type 2 ("account
			 * creation time"), particularly in the self-info.
			 * And particularly for ICQ?
			 */
			outinfo->membersince = byte_stream_get32(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_MEMBERSINCE;

		} else if (type == 0x0006) {
			/*
			 * ICQ Online Status
			 *
			 * ICQ's Away/DND/etc "enriched" status. Some decoding
			 * of values done by Scott <*****@*****.**>
			 */
			byte_stream_get16(bs);
			outinfo->icqinfo.status = byte_stream_get16(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_ICQEXTSTATUS;

		} else if (type == 0x0008) {
			/*
			 * Client type, or some such.
			 */

		} else if (type == 0x000a) {
			/*
			 * ICQ User IP Address
			 *
			 * Ahh, the joy of ICQ security.
			 */
			outinfo->icqinfo.ipaddr = byte_stream_get32(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_ICQIPADDR;

		} else if (type == 0x000c) {
			/*
			 * Random crap containing the IP address,
			 * apparently a port number, and some Other Stuff.
			 *
			 * Format is:
			 * 4 bytes - Our IP address, 0xc0 a8 01 2b for 192.168.1.43
			 */
			byte_stream_getrawbuf(bs, outinfo->icqinfo.crap, 0x25);
			outinfo->present |= AIM_USERINFO_PRESENT_ICQDATA;

		} else if (type == 0x000d) {
			/*
			 * OSCAR Capability information
			 */
			outinfo->capabilities |= aim_locate_getcaps(od, bs, length);
			outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;

		} else if (type == 0x000e) {
			/*
			 * AOL capability information
			 */

		} else if ((type == 0x000f) || (type == 0x0010)) {
			/*
			 * Type = 0x000f: Session Length. (AIM)
			 * Type = 0x0010: Session Length. (AOL)
			 *
			 * The duration, in seconds, of the user's current
			 * session.
			 *
			 * Which TLV type this comes in depends on the
			 * service the user is using (AIM or AOL).
			 */
			outinfo->sessionlen = byte_stream_get32(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_SESSIONLEN;

		} else if (type == 0x0014) {
			/*
			 * My instance number.
			 */
			guint8 instance_number;
			instance_number = byte_stream_get8(bs);

		} else if (type == 0x0019) {
			/*
			 * OSCAR short capability information.  A shortened
			 * form of the normal capabilities.
			 */
			outinfo->capabilities |= aim_locate_getcaps_short(od, bs, length);
			outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;

		} else if (type == 0x001a) {
			/*
			 * Type = 0x001a
			 *
			 * AOL short capability information.  A shortened
			 * form of the normal capabilities.
			 */

		} else if (type == 0x001b) {
			/*
			 * Encryption certification MD5 checksum.
			 */

		} else if (type == 0x001d) {
			/*
			 * Buddy icon information and status/available messages.
			 *
			 * This almost seems like the AIM protocol guys gave
			 * the iChat guys a Type, and the iChat guys tried to
			 * cram as much cool shit into it as possible.  Then
			 * the Windows AIM guys were like, "hey, that's
			 * pretty neat, let's copy those prawns."
			 *
			 * In that spirit, this can contain a custom message,
			 * kind of like an away message, but you're not away
			 * (it's called an "available" message).  Or it can
			 * contain information about the buddy icon the user
			 * has stored on the server.
			 */
			guint16 type2;
			guint8 number2, length2;
			int endpos2;

			/*
			 * Continue looping as long as we're able to read type2,
			 * number2, and length2.
			 */
			while (byte_stream_curpos(bs) + 4 <= endpos) {
				type2 = byte_stream_get16(bs);
				number2 = byte_stream_get8(bs);
				length2 = byte_stream_get8(bs);

				endpos2 = byte_stream_curpos(bs) + MIN(length2, byte_stream_empty(bs));

				switch (type2) {
					case 0x0000: { /* This is an official buddy icon? */
						/* This is always 5 bytes of "0x02 01 d2 04 72"? */
					} break;

					case 0x0001: { /* A buddy icon checksum */
						if ((length2 > 0) && ((number2 == 0x00) || (number2 == 0x01))) {
							g_free(outinfo->iconcsum);
							outinfo->iconcsumtype = number2;
							outinfo->iconcsum = byte_stream_getraw(bs, length2);
							outinfo->iconcsumlen = length2;
						}
					} break;

					case 0x0002: { /* A status/available message */
						g_free(outinfo->status);
						g_free(outinfo->status_encoding);
						if (length2 >= 4) {
							outinfo->status_len = byte_stream_get16(bs);
							outinfo->status = byte_stream_getstr(bs, outinfo->status_len);
							if (byte_stream_get16(bs) == 0x0001) { /* We have an encoding */
								byte_stream_get16(bs);
								outinfo->status_encoding = byte_stream_getstr(bs, byte_stream_get16(bs));
							} else {
								/* No explicit encoding, client should use UTF-8 */
								outinfo->status_encoding = NULL;
							}
						} else {
							byte_stream_advance(bs, length2);
							outinfo->status_len = 0;
							outinfo->status = g_strdup("");
							outinfo->status_encoding = NULL;
						}
					} break;

					case 0x0009: { /* An iTunes Music Store link */
						g_free(outinfo->itmsurl);
						g_free(outinfo->itmsurl_encoding);
						if (length2 >= 4) {
							outinfo->itmsurl_len = byte_stream_get16(bs);
							outinfo->itmsurl = byte_stream_getstr(bs, outinfo->itmsurl_len);
							if (byte_stream_get16(bs) == 0x0001) {
								/* We have an encoding */
								byte_stream_get16(bs);
								outinfo->itmsurl_encoding = byte_stream_getstr(bs, byte_stream_get16(bs));
							} else {
								/* No explicit encoding, client should use UTF-8 */
								outinfo->itmsurl_encoding = NULL;
							}
						} else {
							byte_stream_advance(bs, length2);
							outinfo->itmsurl_len = 0;
							outinfo->itmsurl = g_strdup("");
							outinfo->itmsurl_encoding = NULL;
						}
					} break;
				}

				/* Save ourselves. */
				byte_stream_setpos(bs, endpos2);
			}

		} else if (type == 0x001e) {
			/*
			 * Always four bytes, but it doesn't look like an int.
			 */

		} else if (type == 0x001f) {
			/*
			 * Upper bytes of user flags.  Can be any size
			 *
			 * Seen on a buddy using DeadAIM.  Data was 4 bytes:
			 * 0x00 00 00 10
			 */

		} else if (type == 0x0023) {
			/*
			 * Last Buddy Feed update time, in seconds since the epoch.
			 */

		} else if (type == 0x0026) {
			/*
			 * Time that the profile was set, in seconds since the epoch.
			 */

		} else if (type == 0x0027) {
			/*
			 * Time that the away message was set, in seconds since the epoch.
			 */

		} else if (type == 0x002a) {
			/*
			 * Country code based on GeoIP data.
			 */

		} else {

			/*
			 * Reaching here indicates that either AOL has
			 * added yet another TLV for us to deal with,
			 * or the parsing has gone Terribly Wrong.
			 *
			 * Either way, inform the owner and attempt
			 * recovery.
			 *
			 */
#ifdef LOG_UNKNOWN_TLV
			purple_debug_misc("oscar", "userinfo: **warning: unexpected TLV:\n");
			purple_debug_misc("oscar", "userinfo:   bn    =%s\n", outinfo->bn);
			dumptlv(od, type, bs, length);
#endif
		}

		/* Save ourselves. */
		byte_stream_setpos(bs, endpos);
	}

	aim_locate_adduserinfo(od, outinfo);

	return 0;
}
Exemplo n.º 23
0
/**
 * Handle an incoming peer proxy negotiation frame.
 */
static void
peer_proxy_recv_frame(PeerConnection *conn, ProxyFrame *frame)
{
	purple_debug_info("oscar", "Incoming peer proxy frame with "
			"type=0x%04hx, unknown=0x%08x, "
			"flags=0x%04hx, and payload length=%hd\n", frame->type,
			frame->unknown, frame->flags, frame->payload.len);

	if (frame->type == PEER_PROXY_TYPE_CREATED)
	{
		/*
		 * Read in 2 byte port then 4 byte IP and tell the
		 * remote user to connect to it by sending an ICBM.
		 */
		guint16 pin;
		int i;
		guint8 ip[4];

		pin = byte_stream_get16(&frame->payload);
		for (i = 0; i < 4; i++)
			ip[i] = byte_stream_get8(&frame->payload);
		if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
			aim_im_sendch2_odc_requestproxy(conn->od,
					conn->cookie,
					conn->bn, ip, pin, ++conn->lastrequestnumber);
		else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
		{
			aim_im_sendch2_sendfile_requestproxy(conn->od,
					conn->cookie, conn->bn,
					ip, pin, ++conn->lastrequestnumber,
					(const gchar *)conn->xferdata.name,
					conn->xferdata.size, conn->xferdata.totfiles);
		}
	}
	else if (frame->type == PEER_PROXY_TYPE_READY)
	{
		purple_input_remove(conn->watcher_incoming);
		conn->watcher_incoming = 0;

		peer_connection_finalize_connection(conn);
	}
	else if (frame->type == PEER_PROXY_TYPE_ERROR)
	{
		if (byte_stream_empty(&frame->payload) >= 2)
		{
			guint16 error;
			const char *msg;
			error = byte_stream_get16(&frame->payload);
			if (error == 0x000d)
				msg = "bad request";
			else if (error == 0x0010)
				msg = "initial request timed out";
			else if (error == 0x001a)
				msg ="accept period timed out";
			else
				msg = "unknown reason";
			purple_debug_info("oscar", "Proxy negotiation failed with "
					"error 0x%04hx: %s\n", error, msg);
		}
		else
		{
			purple_debug_warning("oscar", "Proxy negotiation failed with "
					"an unknown error\n");
		}
		peer_connection_trynext(conn);
	}
	else
	{
		purple_debug_warning("oscar", "Unknown peer proxy frame type 0x%04hx.\n",
				frame->type);
	}
}