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

📄 family_icbm.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Purple's oscar protocol plugin * This file is the legal property of its developers. * Please see the AUTHORS file distributed alongside this file. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA*//* * Family 0x0004 - Routines for sending/receiving Instant Messages. * * Note the term ICBM (Inter-Client Basic Message) which blankets * all types of generically routed through-server messages.  Within * the ICBM types (family 4), a channel is defined.  Each channel * represents a different type of message.  Channel 1 is used for * what would commonly be called an "instant message".  Channel 2 * is used for negotiating "rendezvous".  These transactions end in * something more complex happening, such as a chat invitation, or * a file transfer.  Channel 3 is used for chat messages (not in * the same family as these channels).  Channel 4 is used for * various ICQ messages.  Examples are normal messages, URLs, and * old-style authorization. * * In addition to the channel, every ICBM contains a cookie.  For * standard IMs, these are only used for error messages.  However, * the more complex rendezvous messages make suitably more complex * use of this field. * * TODO: Split this up into an im.c file an an icbm.c file.  It *       will be beautiful, you'll see. * *       Make sure flap_connection_findbygroup is used by all functions. */#include "oscar.h"#include "peer.h"#ifdef _WIN32#include "win32dep.h"#endif/** * Add a standard ICBM header to the given bstream with the given * information. * * @param bs The bstream to write the ICBM header to. * @param c c is for cookie, and cookie is for me. * @param channel The ICBM channel (1 through 4). * @param sn Null-terminated scrizeen nizame. * @return The number of bytes written.  It's really not useful. */static int aim_im_puticbm(ByteStream *bs, const guchar *c, guint16 channel, const char *sn){	byte_stream_putraw(bs, c, 8);	byte_stream_put16(bs, channel);	byte_stream_put8(bs, strlen(sn));	byte_stream_putstr(bs, sn);	return 8+2+1+strlen(sn);}/** * Generates a random ICBM cookie in a character array of length 8 * and copies it into the variable passed as cookie * TODO: Maybe we should stop limiting our characters to the visible range? */void aim_icbm_makecookie(guchar *cookie){	int i;	/* Should be like "21CBF95" and null terminated */	for (i = 0; i < 7; i++)		cookie[i] = 0x30 + ((guchar)rand() % 10);	cookie[7] = '\0';}/* * Takes a msghdr (and a length) and returns a client type * code.  Note that this is *only a guess* and has a low likelihood * of actually being accurate. * * Its based on experimental data, with the help of Eric Warmenhoven * who seems to have collected a wide variety of different AIM clients. * * * Heres the current collection: *  0501 0003 0101 0101 01		AOL Mobile Communicator, WinAIM 1.0.414 *  0501 0003 0101 0201 01		WinAIM 2.0.847, 2.1.1187, 3.0.1464, *					4.3.2229, 4.4.2286 *  0501 0004 0101 0102 0101		WinAIM 4.1.2010, libfaim (right here) *  0501 0003 0101 02			WinAIM 5 *  0501 0001 01			iChat x.x, mobile buddies *  0501 0001 0101 01			AOL v6.0, CompuServe 2000 v6.0, any TOC client *  0501 0002 0106			WinICQ 5.45.1.3777.85 * * Note that in this function, only the feature bytes are tested, since * the rest will always be the same. * */guint16 aim_im_fingerprint(const guint8 *msghdr, int len){	static const struct {		guint16 clientid;		int len;		guint8 data[10];	} fingerprints[] = {		/* AOL Mobile Communicator, WinAIM 1.0.414 */		{ AIM_CLIENTTYPE_MC,		  3, {0x01, 0x01, 0x01}},		/* WinAIM 2.0.847, 2.1.1187, 3.0.1464, 4.3.2229, 4.4.2286 */		{ AIM_CLIENTTYPE_WINAIM,		  3, {0x01, 0x01, 0x02}},		/* WinAIM 4.1.2010, libfaim */		{ AIM_CLIENTTYPE_WINAIM41,		  4, {0x01, 0x01, 0x01, 0x02}},		/* AOL v6.0, CompuServe 2000 v6.0, any TOC client */		{ AIM_CLIENTTYPE_AOL_TOC,		  1, {0x01}},		{ 0, 0, {0x00}}	};	int i;	if (!msghdr || (len <= 0))		return AIM_CLIENTTYPE_UNKNOWN;	for (i = 0; fingerprints[i].len; i++) {		if (fingerprints[i].len != len)			continue;		if (memcmp(fingerprints[i].data, msghdr, fingerprints[i].len) == 0)			return fingerprints[i].clientid;	}	return AIM_CLIENTTYPE_UNKNOWN;}/** * Subtype 0x0002 - Set ICBM parameters. * * I definitely recommend sending this.  If you don't, you'll be stuck * with the rather unreasonable defaults. * */int aim_im_setparams(OscarData *od, struct aim_icbmparameters *params){	FlapConnection *conn;	FlapFrame *frame;	aim_snacid_t snacid;	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))		return -EINVAL;	if (!params)		return -EINVAL;	frame = flap_frame_new(od, 0x02, 10+16);	snacid = aim_cachesnac(od, 0x0004, 0x0002, 0x0000, NULL, 0);	aim_putsnac(&frame->data, 0x0004, 0x0002, 0x0000, snacid);	/* This is read-only (see Parameter Reply). Must be set to zero here. */	byte_stream_put16(&frame->data, 0x0000);	/* These are all read-write */	byte_stream_put32(&frame->data, params->flags);	byte_stream_put16(&frame->data, params->maxmsglen);	byte_stream_put16(&frame->data, params->maxsenderwarn);	byte_stream_put16(&frame->data, params->maxrecverwarn);	byte_stream_put32(&frame->data, params->minmsginterval);	flap_connection_send(conn, frame);	return 0;}/** * Subtype 0x0004 - Request ICBM parameter information. * */int aim_im_reqparams(OscarData *od){	FlapConnection *conn;	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))		return -EINVAL;	aim_genericreq_n_snacid(od, conn, 0x0004, 0x0004);	return 0;}/** * Subtype 0x0005 - Receive parameter information. * */static int aim_im_paraminfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs){	aim_rxcallback_t userfunc;	struct aim_icbmparameters params;	params.maxchan = byte_stream_get16(bs);	params.flags = byte_stream_get32(bs);	params.maxmsglen = byte_stream_get16(bs);	params.maxsenderwarn = byte_stream_get16(bs);	params.maxrecverwarn = byte_stream_get16(bs);	params.minmsginterval = byte_stream_get32(bs);	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))		return userfunc(od, conn, frame, &params);	return 0;}/** * Subtype 0x0006 - Send an ICBM (instant message). * * * Possible flags: *   AIM_IMFLAGS_AWAY  -- Marks the message as an autoresponse *   AIM_IMFLAGS_ACK   -- Requests that the server send an ack *                        when the message is received (of type 0x0004/0x000c) *   AIM_IMFLAGS_OFFLINE--If destination is offline, store it until they are *                        online (probably ICQ only). * * Generally, you should use the lowest encoding possible to send * your message.  If you only use basic punctuation and the generic * Latin alphabet, use ASCII7 (no flags).  If you happen to use non-ASCII7 * characters, but they are all clearly defined in ISO-8859-1, then * use that.  Keep in mind that not all characters in the PC ASCII8 * character set are defined in the ISO standard. For those cases (most * notably when the (r) symbol is used), you must use the full UNICODE * encoding for your message.  In UNICODE mode, _all_ characters must * occupy 16bits, including ones that are not special.  (Remember that * the first 128 UNICODE symbols are equivalent to ASCII7, however they * must be prefixed with a zero high order byte.) * * I strongly discourage the use of UNICODE mode, mainly because none * of the clients I use can parse those messages (and besides that, * wchars are difficult and non-portable to handle in most UNIX environments). * If you really need to include special characters, use the HTML UNICODE * entities.  These are of the form &#2026; where 2026 is the hex * representation of the UNICODE index (in this case, UNICODE * "Horizontal Ellipsis", or 133 in in ASCII8). * * Implementation note:  Since this is one of the most-used functions * in all of libfaim, it is written with performance in mind.  As such, * it is not as clear as it could be in respect to how this message is * supposed to be layed out. Most obviously, tlvlists should be used * instead of writing out the bytes manually. * * XXX - more precise verification that we never send SNACs larger than 8192 * XXX - check SNAC size for multipart * */int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args){	FlapConnection *conn;	aim_snacid_t snacid;	ByteStream data;	guchar cookie[8];	int msgtlvlen;	static const guint8 deffeatures[] = { 0x01, 0x01, 0x01, 0x02 };	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))		return -EINVAL;	if (!args)		return -EINVAL;	if (args->flags & AIM_IMFLAGS_MULTIPART) {		if (args->mpmsg->numparts == 0)			return -EINVAL;	} else {		if (!args->msg || (args->msglen <= 0))			return -EINVAL;		if (args->msglen >= MAXMSGLEN)			return -E2BIG;	}	/* Painfully calculate the size of the message TLV */	msgtlvlen = 1 + 1; /* 0501 */	if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES)		msgtlvlen += 2 + args->featureslen;	else		msgtlvlen += 2 + sizeof(deffeatures);	if (args->flags & AIM_IMFLAGS_MULTIPART) {		aim_mpmsg_section_t *sec;		for (sec = args->mpmsg->parts; sec; sec = sec->next) {			msgtlvlen += 2 /* 0101 */ + 2 /* block len */;			msgtlvlen += 4 /* charset */ + sec->datalen;		}	} else {		msgtlvlen += 2 /* 0101 */ + 2 /* block len */;		msgtlvlen += 4 /* charset */ + args->msglen;	}	byte_stream_new(&data, msgtlvlen + 128);	/* Generate an ICBM cookie */	aim_icbm_makecookie(cookie);	/* ICBM header */	aim_im_puticbm(&data, cookie, 0x0001, args->destsn);	/* Message TLV (type 0x0002) */	byte_stream_put16(&data, 0x0002);	byte_stream_put16(&data, msgtlvlen);	/* Features TLV (type 0x0501) */	byte_stream_put16(&data, 0x0501);	if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) {		byte_stream_put16(&data, args->featureslen);		byte_stream_putraw(&data, args->features, args->featureslen);	} else {		byte_stream_put16(&data, sizeof(deffeatures));		byte_stream_putraw(&data, deffeatures, sizeof(deffeatures));	}	if (args->flags & AIM_IMFLAGS_MULTIPART) {		aim_mpmsg_section_t *sec;		/* Insert each message part in a TLV (type 0x0101) */		for (sec = args->mpmsg->parts; sec; sec = sec->next) {			byte_stream_put16(&data, 0x0101);			byte_stream_put16(&data, sec->datalen + 4);			byte_stream_put16(&data, sec->charset);			byte_stream_put16(&data, sec->charsubset);			byte_stream_putraw(&data, (guchar *)sec->data, sec->datalen);		}	} else {		/* Insert message text in a TLV (type 0x0101) */		byte_stream_put16(&data, 0x0101);		/* Message block length */		byte_stream_put16(&data, args->msglen + 0x04);		/* Character set */		byte_stream_put16(&data, args->charset);		byte_stream_put16(&data, args->charsubset);		/* Message.  Not terminated */		byte_stream_putraw(&data, (guchar *)args->msg, args->msglen);	}	/* Set the Autoresponse flag */	if (args->flags & AIM_IMFLAGS_AWAY) {		byte_stream_put16(&data, 0x0004);		byte_stream_put16(&data, 0x0000);	} else if (args->flags & AIM_IMFLAGS_ACK) {		/* Set the Request Acknowledge flag */		byte_stream_put16(&data, 0x0003);		byte_stream_put16(&data, 0x0000);	}	if (args->flags & AIM_IMFLAGS_OFFLINE) {		byte_stream_put16(&data, 0x0006);		byte_stream_put16(&data, 0x0000);	}	/*	 * Set the I HAVE A REALLY PURTY ICON flag.	 * XXX - This should really only be sent on initial	 * IMs and when you change your icon.	 */	if (args->flags & AIM_IMFLAGS_HASICON) {		byte_stream_put16(&data, 0x0008);		byte_stream_put16(&data, 0x000c);		byte_stream_put32(&data, args->iconlen);		byte_stream_put16(&data, 0x0001);		byte_stream_put16(&data, args->iconsum);		byte_stream_put32(&data, args->iconstamp);	}	/*	 * Set the Buddy Icon Requested flag.	 * XXX - Every time?  Surely not...	 */	if (args->flags & AIM_IMFLAGS_BUDDYREQ) {		byte_stream_put16(&data, 0x0009);		byte_stream_put16(&data, 0x0000);	}	/* XXX - should be optional */	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1);	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &data);	g_free(data.data);	/* clean out SNACs over 60sec old */	aim_cleansnacs(od, 60);	return 0;}/* * Simple wrapper for aim_im_sendch1_ext() * * You cannot use aim_send_im if you need the HASICON flag.  You must * use aim_im_sendch1_ext directly for that. * * aim_send_im also cannot be used if you require UNICODE messages, because * that requires an explicit message length.  Use aim_im_sendch1_ext(). * */int aim_im_sendch1(OscarData *od, const char *sn, guint16 flags, const char *msg){	struct aim_sendimext_args args;	args.destsn = sn;	args.flags = flags;	args.msg = msg;	args.msglen = strlen(msg);	args.charset = 0x0000;	args.charsubset = 0x0000;	/* Make these don't get set by accident -- they need aim_im_sendch1_ext */

⌨️ 快捷键说明

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