📄 im.c
字号:
/* * XXX: there are a couple of different request packets for * different things */ if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, 0x0002, userinfo, args); return ret;}/* XXX Ugh. I think its obvious. */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_tlv_t *block1; aim_tlvlist_t *list2; int ret = 0; struct aim_incomingim_ch2_args args; aim_bstream_t bbs; fu8_t *cookie2; memset(&args, 0, sizeof(args)); /* * There's another block of TLVs embedded in the type 5 here. */ if (!(block1 = aim_gettlv(tlvlist, 0x0005, 1)) || !block1->value) { faimdprintf(sess, 0, "no tlv 0x0005 in rendezvous transaction!\n"); return 0; } aim_bstream_init(&bbs, block1->value, block1->length); /* * First two bytes represent the status of the connection. * * 0 is a request, 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. * * Thanks to Eric Warmenhoven <warmenhoven@linux.com> (of GAIM) * for pointing some of this out to me. In fact, a lot of * the client-to-client info comes from the work of the GAIM * developers. Thanks! * * Read off one capability string and we should have it ID'd. * */ if ((args.reqclass = aim_getcap(sess, &bbs, 0x10)) == 0x0000) { faimdprintf(sess, 0, "rend: no ID block\n"); return 0; } /* * 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_readtlvchain(&bbs);#if 0 /* this should be in the per-type blocks */ if (!list2 || ((args.reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) { aim_msgcookie_t *cook; int type; type = aim_msgcookie_gettype(args.reqclass); /* XXX: fix this shitty code */ if ((cook = aim_checkcookie(sess, cookie, type)) == NULL) { faimdprintf(sess, 0, "non-data rendezvous thats not in cache (type %d)\n", type); aim_freetlvchain(&list2); return 1; } if (cook->type == AIM_COOKIETYPE_OFTGET) { struct aim_filetransfer_priv *ft; if (cook->data) { int errorcode = -1; /* XXX shouldnt this be 0? */ ft = (struct aim_filetransfer_priv *)cook->data; if (args.status != 0x0002) { if (aim_gettlv(list2, 0x000b, 1)) errorcode = aim_gettlv16(list2, 0x000b, 1); /* XXX this should make it up to the client, you know.. */ if (errorcode) faimdprintf(sess, 0, "transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sn, ft->ip, ft->fh.name, errorcode); } /* args.status != 0x0002 */ } else { faimdprintf(sess, 0, "no data attached to file transfer\n"); } /* !cook->data */ } else if (cook->type == AIM_CAPS_VOICE) { faimdprintf(sess, 0, "voice request cancelled\n"); } else { faimdprintf(sess, 0, "unknown cookie cache type %d\n", cook->type); } aim_freetlvchain(&list2); return 1; }#endif /* * The rest of the handling depends on what type it is. */ if (args.reqclass & AIM_CAPS_BUDDYICON) ret = incomingim_ch2_buddyicon(sess, mod, rx, snac, userinfo, &args, list2); else if (args.reqclass & AIM_CAPS_SENDBUDDYLIST) ret = incomingim_ch2_buddylist(sess, mod, rx, snac, userinfo, &args, list2); else if (args.reqclass & AIM_CAPS_VOICE) ret = incomingim_ch2_voice(sess, mod, rx, snac, userinfo, &args, list2); else if (args.reqclass & AIM_CAPS_IMIMAGE) ret = incomingim_ch2_imimage(sess, mod, rx, snac, userinfo, &args, list2); else if (args.reqclass & AIM_CAPS_CHAT) ret = incomingim_ch2_chat(sess, mod, rx, snac, userinfo, &args, list2); else if (args.reqclass & AIM_CAPS_GETFILE) ret = incomingim_ch2_getfile(sess, mod, rx, snac, userinfo, &args, list2); else if (args.reqclass & AIM_CAPS_SENDFILE) ret = incomingim_ch2_sendfile(sess, mod, rx, snac, userinfo, &args, list2); else faimdprintf(sess, 0, "rend: unknown rendezvous 0x%04x\n", args.reqclass); aim_freetlvchain(&list2); return ret;}/* * 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. And throw away. */ for (i = 0; i < 8; i++) cookie[i] = aimbs_get8(bs); /* * Channel ID. * * Channel 0x0001 is the message channel. There are * other channels for things called "rendevous" * which represent chat and some of the other new * features of AIM2/3/3.5. * * Channel 0x0002 is the Rendevous channel, which * is where Chat Invitiations and various client-client * connection negotiations come from. * */ 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 seperation. * aim_extractuserinfo() returns the number of bytes used by the * userinfo tlvs, so you can start reading the rest of them right * afterward. * * 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_extractuserinfo(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 == 0x0002) { 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_readtlvchain(bs); ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie); /* * Free up the TLV chain. */ aim_freetlvchain(&tlvlist); } else { faimdprintf(sess, 0, "icbm: ICBM received on an unsupported channel. Ignoring.\n (chan = %04x)", channel); return 0; } return ret;}/* * 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_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_addtlvtochain16(&tl, 0x0003, code); aim_writetlvchain(&fr->data, &tl); aim_freetlvchain(&tl); aim_tx_enqueue(sess, fr); return 0;}/* * aim_reqicbmparaminfo() * * Request ICBM parameter information. * */faim_export int aim_reqicbmparams(aim_session_t *sess){ aim_conn_t *conn; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) return -EINVAL; return aim_genericreq_n(sess, conn, 0x0004, 0x0004);}/* * * I definitly recommend sending this. If you don't, you'll be stuck * with the rather unreasonable defaults. You don't want those. Send this. * */faim_export int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params){ aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) return -EINVAL; if (!params) return -EINVAL; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+16))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0004, 0x0002, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0004, 0x0002, 0x0000, snacid); /* This is read-only (see Parameter Reply). Must be set to zero here. */ aimbs_put16(&fr->data, 0x0000); /* These are all read-write */ aimbs_put32(&fr->data, params->flags); aimbs_put16(&fr->data, params->maxmsglen); aimbs_put16(&fr->data, params->maxsenderwarn); aimbs_put16(&fr->data, params->maxrecverwarn); aimbs_put32(&fr->data, params->minmsginterval); aim_tx_enqueue(sess, fr); return 0;}static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs){ struct aim_icbmparameters params; aim_rxcallback_t userfunc; params.maxchan = aimbs_get16(bs); params.flags = aimbs_get32(bs); params.maxmsglen = aimbs_get16(bs); params.maxsenderwarn = aimbs_get16(bs); params.maxrecverwarn = aimbs_get16(bs); params.minmsginterval = aimbs_get32(bs); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) return userfunc(sess, rx, ¶ms); return 0;}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_extractuserinfo(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); } return ret;}static int clienterr(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 ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, channel, sn, reason); free(ck); free(sn); return ret;}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 type; fu8_t snlen, *ck; char *sn; int ret = 0; ck = aimbs_getraw(bs, 8); type = aimbs_get16(bs); snlen = aimbs_get8(bs); sn = aimbs_getstr(bs, snlen); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, type, sn); free(sn); free(ck); return ret;}static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs){ if (snac->subtype == 0x0005) return paraminfo(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0006) return outgoingim(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0007) return incomingim(sess, mod, rx, snac, bs); else if (snac->subtype == 0x000a) return missedcall(sess, mod, rx, snac, bs); else if (snac->subtype == 0x000b) return clienterr(sess, mod, rx, snac, bs); else if (snac->subtype == 0x000c) return msgack(sess, mod, rx, snac, bs); return 0;}faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod){ mod->family = 0x0004; mod->version = 0x0001; mod->toolid = 0x0110; mod->toolversion = 0x047b; mod->flags = 0; strncpy(mod->name, "messaging", sizeof(mod->name)); mod->snachandler = snachandler; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -