From 00ef5271216e3bea9b233ce26a3c0f21fbca931f Mon Sep 17 00:00:00 2001 From: mid Date: Sat, 24 Mar 2001 03:38:58 +0000 Subject: [PATCH] - Sat Mar 24 03:16:32 UTC 2001 - vaargs to msgerror and locateerror swapped - ** CLIENT CHANGE: Reason code comes before SN now. This is so that the backend code for all three error handlers is identical. - aim_getinfo() returns -1 on failure (hah! I don't think anyone checks return codes from libfaim anyway...they're known for their inconsistency and lack of sensicality) - Remove _DEFAULT handlers in faimtest... - They were not consistent. - They did not make sense. - They did not work anyway. - Most of them were #if 0'd. - Add ICBM Parameter Info callback... you can catch this if you want. - aim_getbuildstring() now takes a buffer instead of returning static (ew!) - Clean up, "factorize", etc - More stuff... (Only one "middle handler" left in rxhandlers.c!) --- CHANGES | 17 + include/aim.h | 4 +- include/aim_internal.h | 29 +- src/admin.c | 9 +- src/auth.c | 9 +- src/bos.c | 9 +- src/buddylist.c | 9 +- src/chat.c | 447 ++++++++-------- src/chatnav.c | 655 +++++++++++------------ src/conn.c | 6 + src/im.c | 1051 ++++++++++++++++++------------------- src/info.c | 245 ++++----- src/login.c | 282 ++++++++++ src/meta.c | 8 +- src/misc.c | 53 ++ src/rxhandlers.c | 379 +------------ src/search.c | 7 +- src/stats.c | 9 +- utils/faimtest/faimtest.c | 38 +- 19 files changed, 1564 insertions(+), 1702 deletions(-) diff --git a/CHANGES b/CHANGES index 27c976f..3ba96eb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,23 @@ No release numbers ------------------ + - Sat Mar 24 03:16:32 UTC 2001 + - vaargs to msgerror and locateerror swapped + - ** CLIENT CHANGE: Reason code comes before SN now. This is so that + the backend code for all three error handlers is identical. + - aim_getinfo() returns -1 on failure (hah! I don't think anyone checks + return codes from libfaim anyway...they're known for their + inconsistency and lack of sensicality) + - Remove _DEFAULT handlers in faimtest... + - They were not consistent. + - They did not make sense. + - They did not work anyway. + - Most of them were #if 0'd. + - Add ICBM Parameter Info callback... you can catch this if you want. + - aim_getbuildstring() now takes a buffer instead of returning static (ew!) + - Clean up, "factorize", etc + - More stuff... (Only one "middle handler" left in rxhandlers.c!) + - Fri Mar 23 05:42:11 UTC 2001 - Export aim_encode_password_md5() - Add middle handler for 000b/0002 (min report interval) diff --git a/include/aim.h b/include/aim.h index 8d57fc2..6a78c77 100644 --- a/include/aim.h +++ b/include/aim.h @@ -679,7 +679,7 @@ faim_export int aim_handlerendconnect(struct aim_session_t *sess, struct aim_con faim_export unsigned long aim_denytransfer(struct aim_session_t *sess, struct aim_conn_t *conn, char *sender, char *cookie, unsigned short code); faim_export struct aim_conn_t *aim_accepttransfer(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, char *cookie, char *ip, unsigned short listingfiles, unsigned short listingtotsize, unsigned short listingsize, unsigned int listingchecksum, unsigned short rendid); -faim_export unsigned long aim_getinfo(struct aim_session_t *, struct aim_conn_t *, const char *, unsigned short); +faim_export int aim_getinfo(struct aim_session_t *, struct aim_conn_t *, const char *, unsigned short); faim_export int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info); faim_export int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn); @@ -772,7 +772,7 @@ faim_export char *aim_strsep(char **pp, const char *delim); /* aim_meta.c */ faim_export char *aim_getbuilddate(void); faim_export char *aim_getbuildtime(void); -faim_export char *aim_getbuildstring(void); +faim_export int aim_getbuildstring(char *buf, int buflen); #include diff --git a/include/aim_internal.h b/include/aim_internal.h index 0682b2d..98c2dd7 100644 --- a/include/aim_internal.h +++ b/include/aim_internal.h @@ -37,7 +37,12 @@ faim_internal int bos_modfirst(struct aim_session_t *sess, aim_module_t *mod); faim_internal int search_modfirst(struct aim_session_t *sess, aim_module_t *mod); faim_internal int stats_modfirst(struct aim_session_t *sess, aim_module_t *mod); faim_internal int auth_modfirst(struct aim_session_t *sess, aim_module_t *mod); - +faim_internal int msg_modfirst(struct aim_session_t *sess, aim_module_t *mod); +faim_internal int misc_modfirst(struct aim_session_t *sess, aim_module_t *mod); +faim_internal int chatnav_modfirst(struct aim_session_t *sess, aim_module_t *mod); +faim_internal int chat_modfirst(struct aim_session_t *sess, aim_module_t *mod); +faim_internal int locate_modfirst(struct aim_session_t *sess, aim_module_t *mod); +faim_internal int general_modfirst(struct aim_session_t *sess, aim_module_t *mod); faim_internal unsigned long aim_genericreq_n(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype); faim_internal unsigned long aim_genericreq_l(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype, u_long *); @@ -46,7 +51,6 @@ faim_internal unsigned long aim_genericreq_s(struct aim_session_t *, struct aim_ faim_internal void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn); faim_internal int aim_recv(int fd, void *buf, size_t count); -faim_internal int aim_parse_unknown(struct aim_session_t *, struct command_rx_struct *command, ...); faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn); faim_internal int aim_tx_sendframe(struct aim_session_t *sess, struct command_tx_struct *cur); @@ -54,8 +58,6 @@ faim_internal unsigned int aim_get_next_txseqnum(struct aim_conn_t *); faim_internal struct command_tx_struct *aim_tx_new(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned char framing, int chan, int datalen); faim_internal int aim_tx_enqueue(struct aim_session_t *, struct command_tx_struct *); faim_internal int aim_tx_printqueue(struct aim_session_t *); -faim_internal int aim_parse_hostonline(struct aim_session_t *sess, struct command_rx_struct *command, ...); -faim_internal int aim_parse_hostversions(struct aim_session_t *sess, struct command_rx_struct *command, ...); faim_internal int aim_tx_cleanqueue(struct aim_session_t *, struct aim_conn_t *); faim_internal rxcallback_t aim_callhandler(struct aim_session_t *sess, struct aim_conn_t *conn, u_short family, u_short type); @@ -87,10 +89,7 @@ faim_internal int aim_oft_buildheader(unsigned char *,struct aim_fileheader_t *) faim_internal int aim_listenestablish(u_short); faim_internal int aim_tx_destroy(struct command_tx_struct *); -faim_internal int aim_handleredirect_middle(struct aim_session_t *, struct command_rx_struct *, ...); faim_internal int aim_parse_unknown(struct aim_session_t *, struct command_rx_struct *, ...); -faim_internal int aim_parse_generalerrs(struct aim_session_t *, struct command_rx_struct *command, ...); -faim_internal int aim_parsemotd_middle(struct aim_session_t *sess, struct command_rx_struct *command, ...); /* these are used by aim_*_clientready */ #define AIM_TOOL_JAVA 0x0001 @@ -107,16 +106,7 @@ struct aim_tool_version { unsigned short toolversion; }; -faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command); - -faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command); -faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command); - -faim_internal int aim_parse_incoming_im_middle(struct aim_session_t *, struct command_rx_struct *); -faim_internal int aim_parse_outgoing_im_middle(struct aim_session_t *, struct command_rx_struct *); -faim_internal int aim_parse_msgerror_middle(struct aim_session_t *, struct command_rx_struct *); faim_internal int aim_negchan_middle(struct aim_session_t *sess, struct command_rx_struct *command); -faim_internal int aim_parse_missedcall(struct aim_session_t *sess, struct command_rx_struct *command); extern u_char aim_caps[8][16]; faim_internal unsigned short aim_getcap(struct aim_session_t *sess, unsigned char *capblock, int buflen); @@ -131,16 +121,9 @@ faim_internal int aim_msgcookie_gettype(int reqclass); faim_internal int aim_cookie_free(struct aim_session_t *sess, struct aim_msgcookie_t *cookie); faim_internal int aim_extractuserinfo(struct aim_session_t *sess, unsigned char *, struct aim_userinfo_s *); -faim_internal int aim_parse_userinfo_middle(struct aim_session_t *, struct command_rx_struct *); faim_internal int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info); -faim_internal int aim_parse_locateerr(struct aim_session_t *sess, struct command_rx_struct *command); faim_internal int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo); -faim_internal int aim_chat_parse_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command); -faim_internal int aim_chat_parse_joined(struct aim_session_t *sess, struct command_rx_struct *command); -faim_internal int aim_chat_parse_leave(struct aim_session_t *sess, struct command_rx_struct *command); -faim_internal int aim_chat_parse_incoming(struct aim_session_t *sess, struct command_rx_struct *command); -faim_internal int aim_chatnav_parse_info(struct aim_session_t *sess, struct command_rx_struct *command); faim_internal void faimdprintf(struct aim_session_t *sess, int dlevel, const char *format, ...); diff --git a/src/admin.c b/src/admin.c index 22419d8..759d096 100644 --- a/src/admin.c +++ b/src/admin.c @@ -72,14 +72,7 @@ static int accountconfirm(struct aim_session_t *sess, aim_module_t *mod, struct static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); - - if (snac->family != mod->family) - return 0; - - if (snac->subtype == 0x0001) - ; - else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0005)) + if ((snac->subtype == 0x0003) || (snac->subtype == 0x0005)) return infochange(sess, mod, rx, snac, data, datalen); else if (snac->subtype == 0x0007) return accountconfirm(sess, mod, rx, snac, data, datalen); diff --git a/src/auth.c b/src/auth.c index 629d755..ba506ae 100644 --- a/src/auth.c +++ b/src/auth.c @@ -203,14 +203,7 @@ static int keyparse(struct aim_session_t *sess, aim_module_t *mod, struct comman static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); - - if (snac->family != mod->family) - return 0; - - if (snac->subtype == 0x0001) - ; - else if (snac->subtype == 0x0003) + if (snac->subtype == 0x0003) return parse(sess, mod, rx, snac, data, datalen); else if (snac->subtype == 0x0007) return keyparse(sess, mod, rx, snac, data, datalen); diff --git a/src/bos.c b/src/bos.c index 829788b..9a6a0de 100644 --- a/src/bos.c +++ b/src/bos.c @@ -56,14 +56,7 @@ static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_ static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); - - if (snac->family != mod->family) - return 0; - - if (snac->subtype == 0x0001) - ; - else if (snac->subtype == 0x0003) + if (snac->subtype == 0x0003) return rights(sess, mod, rx, snac, data, datalen); return 0; diff --git a/src/buddylist.c b/src/buddylist.c index 28492aa..6e3ae9c 100644 --- a/src/buddylist.c +++ b/src/buddylist.c @@ -78,14 +78,7 @@ static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_ static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); - - if (snac->family != mod->family) - return 0; - - if (snac->subtype == 0x0001) - ; - else if (snac->subtype == 0x0003) + if (snac->subtype == 0x0003) return rights(sess, mod, rx, snac, data, datalen); else if (snac->subtype == 0x000b) return oncoming(sess, mod, rx, snac, data, datalen); diff --git a/src/chat.c b/src/chat.c index 8eb1439..51af85b 100644 --- a/src/chat.c +++ b/src/chat.c @@ -208,6 +208,164 @@ faim_internal int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *o return i; } +faim_export unsigned long aim_chat_clientready(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct command_tx_struct *newpacket; + int i; + + if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 0x20))) + return -1; + + newpacket->lock = 1; + + 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++); +} + +faim_export int aim_chat_leaveroom(struct aim_session_t *sess, char *name) +{ + struct aim_conn_t *conn; + + if ((conn = aim_chat_getconn(sess, name))) + aim_conn_close(conn); + + if (!conn) + return -1; + return 0; +} + +/* + * conn must be a BOS connection! + */ +faim_export unsigned 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; + struct aim_msgcookie_t *cookie; + struct aim_invite_priv *priv; + + if (!sess || !conn || !sn || !msg || !roomname) + return -1; + + if (conn->type != AIM_CONN_TYPE_BOS) + return -1; + + if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) + return -1; + + newpacket->lock = 1; + + 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()); + + /* XXX this should get uncached by the unwritten 'invite accept' handler */ + if(!(priv = calloc(sizeof(struct aim_invite_priv), 1))) + return -1; + priv->sn = strdup(sn); + priv->roomname = strdup(roomname); + priv->exchange = exchange; + priv->instance = instance; + + if(!(cookie = aim_mkcookie(newpacket->data+curbyte-8, AIM_COOKIETYPE_INVITE, priv))) + return -1; + aim_cachecookie(sess, cookie); + + /* + * 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++); +} /* * General room information. Lots of stuff. @@ -218,17 +376,16 @@ faim_internal int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *o * * SNAC 000e/0002 */ -faim_internal int aim_chat_parse_infoupdate(struct aim_session_t *sess, - struct command_rx_struct *command) +static int infoupdate(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { struct aim_userinfo_s *userinfo = NULL; rxcallback_t userfunc=NULL; - int ret = 1, i = 0; + int ret = 0, i = 0; int usercount = 0; - u_char detaillevel = 0; + unsigned char detaillevel = 0; char *roomname = NULL; struct aim_chat_roominfo roominfo; - u_short tlvcount = 0; + unsigned short tlvcount = 0; struct aim_tlvlist_t *tlvlist; char *roomdesc = NULL; unsigned short unknown_c9 = 0; @@ -236,10 +393,9 @@ faim_internal int aim_chat_parse_infoupdate(struct aim_session_t *sess, unsigned short maxmsglen = 0; unsigned short unknown_d2 = 0, unknown_d5 = 0; - i = 10; - i += aim_chat_readroominfo(command->data+i, &roominfo); + i += aim_chat_readroominfo(data+i, &roominfo); - detaillevel = aimutil_get8(command->data+i); + detaillevel = aimutil_get8(data+i); i++; if (detaillevel != 0x02) { @@ -250,19 +406,19 @@ faim_internal int aim_chat_parse_infoupdate(struct aim_session_t *sess, return 1; } - tlvcount = aimutil_get16(command->data+i); + tlvcount = aimutil_get16(data+i); i += 2; /* * Everything else are TLVs. */ - tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); + tlvlist = aim_readtlvchain(data+i, datalen-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); + roomname = aim_gettlv_str(tlvlist, 0x006a, 1); /* * Type 0x006f: Number of occupants. @@ -324,9 +480,9 @@ faim_internal int aim_chat_parse_infoupdate(struct aim_session_t *sess, unknown_d5 = aim_gettlv8(tlvlist, 0x00d5, 1); - if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE))) { + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { ret = userfunc(sess, - command, + rx, &roominfo, roomname, usercount, @@ -337,7 +493,8 @@ faim_internal int aim_chat_parse_infoupdate(struct aim_session_t *sess, maxmsglen, unknown_d2, unknown_d5); - } + } + free(roominfo.name); free(userinfo); free(roomname); @@ -347,56 +504,25 @@ faim_internal int aim_chat_parse_infoupdate(struct aim_session_t *sess, return ret; } -faim_internal int aim_chat_parse_joined(struct aim_session_t *sess, - struct command_rx_struct *command) +static int userlistchange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { struct aim_userinfo_s *userinfo = NULL; - rxcallback_t userfunc=NULL; - int i = 10, curcount = 0, ret = 1; + rxcallback_t userfunc; + int i = 0, curcount = 0, ret = 0; - while (i < command->commandlen) { + while (i < datalen) { curcount++; userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); - i += aim_extractuserinfo(sess, command->data+i, &userinfo[curcount-1]); + i += aim_extractuserinfo(sess, data+i, &userinfo[curcount-1]); } - if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN))) { - ret = userfunc(sess, - command, - curcount, - userinfo); - } + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, curcount, userinfo); free(userinfo); return ret; -} - -faim_internal 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(sess, command->data+i, &userinfo[curcount-1]); - } - - if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE))) { - ret = userfunc(sess, - command, - curcount, - userinfo); - } - - free(userinfo); - - return ret; -} +} /* * We could probably include this in the normal ICBM parsing @@ -421,12 +547,11 @@ faim_internal int aim_chat_parse_leave(struct aim_session_t *sess, * possibly others * */ -faim_internal int aim_chat_parse_incoming(struct aim_session_t *sess, - struct command_rx_struct *command) +static int incomingmsg(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { struct aim_userinfo_s userinfo; rxcallback_t userfunc=NULL; - int ret = 1, i = 0, z = 0; + int ret = 0, i = 0; unsigned char cookie[8]; int channel; struct aim_tlvlist_t *outerlist; @@ -435,13 +560,11 @@ faim_internal int aim_chat_parse_incoming(struct aim_session_t *sess, memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); - i = 10; /* skip snac */ - /* * ICBM Cookie. Cache it. */ - for (z=0; z<8; z++,i++) - cookie[z] = command->data[i]; + memcpy(cookie, data, 8); + i += 8; if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) { if (ck->data) @@ -458,18 +581,18 @@ faim_internal int aim_chat_parse_incoming(struct aim_session_t *sess, * We only do channel 3 here. * */ - channel = aimutil_get16(command->data+i); + channel = aimutil_get16(data+i); i += 2; if (channel != 0x0003) { faimdprintf(sess, 0, "faim: chat_incoming: unknown channel! (0x%04x)\n", channel); - return 1; + return 0; } /* * Start parsing TLVs right away. */ - outerlist = aim_readtlvchain(command->data+i, command->commandlen-i); + outerlist = aim_readtlvchain(data+8+2, datalen-8-2); /* * Type 0x0003: Source User Information @@ -490,192 +613,52 @@ faim_internal int aim_chat_parse_incoming(struct aim_session_t *sess, /* * Type 0x0005: Message Block. Conains more TLVs. */ - if (aim_gettlv(outerlist, 0x0005, 1)) - { - struct aim_tlvlist_t *innerlist; - struct aim_tlv_t *msgblock; + 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); + 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); + /* + * Type 0x0001: Message. + */ + if (aim_gettlv(innerlist, 0x0001, 1)) + msg = aim_gettlv_str(innerlist, 0x0001, 1); - aim_freetlvchain(&innerlist); - } + aim_freetlvchain(&innerlist); + } + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, &userinfo, msg); - userfunc = aim_callhandler(sess, 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; -} - -faim_export unsigned long aim_chat_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) -{ - struct command_tx_struct *newpacket; - int i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 0x20))) - return -1; - - newpacket->lock = 1; - - 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++); } -faim_export int aim_chat_leaveroom(struct aim_session_t *sess, char *name) +static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - struct aim_conn_t *conn; - if ((conn = aim_chat_getconn(sess, name))) - aim_conn_close(conn); + if (snac->subtype == 0x0002) + return infoupdate(sess, mod, rx, snac, data, datalen); + else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004)) + return userlistchange(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0006) + return incomingmsg(sess, mod, rx, snac, data, datalen); - if (!conn) - return -1; return 0; } -/* - * conn must be a BOS connection! - */ -faim_export unsigned 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) +faim_internal int chat_modfirst(struct aim_session_t *sess, aim_module_t *mod) { - struct command_tx_struct *newpacket; - int i,curbyte=0; - struct aim_msgcookie_t *cookie; - struct aim_invite_priv *priv; - if (!sess || !conn || !sn || !msg || !roomname) - return -1; - - if (conn->type != AIM_CONN_TYPE_BOS) - return -1; + mod->family = 0x000e; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "chat", sizeof(mod->name)); + mod->snachandler = snachandler; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) - return -1; - - newpacket->lock = 1; - - 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()); - - /* XXX this should get uncached by the unwritten 'invite accept' handler */ - if(!(priv = calloc(sizeof(struct aim_invite_priv), 1))) - return -1; - priv->sn = strdup(sn); - priv->roomname = strdup(roomname); - priv->exchange = exchange; - priv->instance = instance; - - if(!(cookie = aim_mkcookie(newpacket->data+curbyte-8, AIM_COOKIETYPE_INVITE, priv))) - return -1; - aim_cachecookie(sess, cookie); - - /* - * 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++); + return 0; } diff --git a/src/chatnav.c b/src/chatnav.c index 4dff1f0..f057eae 100644 --- a/src/chatnav.c +++ b/src/chatnav.c @@ -51,341 +51,6 @@ faim_export unsigned long aim_chatnav_clientready(struct aim_session_t *sess, 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. - */ -faim_internal 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; - int ret=1; - - snacid = aimutil_get32(command->data+6); - snac = aim_remsnac(sess, snacid); - - if (!snac) { - faimdprintf(sess, 0, "faim: chatnav_parse_info: received response to unknown request! (%08lx)\n", snacid); - return 1; - } - - if (snac->family != 0x000d) { - faimdprintf(sess, 0, "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; - 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)) - maxrooms = aim_gettlv8(tlvlist, 0x0002, 1); - - /* - * 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 0x0002: Unknown - */ - if (aim_gettlv(innerlist, 0x0002, 1)) { - unsigned short classperms; - - classperms = aim_gettlv16(innerlist, 0x0002, 1); - - faimdprintf(sess, 1, "faim: class permissions %x\n", classperms); - } - - /* - * Type 0x00c9: Unknown - */ - if (aim_gettlv(innerlist, 0x00c9, 1)) - ; - - /* - * Type 0x00ca: Creation Date - */ - if (aim_gettlv(innerlist, 0x00ca, 1)) - ; - - /* - * Type 0x00d0: Mandatory Channels? - */ - if (aim_gettlv(innerlist, 0x00d0, 1)) - ; - - /* - * Type 0x00d1: Maximum Message length - */ - if (aim_gettlv(innerlist, 0x00d1, 1)) - ; - - /* - * Type 0x00d2: Maximum Occupancy? - */ - 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: Creation Permissions - * - * 0 Creation not allowed - * 1 Room creation allowed - * 2 Exchange creation allowed - * - */ - if (aim_gettlv(innerlist, 0x00d5, 1)) { - unsigned char createperms; - - createperms = aim_gettlv8(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; - - aim_freetlvchain(&innerlist); - } - - /* - * Call client. - */ - if ((userfunc = aim_callhandler(sess, command->conn, 0x000d, 0x0009))) - ret = userfunc(sess, command, snac->type, maxrooms, curexchange, exchanges); - curexchange--; - while(curexchange >= 0) - { - 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(&tlvlist); - - break; - } - case 0x0003: /* request exchange info */ - faimdprintf(sess, 0, "chatnav_parse_info: resposne to exchange info\n"); - break; - case 0x0004: /* request room info */ - faimdprintf(sess, 0, "chatnav_parse_info: response to room info\n"); - break; - case 0x0005: /* request more room info */ - faimdprintf(sess, 0, "chatnav_parse_info: response to more room info\n"); - break; - case 0x0006: /* request occupant list */ - faimdprintf(sess, 0, "chatnav_parse_info: response to occupant info\n"); - break; - case 0x0007: /* search for a room */ - faimdprintf(sess, 0, "chatnav_parse_info: search results\n"); - break; - case 0x0008: { /* create room */ - /* - 000d 0009 0000 0000 0010 - - 0004 0053 - 0004 -- exchange - 0c 7a 6f6f 6f6d 7a6f 6f6f 6d34 32 cookie/name - 0000 -- instance - 02 -- detail level - 0007 -- unknown! - 006a 000c 7a 6f 6f6f 6d7a 6f6f 6f6d 3432 -- fully qualified name - 00c9 0002 0011 -- flags - 00ca 0004 39c0 0883 -- create time - 00d1 0002 0200 -- max msg len - 00d2 0002 0018 -- max occupants - 00d3 000c -- name - 7a6f 6f6f 6d7a 6f6f 6f6d 3432 - 00d5 0001 02 -- creation permission - */ - struct aim_tlvlist_t *tlvlist, *innerlist; - char *ck = NULL, *fqcn = NULL, *name = NULL; - unsigned short exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0; - unsigned long createtime = 0; - unsigned char createperms = 0; - int i, cklen; - struct aim_tlv_t *bigblock; - - i = 10; - if (!(tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i))) { - faimdprintf(sess, 0, "unable to read top tlv in create room response\n"); - break; - } - - if (!(bigblock = aim_gettlv(tlvlist, 0x0004, 1))) { - faimdprintf(sess, 0, "no bigblock in top tlv in create room response\n"); - aim_freetlvchain(&tlvlist); - break; - } - i = 0; - - exchange = aimutil_get16(bigblock->value+i); - i += 2; - - cklen = aimutil_get8(bigblock->value+i); - i++; - - ck = malloc(cklen+1); - memcpy(ck, bigblock->value+i, cklen); - ck[cklen] = '\0'; - i += cklen; - - instance = aimutil_get16(bigblock->value+i); - i += 2; - - if (aimutil_get8(bigblock->value+i) != 0x02) { - faimdprintf(sess, 0, "unknown detaillevel in create room response (0x%02x)\n", aimutil_get8(bigblock->value+i)); - aim_freetlvchain(&tlvlist); - free(ck); - break; - } - i += 1; - - unknown = aimutil_get16(bigblock->value+i); - i += 2; - - if (!(innerlist = aim_readtlvchain(bigblock->value+i, bigblock->length-i))) { - faimdprintf(sess, 0, "unable to read inner tlv chain in create room response\n"); - aim_freetlvchain(&tlvlist); - free(ck); - break; - } - - if (aim_gettlv(innerlist, 0x006a, 1)) - fqcn = aim_gettlv_str(innerlist, 0x006a, 1); - - if (aim_gettlv(innerlist, 0x00c9, 1)) - flags = aim_gettlv16(innerlist, 0x00c9, 1); - - if (aim_gettlv(innerlist, 0x00ca, 1)) - createtime = aim_gettlv32(innerlist, 0x00ca, 1); - - if (aim_gettlv(innerlist, 0x00d1, 1)) - maxmsglen = aim_gettlv16(innerlist, 0x00d1, 1); - - if (aim_gettlv(innerlist, 0x00d2, 1)) - maxoccupancy = aim_gettlv16(innerlist, 0x00d2, 1); - - if (aim_gettlv(innerlist, 0x00d3, 1)) - name = aim_gettlv_str(innerlist, 0x00d3, 1); - - if (aim_gettlv(innerlist, 0x00d5, 1)) - createperms = aim_gettlv8(innerlist, 0x00d5, 1); - - if ((userfunc = aim_callhandler(sess, command->conn, 0x000d, 0x0009))) { - ret = userfunc(sess, command, snac->type, fqcn, instance, exchange, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck); - } - - if (ck) - free(ck); - if (name) - free(name); - if (fqcn) - free(fqcn); - aim_freetlvchain(&innerlist); - aim_freetlvchain(&tlvlist); - - break; - } - default: /* unknown */ - faimdprintf(sess, 0, "chatnav_parse_info: unknown request subtype (%04x)\n", snac->type); - } - - if (snac && snac->data) - free(snac->data); - if (snac) - free(snac); - - return ret; -} - faim_export unsigned long aim_chatnav_createroom(struct aim_session_t *sess, struct aim_conn_t *conn, char *name, @@ -426,3 +91,323 @@ faim_export unsigned long aim_chatnav_createroom(struct aim_session_t *sess, return sess->snac_nextid; } + +static int parseinfo_perms(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen, struct aim_snac_t *snac2) +{ + rxcallback_t userfunc; + int ret = 0; + struct aim_tlvlist_t *tlvlist; + struct aim_chat_exchangeinfo *exchanges = NULL; + int curexchange = 0; + struct aim_tlv_t *exchangetlv; + unsigned char maxrooms = 0; + struct aim_tlvlist_t *innerlist; + + tlvlist = aim_readtlvchain(data, datalen); + + /* + * Type 0x0002: Maximum concurrent rooms. + */ + if (aim_gettlv(tlvlist, 0x0002, 1)) + maxrooms = aim_gettlv8(tlvlist, 0x0002, 1); + + /* + * 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 0x0002: Unknown + */ + if (aim_gettlv(innerlist, 0x0002, 1)) { + unsigned short classperms; + + classperms = aim_gettlv16(innerlist, 0x0002, 1); + + faimdprintf(sess, 1, "faim: class permissions %x\n", classperms); + } + + /* + * Type 0x00c9: Unknown + */ + if (aim_gettlv(innerlist, 0x00c9, 1)) + ; + + /* + * Type 0x00ca: Creation Date + */ + if (aim_gettlv(innerlist, 0x00ca, 1)) + ; + + /* + * Type 0x00d0: Mandatory Channels? + */ + if (aim_gettlv(innerlist, 0x00d0, 1)) + ; + + /* + * Type 0x00d1: Maximum Message length + */ + if (aim_gettlv(innerlist, 0x00d1, 1)) + ; + + /* + * Type 0x00d2: Maximum Occupancy? + */ + 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: Creation Permissions + * + * 0 Creation not allowed + * 1 Room creation allowed + * 2 Exchange creation allowed + * + */ + if (aim_gettlv(innerlist, 0x00d5, 1)) { + unsigned char createperms; + + createperms = aim_gettlv8(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; + + aim_freetlvchain(&innerlist); + } + + /* + * Call client. + */ + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, snac2->type, maxrooms, curexchange, exchanges); + curexchange--; + while(curexchange >= 0) { + free(exchanges[curexchange].name); + free(exchanges[curexchange].charset1); + free(exchanges[curexchange].lang1); + free(exchanges[curexchange].charset2); + free(exchanges[curexchange].lang2); + curexchange--; + } + free(exchanges); + aim_freetlvchain(&tlvlist); + + return ret; +} + +static int parseinfo_create(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen, struct aim_snac_t *snac2) +{ + rxcallback_t userfunc; + struct aim_tlvlist_t *tlvlist, *innerlist; + char *ck = NULL, *fqcn = NULL, *name = NULL; + unsigned short exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0; + unsigned long createtime = 0; + unsigned char createperms = 0; + int i = 0, cklen; + struct aim_tlv_t *bigblock; + int ret = 0; + + if (!(tlvlist = aim_readtlvchain(data, datalen))) { + faimdprintf(sess, 0, "unable to read top tlv in create room response\n"); + return 0; + } + + if (!(bigblock = aim_gettlv(tlvlist, 0x0004, 1))) { + faimdprintf(sess, 0, "no bigblock in top tlv in create room response\n"); + aim_freetlvchain(&tlvlist); + return 0; + } + + exchange = aimutil_get16(bigblock->value+i); + i += 2; + + cklen = aimutil_get8(bigblock->value+i); + i++; + + ck = malloc(cklen+1); + memcpy(ck, bigblock->value+i, cklen); + ck[cklen] = '\0'; + i += cklen; + + instance = aimutil_get16(bigblock->value+i); + i += 2; + + if (aimutil_get8(bigblock->value+i) != 0x02) { + faimdprintf(sess, 0, "unknown detaillevel in create room response (0x%02x)\n", aimutil_get8(bigblock->value+i)); + aim_freetlvchain(&tlvlist); + free(ck); + return 0; + } + i += 1; + + unknown = aimutil_get16(bigblock->value+i); + i += 2; + + if (!(innerlist = aim_readtlvchain(bigblock->value+i, bigblock->length-i))) { + faimdprintf(sess, 0, "unable to read inner tlv chain in create room response\n"); + aim_freetlvchain(&tlvlist); + free(ck); + return 0; + } + + if (aim_gettlv(innerlist, 0x006a, 1)) + fqcn = aim_gettlv_str(innerlist, 0x006a, 1); + + if (aim_gettlv(innerlist, 0x00c9, 1)) + flags = aim_gettlv16(innerlist, 0x00c9, 1); + + if (aim_gettlv(innerlist, 0x00ca, 1)) + createtime = aim_gettlv32(innerlist, 0x00ca, 1); + + if (aim_gettlv(innerlist, 0x00d1, 1)) + maxmsglen = aim_gettlv16(innerlist, 0x00d1, 1); + + if (aim_gettlv(innerlist, 0x00d2, 1)) + maxoccupancy = aim_gettlv16(innerlist, 0x00d2, 1); + + if (aim_gettlv(innerlist, 0x00d3, 1)) + name = aim_gettlv_str(innerlist, 0x00d3, 1); + + if (aim_gettlv(innerlist, 0x00d5, 1)) + createperms = aim_gettlv8(innerlist, 0x00d5, 1); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck); + + free(ck); + free(name); + free(fqcn); + aim_freetlvchain(&innerlist); + aim_freetlvchain(&tlvlist); + + return ret; +} + +/* + * Since multiple things can trigger this callback, + * we must lookup the snacid to determine the original + * snac subtype that was called. + */ +static int parseinfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + struct aim_snac_t *snac2; + int ret = 0; + + if (!(snac2 = aim_remsnac(sess, snac->id))) { + faimdprintf(sess, 0, "faim: chatnav_parse_info: received response to unknown request! (%08lx)\n", snac->id); + return 0; + } + + if (snac2->family != 0x000d) { + faimdprintf(sess, 0, "faim: chatnav_parse_info: recieved response that maps to corrupt request! (fam=%04x)\n", snac2->family); + return 0; + } + + /* + * We now know what the original SNAC subtype was. + */ + if (snac2->type == 0x0002) /* request chat rights */ + ret = parseinfo_perms(sess, mod, rx, snac, data, datalen, snac2); + else if (snac2->type == 0x0003) /* request exchange info */ + faimdprintf(sess, 0, "chatnav_parse_info: resposne to exchange info\n"); + else if (snac2->type == 0x0004) /* request room info */ + faimdprintf(sess, 0, "chatnav_parse_info: response to room info\n"); + else if (snac2->type == 0x0005) /* request more room info */ + faimdprintf(sess, 0, "chatnav_parse_info: response to more room info\n"); + else if (snac2->type == 0x0006) /* request occupant list */ + faimdprintf(sess, 0, "chatnav_parse_info: response to occupant info\n"); + else if (snac2->type == 0x0007) /* search for a room */ + faimdprintf(sess, 0, "chatnav_parse_info: search results\n"); + else if (snac2->type == 0x0008) /* create room */ + ret = parseinfo_create(sess, mod, rx, snac, data, datalen, snac2); + else + faimdprintf(sess, 0, "chatnav_parse_info: unknown request subtype (%04x)\n", snac2->type); + + if (snac2) + free(snac2->data); + free(snac2); + + return ret; +} + +static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + + if (snac->subtype == 0x0009) + return parseinfo(sess, mod, rx, snac, data, datalen); + + return 0; +} + +faim_internal int chatnav_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0x000d; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "chatnav", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; +} diff --git a/src/conn.c b/src/conn.c index c64d33a..5902b27 100644 --- a/src/conn.c +++ b/src/conn.c @@ -774,12 +774,18 @@ faim_export void aim_session_init(struct aim_session_t *sess, unsigned long flag /* * Register all the modules for this session... */ + aim__registermodule(sess, misc_modfirst); /* load the catch-all first */ aim__registermodule(sess, buddylist_modfirst); aim__registermodule(sess, admin_modfirst); aim__registermodule(sess, bos_modfirst); aim__registermodule(sess, search_modfirst); aim__registermodule(sess, stats_modfirst); aim__registermodule(sess, auth_modfirst); + aim__registermodule(sess, msg_modfirst); + aim__registermodule(sess, chatnav_modfirst); + aim__registermodule(sess, chat_modfirst); + aim__registermodule(sess, locate_modfirst); + aim__registermodule(sess, general_modfirst); return; } diff --git a/src/im.c b/src/im.c index 58ce8c7..ed4bbc9 100644 --- a/src/im.c +++ b/src/im.c @@ -185,11 +185,10 @@ faim_export unsigned long aim_send_im(struct aim_session_t *sess, return sess->snac_nextid; } -faim_internal int aim_parse_outgoing_im_middle(struct aim_session_t *sess, - struct command_rx_struct *command) +static int outgoingim(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - unsigned int i = 0, z; - rxcallback_t userfunc = NULL; + unsigned int i, ret = 0; + rxcallback_t userfunc; unsigned char cookie[8]; int channel; struct aim_tlvlist_t *tlvlist; @@ -198,14 +197,12 @@ faim_internal int aim_parse_outgoing_im_middle(struct aim_session_t *sess, unsigned char flag1 = 0, flag2 = 0; unsigned char *msgblock = NULL, *msg = NULL; - i = 10; - /* ICBM Cookie. */ - for (z=0; z<8; z++,i++) - cookie[z] = command->data[i]; + for (i = 0; i < 8; i++) + cookie[i] = aimutil_get8(data+i); /* Channel ID */ - channel = aimutil_get16(command->data+i); + channel = aimutil_get16(data+i); i += 2; if (channel != 0x01) { @@ -213,10 +210,10 @@ faim_internal int aim_parse_outgoing_im_middle(struct aim_session_t *sess, return 1; } - strncpy(sn, (char *) command->data+i+1, (int) *(command->data+i)); - i += 1 + (int) *(command->data+i); + strncpy(sn, (char *) data+i+1, (int) *(data+i)); + i += 1 + (int) *(data+i); - tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); + tlvlist = aim_readtlvchain(data+i, datalen-i); if (aim_gettlv(tlvlist, 0x0003, 1)) icbmflags |= AIM_IMFLAGS_ACK; @@ -243,14 +240,406 @@ faim_internal int aim_parse_outgoing_im_middle(struct aim_session_t *sess, msg = msgblock+j; } - if ((userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0006)) || (i = 0)) - i = userfunc(sess, command, channel, sn, msg, icbmflags, flag1, flag2); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, channel, sn, msg, icbmflags, flag1, flag2); if (msgblock) free(msgblock); aim_freetlvchain(&tlvlist); - return 0; + return ret; +} + +static int incomingim_ch1(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned short channel, struct aim_userinfo_s *userinfo, struct aim_tlvlist_t *tlvlist, unsigned char *cookie) +{ + rxcallback_t userfunc; + int i, j = 0, y = 0, z = 0, ret = 0; + char *msg = NULL; + unsigned long icbmflags = 0; + struct aim_tlv_t *msgblocktlv; + unsigned char *msgblock; + unsigned short flag1, flag2; + int finlen = 0; + unsigned char fingerprint[10]; + unsigned short wastebits; + + /* + * Check Autoresponse status. If it is an autoresponse, + * it will contain a type 0x0004 TLV, with zero length. + */ + if (aim_gettlv(tlvlist, 0x0004, 1)) + icbmflags |= AIM_IMFLAGS_AWAY; + + /* + * Check Ack Request status. + */ + if (aim_gettlv(tlvlist, 0x0003, 1)) + icbmflags |= AIM_IMFLAGS_ACK; + + /* + * Message block. + */ + msgblocktlv = aim_gettlv(tlvlist, 0x0002, 1); + if (!msgblocktlv || !(msgblock = msgblocktlv->value)) { + faimdprintf(sess, 0, "icbm: major error! no message block TLV found!\n"); + return 0; + } + + /* + * Extracting the message from the unknown cruft. + * + * This is a bit messy, and I'm not really qualified, + * even as the author, to comment on it. At least + * its not as bad as a while loop shooting into infinity. + * + * "Do you believe in magic?" + * + */ + + wastebits = aimutil_get8(msgblock+j++); + wastebits = aimutil_get8(msgblock+j++); + + y = aimutil_get16(msgblock+j); + j += 2; + for (z = 0; z < y; z++) + wastebits = aimutil_get8(msgblock+j++); + wastebits = aimutil_get8(msgblock+j++); + wastebits = aimutil_get8(msgblock+j++); + + finlen = j; + if (finlen > sizeof(fingerprint)) + finlen = sizeof(fingerprint); + memcpy(fingerprint, msgblocktlv->value, finlen); + + /* + * Message string length, including flag words. + */ + i = aimutil_get16(msgblock+j); + j += 2; + + /* + * Flag words. + * + * Its rumored that these can kick in some funky + * 16bit-wide char stuff that used to really kill + * libfaim. Hopefully the latter is no longer true. + * + * Though someone should investiagte the former. + * + */ + flag1 = aimutil_get16(msgblock+j); + j += 2; + flag2 = aimutil_get16(msgblock+j); + j += 2; + + if (flag1 || flag2) + faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", flag1, flag2); + + /* + * Message string. + */ + i -= 4; + msg = (char *)malloc(i+1); + memcpy(msg, msgblock+j, i); + msg[i] = '\0'; + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, channel, userinfo, msg, icbmflags, flag1, flag2, finlen, fingerprint); + + free(msg); + + return ret; +} + +static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned short channel, struct aim_userinfo_s *userinfo, struct aim_tlvlist_t *tlvlist, unsigned char *cookie) +{ + rxcallback_t userfunc; + struct aim_tlv_t *block1; + struct aim_tlvlist_t *list2; + unsigned short reqclass = 0; + unsigned short status = 0; + int ret = 0; + + /* + * There's another block of TLVs embedded in the type 5 here. + */ + block1 = aim_gettlv(tlvlist, 0x0005, 1); + if (!block1 || !block1->value) { + faimdprintf(sess, 0, "no tlv 0x0005 in rendezvous transaction!\n"); + return 0; + } + + /* + * First two bytes represent the status of the connection. + * + * 0 is a request, 2 is an accept + */ + status = aimutil_get16(block1->value+0); + + /* + * Next comes the cookie. Should match the ICBM cookie. + */ + if (memcmp(block1->value+2, cookie, 8) != 0) + faimdprintf(sess, 0, "rend: warning cookies don't match!\n"); + + /* + * The next 16bytes are a capability block so we can + * identify what type of rendezvous this is. + * + * Thanks to Eric Warmenhoven (of GAIM) + * for pointing some of this out to me. In fact, a lot of + * the client-to-client info comes from the work of the GAIM + * developers. Thanks! + * + * Read off one capability string and we should have it ID'd. + * + */ + reqclass = aim_getcap(sess, block1->value+2+8, 0x10); + if (reqclass == 0x0000) { + faimdprintf(sess, 0, "rend: no ID block\n"); + return 0; + } + + /* + * What follows may be TLVs or nothing, depending on the + * purpose of the message. + * + * Ack packets for instance have nothing more to them. + */ + list2 = aim_readtlvchain(block1->value+2+8+16, block1->length-2-8-16); + + if (!list2 || ((reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) { + struct aim_msgcookie_t *cook; + int type; + + type = aim_msgcookie_gettype(reqclass); /* XXX: fix this shitty code */ + + if ((cook = aim_checkcookie(sess, cookie, type)) == NULL) { + faimdprintf(sess, 0, "non-data rendezvous thats not in cache %d/%s!\n", type, cookie); + aim_freetlvchain(&list2); + return 0; + } + + if (cook->type == AIM_COOKIETYPE_OFTGET) { + struct aim_filetransfer_priv *ft; + + if (cook->data) { + int errorcode = -1; /* XXX shouldnt this be 0? */ + + ft = (struct aim_filetransfer_priv *)cook->data; + + if(status != 0x0002) { + if (aim_gettlv(list2, 0x000b, 1)) + errorcode = aim_gettlv16(list2, 0x000b, 1); + + /* XXX this should make it up to the client, you know.. */ + if (errorcode) + faimdprintf(sess, 0, "transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sn, ft->ip, ft->fh.name, errorcode); + } + } else { + faimdprintf(sess, 0, "no data attached to file transfer\n"); + } + } else if (cook->type == AIM_CAPS_VOICE) { + faimdprintf(sess, 0, "voice request cancelled\n"); + } else { + faimdprintf(sess, 0, "unknown cookie cache type %d\n", cook->type); + } + + aim_freetlvchain(&list2); + + return 1; + } + + /* + * The rest of the handling depends on what type it is. + */ + if (reqclass & AIM_CAPS_BUDDYICON) { + + /* XXX implement this (its in ActiveBuddy...) */ + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, channel, reqclass, userinfo); + + } else if (reqclass & AIM_CAPS_VOICE) { + struct aim_msgcookie_t *cachedcook; + + faimdprintf(sess, 0, "rend: voice!\n"); + + if(!(cachedcook = (struct aim_msgcookie_t*)calloc(1, sizeof(struct aim_msgcookie_t)))) { + aim_freetlvchain(&list2); + return 0; + } + + memcpy(cachedcook->cookie, cookie, 8); + cachedcook->type = AIM_COOKIETYPE_OFTVOICE; + cachedcook->data = NULL; + + if (aim_cachecookie(sess, cachedcook) == -1) + faimdprintf(sess, 0, "ERROR caching message cookie\n"); + + /* XXX: implement all this */ + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, channel, reqclass, &userinfo); + + } else if ((reqclass & AIM_CAPS_IMIMAGE) || + (reqclass & AIM_CAPS_BUDDYICON)) { + char ip[30]; + struct aim_directim_priv *priv; + + memset(ip, 0, sizeof(ip)); + + if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0005, 1)) { + struct aim_tlv_t *iptlv, *porttlv; + + iptlv = aim_gettlv(list2, 0x0003, 1); + porttlv = aim_gettlv(list2, 0x0005, 1); + + snprintf(ip, 30, "%d.%d.%d.%d:%d", + aimutil_get8(iptlv->value+0), + aimutil_get8(iptlv->value+1), + aimutil_get8(iptlv->value+2), + aimutil_get8(iptlv->value+3), + 4443 /*aimutil_get16(porttlv->value)*/); + } + + faimdprintf(sess, 0, "rend: directIM request from %s (%s)\n", + userinfo->sn, ip); + + /* + * XXX: there are a couple of different request packets for + * different things + */ + + priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv)); + memcpy(priv->ip, ip, sizeof(priv->ip)); + memcpy(priv->sn, userinfo->sn, sizeof(priv->sn)); + memcpy(priv->cookie, cookie, sizeof(priv->cookie)); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, channel, reqclass, userinfo, priv); + + } else if (reqclass & AIM_CAPS_CHAT) { + struct aim_tlv_t *miscinfo; + struct aim_chat_roominfo roominfo; + char *msg=NULL,*encoding=NULL,*lang=NULL; + + miscinfo = aim_gettlv(list2, 0x2711, 1); + aim_chat_readroominfo(miscinfo->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); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, channel, reqclass, userinfo, &roominfo, msg, encoding?encoding+1:NULL, lang?lang+1:NULL); + + free(roominfo.name); + free(msg); + free(encoding); + free(lang); + + } else if (reqclass & AIM_CAPS_GETFILE) { + char ip[30]; + struct aim_msgcookie_t *cachedcook; + struct aim_tlv_t *miscinfo; + struct aim_tlv_t *iptlv, *porttlv; + + memset(ip, 0, 30); + + if (!(cachedcook = calloc(1, sizeof(struct aim_msgcookie_t)))) { + aim_freetlvchain(&list2); + return 0; + } + + if (!(miscinfo = aim_gettlv(list2, 0x2711, 1)) || + !(iptlv = aim_gettlv(list2, 0x0003, 1)) || + !(porttlv = aim_gettlv(list2, 0x0005, 1))) { + faimdprintf(sess, 0, "rend: badly damaged file get request from %s...\n", userinfo->sn); + aim_cookie_free(sess, cachedcook); + aim_freetlvchain(&list2); + return 0; + } + + snprintf(ip, 30, "%d.%d.%d.%d:%d", + aimutil_get8(iptlv->value+0), + aimutil_get8(iptlv->value+1), + aimutil_get8(iptlv->value+2), + aimutil_get8(iptlv->value+3), + aimutil_get16(porttlv->value)); + + faimdprintf(sess, 0, "rend: file get request from %s (%s)\n", userinfo->sn, ip); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, channel, reqclass, userinfo, ip, cookie); + + } else if (reqclass & AIM_CAPS_SENDFILE) { +#if 0 + char ip[30]; + struct aim_msgcookie_t *cachedcook; + struct aim_tlv_t *miscinfo; + struct aim_tlv_t *iptlv, *porttlv; + + memset(ip, 0, 30); + + if (!(cachedcook = calloc(1, sizeof(struct aim_msgcookie_t)))) { + aim_freetlvchain(&list2); + return 0; + } + + if (!(miscinfo = aim_gettlv(list2, 0x2711, 1)) || + !(iptlv = aim_gettlv(list2, 0x0003, 1)) || + !(porttlv = aim_gettlv(list2, 0x0005, 1))) { + faimdprintf(sess, 0, "rend: badly damaged file get request from %s...\n", userinfo->sn); + aim_cookie_free(sess, cachedcook); + aim_freetlvchain(&list2); + return 0; + } + + snprintf(ip, 30, "%d.%d.%d.%d:%d", + aimutil_get8(iptlv->value+0), + aimutil_get8(iptlv->value+1), + aimutil_get8(iptlv->value+2), + aimutil_get8(iptlv->value+3), + aimutil_get16(porttlv->value)); + + if (aim_gettlv(list2, 0x000c, 1)) + desc = aim_gettlv_str(list2, 0x000c, 1); + + faimdprintf(sess, 0, "rend: file transfer request from %s for %s: %s (%s)\n", + userinfo->sn, miscinfo->value+8, + desc, ip); + + memcpy(cachedcook->cookie, cookie, 8); + + ft = malloc(sizeof(struct aim_filetransfer_priv)); + strncpy(ft->sn, userinfo.sn, sizeof(ft->sn)); + strncpy(ft->ip, ip, sizeof(ft->ip)); + strncpy(ft->fh.name, miscinfo->value+8, sizeof(ft->fh.name)); + cachedcook->type = AIM_COOKIETYPE_OFTSEND; + cachedcook->data = ft; + + if (aim_cachecookie(sess, cachedcook) == -1) + faimdprintf(sess, 0, "ERROR caching message cookie\n"); + + aim_accepttransfer(sess, rx->conn, ft->sn, cookie, AIM_CAPS_SENDFILE); + + if (desc) + free(desc); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, channel, reqclass, userinfo); + +#endif + } else + faimdprintf(sess, 0, "rend: unknown rendezvous 0x%04x\n", reqclass); + + aim_freetlvchain(&list2); + + return ret; } /* @@ -263,30 +652,22 @@ faim_internal int aim_parse_outgoing_im_middle(struct aim_session_t *sess, * can parse both away and normal messages from every client * I have access to. Its not fast, its not clean. But it works. * - * We should also support at least minimal parsing of - * Channel 2, so that we can at least know the name of the - * room we're invited to, but obviously can't attend... - * */ -faim_internal int aim_parse_incoming_im_middle(struct aim_session_t *sess, - struct command_rx_struct *command) +static int incomingim(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - u_int i = 0,z; - rxcallback_t userfunc = NULL; - u_char cookie[8]; + int i, ret = 0; + unsigned char cookie[8]; int channel; struct aim_tlvlist_t *tlvlist; struct aim_userinfo_s userinfo; memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); - i = 10; /* Skip SNAC header */ - /* * Read ICBM Cookie. And throw away. */ - for (z=0; z<8; z++,i++) - cookie[z] = command->data[i]; + for (i = 0; i < 8; i++) + cookie[i] = aimutil_get8(data+i); /* * Channel ID. @@ -301,7 +682,7 @@ faim_internal int aim_parse_incoming_im_middle(struct aim_session_t *sess, * connection negotiations come from. * */ - channel = aimutil_get16(command->data+i); + channel = aimutil_get16(data+i); i += 2; /* @@ -328,468 +709,28 @@ faim_internal int aim_parse_incoming_im_middle(struct aim_session_t *sess, * never be two TLVs of the same type in one block. * */ - i += aim_extractuserinfo(sess, command->data+i, &userinfo); + i += aim_extractuserinfo(sess, data+i, &userinfo); /* * Read block of TLVs (not including the userinfo data). All * further data is derived from what is parsed here. */ - tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); + tlvlist = aim_readtlvchain(data+i, datalen-i); /* * From here on, its depends on what channel we're on. */ if (channel == 1) - { - u_int j = 0, y = 0, z = 0; - char *msg = NULL; - u_int icbmflags = 0; - struct aim_tlv_t *msgblocktlv; - u_char *msgblock; - u_short flag1,flag2; - int finlen = 0; - unsigned char fingerprint[10]; - u_short wastebits; - - /* - * Check Autoresponse status. If it is an autoresponse, - * it will contain a type 0x0004 TLV, with zero length. - */ - if (aim_gettlv(tlvlist, 0x0004, 1)) - icbmflags |= AIM_IMFLAGS_AWAY; - - /* - * Check Ack Request status. - */ - if (aim_gettlv(tlvlist, 0x0003, 1)) - icbmflags |= AIM_IMFLAGS_ACK; - - /* - * Message block. - */ - msgblocktlv = aim_gettlv(tlvlist, 0x0002, 1); - if (!msgblocktlv || !msgblocktlv->value) { - faimdprintf(sess, 0, "icbm: major error! no message block TLV found!\n"); - aim_freetlvchain(&tlvlist); - return 1; - } - - /* - * Extracting the message from the unknown cruft. - * - * This is a bit messy, and I'm not really qualified, - * even as the author, to comment on it. At least - * its not as bad as a while loop shooting into infinity. - * - * "Do you believe in magic?" - * - */ - msgblock = msgblocktlv->value; - j = 0; - - wastebits = aimutil_get8(msgblock+j++); - wastebits = aimutil_get8(msgblock+j++); - - y = aimutil_get16(msgblock+j); - j += 2; - for (z = 0; z < y; z++) - wastebits = aimutil_get8(msgblock+j++); - wastebits = aimutil_get8(msgblock+j++); - wastebits = aimutil_get8(msgblock+j++); - - finlen = j; - if (finlen > sizeof(fingerprint)) - finlen = sizeof(fingerprint); - memcpy(fingerprint, msgblocktlv->value, finlen); - - /* - * Message string length, including flag words. - */ - i = aimutil_get16(msgblock+j); - j += 2; - - /* - * Flag words. - * - * Its rumored that these can kick in some funky - * 16bit-wide char stuff that used to really kill - * libfaim. Hopefully the latter is no longer true. - * - * Though someone should investiagte the former. - * - */ - flag1 = aimutil_get16(msgblock+j); - j += 2; - flag2 = aimutil_get16(msgblock+j); - j += 2; - - if (flag1 || flag2) - faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", flag1, flag2); - - /* - * Message string. - */ - i -= 4; - msg = (char *)malloc(i+1); - memcpy(msg, msgblock+j, i); - msg[i] = '\0'; - - /* - * Call client. - */ - userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); - if (userfunc) - i = userfunc(sess, command, channel, &userinfo, msg, icbmflags, flag1, flag2, finlen, fingerprint); - else - i = 0; - - free(msg); - } + ret = incomingim_ch1(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie); else if (channel == 0x0002) - { - struct aim_tlv_t *block1; - struct aim_tlvlist_t *list2; - unsigned short reqclass = 0; - unsigned short status = 0; - - /* - * There's another block of TLVs embedded in the type 5 here. - */ - block1 = aim_gettlv(tlvlist, 0x0005, 1); - if (!block1) { - faimdprintf(sess, 0, "no tlv 0x0005 in rendezvous transaction!\n"); - aim_freetlvchain(&tlvlist); - return 1; /* major problem */ - } - - /* - * First two bytes represent the status of the connection. - * - * 0 is a request, 2 is an accept - */ - status = aimutil_get16(block1->value+0); - - /* - * Next comes the cookie. Should match the ICBM cookie. - */ - if (memcmp(block1->value+2, cookie, 8) != 0) - faimdprintf(sess, 0, "rend: warning cookies don't match!\n"); - - /* - * The next 16bytes are a capability block so we can - * identify what type of rendezvous this is. - * - * Thanks to Eric Warmenhoven (of GAIM) - * for pointing some of this out to me. In fact, a lot of - * the client-to-client info comes from the work of the GAIM - * developers. Thanks! - * - * Read off one capability string and we should have it ID'd. - * - */ - reqclass = aim_getcap(sess, block1->value+2+8, 0x10); - if (reqclass == 0x0000) { - faimdprintf(sess, 0, "rend: no ID block\n"); - aim_freetlvchain(&tlvlist); - return 1; - } - - /* - * What follows may be TLVs or nothing, depending on the - * purpose of the message. - * - * Ack packets for instance have nothing more to them. - */ - list2 = aim_readtlvchain(block1->value+2+8+16, block1->length-2-8-16); - - if (!list2 || ((reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) { - struct aim_msgcookie_t *cook; - int type; - - type = aim_msgcookie_gettype(reqclass); /* XXX: fix this shitty code */ - - if ((cook = aim_checkcookie(sess, cookie, type)) == NULL) { - faimdprintf(sess, 0, "non-data rendezvous thats not in cache %d/%s!\n", type, cookie); - aim_freetlvchain(&list2); - aim_freetlvchain(&tlvlist); - return 1; - } - - if (cook->type == AIM_COOKIETYPE_OFTGET) { - struct aim_filetransfer_priv *ft; - - if (cook->data) { - int errorcode = -1; /* XXX shouldnt this be 0? */ - - ft = (struct aim_filetransfer_priv *)cook->data; - - if(status != 0x0002) { - if (aim_gettlv(list2, 0x000b, 1)) - errorcode = aim_gettlv16(list2, 0x000b, 1); - - if (errorcode) - faimdprintf(sess, 0, "transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sn, ft->ip, ft->fh.name, errorcode); - } - } else { - faimdprintf(sess, 0, "no data attached to file transfer\n"); - } - } else if (cook->type == AIM_CAPS_VOICE) { - faimdprintf(sess, 0, "voice request cancelled\n"); - } else { - faimdprintf(sess, 0, "unknown cookie cache type %d\n", cook->type); - } - - if (list2) - aim_freetlvchain(&list2); - aim_freetlvchain(&tlvlist); - return 1; - } - - /* - * The rest of the handling depends on what type it is. - */ - if (reqclass & AIM_CAPS_BUDDYICON) { - - /* - * Call client. - */ -#if 0 - userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); - if (userfunc || (i = 0)) - i = userfunc(sess, - command, - channel, - reqclass, - &userinfo, - ip, - cookie); -#endif - - } else if (reqclass & AIM_CAPS_VOICE) { - struct aim_msgcookie_t *cachedcook; - - faimdprintf(sess, 0, "rend: voice!\n"); - - if(!(cachedcook = (struct aim_msgcookie_t*)calloc(1, sizeof(struct aim_msgcookie_t)))) - return 1; - - memcpy(cachedcook->cookie, cookie, 8); - cachedcook->type = AIM_COOKIETYPE_OFTVOICE; - cachedcook->data = NULL; - - if (aim_cachecookie(sess, cachedcook) == -1) - faimdprintf(sess, 0, "ERROR caching message cookie\n"); - - /* XXX: implement all this */ - - /* - * Call client. - */ - userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); - if (userfunc || (i = 0)) { - i = userfunc(sess, command, channel, reqclass, &userinfo); - } - } else if ((reqclass & AIM_CAPS_IMIMAGE) || (reqclass & AIM_CAPS_BUDDYICON)) { - char ip[30]; - struct aim_directim_priv *priv; - - memset(ip, 0, 30); - - if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0005, 1)) { - struct aim_tlv_t *iptlv, *porttlv; - - iptlv = aim_gettlv(list2, 0x0003, 1); - porttlv = aim_gettlv(list2, 0x0005, 1); - - snprintf(ip, 30, "%d.%d.%d.%d:%d", - aimutil_get8(iptlv->value+0), - aimutil_get8(iptlv->value+1), - aimutil_get8(iptlv->value+2), - aimutil_get8(iptlv->value+3), - 4443 /*aimutil_get16(porttlv->value)*/); - } - - faimdprintf(sess, 0, "rend: directIM request from %s (%s)\n", - userinfo.sn, ip); - - /* XXX: there are a couple of different request packets for - * different things */ - - priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv)); - memcpy(priv->ip, ip, sizeof(priv->ip)); - memcpy(priv->sn, userinfo.sn, sizeof(priv->sn)); - memcpy(priv->cookie, cookie, sizeof(priv->cookie)); - - /* - * Call client. - */ - userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); - if (userfunc || (i = 0)) - i = userfunc(sess, - command, - channel, - reqclass, - &userinfo, priv); - - } else if (reqclass & AIM_CAPS_CHAT) { - struct aim_tlv_t *miscinfo; - struct aim_chat_roominfo roominfo; - char *msg=NULL,*encoding=NULL,*lang=NULL; - - miscinfo = aim_gettlv(list2, 0x2711, 1); - aim_chat_readroominfo(miscinfo->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(sess, command->conn, 0x0004, 0x0007); - if (userfunc || (i = 0)) - i = userfunc(sess, - command, - channel, - reqclass, - &userinfo, - &roominfo, - msg, - encoding?encoding+1:NULL, - lang?lang+1:NULL); - free(roominfo.name); - free(msg); - free(encoding); - free(lang); - } else if (reqclass & AIM_CAPS_GETFILE) { - char ip[30]; - struct aim_msgcookie_t *cachedcook; - struct aim_tlv_t *miscinfo; - - if (!(cachedcook = calloc(1, sizeof(struct aim_msgcookie_t)))) - return 0; - - memset(ip, 0, 30); - - if (!(miscinfo = aim_gettlv(list2, 0x2711, 1))) { - aim_cookie_free(sess, cachedcook); - return 0; - } - - if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0005, 1)) { - struct aim_tlv_t *iptlv, *porttlv; - - if (!(iptlv = aim_gettlv(list2, 0x0003, 1)) || !(porttlv = aim_gettlv(list2, 0x0005, 1))) { - aim_cookie_free(sess, cachedcook); - return 0; - } - - snprintf(ip, 30, "%d.%d.%d.%d:%d", - aimutil_get8(iptlv->value+0), - aimutil_get8(iptlv->value+1), - aimutil_get8(iptlv->value+2), - aimutil_get8(iptlv->value+3), - aimutil_get16(porttlv->value)); - } - - faimdprintf(sess, 0, "rend: file get request from %s (%s)\n", userinfo.sn, ip); - - /* - * Call client. - */ - userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); - if (userfunc || (i = 0)) - i = userfunc(sess, - command, - channel, - reqclass, - &userinfo, - ip, - cookie); - - } else if (reqclass & AIM_CAPS_SENDFILE) { -#if 0 - char ip[30]; - char *desc = NULL; - struct aim_msgcookie_t *cachedcook; - struct aim_filetransfer_priv *ft; - struct aim_tlv_t *miscinfo; - - memset(ip, 0, sizeof(ip)); - - if (!(miscinfo = aim_gettlv(list2, 0x2711, 1))) - return 0; - - if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0003, 1)) { - struct aim_tlv_t *iptlv, *porttlv; - - iptlv = aim_gettlv(list2, 0x0003, 1); - porttlv = aim_gettlv(list2, 0x0005, 1); - - snprintf(ip, sizeof(ip)-1, "%d.%d.%d.%d:%d", - aimutil_get8(iptlv->value+0), - aimutil_get8(iptlv->value+1), - aimutil_get8(iptlv->value+2), - aimutil_get8(iptlv->value+3), - aimutil_get16(porttlv->value)); - } - - if (aim_gettlv(list2, 0x000c, 1)) { - desc = aim_gettlv_str(list2, 0x000c, 1); - } - - faimdprintf(sess, 0, "rend: file transfer request from %s for %s: %s (%s)\n", - userinfo.sn, - miscinfo->value+8, - desc, - ip); - - memcpy(cachedcook->cookie, cookie, 8); - - ft = malloc(sizeof(struct aim_filetransfer_priv)); - strncpy(ft->sn, userinfo.sn, sizeof(ft->sn)); - strncpy(ft->ip, ip, sizeof(ft->ip)); - strncpy(ft->fh.name, miscinfo->value+8, sizeof(ft->fh.name)); - cachedcook->type = AIM_COOKIETYPE_OFTSEND; - cachedcook->data = ft; - - if (aim_cachecookie(sess, cachedcook) == -1) - faimdprintf(sess, 0, "ERROR caching message cookie\n"); - - - aim_accepttransfer(sess, command->conn, ft->sn, cookie, AIM_CAPS_SENDFILE); - - if (desc) - free(desc); -#endif - /* - * Call client. - */ - userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0007); - if (userfunc || (i = 0)) - i = userfunc(sess, - command, - channel, - reqclass, - &userinfo); - } else - faimdprintf(sess, 0, "rend: unknown rendezvous 0x%04x\n", reqclass); - - aim_freetlvchain(&list2); - } + ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie); /* * Free up the TLV chain. */ aim_freetlvchain(&tlvlist); - - return i; + return ret; } /* @@ -848,14 +789,10 @@ faim_export unsigned long aim_seticbmparam(struct aim_session_t *sess, curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0002, 0x0000, sess->snac_nextid); curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); curbyte += aimutil_put32(newpacket->data+curbyte, 0x00000003); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x1f); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x40); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x03); - curbyte += aimutil_put8(newpacket->data+curbyte, 0xe7); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x03); - curbyte += aimutil_put8(newpacket->data+curbyte, 0xe7); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x1f40); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x03e7); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x03e7); + curbyte += aimutil_put32(newpacket->data+curbyte, 0x00000000); newpacket->lock = 0; aim_tx_enqueue(sess, newpacket); @@ -863,66 +800,44 @@ faim_export unsigned long aim_seticbmparam(struct aim_session_t *sess, return (sess->snac_nextid++); } -faim_internal int aim_parse_msgerror_middle(struct aim_session_t *sess, - struct command_rx_struct *command) +static int paraminfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - u_long snacid = 0x000000000; - struct aim_snac_t *snac = NULL; - int ret = 0; - rxcallback_t userfunc = NULL; - char *dest; - unsigned short reason = 0; + unsigned long defflags, minmsginterval; + unsigned short maxicbmlen, maxsenderwarn, maxrecverwarn, maxchannel; + rxcallback_t userfunc; + int i = 0; - /* - * Get SNAC from packet and look it up - * the list of unrepliedto/outstanding - * SNACs. - * - * After its looked up, the SN that the - * message should've gone to will be - * in the ->data element of the snac struct. - * - */ - snacid = aimutil_get32(command->data+6); - snac = aim_remsnac(sess, snacid); + maxchannel = aimutil_get16(data+i); + i += 2; - if (!snac) { - faimdprintf(sess, 0, "msgerr: got an ICBM-failed error on an unknown SNAC ID! (%08lx)\n", snacid); - dest = NULL; - } else - dest = snac->data; + defflags = aimutil_get32(data+i); + i += 4; - reason = aimutil_get16(command->data+10); + maxicbmlen = aimutil_get16(data+i); + i += 2; - /* - * Call client. - */ - userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x0001); - if (userfunc) - ret = userfunc(sess, command, dest, reason); - else - ret = 0; - - if (snac) { - free(snac->data); - free(snac); - } + maxsenderwarn = aimutil_get16(data+i); + i += 2; - return ret; -} + maxrecverwarn = aimutil_get16(data+i); + i += 2; + minmsginterval = aimutil_get32(data+i); + i += 4; -faim_internal int aim_parse_missedcall(struct aim_session_t *sess, - struct command_rx_struct *command) + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, maxchannel, defflags, maxicbmlen, maxsenderwarn, maxrecverwarn, minmsginterval); + + return 0; +} + +static int missedcall(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - int i, ret = 1; - rxcallback_t userfunc = NULL; + int i = 0; + rxcallback_t userfunc; unsigned short channel, nummissed, reason; struct aim_userinfo_s userinfo; - i = 10; /* Skip SNAC header */ - - /* * XXX: supposedly, this entire packet can repeat as many times * as necessary. Should implement that. @@ -931,28 +846,78 @@ faim_internal int aim_parse_missedcall(struct aim_session_t *sess, /* * Channel ID. */ - channel = aimutil_get16(command->data+i); + channel = aimutil_get16(data+i); i += 2; /* * Extract the standard user info block. */ - i += aim_extractuserinfo(sess, command->data+i, &userinfo); + i += aim_extractuserinfo(sess, data+i, &userinfo); - nummissed = aimutil_get16(command->data+i); + nummissed = aimutil_get16(data+i); i += 2; - reason = aimutil_get16(command->data+i); + reason = aimutil_get16(data+i); i += 2; - /* - * Call client. - */ - userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x000a); - if (userfunc) - ret = userfunc(sess, command, channel, &userinfo, nummissed, reason); - else - ret = 0; + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, channel, &userinfo, nummissed, reason); - return ret; + return 0; +} + +static int msgack(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + rxcallback_t userfunc; + char sn[MAXSNLEN]; + unsigned char ck[8]; + unsigned short type; + int i = 0; + unsigned char snlen; + + memcpy(ck, data, 8); + i += 8; + + type = aimutil_get16(data+i); + i += 2; + + snlen = aimutil_get8(data+i); + i++; + + memset(sn, 0, sizeof(sn)); + strncpy(sn, (char *)data+i, snlen); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, type, sn); + + return 0; +} + +static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + + if (snac->subtype == 0x0005) + return paraminfo(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0006) + return outgoingim(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0007) + return incomingim(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x000a) + return missedcall(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x000c) + return msgack(sess, mod, rx, snac, data, datalen); + + return 0; +} + +faim_internal int msg_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0x0004; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "messaging", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; } diff --git a/src/info.c b/src/info.c index ee140fe..4c67a6b 100644 --- a/src/info.c +++ b/src/info.c @@ -14,17 +14,21 @@ struct aim_priv_inforeq { unsigned short infotype; }; -faim_export unsigned long aim_getinfo(struct aim_session_t *sess, - struct aim_conn_t *conn, - const char *sn, - unsigned short infotype) +faim_export int aim_getinfo(struct aim_session_t *sess, + struct aim_conn_t *conn, + const char *sn, + unsigned short infotype) { struct command_tx_struct *newpacket; struct aim_priv_inforeq privdata; int i = 0; if (!sess || !conn || !sn) - return 0; + return -1; + + if ((infotype != AIM_GETINFO_GENERALINFO) && + (infotype != AIM_GETINFO_AWAYMESSAGE)) + return -1; if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 12+1+strlen(sn)))) return -1; @@ -44,51 +48,7 @@ faim_export unsigned long aim_getinfo(struct aim_session_t *sess, privdata.infotype = infotype; aim_cachesnac(sess, 0x0002, 0x0005, 0x0000, &privdata, sizeof(struct aim_priv_inforeq)); - return sess->snac_nextid; -} - -faim_internal int aim_parse_locateerr(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - u_long snacid = 0x000000000; - struct aim_snac_t *snac = NULL; - int ret = 0; - rxcallback_t userfunc = NULL; - char *dest; - unsigned short reason = 0; - - /* - * Get SNAC from packet and look it up - * the list of unrepliedto/outstanding - * SNACs. - * - */ - snacid = aimutil_get32(command->data+6); - snac = aim_remsnac(sess, snacid); - - if (!snac) { - faimdprintf(sess, 0, "locerr: got an locate-failed error on an unknown SNAC ID! (%08lx)\n", snacid); - dest = NULL; - } else - dest = snac->data; - - reason = aimutil_get16(command->data+10); - - /* - * Call client. - */ - userfunc = aim_callhandler(sess, command->conn, 0x0002, 0x0001); - if (userfunc) - ret = userfunc(sess, command, dest, reason); - else - ret = 0; - - if (snac) { - free(snac->data); - free(snac); - } - - return ret; + return 0; } /* @@ -461,91 +421,6 @@ faim_internal int aim_extractuserinfo(struct aim_session_t *sess, unsigned char return i; } -/* - * This parses the user info stuff out all nice and pretty then calls - * the higher-level callback (in the user app). - * - */ -faim_internal int aim_parse_userinfo_middle(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - struct aim_userinfo_s userinfo; - char *text_encoding = NULL; - char *text = NULL; - u_int i = 0; - rxcallback_t userfunc=NULL; - struct aim_tlvlist_t *tlvlist; - struct aim_snac_t *origsnac = NULL; - u_long snacid; - struct aim_priv_inforeq *inforeq; - - snacid = aimutil_get32(&command->data[6]); - origsnac = aim_remsnac(sess, snacid); - - if (!origsnac || !origsnac->data) { - faimdprintf(sess, 0, "parse_userinfo_middle: major problem: no snac stored!\n"); - return 1; - } - - inforeq = (struct aim_priv_inforeq *)origsnac->data; - - switch (inforeq->infotype) { - case AIM_GETINFO_GENERALINFO: - case AIM_GETINFO_AWAYMESSAGE: - i = 10; - - /* - * extractuserinfo will give us the basic metaTLV information - */ - i += aim_extractuserinfo(sess, command->data+i, &userinfo); - - /* - * However, in this command, there's usually more TLVs following... - */ - tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); - - /* - * Depending on what informational text was requested, different - * TLVs will appear here. - * - * Profile will be 1 and 2, away message will be 3 and 4. - */ - if (aim_gettlv(tlvlist, 0x0001, 1)) { - text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1); - text = aim_gettlv_str(tlvlist, 0x0002, 1); - } else if (aim_gettlv(tlvlist, 0x0003, 1)) { - text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1); - text = aim_gettlv_str(tlvlist, 0x0004, 1); - } - - userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO); - if (userfunc) { - i = userfunc(sess, - command, - &userinfo, - text_encoding, - text, - inforeq->infotype); - } - - free(text_encoding); - free(text); - aim_freetlvchain(&tlvlist); - break; - default: - faimdprintf(sess, 0, "parse_userinfo_middle: unknown infotype in request! (0x%04x)\n", inforeq->infotype); - break; - } - - if (origsnac) { - if (origsnac->data) - free(origsnac->data); - free(origsnac); - } - - return 1; -} - /* * Inverse of aim_extractuserinfo() */ @@ -651,3 +526,103 @@ faim_export int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_con return 0; } +static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + struct aim_tlvlist_t *tlvlist; + rxcallback_t userfunc; + int ret = 0; + + tlvlist = aim_readtlvchain(data, datalen); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx); + + aim_freetlvchain(&tlvlist); + + return ret; +} + +static int userinfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + struct aim_userinfo_s userinfo; + char *text_encoding = NULL; + char *text = NULL; + int i = 0; + rxcallback_t userfunc; + struct aim_tlvlist_t *tlvlist; + struct aim_snac_t *origsnac = NULL; + struct aim_priv_inforeq *inforeq; + int ret = 0; + + origsnac = aim_remsnac(sess, snac->id); + + if (!origsnac || !origsnac->data) { + faimdprintf(sess, 0, "parse_userinfo_middle: major problem: no snac stored!\n"); + return 0; + } + + inforeq = (struct aim_priv_inforeq *)origsnac->data; + + if ((inforeq->infotype != AIM_GETINFO_GENERALINFO) && + (inforeq->infotype != AIM_GETINFO_AWAYMESSAGE)) { + faimdprintf(sess, 0, "parse_userinfo_middle: unknown infotype in request! (0x%04x)\n", inforeq->infotype); + return 0; + } + + i = aim_extractuserinfo(sess, data, &userinfo); + + tlvlist = aim_readtlvchain(data+i, datalen-i); + + /* + * Depending on what informational text was requested, different + * TLVs will appear here. + * + * Profile will be 1 and 2, away message will be 3 and 4. + */ + if (aim_gettlv(tlvlist, 0x0001, 1)) { + text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1); + text = aim_gettlv_str(tlvlist, 0x0002, 1); + } else if (aim_gettlv(tlvlist, 0x0003, 1)) { + text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1); + text = aim_gettlv_str(tlvlist, 0x0004, 1); + } + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, &userinfo, text_encoding, text, inforeq->infotype); + + free(text_encoding); + free(text); + + aim_freetlvchain(&tlvlist); + + if (origsnac) { + if (origsnac->data) + free(origsnac->data); + free(origsnac); + } + + return ret; +} + +static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + + if (snac->subtype == 0x0003) + return rights(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0006) + return userinfo(sess, mod, rx, snac, data, datalen); + + return 0; +} + +faim_internal int locate_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0x0002; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "locate", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; +} diff --git a/src/login.c b/src/login.c index 3e6e9cd..4b55be0 100644 --- a/src/login.c +++ b/src/login.c @@ -405,3 +405,285 @@ faim_export unsigned long aim_sendredirect(struct aim_session_t *sess, tx->lock = 0; return aim_tx_enqueue(sess, tx); } + + +static int hostonline(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + rxcallback_t userfunc; + int ret = 0; + unsigned short *families; + int famcount, i; + + famcount = datalen/2; + + if (!(families = malloc(datalen))) + return 0; + + for (i = 0; i < famcount; i++) + families[i] = aimutil_get16(data+(i*2)); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, famcount, families); + + free(families); + + return ret; +} + +static int redirect(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + int serviceid; + unsigned char *cookie; + char *ip; + rxcallback_t userfunc; + struct aim_tlvlist_t *tlvlist; + char *chathack = NULL; + int chathackex = 0; + int ret = 0; + + tlvlist = aim_readtlvchain(data, datalen); + + if (!aim_gettlv(tlvlist, 0x000d, 1) || + !aim_gettlv(tlvlist, 0x0005, 1) || + !aim_gettlv(tlvlist, 0x0006, 1)) { + aim_freetlvchain(&tlvlist); + return 0; + } + + serviceid = aim_gettlv16(tlvlist, 0x000d, 1); + ip = aim_gettlv_str(tlvlist, 0x0005, 1); + cookie = aim_gettlv_str(tlvlist, 0x0006, 1); + + /* + * Chat hack. + * + */ + if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) { + chathack = sess->pendingjoin; + chathackex = sess->pendingjoinexchange; + sess->pendingjoin = NULL; + sess->pendingjoinexchange = 0; + } + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, serviceid, ip, cookie, chathack, chathackex); + + free(ip); + free(cookie); + free(chathack); + + aim_freetlvchain(&tlvlist); + + return ret; +} + +/* + * The Rate Limiting System, An Abridged Guide to Nonsense. + * + * OSCAR defines several 'rate classes'. Each class has seperate + * rate limiting properties (limit level, alert level, disconnect + * level, etc), and a set of SNAC family/type pairs associated with + * it. The rate classes, their limiting properties, and the definitions + * of which SNACs are belong to which class, are defined in the + * Rate Response packet at login to each host. + * + * Logically, all rate offenses within one class count against further + * offenses for other SNACs in the same class (ie, sending messages + * too fast will limit the number of user info requests you can send, + * since those two SNACs are in the same rate class). + * + * Since the rate classes are defined dynamically at login, the values + * below may change. But they seem to be fairly constant. + * + * Currently, BOS defines five rate classes, with the commonly used + * members as follows... + * + * Rate class 0x0001: + * - Everything thats not in any of the other classes + * + * Rate class 0x0002: + * - Buddy list add/remove + * - Permit list add/remove + * - Deny list add/remove + * + * Rate class 0x0003: + * - User information requests + * - Outgoing ICBMs + * + * Rate class 0x0004: + * - A few unknowns: 2/9, 2/b, and f/2 + * + * Rate class 0x0005: + * - Chat room create + * - Outgoing chat ICBMs + * + * The only other thing of note is that class 5 (chat) has slightly looser + * limiting properties than class 3 (normal messages). But thats just a + * small bit of trivia for you. + * + * The last thing that needs to be learned about the rate limiting + * system is how the actual numbers relate to the passing of time. This + * seems to be a big mystery. + * + */ + +/* XXX parse this */ +static int rateresp(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + rxcallback_t userfunc; + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx); + + return 0; +} + +static int ratechange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + rxcallback_t userfunc; + int i = 0, code; + unsigned long currentavg, maxavg; + unsigned long rateclass, windowsize, clear, alert, limit, disconnect; + + code = aimutil_get16(data+i); + i += 2; + + rateclass = aimutil_get16(data+i); + i += 2; + + windowsize = aimutil_get32(data+i); + i += 4; + clear = aimutil_get32(data+i); + i += 4; + alert = aimutil_get32(data+i); + i += 4; + limit = aimutil_get32(data+i); + i += 4; + disconnect = aimutil_get32(data+i); + i += 4; + currentavg = aimutil_get32(data+i); + i += 4; + maxavg = aimutil_get32(data+i); + i += 4; + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg); + + return 0; +} + +/* XXX parse this */ +static int selfinfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + rxcallback_t userfunc; + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx); + + return 0; +} + +static int evilnotify(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + rxcallback_t userfunc = NULL; + int i = 0; + unsigned short newevil; + struct aim_userinfo_s userinfo; + + newevil = aimutil_get16(data); + i += 2; + + memset(&userinfo, 0, sizeof(struct aim_userinfo_s)); + + if (datalen-i) + i += aim_extractuserinfo(sess, data+i, &userinfo); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, newevil, &userinfo); + + return 0; +} + +static int motd(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + rxcallback_t userfunc; + char *msg = NULL; + int ret = 0; + struct aim_tlvlist_t *tlvlist; + unsigned short id; + + /* + * Code. + * + * Valid values: + * 1 Mandatory upgrade + * 2 Advisory upgrade + * 3 System bulletin + * 4 Nothing's wrong ("top o the world" -- normal) + * + */ + id = aimutil_get16(data); + + /* + * TLVs follow + */ + if ((tlvlist = aim_readtlvchain(data+2, datalen-2))) + msg = aim_gettlv_str(tlvlist, 0x000b, 1); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, id, msg); + + free(msg); + + aim_freetlvchain(&tlvlist); + + return ret; +} + +static int hostversions(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + rxcallback_t userfunc; + int vercount; + + vercount = datalen/4; + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, vercount, data); + + return 0; +} + +static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + + if (snac->subtype == 0x0003) + return hostonline(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0005) + return redirect(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0007) + return rateresp(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x000a) + return ratechange(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x000f) + return selfinfo(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0010) + return evilnotify(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0013) + return motd(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0018) + return hostversions(sess, mod, rx, snac, data, datalen); + + return 0; +} + +faim_internal int general_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0x0001; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "general", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; +} diff --git a/src/meta.c b/src/meta.c index 5bde289..55fff2a 100644 --- a/src/meta.c +++ b/src/meta.c @@ -16,17 +16,17 @@ faim_export char *aim_getbuildtime(void) return AIM_BUILDTIME; } -faim_export char *aim_getbuildstring(void) +faim_export int aim_getbuildstring(char *buf, int buflen) { - static char string[100]; - snprintf(string, 99, "%d.%d.%d-%s%s", + snprintf(buf, buflen, "%d.%d.%d-%s%s", FAIM_VERSION_MAJOR, FAIM_VERSION_MINOR, FAIM_VERSION_MINORMINOR, aim_getbuilddate(), aim_getbuildtime()); - return string; + + return 0; } faim_internal void faimdprintf(struct aim_session_t *sess, int dlevel, const char *format, ...) diff --git a/src/misc.c b/src/misc.c index c8f8a80..c8975ef 100644 --- a/src/misc.c +++ b/src/misc.c @@ -818,3 +818,56 @@ faim_export unsigned long aim_icq_setstatus(struct aim_session_t *sess, return(sess->snac_nextid); } + +/* + * Should be generic enough to handle the errors for all families... + * + */ +static int generror(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + int ret = 0; + int error = 0; + rxcallback_t userfunc; + struct aim_snac_t *snac2; + + snac2 = aim_remsnac(sess, snac->id); + + if (datalen) + error = aimutil_get16(data); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, error, snac2?snac2->data:NULL); + + if (snac2) + free(snac2->data); + free(snac2); + + return ret; +} + +static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + + if (snac->subtype == 0x0001) + return generror(sess, mod, rx, snac, data, datalen); + else if ((snac->family == 0xffff) && (snac->subtype == 0xffff)) { + rxcallback_t userfunc; + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx); + } + + return 0; +} + +faim_internal int misc_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0xffff; + mod->version = 0x0000; + mod->flags = AIM_MODFLAG_MULTIFAMILY; + strncpy(mod->name, "misc", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; +} diff --git a/src/rxhandlers.c b/src/rxhandlers.c index 493d040..2f897da 100644 --- a/src/rxhandlers.c +++ b/src/rxhandlers.c @@ -48,7 +48,7 @@ faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst mod->next = (aim_module_t *)sess->modlistv; (aim_module_t *)sess->modlistv = mod; - faimdprintf(sess, 0, "registered module %s (family 0x%04x)\n", mod->name, mod->family); + faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family); return 0; } @@ -487,89 +487,13 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) if ((workingPtr->handled = consumesnac(sess, workingPtr))) continue; - family = aimutil_get16(workingPtr->data); - subtype = aimutil_get16(workingPtr->data+2); - - if (family == 0x0001) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_parse_hostonline(sess, workingPtr); - else if (subtype == 0x0005) - workingPtr->handled = aim_handleredirect_middle(sess, workingPtr); - else if (subtype == 0x0007) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr); - else if (subtype == 0x000a) - workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr); - else if (subtype == 0x000f) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr); - else if (subtype == 0x0010) - workingPtr->handled = aim_parse_evilnotify_middle(sess, workingPtr); - else if (subtype == 0x0013) - workingPtr->handled = aim_parsemotd_middle(sess, workingPtr); - else if (subtype == 0x0018) - workingPtr->handled = aim_parse_hostversions(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0xffff, workingPtr); - - } else if (family == 0x0002) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_locateerr(sess, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr); - else if (subtype == 0x0006) - workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr); - - } else if (family == 0x0003) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); - - } else if (family == 0x0004) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr); - else if (subtype == 0x0005) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr); - else if (subtype == 0x0006) - workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr); - else if (subtype == 0x0007) - workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr); - else if (subtype == 0x000a) - workingPtr->handled = aim_parse_missedcall(sess, workingPtr); - else if (subtype == 0x000c) - workingPtr->handled = aim_parse_msgack_middle(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr); - - } else if (family == 0x000d) { - - if (subtype == 0x0009) - workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr); - - } 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 if (family == 0x0013) { - - faimdprintf(sess, 0, "lalala: 0x%04x/0x%04x\n", family, subtype); - - } else if (family == AIM_CB_FAM_SPECIAL) { - - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); + if (!workingPtr->handled) { + family = aimutil_get16(workingPtr->data); + subtype = aimutil_get16(workingPtr->data+2); + faimdprintf(sess, 1, "warning: unhandled packet %04x/%04x\n", family, subtype); + consumenonsnac(sess, workingPtr, 0xffff, 0xffff); /* last chance! */ + workingPtr->handled = 1; } } } @@ -587,266 +511,6 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) return 0; } -faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command) -{ - rxcallback_t userfunc = NULL; - char sn[MAXSNLEN]; - unsigned short type; - int i = 10+8; /* skip SNAC and cookie */ - int ret = 1; - unsigned char snlen; - - type = aimutil_get16(command->data+i); - i += 2; - - snlen = aimutil_get8(command->data+i); - i++; - - memset(sn, 0, sizeof(sn)); - strncpy(sn, (char *)command->data+i, snlen); - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x000c))) - ret = userfunc(sess, command, type, sn); - - return ret; -} - -/* - * The Rate Limiting System, An Abridged Guide to Nonsense. - * - * OSCAR defines several 'rate classes'. Each class has seperate - * rate limiting properties (limit level, alert level, disconnect - * level, etc), and a set of SNAC family/type pairs associated with - * it. The rate classes, their limiting properties, and the definitions - * of which SNACs are belong to which class, are defined in the - * Rate Response packet at login to each host. - * - * Logically, all rate offenses within one class count against further - * offenses for other SNACs in the same class (ie, sending messages - * too fast will limit the number of user info requests you can send, - * since those two SNACs are in the same rate class). - * - * Since the rate classes are defined dynamically at login, the values - * below may change. But they seem to be fairly constant. - * - * Currently, BOS defines five rate classes, with the commonly used - * members as follows... - * - * Rate class 0x0001: - * - Everything thats not in any of the other classes - * - * Rate class 0x0002: - * - Buddy list add/remove - * - Permit list add/remove - * - Deny list add/remove - * - * Rate class 0x0003: - * - User information requests - * - Outgoing ICBMs - * - * Rate class 0x0004: - * - A few unknowns: 2/9, 2/b, and f/2 - * - * Rate class 0x0005: - * - Chat room create - * - Outgoing chat ICBMs - * - * The only other thing of note is that class 5 (chat) has slightly looser - * limiting properties than class 3 (normal messages). But thats just a - * small bit of trivia for you. - * - * The last thing that needs to be learned about the rate limiting - * system is how the actual numbers relate to the passing of time. This - * seems to be a big mystery. - * - */ -faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command) -{ - rxcallback_t userfunc = NULL; - int ret = 1; - int i; - int code; - unsigned long rateclass, windowsize, clear, alert, limit, disconnect; - unsigned long currentavg, maxavg; - - i = 10; - - code = aimutil_get16(command->data+i); - i += 2; - - rateclass = aimutil_get16(command->data+i); - i += 2; - - windowsize = aimutil_get32(command->data+i); - i += 4; - clear = aimutil_get32(command->data+i); - i += 4; - alert = aimutil_get32(command->data+i); - i += 4; - limit = aimutil_get32(command->data+i); - i += 4; - disconnect = aimutil_get32(command->data+i); - i += 4; - currentavg = aimutil_get32(command->data+i); - i += 4; - maxavg = aimutil_get32(command->data+i); - i += 4; - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x000a))) - ret = userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg); - - return ret; -} - -faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command) -{ - rxcallback_t userfunc = NULL; - int ret = 1; - int i; - unsigned short newevil; - struct aim_userinfo_s userinfo; - - i = 10; - newevil = aimutil_get16(command->data+10); - i += 2; - - memset(&userinfo, 0, sizeof(struct aim_userinfo_s)); - if (command->commandlen-i) - i += aim_extractuserinfo(sess, command->data+i, &userinfo); - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0010))) - ret = userfunc(sess, command, newevil, &userinfo); - - return ret; -} - -faim_internal int aim_parsemotd_middle(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - rxcallback_t userfunc = NULL; - char *msg; - int ret=1; - struct aim_tlvlist_t *tlvlist; - u_short id; - - /* - * Code. - * - * Valid values: - * 1 Mandatory upgrade - * 2 Advisory upgrade - * 3 System bulletin - * 4 Nothing's wrong ("top o the world" -- normal) - * - */ - id = aimutil_get16(command->data+10); - - /* - * TLVs follow - */ - if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12))) - return ret; - - if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) { - aim_freetlvchain(&tlvlist); - return ret; - } - - userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0013); - if (userfunc) - ret = userfunc(sess, command, id, msg); - - aim_freetlvchain(&tlvlist); - free(msg); - - return ret; -} - -faim_internal int aim_parse_hostonline(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - rxcallback_t userfunc = NULL; - int ret = 1; - unsigned short *families = NULL; - int famcount = 0, i; - - famcount = (command->commandlen-10)/2; - if (!(families = malloc(command->commandlen-10))) - return ret; - - for (i = 0; i < famcount; i++) - families[i] = aimutil_get16(command->data+((i*2)+10)); - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0003))) - ret = userfunc(sess, command, famcount, families); - - free(families); - - return ret; -} - -faim_internal int aim_parse_hostversions(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - rxcallback_t userfunc = NULL; - int ret = 1; - int vercount; - - vercount = (command->commandlen-10)/4; - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0018))) - ret = userfunc(sess, command, vercount, command->data+10); - - return ret; -} - -faim_internal int aim_handleredirect_middle(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - int serviceid = 0; - unsigned char *cookie = NULL; - char *ip = NULL; - rxcallback_t userfunc = NULL; - struct aim_tlvlist_t *tlvlist; - int ret = 1; - - tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10); - - if (aim_gettlv(tlvlist, 0x000d, 1)) - serviceid = aim_gettlv16(tlvlist, 0x000d, 1); - if (aim_gettlv(tlvlist, 0x0005, 1)) - ip = aim_gettlv_str(tlvlist, 0x0005, 1); - if (aim_gettlv(tlvlist, 0x0006, 1)) - cookie = aim_gettlv_str(tlvlist, 0x0006, 1); - - if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) { - - /* - * Chat hack. - * - */ - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005))) - ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin, (int)sess->pendingjoinexchange); - free(sess->pendingjoin); - sess->pendingjoin = NULL; - sess->pendingjoinexchange = 0; - } else if (!serviceid || !ip || !cookie) { /* yeep! */ - ret = 1; - } else { - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005))) - ret = userfunc(sess, command, serviceid, ip, cookie); - } - - if (ip) - free(ip); - if (cookie) - free(cookie); - - aim_freetlvchain(&tlvlist); - - return ret; -} - faim_internal int aim_parse_unknown(struct aim_session_t *sess, struct command_rx_struct *command, ...) { @@ -904,32 +568,3 @@ faim_internal int aim_negchan_middle(struct aim_session_t *sess, return ret; } -/* - * aim_parse_generalerrs() - * - * Middle handler for 0x0001 snac of each family. - * - */ -faim_internal int aim_parse_generalerrs(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - unsigned short family; - unsigned short subtype; - int ret = 1; - int error = 0; - rxcallback_t userfunc = NULL; - - family = aimutil_get16(command->data+0); - subtype= aimutil_get16(command->data+2); - - if (command->commandlen > 10) - error = aimutil_get16(command->data+10); - - if ((userfunc = aim_callhandler(sess, command->conn, family, subtype))) - ret = userfunc(sess, command, error); - - return ret; -} - - - diff --git a/src/search.c b/src/search.c index a102412..5b080dd 100644 --- a/src/search.c +++ b/src/search.c @@ -34,7 +34,7 @@ faim_export unsigned long aim_usersearch_address(struct aim_session_t *sess, return sess->snac_nextid; } - +/* XXX can this be integrated with the rest of the error handling? */ static int error(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { int ret = 0; @@ -111,11 +111,6 @@ static int reply(struct aim_session_t *sess, aim_module_t *mod, struct command_r static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); - - if (snac->family != mod->family) - return 0; - if (snac->subtype == 0x0001) return error(sess, mod, rx, snac, data, datalen); else if (snac->subtype == 0x0003) diff --git a/src/stats.c b/src/stats.c index 4f7f741..65dd009 100644 --- a/src/stats.c +++ b/src/stats.c @@ -18,14 +18,7 @@ static int reportinterval(struct aim_session_t *sess, aim_module_t *mod, struct static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); - - if (snac->family != mod->family) - return 0; - - if (snac->subtype == 0x0001) - ; - else if (snac->subtype == 0x0002) + if (snac->subtype == 0x0002) return reportinterval(sess, mod, rx, snac, data, datalen); return 0; diff --git a/utils/faimtest/faimtest.c b/utils/faimtest/faimtest.c index a2976af..96d993d 100644 --- a/utils/faimtest/faimtest.c +++ b/utils/faimtest/faimtest.c @@ -367,7 +367,7 @@ int main(int argc, char **argv) #endif /* _WIN32 */ /* Pass zero as flags if you want blocking connects */ - aim_session_init(&aimsess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 0); + aim_session_init(&aimsess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 1); aim_setdebuggingcb(&aimsess, faimtest_debugcb); /* still needed even if debuglevel = 0 ! */ if(listingpath) { @@ -497,6 +497,26 @@ int faimtest_rateresp(struct aim_session_t *sess, struct command_rx_struct *comm return 1; } +static int faimtest_icbmparaminfo(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + unsigned long defflags, minmsginterval; + unsigned short maxicbmlen, maxsenderwarn, maxrecverwarn, maxchannel; + va_list ap; + + va_start(ap, command); + maxchannel = va_arg(ap, unsigned short); + defflags = va_arg(ap, unsigned long); + maxicbmlen = va_arg(ap, unsigned short); + maxsenderwarn = va_arg(ap, unsigned short); + maxrecverwarn = va_arg(ap, unsigned short); + minmsginterval = va_arg(ap, unsigned long); + va_end(ap); + + dvprintf("ICBM Parameters: maxchannel = %d, default flags = 0x%08lx, max msg len = %d, max sender evil = %f, max reciever evil = %f, min msg interval = %ld\n", maxchannel, defflags, maxicbmlen, ((float)maxsenderwarn)/10.0, ((float)maxrecverwarn)/10.0, minmsginterval); + + return 1; +} + int faimtest_hostversions(struct aim_session_t *sess, struct command_rx_struct *command, ...) { int vercount, i; @@ -726,10 +746,7 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct if (tstconn) aim_conn_kill(sess, &tstconn); return 1; } -#if 0 - aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_CTN, AIM_CB_SPECIAL_DEFAULT, faimtest_parse_unknown, 0); - aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, AIM_CB_SPECIAL_DEFAULT, faimtest_parse_unknown, 0); -#endif + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0); aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); aim_auth_sendcookie(sess, tstconn, cookie); @@ -863,10 +880,9 @@ int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_CTN, AIM_CB_CTN_DEFAULT, faimtest_parse_unknown, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEFAULT, faimtest_parse_unknown, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0); - + + aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0); aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0); aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0); aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0); @@ -1008,6 +1024,8 @@ static int faimtest_handlecmd(struct aim_session_t *sess, struct command_rx_stru aim_getinfo(sess, command->conn, "75784102", AIM_GETINFO_GENERALINFO); aim_getinfo(sess, command->conn, "15853637", AIM_GETINFO_AWAYMESSAGE); + aim_getinfo(sess, command->conn, "midendian", AIM_GETINFO_GENERALINFO); + aim_getinfo(sess, command->conn, "midendian", AIM_GETINFO_AWAYMESSAGE); } else if (!strncmp(tmpstr, "open directim", 13)) { struct aim_conn_t *newconn; @@ -1522,8 +1540,8 @@ int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct * unsigned short reason; va_start(ap, command); - destsn = va_arg(ap, char *); reason = va_arg(ap, int); + destsn = va_arg(ap, char *); va_end(ap); dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason