📄 im.c
字号:
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(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, fu16_t channel, aim_userinfo_t *userinfo, aim_bstream_t *bs, fu8_t *cookie){ fu16_t 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 == 0x000b) { /* Non-direct connect typing notification */ args.icbmflags |= AIM_IMFLAGS_TYPINGNOT; } else if (type == 0x0017) { args.extdatalen = length; args.extdata = aimbs_getraw(bs, args.extdatalen); } else { faimdprintf(sess, 0, "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. * */ 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); free(args.extdata); return ret;}static void incomingim_ch2_buddylist(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *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 (servdata && aim_bstream_empty(servdata)) { fu16_t gnlen, numb; int i; char *gn; gnlen = aimbs_get16(servdata); gn = aimbs_getstr(servdata, gnlen); numb = aimbs_get16(servdata); for (i = 0; i < numb; i++) { fu16_t bnlen; char *bn; bnlen = aimbs_get16(servdata); bn = aimbs_getstr(servdata, bnlen); faimdprintf(sess, 0, "got a buddy list from %s: group %s, buddy %s\n", userinfo->sn, gn, bn); free(bn); } free(gn); } return;}static void incomingim_ch2_buddyicon_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args){ free(args->info.icon.icon); return;}static void incomingim_ch2_buddyicon(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata){ if (servdata) { args->info.icon.checksum = aimbs_get32(servdata); args->info.icon.length = aimbs_get32(servdata); args->info.icon.timestamp = aimbs_get32(servdata); args->info.icon.icon = aimbs_getraw(servdata, args->info.icon.length); } args->destructor = (void *)incomingim_ch2_buddyicon_free; return;}static void incomingim_ch2_chat_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args){ /* XXX - aim_chat_roominfo_free() */ free(args->info.chat.roominfo.name); return;}static void incomingim_ch2_chat(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata){ /* * Chat room info. */ if (servdata) aim_chat_readroominfo(servdata, &args->info.chat.roominfo); args->destructor = (void *)incomingim_ch2_chat_free; return;}static void incomingim_ch2_icqserverrelay_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args){ free((char *)args->info.rtfmsg.rtfmsg); return;}/* * The relationship between AIM_CAPS_ICQSERVERRELAY and AIM_CAPS_ICQRTF is * kind of odd. This sends the client ICQRTF since that is all that I've seen * SERVERRELAY used for. * * Note that this is all little-endian. Cringe. * */static void incomingim_ch2_icqserverrelay(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata){ fu16_t hdrlen, anslen, msglen; hdrlen = aimbs_getle16(servdata); aim_bstream_advance(servdata, hdrlen); hdrlen = aimbs_getle16(servdata); aim_bstream_advance(servdata, hdrlen); args->info.rtfmsg.msgtype = aimbs_getle16(servdata); anslen = aimbs_getle32(servdata); aim_bstream_advance(servdata, anslen); msglen = aimbs_getle16(servdata); args->info.rtfmsg.rtfmsg = aimbs_getstr(servdata, msglen); args->info.rtfmsg.fgcolor = aimbs_getle32(servdata); args->info.rtfmsg.bgcolor = aimbs_getle32(servdata); hdrlen = aimbs_getle32(servdata); aim_bstream_advance(servdata, hdrlen); args->destructor = (void *)incomingim_ch2_icqserverrelay_free; return;}static void incomingim_ch2_sendfile_free(aim_session_t *sess, struct aim_incomingim_ch2_args *args){ free(args->info.sendfile.filename);}static void incomingim_ch2_sendfile(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args, aim_bstream_t *servdata){ args->destructor = (void *)incomingim_ch2_sendfile_free; /* Maybe there is a better way to tell what kind of sendfile * this is? Maybe TLV t(000a)? */ if (servdata) { /* Someone is sending us a file */ int flen; /* subtype is one of AIM_OFT_SUBTYPE_* */ args->info.sendfile.subtype = aimbs_get16(servdata); args->info.sendfile.totfiles = aimbs_get16(servdata); args->info.sendfile.totsize = aimbs_get32(servdata); /* * I hope to God I'm right when I guess that there is a * 32 char max filename length for single files. I think * OFT tends to do that. Gotta love inconsistency. I saw * a 26 byte filename? */ /* AAA - create an aimbs_getnullstr function (don't anymore)(maybe) */ /* Use an inelegant way of getting the null-terminated filename, * since there's no easy bstream routine. */ for (flen = 0; aimbs_get8(servdata); flen++); aim_bstream_advance(servdata, -flen -1); args->info.sendfile.filename = aimbs_getstr(servdata, flen); /* There is sometimes more after the null-terminated filename, * but I'm unsure of its format. */ /* I don't believe him. */ } return;}typedef void (*ch2_args_destructor_t)(aim_session_t *sess, struct aim_incomingim_ch2_args *args);static int incomingim_ch2(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_rxcallback_t userfunc; aim_tlv_t *block1, *servdatatlv; aim_tlvlist_t *list2; struct aim_incomingim_ch2_args args; aim_bstream_t bbs, sdbs, *sdbsptr = NULL; fu8_t *cookie2; int ret = 0; char proxyip[30] = {""}; char clientip[30] = {""}; char verifiedip[30] = {""}; memset(&args, 0, sizeof(args)); /* * There's another block of TLVs embedded in the type 5 here. */ block1 = aim_tlv_gettlv(tlvlist, 0x0005, 1); aim_bstream_init(&bbs, block1->value, block1->length); /* * First two bytes represent the status of the connection. * * 0 is a request, 1 is a cancel, 2 is an accept */ args.status = aimbs_get16(&bbs); /* * Next comes the cookie. Should match the ICBM cookie. */ cookie2 = aimbs_getraw(&bbs, 8); if (memcmp(cookie, cookie2, 8) != 0) faimdprintf(sess, 0, "rend: warning cookies don't match!\n"); memcpy(args.cookie, cookie2, 8); free(cookie2); /* * The next 16bytes are a capability block so we can * identify what type of rendezvous this is. */ args.reqclass = aim_locate_getcaps(sess, &bbs, 0x10); /* * What follows may be TLVs or nothing, depending on the * purpose of the message. * * Ack packets for instance have nothing more to them. */ list2 = aim_tlvlist_read(&bbs); /* * IP address to proxy the file transfer through. * * XXX - I don't like this. Maybe just read in an int? Or inet_ntoa... */ if (aim_tlv_gettlv(list2, 0x0002, 1)) { aim_tlv_t *iptlv; iptlv = aim_tlv_gettlv(list2, 0x0002, 1); if (iptlv->length == 4) snprintf(proxyip, sizeof(proxyip), "%hhu.%hhu.%hhu.%hhu", iptlv->value[0], iptlv->value[1], iptlv->value[2], iptlv->value[3]); } /* * IP address from the perspective of the client. */ if (aim_tlv_gettlv(list2, 0x0003, 1)) { aim_tlv_t *iptlv; iptlv = aim_tlv_gettlv(list2, 0x0003, 1); if (iptlv->length == 4) snprintf(clientip, sizeof(clientip), "%hhu.%hhu.%hhu.%hhu", iptlv->value[0], iptlv->value[1], iptlv->value[2], iptlv->value[3]); } /* * Verified IP address (from the perspective of Oscar). * * This is added by the server. */ if (aim_tlv_gettlv(list2, 0x0004, 1)) { aim_tlv_t *iptlv; iptlv = aim_tlv_gettlv(list2, 0x0004, 1); if (iptlv->length == 4) snprintf(verifiedip, sizeof(verifiedip), "%hhu.%hhu.%hhu.%hhu", iptlv->value[0], iptlv->value[1], iptlv->value[2], iptlv->value[3]); } /* * Port number for something. */ if (aim_tlv_gettlv(list2, 0x0005, 1)) args.port = aim_tlv_get16(list2, 0x0005, 1); /* * Something to do with ft? -- two bytes * 0x0001 - "I want to send you this file" * 0x0002 - "I will accept this file from you" * 0x0002 - Also used in ICQ Lite Beta 4.0 URLs */ if (aim_tlv_gettlv(list2, 0x000a, 1)) ; /* * Error code. */ if (aim_tlv_gettlv(list2, 0x000b, 1)) args.errorcode = aim_tlv_get16(list2, 0x000b, 1); /* * Invitation message / chat description. */ if (aim_tlv_gettlv(list2, 0x000c, 1)) { args.msg = aim_tlv_getstr(list2, 0x000c, 1); args.msglen = aim_tlv_getlength(list2, 0x000c, 1); } /* * Character set. */ if (aim_tlv_gettlv(list2, 0x000d, 1)) args.encoding = aim_tlv_getstr(list2, 0x000d, 1); /* * Language. */ if (aim_tlv_gettlv(list2, 0x000e, 1)) args.language = aim_tlv_getstr(list2, 0x000e, 1); /* * Unknown -- no value * * Maybe means we should connect directly to transfer the file? * Also used in ICQ Lite Beta 4.0 URLs. Also empty. */ if (aim_tlv_gettlv(list2, 0x000f, 1)) ; /* * Unknown -- no value * * Maybe means we should proxy the file transfer through an AIM server?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -