📄 family_icbm.c
字号:
* sections at run time. So if you have, say, ASCII then UNICODE then ASCII, * you must supply two ASCII sections with a UNICODE in the middle, and incur * the associated overhead. * * Normally I would have laughed and given a firm 'no' to supporting this * seldom-used feature, but something is attracting me to it. In the future, * it may be possible to abuse this to send mixed-media messages to other * open source clients (like encryption or something) -- see faimtest for * examples of how to do this. * * I would definitely recommend avoiding this feature unless you really * know what you are doing, and/or you have something neat to do with it. * */int aim_mpmsg_init(OscarData *od, aim_mpmsg_t *mpm){ memset(mpm, 0, sizeof(aim_mpmsg_t)); return 0;}static int mpmsg_addsection(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, gchar *data, guint16 datalen){ aim_mpmsg_section_t *sec; sec = g_malloc(sizeof(aim_mpmsg_section_t)); sec->charset = charset; sec->charsubset = charsubset; sec->data = data; sec->datalen = datalen; sec->next = NULL; if (!mpm->parts) mpm->parts = sec; else { aim_mpmsg_section_t *cur; for (cur = mpm->parts; cur->next; cur = cur->next) ; cur->next = sec; } mpm->numparts++; return 0;}int aim_mpmsg_addraw(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, const gchar *data, guint16 datalen){ gchar *dup; dup = g_malloc(datalen); memcpy(dup, data, datalen); if (mpmsg_addsection(od, mpm, charset, charsubset, dup, datalen) == -1) { g_free(dup); return -1; } return 0;}/* XXX - should provide a way of saying ISO-8859-1 specifically */int aim_mpmsg_addascii(OscarData *od, aim_mpmsg_t *mpm, const char *ascii){ gchar *dup; if (!(dup = g_strdup(ascii))) return -1; if (mpmsg_addsection(od, mpm, 0x0000, 0x0000, dup, strlen(ascii)) == -1) { g_free(dup); return -1; } return 0;}int aim_mpmsg_addunicode(OscarData *od, aim_mpmsg_t *mpm, const guint16 *unicode, guint16 unicodelen){ gchar *buf; ByteStream bs; int i; buf = g_malloc(unicodelen * 2); byte_stream_init(&bs, (guchar *)buf, unicodelen * 2); /* We assume unicode is in /host/ byte order -- convert to network */ for (i = 0; i < unicodelen; i++) byte_stream_put16(&bs, unicode[i]); if (mpmsg_addsection(od, mpm, 0x0002, 0x0000, buf, byte_stream_curpos(&bs)) == -1) { g_free(buf); return -1; } return 0;}void aim_mpmsg_free(OscarData *od, aim_mpmsg_t *mpm){ aim_mpmsg_section_t *cur; for (cur = mpm->parts; cur; ) { aim_mpmsg_section_t *tmp; tmp = cur->next; g_free(cur->data); g_free(cur); cur = tmp; } mpm->numparts = 0; mpm->parts = NULL; return;}/* * 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(OscarData *od, aim_userinfo_t *userinfo, guint8 *data, int len, struct aim_incomingim_ch1_args *args){ /* Should this be ASCII -> UNICODE -> Custom */ static const guint16 charsetpri[] = { AIM_CHARSET_ASCII, /* ASCII first */ AIM_CHARSET_CUSTOM, /* then ISO-8859-1 */ AIM_CHARSET_UNICODE, /* UNICODE as last resort */ }; static const int charsetpricount = 3; int i; ByteStream mbs; aim_mpmsg_section_t *sec; byte_stream_init(&mbs, data, len); while (byte_stream_empty(&mbs)) { guint16 msglen, flag1, flag2; gchar *msgbuf; byte_stream_get8(&mbs); /* 01 */ byte_stream_get8(&mbs); /* 01 */ /* Message string length, including character set info. */ msglen = byte_stream_get16(&mbs); if (msglen > byte_stream_empty(&mbs)) { purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.", userinfo->sn); break; } /* Character set info */ flag1 = byte_stream_get16(&mbs); flag2 = byte_stream_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 = (gchar *)byte_stream_getraw(&mbs, msglen); mpmsg_addsection(od, &args->mpmsg, flag1, flag2, msgbuf, 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; /* Set up the simple flags */ switch (args->charsubset) { case 0x0000: /* standard subencoding? */ break; case 0x000b: args->icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH; break; case 0xffff: /* no subencoding */ break; default: break; } args->msg = 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;}static int incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, ByteStream *bs, guint8 *cookie){ guint16 type, length; aim_rxcallback_t userfunc; int ret = 0; struct aim_incomingim_ch1_args args; unsigned int endpos; memset(&args, 0, sizeof(args)); aim_mpmsg_init(od, &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 (byte_stream_empty(bs) >= 4) { type = byte_stream_get16(bs); length = byte_stream_get16(bs); if (length > byte_stream_empty(bs)) { purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->sn); break; } endpos = byte_stream_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 * */ byte_stream_get8(bs); /* 05 */ byte_stream_get8(bs); /* 01 */ args.featureslen = byte_stream_get16(bs); if (args.featureslen > byte_stream_empty(bs)) { purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->sn); break; } if (args.featureslen == 0) { args.features = NULL; } else { args.features = byte_stream_getraw(bs, args.featureslen); args.icbmflags |= AIM_IMFLAGS_CUSTOMFEATURES; } /* * The rest of the TLV contains one or more message * blocks... */ incomingim_ch1_parsemsgs(od, userinfo, 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 = byte_stream_get32(bs); byte_stream_get16(bs); /* 0x0001 */ args.iconsum = byte_stream_get16(bs); args.iconstamp = byte_stream_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 == 0x000b) { /* Non-direct connect typing notification */ args.icbmflags |= AIM_IMFLAGS_TYPINGNOT; } else if (type == 0x0017) { if (length > byte_stream_empty(bs)) { purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->sn); break; } g_free(args.extdata); args.extdatalen = length; if (args.extdatalen == 0) args.extdata = NULL; else args.extdata = byte_stream_getraw(bs, args.extdatalen); } else { purple_debug_misc("oscar", "incomingim_ch1: unknown TLV 0x%04x (len %d)\n", type, length); } /* * This is here to protect ourselves from ourselves. That * is, if something above doesn't completely 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. * */ byte_stream_setpos(bs, endpos); } if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, channel, userinfo, &args); aim_mpmsg_free(od, &args.mpmsg); g_free(args.features); g_free(args.extdata); return ret;}static voidincomingim_ch2_buddylist(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata){ /* * This goes like this... * * group name length * group name * num of buddies in group * buddy name length * buddy name * buddy name length * buddy name * ... * group name length * group name * num of buddies in group * buddy name length * buddy name * ... * ... */ while (byte_stream_empty(servdata)) { guint16 gnlen, numb; int i; char *gn; gnlen = byte_stream_get16(servdata); gn = byte_stream_getstr(servdata, gnlen); numb = byte_stream_get16(servdata); for (i = 0; i < numb; i++) { guint16 bnlen; char *bn; bnlen = byte_stream_get16(servdata); bn = byte_stream_getstr(servdata, bnlen); purple_debug_misc("oscar", "got a buddy list from %s: group %s, buddy %s\n", userinfo->sn, gn, bn); g_free(bn); } g_free(gn); } return;}static voidincomingim_ch2_buddyicon_free(OscarData *od, IcbmArgsCh2 *args){ g_free(args->info.icon.icon);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -