⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 im.c

📁 oscar message protocol stack
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	if (aim_tlv_gettlv(list2, 0x0010, 1))		;	if (strlen(proxyip))		args.proxyip = (char *)proxyip;	if (strlen(clientip))		args.clientip = (char *)clientip;	if (strlen(verifiedip))		args.verifiedip = (char *)verifiedip;	/*	 * This must be present in PROPOSALs, but will probably not	 * exist in CANCELs and ACCEPTs.  Also exists in ICQ Lite	 * Beta 4.0 URLs (AIM_CAPS_ICQSERVERRELAY).	 *	 * Service Data blocks are module-specific in format.	 */	if ((servdatatlv = aim_tlv_gettlv(list2, 0x2711 /* 10001 */, 1))) {		aim_bstream_init(&sdbs, servdatatlv->value, servdatatlv->length);		sdbsptr = &sdbs;	}	/*	 * The rest of the handling depends on what type it is.	 *	 * Not all of them have special handling (yet).	 */	if (args.reqclass & AIM_CAPS_BUDDYICON)		incomingim_ch2_buddyicon(sess, mod, rx, snac, userinfo, &args, sdbsptr);	else if (args.reqclass & AIM_CAPS_SENDBUDDYLIST)		incomingim_ch2_buddylist(sess, mod, rx, snac, userinfo, &args, sdbsptr);	else if (args.reqclass & AIM_CAPS_CHAT)		incomingim_ch2_chat(sess, mod, rx, snac, userinfo, &args, sdbsptr);	else if (args.reqclass & AIM_CAPS_ICQSERVERRELAY)		incomingim_ch2_icqserverrelay(sess, mod, rx, snac, userinfo, &args, sdbsptr);	else if (args.reqclass & AIM_CAPS_SENDFILE)		incomingim_ch2_sendfile(sess, mod, rx, snac, userinfo, &args, sdbsptr);	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))		ret = userfunc(sess, rx, channel, userinfo, &args);	if (args.destructor)		((ch2_args_destructor_t)args.destructor)(sess, &args);	free((char *)args.msg);	free((char *)args.encoding);	free((char *)args.language);	aim_tlvlist_free(&list2);	return ret;}static int incomingim_ch4(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, fu16_t channel, aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, fu8_t *cookie){	aim_bstream_t meat;	aim_rxcallback_t userfunc;	aim_tlv_t *block;	struct aim_incomingim_ch4_args args;	int ret = 0;	/*	 * Make a bstream for the meaty part.  Yum.  Meat.	 */	if (!(block = aim_tlv_gettlv(tlvlist, 0x0005, 1)))		return -1;	aim_bstream_init(&meat, block->value, block->length);	args.uin = aimbs_getle32(&meat);	args.type = aimbs_getle8(&meat);	args.flags = aimbs_getle8(&meat);	args.msglen = aimbs_getle16(&meat);	args.msg = aimbs_getraw(&meat, args.msglen);	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))		ret = userfunc(sess, rx, channel, userinfo, &args);	free(args.msg);	return ret;}/* * Subtype 0x0007 * * 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;	fu8_t cookie[8];	fu16_t channel;	aim_userinfo_t userinfo;	memset(&userinfo, 0x00, sizeof(aim_userinfo_t));	/*	 * Read ICBM Cookie.	 */	for (i = 0; i < 8; i++)		cookie[i] = aimbs_get8(bs);	/*	 * Channel ID.	 *	 * Channel 0x0001 is the message channel.  It is 	 * used to send basic ICBMs.	 *	 * Channel 0x0002 is the Rendezvous channel, which	 * is where Chat Invitiations and various client-client	 * connection negotiations come from.	 *	 * Channel 0x0003 is used for chat messages.	 *	 * 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 separation.	 * You can start reading the message TLVs after aim_info_extract() 	 * parses out the standard userinfo block.	 *	 * 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_info_extract(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_tlvlist_read(bs);		ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);		aim_tlvlist_free(&tlvlist);	} else if (channel == 4) {		aim_tlvlist_t *tlvlist;		tlvlist = aim_tlvlist_read(bs);		ret = incomingim_ch4(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);		aim_tlvlist_free(&tlvlist);	} else {		faimdprintf(sess, 0, "icbm: ICBM received on an unsupported channel.  Ignoring.  (chan = %04x)\n", channel);	}	aim_info_free(&userinfo);	return ret;}/* * Subtype 0x0008 - Send a warning to sn. *  * Flags: *  AIM_WARN_ANON  Send as an anonymous (doesn't count as much) * * returns -1 on error (couldn't alloc packet), 0 on success.  * */faim_export int aim_im_warn(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu32_t flags){	aim_frame_t *fr;	aim_snacid_t snacid;	if (!sess || !conn || !sn)		return -EINVAL;	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(sn)+13)))		return -ENOMEM;	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_put8(&fr->data, strlen(sn));	aimbs_putraw(&fr->data, sn, strlen(sn));	aim_tx_enqueue(sess, fr);	return 0;}/* Subtype 0x000a */static int missedcall(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 channel, nummissed, reason;	aim_userinfo_t userinfo;	while (aim_bstream_empty(bs)) {			channel = aimbs_get16(bs);		aim_info_extract(sess, bs, &userinfo);		nummissed = aimbs_get16(bs);		reason = aimbs_get16(bs);		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))			 ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason);		aim_info_free(&userinfo);	}	return ret;}/* * Subtype 0x000b * * Possible codes: *    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 char *cookie, fu16_t code){	aim_conn_t *conn;	aim_frame_t *fr;	aim_snacid_t snacid;	aim_tlvlist_t *tl = NULL;		if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))		return -EINVAL;	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sender)+6)))		return -ENOMEM;	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 */	aimbs_put8(&fr->data, strlen(sender));	aimbs_putraw(&fr->data, sender, strlen(sender));	aim_tlvlist_add_16(&tl, 0x0003, code);	aim_tlvlist_write(&fr->data, &tl);	aim_tlvlist_free(&tl);	aim_tx_enqueue(sess, fr);	return 0;}/* * Subtype 0x000b - 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;	fu16_t channel, reason;	char *sn;	fu8_t *ck, snlen;	ck = aimbs_getraw(bs, 8);	channel = aimbs_get16(bs);	snlen = aimbs_get8(bs);	sn = aimbs_getstr(bs, snlen);	reason = aimbs_get16(bs);	if (channel == 0x0002) { /* File transfer declined */		aimbs_get16(bs); /* Unknown */		aimbs_get16(bs); /* Unknown */		if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))			ret = userfunc(sess, rx, channel, sn, reason, ck);	} else if (channel == 0x0004) { /* ICQ message */		switch (reason) {			case 0x0003: { /* ICQ status message.  Maybe other stuff too, you never know with these people. */				fu8_t statusmsgtype, *msg;				fu16_t len;				fu32_t 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);				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 */	}	free(ck);	free(sn);	return ret;}/* * Subtype 0x000c - Receive an ack after sending an ICBM. * * You have to have send the message with the AIM_IMFLAGS_ACK flag set  * (TLV t(0003)).  The ack contains the ICBM header of the message you  * sent. * */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;	fu16_t ch;	fu8_t *ck;	char *sn;	int ret = 0;	ck = aimbs_getraw(bs, 8);	ch = aimbs_get16(bs);	sn = aimbs_getstr(bs, aimbs_get8(bs));	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))		ret = userfunc(sess, rx, ch, sn);	free(sn);	free(ck);	return ret;}/* * Subtype 0x0014 - Send 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. * */faim_export int aim_im_sendmtn(aim_session_t *sess, fu16_t type1, const char *sn, fu16_t type2){	aim_conn_t *conn;	aim_frame_t *fr;	aim_snacid_t snacid;	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))		return -EINVAL;	if (!sn)		return -EINVAL;	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+11+strlen(sn)+2)))		return -ENOMEM;	snacid = aim_cachesnac(sess, 0x0004, 0x0014, 0x0000, NULL, 0);	aim_putsnac(&fr->data, 0x0004, 0x0014, 0x0000, snacid);	/*	 * 8 days of light	 * Er, that is to say, 8 bytes of 0's	 */	aimbs_put16(&fr->data, 0x0000);	aimbs_put16(&fr->data, 0x0000);	aimbs_put16(&fr->data, 0x0000);	aimbs_put16(&fr->data, 0x0000);	/*	 * Type 1 (should be 0x0001 for mtn)	 */	aimbs_put16(&fr->data, type1);	/*	 * Dest sn	 */	aimbs_put8(&fr->data, strlen(sn));	aimbs_putraw(&fr->data, sn, strlen(sn));	/*	 * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn)	 */	aimbs_put16(&fr->data, type2);	aim_tx_enqueue(sess, fr);	return 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -