Exemple #1
0
/* Subtype 0x0006 */
static int
userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
	int ret = 0;
	aim_rxcallback_t userfunc;
	aim_userinfo_t *userinfo, *userinfo2;
	GSList *tlvlist;
	aim_tlv_t *tlv = NULL;
	int was_explicit;

	userinfo = (aim_userinfo_t *)g_malloc(sizeof(aim_userinfo_t));
	aim_info_extract(od, bs, userinfo);
	tlvlist = aim_tlvlist_read(bs);

	/* Profile will be 1 and 2 */
	userinfo->info_encoding = aim_tlv_getstr(tlvlist, 0x0001, 1);
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0002, 1))) {
		userinfo->info = (char *)g_malloc(tlv->length);
		memcpy(userinfo->info, tlv->value, tlv->length);
		userinfo->info_len = tlv->length;
	}

	/* Away message will be 3 and 4 */
	userinfo->away_encoding = aim_tlv_getstr(tlvlist, 0x0003, 1);
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) {
		userinfo->away = (char *)g_malloc(tlv->length);
		memcpy(userinfo->away, tlv->value, tlv->length);
		userinfo->away_len = tlv->length;
	}

	/* Caps will be 5 */
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) {
		ByteStream cbs;
		byte_stream_init(&cbs, tlv->value, tlv->length);
		userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length);
		userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES;
	}
	aim_tlvlist_free(tlvlist);

	aim_locate_adduserinfo(od, userinfo);
	userinfo2 = aim_locate_finduserinfo(od, userinfo->sn);
	aim_info_free(userinfo);
	g_free(userinfo);

	/*
	 * Remove this screen name from our queue.  If the client requested
	 * this buddy's info explicitly, then notify them that we have info
	 * for this buddy.
	 */
	if (userinfo2 != NULL)
	{
		was_explicit = aim_locate_gotuserinfo(od, conn, userinfo2->sn);
		if (was_explicit == TRUE)
			if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
				ret = userfunc(od, conn, frame, userinfo2);
	}

	return ret;
}
/* Subtype 0x0006 */
static int
userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
	int ret = 0;
	aim_userinfo_t *userinfo, *userinfo2;
	GSList *tlvlist;
	aim_tlv_t *tlv = NULL;

	userinfo = (aim_userinfo_t *)g_malloc(sizeof(aim_userinfo_t));
	aim_info_extract(od, bs, userinfo);
	tlvlist = aim_tlvlist_read(bs);

	/* Profile will be 1 and 2 */
	userinfo->info_encoding = aim_tlv_getstr(tlvlist, 0x0001, 1);
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0002, 1))) {
		userinfo->info = (char *)g_malloc(tlv->length);
		memcpy(userinfo->info, tlv->value, tlv->length);
		userinfo->info_len = tlv->length;
	}

	/* Away message will be 3 and 4 */
	userinfo->away_encoding = aim_tlv_getstr(tlvlist, 0x0003, 1);
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) {
		userinfo->away = (char *)g_malloc(tlv->length);
		memcpy(userinfo->away, tlv->value, tlv->length);
		userinfo->away_len = tlv->length;
	}

	/* Caps will be 5 */
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) {
		ByteStream cbs;
		PurpleAccount *account = purple_connection_get_account(od->gc);
		const char *mood;

		byte_stream_init(&cbs, tlv->value, tlv->length);
		userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length);
		byte_stream_rewind(&cbs);
		userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES;

		mood = aim_receive_custom_icon(od, &cbs, tlv->length);
		if (mood)
			purple_prpl_got_user_status(account, userinfo->bn, "mood",
					PURPLE_MOOD_NAME, mood,
					NULL);
		else
			purple_prpl_got_user_status_deactive(account, userinfo->bn, "mood");
	}
	aim_tlvlist_free(tlvlist);

	aim_locate_adduserinfo(od, userinfo);
	userinfo2 = aim_locate_finduserinfo(od, userinfo->bn);
	aim_info_free(userinfo);
	g_free(userinfo);

	/* Show the info to the user */
	oscar_user_info_display_aim(od, userinfo2);

	return ret;
}
Exemple #3
0
/* Subtype 0x0006 */
static int
userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
	int ret = 0;
	aim_rxcallback_t userfunc;
	aim_userinfo_t *userinfo, *userinfo2;
	GSList *tlvlist;
	aim_tlv_t *tlv = NULL;

	userinfo = (aim_userinfo_t *)g_malloc(sizeof(aim_userinfo_t));
	aim_info_extract(od, bs, userinfo);
	tlvlist = aim_tlvlist_read(bs);

	/* Profile will be 1 and 2 */
	userinfo->info_encoding = aim_tlv_getstr(tlvlist, 0x0001, 1);
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0002, 1))) {
		userinfo->info = (char *)g_malloc(tlv->length);
		memcpy(userinfo->info, tlv->value, tlv->length);
		userinfo->info_len = tlv->length;
	}

	/* Away message will be 3 and 4 */
	userinfo->away_encoding = aim_tlv_getstr(tlvlist, 0x0003, 1);
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) {
		userinfo->away = (char *)g_malloc(tlv->length);
		memcpy(userinfo->away, tlv->value, tlv->length);
		userinfo->away_len = tlv->length;
	}

	/* Caps will be 5 */
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) {
		ByteStream cbs;
		byte_stream_init(&cbs, tlv->value, tlv->length);
		userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length);
		userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES;
	}
	aim_tlvlist_free(tlvlist);

	aim_locate_adduserinfo(od, userinfo);
	userinfo2 = aim_locate_finduserinfo(od, userinfo->bn);
	aim_info_free(userinfo);
	g_free(userinfo);

	/* Show the info to the user */
	if (userinfo2 != NULL && ((userfunc = aim_callhandler(od, snac->family, snac->subtype))))
		ret = userfunc(od, conn, frame, userinfo2);

	return ret;
}
Exemple #4
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;
}