/** * Subtype 0x0005 - Receive a buddy icon. * * This is sent in response to a buddy icon request. */ static int parseicon(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; char *sn; fu16_t flags, iconlen; fu8_t iconcsumtype, iconcsumlen, *iconcsum, *icon; sn = aimbs_getstr(bs, aimbs_get8(bs)); flags = aimbs_get16(bs); iconcsumtype = aimbs_get8(bs); iconcsumlen = aimbs_get8(bs); iconcsum = aimbs_getraw(bs, iconcsumlen); iconlen = aimbs_get16(bs); icon = aimbs_getraw(bs, iconlen); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, sn, iconcsumtype, iconcsum, iconcsumlen, icon, iconlen); free(sn); free(iconcsum); free(icon); return ret; }
faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo) { int namelen; if (!bs || !outinfo) return 0; outinfo->exchange = aimbs_get16(bs); namelen = aimbs_get8(bs); outinfo->name = aimbs_getstr(bs, namelen); outinfo->instance = aimbs_get16(bs); return 0; }
/* called for both reply and change-reply */ static int infochange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { /* * struct { * guint16 perms; * guint16 tlvcount; * aim_tlv_t tlvs[tlvcount]; * } admin_info[n]; */ while (aim_bstream_empty(bs)) { guint16 perms, tlvcount; perms = aimbs_get16(bs); tlvcount = aimbs_get16(bs); while (tlvcount && aim_bstream_empty(bs)) { aim_rxcallback_t userfunc; guint16 type, len; guint8 *val; int str = 0; type = aimbs_get16(bs); len = aimbs_get16(bs); if ((type == 0x0011) || (type == 0x0004)) { str = 1; } if (str) { val = (guint8 *) aimbs_getstr(bs, len); } else { val = aimbs_getraw(bs, len); } /* XXX fix so its only called once for the entire packet */ if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { userfunc(sess, rx, (snac->subtype == 0x0005) ? 1 : 0, perms, type, len, val, str); } g_free(val); tlvcount--; } } return 1; }
/* * Middle handler for 0017/0007 SNACs. Contains the auth key prefixed * by only its length in a two byte word. * * Calls the client, which should then use the value to call aim_send_login. * */ static int keyparse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int keylen, ret = 1; aim_rxcallback_t userfunc; char *keystr; keylen = aimbs_get16(bs); keystr = aimbs_getstr(bs, keylen); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, keystr); g_free(keystr); return ret; }
/* * 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; char *sn; guint8 snlen; guint16 type1, type2; aim_bstream_advance(bs, 8); /* Unknown - All 0's */ type1 = aimbs_get16(bs); snlen = aimbs_get8(bs); sn = aimbs_getstr(bs, snlen); type2 = aimbs_get16(bs); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, type1, sn, type2); g_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; guint16 type; guint8 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); g_free(sn); g_free(ck); return ret; }
static int parseinfo_create(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs, aim_snac_t *snac2) { aim_rxcallback_t userfunc; aim_tlvlist_t *tlvlist, *innerlist; char *ck = NULL, *fqcn = NULL, *name = NULL; fu16_t exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0; fu32_t createtime = 0; fu8_t createperms = 0, detaillevel; int cklen; aim_tlv_t *bigblock; int ret = 0; aim_bstream_t bbbs; tlvlist = aim_readtlvchain(bs); if (!(bigblock = aim_gettlv(tlvlist, 0x0004, 1))) { faimdprintf(sess, 0, "no bigblock in top tlv in create room response\n"); aim_freetlvchain(&tlvlist); return 0; } aim_bstream_init(&bbbs, bigblock->value, bigblock->length); exchange = aimbs_get16(&bbbs); cklen = aimbs_get8(&bbbs); ck = aimbs_getstr(&bbbs, cklen); instance = aimbs_get16(&bbbs); detaillevel = aimbs_get8(&bbbs); if (detaillevel != 0x02) { faimdprintf(sess, 0, "unknown detaillevel in create room response (0x%02x)\n", detaillevel); aim_freetlvchain(&tlvlist); free(ck); return 0; } unknown = aimbs_get16(&bbbs); innerlist = aim_readtlvchain(&bbbs); if (aim_gettlv(innerlist, 0x006a, 1)) fqcn = aim_gettlv_str(innerlist, 0x006a, 1); if (aim_gettlv(innerlist, 0x00c9, 1)) flags = aim_gettlv16(innerlist, 0x00c9, 1); if (aim_gettlv(innerlist, 0x00ca, 1)) createtime = aim_gettlv32(innerlist, 0x00ca, 1); if (aim_gettlv(innerlist, 0x00d1, 1)) maxmsglen = aim_gettlv16(innerlist, 0x00d1, 1); if (aim_gettlv(innerlist, 0x00d2, 1)) maxoccupancy = aim_gettlv16(innerlist, 0x00d2, 1); if (aim_gettlv(innerlist, 0x00d3, 1)) name = aim_gettlv_str(innerlist, 0x00d3, 1); if (aim_gettlv(innerlist, 0x00d5, 1)) createperms = aim_gettlv8(innerlist, 0x00d5, 1); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { ret = userfunc(sess, rx, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck); } free(ck); free(name); free(fqcn); aim_freetlvchain(&innerlist); aim_freetlvchain(&tlvlist); return ret; }
/** * Subtype 0x0003 - Response to 0x0015/0x002, contains an ICQesque packet. */ static int icqresponse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int ret = 0; aim_tlvlist_t *tl; aim_tlv_t *datatlv; aim_bstream_t qbs; fu32_t ouruin; fu16_t cmdlen, cmd, reqid; if (!(tl = aim_tlvlist_read(bs)) || !(datatlv = aim_tlv_gettlv(tl, 0x0001, 1))) { aim_tlvlist_free(&tl); faimdprintf(sess, 0, "corrupt ICQ response\n"); return 0; } aim_bstream_init(&qbs, datatlv->value, datatlv->length); cmdlen = aimbs_getle16(&qbs); ouruin = aimbs_getle32(&qbs); cmd = aimbs_getle16(&qbs); reqid = aimbs_getle16(&qbs); faimdprintf(sess, 1, "icq response: %d bytes, %ld, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid); if (cmd == 0x0041) { /* offline message */ struct aim_icq_offlinemsg msg; aim_rxcallback_t userfunc; memset(&msg, 0, sizeof(msg)); msg.sender = aimbs_getle32(&qbs); msg.year = aimbs_getle16(&qbs); msg.month = aimbs_getle8(&qbs); msg.day = aimbs_getle8(&qbs); msg.hour = aimbs_getle8(&qbs); msg.minute = aimbs_getle8(&qbs); msg.type = aimbs_getle8(&qbs); msg.flags = aimbs_getle8(&qbs); msg.msglen = aimbs_getle16(&qbs); msg.msg = aimbs_getstr(&qbs, msg.msglen); if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG))) ret = userfunc(sess, rx, &msg); free(msg.msg); } else if (cmd == 0x0042) { aim_rxcallback_t userfunc; if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE))) ret = userfunc(sess, rx); } else if (cmd == 0x07da) { /* information */ fu16_t subtype; struct aim_icq_info *info; aim_rxcallback_t userfunc; subtype = aimbs_getle16(&qbs); aim_bstream_advance(&qbs, 1); /* 0x0a */ /* find other data from the same request */ for (info = sess->icq_info; info && (info->reqid != reqid); info = info->next); if (!info) { info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info)); info->reqid = reqid; info->next = sess->icq_info; sess->icq_info = info; } switch (subtype) { case 0x00a0: { /* hide ip status */ /* nothing */ } break; case 0x00aa: { /* password change status */ /* nothing */ } break; case 0x00c8: { /* general and "home" information */ info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->homecity = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->homestate = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->homephone = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->homefax = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->homeaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->mobile = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->homezip = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->homecountry = aimbs_getle16(&qbs); /* 0x0a 00 02 00 */ /* 1 byte timezone? */ /* 1 byte hide email flag? */ } break; case 0x00dc: { /* personal information */ info->age = aimbs_getle8(&qbs); info->unknown = aimbs_getle8(&qbs); info->gender = aimbs_getle8(&qbs); /* Not specified=0x00, Female=0x01, Male=0x02 */ info->personalwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->birthyear = aimbs_getle16(&qbs); info->birthmonth = aimbs_getle8(&qbs); info->birthday = aimbs_getle8(&qbs); info->language1 = aimbs_getle8(&qbs); info->language2 = aimbs_getle8(&qbs); info->language3 = aimbs_getle8(&qbs); /* 0x00 00 01 00 00 01 00 00 00 00 00 */ } break; case 0x00d2: { /* work information */ info->workcity = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->workstate = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->workphone = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->workfax = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->workaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->workzip = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->workcountry = aimbs_getle16(&qbs); info->workcompany = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->workdivision = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->workposition = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); aim_bstream_advance(&qbs, 2); /* 0x01 00 */ info->workwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); } break; case 0x00e6: { /* additional personal information */ info->info = aimbs_getstr(&qbs, aimbs_getle16(&qbs)-1); } break; case 0x00eb: { /* email address(es) */ int i; info->numaddresses = aimbs_getle16(&qbs); info->email2 = (char **)calloc(info->numaddresses, sizeof(char *)); for (i = 0; i < info->numaddresses; i++) { info->email2[i] = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); if (i+1 != info->numaddresses) aim_bstream_advance(&qbs, 1); /* 0x00 */ } } break; case 0x00f0: { /* personal interests */ } break; case 0x00fa: { /* past background and current organizations */ } break; case 0x0104: { /* alias info */ info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); aim_bstream_advance(&qbs, aimbs_getle16(&qbs)); /* email address? */ /* Then 0x00 02 00 */ } break; case 0x010e: { /* unknown */ /* 0x00 00 */ } break; case 0x019a: { /* simple info */ aim_bstream_advance(&qbs, 2); info->uin = aimbs_getle32(&qbs); info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); /* Then 0x00 02 00 00 00 00 00 */ } break; } /* End switch statement */ if (!(snac->flags & 0x0001)) { if (subtype != 0x0104) if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_INFO))) ret = userfunc(sess, rx, info); if (info->uin && info->nick) if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_ALIAS))) ret = userfunc(sess, rx, info); if (sess->icq_info == info) { sess->icq_info = info->next; } else { struct aim_icq_info *cur; for (cur=sess->icq_info; (cur->next && (cur->next!=info)); cur=cur->next); if (cur->next) cur->next = cur->next->next; } aim_icq_freeinfo(info); } } aim_tlvlist_free(&tl); return ret; }
/* * 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. * * This cap is used for auto status message replies, too [ft] * */ 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) { guint16 hdrlen, msglen, dc; guint8 msgtype; guint8 *plugin; int i = 0, tmp = 0; struct im_connection *ic = sess->aux_data; /* at the moment we just can deal with requests, not with cancel or accept */ if (args->status != 0) return; hdrlen = aimbs_getle16(servdata); aim_bstream_advance(servdata, 0x02); /* protocol version */ plugin = aimbs_getraw(servdata, 0x10); /* following data is a message or something plugin specific */ /* as there is no plugin handling, just skip the rest */ aim_bstream_advance(servdata, hdrlen - 0x12); hdrlen = aimbs_getle16(servdata); dc = aimbs_getle16(servdata); /* save the sequence number */ aim_bstream_advance(servdata, hdrlen - 0x02); /* TODO is it a message or something for a plugin? */ for (i = 0; i < 0x10; i++) { tmp |= plugin[i]; } if (!tmp) { /* message follows */ msgtype = aimbs_getle8(servdata); aimbs_getle8(servdata); /* msgflags */ aim_bstream_advance(servdata, 0x04); /* status code and priority code */ msglen = aimbs_getle16(servdata); /* message string length */ args->info.rtfmsg.rtfmsg = aimbs_getstr(servdata, msglen); switch(msgtype) { case AIM_MTYPE_PLAIN: args->info.rtfmsg.fgcolor = aimbs_getle32(servdata); args->info.rtfmsg.bgcolor = aimbs_getle32(servdata); hdrlen = aimbs_getle32(servdata); aim_bstream_advance(servdata, hdrlen); /* XXX This is such a hack. */ args->reqclass = AIM_CAPS_ICQRTF; break; case AIM_MTYPE_AUTOAWAY: case AIM_MTYPE_AUTOBUSY: case AIM_MTYPE_AUTONA: case AIM_MTYPE_AUTODND: case AIM_MTYPE_AUTOFFC: case 0x9c: /* ICQ 5 seems to send this */ aim_send_im_ch2_statusmessage(sess, userinfo->sn, args->cookie, ic->away ? ic->away : "", sess->aim_icq_state, dc); break; } } /* message or plugin specific */ g_free(plugin); args->destructor = (void *)incomingim_ch2_icqserverrelay_free; 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(aim_session_t *sess, guint8 *data, int len, struct aim_incomingim_ch1_args *args) { static const guint16 charsetpri[] = { 0x0000, /* ASCII first */ 0x0003, /* then ISO-8859-1 */ 0x0002, /* UNICODE as last resort */ }; static const int charsetpricount = 3; int i; aim_bstream_t mbs; aim_mpmsg_section_t *sec; aim_bstream_init(&mbs, data, len); while (aim_bstream_empty(&mbs)) { guint16 msglen, flag1, flag2; char *msgbuf; aimbs_get8(&mbs); /* 01 */ aimbs_get8(&mbs); /* 01 */ /* Message string length, including character set info. */ msglen = aimbs_get16(&mbs); /* Character set info */ flag1 = aimbs_get16(&mbs); flag2 = aimbs_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 = aimbs_getstr(&mbs, msglen); mpmsg_addsection(sess, &args->mpmsg, flag1, flag2, (guint8 *)msgbuf, (guint16) 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; args->icbmflags |= AIM_IMFLAGS_CUSTOMCHARSET; /* Set up the simple flags */ if (args->charset == 0x0000) ; /* ASCII */ else if (args->charset == 0x0002) args->icbmflags |= AIM_IMFLAGS_UNICODE; else if (args->charset == 0x0003) args->icbmflags |= AIM_IMFLAGS_ISO_8859_1; else if (args->charset == 0xffff) ; /* no encoding (yeep!) */ if (args->charsubset == 0x0000) ; /* standard subencoding? */ else if (args->charsubset == 0x000b) args->icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH; else if (args->charsubset == 0xffff) ; /* no subencoding */ #if 0 /* XXX this isn't really necesary... */ if ( ((args.flag1 != 0x0000) && (args.flag1 != 0x0002) && (args.flag1 != 0x0003) && (args.flag1 != 0xffff)) || ((args.flag2 != 0x0000) && (args.flag2 != 0x000b) && (args.flag2 != 0xffff))) { faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", args.flag1, args.flag2); } #endif args->msg = (char *)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 outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int i, ret = 0; aim_rxcallback_t userfunc; guint16 channel; aim_tlvlist_t *tlvlist; char *sn; int snlen; guint16 icbmflags = 0; guint8 flag1 = 0, flag2 = 0; char *msg = NULL; aim_tlv_t *msgblock; /* ICBM Cookie. */ for (i = 0; i < 8; i++) aimbs_get8(bs); /* Channel ID */ channel = aimbs_get16(bs); if (channel != 0x01) { imcb_error(sess->aux_data, "icbm: ICBM received on unsupported channel. Ignoring."); return 0; } snlen = aimbs_get8(bs); sn = aimbs_getstr(bs, snlen); tlvlist = aim_readtlvchain(bs); if (aim_gettlv(tlvlist, 0x0003, 1)) icbmflags |= AIM_IMFLAGS_ACK; if (aim_gettlv(tlvlist, 0x0004, 1)) icbmflags |= AIM_IMFLAGS_AWAY; if ((msgblock = aim_gettlv(tlvlist, 0x0002, 1))) { aim_bstream_t mbs; int featurelen, msglen; aim_bstream_init(&mbs, msgblock->value, msgblock->length); aimbs_get8(&mbs); aimbs_get8(&mbs); for (featurelen = aimbs_get16(&mbs); featurelen; featurelen--) aimbs_get8(&mbs); aimbs_get8(&mbs); aimbs_get8(&mbs); msglen = aimbs_get16(&mbs) - 4; /* final block length */ flag1 = aimbs_get16(&mbs); flag2 = aimbs_get16(&mbs); msg = aimbs_getstr(&mbs, msglen); } if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, channel, sn, msg, icbmflags, flag1, flag2); g_free(sn); aim_freetlvchain(&tlvlist); return ret; }
/* * 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; guint16 channel, reason; char *sn; guint8 *ck, snlen; ck = aimbs_getraw(bs, 8); channel = aimbs_get16(bs); snlen = aimbs_get8(bs); sn = aimbs_getstr(bs, snlen); reason = aimbs_get16(bs); switch (reason) { case 0x0003: { /* ICQ status message. Maybe other stuff too, you never know with these people. */ guint8 statusmsgtype, *msg; guint16 len; guint32 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); g_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 */ g_free(ck); g_free(sn); return ret; }
/* * Response to 15/2, contains an ICQ packet. */ static int icqresponse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int ret = 0; aim_tlvlist_t *tl; aim_tlv_t *datatlv; aim_bstream_t qbs; fu32_t ouruin; fu16_t cmdlen, cmd, reqid; if (!(tl = aim_readtlvchain(bs)) || !(datatlv = aim_gettlv(tl, 0x0001, 1))) { aim_freetlvchain(&tl); faimdprintf(sess, 0, "corrupt ICQ response\n"); return 0; } aim_bstream_init(&qbs, datatlv->value, datatlv->length); cmdlen = aimbs_getle16(&qbs); ouruin = aimbs_getle32(&qbs); cmd = aimbs_getle16(&qbs); reqid = aimbs_getle16(&qbs); faimdprintf(sess, 1, "icq response: %d bytes, %ld, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid); if (cmd == 0x0041) { fu16_t msglen; struct aim_icq_offlinemsg msg; aim_rxcallback_t userfunc; memset(&msg, 0, sizeof(msg)); msg.sender = aimbs_getle32(&qbs); msg.year = aimbs_getle16(&qbs); msg.month = aimbs_getle8(&qbs); msg.day = aimbs_getle8(&qbs); msg.hour = aimbs_getle8(&qbs); msg.minute = aimbs_getle8(&qbs); msg.type = aimbs_getle16(&qbs); msglen = aimbs_getle16(&qbs); msg.msg = aimbs_getstr(&qbs, msglen); if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG))) ret = userfunc(sess, rx, &msg); free(msg.msg); } else if (cmd == 0x0042) { aim_rxcallback_t userfunc; if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE))) ret = userfunc(sess, rx); } else if (cmd == 0x07da) { fu16_t subtype; subtype = aimbs_getle16(&qbs); if (subtype == 0x019a) { fu16_t tlen; struct aim_icq_simpleinfo info; aim_rxcallback_t userfunc; memset(&info, 0, sizeof(info)); aimbs_getle8(&qbs); /* no clue */ aimbs_getle16(&qbs); /* no clue */ info.uin = aimbs_getle32(&qbs); tlen = aimbs_getle16(&qbs); info.nick = aimbs_getstr(&qbs, tlen); tlen = aimbs_getle16(&qbs); info.first = aimbs_getstr(&qbs, tlen); tlen = aimbs_getle16(&qbs); info.last = aimbs_getstr(&qbs, tlen); tlen = aimbs_getle16(&qbs); info.email = aimbs_getstr(&qbs, tlen); /* no clue what the rest of it is */ if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_SIMPLEINFO))) ret = userfunc(sess, rx, &info); free(info.nick); free(info.first); free(info.last); free(info.email); } else if (subtype == 100 || subtype == 150) { fu16_t tlen; struct aim_icq_smsresponse response; aim_rxcallback_t userfunc; memset(&response, 0, sizeof(response)); for(tlen = 0; tlen < 7; tlen++) aimbs_getle8(&qbs); /* no clue */ response.type = subtype; tlen = aimbs_getle16(&qbs); response.tag = aimbs_getstr(&qbs, tlen); tlen = aimbs_getle16(&qbs); response.xml = aimbs_getstr(&qbs, tlen); if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_SMSRESPONSE))) ret = userfunc(sess, rx, &response); free(response.tag); free(response.xml); } else faimdprintf(sess, 1, "unknown subtype 0x%04x\n", subtype); } aim_freetlvchain(&tl); return ret; }
/** * Subtype 0x0003 - Response to 0x0015/0x002, contains an ICQesque packet. */ static int icqresponse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int ret = 0; aim_tlvlist_t *tl; aim_tlv_t *datatlv; aim_bstream_t qbs; guint32 ouruin; guint16 cmdlen, cmd, reqid; if (!(tl = aim_readtlvchain(bs)) || !(datatlv = aim_gettlv(tl, 0x0001, 1))) { aim_freetlvchain(&tl); imcb_error(sess->aux_data, "corrupt ICQ response\n"); return 0; } aim_bstream_init(&qbs, datatlv->value, datatlv->length); cmdlen = aimbs_getle16(&qbs); ouruin = aimbs_getle32(&qbs); cmd = aimbs_getle16(&qbs); reqid = aimbs_getle16(&qbs); if (cmd == 0x0041) { /* offline message */ guint16 msglen; struct aim_icq_offlinemsg msg; aim_rxcallback_t userfunc; memset(&msg, 0, sizeof(msg)); msg.sender = aimbs_getle32(&qbs); msg.year = aimbs_getle16(&qbs); msg.month = aimbs_getle8(&qbs); msg.day = aimbs_getle8(&qbs); msg.hour = aimbs_getle8(&qbs); msg.minute = aimbs_getle8(&qbs); msg.type = aimbs_getle16(&qbs); msglen = aimbs_getle16(&qbs); msg.msg = aimbs_getstr(&qbs, msglen); if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG))) ret = userfunc(sess, rx, &msg); g_free(msg.msg); } else if (cmd == 0x0042) { aim_rxcallback_t userfunc; if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE))) ret = userfunc(sess, rx); } else if (cmd == 0x07da) { /* information */ guint16 subtype; struct aim_icq_info *info; aim_rxcallback_t userfunc; subtype = aimbs_getle16(&qbs); aim_bstream_advance(&qbs, 1); /* 0x0a */ /* find another data from the same request */ for (info = sess->icq_info; info && (info->reqid != reqid); info = info->next); if (!info) { info = g_new0(struct aim_icq_info, 1); info->reqid = reqid; info->next = sess->icq_info; sess->icq_info = info; }