static int negchan_middle(aim_session_t *sess, aim_frame_t *fr) { aim_tlvlist_t *tlvlist; char *msg = NULL; fu16_t code = 0; aim_rxcallback_t userfunc; int ret = 1; if (aim_bstream_empty(&fr->data) == 0) { /* XXX should do something with this */ return 1; } /* Used only by the older login protocol */ /* XXX remove this special case? */ if (fr->conn->type == AIM_CONN_TYPE_AUTH) return consumenonsnac(sess, fr, 0x0017, 0x0003); tlvlist = aim_tlvlist_read(&fr->data); if (aim_tlv_gettlv(tlvlist, 0x0009, 1)) code = aim_tlv_get16(tlvlist, 0x0009, 1); if (aim_tlv_gettlv(tlvlist, 0x000b, 1)) msg = aim_tlv_getstr(tlvlist, 0x000b, 1); if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) ret = userfunc(sess, fr, code, msg); aim_tlvlist_free(&tlvlist); free(msg); return ret; }
/* Subtype 0x0003 - BOS Rights. */ static int rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { aim_rxcallback_t userfunc; GSList *tlvlist; guint16 maxpermits = 0, maxdenies = 0; int ret = 0; /* * TLVs follow */ tlvlist = aim_tlvlist_read(bs); /* * TLV type 0x0001: Maximum number of buddies on permit list. */ if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) maxpermits = aim_tlv_get16(tlvlist, 0x0001, 1); /* * TLV type 0x0002: Maximum number of buddies on deny list. */ if (aim_tlv_gettlv(tlvlist, 0x0002, 1)) maxdenies = aim_tlv_get16(tlvlist, 0x0002, 1); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, maxpermits, maxdenies); aim_tlvlist_free(tlvlist); return ret; }
/* * Subtype 0x0007 * * 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(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { int keylen, ret = 1; aim_rxcallback_t userfunc; char *keystr; GSList *tlvlist; gboolean truncate_pass; keylen = byte_stream_get16(bs); keystr = byte_stream_getstr(bs, keylen); tlvlist = aim_tlvlist_read(bs); /* * If the truncate_pass TLV exists then we should truncate the * user's password to 8 characters. This flag is sent to us * when logging in with an AOL user's username. */ truncate_pass = aim_tlv_gettlv(tlvlist, 0x0026, 1) != NULL; /* XXX - When GiantGrayPanda signed on AIM I got a thing asking me to register * for the netscape network. This SNAC had a type 0x0058 TLV with length 10. * Data is 0x0007 0004 3e19 ae1e 0006 0004 0000 0005 */ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, keystr, (int)truncate_pass); g_free(keystr); aim_tlvlist_free(tlvlist); return ret; }
/* Subtype 0x0006 */ static int userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { int ret = 0; aim_rxcallback_t userfunc; aim_userinfo_t *userinfo, *userinfo2; GSList *tlvlist; aim_tlv_t *tlv = NULL; int was_explicit; userinfo = (aim_userinfo_t *)g_malloc(sizeof(aim_userinfo_t)); aim_info_extract(od, bs, userinfo); tlvlist = aim_tlvlist_read(bs); /* Profile will be 1 and 2 */ userinfo->info_encoding = aim_tlv_getstr(tlvlist, 0x0001, 1); if ((tlv = aim_tlv_gettlv(tlvlist, 0x0002, 1))) { userinfo->info = (char *)g_malloc(tlv->length); memcpy(userinfo->info, tlv->value, tlv->length); userinfo->info_len = tlv->length; } /* Away message will be 3 and 4 */ userinfo->away_encoding = aim_tlv_getstr(tlvlist, 0x0003, 1); if ((tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) { userinfo->away = (char *)g_malloc(tlv->length); memcpy(userinfo->away, tlv->value, tlv->length); userinfo->away_len = tlv->length; } /* Caps will be 5 */ if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) { ByteStream cbs; byte_stream_init(&cbs, tlv->value, tlv->length); userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length); userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES; } aim_tlvlist_free(tlvlist); aim_locate_adduserinfo(od, userinfo); userinfo2 = aim_locate_finduserinfo(od, userinfo->sn); aim_info_free(userinfo); g_free(userinfo); /* * Remove this screen name from our queue. If the client requested * this buddy's info explicitly, then notify them that we have info * for this buddy. */ if (userinfo2 != NULL) { was_explicit = aim_locate_gotuserinfo(od, conn, userinfo2->sn); if (was_explicit == TRUE) if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, userinfo2); } return ret; }
/* Subtype 0x0006 */ static int userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { int ret = 0; aim_userinfo_t *userinfo, *userinfo2; GSList *tlvlist; aim_tlv_t *tlv = NULL; userinfo = (aim_userinfo_t *)g_malloc(sizeof(aim_userinfo_t)); aim_info_extract(od, bs, userinfo); tlvlist = aim_tlvlist_read(bs); /* Profile will be 1 and 2 */ userinfo->info_encoding = aim_tlv_getstr(tlvlist, 0x0001, 1); if ((tlv = aim_tlv_gettlv(tlvlist, 0x0002, 1))) { userinfo->info = (char *)g_malloc(tlv->length); memcpy(userinfo->info, tlv->value, tlv->length); userinfo->info_len = tlv->length; } /* Away message will be 3 and 4 */ userinfo->away_encoding = aim_tlv_getstr(tlvlist, 0x0003, 1); if ((tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) { userinfo->away = (char *)g_malloc(tlv->length); memcpy(userinfo->away, tlv->value, tlv->length); userinfo->away_len = tlv->length; } /* Caps will be 5 */ if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) { ByteStream cbs; PurpleAccount *account = purple_connection_get_account(od->gc); const char *mood; byte_stream_init(&cbs, tlv->value, tlv->length); userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length); byte_stream_rewind(&cbs); userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES; mood = aim_receive_custom_icon(od, &cbs, tlv->length); if (mood) purple_prpl_got_user_status(account, userinfo->bn, "mood", PURPLE_MOOD_NAME, mood, NULL); else purple_prpl_got_user_status_deactive(account, userinfo->bn, "mood"); } aim_tlvlist_free(tlvlist); aim_locate_adduserinfo(od, userinfo); userinfo2 = aim_locate_finduserinfo(od, userinfo->bn); aim_info_free(userinfo); g_free(userinfo); /* Show the info to the user */ oscar_user_info_display_aim(od, userinfo2); return ret; }
/* Subtype 0x0006 */ static int userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { int ret = 0; aim_rxcallback_t userfunc; aim_userinfo_t *userinfo, *userinfo2; GSList *tlvlist; aim_tlv_t *tlv = NULL; userinfo = (aim_userinfo_t *)g_malloc(sizeof(aim_userinfo_t)); aim_info_extract(od, bs, userinfo); tlvlist = aim_tlvlist_read(bs); /* Profile will be 1 and 2 */ userinfo->info_encoding = aim_tlv_getstr(tlvlist, 0x0001, 1); if ((tlv = aim_tlv_gettlv(tlvlist, 0x0002, 1))) { userinfo->info = (char *)g_malloc(tlv->length); memcpy(userinfo->info, tlv->value, tlv->length); userinfo->info_len = tlv->length; } /* Away message will be 3 and 4 */ userinfo->away_encoding = aim_tlv_getstr(tlvlist, 0x0003, 1); if ((tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) { userinfo->away = (char *)g_malloc(tlv->length); memcpy(userinfo->away, tlv->value, tlv->length); userinfo->away_len = tlv->length; } /* Caps will be 5 */ if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) { ByteStream cbs; byte_stream_init(&cbs, tlv->value, tlv->length); userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length); userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES; } aim_tlvlist_free(tlvlist); aim_locate_adduserinfo(od, userinfo); userinfo2 = aim_locate_finduserinfo(od, userinfo->bn); aim_info_free(userinfo); g_free(userinfo); /* Show the info to the user */ if (userinfo2 != NULL && ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))) ret = userfunc(od, conn, frame, userinfo2); return ret; }
static int error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { int ret = 0; aim_snac_t *snac2; guint16 error, chatnav_error; GSList *tlvlist; snac2 = aim_remsnac(od, snac->id); if (!snac2) { purple_debug_warning("oscar", "chatnav error: received response to unknown request (%08x)\n", snac->id); return 0; } if (snac2->family != SNAC_FAMILY_CHATNAV) { purple_debug_warning("oscar", "chatnav error: received response that maps to corrupt request (fam=%04x)\n", snac2->family); g_free(snac2->data); g_free(snac2); return 0; } /* * We now know what the original SNAC subtype was. */ if (snac2->type == 0x0008) /* create room */ { error = byte_stream_get16(bs); tlvlist = aim_tlvlist_read(bs); chatnav_error = aim_tlv_get16(tlvlist, 0x0008, 1); purple_debug_warning("oscar", "Could not join room, error=0x%04hx, chatnav_error=0x%04hx\n", error, chatnav_error); purple_notify_error(od->gc, NULL, _("Could not join chat room"), chatnav_error == 0x0033 ? _("Invalid chat room name") : _("Unknown error"), purple_request_cpar_from_connection(od->gc)); ret = 1; } g_free(snac2->data); g_free(snac2); return ret; }
/* * Subtype 0x0002 - General room information. Lots of stuff. * * Values I know are in here but I haven't attached * them to any of the 'Unknown's: * - Language (English) * */ static int infoupdate(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { aim_rxcallback_t userfunc; int ret = 0; guint8 detaillevel = 0; struct aim_chat_roominfo roominfo; GSList *tlvlist; guint16 maxmsglen, maxvisiblemsglen; aim_chat_readroominfo(bs, &roominfo); detaillevel = byte_stream_get8(bs); if (detaillevel != 0x02) { purple_debug_misc("oscar", "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel); return 1; } byte_stream_get16(bs); /* skip the TLV count */ /* * Everything else are TLVs. */ tlvlist = aim_tlvlist_read(bs); /* * Type 0x00d1: Maximum Message Length */ maxmsglen = aim_tlv_get16(tlvlist, 0x00d1, 1); /* * Type 0x00da: Maximum visible message length */ maxvisiblemsglen = aim_tlv_get16(tlvlist, 0x00da, 1); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) { ret = userfunc(od, conn, frame, maxmsglen, maxvisiblemsglen); } g_free(roominfo.name); aim_tlvlist_free(tlvlist); return ret; }
/* * Subtype 0x0003 - Rights. * */ static int rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { aim_rxcallback_t userfunc; GSList *tlvlist; guint16 maxbuddies = 0, maxwatchers = 0; int ret = 0; /* * TLVs follow */ tlvlist = aim_tlvlist_read(bs); /* * TLV type 0x0001: Maximum number of buddies. */ if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) maxbuddies = aim_tlv_get16(tlvlist, 0x0001, 1); /* * TLV type 0x0002: Maximum number of watchers. * * Watchers are other users who have you on their buddy * list. (This is called the "reverse list" by a certain * other IM protocol.) * */ if (aim_tlv_gettlv(tlvlist, 0x0002, 1)) maxwatchers = aim_tlv_get16(tlvlist, 0x0002, 1); /* * TLV type 0x0003: Unknown. * * ICQ only? */ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, maxbuddies, maxwatchers); aim_tlvlist_free(tlvlist); return ret; }
/* * Subtype 0x0003 - Rights. * */ static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; aim_tlvlist_t *tlvlist; fu16_t maxbuddies = 0, maxwatchers = 0; int ret = 0; /* * TLVs follow */ tlvlist = aim_tlvlist_read(bs); /* * TLV type 0x0001: Maximum number of buddies. */ if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) maxbuddies = aim_tlv_get16(tlvlist, 0x0001, 1); /* * TLV type 0x0002: Maximum number of watchers. * * Watchers are other users who have you on their buddy * list. (This is called the "reverse list" by a certain * other IM protocol.) * */ if (aim_tlv_gettlv(tlvlist, 0x0002, 1)) maxwatchers = aim_tlv_get16(tlvlist, 0x0002, 1); /* * TLV type 0x0003: Unknown. * * ICQ only? */ if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, maxbuddies, maxwatchers); aim_tlvlist_free(&tlvlist); return ret; }
/* * Subtype 0x0003 * * Normally contains: * t(0001) - short containing max profile length (value = 1024) * t(0002) - short - unknown (value = 16) [max MIME type length?] * t(0003) - short - unknown (value = 10) * t(0004) - short - unknown (value = 2048) [ICQ only?] */ static int rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { GSList *tlvlist; aim_rxcallback_t userfunc; int ret = 0; guint16 maxsiglen = 0; tlvlist = aim_tlvlist_read(bs); if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) maxsiglen = aim_tlv_get16(tlvlist, 0x0001, 1); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, maxsiglen); aim_tlvlist_free(tlvlist); return ret; }
static void parse_flap_ch4(OscarData *od, FlapConnection *conn, FlapFrame *frame) { GSList *tlvlist; char *msg = NULL; if (byte_stream_bytes_left(&frame->data) == 0) { /* XXX should do something with this */ return; } /* An ICQ account is logging in */ if (conn->type == SNAC_FAMILY_AUTH) { parse_fakesnac(od, conn, frame, 0x0017, 0x0003); return; } tlvlist = aim_tlvlist_read(&frame->data); if (aim_tlv_gettlv(tlvlist, 0x0009, 1)) conn->disconnect_code = aim_tlv_get16(tlvlist, 0x0009, 1); if (aim_tlv_gettlv(tlvlist, 0x000b, 1)) msg = aim_tlv_getstr(tlvlist, 0x000b, 1); /* * The server ended this FLAP connnection, so let's be nice and * close the physical TCP connection */ flap_connection_schedule_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, msg); aim_tlvlist_free(tlvlist); g_free(msg); }
/* * Subtype 0x0002 - General room information. Lots of stuff. * * Values I know are in here but I haven't attached * them to any of the 'Unknown's: * - Language (English) * */ static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_userinfo_t *userinfo = NULL; aim_rxcallback_t userfunc; int ret = 0; int usercount = 0; fu8_t detaillevel = 0; char *roomname = NULL; struct aim_chat_roominfo roominfo; fu16_t tlvcount = 0; aim_tlvlist_t *tlvlist; char *roomdesc = NULL; fu16_t flags = 0; fu32_t creationtime = 0; fu16_t maxmsglen = 0, maxvisiblemsglen = 0; fu16_t unknown_d2 = 0, unknown_d5 = 0; aim_chat_readroominfo(bs, &roominfo); detaillevel = aimbs_get8(bs); if (detaillevel != 0x02) { faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel); return 1; } tlvcount = aimbs_get16(bs); /* * Everything else are TLVs. */ tlvlist = aim_tlvlist_read(bs); /* * TLV type 0x006a is the room name in Human Readable Form. */ if (aim_tlv_gettlv(tlvlist, 0x006a, 1)) roomname = aim_tlv_getstr(tlvlist, 0x006a, 1); /* * Type 0x006f: Number of occupants. */ if (aim_tlv_gettlv(tlvlist, 0x006f, 1)) usercount = aim_tlv_get16(tlvlist, 0x006f, 1); /* * Type 0x0073: Occupant list. */ if (aim_tlv_gettlv(tlvlist, 0x0073, 1)) { int curoccupant = 0; aim_tlv_t *tmptlv; aim_bstream_t occbs; tmptlv = aim_tlv_gettlv(tlvlist, 0x0073, 1); /* Allocate enough userinfo structs for all occupants */ userinfo = calloc(usercount, sizeof(aim_userinfo_t)); aim_bstream_init(&occbs, tmptlv->value, tmptlv->length); while (curoccupant < usercount) aim_info_extract(sess, &occbs, &userinfo[curoccupant++]); } /* * Type 0x00c9: Flags. (AIM_CHATROOM_FLAG) */ if (aim_tlv_gettlv(tlvlist, 0x00c9, 1)) flags = aim_tlv_get16(tlvlist, 0x00c9, 1); /* * Type 0x00ca: Creation time (4 bytes) */ if (aim_tlv_gettlv(tlvlist, 0x00ca, 1)) creationtime = aim_tlv_get32(tlvlist, 0x00ca, 1); /* * Type 0x00d1: Maximum Message Length */ if (aim_tlv_gettlv(tlvlist, 0x00d1, 1)) maxmsglen = aim_tlv_get16(tlvlist, 0x00d1, 1); /* * Type 0x00d2: Unknown. (2 bytes) */ if (aim_tlv_gettlv(tlvlist, 0x00d2, 1)) unknown_d2 = aim_tlv_get16(tlvlist, 0x00d2, 1); /* * Type 0x00d3: Room Description */ if (aim_tlv_gettlv(tlvlist, 0x00d3, 1)) roomdesc = aim_tlv_getstr(tlvlist, 0x00d3, 1); /* * Type 0x000d4: Unknown (flag only) */ if (aim_tlv_gettlv(tlvlist, 0x000d4, 1)) ; /* * Type 0x00d5: Unknown. (1 byte) */ if (aim_tlv_gettlv(tlvlist, 0x00d5, 1)) unknown_d5 = aim_tlv_get8(tlvlist, 0x00d5, 1); /* * Type 0x00d6: Encoding 1 ("us-ascii") */ if (aim_tlv_gettlv(tlvlist, 0x000d6, 1)) ; /* * Type 0x00d7: Language 1 ("en") */ if (aim_tlv_gettlv(tlvlist, 0x000d7, 1)) ; /* * Type 0x00d8: Encoding 2 ("us-ascii") */ if (aim_tlv_gettlv(tlvlist, 0x000d8, 1)) ; /* * Type 0x00d9: Language 2 ("en") */ if (aim_tlv_gettlv(tlvlist, 0x000d9, 1)) ; /* * Type 0x00da: Maximum visible message length */ if (aim_tlv_gettlv(tlvlist, 0x000da, 1)) maxvisiblemsglen = aim_tlv_get16(tlvlist, 0x00da, 1); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { ret = userfunc(sess, rx, &roominfo, roomname, usercount, userinfo, roomdesc, flags, creationtime, maxmsglen, unknown_d2, unknown_d5, maxvisiblemsglen); } free(roominfo.name); while (usercount > 0) aim_info_free(&userinfo[--usercount]); free(userinfo); free(roomname); free(roomdesc); aim_tlvlist_free(&tlvlist); return ret; }
/* * Subtype 0x0006 * * We could probably include this in the normal ICBM parsing * code as channel 0x0003, however, since only the start * would be the same, we might as well do it here. * * General outline of this SNAC: * snac * cookie * channel id * tlvlist * unknown * source user info * name * evility * userinfo tlvs * online time * etc * message metatlv * message tlv * message string * possibly others * */ static int incomingim_ch3(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int ret = 0, i; aim_rxcallback_t userfunc; aim_userinfo_t userinfo; fu8_t cookie[8]; fu16_t channel; aim_tlvlist_t *otl; char *msg = NULL; int len = 0; char *encoding = NULL, *language = NULL; aim_msgcookie_t *ck; memset(&userinfo, 0, sizeof(aim_userinfo_t)); /* * Read ICBM Cookie. */ for (i = 0; i < 8; i++) cookie[i] = aimbs_get8(bs); if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) { free(ck->data); free(ck); } /* * Channel ID * * Channel 0x0003 is used for chat messages. * */ channel = aimbs_get16(bs); if (channel != 0x0003) { faimdprintf(sess, 0, "faim: chat_incoming: unknown channel! (0x%04x)\n", channel); return 0; } /* * Start parsing TLVs right away. */ otl = aim_tlvlist_read(bs); /* * Type 0x0003: Source User Information */ if (aim_tlv_gettlv(otl, 0x0003, 1)) { aim_tlv_t *userinfotlv; aim_bstream_t tbs; userinfotlv = aim_tlv_gettlv(otl, 0x0003, 1); aim_bstream_init(&tbs, userinfotlv->value, userinfotlv->length); aim_info_extract(sess, &tbs, &userinfo); } /* * Type 0x0001: If present, it means it was a message to the * room (as opposed to a whisper). */ if (aim_tlv_gettlv(otl, 0x0001, 1)) ; /* * Type 0x0005: Message Block. Conains more TLVs. */ if (aim_tlv_gettlv(otl, 0x0005, 1)) { aim_tlvlist_t *itl; aim_tlv_t *msgblock; aim_bstream_t tbs; msgblock = aim_tlv_gettlv(otl, 0x0005, 1); aim_bstream_init(&tbs, msgblock->value, msgblock->length); itl = aim_tlvlist_read(&tbs); /* * Type 0x0001: Message. */ if (aim_tlv_gettlv(itl, 0x0001, 1)) { msg = aim_tlv_getstr(itl, 0x0001, 1); len = aim_tlv_gettlv(itl, 0x0001, 1)->length; } /* * Type 0x0002: Encoding. */ if (aim_tlv_gettlv(itl, 0x0002, 1)) encoding = aim_tlv_getstr(itl, 0x0002, 1); /* * Type 0x0003: Language. */ if (aim_tlv_gettlv(itl, 0x0003, 1)) language = aim_tlv_getstr(itl, 0x0003, 1); aim_tlvlist_free(&itl); } if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, &userinfo, len, msg, encoding, language); aim_info_free(&userinfo); free(msg); aim_tlvlist_free(&otl); 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; }
static int parseinfo_create(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs, aim_snac_t *snac2) { aim_rxcallback_t userfunc; GSList *tlvlist, *innerlist; char *ck = NULL, *fqcn = NULL, *name = NULL; guint16 exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0; guint32 createtime = 0; guint8 createperms = 0, detaillevel; int cklen; aim_tlv_t *bigblock; int ret = 0; ByteStream bbbs; tlvlist = aim_tlvlist_read(bs); if (!(bigblock = aim_tlv_gettlv(tlvlist, 0x0004, 1))) { purple_debug_misc("oscar", "no bigblock in top tlv in create room response\n"); aim_tlvlist_free(tlvlist); return 0; } byte_stream_init(&bbbs, bigblock->value, bigblock->length); exchange = byte_stream_get16(&bbbs); cklen = byte_stream_get8(&bbbs); ck = byte_stream_getstr(&bbbs, cklen); instance = byte_stream_get16(&bbbs); detaillevel = byte_stream_get8(&bbbs); if (detaillevel != 0x02) { purple_debug_misc("oscar", "unknown detaillevel in create room response (0x%02x)\n", detaillevel); aim_tlvlist_free(tlvlist); g_free(ck); return 0; } unknown = byte_stream_get16(&bbbs); innerlist = aim_tlvlist_read(&bbbs); if (aim_tlv_gettlv(innerlist, 0x006a, 1)) fqcn = aim_tlv_getstr(innerlist, 0x006a, 1); if (aim_tlv_gettlv(innerlist, 0x00c9, 1)) flags = aim_tlv_get16(innerlist, 0x00c9, 1); if (aim_tlv_gettlv(innerlist, 0x00ca, 1)) createtime = aim_tlv_get32(innerlist, 0x00ca, 1); if (aim_tlv_gettlv(innerlist, 0x00d1, 1)) maxmsglen = aim_tlv_get16(innerlist, 0x00d1, 1); if (aim_tlv_gettlv(innerlist, 0x00d2, 1)) maxoccupancy = aim_tlv_get16(innerlist, 0x00d2, 1); if (aim_tlv_gettlv(innerlist, 0x00d3, 1)) name = aim_tlv_getstr(innerlist, 0x00d3, 1); if (aim_tlv_gettlv(innerlist, 0x00d5, 1)) createperms = aim_tlv_get8(innerlist, 0x00d5, 1); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) { ret = userfunc(od, conn, frame, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck); } g_free(ck); g_free(name); g_free(fqcn); aim_tlvlist_free(innerlist); aim_tlvlist_free(tlvlist); return ret; }
/* * This is sent back as a general response to the login command. * It can be either an error or a success, depending on the * presence of certain TLVs. * * The client should check the value passed as errorcode. If * its nonzero, there was an error. */ static int parse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { GSList *tlvlist; aim_rxcallback_t userfunc; struct aim_authresp_info *info; int ret = 0; info = g_new0(struct aim_authresp_info, 1); /* * Read block of TLVs. All further data is derived * from what is parsed here. */ tlvlist = aim_tlvlist_read(bs); /* * No matter what, we should have a username. */ if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) { info->bn = aim_tlv_getstr(tlvlist, 0x0001, 1); purple_connection_set_display_name(od->gc, info->bn); } /* * Check for an error code. If so, we should also * have an error url. */ if (aim_tlv_gettlv(tlvlist, 0x0008, 1)) info->errorcode = aim_tlv_get16(tlvlist, 0x0008, 1); if (aim_tlv_gettlv(tlvlist, 0x0004, 1)) info->errorurl = aim_tlv_getstr(tlvlist, 0x0004, 1); /* * BOS server address. */ if (aim_tlv_gettlv(tlvlist, 0x0005, 1)) info->bosip = aim_tlv_getstr(tlvlist, 0x0005, 1); /* * Authorization cookie. */ if (aim_tlv_gettlv(tlvlist, 0x0006, 1)) { aim_tlv_t *tmptlv; tmptlv = aim_tlv_gettlv(tlvlist, 0x0006, 1); if (tmptlv != NULL) { info->cookielen = tmptlv->length; info->cookie = tmptlv->value; } } /* * The email address attached to this account * Not available for ICQ or @mac.com logins. * If you receive this TLV, then you are allowed to use * family 0x0018 to check the status of your email. * XXX - Not really true! */ if (aim_tlv_gettlv(tlvlist, 0x0011, 1)) info->email = aim_tlv_getstr(tlvlist, 0x0011, 1); /* * The registration status. (Not real sure what it means.) * Not available for ICQ or @mac.com logins. * * 1 = No disclosure * 2 = Limited disclosure * 3 = Full disclosure * * This has to do with whether your email address is available * to other users or not. AFAIK, this feature is no longer used. * * Means you can use the admin family? (0x0007) * */ if (aim_tlv_gettlv(tlvlist, 0x0013, 1)) info->regstatus = aim_tlv_get16(tlvlist, 0x0013, 1); if (aim_tlv_gettlv(tlvlist, 0x0040, 1)) info->latestbeta.build = aim_tlv_get32(tlvlist, 0x0040, 1); if (aim_tlv_gettlv(tlvlist, 0x0041, 1)) info->latestbeta.url = aim_tlv_getstr(tlvlist, 0x0041, 1); if (aim_tlv_gettlv(tlvlist, 0x0042, 1)) info->latestbeta.info = aim_tlv_getstr(tlvlist, 0x0042, 1); if (aim_tlv_gettlv(tlvlist, 0x0043, 1)) info->latestbeta.name = aim_tlv_getstr(tlvlist, 0x0043, 1); #if 0 if (aim_tlv_gettlv(tlvlist, 0x0048, 1)) { /* beta serial */ } #endif if (aim_tlv_gettlv(tlvlist, 0x0044, 1)) info->latestrelease.build = aim_tlv_get32(tlvlist, 0x0044, 1); if (aim_tlv_gettlv(tlvlist, 0x0045, 1)) info->latestrelease.url = aim_tlv_getstr(tlvlist, 0x0045, 1); if (aim_tlv_gettlv(tlvlist, 0x0046, 1)) info->latestrelease.info = aim_tlv_getstr(tlvlist, 0x0046, 1); if (aim_tlv_gettlv(tlvlist, 0x0047, 1)) info->latestrelease.name = aim_tlv_getstr(tlvlist, 0x0047, 1); #if 0 if (aim_tlv_gettlv(tlvlist, 0x0049, 1)) { /* lastest release serial */ } #endif /* * URL to change password. */ if (aim_tlv_gettlv(tlvlist, 0x0054, 1)) info->chpassurl = aim_tlv_getstr(tlvlist, 0x0054, 1); #if 0 /* * Unknown. Seen on an @mac.com username with value of 0x003f */ if (aim_tlv_gettlv(tlvlist, 0x0055, 1)) { /* Unhandled */ } #endif od->authinfo = info; if ((userfunc = aim_callhandler(od, snac ? snac->family : SNAC_FAMILY_AUTH, snac ? snac->subtype : 0x0003))) ret = userfunc(od, conn, frame, info); aim_tlvlist_free(tlvlist); return ret; }
static int parseinfo_perms(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs, aim_snac_t *snac2) { aim_rxcallback_t userfunc; int ret = 0; struct aim_chat_exchangeinfo *exchanges = NULL; int curexchange; aim_tlv_t *exchangetlv; guint8 maxrooms = 0; GSList *tlvlist, *innerlist; tlvlist = aim_tlvlist_read(bs); /* * Type 0x0002: Maximum concurrent rooms. */ if (aim_tlv_gettlv(tlvlist, 0x0002, 1)) maxrooms = aim_tlv_get8(tlvlist, 0x0002, 1); /* * Type 0x0003: Exchange information * * There can be any number of these, each one * representing another exchange. * */ for (curexchange = 0; ((exchangetlv = aim_tlv_gettlv(tlvlist, 0x0003, curexchange+1))); ) { ByteStream tbs; byte_stream_init(&tbs, exchangetlv->value, exchangetlv->length); curexchange++; exchanges = g_realloc(exchanges, curexchange * sizeof(struct aim_chat_exchangeinfo)); /* exchange number */ exchanges[curexchange-1].number = byte_stream_get16(&tbs); innerlist = aim_tlvlist_read(&tbs); /* * Type 0x0002: Unknown */ if (aim_tlv_gettlv(innerlist, 0x0002, 1)) { guint16 classperms; classperms = aim_tlv_get16(innerlist, 0x0002, 1); purple_debug_misc("oscar", "faim: class permissions %x\n", classperms); } /* * Type 0x00c9: Flags * * 1 Evilable * 2 Nav Only * 4 Instancing Allowed * 8 Occupant Peek Allowed * */ if (aim_tlv_gettlv(innerlist, 0x00c9, 1)) exchanges[curexchange-1].flags = aim_tlv_get16(innerlist, 0x00c9, 1); /* * Type 0x00d3: Exchange Description */ if (aim_tlv_gettlv(innerlist, 0x00d3, 1)) exchanges[curexchange-1].name = aim_tlv_getstr(innerlist, 0x00d3, 1); else exchanges[curexchange-1].name = NULL; /* * Type 0x00d5: Creation Permissions * * 0 Creation not allowed * 1 Room creation allowed * 2 Exchange creation allowed * */ if (aim_tlv_gettlv(innerlist, 0x00d5, 1)) aim_tlv_get8(innerlist, 0x00d5, 1); /* createperms */ /* * Type 0x00d6: Character Set (First Time) */ if (aim_tlv_gettlv(innerlist, 0x00d6, 1)) exchanges[curexchange-1].charset1 = aim_tlv_getstr(innerlist, 0x00d6, 1); else exchanges[curexchange-1].charset1 = NULL; /* * Type 0x00d7: Language (First Time) */ if (aim_tlv_gettlv(innerlist, 0x00d7, 1)) exchanges[curexchange-1].lang1 = aim_tlv_getstr(innerlist, 0x00d7, 1); else exchanges[curexchange-1].lang1 = NULL; /* * Type 0x00d8: Character Set (Second Time) */ if (aim_tlv_gettlv(innerlist, 0x00d8, 1)) exchanges[curexchange-1].charset2 = aim_tlv_getstr(innerlist, 0x00d8, 1); else exchanges[curexchange-1].charset2 = NULL; /* * Type 0x00d9: Language (Second Time) */ if (aim_tlv_gettlv(innerlist, 0x00d9, 1)) exchanges[curexchange-1].lang2 = aim_tlv_getstr(innerlist, 0x00d9, 1); else exchanges[curexchange-1].lang2 = NULL; aim_tlvlist_free(innerlist); } /* * Call client. */ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, snac2->type, maxrooms, curexchange, exchanges); for (curexchange--; curexchange >= 0; curexchange--) { g_free(exchanges[curexchange].name); g_free(exchanges[curexchange].charset1); g_free(exchanges[curexchange].lang1); g_free(exchanges[curexchange].charset2); g_free(exchanges[curexchange].lang2); } g_free(exchanges); aim_tlvlist_free(tlvlist); return ret; }
/* * Subtype 0x0006 * * We could probably include this in the normal ICBM parsing * code as channel 0x0003, however, since only the start * would be the same, we might as well do it here. * * General outline of this SNAC: * snac * cookie * channel id * tlvlist * unknown * source user info * name * evility * userinfo tlvs * online time * etc * message metatlv * message tlv * message string * possibly others * */ static int incomingim_ch3(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { int ret = 0, i; aim_rxcallback_t userfunc; aim_userinfo_t userinfo; guint8 cookie[8]; guint16 channel; GSList *tlvlist; char *msg = NULL; int len = 0; char *encoding = NULL, *language = NULL; IcbmCookie *ck; aim_tlv_t *tlv; ByteStream tbs; memset(&userinfo, 0, sizeof(aim_userinfo_t)); /* * Read ICBM Cookie. */ for (i = 0; i < 8; i++) cookie[i] = byte_stream_get8(bs); if ((ck = aim_uncachecookie(od, cookie, AIM_COOKIETYPE_CHAT))) { g_free(ck->data); g_free(ck); } /* * Channel ID * * Channel 0x0003 is used for chat messages. * */ channel = byte_stream_get16(bs); if (channel != 0x0003) { purple_debug_misc("oscar", "faim: chat_incoming: unknown channel! (0x%04x)\n", channel); return 0; } /* * Start parsing TLVs right away. */ tlvlist = aim_tlvlist_read(bs); /* * Type 0x0003: Source User Information */ tlv = aim_tlv_gettlv(tlvlist, 0x0003, 1); if (tlv != NULL) { byte_stream_init(&tbs, tlv->value, tlv->length); aim_info_extract(od, &tbs, &userinfo); } /* * Type 0x0005: Message Block. Conains more TLVs. */ tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1); if (tlv != NULL) { GSList *inner_tlvlist; aim_tlv_t *inner_tlv; byte_stream_init(&tbs, tlv->value, tlv->length); inner_tlvlist = aim_tlvlist_read(&tbs); /* * Type 0x0001: Message. */ inner_tlv = aim_tlv_gettlv(inner_tlvlist, 0x0001, 1); if (inner_tlv != NULL) { len = inner_tlv->length; msg = aim_tlv_getvalue_as_string(inner_tlv); } /* * Type 0x0002: Encoding. */ encoding = aim_tlv_getstr(inner_tlvlist, 0x0002, 1); /* * Type 0x0003: Language. */ language = aim_tlv_getstr(inner_tlvlist, 0x0003, 1); aim_tlvlist_free(inner_tlvlist); } if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, &userinfo, len, msg, encoding, language); aim_info_free(&userinfo); g_free(msg); g_free(encoding); g_free(language); aim_tlvlist_free(tlvlist); return ret; }