From 0c20631fc9dd6411357abe57e146196087631010 Mon Sep 17 00:00:00 2001 From: mid Date: Sun, 2 Jan 2000 10:40:26 +0000 Subject: [PATCH] Implemented chat and some chatnav. Nearly a 2000line diff. --- CHANGES | 21 +- aim_chat.c | 657 ++++++++++++++++++++++++++++++++-- aim_chatnav.c | 323 +++++++++++++++++ aim_conn.c | 9 +- aim_im.c | 110 ++++-- aim_info.c | 52 +-- aim_misc.c | 24 +- aim_rxhandlers.c | 64 +++- aim_tlv.c | 7 +- aim_txqueue.c | 6 +- faim/aim.h | 54 ++- faim/aim_cbtypes.h | 7 + faim/faimconfig.h | 2 +- tcpdumps/randombits.txt | 728 ++++++++++++++++++++++++++++++++++++++ utils/faimtest/faimtest.c | 337 ++++++++++++++---- 15 files changed, 2210 insertions(+), 191 deletions(-) create mode 100644 tcpdumps/randombits.txt diff --git a/CHANGES b/CHANGES index 2f79562..e1bd75d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,14 +1,31 @@ No release numbers ------------------ + - Sun Jan 2 10:31:19 UTC 2000 + - Cleanups in aim_info.c + - Can compile with -Ddebug=100 again + - Implemented chat: Joining/Leaving, info parsing, IM parsing/sending + - Implemented some chatnav: rights req/parsing, room creation + + - Thu Dec 30 10:08:42 UTC 1999 + - Fixed bug in aim_im.c when (encoding == NULL) || (lang == NULL) + - Added detection of voice chat requests + - Added AIM_CLASS_* defines, including new Away flag + - Added awaymsg parameter to bos_setprofile. + - If awaymsg is nonnull, you will be advertised as being away (your + class will be ORed with AIM_CLASS_AWAY), otherwise you'll show + up normal. + - Wed Dec 29 10:06:35 UTC 1999 - Fixed small bug in IM parser - Added stubs for the capability TLVs in userinfo. - Wed Dec 29 09:14:45 UTC 1999 - - Added a capability block to aim_bos_setprofile. Can now get chat invites again. + - Added a capability block to aim_bos_setprofile. Can now get chat + invites again. - Extended ICBM parser to support channel 2 messages (chat invites) - - A channel parameter has been prepended to the varargs -- REQUIRES CLIENT CHANGES. + - A channel parameter has been prepended to the varargs -- REQUIRES + CLIENT CHANGES. - Extended faimtest to support chat invites. - Changed faimtest to get sn/password from environment diff --git a/aim_chat.c b/aim_chat.c index a7af344..6ce4b69 100644 --- a/aim_chat.c +++ b/aim_chat.c @@ -7,15 +7,145 @@ #include +char *aim_chat_getname(struct aim_conn_t *conn) +{ + if (!conn) + return NULL; + if (conn->type != AIM_CONN_TYPE_CHAT) + return NULL; + + return (char *)conn->priv; /* yuck ! */ +} + +struct aim_conn_t *aim_chat_getconn(struct aim_session_t *sess, char *name) +{ + int i; + + for (i=0;iconns[i].type == AIM_CONN_TYPE_CHAT) + { + if (sess->conns[i].priv) + if (!strcmp((char *)sess->conns[i].priv, name)) + { + return &sess->conns[i]; + } + } + } + return NULL; +} + +int aim_chat_attachname(struct aim_conn_t *conn, char *roomname) +{ + if (!conn || !roomname) + return -1; + + conn->priv = malloc(strlen(roomname)+1); + strcpy(conn->priv, roomname); + + return 0; +} + +u_long aim_chat_send_im(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *msg) +{ + + int curbyte,i; + struct command_tx_struct newpacket; + + if (!sess || !conn || !msg) + return 0; + + newpacket.lock = 1; /* lock struct */ + newpacket.type = 0x02; /* IMs are always family 0x02 */ + + /* + * Since we must have a specific connection, then theres + * no use in going on if we don't have one... + */ + if (!conn) + return sess->snac_nextid; + newpacket.conn = conn; + + /* + * Its simplest to set this arbitrarily large and waste + * space. Precalculating is costly here. + */ + newpacket.commandlen = 1152; + + newpacket.data = (u_char *) calloc(1, newpacket.commandlen); + + curbyte = 0; + curbyte += aim_putsnac(newpacket.data+curbyte, + 0x000e, 0x0005, 0x0000, sess->snac_nextid); + + /* + * Generate a random message cookie + * + */ + for (i=0;i<8;i++) + curbyte += aimutil_put8(newpacket.data+curbyte, (u_char) random()); + + /* + * metaTLV start. -- i assume this is a metaTLV. it could be the + * channel ID though. + */ + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0003); + + /* + * Type 1: Unknown. Blank. + */ + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); + + /* + * Type 6: Unknown. Blank. + */ + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0006); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); + + /* + * Type 5: Message block. Contains more TLVs. + * + * This could include other information... We just + * put in a message TLV however. + * + */ + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0005); + curbyte += aimutil_put16(newpacket.data+curbyte, strlen(msg)+4); + + /* + * SubTLV: Type 1: Message + */ + curbyte += aim_puttlv_str(newpacket.data+curbyte, 0x0001, strlen(msg), msg); + + newpacket.commandlen = curbyte; + + newpacket.lock = 0; + aim_tx_enqueue(sess, &newpacket); + + return (sess->snac_nextid++); +} + /* - * FIXME: Doesn't work. + * Join a room of name roomname. This is the first + * step to joining an already created room. It's + * basically a Service Request for family 0x000e, + * with a little added on to specify the exchange + * and room name. * */ u_long aim_chat_join(struct aim_session_t *sess, struct aim_conn_t *conn, + u_short exchange, const char *roomname) { struct command_tx_struct newpacket; + int i; + + if (!sess || !conn || !roomname) + return 0; newpacket.lock = 1; if (conn) @@ -23,35 +153,45 @@ u_long aim_chat_join(struct aim_session_t *sess, else newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); - newpacket.type = 0x0002; + newpacket.type = 0x02; - newpacket.commandlen = 12+7+strlen(roomname)+6; + newpacket.commandlen = 10 + 9 + strlen(roomname) + 2; newpacket.data = (char *) malloc(newpacket.commandlen); memset(newpacket.data, 0x00, newpacket.commandlen); - aim_putsnac(newpacket.data, 0x0001, 0x0004, 0x0000, sess->snac_nextid); + i = aim_putsnac(newpacket.data, 0x0001, 0x0004, 0x0000, sess->snac_nextid); - newpacket.data[10] = 0x00; - newpacket.data[11] = 0x0e; - newpacket.data[12] = 0x00; - newpacket.data[13] = 0x01; - newpacket.data[14] = 0x00; - newpacket.data[15] = 0x0c; - newpacket.data[16] = 0x00; - newpacket.data[17] = 0x04; - newpacket.data[18] = strlen(roomname) & 0x00ff; - memcpy(&(newpacket.data[19]), roomname, strlen(roomname)); - - { - u_int i = 0; - printf("\n\n\n"); - for (i = 0;i < newpacket.commandlen; i++) - printf("0x%02x ", newpacket.data[i]); - printf("\n\n\n"); - } + i+= aimutil_put16(newpacket.data+i, 0x000e); + + /* + * this is techinally a TLV, but we can't use normal functions + * because we need the extraneous nulls and other weird things. + */ + i+= aimutil_put16(newpacket.data+i, 0x0001); + i+= aimutil_put16(newpacket.data+i, 2+1+strlen(roomname)+2); + i+= aimutil_put16(newpacket.data+i, exchange); + i+= aimutil_put8(newpacket.data+i, strlen(roomname)); + memcpy(newpacket.data+i, roomname, strlen(roomname)); + i+= strlen(roomname); + //i+= aimutil_putstr(newpacket.data+i, roomname, strlen(roomname)); + i+= aimutil_put16(newpacket.data+i, 0x0000); + /* + * Chat hack. + * + * XXX: A problem occurs here if we request a channel + * join but it fails....pendingjoin will be nonnull + * even though the channel is never going to get a + * redirect! + * + */ + sess->pendingjoin = (char *)malloc(strlen(roomname)+1); + strcpy(sess->pendingjoin, roomname); + + newpacket.lock = 0; aim_tx_enqueue(sess, &newpacket); +#if 0 { struct aim_snac_t snac; @@ -60,11 +200,480 @@ u_long aim_chat_join(struct aim_session_t *sess, snac.type = 0x0004; snac.flags = 0x0000; - snac.data = malloc(strlen(roomname)); - memcpy(snac.data, roomname, strlen(roomname)); + snac.data = malloc(strlen(roomname)+1); + strcpy(snac.data, roomname); aim_newsnac(sess, &snac); } +#endif + return (sess->snac_nextid++); +} + +int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo) +{ + int namelen = 0; + int i = 0; + + if (!buf || !outinfo) + return 0; + + outinfo->exchange = aimutil_get16(buf+i); + i += 2; + + namelen = aimutil_get8(buf+i); + i += 1; + + outinfo->name = (char *)malloc(namelen+1); + memcpy(outinfo->name, buf+i, namelen); + outinfo->name[namelen] = '\0'; + i += namelen; + + outinfo->instance = aimutil_get16(buf+i); + i += 2; + + return i; +}; + + +/* + * General room information. Lots of stuff. + * + * Values I know are in here but I havent attached + * them to any of the 'Unknown's: + * - Language (English) + * + */ +int aim_chat_parse_infoupdate(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + struct aim_userinfo_s *userinfo; + rxcallback_t userfunc=NULL; + int ret = 1, i = 0; + int usercount = 0; + u_char detaillevel = 0; + char *roomname; + struct aim_chat_roominfo roominfo; + u_short tlvcount = 0; + struct aim_tlvlist_t *tlvlist; + char *roomdesc; + + i = 10; + i += aim_chat_readroominfo(command->data+i, &roominfo); + + detaillevel = aimutil_get8(command->data+i); + i++; + + tlvcount = aimutil_get16(command->data+i); + i += 2; + + /* + * Everything else are TLVs. + */ + tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); + + /* + * TLV type 0x006a is the room name in Human Readable Form. + */ + if (aim_gettlv(tlvlist, 0x006a, 1)) + roomname = aim_gettlv_str(tlvlist, 0x006a, 1); + + /* + * Type 0x006f: Number of occupants. + */ + if (aim_gettlv(tlvlist, 0x006f, 1)) + { + struct aim_tlv_t *tmptlv; + tmptlv = aim_gettlv(tlvlist, 0x006f, 1); + + usercount = aimutil_get16(tmptlv->value); + } + + /* + * Type 0x0073: Occupant list. + */ + if (aim_gettlv(tlvlist, 0x0073, 1)) + { + int curoccupant = 0; + struct aim_tlv_t *tmptlv; + + tmptlv = aim_gettlv(tlvlist, 0x0073, 1); + + /* Allocate enough userinfo structs for all occupants */ + userinfo = calloc(usercount, sizeof(struct aim_userinfo_s)); + + i = 0; + while (curoccupant < usercount) + i += aim_extractuserinfo(tmptlv->value+i, &userinfo[curoccupant++]); + } + + /* + * Type 0x00c9: Unknown. + */ + if (aim_gettlv(tlvlist, 0x00c9, 1)) + ; + + /* + * Type 0x00ca: Creation date + */ + if (aim_gettlv(tlvlist, 0x00ca, 1)) + ; + + /* + * Type 0x00d1: Maximum Message Length + */ + if (aim_gettlv(tlvlist, 0x00d1, 1)) + ; + + /* + * Type 0x00d2: Unknown. + */ + if (aim_gettlv(tlvlist, 0x00d2, 1)) + ; + + /* + * Type 0x00d3: Room Description + */ + if (aim_gettlv(tlvlist, 0x00d3, 1)) + roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1); + + /* + * Type 0x00d5: Unknown. + */ + if (aim_gettlv(tlvlist, 0x00d5, 1)) + ; + + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE); + if (userfunc) + { + ret = userfunc(sess, + command, + &roominfo, + roomname, + usercount, + userinfo, + roomdesc); + } + free(roominfo.name); + free(userinfo); + free(roomname); + free(roomdesc); + aim_freetlvchain(&tlvlist); + + return ret; +} + +int aim_chat_parse_joined(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + struct aim_userinfo_s *userinfo = NULL; + rxcallback_t userfunc=NULL; + int i = 10, curcount = 0, ret = 1; + + while (i < command->commandlen) + { + curcount++; + userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); + i += aim_extractuserinfo(command->data+i, &userinfo[curcount-1]); + } + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN); + if (userfunc) + { + ret = userfunc(sess, + command, + curcount, + userinfo); + } + + free(userinfo); + + return ret; +} + +int aim_chat_parse_leave(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + + struct aim_userinfo_s *userinfo = NULL; + rxcallback_t userfunc=NULL; + int i = 10, curcount = 0, ret = 1; + + while (i < command->commandlen) + { + curcount++; + userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); + i += aim_extractuserinfo(command->data+i, &userinfo[curcount-1]); + } + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE); + if (userfunc) + { + ret = userfunc(sess, + command, + curcount, + userinfo); + } + + free(userinfo); + + return ret; +} + +/* + * 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. + */ +int aim_chat_parse_incoming(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + struct aim_userinfo_s userinfo; + rxcallback_t userfunc=NULL; + int ret = 1, i = 0, z = 0; + u_char cookie[8]; + int channel; + struct aim_tlvlist_t *outerlist; + char *msg = NULL; + + memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); + + i = 10; /* skip snac */ + + /* + * ICBM Cookie. Ignore it. + */ + for (z=0; z<8; z++,i++) + cookie[z] = command->data[i]; + + /* + * Channel ID + * + * Channels 1 and 2 are implemented in the normal ICBM + * parser. + * + * We only do channel 3 here. + * + */ + channel = aimutil_get16(command->data+i); + i += 2; + + if (channel != 0x0003) + { + printf("faim: chat_incoming: unknown channel! (0x%04x)\n", channel); + return 1; + } + + /* + * Start parsing TLVs right away. + */ + outerlist = aim_readtlvchain(command->data+i, command->commandlen-i); + + /* + * Type 0x0003: Source User Information + */ + if (aim_gettlv(outerlist, 0x0003, 1)) + { + struct aim_tlv_t *userinfotlv; + + userinfotlv = aim_gettlv(outerlist, 0x0003, 1); + aim_extractuserinfo(userinfotlv->value, &userinfo); + } + + /* + * Type 0x0001: Unknown. + */ + if (aim_gettlv(outerlist, 0x0001, 1)) + ; + + /* + * Type 0x0005: Message Block. Conains more TLVs. + */ + if (aim_gettlv(outerlist, 0x0005, 1)) + { + struct aim_tlvlist_t *innerlist; + struct aim_tlv_t *msgblock; + + msgblock = aim_gettlv(outerlist, 0x0005, 1); + innerlist = aim_readtlvchain(msgblock->value, msgblock->length); + + /* + * Type 0x0001: Message. + */ + if (aim_gettlv(innerlist, 0x0001, 1)) + msg = aim_gettlv_str(innerlist, 0x0001, 1); + + aim_freetlvchain(&innerlist); + } + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG); + if (userfunc) + { + ret = userfunc(sess, + command, + &userinfo, + msg); + } + free(msg); + aim_freetlvchain(&outerlist); + + return ret; +} + +u_long aim_chat_clientready(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct command_tx_struct newpacket; + int i; + + newpacket.lock = 1; + if (conn) + newpacket.conn = conn; + else + newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_CHAT); + newpacket.type = 0x02; + newpacket.commandlen = 0x20; + + newpacket.data = (char *) malloc(newpacket.commandlen); + i = aim_putsnac(newpacket.data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + + i+= aimutil_put16(newpacket.data+i, 0x000e); + i+= aimutil_put16(newpacket.data+i, 0x0001); + + i+= aimutil_put16(newpacket.data+i, 0x0004); + i+= aimutil_put16(newpacket.data+i, 0x0001); + + i+= aimutil_put16(newpacket.data+i, 0x0001); + i+= aimutil_put16(newpacket.data+i, 0x0003); + + i+= aimutil_put16(newpacket.data+i, 0x0004); + i+= aimutil_put16(newpacket.data+i, 0x0686); + + newpacket.lock = 0; + aim_tx_enqueue(sess, &newpacket); + + return (sess->snac_nextid++); +} + +int aim_chat_leaveroom(struct aim_session_t *sess, char *name) +{ + int i; + + for (i=0;iconns[i].type == AIM_CONN_TYPE_CHAT) + { + if (sess->conns[i].priv) + if (!strcmp((char *)sess->conns[i].priv, name)) + { + aim_conn_close(&sess->conns[i]); + return 0; + } + } + } + return -1; +} + +/* + * conn must be a BOS connection! + */ +u_long aim_chat_invite(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *sn, + char *msg, + u_short exchange, + char *roomname, + u_short instance) +{ + struct command_tx_struct newpacket; + int i,curbyte=0; + + if (!sess || !conn || !sn || !msg || !roomname) + return 0; + + newpacket.lock = 1; + if (conn) + newpacket.conn = conn; + else + newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); + newpacket.type = 0x02; + newpacket.commandlen = 1152+strlen(sn)+strlen(roomname)+strlen(msg); + + newpacket.data = (char *) malloc(newpacket.commandlen); + curbyte = aim_putsnac(newpacket.data, 0x0004, 0x0006, 0x0000, sess->snac_nextid); + + /* + * Cookie + */ + for (i=0;i<8;i++) + curbyte += aimutil_put8(newpacket.data+curbyte, (u_char)rand()); + + /* + * Channel (2) + */ + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0002); + + /* + * Dest sn + */ + curbyte += aimutil_put8(newpacket.data+curbyte, strlen(sn)); + curbyte += aimutil_putstr(newpacket.data+curbyte, sn, strlen(sn)); + + /* + * TLV t(0005) + */ + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0005); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x28+strlen(msg)+0x04+0x03+strlen(roomname)+0x02); + + /* + * Unknown info + */ + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x3131); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x3538); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x3446); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x4100); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x748f); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x2420); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x6287); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x11d1); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x8222); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x4445); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x5354); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); + + /* + * TLV t(000a) -- Unknown + */ + curbyte += aimutil_put16(newpacket.data+curbyte, 0x000a); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0002); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); + + /* + * TLV t(000f) -- Unknown + */ + curbyte += aimutil_put16(newpacket.data+curbyte, 0x000f); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); + + /* + * TLV t(000c) -- Invitation message + */ + curbyte += aim_puttlv_str(newpacket.data+curbyte, 0x000c, strlen(msg), msg); + + /* + * TLV t(2711) -- Container for room information + */ + curbyte += aimutil_put16(newpacket.data+curbyte, 0x2711); + curbyte += aimutil_put16(newpacket.data+curbyte, 3+strlen(roomname)+2); + curbyte += aimutil_put16(newpacket.data+curbyte, exchange); + curbyte += aimutil_put8(newpacket.data+curbyte, strlen(roomname)); + curbyte += aimutil_putstr(newpacket.data+curbyte, roomname, strlen(roomname)); + curbyte += aimutil_put16(newpacket.data+curbyte, instance); + + newpacket.commandlen = curbyte; + newpacket.lock = 0; + aim_tx_enqueue(sess, &newpacket); + return (sess->snac_nextid++); } diff --git a/aim_chatnav.c b/aim_chatnav.c index be99cfd..b6764e1 100644 --- a/aim_chatnav.c +++ b/aim_chatnav.c @@ -7,3 +7,326 @@ #include + +/* + * conn must be a chatnav connection! + */ +u_long aim_chatnav_reqrights(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct aim_snac_t snac; + + snac.id = aim_genericreq_n(sess, conn, 0x000d, 0x0002); + + snac.family = 0x000d; + snac.type = 0x0002; + snac.flags = 0x0000; + snac.data = NULL; + + aim_newsnac(sess, &snac); + + return (sess->snac_nextid); /* already incremented */ +} + +u_long aim_chatnav_clientready(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct command_tx_struct newpacket; + int i; + + newpacket.lock = 1; + if (conn) + newpacket.conn = conn; + else + newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV); + newpacket.type = 0x02; + newpacket.commandlen = 0x20; + + newpacket.data = (char *) malloc(newpacket.commandlen); + i = aim_putsnac(newpacket.data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + + i+= aimutil_put16(newpacket.data+i, 0x000d); + i+= aimutil_put16(newpacket.data+i, 0x0001); + + i+= aimutil_put16(newpacket.data+i, 0x0004); + i+= aimutil_put16(newpacket.data+i, 0x0001); + + i+= aimutil_put16(newpacket.data+i, 0x0001); + i+= aimutil_put16(newpacket.data+i, 0x0003); + + i+= aimutil_put16(newpacket.data+i, 0x0004); + i+= aimutil_put16(newpacket.data+i, 0x0686); + + aim_tx_enqueue(sess, &newpacket); + + return (sess->snac_nextid++); +} + +/* + * Since multiple things can trigger this callback, + * we must lookup the snacid to determine the original + * snac subtype that was called. + */ +int aim_chatnav_parse_info(struct aim_session_t *sess, struct command_rx_struct *command) +{ + struct aim_snac_t *snac; + u_long snacid; + rxcallback_t userfunc; + + snacid = aimutil_get32(command->data+6); + snac = aim_remsnac(sess, snacid); + + if (!snac) + { + printf("faim: chatnav_parse_info: received response to unknown request! (%08lx)\n", snacid); + return 1; + } + + if (snac->family != 0x000d) + { + printf("faim: chatnav_parse_info: recieved response that maps to corrupt request! (fam=%04x)\n", snac->family); + return 1; + } + + /* + * We now know what the original SNAC subtype was. + */ + switch(snac->type) + { + case 0x0002: /* request chat rights */ + { + struct aim_tlvlist_t *tlvlist; + struct aim_chat_exchangeinfo *exchanges = NULL; + int curexchange = 0; + struct aim_tlv_t *exchangetlv; + u_char maxrooms = 0; + int ret = 1; + struct aim_tlvlist_t *innerlist; + + tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10); + + /* + * Type 0x0002: Maximum concurrent rooms. + */ + if (aim_gettlv(tlvlist, 0x0002, 1)) + { + struct aim_tlv_t *maxroomstlv; + maxroomstlv = aim_gettlv(tlvlist, 0x0002, 1); + maxrooms = aimutil_get8(maxroomstlv->value); + } + + /* + * Type 0x0003: Exchange information + * + * There can be any number of these, each one + * representing another exchange. + * + */ + curexchange = 0; + while ((exchangetlv = aim_gettlv(tlvlist, 0x0003, curexchange+1))) + { + curexchange++; + exchanges = realloc(exchanges, curexchange * sizeof(struct aim_chat_exchangeinfo)); + + /* exchange number */ + exchanges[curexchange-1].number = aimutil_get16(exchangetlv->value); + innerlist = aim_readtlvchain(exchangetlv->value+2, exchangetlv->length-2); + + /* + * Type 0x000d: Unknown. + */ + if (aim_gettlv(innerlist, 0x000d, 1)) + ; + + /* + * Type 0x0004: Unknown + */ + if (aim_gettlv(innerlist, 0x0004, 1)) + ; + + /* + * Type 0x00c9: Unknown + */ + if (aim_gettlv(innerlist, 0x00c9, 1)) + ; + + /* + * Type 0x00ca: Creation Date + */ + if (aim_gettlv(innerlist, 0x00ca, 1)) + ; + + /* + * Type 0x00d0: Unknown + */ + if (aim_gettlv(innerlist, 0x00d0, 1)) + ; + + /* + * Type 0x00d1: Maximum Message length + */ + if (aim_gettlv(innerlist, 0x00d1, 1)) + ; + + /* + * Type 0x00d2: Unknown + */ + if (aim_gettlv(innerlist, 0x00d2, 1)) + ; + + /* + * Type 0x00d3: Exchange Name + */ + if (aim_gettlv(innerlist, 0x00d3, 1)) + exchanges[curexchange-1].name = aim_gettlv_str(innerlist, 0x00d3, 1); + else + exchanges[curexchange-1].name = NULL; + + /* + * Type 0x00d5: Unknown + */ + if (aim_gettlv(innerlist, 0x00d5, 1)) + ; + + /* + * Type 0x00d6: Character Set (First Time) + */ + if (aim_gettlv(innerlist, 0x00d6, 1)) + exchanges[curexchange-1].charset1 = aim_gettlv_str(innerlist, 0x00d6, 1); + else + exchanges[curexchange-1].charset1 = NULL; + + /* + * Type 0x00d7: Language (First Time) + */ + if (aim_gettlv(innerlist, 0x00d7, 1)) + exchanges[curexchange-1].lang1 = aim_gettlv_str(innerlist, 0x00d7, 1); + else + exchanges[curexchange-1].lang1 = NULL; + + /* + * Type 0x00d8: Character Set (Second Time) + */ + if (aim_gettlv(innerlist, 0x00d8, 1)) + exchanges[curexchange-1].charset2 = aim_gettlv_str(innerlist, 0x00d8, 1); + else + exchanges[curexchange-1].charset2 = NULL; + + /* + * Type 0x00d9: Language (Second Time) + */ + if (aim_gettlv(innerlist, 0x00d9, 1)) + exchanges[curexchange-1].lang2 = aim_gettlv_str(innerlist, 0x00d9, 1); + else + exchanges[curexchange-1].lang2 = NULL; + + } + + /* + * Call client. + */ + userfunc = aim_callhandler(command->conn, 0x000d, 0x0009); + if (userfunc) + ret = userfunc(sess, + command, + snac->type, + maxrooms, + curexchange, + exchanges); + curexchange--; + while(curexchange) + { + if (exchanges[curexchange].name) + free(exchanges[curexchange].name); + if (exchanges[curexchange].charset1) + free(exchanges[curexchange].charset1); + if (exchanges[curexchange].lang1) + free(exchanges[curexchange].lang1); + if (exchanges[curexchange].charset2) + free(exchanges[curexchange].charset2); + if (exchanges[curexchange].lang2) + free(exchanges[curexchange].lang2); + curexchange--; + } + free(exchanges); + aim_freetlvchain(&innerlist); + aim_freetlvchain(&tlvlist); + return ret; + } + case 0x0003: /* request exchange info */ + printf("faim: chatnav_parse_info: resposne to exchange info\n"); + return 1; + case 0x0004: /* request room info */ + printf("faim: chatnav_parse_info: response to room info\n"); + return 1; + case 0x0005: /* request more room info */ + printf("faim: chatnav_parse_info: response to more room info\n"); + return 1; + case 0x0006: /* request occupant list */ + printf("faim: chatnav_parse_info: response to occupant info\n"); + return 1; + case 0x0007: /* search for a room */ + printf("faim: chatnav_parse_info: search results\n"); + return 1; + case 0x0008: /* create room */ + printf("faim: chatnav_parse_info: response to create room\n"); + return 1; + default: /* unknown */ + printf("faim: chatnav_parse_info: unknown request subtype (%04x)\n", snac->type); + } + + return 1; /* shouldn't get here */ +} + +u_long aim_chatnav_createroom(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *name, + u_short exchange) +{ + struct command_tx_struct newpacket; + int i; + struct aim_snac_t snac; + + newpacket.lock = 1; + if (conn) + newpacket.conn = conn; + else + newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV); + newpacket.type = 0x02; + + newpacket.commandlen = 10 + 12 + strlen("invite") + strlen(name); + + newpacket.data = (char *) malloc(newpacket.commandlen); + i = aim_putsnac(newpacket.data, 0x000d, 0x0008, 0x0000, sess->snac_nextid); + + /* exchange */ + i+= aimutil_put16(newpacket.data+i, exchange); + + /* room cookie */ + i+= aimutil_put8(newpacket.data+i, strlen("invite")); + i+= aimutil_putstr(newpacket.data+i, "invite", strlen("invite")); + + /* instance */ + i+= aimutil_put16(newpacket.data+i, 0xffff); + + /* detail level */ + i+= aimutil_put8(newpacket.data+i, 0x01); + + /* tlvcount */ + i+= aimutil_put16(newpacket.data+i, 0x0001); + + /* room name */ + i+= aim_puttlv_str(newpacket.data+i, 0x00d3, strlen(name), name); + + snac.id = sess->snac_nextid; + snac.family = 0x000d; + snac.type = 0x0008; + snac.flags = 0x0000; + snac.data = NULL; + + aim_newsnac(sess, &snac); + + aim_tx_enqueue(sess, &newpacket); + + return (sess->snac_nextid++); +} diff --git a/aim_conn.c b/aim_conn.c index ddc0ba8..ee2418c 100644 --- a/aim_conn.c +++ b/aim_conn.c @@ -45,6 +45,9 @@ void aim_conn_close(struct aim_conn_t *deadconn) deadconn->forcedlatency = 0; aim_clearhandlers(deadconn); deadconn->handlerlist = NULL; + if (deadconn->priv) + free(deadconn->priv); + deadconn->priv = NULL; } struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess, @@ -240,9 +243,9 @@ void aim_session_init(struct aim_session_t *sess) if (!sess) return; - sess->logininfo.screen_name[0] = '\0'; + memset(sess->logininfo.screen_name, 0x00, MAXSNLEN); sess->logininfo.BOSIP = NULL; - sess->logininfo.cookie[0] = '\0'; + memset(sess->logininfo.cookie, 0x00, AIM_COOKIELEN); sess->logininfo.email = NULL; sess->logininfo.regstatus = 0x00; @@ -255,10 +258,12 @@ void aim_session_init(struct aim_session_t *sess) sess->conns[i].lastactivity = 0; sess->conns[i].forcedlatency = 0; sess->conns[i].handlerlist = NULL; + sess->conns[i].priv = NULL; } sess->queue_outgoing = NULL; sess->queue_incoming = NULL; + sess->pendingjoin = NULL; sess->outstanding_snacs = NULL; sess->snac_nextid = 0x00000001; diff --git a/aim_im.c b/aim_im.c index c131687..867750b 100644 --- a/aim_im.c +++ b/aim_im.c @@ -355,13 +355,12 @@ int aim_parse_incoming_im_middle(struct aim_session_t *sess, free(msg); } else if (channel == 0x0002) - { + { + int rendtype; struct aim_tlv_t *block1; struct aim_tlvlist_t *list2; struct aim_tlv_t *tmptlv; int a; - u_short exchange,instance; - char *roomname,*msg,*encoding,*lang; /* Class. */ if ((tmptlv = aim_gettlv(tlvlist, 0x0001, 1))) @@ -388,46 +387,83 @@ int aim_parse_incoming_im_middle(struct aim_session_t *sess, a = 0x1a; /* skip -- not sure what this information is! */ - list2 = aim_readtlvchain(block1->value+a, block1->length-a); - if (aim_gettlv(list2, 0x2711, 1)) + /* + * XXX: Ignore if there's no data, only cookie information. + * + * Its probably just an accepted invitation or something. + * + */ + if (block1->length <= 0x1a) { - struct aim_tlv_t *name; - int len; - - name = aim_gettlv(list2, 0x2711, 1); - - exchange = aimutil_get16(name->value+0); - - len = aimutil_get16(name->value+2); - roomname = (char *)malloc(len+1); - memcpy(roomname, name->value+3, len); - roomname[len] = '\0'; - - instance = aimutil_get16(name->value+3+len); + aim_freetlvchain(&tlvlist); + return 1; } - if (aim_gettlv(list2, 0x000c, 1)) - msg = aim_gettlv_str(list2, 0x000c, 1); + list2 = aim_readtlvchain(block1->value+a, block1->length-a); - if (aim_gettlv(list2, 0x000d, 1)) - encoding = aim_gettlv_str(list2, 0x000d, 1); - - if (aim_gettlv(list2, 0x000e, 1)) - lang = aim_gettlv_str(list2, 0x000e, 1); + if (aim_gettlv(list2, 0x0004, 1) /* start connection */ || + aim_gettlv(list2, 0x000b, 1) /* close conncetion */) + { + rendtype = 1; /* voice request */ + + /* + * Call client. + */ + userfunc = aim_callhandler(command->conn, 0x0004, 0x0007); + if (userfunc) + i = userfunc(sess, + command, + channel, + rendtype, + &userinfo); + else + i = 0; + } + else + { + struct aim_chat_roominfo roominfo; + char *msg=NULL,*encoding=NULL,*lang=NULL; + + rendtype = 0; /* chat invite */ + if (aim_gettlv(list2, 0x2711, 1)) + { + struct aim_tlv_t *nametlv; + + nametlv = aim_gettlv(list2, 0x2711, 1); + aim_chat_readroominfo(nametlv->value, &roominfo); + } + + if (aim_gettlv(list2, 0x000c, 1)) + msg = aim_gettlv_str(list2, 0x000c, 1); + + if (aim_gettlv(list2, 0x000d, 1)) + encoding = aim_gettlv_str(list2, 0x000d, 1); + + if (aim_gettlv(list2, 0x000e, 1)) + lang = aim_gettlv_str(list2, 0x000e, 1); - /* - * Call client. - */ - userfunc = aim_callhandler(command->conn, 0x0004, 0x0007); - if (userfunc) - i = userfunc(sess, command, channel, &userinfo, roomname, msg, encoding+1, lang+1, exchange, instance); - else - i = 0; + /* + * Call client. + */ + userfunc = aim_callhandler(command->conn, 0x0004, 0x0007); + if (userfunc) + i = userfunc(sess, + command, + channel, + rendtype, + &userinfo, + &roominfo, + msg, + encoding?encoding+1:NULL, + lang?lang+1:NULL); + else + i = 0; - free(roomname); - free(msg); - free(encoding); - free(lang); + free(roominfo.name); + free(msg); + free(encoding); + free(lang); + } aim_freetlvchain(&list2); } diff --git a/aim_info.c b/aim_info.c index b0c9b74..daf4746 100644 --- a/aim_info.c +++ b/aim_info.c @@ -108,6 +108,7 @@ int aim_extractuserinfo(u_char *buf, struct aim_userinfo_s *outinfo) * 0x0004 AOL Main Service user * 0x0008 Unknown bit 4 * 0x0010 Free (AIM) user + * 0x0020 Away * * In some odd cases, we can end up with more * than one of these. We only want the first, @@ -306,6 +307,7 @@ int aim_parse_userinfo_middle(struct aim_session_t *sess, char *prof = NULL; u_int i = 0; rxcallback_t userfunc=NULL; + struct aim_tlvlist_t *tlvlist; { u_long snacid = 0x000000000; @@ -320,43 +322,18 @@ int aim_parse_userinfo_middle(struct aim_session_t *sess, } i = 10; - i += aim_extractuserinfo(command->data+i, &userinfo); - - if (i < command->commandlen) - { - if (aimutil_get16(&command->data[i]) == 0x0001) - { - int len = 0; - - len = aimutil_get16(&command->data[i+2]); - - prof_encoding = (char *) malloc(len+1); - memcpy(prof_encoding, &(command->data[i+4]), len); - prof_encoding[len] = '\0'; - - i += (2+2+len); - } - else - { - printf("faim: userinfo: **warning: unexpected TLV after TLVblock t(%04x) l(%04x)\n", aimutil_get16(command->data+i), aimutil_get16(command->data+i+2)); - i += 2 + 2 + command->data[i+3]; - } - } - if (i < command->commandlen) - { - if (aimutil_get16(&command->data[i]) == 0x0002) - { - int len = 0; - len = aimutil_get16(&command->data[i+2]); - - prof = (char *) malloc(len+1); - memcpy(prof, &(command->data[i+4]), len); - prof[len] = '\0'; - } - else - printf("faim:userinfo: **warning: profile not found, but still have data\n"); - } + /* + * extractuserinfo will give us the basic metaTLV information + */ + i += aim_extractuserinfo(command->data+i, &userinfo); + + /* + * However, in this command, there's usually more TLVs following... + */ + tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); + prof_encoding = aim_gettlv_str(tlvlist, 0x0001, 1); + prof = aim_gettlv_str(tlvlist, 0x0002, 1); userfunc = aim_callhandler(command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO); if (userfunc) @@ -367,9 +344,10 @@ int aim_parse_userinfo_middle(struct aim_session_t *sess, prof_encoding, prof); } - + free(prof_encoding); free(prof); + aim_freetlvchain(&tlvlist); return 1; } diff --git a/aim_misc.c b/aim_misc.c index b882c80..a451d7a 100644 --- a/aim_misc.c +++ b/aim_misc.c @@ -241,7 +241,8 @@ u_long aim_bos_setbuddylist(struct aim_session_t *sess, */ u_long aim_bos_setprofile(struct aim_session_t *sess, struct aim_conn_t *conn, - char *profile) + char *profile, + char *awaymsg) { struct command_tx_struct newpacket; int i = 0; @@ -269,6 +270,9 @@ u_long aim_bos_setprofile(struct aim_session_t *sess, newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); newpacket.commandlen = 1152+strlen(profile)+1; /*arbitrarily large */ + if (awaymsg) + newpacket.commandlen += strlen(awaymsg); + newpacket.data = (char *) malloc(newpacket.commandlen); i += aim_putsnac(newpacket.data, 0x0002, 0x004, 0x0000, sess->snac_nextid); @@ -277,9 +281,11 @@ u_long aim_bos_setprofile(struct aim_session_t *sess, /* why do we send this twice? */ i += aim_puttlv_str(newpacket.data+i, 0x0003, strlen("text/x-aolrtf; charset=\"us-ascii\""), "text/x-aolrtf; charset=\"us-ascii\""); - /* a blank TLV 0x0004 --- not sure what this is either */ - i += aimutil_put16(newpacket.data+i, 0x0004); - i += aimutil_put16(newpacket.data+i, 0x0000); + /* Away message -- we send this no matter what, even if its blank */ + if (awaymsg) + i += aim_puttlv_str(newpacket.data+i, 0x0004, strlen(awaymsg), awaymsg); + else + i += aim_puttlv_str(newpacket.data+i, 0x0004, 0x0000, NULL); /* Capability information. */ i += aim_puttlv_str(newpacket.data+i, 0x0005, 0x0060, funkydata); @@ -413,6 +419,8 @@ u_long aim_bos_ackrateresp(struct aim_session_t *sess, newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); newpacket.type = 0x02; newpacket.commandlen = 18; + if (conn->type != AIM_CONN_TYPE_BOS) + newpacket.commandlen += 2; newpacket.data = (char *) malloc(newpacket.commandlen); aim_putsnac(newpacket.data, 0x0001, 0x0008, 0x0000, sess->snac_nextid); @@ -425,6 +433,11 @@ u_long aim_bos_ackrateresp(struct aim_session_t *sess, newpacket.data[15] = 0x03; newpacket.data[16] = 0x00; newpacket.data[17] = 0x04; + if (conn->type != AIM_CONN_TYPE_BOS) + { + newpacket.data[16] = 0x00; + newpacket.data[17] = 0x05; + } aim_tx_enqueue(sess, &newpacket); @@ -483,7 +496,7 @@ u_long aim_setversions(struct aim_session_t *sess, struct aim_conn_t *conn) { struct command_tx_struct newpacket; - int i,j; + int i; newpacket.lock = 1; if (conn) @@ -531,7 +544,6 @@ u_long aim_setversions(struct aim_session_t *sess, #if 0 for (j = 0; j < 0x10; j++) -A { i += aimutil_put16(newpacket.data+i, j); /* family */ i += aimutil_put16(newpacket.data+i, 0x0003); /* version */ diff --git a/aim_rxhandlers.c b/aim_rxhandlers.c index 3e81c92..9fa45d9 100644 --- a/aim_rxhandlers.c +++ b/aim_rxhandlers.c @@ -512,6 +512,8 @@ int aim_rxdispatch(struct aim_session_t *sess) workingPtr->handled = 1; aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY); } + else if ((family == 0x000d) && (subtype == 0x0009)) + workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr); else { workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); @@ -519,8 +521,44 @@ int aim_rxdispatch(struct aim_session_t *sess) } break; case AIM_CONN_TYPE_CHAT: - printf("\nAHH! Dont know what to do with CHAT stuff yet!\n"); - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr); + { + u_short family, subtype; + + family = aimutil_get16(workingPtr->data); + subtype= aimutil_get16(workingPtr->data+2); + + if ((family == 0x0000) && (subtype == 0x00001)) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr); + else if (family == 0x0001) + { + if (subtype == 0x0001) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr); + else if (subtype == 0x0007) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr); + else + printf("Chat: unknown snac %04x/%04x\n", family, subtype); + } + else if (family == 0x000e) + { + if (subtype == 0x0002) + workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_chat_parse_joined(sess, workingPtr); + else if (subtype == 0x0004) + workingPtr->handled = aim_chat_parse_leave(sess, workingPtr); + else if (subtype == 0x0006) + workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr); + else + printf("Chat: unknown snac %04x/%04x\n", family, subtype); + } + else + { + printf("Chat: unknown snac %04x/%04x\n", family, subtype); + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr); + } + } break; default: printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type); @@ -589,10 +627,24 @@ int aim_handleredirect_middle(struct aim_session_t *sess, tmptlv = aim_gettlv(tlvlist, 0x0006, 1); memcpy(cookie, tmptlv->value, AIM_COOKIELEN); - userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); - if (userfunc) - ret = userfunc(sess, command, serviceid, ip, cookie); - + if (serviceid == AIM_CONN_TYPE_CHAT) + { + /* + * Chat hack. + * + */ + userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); + if (userfunc) + ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin); + free(sess->pendingjoin); + sess->pendingjoin = NULL; + } + else + { + userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); + if (userfunc) + ret = userfunc(sess, command, serviceid, ip, cookie); + } aim_freetlvchain(&tlvlist); return ret; diff --git a/aim_tlv.c b/aim_tlv.c index 94acf03..d03f2f9 100644 --- a/aim_tlv.c +++ b/aim_tlv.c @@ -31,7 +31,7 @@ struct aim_tlvlist_t *aim_readtlvchain(u_char *buf, int maxlen) cur = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); memset(cur, 0x00, sizeof(struct aim_tlvlist_t)); - cur->tlv = aim_createtlv(); + cur->tlv = aim_createtlv(); cur->tlv->type = type; cur->tlv->length = length; cur->tlv->value = (u_char *)malloc(length*sizeof(u_char)); @@ -201,13 +201,12 @@ int aim_puttlv_32(u_char *buf, u_short t, u_long v) int aim_puttlv_str(u_char *buf, u_short t, u_short l, u_char *v) { int curbyte; - if (!v || !buf) - return 0; curbyte = 0; curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff)); curbyte += aimutil_put16(buf+curbyte, (u_short)(l&0xffff)); - memcpy(buf+curbyte, v, l); + if (v) + memcpy(buf+curbyte, v, l); curbyte += l; return curbyte; } diff --git a/aim_txqueue.c b/aim_txqueue.c index 50bf425..f2ed1e8 100644 --- a/aim_txqueue.c +++ b/aim_txqueue.c @@ -59,7 +59,7 @@ int aim_tx_enqueue(struct aim_session_t *sess, #if debug > 2 printf("calling aim_tx_printqueue()\n"); - aim_tx_printqueue(); + aim_tx_printqueue(sess); printf("back from aim_tx_printqueue()\n"); #endif @@ -98,7 +98,7 @@ u_int aim_get_next_txseqnum(struct aim_conn_t *conn) * */ #if debug > 2 -int aim_tx_printqueue(void) +int aim_tx_printqueue(struct aim_session_t *sess) { struct command_tx_struct *workingPtr = NULL; @@ -280,7 +280,7 @@ int aim_tx_purgequeue(struct aim_session_t *sess) (sess->queue_outgoing->sent == 1) ) { #if debug > 1 - printf("purgequeue(): purging seqnum 0x%04x\n", aim_queue_outgoing->seqnum); + printf("purgequeue(): purging seqnum 0x%04x\n", sess->queue_outgoing->seqnum); #endif workingPtr2 = sess->queue_outgoing; sess->queue_outgoing = NULL; diff --git a/faim/aim.h b/faim/aim.h index 38450f3..8b52f85 100644 --- a/faim/aim.h +++ b/faim/aim.h @@ -176,6 +176,13 @@ struct aim_session_t { struct command_tx_struct *queue_outgoing; struct command_rx_struct *queue_incoming; + /* + * This is a dreadful solution to the what-room-are-we-joining + * problem. (There's no connection between the service + * request and the resulting redirect.) + */ + char *pendingjoin; + /* * Outstanding snac handling * @@ -199,6 +206,15 @@ struct aim_userinfo_s { u_long sessionlen; }; +#define AIM_CLASS_TRIAL 0x0001 +#define AIM_CLASS_UNKNOWN2 0x0002 +#define AIM_CLASS_AOL 0x0004 +#define AIM_CLASS_UNKNOWN4 0x0008 +#define AIM_CLASS_FREE 0x0010 +#define AIM_CLASS_AWAY 0x0020 +#define AIM_CLASS_UNKNOWN40 0x0040 +#define AIM_CLASS_UNKNOWN80 0x0080 + /* * TLV handling */ @@ -321,7 +337,7 @@ void aim_session_init(struct aim_session_t *); u_long aim_bos_setidle(struct aim_session_t *, struct aim_conn_t *, u_long); u_long aim_bos_changevisibility(struct aim_session_t *, struct aim_conn_t *, int, char *); u_long aim_bos_setbuddylist(struct aim_session_t *, struct aim_conn_t *, char *); -u_long aim_bos_setprofile(struct aim_session_t *, struct aim_conn_t *, char *); +u_long aim_bos_setprofile(struct aim_session_t *, struct aim_conn_t *, char *, char *); u_long aim_bos_setgroupperm(struct aim_session_t *, struct aim_conn_t *, u_long); u_long aim_bos_clientready(struct aim_session_t *, struct aim_conn_t *); u_long aim_bos_reqrate(struct aim_session_t *, struct aim_conn_t *); @@ -333,6 +349,7 @@ u_long aim_bos_reqrights(struct aim_session_t *, struct aim_conn_t *); u_long aim_bos_reqbuddyrights(struct aim_session_t *, struct aim_conn_t *); u_long aim_bos_reqlocaterights(struct aim_session_t *, struct aim_conn_t *); u_long aim_bos_reqicbmparaminfo(struct aim_session_t *, struct aim_conn_t *); +u_long aim_setversions(struct aim_session_t *sess, struct aim_conn_t *conn); /* aim_rxhandlers.c */ int aim_rxdispatch(struct aim_session_t *); @@ -372,6 +389,41 @@ u_long aim_remove_buddy(struct aim_session_t *, struct aim_conn_t *, char *); u_long aim_usersearch_address(struct aim_session_t *, struct aim_conn_t *, char *); /* u_long aim_usersearch_name(struct aim_session_t *, struct aim_conn_t *, char *); */ + +struct aim_chat_roominfo { + u_short exchange; + char *name; + u_short instance; +}; +int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo); +int aim_chat_parse_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command); +int aim_chat_parse_joined(struct aim_session_t *sess, struct command_rx_struct *command); +int aim_chat_parse_leave(struct aim_session_t *sess, struct command_rx_struct *command); +int aim_chat_parse_incoming(struct aim_session_t *sess, struct command_rx_struct *command); +u_long aim_chat_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, char *msg); +u_long aim_chat_join(struct aim_session_t *sess, struct aim_conn_t *conn, u_short exchange, const char *roomname); +u_long aim_chat_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); +int aim_chat_attachname(struct aim_conn_t *conn, char *roomname); +char *aim_chat_getname(struct aim_conn_t *conn); +struct aim_conn_t *aim_chat_getconn(struct aim_session_t *, char *name); + +u_long aim_chatnav_reqrights(struct aim_session_t *sess, struct aim_conn_t *conn); +u_long aim_chatnav_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); + +u_long aim_chat_invite(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, char *msg, u_short exchange, char *roomname, u_short instance); + +struct aim_chat_exchangeinfo { + u_short number; + char *name; + char *charset1; + char *lang1; + char *charset2; + char *lang2; +}; +int aim_chatnav_parse_info(struct aim_session_t *sess, struct command_rx_struct *command); +u_long aim_chatnav_createroom(struct aim_session_t *sess, struct aim_conn_t *conn, char *name, u_short exchange); +int aim_chat_leaveroom(struct aim_session_t *sess, char *name); + /* aim_util.c */ int aimutil_put8(u_char *, u_char); u_char aimutil_get8(u_char *buf); diff --git a/faim/aim_cbtypes.h b/faim/aim_cbtypes.h index 78b1ab5..5c15b43 100644 --- a/faim/aim_cbtypes.h +++ b/faim/aim_cbtypes.h @@ -153,12 +153,19 @@ * SNAC Family: Chat Navigation Services */ #define AIM_CB_CTN_ERROR 0x0001 +#define AIM_CB_CTN_CREATE 0x0008 +#define AIM_CB_CTN_INFO 0x0009 #define AIM_CB_CTN_DEFAULT 0xffff /* * SNAC Family: Chat Services */ #define AIM_CB_CHT_ERROR 0x0001 +#define AIM_CB_CHT_ROOMINFOUPDATE 0x0002 +#define AIM_CB_CHT_USERJOIN 0x0003 +#define AIM_CB_CHT_USERLEAVE 0x0004 +#define AIM_CB_CHT_OUTGOINGMSG 0x0005 +#define AIM_CB_CHT_INCOMINGMSG 0x0006 #define AIM_CB_CHT_DEFAULT 0xffff /* diff --git a/faim/faimconfig.h b/faim/faimconfig.h index 395ed5a..64229c8 100644 --- a/faim/faimconfig.h +++ b/faim/faimconfig.h @@ -18,7 +18,7 @@ * * Default: 0 */ -#define debug 0 +#define debug 0 /* * Maximum number of connections the library can simultaneously diff --git a/tcpdumps/randombits.txt b/tcpdumps/randombits.txt new file mode 100644 index 0000000..633b368 --- /dev/null +++ b/tcpdumps/randombits.txt @@ -0,0 +1,728 @@ + +17/6 (client) +----- + +0100 0010 +7468 6973 6865 7265 6973 616e 616d 6532 + t h i s h e r e i s a n a m e 2 + +17/7 (server) +---- + +0a00 3336 3831 3531 3737 3430 + 3 6 8 1 5 1 7 7 4 0 + +17/2 (client) +---- +0100 0010 +7468 6973 6865 7265 6973 616e 616d 6532 + t h i s h e r e i s a n a m e 2 + +0025 0010 +473c 5d77 c795 1c1c 4aba 2c9c 50df 275b + G < ] w , P ' + +0003 0032 +414f 4c20 496e 7374 616e 7420 4d65 7373 + A O L I n s t a n t M e s s +656e 6765 7220 2853 4d29 2c20 7665 7273 + e n g e r ( S M ) , v e r s +696f 6e20 332e 352e 3136 3730 2f57 494e + i o n 3 . 5 . 1 6 7 0 / W I N +3332 + 3 2 + +0016 0002 0004 +0017 0002 0003 +0018 0002 0005 +0019 0002 0000 +001a 0002 0686 +000e 0002 7573 + u s +000f 0002 656e + e n +0014 0004 0000 002a +0009 0002 0015 + +17/3 (server) +---- + +0100 0010 +5468 6973 4865 7265 4973 414e 616d 6532 + +0005 000d +3230 352e 3138 382e 342e 3233 36 + 2 0 5 . 1 8 8 . 4 . 2 3 6 + +0006 0100 c11d 7e73 30d0 db + 6ea7 88b7 b73d 6ad9 f73f e1e8 6359 dda0 + 4289 7651 9a32 9a27 edca 53c3 2b57 6838 + 5f38 4968 1b83 1ae3 db0f 47db c380 59d1 + 0b00 8f96 42e2 3785 68d8 3547 4c41 7dc9 + 85b0 c4e2 fc7e 63b6 248d 9c33 f899 0801 + 6e45 f038 5ff3 ea1e 2e29 0c4d d48c c902 + 5a1e 8417 2c81 919b fc67 5a82 e1ce 3180 + f2b9 c3db a3cc c073 b0b2 4964 992f 1693 + cd0d 817b 4ee6 2665 4a80 dada c301 19a8 + 388c 11d8 1e55 f2dd 0572 43a1 459d 884c + 2733 0f7f 715d 8364 0c3d 13e0 e4a8 ebeb + a181 6b2d 278f cab1 b4ea 0bda f8b7 3d43 + e4ec f6fb a66f b511 0009 1c1e 12ab 12fd + e083 f44b 38bc 7401 2a47 b739 558b 9e96 + d365 e9ee 03d6 0e4d 3650 c9f8 c728 9c04 + 14c3 1505 0304 abc6 78 +0011 000a +6d69 6440 6175 6b2e 6378 + +0013 0002 0003 + +2a04 ce58 0000 00 + + +2/4 (client) +--- +0001 001f 7465 7874 2f61 6f6c 7274 663b + 2063 6861 7273 6574 3d22 7573 2d61 7363 + 6969 22 + +0002 0001 00 + +0003 001f 7465 7874 + 2f61 6f6c 7274 663b 2063 6861 7273 6574 + 3d22 7573 2d61 7363 6969 22 + +0004 0000 + +0005 0060 + 09 4613 464c 7f11 d182 2244 4553 + 5400 0009 4613 414c 7f11 d182 2244 4553 + 5400 0009 4613 454c 7f11 d182 2244 4553 + 5400 0074 8f24 2062 8711 d182 2244 4553 + 5400 0009 4613 484c 7f11 d182 2244 4553 + 5400 0009 4613 434c 7f11 d182 2244 4553 + 5400 00 + + + +2a02 3764 000a +0003 0002 0000 0000 0000 + +2a02 3765 005c + +0003 0004 0000 0000 0000 + 06 6d69 6467 6f64 + 07 4d69 6447 7572 75 + 0a 7467 4161 7264 7661 726b + 10 5468 6973 4865 7265 4973 414e 616d 6532 + 09 6d69 6465 6e64 6961 6e + 09 7661 7868 6572 6465 72 + 0a 6d6f 7573 6574 726f 7574 + 07 6177 7761 6969 64 + + + +2a02 3766 001a + +0004 0002 0000 0000 8012 + 0000 0000 0003 1f40 + 03e7 03e7 0000 0000 + + + +4/4 +--- +2a02 3767 000a +0004 0004 0000 0000 8013 + +9/2 +--- +2a02 3768 000a +0009 0002 0000 0000 0000 + +9/4 +--- +2a02 3769 000e +0009 0004 0000 0000 0000 + 0000 001f + +1/14 +---- +2a02 376a 000e +0001 0014 0000 0000 0000 + 0000 0001 + +2a02 376b 00bd +0002 0004 0000 0000 0002 + 0001 001f 7465 7874 2f61 6f6c 7274 663b 2063 68 + 6172 7365 743d 2275 732d 6173 6369 6922 + + 0002 0001 00 + + 0003 001f 7465 7874 2f61 6f6c 7274 663b 2063 68 + 6172 7365 743d 2275 732d 6173 6369 6922 + + 0004 0000 + + 0005 0060 + 0946 1346 4c7f 11d1 8222 4445 5354 0000 + 0946 1341 4c7f 11d1 8222 4445 5354 0000 + 0946 1345 4c7f 11d1 8222 4445 5354 0000 + 748f 2420 6287 11d1 8222 4445 5354 0000 + 0946 1348 4c7f 11d1 8222 4445 5354 0000 + 0946 1343 4c7f 11d1 8222 4445 5354 0000 + + + +win chat invite +---------------- + +4233 3731 3931 5f00 cookie + +0002 channel + +10 5468 6973 4865 7265 4973 414e 616d 6532 src sn + +0000 warnlevel +0004 num of tlvs that follow +0001 0002 0011 class +0004 0002 0000 idletime +000f 0004 0000 0c7a sessionlen +0003 0004 386a e35b onsince + +0005 0063 + 0000 3342 3731 3931 5f00 748f 2420 6287 11d1 8222 4445 5354 0000 + +000a 0002 0001 +000f 0000 +000c 001b 4a6f 696e 206d 6520 696e 2074 6869 7320 + 4275 6464 7920 4368 6174 2e +2711 001c 0004 1774 6869 7368 6572 6569 7361 6e61 + 6d65 325f 6368 6174 3538 0000 + +mac chat invite +--------------- +4252 432d 0000 0009 cookie + +0002 channel + +07 4d69 6447 7572 75 src sn + +0000 warnlevel + +0004 tlvcount + +0001 0002 0010 class +0004 0002 0000 idle +000f 0004 0000 1978 sessionlen +0003 0004 3869 93f9 onsince + +0005 0071 + +0000 5242 432d 0000 0009 748f 2420 6287 11d1 8222 4445 5354 0000 + +000a 0002 0001 +2711 0013 0004 0e6d 6964 + 6775 7275 5f63 6861 7434 3700 00 +000f 0000 +000c 001b 4a6f 696e 206d 6520 696e 2074 6869 7320 + 4275 6464 7920 4368 6174 2e +000d 0008 0875 732d 6173 6369 +000e 0007 0765 6e67 6c69 7320 + +win voice invite +---------------- + +3434 4443 395f 7800 cookie + +0002 channel + +10 5468 6973 4865 7265 4973 414e 616d 6532 src sn + +0000 warnlevel + +0004 tlvcount + +0001 0002 0011 class + +0004 0002 0000 +000f 0004 0000 00d8 +0003 0004 386b 27ab +0005 003c +0000 3434 4443 395f 7800 0946 1341 4c7f 11d1 8222 4445 5354 0000 +000a 0002 0001 +0003 0004 c63c 9612 +000f 0000 +2711 0004 0000 0001 +0004 0004 18dd 0fac +00 + +win voice disconnect +-------------------- + +3431 3246 3237 5f00 + +0002 + +10 5468 6973 4865 7265 4973 414e 616d 6532 +0000 + +0004 + +0001 0002 0011 +0004 0002 0000 +000f 0004 0000 04ec +0003 0004 386b 27ab +0005 0020 +0001 3134 3246 3237 5f00 0946 1341 4c7f 11d1 8222 4445 5354 0000 +000b 0002 0001 +00 + + +gone away +--------- +10 5468 6973 4865 7265 4973 414e 616d 6532 +0000 warnlevel +0004 tlvcount +0001 0002 0031 +0004 0002 0000 +000f 0004 0000 0817 +0003 0004 386b 27ab +61 + +came back +--------- +10 5468 6973 4865 7265 4973 414e 616d 6532 +0000 +0004 +0001 0002 0011 +0004 0002 00 + 0000 0f00 0400 0008 2600 0300 0438 6b27 + ab61 + +2/4 -- going away +----------------- +0001 001f 7465 7874 2f61 6f6c 7274 663b + 2063 6861 7273 6574 3d22 7573 2d61 7363 + 6969 22 +0002 0001 00 +0003 001f 7465 7874 2f61 6f6c 7274 663b + 2063 6861 7273 6574 3d22 7573 2d61 7363 + 6969 22 + +0004 0025 49 + 2061 6d20 6177 6179 2066 726f 6d20 6d79 + 2063 6f6d 7075 7465 7220 7269 6768 7420 + 6e6f 772e + + +2/4 -- coming back +------------------ +0001 001f 7465 7874 2f61 6f6c 7274 663b + 2063 6861 7273 6574 3d22 7573 2d61 7363 + 6969 22 +0002 0001 00 +0003 001f 7465 7874 2f61 6f6c 7274 663b + 2063 6861 7273 6574 3d22 7573 2d61 7363 + 6969 22 +0004 0000 00 + +getuserinfo with awaymsg 2/6 +------------------------ +06 6d69 6467 6f64 + +0000 +0005 +0001 0002 0030 +0004 0002 0000 +000f 0004 0000 0044 +0002 0004 374e 69cf +0003 0004 386b 3aa4 +0001 0021 + 7465 7874 2f78 2d61 6f6c 7274 663b 2063 + 6861 7273 6574 3d22 7573 2d61 7363 6969 + 22 +0002 003a + 3c70 3e6d 6661 696d 2d70 7265 322e 322d + 6d69 6428 3330 6465 6331 3939 3929 3b20 + 6c69 6266 6169 6d20 302e 3935 6973 6828 + 3330 6465 6331 3939 3929 + +getuserinfo--parameter 3 +------------------------ + +10 5468 6973 4865 7265 4973 414e 616d 6532 + +0000 +0004 +0001 0002 0031 +0004 0002 0000 +000f 0004 0000 1797 +0003 0004 386b 27ab +0003 001f 7465 7874 2f61 6f6c 7274 663b 2063 6861 72 7365 743d 2275 732d 6173 + 6369 6922 0004 0025 4920 616d 2061 7761 + 7920 6672 6f6d 206d 7920 636f 6d70 7574 + 6572 2072 6967 6874 206e 6f77 2e00 + +chat join -- 1/4 +---------- +000e + +0001 001c + +0004 17 7468 6973 6865 7265 6973 616e 616d 6532 5f63 6861 7438 3500 00 + +0000 0000 + +redirect -- 1/5 +--------------- +000d 0002 000e service id +0005 000c 3230 352e 3138 382e 342e 3636 IP +0006 0100 cookie + e2df 8c0b 8caf + adc3 3996 0883 d2a0 1af6 ea29 404c 1935 + d364 d4cf 9c0a 0ad9 c3d7 ac7c 5f5d 2c57 + cb3e 00a4 4deb 62e0 9d57 8dc6 9a6b 2916 + 15b8 d496 d735 7d28 0323 c931 795e b2cf + 459d db9b c726 5467 7170 fd55 65ae 04df + fd94 979e f47a 1c9d 2c60 56bb 41a3 6778 + 6c8c 8b97 2397 e187 0541 a5cc 9927 b707 + 8340 3c42 e40d c070 65c4 c2c0 88c1 3af1 + ec10 eda8 9875 89ec 2a17 eee6 e7dd 2a74 + 82cd 6b6d cb97 af9a c541 8b1b 5c9f f4e4 + f858 93b3 5cea ff78 b816 cc37 c721 0097 + c204 4fbb 8e66 ec3d 94ac 964e cb1b 2c78 + a39e 6c2b 75f2 1acd ceb2 d529 2c82 81e8 + ef84 b382 5d7d 90d2 7f31 12ac 35b6 cf51 + a296 28fa 2623 0997 1e1b 636b 4154 d08f + c900 2137 3fa4 1a09 d1bc + +(open new connection) + +(send cookie on channel one, prefixed by 0000 0001 then type 6 TLV) + +(get server ready -- supports services 0001 and 000e) + +set client versions (client -- 1/17) +------------------- +000e 0001 +0001 0003 + +server versions (server 1/18) +--------------- +0001 0003 +000e 0001 + +(request rate info 1/6 from client) + +(never gets rate info?) + +rate info ack (client -- 1/8) +------------- +0001 +0002 +0003 +0004 +0005 + +send chat invite (client 4/6 -- on BOS connection) +---------------- +3033 4136 3445 5f00 cookie + +0002 channel + +06 6d69 6467 6f64 +0005 0063 + 0000 3330 4136 3445 5f00 74 + 8f24 2062 8711 d182 2244 4553 5400 00 + + 000a 0002 0001 + 000f 0000 + 000c 001b + 4a6f 696e 206d 6520 69 6e20 7468 6973 2042 7564 + 6479 2043 6861 742e + 2711 001c + 0004 17 7468 6973 6865 7265 6973 616e 616d 6532 + 5f63 6861 7438 3500 00 + +client ready (1/2) +------------ +000e 0001 +0004 0001 +0001 0003 +0004 0686 + + +users joined -- e/3 +------------ +10 5468 6973 4865 7265 4973 414e 616d 6532 joining sn +0000 warnlevel +0004 tlvcount +0001 0002 0011 class +0002 0004 3355 6800 +0003 0004 386b e770 +0004 0002 0000 + +user joined -- e/3 --another sample +------------------------------------ +09 7661 7868 6572 6465 72 +0000 warnlevel +0004 +0001 0002 0011 +0002 0004 3566 7a92 +0003 0004 386c 0d5a +0004 0002 0000 +10 5468 6973 4865 7265 4973 414e 616d 6532 +0000 +0004 +0001 0002 0011 +0002 0004 3355 6800 +0003 0004 386b e770 +0004 0002 0028 + +info update -- e/2 --another sample +----------------------------------- +0004 17 7468 6973 6865 7265 6973 616e 616d 6532 5f63 6861 7438 35 0000 +02 detail level + +0009 + +006a 0017 5468 6973 4865 7265 4973 414e 616d 6532 2043 6861 7438 35 +006f 0002 0002 + +0073 005b + 09 7661 7868 6572 6465 72 + 0000 + 0004 + 0001 0002 0011 + 0002 0004 3566 7a92 + 0003 0004 386c 0d5a + 0004 0002 0000 + 10 5468 6973 4865 7265 4973 414e 616d 6532 + 0000 + 0004 + 0001 0002 0011 + 0002 0004 3355 6800 + 0003 0004 386b e770 + 0004 0002 0028 +00c9 0002 0011 +00ca 0004 386b e76f +00d1 0002 0200 +00d2 0002 0018 +00d3 0017 5468 6973 4865 7265 4973 414e 616d 6532 2043 6861 7438 35 +00d5 0001 02 + +room info update -- e/2 +---------------- +0004 17 7468 6973 6865 7265 6973 616e 616d 6532 5f63 6861 7438 35 0000 +02 detail level + +0009 tlvcount + +006a 0017 5468 6973 4865 7265 4973 414e 616d 6532 2043 6861 7438 35 +006f 0002 0001 +0073 0031 + 10 5468 6973 4865 7265 4973 414e 616d 6532 sn + 0000 warnlevel + 0004 tlvcount + 0001 0002 0011 class + 0002 0004 3355 6800 + 0003 0004 386b e770 + 0004 0002 0000 + 00c9 0002 0011 + 00ca 0004 386b e76f + 00d1 0002 0200 + 00d2 0002 0018 + 00d3 0017 5468 6973 4865 7265 4973 414e 616d 6532 2043 6861 7438 35 + 00d5 0001 02 + +users left -- e/4 +---------- +07 4d69 6447 7572 75 +0000 +0001 +0001 0002 0000 + + +incoming message -- e/6 +----------------- + +3330 3945 3446 0000 + +0003 + +0003 0031 + 10 5468 6973 4865 7265 4973 414e 616d 6532 + 0000 + 0004 + 0001 0002 0011 + 0002 0004 3355 6800 + 0003 0004 386b e770 + 0004 0002 0000 +0001 0000 +0005 003f + 0001 003b 3c48 544d 4c + 3e3c 424f 4459 2042 4743 4f4c 4f52 3d22 + 2366 6666 6666 6622 3e3c 464f 4e54 3e68 + 693c 2f46 4f4e 543e 3c2f 424f 4459 3e3c + 2f48 544d 4c3e + +outgoing message -- e/5 +---------------- +3330 3945 3446 0000 + +0003 + +0001 0000 +0006 0000 +0005 003f + 0001 003b + 3c48 544d 4c3e 3c42 4f44 5920 4247 434f 4c4f 523d 2223 + 6666 6666 6666 223e 3c46 4f4e 543e 6869 + 3c2f 464f 4e54 3e3c 2f42 4f44 593e 3c2f + 4854 4d4c 3e00 + + + + +CHATNAV +-------- + + + +request service: 1/4 -- data=0x000d + +gets normal redirect 1/5 + +sends cookie + +gets server ready (supports 1, d) + +set client versions {{d,1}, {1,3}} + +gets server versions {{1,3}, {d,1}} + +request rate info -- 1/6 + +rate info ack -- 1/8 + +sets client ready -- 1/2 (supports d, 1, 4, 1, 1, 3, 4, 0686) + +request chat rights -- d/2 -- no data + +gets nav information -- d/9 +-------------------- +0002 0001 03 concurrent max rooms +0003 006d EXCHANGE DESC -- EXCHANGE 4 + 0004 exchange + 000d 0003 0001 03 unknown + 0004 0002 001e unknown + 00c9 0002 0011 unknown + 00ca 0004 3842 4ca3 + 00d0 0002 0003 unknown + 00d1 0002 0200 maxmsglen? + 00d2 0002 0018 unknown + 00d3 0011 6169 6d20 7072 6976 6174 6520 6368 6174 73 exch name + aim private chats + 00d5 0001 02 unknown + 00d6 0008 7573 2d61 7363 6969 charset + 00d7 0002 656e lang + 00d8 0008 7573 2d61 7363 6969 charset + 00d9 0002 656e lang +0003 006f EXCHANGE DESC -- EXCHANGE 5 + 0005 + 000d 0003 0001 03 + 0004 0002 001e + 00c9 0002 0015 + 00ca 0004 3842 4ca3 + 00d0 0002 0003 + 00d1 0002 0200 + 00d2 0002 0018 + 00d3 0013 616f 6c20 636f 6d6d 756e 6974 7920 6368 + 6174 73 + aol community chats + 00d5 0001 02 + 00d6 0008 7573 2d61 7363 6969 + 00d7 0002 656e + 00d8 0008 7573 2d61 7363 6969 + 00d9 0002 656e +0003 0075 EXCHANGE DESC -- EXCHANGE 6 + 0006 + 000d 0003 0001 03 unknown + 0004 0002 001e unknown + 00c9 0002 0015 unknown + 00ca 0004 3842 4ca3 cookie? + 00d0 0002 0003 mxchan? + 00d1 0002 0200 msgsz? + 00d2 0002 0018 unknown + 00d3 0019 6e65 7463 656e 7465 7220 636f 6d6d 756e + 6974 7920 6368 6174 73 + netcenter community chats exchange name + 00d5 0001 02 unknown + 00d6 0008 7573 2d61 7363 6969 charset + 00d7 0002 656e lang + 00d8 0008 7573 2d61 7363 6969 charset + 00d9 0002 656e lang + + +create room -- d/8 +------------------ +0004 06 69 6e76 6974 65 ffff roominfo (cookie: invite) +01 detail level +0001 tlvcount +00d3 000e 6177 7761 6969 6420 4368 6174 3235 + awwaiid Chat25 + +new room info -- d/9 (need to identify somehow!) +------------- +0004 0059 + 0004 0e 6177 7761 6969 645f 6368 6174 3235 0000 roominfo + 02 detail level + 0007 + 006a 000e 6177 7761 6969 6420 4368 6174 3235 + 00c9 0002 0011 + 00ca 0004 386c 72c5 + 00d1 0002 0200 + 00d2 0002 0018 + 00d3 000e 6177 7761 6969 6420 4368 6174 3235 + 00d5 0001 02 + + +outgoing invitation -- 4/6 +-------------------- +3131 3538 3446 4100 cookie +0002 channel +07 4d69 6447 7572 75 destsn +0005 0063 + 0000 + 3131 3538 3446 4100 + 748f 2420 6287 11d1 8222 4445 5354 0000 + + 000a 0002 0001 + 000f 0000 + 000c 001b + 4a6f 696e 206d 6520 696e 2074 6869 7320 + 4275 6464 7920 4368 6174 2e + + + 2711 001c + 0004 17 + 7468 6973 6865 7265 6973 616e 616d 6532 + 5f63 6861 7438 35 + 0000 + + +invitation accepted +------------------- +3131 3538 3446 4100 + +0002 +10 5468 6973 4865 7265 4973 414e 616d 6532 +0000 +0004 +0001 0002 0011 +0004 0002 0000 +000f 0004 0000 001e +0003 0004 386f 2026 +0005 001a + 0002 3131 3538 3446 4100 748f 24 2062 8711 + d182 2244 4553 5400 0000 diff --git a/utils/faimtest/faimtest.c b/utils/faimtest/faimtest.c index f54667f..1456a0f 100644 --- a/utils/faimtest/faimtest.c +++ b/utils/faimtest/faimtest.c @@ -49,7 +49,6 @@ int faimtest_parse_oncoming(struct aim_session_t *, struct command_rx_struct *, ...); int faimtest_parse_offgoing(struct aim_session_t *, struct command_rx_struct *, ...); int faimtest_parse_login_phase3d_f(struct aim_session_t *, struct command_rx_struct *, ...); -int faimtest_auth_error(struct aim_session_t *, struct command_rx_struct *, ...); int faimtest_parse_authresp(struct aim_session_t *, struct command_rx_struct *, ...); int faimtest_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *command, ...); int faimtest_parse_userinfo(struct aim_session_t *, struct command_rx_struct *command, ...); @@ -60,6 +59,11 @@ int faimtest_serverready(struct aim_session_t *, struct command_rx_struct *comma int faimtest_parse_misses(struct aim_session_t *, struct command_rx_struct *command, ...); int faimtest_parse_motd(struct aim_session_t *, struct command_rx_struct *command, ...); int faimtest_parse_login(struct aim_session_t *, struct command_rx_struct *command, ...); +int faimtest_chatnav_info(struct aim_session_t *, struct command_rx_struct *command, ...); +int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...); +int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...); +int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...); +int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...); static char *screenname,*password; @@ -175,8 +179,24 @@ int faimtest_serverready(struct aim_session_t *sess, struct command_rx_struct *c aim_bos_setgroupperm(sess, command->conn, 0x1f); fprintf(stderr, "faimtest: done with BOS ServerReady\n"); break; + case AIM_CONN_TYPE_CHATNAV: fprintf(stderr, "faimtest: chatnav: got server ready\n"); + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0); + aim_bos_reqrate(sess, command->conn); + aim_bos_ackrateresp(sess, command->conn); + aim_chatnav_clientready(sess, command->conn); + aim_chatnav_reqrights(sess, command->conn); + + break; + case AIM_CONN_TYPE_CHAT: + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0); + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0); + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0); + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0); + aim_bos_reqrate(sess, command->conn); + aim_bos_ackrateresp(sess, command->conn); + aim_chat_clientready(sess, command->conn); break; default: fprintf(stderr, "faimtest: unknown connection type on Server Ready\n"); @@ -207,7 +227,7 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct char *cookie; /* this is the new buddy list */ - char buddies[] = "Buddy1&Buddy2&"; + char buddies[] = "Buddy1&Buddy2&ThisHereIsAName2&"; /* this is the new profile */ char profile[] = "Hello"; @@ -215,8 +235,7 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct serviceid = va_arg(ap, int); ip = va_arg(ap, char *); cookie = va_arg(ap, char *); - va_end(ap); - + switch(serviceid) { case 0x0005: /* Advertisements */ @@ -228,7 +247,7 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct /* send the buddy list and profile (required, even if empty) */ aim_bos_setbuddylist(sess, command->conn, buddies); - aim_bos_setprofile(sess, command->conn, profile); + aim_bos_setprofile(sess, command->conn, profile, NULL); /* send final login command (required) */ aim_bos_clientready(sess, command->conn); /* tell BOS we're ready to go live */ @@ -259,25 +278,37 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct fprintf(stderr, "faimtest: unable to connect to chatnav server\n"); return 1; } +#if 0 aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_CTN, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0); aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0); +#endif + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0); aim_auth_sendcookie(sess, tstconn, cookie); fprintf(stderr, "\achatnav: connected\n"); } break; case 0x000e: /* Chat */ { -#if 0 + char *roomname = NULL; struct aim_conn_t *tstconn = NULL; + + roomname = va_arg(ap, char *); + tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, ip); if ( (tstconn==NULL) || (tstconn->status >= AIM_CONN_STATUS_RESOLVERR)) { fprintf(stderr, "faimtest: unable to connect to chat server\n"); return 1; - } - aim_auth_sendcookie(sess, aim_getconn_type(sess, AIM_CONN_TYPE_CHAT), cookie); - fprintf(stderr, "\achat: connected\n"); -#endif + } + printf("faimtest: chat: connected\n"); + + /* + * We must do this to attach the stored name to the connection! + */ + aim_chat_attachname(tstconn, roomname); + + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0); + aim_auth_sendcookie(sess, tstconn, cookie); } break; default: @@ -285,30 +316,10 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct /* dunno */ } - return 1; -} - -#if 0 -int faimtest_auth_error(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - char *errorurl; - short errorcode; - - va_start(ap, command); - printf("Screen name: %s\n", sess->logininfo.screen_name); - errorurl = va_arg(ap, char *); - printf("Error URL: %s\n", errorurl); - errorcode = va_arg(ap, short); - printf("Error code: 0x%02x\n", errorcode); va_end(ap); - aim_conn_close(aim_getconn_type(sess, AIM_CONN_TYPE_AUTH)); - exit(0); - - return 0; + return 1; } -#endif int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) { @@ -503,12 +514,23 @@ int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_str printf("faimtest: icbm: sending response\n"); aim_send_im(sess, command->conn, userinfo->sn, 0, "Good day to you too."); } -#if 0 - else if (!strncmp(tmpstr, "joinchat", 8)) + else if (!strncmp(tmpstr, "open chatnav", 12)) { - aim_chat_join(sess, command->conn, "GoodDay"); + aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV); + //aim_chat_join(sess, command->conn, "thishereisaname2_chat85"); } -#endif + else if (!strncmp(tmpstr, "create", 6)) + { + aim_chatnav_createroom(sess, aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), "WorldDomination", 0x0004); + } + else if (!strncmp(tmpstr, "close chatnav", 13)) + aim_conn_close(aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV)); + else if (!strncmp(tmpstr, "join", 4)) + { + aim_chat_join(sess, command->conn, 0x0004, "worlddomination"); + } + else if (!strncmp(tmpstr, "leave", 5)) + aim_chat_leaveroom(sess, "worlddomination"); else { #if 0 @@ -522,43 +544,74 @@ int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_str } } /* - * Channel 2: Chat Invitation + * Channel 2: Rendevous Request */ else if (channel == 2) { struct aim_userinfo_s *userinfo; - char *roomname,*msg,*encoding,*lang; - u_short exchange, instance; + int rendtype = 0; - userinfo = va_arg(ap, struct aim_userinfo_s *); - roomname = va_arg(ap, char *); - msg = va_arg(ap, char *); - encoding = va_arg(ap, char *); - lang = va_arg(ap, char *); - exchange = va_arg(ap, u_short); - instance = va_arg(ap, u_short); - va_end(ap); - - printf("faimtest: chat invitation: source sn = %s\n", userinfo->sn); - printf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel); - printf("faimtest: chat invitation: \tclass = 0x%04x ", userinfo->class); - if (userinfo->class & 0x0010) - printf("(FREE) "); - if (userinfo->class & 0x0001) - printf("(TRIAL) "); - if (userinfo->class & 0x0004) - printf("(AOL) "); - printf("\n"); - /* we dont get membersince on chat invites! */ - printf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince); - printf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime); - - printf("faimtest: chat invitation: message = %s\n", msg); - printf("faimtest: chat invitation: room name = %s\n", roomname); - printf("faimtest: chat invitation: encoding = %s\n", encoding); - printf("faimtest: chat invitation: language = %s\n", lang); - printf("faimtest: chat invitation: exchange = 0x%04x\n", exchange); - printf("faimtest: chat invitation: instance = 0x%04x\n", instance); + rendtype = va_arg(ap, int); + if (rendtype == 0) + { + char *msg,*encoding,*lang; + struct aim_chat_roominfo *roominfo; + + userinfo = va_arg(ap, struct aim_userinfo_s *); + roominfo = va_arg(ap, struct aim_chat_roominfo *); + msg = va_arg(ap, char *); + encoding = va_arg(ap, char *); + lang = va_arg(ap, char *); + va_end(ap); + + printf("faimtest: chat invitation: source sn = %s\n", userinfo->sn); + printf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel); + printf("faimtest: chat invitation: \tclass = 0x%04x ", userinfo->class); + if (userinfo->class & 0x0010) + printf("(FREE) "); + if (userinfo->class & 0x0001) + printf("(TRIAL) "); + if (userinfo->class & 0x0004) + printf("(AOL) "); + printf("\n"); + /* we dont get membersince on chat invites! */ + printf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince); + printf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime); + + printf("faimtest: chat invitation: message = %s\n", msg); + printf("faimtest: chat invitation: room name = %s\n", roominfo->name); + printf("faimtest: chat invitation: encoding = %s\n", encoding); + printf("faimtest: chat invitation: language = %s\n", lang); + printf("faimtest: chat invitation: exchange = 0x%04x\n", roominfo->exchange); + printf("faimtest: chat invitation: instance = 0x%04x\n", roominfo->instance); + printf("faimtest: chat invitiation: autojoining %s...\n", roominfo->name); + /* + * Automatically join room... + */ + aim_chat_join(sess, command->conn, 0x0004, roominfo->name); + } + else if (rendtype == 1) + { + userinfo = va_arg(ap, struct aim_userinfo_s *); + va_end(ap); + + printf("faimtest: voice invitation: source sn = %s\n", userinfo->sn); + printf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel); + printf("faimtest: voice invitation: \tclass = 0x%04x ", userinfo->class); + if (userinfo->class & 0x0010) + printf("(FREE) "); + if (userinfo->class & 0x0001) + printf("(TRIAL) "); + if (userinfo->class & 0x0004) + printf("(AOL) "); + printf("\n"); + /* we dont get membersince on chat invites! */ + printf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince); + printf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime); + + } + else + printf("faimtest: icbm: unknown rendtype (%d)\n", rendtype); } else printf("faimtest does not support channels > 2 (chan = %02x)\n", channel); @@ -602,7 +655,15 @@ int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct userinfo = va_arg(ap, struct aim_userinfo_s *); va_end(ap); - printf("\n%s is now online\n", userinfo->sn); + printf("\n%s is now online (class: %04x = %s%s%s%s%s%s%s%s)\n", userinfo->sn, userinfo->class, + (userinfo->class&AIM_CLASS_TRIAL)?" TRIAL":"", + (userinfo->class&AIM_CLASS_UNKNOWN2)?" UNKNOWN2":"", + (userinfo->class&AIM_CLASS_AOL)?" AOL":"", + (userinfo->class&AIM_CLASS_UNKNOWN4)?" UNKNOWN4":"", + (userinfo->class&AIM_CLASS_FREE)?" FREE":"", + (userinfo->class&AIM_CLASS_AWAY)?" AWAY":"", + (userinfo->class&AIM_CLASS_UNKNOWN40)?" UNKNOWN40":"", + (userinfo->class&AIM_CLASS_UNKNOWN80)?" UNKNOWN80":""); return 1; } @@ -694,3 +755,143 @@ int faimtest_parse_login(struct aim_session_t *sess, struct command_rx_struct *c return 1; } #endif + +int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + va_list ap; + struct aim_userinfo_s *userinfo; + int count = 0, i = 0; + + va_start(ap, command); + count = va_arg(ap, int); + userinfo = va_arg(ap, struct aim_userinfo_s *); + va_end(ap); + + printf("faimtest: chat: %s: New occupants have joined:\n", (char *)command->conn->priv); + while (i < count) + printf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn); + + return 1; +} + +int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + va_list ap; + struct aim_userinfo_s *userinfo; + int count = 0, i = 0; + + va_start(ap, command); + count = va_arg(ap, int); + userinfo = va_arg(ap, struct aim_userinfo_s *); + va_end(ap); + + printf("faimtest: chat: %s: Some occupants have left:\n", (char *)command->conn->priv); + while (i < count) + printf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn); + + return 1; +} + +int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + va_list ap; + struct aim_userinfo_s *userinfo; + struct aim_chat_roominfo *roominfo; + char *roomname; + int usercount,i; + char *roomdesc; + + va_start(ap, command); + roominfo = va_arg(ap, struct aim_chat_roominfo *); + roomname = va_arg(ap, char *); + usercount= va_arg(ap, int); + userinfo = va_arg(ap, struct aim_userinfo_s *); + roomdesc = va_arg(ap, char *); + va_end(ap); + + printf("faimtest: chat: %s: info update:\n", (char *)command->conn->priv); + printf("faimtest: chat: %s: \tRoominfo: {%04x, %s, %04x}\n", + (char *)command->conn->priv, + roominfo->exchange, + roominfo->name, + roominfo->instance); + printf("faimtest: chat: %s: \tRoomname: %s\n", (char *)command->conn->priv, roomname); + printf("faimtest: chat: %s: \tRoomdesc: %s\n", (char *)command->conn->priv, roomdesc); + printf("faimtest: chat: %s: \tOccupants: (%d)\n", (char *)command->conn->priv, usercount); + + i = 0; + while (i < usercount) + printf("faimtest: chat: %s: \t\t%s\n", (char *)command->conn->priv, userinfo[i++].sn); + + return 1; +} + +int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + va_list ap; + struct aim_userinfo_s *userinfo; + char *msg; + char tmpbuf[1152]; + + va_start(ap, command); + userinfo = va_arg(ap, struct aim_userinfo_s *); + msg = va_arg(ap, char *); + va_end(ap); + + printf("faimtest: chat: %s: incoming msg from %s: %s\n", (char *)command->conn->priv, userinfo->sn, msg); + + /* + * Do an echo for testing purposes. But not for ourselves ("oops!") + */ + if (strcmp(userinfo->sn, sess->logininfo.screen_name) != 0) + { + sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); + aim_chat_send_im(sess, command->conn, tmpbuf); + } + + return 1; +} + +int faimtest_chatnav_info(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + u_short type; + va_list ap; + + ap = va_start(ap, command); + type = va_arg(ap, u_short); + + switch(type) + { + case 0x0002: + { + int maxrooms; + struct aim_chat_exchangeinfo *exchanges; + int exchangecount,i = 0; + + maxrooms = va_arg(ap, u_char); + exchangecount = va_arg(ap, int); + exchanges = va_arg(ap, struct aim_chat_exchangeinfo *); + va_end(ap); + + printf("faimtest: chat info: Chat Rights:\n"); + printf("faimtest: chat info: \tMax Concurrent Rooms: %d\n", maxrooms); + + printf("faimtest: chat info: \tExchange List: (%d total)\n", exchangecount); + while (i < exchangecount) + { + printf("faimtest: chat info: \t\t%x: %s (%s/%s)\n", + exchanges[i].number, + exchanges[i].name, + exchanges[i].charset1, + exchanges[i].lang1); + i++; + } + + } + break; + default: + va_end(ap); + printf("faimtest: chatnav info: unknown type (%04x)\n", type); + } + return 1; +} -- 2.45.2