Example #1
0
/**
 * Subtype 0x0005 - Receive a buddy icon.
 *
 * This is sent in response to a buddy icon request.
 */
static int parseicon(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
	int ret = 0;
	aim_rxcallback_t userfunc;
	char *sn;
	fu16_t flags, iconlen;
	fu8_t iconcsumtype, iconcsumlen, *iconcsum, *icon;

	sn = aimbs_getstr(bs, aimbs_get8(bs));
	flags = aimbs_get16(bs);
	iconcsumtype = aimbs_get8(bs);
	iconcsumlen = aimbs_get8(bs);
	iconcsum = aimbs_getraw(bs, iconcsumlen);
	iconlen = aimbs_get16(bs);
	icon = aimbs_getraw(bs, iconlen);

	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
		ret = userfunc(sess, rx, sn, iconcsumtype, iconcsum, iconcsumlen, icon, iconlen);

	free(sn);
	free(iconcsum);
	free(icon);

	return ret;
}
Example #2
0
/*
 * Read a FLAP header from conn into fr, and return the number of bytes in the payload.
 */
static int aim_get_command_flap(aim_session_t *sess, aim_conn_t *conn,
	aim_frame_t *fr)
{
	fu8_t flaphdr_raw[6];
	aim_bstream_t flaphdr;
	fu16_t payloadlen;

	aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw));

	/*
	 * Read FLAP header.  Six bytes:
	 *   0 char  -- Always 0x2a
	 *   1 char  -- Channel ID.  Usually 2 -- 1 and 4 are used during login.
	 *   2 short -- Sequence number
	 *   4 short -- Number of data bytes that follow.
	 */
	if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) {
		aim_conn_close(conn);
		return -1;
	}

	aim_bstream_rewind(&flaphdr);

	/*
	 * This shouldn't happen unless the socket breaks, the server breaks,
	 * or we break.  We must handle it just in case.
	 */
	if (aimbs_get8(&flaphdr) != 0x2a) {
		fu8_t start;

		aim_bstream_rewind(&flaphdr);
		start = aimbs_get8(&flaphdr);
		faimdprintf(sess, 0, "FLAP framing disrupted (0x%02x)", start);
		aim_conn_close(conn);
		return -1;
	}

	/* we're doing FLAP if we're here */
	fr->hdrtype = AIM_FRAMETYPE_FLAP;

	fr->hdr.flap.type = aimbs_get8(&flaphdr);
	fr->hdr.flap.seqnum = aimbs_get16(&flaphdr);
	payloadlen = aimbs_get16(&flaphdr);	/* length of payload */

	return payloadlen;
}
Example #3
0
faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo)
{
	int namelen;

	if (!bs || !outinfo)
		return 0;

	outinfo->exchange = aimbs_get16(bs);
	namelen = aimbs_get8(bs);
	outinfo->name = aimbs_getstr(bs, namelen);
	outinfo->instance = aimbs_get16(bs);

	return 0;
}
Example #4
0
/**
 * Subtype 0x0003 - Acknowledgement for uploading a buddy icon.
 *
 * You get this honky after you upload a buddy icon.
 */
static int uploadack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
	int ret = 0;
	aim_rxcallback_t userfunc;
	fu16_t something, somethingelse;
	fu8_t onemorething;

	something = aimbs_get16(bs);
	somethingelse = aimbs_get16(bs);
	onemorething = aimbs_get8(bs);

	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
		ret = userfunc(sess, rx);

	return ret;
}
Example #5
0
faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...)
{
	int i;

	faimdprintf(sess, 1, "\nRecieved unknown packet:");

	for (i = 0; aim_bstream_empty(&frame->data); i++) {
		if ((i % 8) == 0)
			faimdprintf(sess, 1, "\n\t");

		faimdprintf(sess, 1, "0x%2x ", aimbs_get8(&frame->data));
	}

	faimdprintf(sess, 1, "\n\n");

	return 1;
}
Example #6
0
/*
 * Subtype 0x0014 - Receive a mini typing notification (mtn) packet.
 *
 * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, 
 * and Gaim 0.60 and newer.
 *
 */
static int mtn_receive(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
	int ret = 0;
	aim_rxcallback_t userfunc;
	char *sn;
	guint8 snlen;
	guint16 type1, type2;

	aim_bstream_advance(bs, 8); /* Unknown - All 0's */
	type1 = aimbs_get16(bs);
	snlen = aimbs_get8(bs);
	sn = aimbs_getstr(bs, snlen);
	type2 = aimbs_get16(bs);

	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
		ret = userfunc(sess, rx, type1, sn, type2);

	g_free(sn);

	return ret;
}
Example #7
0
static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
	aim_rxcallback_t userfunc;
	guint16 type;
	guint8 snlen, *ck;
	char *sn;
	int ret = 0;

	ck = aimbs_getraw(bs, 8);
	type = aimbs_get16(bs);
	snlen = aimbs_get8(bs);
	sn = aimbs_getstr(bs, snlen);

	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
		ret = userfunc(sess, rx, type, sn);

	g_free(sn);
	g_free(ck);

	return ret;
}
Example #8
0
static void dumptlv(aim_session_t *sess, fu16_t type, aim_bstream_t *bs, fu8_t len)
{
	int i;

	if (!sess || !bs || !len)
		return;

	faimdprintf(sess, 0, "userinfo:   type  =0x%04x\n", type);
	faimdprintf(sess, 0, "userinfo:   length=0x%04x\n", len);

	faimdprintf(sess, 0, "userinfo:   value:\n");

	for (i = 0; i < len; i++) {
		if ((i % 8) == 0)
			faimdprintf(sess, 0, "\nuserinfo:        ");

		faimdprintf(sess, 0, "0x%2x ", aimbs_get8(bs));
	}

	faimdprintf(sess, 0, "\n");

	return;
}
Example #9
0
/*
 * Grab a single command sequence off the socket, and enqueue
 * it in the incoming event queue in a seperate struct.
 */
faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn)
{
    fu8_t flaphdr_raw[6];
    aim_bstream_t flaphdr;
    aim_frame_t *newrx;
    fu16_t payloadlen;

    if (!sess || !conn)
        return 0;

    if (conn->fd == -1)
        return -1; /* its a aim_conn_close()'d connection */

    if (conn->fd < 3)  /* can happen when people abuse the interface */
        return 0;

    if (conn->status & AIM_CONN_STATUS_INPROGRESS)
        return aim_conn_completeconnect(sess, conn);

    /*
     * Rendezvous (client-client) connections do not speak
     * FLAP, so this function will break on them.
     */
    if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)
        return aim_get_command_rendezvous(sess, conn);
    else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
        faimdprintf(sess, 0, "AIM_CONN_TYPE_RENDEZVOUS_OUT on fd %d\n", conn->fd);
        return 0;
    }

    aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw));

    /*
     * Read FLAP header.  Six bytes:
     *
     *   0 char  -- Always 0x2a
     *   1 char  -- Channel ID.  Usually 2 -- 1 and 4 are used during login.
     *   2 short -- Sequence number
     *   4 short -- Number of data bytes that follow.
     */
    if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) {
        aim_conn_close(conn);
        return -1;
    }

    aim_bstream_rewind(&flaphdr);

    /*
     * This shouldn't happen unless the socket breaks, the server breaks,
     * or we break.  We must handle it just in case.
     */
    if (aimbs_get8(&flaphdr) != 0x2a) {
        fu8_t start;

        aim_bstream_rewind(&flaphdr);
        start = aimbs_get8(&flaphdr);
        faimdprintf(sess, 0, "FLAP framing disrupted (0x%02x)", start);
        aim_conn_close(conn);
        return -1;
    }

    /* allocate a new struct */
    if (!(newrx = (aim_frame_t *)malloc(sizeof(aim_frame_t))))
        return -1;
    memset(newrx, 0, sizeof(aim_frame_t));

    /* we're doing FLAP if we're here */
    newrx->hdrtype = AIM_FRAMETYPE_FLAP;

    newrx->hdr.flap.type = aimbs_get8(&flaphdr);
    newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr);
    payloadlen = aimbs_get16(&flaphdr);

    newrx->nofree = 0; /* free by default */

    if (payloadlen) {
        fu8_t *payload = NULL;

        if (!(payload = (fu8_t *) malloc(payloadlen))) {
            aim_frame_destroy(newrx);
            return -1;
        }

        aim_bstream_init(&newrx->data, payload, payloadlen);

        /* read the payload */
        if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) {
            free(payload);
            aim_frame_destroy(newrx);
            aim_conn_close(conn);
            return -1;
        }
    } else
        aim_bstream_init(&newrx->data, NULL, 0);


    aim_bstream_rewind(&newrx->data);

    newrx->conn = conn;

    newrx->next = NULL;  /* this will always be at the bottom */

    if (!sess->queue_incoming)
        sess->queue_incoming = newrx;
    else {
        aim_frame_t *cur;

        for (cur = sess->queue_incoming; cur->next; cur = cur->next)
            ;
        cur->next = newrx;
    }

    newrx->conn->lastactivity = time(NULL);

    return 0;
}
Example #10
0
/*
 * General room information.  Lots of stuff.
 *
 * Values I know are in here but I havent attached
 * them to any of the 'Unknown's:
 *	- Language (English)
 *
 * SNAC 000e/0002
 */
static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
	aim_userinfo_t *userinfo = NULL;
	aim_rxcallback_t userfunc;
	int ret = 0;
	int usercount = 0;
	fu8_t detaillevel = 0;
	char *roomname = NULL;
	struct aim_chat_roominfo roominfo;
	fu16_t tlvcount = 0;
	aim_tlvlist_t *tlvlist;
	char *roomdesc = NULL;
	fu16_t flags = 0;
	fu32_t creationtime = 0;
	fu16_t maxmsglen = 0, maxvisiblemsglen = 0;
	fu16_t unknown_d2 = 0, unknown_d5 = 0;

	aim_chat_readroominfo(bs, &roominfo);

	detaillevel = aimbs_get8(bs);

	if (detaillevel != 0x02) {
		faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel);
		return 1;
	}

	tlvcount = aimbs_get16(bs);

	/*
	 * Everything else are TLVs.
	 */ 
	tlvlist = aim_readtlvchain(bs);

	/*
	 * TLV type 0x006a is the room name in Human Readable Form.
	 */
	if (aim_gettlv(tlvlist, 0x006a, 1))
		roomname = aim_gettlv_str(tlvlist, 0x006a, 1);

	/*
	 * Type 0x006f: Number of occupants.
	 */
	if (aim_gettlv(tlvlist, 0x006f, 1))
		usercount = aim_gettlv16(tlvlist, 0x006f, 1);

	/*
	 * Type 0x0073:  Occupant list.
	 */
	if (aim_gettlv(tlvlist, 0x0073, 1)) {	
		int curoccupant = 0;
		aim_tlv_t *tmptlv;
		aim_bstream_t occbs;

		tmptlv = aim_gettlv(tlvlist, 0x0073, 1);

		/* Allocate enough userinfo structs for all occupants */
		userinfo = calloc(usercount, sizeof(aim_userinfo_t));

		aim_bstream_init(&occbs, tmptlv->value, tmptlv->length);

		while (curoccupant < usercount)
			aim_extractuserinfo(sess, &occbs, &userinfo[curoccupant++]);
	}

	/* 
	 * Type 0x00c9: Flags. (AIM_CHATROOM_FLAG)
	 */
	if (aim_gettlv(tlvlist, 0x00c9, 1))
		flags = aim_gettlv16(tlvlist, 0x00c9, 1);

	/* 
	 * Type 0x00ca: Creation time (4 bytes)
	 */
	if (aim_gettlv(tlvlist, 0x00ca, 1))
		creationtime = aim_gettlv32(tlvlist, 0x00ca, 1);

	/* 
	 * Type 0x00d1: Maximum Message Length
	 */
	if (aim_gettlv(tlvlist, 0x00d1, 1))
		maxmsglen = aim_gettlv16(tlvlist, 0x00d1, 1);

	/* 
	 * Type 0x00d2: Unknown. (2 bytes)
	 */
	if (aim_gettlv(tlvlist, 0x00d2, 1))
		unknown_d2 = aim_gettlv16(tlvlist, 0x00d2, 1);

	/* 
	 * Type 0x00d3: Room Description
	 */
	if (aim_gettlv(tlvlist, 0x00d3, 1))
		roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1);

	/*
	 * Type 0x000d4: Unknown (flag only)
	 */
	if (aim_gettlv(tlvlist, 0x000d4, 1))
		;

	/* 
	 * Type 0x00d5: Unknown. (1 byte)
	 */
	if (aim_gettlv(tlvlist, 0x00d5, 1))
		unknown_d5 = aim_gettlv8(tlvlist, 0x00d5, 1);


	/*
	 * Type 0x00d6: Encoding 1 ("us-ascii")
	 */
	if (aim_gettlv(tlvlist, 0x000d6, 1))
		;
	
	/*
	 * Type 0x00d7: Language 1 ("en")
	 */
	if (aim_gettlv(tlvlist, 0x000d7, 1))
		;

	/*
	 * Type 0x00d8: Encoding 2 ("us-ascii")
	 */
	if (aim_gettlv(tlvlist, 0x000d8, 1))
		;
	
	/*
	 * Type 0x00d9: Language 2 ("en")
	 */
	if (aim_gettlv(tlvlist, 0x000d9, 1))
		;

	/*
	 * Type 0x00da: Maximum visible message length
	 */
	if (aim_gettlv(tlvlist, 0x000da, 1))
		maxvisiblemsglen = aim_gettlv16(tlvlist, 0x00da, 1);

	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
		ret = userfunc(sess,
				rx, 
				&roominfo,
				roomname,
				usercount,
				userinfo,	
				roomdesc,
				flags,
				creationtime,
				maxmsglen,
				unknown_d2,
				unknown_d5,
				maxvisiblemsglen);
	}

	free(roominfo.name);
	free(userinfo);
	free(roomname);
	free(roomdesc);
	aim_freetlvchain(&tlvlist);

	return ret;
}
Example #11
0
/*
 * Grab a single command sequence off the socket, and enqueue
 * it in the incoming event queue in a seperate struct.
 */
int aim_get_command(aim_session_t *sess, aim_conn_t *conn)
{
	guint8 flaphdr_raw[6];
	aim_bstream_t flaphdr;
	aim_frame_t *newrx;
	guint16 payloadlen;
	
	if (!sess || !conn)
		return 0;

	if (conn->fd == -1)
		return -1; /* its a aim_conn_close()'d connection */

	/* KIDS, THIS IS WHAT HAPPENS IF YOU USE CODE WRITTEN FOR GUIS IN A DAEMON!
	   
	   And wouldn't it make sense to return something that prevents this function
	   from being called again IMMEDIATELY (and making the program suck up all
	   CPU time)?...
	   
	if (conn->fd < 3)
		return 0;
	*/

	if (conn->status & AIM_CONN_STATUS_INPROGRESS)
		return aim_conn_completeconnect(sess, conn);

	aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw));

	/*
	 * Read FLAP header.  Six bytes:
	 *    
	 *   0 char  -- Always 0x2a
	 *   1 char  -- Channel ID.  Usually 2 -- 1 and 4 are used during login.
	 *   2 short -- Sequence number 
	 *   4 short -- Number of data bytes that follow.
	 */
	if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) {
		aim_conn_close(conn);
		return -1;
	}

	aim_bstream_rewind(&flaphdr);

	/*
	 * This shouldn't happen unless the socket breaks, the server breaks,
	 * or we break.  We must handle it just in case.
	 */
	if (aimbs_get8(&flaphdr) != 0x2a) {
		aim_bstream_rewind(&flaphdr);
		aimbs_get8(&flaphdr);
		imcb_error(sess->aux_data, "FLAP framing disrupted");
		aim_conn_close(conn);
		return -1;
	}	

	/* allocate a new struct */
	if (!(newrx = (aim_frame_t *)g_new0(aim_frame_t,1)))
		return -1;

	/* we're doing FLAP if we're here */
	newrx->hdrtype = AIM_FRAMETYPE_FLAP;
	
	newrx->hdr.flap.type = aimbs_get8(&flaphdr);
	newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr);
	payloadlen = aimbs_get16(&flaphdr);

	newrx->nofree = 0; /* free by default */

	if (payloadlen) {
		guint8 *payload = NULL;

		if (!(payload = (guint8 *) g_malloc(payloadlen))) {
			aim_frame_destroy(newrx);
			return -1;
		}

		aim_bstream_init(&newrx->data, payload, payloadlen);

		/* read the payload */
		if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) {
			aim_frame_destroy(newrx); /* free's payload */
			aim_conn_close(conn);
			return -1;
		}
	} else
		aim_bstream_init(&newrx->data, NULL, 0);


	aim_bstream_rewind(&newrx->data);

	newrx->conn = conn;

	newrx->next = NULL;  /* this will always be at the bottom */

	if (!sess->queue_incoming)
		sess->queue_incoming = newrx;
	else {
		aim_frame_t *cur;

		for (cur = sess->queue_incoming; cur->next; cur = cur->next)
			;
		cur->next = newrx;
	}

	newrx->conn->lastactivity = time(NULL);

	return 0;  
}
Example #12
0
/*
 * Receive the response from an ICQ status message request.  This contains the 
 * ICQ status message.  Go figure.
 */
static int clientautoresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
	int ret = 0;
	aim_rxcallback_t userfunc;
	guint16 channel, reason;
	char *sn;
	guint8 *ck, snlen;

	ck = aimbs_getraw(bs, 8);
	channel = aimbs_get16(bs);
	snlen = aimbs_get8(bs);
	sn = aimbs_getstr(bs, snlen);
	reason = aimbs_get16(bs);

	switch (reason) {
		case 0x0003: { /* ICQ status message.  Maybe other stuff too, you never know with these people. */
			guint8 statusmsgtype, *msg;
			guint16 len;
			guint32 state;

			len = aimbs_getle16(bs); /* Should be 0x001b */
			aim_bstream_advance(bs, len); /* Unknown */

			len = aimbs_getle16(bs); /* Should be 0x000e */
			aim_bstream_advance(bs, len); /* Unknown */

			statusmsgtype = aimbs_getle8(bs);
			switch (statusmsgtype) {
				case 0xe8:
					state = AIM_ICQ_STATE_AWAY;
					break;
				case 0xe9:
					state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY;
					break;
				case 0xea:
					state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_OUT;
					break;
				case 0xeb:
					state = AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY;
					break;
				case 0xec:
					state = AIM_ICQ_STATE_CHAT;
					break;
				default:
					state = 0;
					break;
			}

			aimbs_getle8(bs); /* Unknown - 0x03 Maybe this means this is an auto-reply */
			aimbs_getle16(bs); /* Unknown - 0x0000 */
			aimbs_getle16(bs); /* Unknown - 0x0000 */

			len = aimbs_getle16(bs);
			msg = aimbs_getraw(bs, len);

			if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
				ret = userfunc(sess, rx, channel, sn, reason, state, msg);

			g_free(msg);
		} break;

		default: {
			if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
				ret = userfunc(sess, rx, channel, sn, reason);
		} break;
	} /* end switch */

	g_free(ck);
	g_free(sn);

	return ret;
}
Example #13
0
/*
 * Subtype 0x0006
 *
 * We could probably include this in the normal ICBM parsing 
 * code as channel 0x0003, however, since only the start
 * would be the same, we might as well do it here.
 *
 * General outline of this SNAC:
 *   snac
 *   cookie
 *   channel id
 *   tlvlist
 *     unknown
 *     source user info
 *       name
 *       evility
 *       userinfo tlvs
 *         online time
 *         etc
 *     message metatlv
 *       message tlv
 *         message string
 *       possibly others
 *  
 */
static int incomingim_ch3(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
	int ret = 0, i;
	aim_rxcallback_t userfunc;	
	aim_userinfo_t userinfo;
	fu8_t cookie[8];
	fu16_t channel;
	aim_tlvlist_t *otl;
	char *msg = NULL;
	int len = 0;
	char *encoding = NULL, *language = NULL;
	aim_msgcookie_t *ck;

	memset(&userinfo, 0, sizeof(aim_userinfo_t));

	/*
	 * Read ICBM Cookie.
	 */
	for (i = 0; i < 8; i++)
		cookie[i] = aimbs_get8(bs);

	if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) {
		free(ck->data);
		free(ck);
	}

	/*
	 * Channel ID
	 *
	 * Channel 0x0003 is used for chat messages.
	 *
	 */
	channel = aimbs_get16(bs);

	if (channel != 0x0003) {
		faimdprintf(sess, 0, "faim: chat_incoming: unknown channel! (0x%04x)\n", channel);
		return 0;
	}

	/*
	 * Start parsing TLVs right away. 
	 */
	otl = aim_tlvlist_read(bs);

	/*
	 * Type 0x0003: Source User Information
	 */
	if (aim_tlv_gettlv(otl, 0x0003, 1)) {
		aim_tlv_t *userinfotlv;
		aim_bstream_t tbs;

		userinfotlv = aim_tlv_gettlv(otl, 0x0003, 1);

		aim_bstream_init(&tbs, userinfotlv->value, userinfotlv->length);
		aim_info_extract(sess, &tbs, &userinfo);
	}

	/*
	 * Type 0x0001: If present, it means it was a message to the 
	 * room (as opposed to a whisper).
	 */
	if (aim_tlv_gettlv(otl, 0x0001, 1))
		;

	/*
	 * Type 0x0005: Message Block.  Conains more TLVs.
	 */
	if (aim_tlv_gettlv(otl, 0x0005, 1)) {
		aim_tlvlist_t *itl;
		aim_tlv_t *msgblock;
		aim_bstream_t tbs;

		msgblock = aim_tlv_gettlv(otl, 0x0005, 1);
		aim_bstream_init(&tbs, msgblock->value, msgblock->length);
		itl = aim_tlvlist_read(&tbs);

		/* 
		 * Type 0x0001: Message.
		 */	
		if (aim_tlv_gettlv(itl, 0x0001, 1)) {
			msg = aim_tlv_getstr(itl, 0x0001, 1);
			len = aim_tlv_gettlv(itl, 0x0001, 1)->length;
		}

		/*
		 * Type 0x0002: Encoding.
		 */	
		if (aim_tlv_gettlv(itl, 0x0002, 1))
			encoding = aim_tlv_getstr(itl, 0x0002, 1);

		/*
		 * Type 0x0003: Language.
		 */	
		if (aim_tlv_gettlv(itl, 0x0003, 1))
			language = aim_tlv_getstr(itl, 0x0003, 1);

		aim_tlvlist_free(&itl); 
	}

	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
		ret = userfunc(sess, rx, &userinfo, len, msg, encoding, language);

	aim_info_free(&userinfo);
	free(msg);
	aim_tlvlist_free(&otl);

	return ret;
}
Example #14
0
/*
 * AIM is fairly regular about providing user info.  This is a generic 
 * routine to extract it in its standard form.
 */
faim_internal int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *outinfo)
{
	int curtlv, tlvcnt;
	fu8_t snlen;

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

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

	/*
	 * Screen name.  Stored as an unterminated string prepended with a 
	 * byte containing its length.
	 */
	snlen = aimbs_get8(bs);
	aimbs_getrawbuf(bs, outinfo->sn, snlen);

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

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

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

		type = aimbs_get16(bs);
		length = aimbs_get16(bs);

		endpos = aim_bstream_curpos(bs) + length;

		if (type == 0x0001) {
			/*
			 * Type = 0x0001: User flags
			 * 
			 * Specified as any of the following ORed together:
			 *      0x0001  Trial (user less than 60days)
			 *      0x0002  Unknown bit 2
			 *      0x0004  AOL Main Service user
			 *      0x0008  Unknown bit 4
			 *      0x0010  Free (AIM) user 
			 *      0x0020  Away
			 *      0x0400  ActiveBuddy
			 *
			 */
			outinfo->flags = aimbs_get16(bs);

		} else if (type == 0x0002) {
			/*
			 * Type = 0x0002: Member-Since date. 
			 *
			 * The time/date that the user originally registered for
			 * the service, stored in time_t format.
			 */
			outinfo->membersince = aimbs_get32(bs);

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

		} else if (type == 0x0004) {
			/*
			 * Type = 0x0004: Idle time.
			 *
			 * Number of seconds 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 = aimbs_get16(bs);

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

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

		} else if (type == 0x000c) {
			/* 
			 * Type = 0x000c
			 *
			 * random crap containing the IP address,
			 * apparently a port number, and some Other Stuff.
			 *
			 */
			aimbs_getrawbuf(bs, outinfo->icqinfo.crap, 0x25);

		} else if (type == 0x000d) {
			/*
			 * Type = 0x000d
			 *
			 * Capability information.
			 *
			 */
			outinfo->capabilities = aim_getcap(sess, bs, length);
			outinfo->capspresent = 1;

		} else if (type == 0x000e) {
			/*
			 * Type = 0x000e
			 *
			 * Unknown.  Always of zero length, and always only
			 * on AOL users.
			 *
			 * Ignore.
			 *
			 */

		} 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 = aimbs_get32(bs);

		} 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.
			 *
			 */
			faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV:\n");
			faimdprintf(sess, 0, "userinfo:   sn    =%s\n", outinfo->sn);
			faimdprintf(sess, 0, "userinfo:   type  =0x%04x\n",type);
			faimdprintf(sess, 0, "userinfo:   length=0x%04x\n", length);

		}

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

	return 0;
}
Example #15
0
static int incomingim_ch1(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, aim_bstream_t *bs, guint8 *cookie)
{
	guint16 type, length;
	aim_rxcallback_t userfunc;
	int ret = 0;
	struct aim_incomingim_ch1_args args;
	int endpos;

	memset(&args, 0, sizeof(args));

	aim_mpmsg_init(sess, &args.mpmsg);

	/*
	 * This used to be done using tlvchains.  For performance reasons,
	 * I've changed it to process the TLVs in-place.  This avoids lots
	 * of per-IM memory allocations.
	 */
	while (aim_bstream_empty(bs)) {

		type = aimbs_get16(bs);
		length = aimbs_get16(bs);

		endpos = aim_bstream_curpos(bs) + length;

		if (type == 0x0002) { /* Message Block */

			/*
			 * This TLV consists of the following:
			 *   - 0501 -- Unknown
			 *   - Features: Don't know how to interpret these
			 *   - 0101 -- Unknown
			 *   - Message
			 *
			 */

			aimbs_get8(bs); /* 05 */
			aimbs_get8(bs); /* 01 */

			args.featureslen = aimbs_get16(bs);
			/* XXX XXX this is all evil! */
			args.features = bs->data + bs->offset;
			aim_bstream_advance(bs, args.featureslen);
			args.icbmflags |= AIM_IMFLAGS_CUSTOMFEATURES;

			/*
			 * The rest of the TLV contains one or more message
			 * blocks...
			 */
			incomingim_ch1_parsemsgs(sess, bs->data + bs->offset /* XXX evil!!! */, length - 2 - 2 - args.featureslen, &args);

		} else if (type == 0x0003) { /* Server Ack Requested */

			args.icbmflags |= AIM_IMFLAGS_ACK;

		} else if (type == 0x0004) { /* Message is Auto Response */

			args.icbmflags |= AIM_IMFLAGS_AWAY;

		} else if (type == 0x0006) { /* Message was received offline. */

			/* XXX not sure if this actually gets sent. */
			args.icbmflags |= AIM_IMFLAGS_OFFLINE;

		} else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */

			args.iconlen = aimbs_get32(bs);
			aimbs_get16(bs); /* 0x0001 */
			args.iconsum = aimbs_get16(bs);
			args.iconstamp = aimbs_get32(bs);

			/*
			 * This looks to be a client bug.  MacAIM 4.3 will
			 * send this tag, but with all zero values, in the
			 * first message of a conversation. This makes no
			 * sense whatsoever, so I'm going to say its a bug.
			 *
			 * You really shouldn't advertise a zero-length icon
			 * anyway.
			 * 
			 */
			if (args.iconlen)
				args.icbmflags |= AIM_IMFLAGS_HASICON;

		} else if (type == 0x0009) {

			args.icbmflags |= AIM_IMFLAGS_BUDDYREQ;

		} else if (type == 0x0017) {

			args.extdatalen = length;
			args.extdata = aimbs_getraw(bs, args.extdatalen);

		} else {
			// imcb_error(sess->aux_data, "Unknown TLV encountered");
		}

		/*
		 * This is here to protect ourselves from ourselves.  That
		 * is, if something above doesn't completly parse its value
		 * section, or, worse, overparses it, this will set the
		 * stream where it needs to be in order to land on the next
		 * TLV when the loop continues.
		 *
		 */
		aim_bstream_setpos(bs, endpos);
	}


	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
		ret = userfunc(sess, rx, channel, userinfo, &args);

	aim_mpmsg_free(sess, &args.mpmsg);
	g_free(args.extdata);

	return ret;
}
Example #16
0
/*
 * Start by building the multipart structures, then pick the first 
 * human-readable section and stuff it into args->msg so no one gets
 * suspicious.
 *
 */
static int incomingim_ch1_parsemsgs(aim_session_t *sess, guint8 *data, int len, struct aim_incomingim_ch1_args *args)
{
	static const guint16 charsetpri[] = {
		0x0000, /* ASCII first */
		0x0003, /* then ISO-8859-1 */
		0x0002, /* UNICODE as last resort */
	};
	static const int charsetpricount = 3;
	int i;
	aim_bstream_t mbs;
	aim_mpmsg_section_t *sec;

	aim_bstream_init(&mbs, data, len);

	while (aim_bstream_empty(&mbs)) {
		guint16 msglen, flag1, flag2;
		char *msgbuf;

		aimbs_get8(&mbs); /* 01 */
		aimbs_get8(&mbs); /* 01 */

		/* Message string length, including character set info. */
		msglen = aimbs_get16(&mbs);

		/* Character set info */
		flag1 = aimbs_get16(&mbs);
		flag2 = aimbs_get16(&mbs);

		/* Message. */
		msglen -= 4;

		/*
		 * For now, we don't care what the encoding is.  Just copy
		 * it into a multipart struct and deal with it later. However,
		 * always pad the ending with a NULL.  This makes it easier
		 * to treat ASCII sections as strings.  It won't matter for
		 * UNICODE or binary data, as you should never read past
		 * the specified data length, which will not include the pad.
		 *
		 * XXX There's an API bug here.  For sending, the UNICODE is
		 * given in host byte order (aim_mpmsg_addunicode), but here
		 * the received messages are given in network byte order.
		 *
		 */
		msgbuf = aimbs_getstr(&mbs, msglen);
		mpmsg_addsection(sess, &args->mpmsg, flag1, flag2, (guint8 *)msgbuf, (guint16) msglen);

	} /* while */

	args->icbmflags |= AIM_IMFLAGS_MULTIPART; /* always set */

	/*
	 * Clients that support multiparts should never use args->msg, as it
	 * will point to an arbitrary section.
	 *
	 * Here, we attempt to provide clients that do not support multipart
	 * messages with something to look at -- hopefully a human-readable
	 * string.  But, failing that, a UNICODE message, or nothing at all.
	 *
	 * Which means that even if args->msg is NULL, it does not mean the
	 * message was blank.
	 *
	 */
	for (i = 0; i < charsetpricount; i++) {
		for (sec = args->mpmsg.parts; sec; sec = sec->next) {

			if (sec->charset != charsetpri[i])
				continue;

			/* Great. We found one.  Fill it in. */
			args->charset = sec->charset;
			args->charsubset = sec->charsubset;
			args->icbmflags |= AIM_IMFLAGS_CUSTOMCHARSET;

			/* Set up the simple flags */
			if (args->charset == 0x0000)
				; /* ASCII */
			else if (args->charset == 0x0002)
				args->icbmflags |= AIM_IMFLAGS_UNICODE;
			else if (args->charset == 0x0003)
				args->icbmflags |= AIM_IMFLAGS_ISO_8859_1;
			else if (args->charset == 0xffff)
				; /* no encoding (yeep!) */

			if (args->charsubset == 0x0000)
				; /* standard subencoding? */
			else if (args->charsubset == 0x000b)
				args->icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH;
			else if (args->charsubset == 0xffff)
				; /* no subencoding */
#if 0
			/* XXX this isn't really necesary... */	
			if (	((args.flag1 != 0x0000) &&
				 (args.flag1 != 0x0002) &&
				 (args.flag1 != 0x0003) &&
				 (args.flag1 != 0xffff)) ||
				((args.flag2 != 0x0000) &&
				 (args.flag2 != 0x000b) &&
				 (args.flag2 != 0xffff))) {
				faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", args.flag1, args.flag2);
			}
#endif

			args->msg = (char *)sec->data;
			args->msglen = sec->datalen;

			return 0;
		}
	}

	/* No human-readable sections found.  Oh well. */
	args->charset = args->charsubset = 0xffff;
	args->msg = NULL;
	args->msglen = 0;

	return 0;
}
Example #17
0
static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
	int i, ret = 0;
	aim_rxcallback_t userfunc;
	guint16 channel;
	aim_tlvlist_t *tlvlist;
	char *sn;
	int snlen;
	guint16 icbmflags = 0;
	guint8 flag1 = 0, flag2 = 0;
	char *msg = NULL;
	aim_tlv_t *msgblock;

	/* ICBM Cookie. */
	for (i = 0; i < 8; i++)
		aimbs_get8(bs);

	/* Channel ID */
	channel = aimbs_get16(bs);

	if (channel != 0x01) {
		imcb_error(sess->aux_data, "icbm: ICBM received on unsupported channel.  Ignoring.");
		return 0;
	}

	snlen = aimbs_get8(bs);
	sn = aimbs_getstr(bs, snlen);

	tlvlist = aim_readtlvchain(bs);

	if (aim_gettlv(tlvlist, 0x0003, 1))
		icbmflags |= AIM_IMFLAGS_ACK;
	if (aim_gettlv(tlvlist, 0x0004, 1))
		icbmflags |= AIM_IMFLAGS_AWAY;

	if ((msgblock = aim_gettlv(tlvlist, 0x0002, 1))) {
		aim_bstream_t mbs;
		int featurelen, msglen;

		aim_bstream_init(&mbs, msgblock->value, msgblock->length);

		aimbs_get8(&mbs);
		aimbs_get8(&mbs);
		for (featurelen = aimbs_get16(&mbs); featurelen; featurelen--)
			aimbs_get8(&mbs);
		aimbs_get8(&mbs);
		aimbs_get8(&mbs);

		msglen = aimbs_get16(&mbs) - 4; /* final block length */

		flag1 = aimbs_get16(&mbs);
		flag2 = aimbs_get16(&mbs);

		msg = aimbs_getstr(&mbs, msglen);
	}

	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
		ret = userfunc(sess, rx, channel, sn, msg, icbmflags, flag1, flag2);

	g_free(sn);
	aim_freetlvchain(&tlvlist);

	return ret;
}
Example #18
0
/*
 * AIM is fairly regular about providing user info.  This is a generic 
 * routine to extract it in its standard form.
 */
faim_internal int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, aim_userinfo_t *outinfo)
{
	int curtlv, tlvcnt;
	fu8_t snlen;

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

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

	/*
	 * Screen name.  Stored as an unterminated string prepended with a 
	 * byte containing its length.
	 */
	snlen = aimbs_get8(bs);
	aimbs_getrawbuf(bs, outinfo->sn, snlen);

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

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

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

		type = aimbs_get16(bs);
		length = aimbs_get16(bs);

		endpos = aim_bstream_curpos(bs) + length;

		if (type == 0x0001) {
			/*
			 * Type = 0x0001: User flags
			 * 
			 * Specified as any of the following ORed together:
			 *      0x0001  Trial (user less than 60days)
			 *      0x0002  Unknown bit 2
			 *      0x0004  AOL Main Service user
			 *      0x0008  Unknown bit 4
			 *      0x0010  Free (AIM) user 
			 *      0x0020  Away
			 *      0x0400  ActiveBuddy
			 *
			 */
			outinfo->flags = aimbs_get16(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_FLAGS;

		} else if (type == 0x0002) {
			/*
			 * 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 = aimbs_get32(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_CREATETIME;

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

		} else if (type == 0x0004) {
			/*
			 * Type = 0x0004: Idle time.
			 *
			 * Number of seconds 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 = aimbs_get16(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_IDLE;

		} else if (type == 0x0005) {
			/*
			 * 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.
			 */
			outinfo->membersince = aimbs_get32(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_MEMBERSINCE;

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

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

		} else if (type == 0x000c) {
			/* 
			 * Type = 0x000c
			 *
			 * random crap containing the IP address,
			 * apparently a port number, and some Other Stuff.
			 *
			 */
			aimbs_getrawbuf(bs, outinfo->icqinfo.crap, 0x25);
			outinfo->present |= AIM_USERINFO_PRESENT_ICQDATA;

		} else if (type == 0x000d) {
			/*
			 * Type = 0x000d
			 *
			 * Capability information.
			 *
			 */
			outinfo->capabilities = aim_getcap(sess, bs, length);
			outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;

		} else if (type == 0x000e) {
			/*
			 * Type = 0x000e
			 *
			 * Unknown.  Always of zero length, and always only
			 * on AOL users.
			 *
			 * Ignore.
			 *
			 */

		} 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 = aimbs_get32(bs);
			outinfo->present |= AIM_USERINFO_PRESENT_SESSIONLEN;

		} else if (type == 0x001d) {
			/*
			 * Type 29: Unknown.
			 *
			 * Currently very rare. Always 18 bytes of mostly zero.
			 */

		} else if (type == 0x001e) {
			/*
			 * Type 30: Unknown.
			 *
			 * Always four bytes, but it doesn't look like an int.
			 */
		} 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.
			 *
			 */
			faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV:\n");
			faimdprintf(sess, 0, "userinfo:   sn    =%s\n", outinfo->sn);
			dumptlv(sess, type, bs, length);
		}

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

	return 0;
}
Example #19
0
static int parseinfo_create(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs, aim_snac_t *snac2)
{
	aim_rxcallback_t userfunc;
	aim_tlvlist_t *tlvlist, *innerlist;
	char *ck = NULL, *fqcn = NULL, *name = NULL;
	fu16_t exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0;
	fu32_t createtime = 0;
	fu8_t createperms = 0, detaillevel;
	int cklen;
	aim_tlv_t *bigblock;
	int ret = 0;
	aim_bstream_t bbbs;

	tlvlist = aim_readtlvchain(bs);

	if (!(bigblock = aim_gettlv(tlvlist, 0x0004, 1))) {
		faimdprintf(sess, 0, "no bigblock in top tlv in create room response\n");
		aim_freetlvchain(&tlvlist);
		return 0;
	}

	aim_bstream_init(&bbbs, bigblock->value, bigblock->length);

	exchange = aimbs_get16(&bbbs);
	cklen = aimbs_get8(&bbbs);
	ck = aimbs_getstr(&bbbs, cklen);
	instance = aimbs_get16(&bbbs);
	detaillevel = aimbs_get8(&bbbs);

	if (detaillevel != 0x02) {
		faimdprintf(sess, 0, "unknown detaillevel in create room response (0x%02x)\n", detaillevel);
		aim_freetlvchain(&tlvlist);
		free(ck);
		return 0;
	}

	unknown = aimbs_get16(&bbbs);

	innerlist = aim_readtlvchain(&bbbs);

	if (aim_gettlv(innerlist, 0x006a, 1))
		fqcn = aim_gettlv_str(innerlist, 0x006a, 1);

	if (aim_gettlv(innerlist, 0x00c9, 1))
		flags = aim_gettlv16(innerlist, 0x00c9, 1);

	if (aim_gettlv(innerlist, 0x00ca, 1))
		createtime = aim_gettlv32(innerlist, 0x00ca, 1);

	if (aim_gettlv(innerlist, 0x00d1, 1))
		maxmsglen = aim_gettlv16(innerlist, 0x00d1, 1);

	if (aim_gettlv(innerlist, 0x00d2, 1))
		maxoccupancy = aim_gettlv16(innerlist, 0x00d2, 1);

	if (aim_gettlv(innerlist, 0x00d3, 1))
		name = aim_gettlv_str(innerlist, 0x00d3, 1);

	if (aim_gettlv(innerlist, 0x00d5, 1))
		createperms = aim_gettlv8(innerlist, 0x00d5, 1);

	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
		ret = userfunc(sess, rx, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck);
	}

	free(ck);
	free(name);
	free(fqcn);
	aim_freetlvchain(&innerlist);
	aim_freetlvchain(&tlvlist);

	return ret;
}
Example #20
0
/*
 * It can easily be said that parsing ICBMs is THE single
 * most difficult thing to do in the in AIM protocol.  In
 * fact, I think I just did say that.
 *
 * Below is the best damned solution I've come up with
 * over the past sixteen months of battling with it. This
 * can parse both away and normal messages from every client
 * I have access to.  Its not fast, its not clean.  But it works.
 *
 */
static int incomingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
	int i, ret = 0;
	guint8 cookie[8];
	guint16 channel;
	aim_userinfo_t userinfo;

	memset(&userinfo, 0x00, sizeof(aim_userinfo_t));

	/*
	 * Read ICBM Cookie.  And throw away.
	 */
	for (i = 0; i < 8; i++)
		cookie[i] = aimbs_get8(bs);

	/*
	 * Channel ID.
	 *
	 * Channel 0x0001 is the message channel.  There are 
	 * other channels for things called "rendevous"
	 * which represent chat and some of the other new
	 * features of AIM2/3/3.5. 
	 *
	 * Channel 0x0002 is the Rendevous channel, which
	 * is where Chat Invitiations and various client-client
	 * connection negotiations come from.
	 *
	 * Channel 0x0004 is used for ICQ authorization, or 
	 * possibly any system notice.
	 *
	 */
	channel = aimbs_get16(bs);

	/*
	 * Extract the standard user info block.
	 *
	 * Note that although this contains TLVs that appear contiguous
	 * with the TLVs read below, they are two different pieces.  The
	 * userinfo block contains the number of TLVs that contain user
	 * information, the rest are not even though there is no seperation.
	 * aim_extractuserinfo() returns the number of bytes used by the
	 * userinfo tlvs, so you can start reading the rest of them right
	 * afterward.  
	 *
	 * That also means that TLV types can be duplicated between the
	 * userinfo block and the rest of the message, however there should
	 * never be two TLVs of the same type in one block.
	 * 
	 */
	aim_extractuserinfo(sess, bs, &userinfo);

	/*
	 * From here on, its depends on what channel we're on.
	 *
	 * Technically all channels have a TLV list have this, however,
	 * for the common channel 1 case, in-place parsing is used for
	 * performance reasons (less memory allocation).
	 */
	if (channel == 1) {

		ret = incomingim_ch1(sess, mod, rx, snac, channel, &userinfo, bs, cookie);

	} else if (channel == 2) {
		aim_tlvlist_t *tlvlist;

		/*
		 * Read block of TLVs (not including the userinfo data).  All 
		 * further data is derived from what is parsed here.
		 */
		tlvlist = aim_readtlvchain(bs);

		ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);

		aim_freetlvchain(&tlvlist);

	} else if (channel == 4) {
		aim_tlvlist_t *tlvlist;

		tlvlist = aim_readtlvchain(bs);
		ret = incomingim_ch4(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);
		aim_freetlvchain(&tlvlist);

	} else {

		imcb_error(sess->aux_data, "ICBM received on an unsupported channel.  Ignoring.");

		return 0;
	}

	return ret;
}