Mercurial > pidgin.yaz
changeset 1649:3fe5799b7823
[gaim-migrate @ 1659]
Update libfaim.
committer: Tailor Script <tailor@pidgin.im>
author | Adam Fritzler <mid@auk.cx> |
---|---|
date | Tue, 27 Mar 2001 00:51:09 +0000 |
parents | 09445224e2d9 |
children | 566562641cf0 |
files | libfaim/CHANGES libfaim/Makefile.am libfaim/admin.c libfaim/aim.h libfaim/aim_internal.h libfaim/auth.c libfaim/bos.c libfaim/buddylist.c libfaim/chat.c libfaim/chatnav.c libfaim/conn.c libfaim/im.c libfaim/info.c libfaim/login.c libfaim/md5.c libfaim/meta.c libfaim/misc.c libfaim/rxhandlers.c libfaim/search.c libfaim/stats.c src/oscar.c |
diffstat | 21 files changed, 2627 insertions(+), 2382 deletions(-) [+] |
line wrap: on
line diff
--- a/libfaim/CHANGES Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/CHANGES Tue Mar 27 00:51:09 2001 +0000 @@ -1,6 +1,72 @@ No release numbers ------------------ + - Mon Mar 26 16:08:45 PST 2001 + - Why didn't anyone tell me buddy-offgoing wasn't working? + - *** REQUIRES CLIENT CHANGES... buddy-offgoing now passes a userinfo + struct (its now identical to buddy-oncoming) + + - Mon Mar 26 15:57:41 PST 2001 + - Hrmph. + - Debuglevel wasn't getting set properly by aim_session_init + + - 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) + - Add aim_session_kill() + - CLIENTS MUST CALL THIS either in addition to or instead of + aim_logoff(), particularly if you keep lots of sessions open. + (Sessions now contain dynamically allocated memory which must be freed.) + - Oh, and some other stuff... + + - Fri Mar 23 01:45:28 UTC 2001 + - Add AIM_CLIENTINFO_KNOWNGOOD + - Fix a few details in aim_send_login (thanks temas) + - Prevent aim_rxhandlers from being called recursively + - This is something that has been in my PENDING_AIM mailbox for over + a year now. I figured it was trivial enough to throw in. EveryBuddy + wanted it, but I don't remember why. It should never happen anyway. + - Use AIM_CLIENTINFO_KNOWNGOOD + - This lets faimtest log in after today's round of AOL being mean. + + - Fri Mar 16 23:12:58 UTC 2001 + - Remove one level from aim_rxdispatch() + + - Wed Mar 14 20:21:49 UTC 2001 + - Clean up declarations of TLV functions (ie, const) + - Add -o and -O to faimtest (I didn't use your patch, josh) + + - Wed Mar 14 03:11:03 UTC 2001 + - Err...I'll commit before I go home. More faimtest crap. + + - Tue Mar 13 20:23:04 UTC 2001 + - Fiddle with faimtest a bit. + + - Sun Mar 11 06:02:19 UTC 2001 + - Banish socklen_t. + + - Sun Mar 11 05:51:45 UTC 2001 (jbm) + - Split off aim_internal.h + - Add aim_tx_cleanqueue() + - Remove sn from directim callback (use priv) + - Mon Mar 5 01:19:48 UTC 2001 - Fix typo in last CHANGES entry. - Add fix from Eric to keep efence from complaining about malloc(0)
--- a/libfaim/Makefile.am Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/Makefile.am Tue Mar 27 00:51:09 2001 +0000 @@ -3,8 +3,10 @@ EXTRA_DIST = aim.h aim_cbtypes.h aim_internal.h faimconfig.h md5.h README \ CHANGES COPYING BUGS AUTHORS -libfaim_a_SOURCES = adverts.c \ +libfaim_a_SOURCES = admin.c \ + adverts.c \ auth.c \ + bos.c \ buddylist.c \ chat.c \ chatnav.c \ @@ -21,6 +23,7 @@ rxqueue.c \ search.c \ snac.c \ + stats.c \ tlv.c \ txqueue.c \ util.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfaim/admin.c Tue Mar 27 00:51:09 2001 +0000 @@ -0,0 +1,247 @@ + +#define FAIM_INTERNAL +#include <aim.h> + +/* called for both reply and change-reply */ +static int infochange(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; + + /* + * struct { + * unsigned short perms; + * unsigned short tlvcount; + * aim_tlv_t tlvs[tlvcount]; + * } admin_info[n]; + */ + for (i = 0; i < datalen; ) { + int perms, tlvcount; + + perms = aimutil_get16(data+i); + i += 2; + + tlvcount = aimutil_get16(data+i); + i += 2; + + while (tlvcount) { + rxcallback_t userfunc; + struct aim_tlv_t *tlv; + int str = 0; + + if ((aimutil_get16(data+i) == 0x0011) || + (aimutil_get16(data+i) == 0x0004)) + str = 1; + + if (str) + tlv = aim_grabtlvstr(data+i); + else + tlv = aim_grabtlv(data+i); + + /* XXX fix so its only called once for the entire packet */ + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + userfunc(sess, rx, perms, tlv->type, tlv->length, tlv->value, str); + + if (tlv) + i += 2+2+tlv->length; + + if (tlv && tlv->value) + free(tlv->value); + if (tlv) + free(tlv); + + tlvcount--; + } + } + + return 1; +} + +static int accountconfirm(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 status; + + status = aimutil_get16(data); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, status); + + 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) || (snac->subtype == 0x0005)) + return infochange(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0007) + return accountconfirm(sess, mod, rx, snac, data, datalen); + + return 0; +} + +faim_internal int admin_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0x0007; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "admin", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; +} + +faim_export unsigned long aim_auth_clientready(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct aim_tool_version tools[] = { + {0x0001, 0x0003, AIM_TOOL_NEWWIN, 0x0361}, + {0x0007, 0x0001, AIM_TOOL_NEWWIN, 0x0361}, + }; + int i,j; + struct command_tx_struct *newpacket; + int toolcount = sizeof(tools)/sizeof(struct aim_tool_version); + + if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) + return -1; + + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + + for (j = 0; j < toolcount; j++) { + i += aimutil_put16(newpacket->data+i, tools[j].group); + i += aimutil_put16(newpacket->data+i, tools[j].version); + i += aimutil_put16(newpacket->data+i, tools[j].tool); + i += aimutil_put16(newpacket->data+i, tools[j].toolversion); + } + + newpacket->commandlen = i; + newpacket->lock = 0; + + aim_tx_enqueue(sess, newpacket); + + return sess->snac_nextid; +} + +faim_export unsigned long aim_auth_changepasswd(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *new, char *current) +{ + struct command_tx_struct *newpacket; + int i; + + if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+4+strlen(current)+4+strlen(new)))) + return -1; + + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x0007, 0x0004, 0x0000, sess->snac_nextid); + aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + + /* new password TLV t(0002) */ + i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(new), new); + + /* current password TLV t(0012) */ + i += aim_puttlv_str(newpacket->data+i, 0x0012, strlen(current), current); + + aim_tx_enqueue(sess, newpacket); + + return sess->snac_nextid; +} + +faim_export unsigned long aim_auth_setversions(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, 10 + (4*2)))) + return -1; + + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x0001, 0x0017, 0x0000, sess->snac_nextid); + aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); + + i += aimutil_put16(newpacket->data+i, 0x0001); + i += aimutil_put16(newpacket->data+i, 0x0003); + + i += aimutil_put16(newpacket->data+i, 0x0007); + i += aimutil_put16(newpacket->data+i, 0x0001); + + newpacket->commandlen = i; + newpacket->lock = 0; + aim_tx_enqueue(sess, newpacket); + + return sess->snac_nextid; +} + +/* + * Request account confirmation. + * + * This will cause an email to be sent to the address associated with + * the account. By following the instructions in the mail, you can + * get the TRIAL flag removed from your account. + * + */ +faim_export unsigned long aim_auth_reqconfirm(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + return aim_genericreq_n(sess, conn, 0x0007, 0x0006); +} + +/* + * Request a bit of account info. + * + * The only known valid tag is 0x0011 (email address). + * + */ +faim_export unsigned long aim_auth_getinfo(struct aim_session_t *sess, + struct aim_conn_t *conn, + unsigned short info) +{ + struct command_tx_struct *newpacket; + int i; + + if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + 4))) + return -1; + + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x0007, 0x0002, 0x0000, sess->snac_nextid); + aim_cachesnac(sess, 0x0002, 0x0002, 0x0000, NULL, 0); + + i += aimutil_put16(newpacket->data+i, info); + i += aimutil_put16(newpacket->data+i, 0x0000); + + newpacket->commandlen = i; + newpacket->lock = 0; + aim_tx_enqueue(sess, newpacket); + + return sess->snac_nextid; +} + +faim_export unsigned long aim_auth_setemail(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *newemail) +{ + struct command_tx_struct *newpacket; + int i; + + if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+2+strlen(newemail)))) + return -1; + + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x0007, 0x0004, 0x0000, sess->snac_nextid); + aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + + i += aim_puttlv_str(newpacket->data+i, 0x0011, strlen(newemail), newemail); + + aim_tx_enqueue(sess, newpacket); + + return sess->snac_nextid; +}
--- a/libfaim/aim.h Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/aim.h Tue Mar 27 00:51:09 2001 +0000 @@ -169,6 +169,18 @@ long unknown; }; +#define AIM_CLIENTINFO_KNOWNGOOD { \ + "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \ + 0x0003, \ + 0x0005, \ + 0x0686, \ + "us", \ + "en", \ + 0x0004, \ + 0x0000, \ + 0x0000002a, \ +} + #ifndef TRUE #define TRUE 1 #define FALSE 0 @@ -340,6 +352,8 @@ void (*debugcb)(struct aim_session_t *sess, int level, const char *format, va_list va); /* same as faim_debugging_callback_t */ struct aim_msgcookie_t *msgcookies; + + void *modlistv; }; /* Values for sess->flags */ @@ -444,6 +458,7 @@ faim_export int aim_sendconnack(struct aim_session_t *sess, struct aim_conn_t *conn); faim_export int aim_request_login (struct aim_session_t *sess, struct aim_conn_t *conn, char *sn); faim_export int aim_send_login (struct aim_session_t *, struct aim_conn_t *, char *, char *, struct client_info_s *, char *key); +faim_export int aim_encode_password_md5(const char *password, const char *key, unsigned char *digest); faim_export unsigned long aim_sendauthresp(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, int errorcode, char *errorurl, char *bosip, char *cookie, char *email, int regstatus); faim_export int aim_gencookie(unsigned char *buf); faim_export int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn); @@ -483,6 +498,7 @@ typedef void (*faim_debugging_callback_t)(struct aim_session_t *sess, int level, const char *format, va_list va); faim_export int aim_setdebuggingcb(struct aim_session_t *sess, faim_debugging_callback_t); faim_export void aim_session_init(struct aim_session_t *, unsigned long flags, int debuglevel); +faim_export void aim_session_kill(struct aim_session_t *); faim_export void aim_setupproxy(struct aim_session_t *sess, char *server, char *username, char *password); faim_export struct aim_conn_t *aim_getconn_type(struct aim_session_t *, int type); @@ -620,6 +636,9 @@ #define AIM_CAPS_GAMES 0x40 #define AIM_CAPS_SAVESTOCKS 0x80 +faim_export int aim_0002_000b(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn); +faim_export int aim_0001_0020(struct aim_session_t *sess, struct aim_conn_t *conn); + #define AIM_GETINFO_GENERALINFO 0x00001 #define AIM_GETINFO_AWAYMESSAGE 0x00003 @@ -663,7 +682,7 @@ 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); @@ -756,7 +775,7 @@ /* 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 <aim_internal.h>
--- a/libfaim/aim_internal.h Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/aim_internal.h Tue Mar 27 00:51:09 2001 +0000 @@ -7,15 +7,50 @@ #ifndef __AIM_INTERNAL_H__ #define __AIM_INTERNAL_H__ 1 +typedef struct { + unsigned short family; + unsigned short subtype; + unsigned short flags; + unsigned long id; +} aim_modsnac_t; + +#define AIM_MODULENAME_MAXLEN 16 +#define AIM_MODFLAG_MULTIFAMILY 0x0001 +typedef struct aim_module_s { + unsigned short family; + unsigned short flags; + unsigned short version; + char name[AIM_MODULENAME_MAXLEN+1]; + int (*snachandler)(struct aim_session_t *sess, struct aim_module_s *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen); + void (*shutdown)(struct aim_session_t *sess, struct aim_module_s *mod); + void *priv; + struct aim_module_s *next; +} aim_module_t; + +faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst)(struct aim_session_t *, aim_module_t *)); +faim_internal void aim__shutdownmodules(struct aim_session_t *sess); + + +faim_internal int buddylist_modfirst(struct aim_session_t *sess, aim_module_t *mod); +faim_internal int admin_modfirst(struct aim_session_t *sess, aim_module_t *mod); +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 *); faim_internal unsigned long aim_genericreq_s(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype, u_short *); -faim_internal int aim_authkeyparse(struct aim_session_t *sess, struct command_rx_struct *command); 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); @@ -23,10 +58,6 @@ 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_parse_accountconfirm(struct aim_session_t *sess, struct command_rx_struct *command); -faim_internal int aim_parse_infochange(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); @@ -58,11 +89,7 @@ faim_internal int aim_listenestablish(u_short); faim_internal int aim_tx_destroy(struct command_tx_struct *); -faim_internal int aim_authparse(struct aim_session_t *, struct command_rx_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 @@ -79,17 +106,7 @@ 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_bosrights(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); @@ -104,23 +121,9 @@ 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_parse_oncoming_middle(struct aim_session_t *, struct command_rx_struct *); -faim_internal int aim_parse_offgoing_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_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...); - -faim_internal unsigned long aim_parse_searcherror(struct aim_session_t *, struct command_rx_struct *); -faim_internal unsigned long aim_parse_searchreply(struct aim_session_t *, struct command_rx_struct *); 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, ...);
--- a/libfaim/auth.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/auth.c Tue Mar 27 00:51:09 2001 +0000 @@ -30,156 +30,195 @@ return aim_tx_enqueue(sess, newpacket); } -faim_export unsigned long aim_auth_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +/* + * This is sent back as a general response to the login command. + * It can be either an error or a success, depending on the + * precense of certain TLVs. + * + * The client should check the value passed as errorcode. If + * its nonzero, there was an error. + * + */ +static int parse(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_tool_version tools[] = { - {0x0001, 0x0003, AIM_TOOL_NEWWIN, 0x0361}, - {0x0007, 0x0001, AIM_TOOL_NEWWIN, 0x0361}, - }; - int i,j; - struct command_tx_struct *newpacket; - int toolcount = sizeof(tools)/sizeof(struct aim_tool_version); + struct aim_tlvlist_t *tlvlist; + int ret = 0; + rxcallback_t userfunc; + char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL; + unsigned char *cookie = NULL; + int errorcode = 0, regstatus = 0; + int latestbuild = 0, latestbetabuild = 0; + char *latestrelease = NULL, *latestbeta = NULL; + char *latestreleaseurl = NULL, *latestbetaurl = NULL; + char *latestreleaseinfo = NULL, *latestbetainfo = NULL; + + /* + * Read block of TLVs. All further data is derived + * from what is parsed here. + * + */ + tlvlist = aim_readtlvchain(data, datalen); - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) - return -1; - - newpacket->lock = 1; + /* + * No matter what, we should have a screen name. + */ + memset(sess->sn, 0, sizeof(sess->sn)); + if (aim_gettlv(tlvlist, 0x0001, 1)) { + sn = aim_gettlv_str(tlvlist, 0x0001, 1); + strncpy(sess->sn, sn, sizeof(sess->sn)); + } - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + /* + * Check for an error code. If so, we should also + * have an error url. + */ + if (aim_gettlv(tlvlist, 0x0008, 1)) + errorcode = aim_gettlv16(tlvlist, 0x0008, 1); + if (aim_gettlv(tlvlist, 0x0004, 1)) + errurl = aim_gettlv_str(tlvlist, 0x0004, 1); - for (j = 0; j < toolcount; j++) { - i += aimutil_put16(newpacket->data+i, tools[j].group); - i += aimutil_put16(newpacket->data+i, tools[j].version); - i += aimutil_put16(newpacket->data+i, tools[j].tool); - i += aimutil_put16(newpacket->data+i, tools[j].toolversion); + /* + * BOS server address. + */ + if (aim_gettlv(tlvlist, 0x0005, 1)) + bosip = aim_gettlv_str(tlvlist, 0x0005, 1); + + /* + * Authorization cookie. + */ + if (aim_gettlv(tlvlist, 0x0006, 1)) { + struct aim_tlv_t *tmptlv; + + tmptlv = aim_gettlv(tlvlist, 0x0006, 1); + + if ((cookie = malloc(tmptlv->length))) + memcpy(cookie, tmptlv->value, tmptlv->length); } - newpacket->commandlen = i; - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; -} + /* + * The email address attached to this account + * Not available for ICQ logins. + */ + if (aim_gettlv(tlvlist, 0x0011, 1)) + email = aim_gettlv_str(tlvlist, 0x0011, 1); -faim_export unsigned long aim_auth_changepasswd(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *new, char *current) -{ - struct command_tx_struct *newpacket; - int i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+4+strlen(current)+4+strlen(new)))) - return -1; + /* + * The registration status. (Not real sure what it means.) + * Not available for ICQ logins. + * + * 1 = No disclosure + * 2 = Limited disclosure + * 3 = Full disclosure + * + * This has to do with whether your email address is available + * to other users or not. AFAIK, this feature is no longer used. + * + */ + if (aim_gettlv(tlvlist, 0x0013, 1)) + regstatus = aim_gettlv16(tlvlist, 0x0013, 1); - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0007, 0x0004, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); - - /* new password TLV t(0002) */ - i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(new), new); - - /* current password TLV t(0012) */ - i += aim_puttlv_str(newpacket->data+i, 0x0012, strlen(current), current); + if (aim_gettlv(tlvlist, 0x0040, 1)) + latestbetabuild = aim_gettlv32(tlvlist, 0x0040, 1); + if (aim_gettlv(tlvlist, 0x0041, 1)) + latestbetaurl = aim_gettlv_str(tlvlist, 0x0041, 1); + if (aim_gettlv(tlvlist, 0x0042, 1)) + latestbetainfo = aim_gettlv_str(tlvlist, 0x0042, 1); + if (aim_gettlv(tlvlist, 0x0043, 1)) + latestbeta = aim_gettlv_str(tlvlist, 0x0043, 1); + if (aim_gettlv(tlvlist, 0x0048, 1)) + ; /* no idea what this is */ - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; -} + if (aim_gettlv(tlvlist, 0x0044, 1)) + latestbuild = aim_gettlv32(tlvlist, 0x0044, 1); + if (aim_gettlv(tlvlist, 0x0045, 1)) + latestreleaseurl = aim_gettlv_str(tlvlist, 0x0045, 1); + if (aim_gettlv(tlvlist, 0x0046, 1)) + latestreleaseinfo = aim_gettlv_str(tlvlist, 0x0046, 1); + if (aim_gettlv(tlvlist, 0x0047, 1)) + latestrelease = aim_gettlv_str(tlvlist, 0x0047, 1); + if (aim_gettlv(tlvlist, 0x0049, 1)) + ; /* no idea what this is */ -faim_export unsigned long aim_auth_setversions(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, 10 + (4*2)))) - return -1; + if ((userfunc = aim_callhandler(sess, rx->conn, snac?snac->family:0x0017, snac?snac->subtype:0x0003))) + ret = userfunc(sess, rx, sn, errorcode, errurl, regstatus, email, bosip, cookie, latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo, latestbeta, latestbetabuild, latestbetaurl, latestbetainfo); + - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0017, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); - - i += aimutil_put16(newpacket->data+i, 0x0001); - i += aimutil_put16(newpacket->data+i, 0x0003); + if (sn) + free(sn); + if (bosip) + free(bosip); + if (errurl) + free(errurl); + if (email) + free(email); + if (cookie) + free(cookie); + if (latestrelease) + free(latestrelease); + if (latestreleaseurl) + free(latestreleaseurl); + if (latestbeta) + free(latestbeta); + if (latestbetaurl) + free(latestbetaurl); + if (latestreleaseinfo) + free(latestreleaseinfo); + if (latestbetainfo) + free(latestbetainfo); - i += aimutil_put16(newpacket->data+i, 0x0007); - i += aimutil_put16(newpacket->data+i, 0x0001); + aim_freetlvchain(&tlvlist); - newpacket->commandlen = i; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + return ret; } /* - * Request account confirmation. + * Middle handler for 0017/0007 SNACs. Contains the auth key prefixed + * by only its length in a two byte word. * - * This will cause an email to be sent to the address associated with - * the account. By following the instructions in the mail, you can - * get the TRIAL flag removed from your account. + * Calls the client, which should then use the value to call aim_send_login. * */ -faim_export unsigned long aim_auth_reqconfirm(struct aim_session_t *sess, - struct aim_conn_t *conn) +static int keyparse(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { - return aim_genericreq_n(sess, conn, 0x0007, 0x0006); + unsigned char *key; + int keylen; + int ret = 1; + rxcallback_t userfunc; + + keylen = aimutil_get16(data); + if (!(key = malloc(keylen+1))) + return ret; + memcpy(key, data+2, keylen); + key[keylen] = '\0'; + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, (char *)key); + + free(key); + + return ret; } -/* - * Request a bit of account info. - * - * The only known valid tag is 0x0011 (email address). - * - */ -faim_export unsigned long aim_auth_getinfo(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned short info) +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 command_tx_struct *newpacket; - int i; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + 4))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0007, 0x0002, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0002, 0x0002, 0x0000, NULL, 0); + 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); - i += aimutil_put16(newpacket->data+i, info); - i += aimutil_put16(newpacket->data+i, 0x0000); - - newpacket->commandlen = i; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + return 0; } -faim_export unsigned long aim_auth_setemail(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *newemail) +faim_internal int auth_modfirst(struct aim_session_t *sess, aim_module_t *mod) { - struct command_tx_struct *newpacket; - int i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+2+strlen(newemail)))) - return -1; - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0007, 0x0004, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + mod->family = 0x0017; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "auth", sizeof(mod->name)); + mod->snachandler = snachandler; - i += aim_puttlv_str(newpacket->data+i, 0x0011, strlen(newemail), newemail); - - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + return 0; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfaim/bos.c Tue Mar 27 00:51:09 2001 +0000 @@ -0,0 +1,103 @@ + +#define FAIM_INTERNAL +#include <aim.h> + +/* + * aim_bos_setgroupperm(mask) + * + * Set group permisson mask. Normally 0x1f (all classes). + * + * The group permission mask allows you to keep users of a certain + * class or classes from talking to you. The mask should be + * a bitwise OR of all the user classes you want to see you. + * + */ +faim_export unsigned long aim_bos_setgroupperm(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_long mask) +{ + return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask); +} + +faim_export int aim_0001_0020(struct aim_session_t *sess, struct aim_conn_t *conn) +{ + struct command_tx_struct *tx; + int i = 0; + + if (!sess || !conn) + return 0; + + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+16))) + return -1; + + tx->lock = 1; + + /* Hummm.... */ + i = aim_putsnac(tx->data, 0x0001, 0x0020, 0x0000, sess->snac_nextid++); + i += aimutil_put16(tx->data+i, 0x0010); + i += aimutil_put32(tx->data+i, 0x469bf5e7); + i += aimutil_put32(tx->data+i, 0x01a19b28); + i += aimutil_put32(tx->data+i, 0x54c59ea6); + i += aimutil_put32(tx->data+i, 0x88eae54a); + + tx->commandlen = i; + tx->lock = 0; + aim_tx_enqueue(sess, tx); + + 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) +{ + rxcallback_t userfunc; + int ret = 0; + struct aim_tlvlist_t *tlvlist; + unsigned short maxpermits = 0, maxdenies = 0; + + /* + * TLVs follow + */ + if (!(tlvlist = aim_readtlvchain(data, datalen))) + return 0; + + /* + * TLV type 0x0001: Maximum number of buddies on permit list. + */ + if (aim_gettlv(tlvlist, 0x0001, 1)) + maxpermits = aim_gettlv16(tlvlist, 0x0001, 1); + + /* + * TLV type 0x0002: Maximum number of buddies on deny list. + * + */ + if (aim_gettlv(tlvlist, 0x0002, 1)) + maxdenies = aim_gettlv16(tlvlist, 0x0002, 1); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, maxpermits, maxdenies); + + aim_freetlvchain(&tlvlist); + + 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); + + return 0; +} + +faim_internal int bos_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0x0009; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "bos", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; +}
--- a/libfaim/buddylist.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/buddylist.c Tue Mar 27 00:51:09 2001 +0000 @@ -3,6 +3,87 @@ #include <aim.h> /* + * Oncoming Buddy notifications contain a subset of the + * user information structure. Its close enough to run + * through aim_extractuserinfo() however. + * + * Although the offgoing notification contains no information, + * it is still in a format parsable by extractuserinfo. + * + */ +static int buddychange(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; + + aim_extractuserinfo(sess, data, &userinfo); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, &userinfo); + + 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) +{ + rxcallback_t userfunc; + struct aim_tlvlist_t *tlvlist; + unsigned short maxbuddies = 0, maxwatchers = 0; + int ret = 0; + + /* + * TLVs follow + */ + if (!(tlvlist = aim_readtlvchain(data, datalen))) + return 0; + + /* + * TLV type 0x0001: Maximum number of buddies. + */ + if (aim_gettlv(tlvlist, 0x0001, 1)) + maxbuddies = aim_gettlv16(tlvlist, 0x0001, 1); + + /* + * TLV type 0x0002: Maximum number of watchers. + * + * XXX: what the hell is a watcher? + * + */ + if (aim_gettlv(tlvlist, 0x0002, 1)) + maxwatchers = aim_gettlv16(tlvlist, 0x0002, 1); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, maxbuddies, maxwatchers); + + aim_freetlvchain(&tlvlist); + + 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 == 0x000b) || (snac->subtype == 0x000c)) + return buddychange(sess, mod, rx, snac, data, datalen); + + return 0; +} + +faim_internal int buddylist_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0x0003; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "buddylist", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; +} + +/* * aim_add_buddy() * * Adds a single buddy to your buddy list after login. @@ -68,39 +149,3 @@ return sess->snac_nextid; } -faim_internal int aim_parse_buddyrights(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - rxcallback_t userfunc = NULL; - int ret=1; - struct aim_tlvlist_t *tlvlist; - unsigned short maxbuddies = 0, maxwatchers = 0; - - /* - * TLVs follow - */ - if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10))) - return ret; - - /* - * TLV type 0x0001: Maximum number of buddies. - */ - if (aim_gettlv(tlvlist, 0x0001, 1)) - maxbuddies = aim_gettlv16(tlvlist, 0x0001, 1); - - /* - * TLV type 0x0002: Maximum number of watchers. - * - * XXX: what the hell is a watcher? - * - */ - if (aim_gettlv(tlvlist, 0x0002, 1)) - maxwatchers = aim_gettlv16(tlvlist, 0x0002, 1); - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0003, 0x0003))) - ret = userfunc(sess, command, maxbuddies, maxwatchers); - - aim_freetlvchain(&tlvlist); - - return ret; -}
--- a/libfaim/chat.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/chat.c Tue Mar 27 00:51:09 2001 +0000 @@ -208,319 +208,6 @@ return i; } - -/* - * General room information. Lots of stuff. - * - * Values I know are in here but I havent attached - * them to any of the 'Unknown's: - * - Language (English) - * - * SNAC 000e/0002 - */ -faim_internal int aim_chat_parse_infoupdate(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - struct aim_userinfo_s *userinfo = NULL; - rxcallback_t userfunc=NULL; - int ret = 1, i = 0; - int usercount = 0; - u_char detaillevel = 0; - char *roomname = NULL; - struct aim_chat_roominfo roominfo; - u_short tlvcount = 0; - struct aim_tlvlist_t *tlvlist; - char *roomdesc = NULL; - unsigned short unknown_c9 = 0; - unsigned long creationtime = 0; - unsigned short maxmsglen = 0; - unsigned short unknown_d2 = 0, unknown_d5 = 0; - - i = 10; - i += aim_chat_readroominfo(command->data+i, &roominfo); - - detaillevel = aimutil_get8(command->data+i); - i++; - - if (detaillevel != 0x02) { - if (detaillevel == 0x01) - faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level 1 not supported\n"); - else - faimdprintf(sess, 0, "faim: chat_roomupdateinfo: unknown detail level %d\n", detaillevel); - return 1; - } - - tlvcount = aimutil_get16(command->data+i); - i += 2; - - /* - * Everything else are TLVs. - */ - tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); - - /* - * TLV type 0x006a is the room name in Human Readable Form. - */ - if (aim_gettlv(tlvlist, 0x006a, 1)) - roomname = aim_gettlv_str(tlvlist, 0x006a, 1); - - /* - * Type 0x006f: Number of occupants. - */ - if (aim_gettlv(tlvlist, 0x006f, 1)) - usercount = aim_gettlv16(tlvlist, 0x006f, 1); - - /* - * Type 0x0073: Occupant list. - */ - if (aim_gettlv(tlvlist, 0x0073, 1)) { - int curoccupant = 0; - struct aim_tlv_t *tmptlv; - - tmptlv = aim_gettlv(tlvlist, 0x0073, 1); - - /* Allocate enough userinfo structs for all occupants */ - userinfo = calloc(usercount, sizeof(struct aim_userinfo_s)); - - i = 0; - while (curoccupant < usercount) - i += aim_extractuserinfo(sess, tmptlv->value+i, &userinfo[curoccupant++]); - } - - /* - * Type 0x00c9: Unknown. (2 bytes) - */ - if (aim_gettlv(tlvlist, 0x00c9, 1)) - unknown_c9 = aim_gettlv16(tlvlist, 0x00c9, 1); - - /* - * Type 0x00ca: Creation time (4 bytes) - */ - if (aim_gettlv(tlvlist, 0x00ca, 1)) - creationtime = aim_gettlv32(tlvlist, 0x00ca, 1); - - /* - * Type 0x00d1: Maximum Message Length - */ - if (aim_gettlv(tlvlist, 0x00d1, 1)) - maxmsglen = aim_gettlv16(tlvlist, 0x00d1, 1); - - /* - * Type 0x00d2: Unknown. (2 bytes) - */ - if (aim_gettlv(tlvlist, 0x00d2, 1)) - unknown_d2 = aim_gettlv16(tlvlist, 0x00d2, 1); - - /* - * Type 0x00d3: Room Description - */ - if (aim_gettlv(tlvlist, 0x00d3, 1)) - roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1); - - /* - * Type 0x00d5: Unknown. (1 byte) - */ - if (aim_gettlv(tlvlist, 0x00d5, 1)) - unknown_d5 = aim_gettlv8(tlvlist, 0x00d5, 1); - - - if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE))) { - ret = userfunc(sess, - command, - &roominfo, - roomname, - usercount, - userinfo, - roomdesc, - unknown_c9, - creationtime, - maxmsglen, - unknown_d2, - unknown_d5); - } - free(roominfo.name); - free(userinfo); - free(roomname); - free(roomdesc); - aim_freetlvchain(&tlvlist); - - return ret; -} - -faim_internal int aim_chat_parse_joined(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - struct aim_userinfo_s *userinfo = NULL; - rxcallback_t userfunc=NULL; - int i = 10, curcount = 0, ret = 1; - - while (i < command->commandlen) { - curcount++; - userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); - i += aim_extractuserinfo(sess, command->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); - } - - 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 - * code as channel 0x0003, however, since only the start - * would be the same, we might as well do it here. - * - * General outline of this SNAC: - * snac - * cookie - * channel id - * tlvlist - * unknown - * source user info - * name - * evility - * userinfo tlvs - * online time - * etc - * message metatlv - * message tlv - * message string - * possibly others - * - */ -faim_internal int aim_chat_parse_incoming(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - struct aim_userinfo_s userinfo; - rxcallback_t userfunc=NULL; - int ret = 1, i = 0, z = 0; - unsigned char cookie[8]; - int channel; - struct aim_tlvlist_t *outerlist; - char *msg = NULL; - struct aim_msgcookie_t *ck; - - 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]; - - if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) { - if (ck->data) - free(ck->data); - free(ck); - } - - /* - * Channel ID - * - * Channels 1 and 2 are implemented in the normal ICBM - * parser. - * - * We only do channel 3 here. - * - */ - channel = aimutil_get16(command->data+i); - i += 2; - - if (channel != 0x0003) { - faimdprintf(sess, 0, "faim: chat_incoming: unknown channel! (0x%04x)\n", channel); - return 1; - } - - /* - * Start parsing TLVs right away. - */ - outerlist = aim_readtlvchain(command->data+i, command->commandlen-i); - - /* - * Type 0x0003: Source User Information - */ - if (aim_gettlv(outerlist, 0x0003, 1)) { - struct aim_tlv_t *userinfotlv; - - userinfotlv = aim_gettlv(outerlist, 0x0003, 1); - aim_extractuserinfo(sess, userinfotlv->value, &userinfo); - } - - /* - * Type 0x0001: Unknown. - */ - if (aim_gettlv(outerlist, 0x0001, 1)) - ; - - /* - * Type 0x0005: Message Block. Conains more TLVs. - */ - if (aim_gettlv(outerlist, 0x0005, 1)) - { - struct aim_tlvlist_t *innerlist; - struct aim_tlv_t *msgblock; - - msgblock = aim_gettlv(outerlist, 0x0005, 1); - innerlist = aim_readtlvchain(msgblock->value, msgblock->length); - - /* - * Type 0x0001: Message. - */ - if (aim_gettlv(innerlist, 0x0001, 1)) - msg = aim_gettlv_str(innerlist, 0x0001, 1); - - aim_freetlvchain(&innerlist); - } - - userfunc = aim_callhandler(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) { @@ -679,3 +366,299 @@ return (sess->snac_nextid++); } + +/* + * General room information. Lots of stuff. + * + * Values I know are in here but I havent attached + * them to any of the 'Unknown's: + * - Language (English) + * + * SNAC 000e/0002 + */ +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 = 0, i = 0; + int usercount = 0; + unsigned char detaillevel = 0; + char *roomname = NULL; + struct aim_chat_roominfo roominfo; + unsigned short tlvcount = 0; + struct aim_tlvlist_t *tlvlist; + char *roomdesc = NULL; + unsigned short unknown_c9 = 0; + unsigned long creationtime = 0; + unsigned short maxmsglen = 0; + unsigned short unknown_d2 = 0, unknown_d5 = 0; + + i += aim_chat_readroominfo(data+i, &roominfo); + + detaillevel = aimutil_get8(data+i); + i++; + + if (detaillevel != 0x02) { + if (detaillevel == 0x01) + faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level 1 not supported\n"); + else + faimdprintf(sess, 0, "faim: chat_roomupdateinfo: unknown detail level %d\n", detaillevel); + return 1; + } + + tlvcount = aimutil_get16(data+i); + i += 2; + + /* + * Everything else are TLVs. + */ + 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); + + /* + * Type 0x006f: Number of occupants. + */ + if (aim_gettlv(tlvlist, 0x006f, 1)) + usercount = aim_gettlv16(tlvlist, 0x006f, 1); + + /* + * Type 0x0073: Occupant list. + */ + if (aim_gettlv(tlvlist, 0x0073, 1)) { + int curoccupant = 0; + struct aim_tlv_t *tmptlv; + + tmptlv = aim_gettlv(tlvlist, 0x0073, 1); + + /* Allocate enough userinfo structs for all occupants */ + userinfo = calloc(usercount, sizeof(struct aim_userinfo_s)); + + i = 0; + while (curoccupant < usercount) + i += aim_extractuserinfo(sess, tmptlv->value+i, &userinfo[curoccupant++]); + } + + /* + * Type 0x00c9: Unknown. (2 bytes) + */ + if (aim_gettlv(tlvlist, 0x00c9, 1)) + unknown_c9 = aim_gettlv16(tlvlist, 0x00c9, 1); + + /* + * Type 0x00ca: Creation time (4 bytes) + */ + if (aim_gettlv(tlvlist, 0x00ca, 1)) + creationtime = aim_gettlv32(tlvlist, 0x00ca, 1); + + /* + * Type 0x00d1: Maximum Message Length + */ + if (aim_gettlv(tlvlist, 0x00d1, 1)) + maxmsglen = aim_gettlv16(tlvlist, 0x00d1, 1); + + /* + * Type 0x00d2: Unknown. (2 bytes) + */ + if (aim_gettlv(tlvlist, 0x00d2, 1)) + unknown_d2 = aim_gettlv16(tlvlist, 0x00d2, 1); + + /* + * Type 0x00d3: Room Description + */ + if (aim_gettlv(tlvlist, 0x00d3, 1)) + roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1); + + /* + * Type 0x00d5: Unknown. (1 byte) + */ + if (aim_gettlv(tlvlist, 0x00d5, 1)) + unknown_d5 = aim_gettlv8(tlvlist, 0x00d5, 1); + + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { + ret = userfunc(sess, + rx, + &roominfo, + roomname, + usercount, + userinfo, + roomdesc, + unknown_c9, + creationtime, + maxmsglen, + unknown_d2, + unknown_d5); + } + + free(roominfo.name); + free(userinfo); + free(roomname); + free(roomdesc); + aim_freetlvchain(&tlvlist); + + return ret; +} + +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; + int i = 0, curcount = 0, ret = 0; + + while (i < datalen) { + curcount++; + userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); + i += aim_extractuserinfo(sess, data+i, &userinfo[curcount-1]); + } + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, curcount, userinfo); + + free(userinfo); + + return ret; +} + +/* + * We could probably include this in the normal ICBM parsing + * code as channel 0x0003, however, since only the start + * would be the same, we might as well do it here. + * + * General outline of this SNAC: + * snac + * cookie + * channel id + * tlvlist + * unknown + * source user info + * name + * evility + * userinfo tlvs + * online time + * etc + * message metatlv + * message tlv + * message string + * possibly others + * + */ +static int 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 = 0, i = 0; + unsigned char cookie[8]; + int channel; + struct aim_tlvlist_t *outerlist; + char *msg = NULL; + struct aim_msgcookie_t *ck; + + memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); + + /* + * ICBM Cookie. Cache it. + */ + memcpy(cookie, data, 8); + i += 8; + + if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) { + if (ck->data) + free(ck->data); + free(ck); + } + + /* + * Channel ID + * + * Channels 1 and 2 are implemented in the normal ICBM + * parser. + * + * We only do channel 3 here. + * + */ + channel = aimutil_get16(data+i); + i += 2; + + if (channel != 0x0003) { + faimdprintf(sess, 0, "faim: chat_incoming: unknown channel! (0x%04x)\n", channel); + return 0; + } + + /* + * Start parsing TLVs right away. + */ + outerlist = aim_readtlvchain(data+8+2, datalen-8-2); + + /* + * Type 0x0003: Source User Information + */ + if (aim_gettlv(outerlist, 0x0003, 1)) { + struct aim_tlv_t *userinfotlv; + + userinfotlv = aim_gettlv(outerlist, 0x0003, 1); + aim_extractuserinfo(sess, userinfotlv->value, &userinfo); + } + + /* + * Type 0x0001: Unknown. + */ + if (aim_gettlv(outerlist, 0x0001, 1)) + ; + + /* + * Type 0x0005: Message Block. Conains more TLVs. + */ + if (aim_gettlv(outerlist, 0x0005, 1)) { + struct aim_tlvlist_t *innerlist; + struct aim_tlv_t *msgblock; + + msgblock = aim_gettlv(outerlist, 0x0005, 1); + innerlist = aim_readtlvchain(msgblock->value, msgblock->length); + + /* + * Type 0x0001: Message. + */ + if (aim_gettlv(innerlist, 0x0001, 1)) + msg = aim_gettlv_str(innerlist, 0x0001, 1); + + aim_freetlvchain(&innerlist); + } + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, &userinfo, msg); + + free(msg); + aim_freetlvchain(&outerlist); + + 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 == 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); + + return 0; +} + +faim_internal int chat_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0x000e; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "chat", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; +}
--- a/libfaim/chatnav.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/chatnav.c Tue Mar 27 00:51:09 2001 +0000 @@ -51,341 +51,6 @@ 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 @@ 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; +}
--- a/libfaim/conn.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/conn.c Tue Mar 27 00:51:09 2001 +0000 @@ -722,6 +722,11 @@ return; } +static void defaultdebugcb(struct aim_session_t *sess, int level, const char *format, va_list va) +{ + vfprintf(stderr, format, va); +} + /** * aim_session_init - Initializes a session structure * @sess: Session to initialize @@ -747,8 +752,10 @@ sess->snac_nextid = 0x00000001; sess->flags = 0; - sess->debug = 0; - sess->debugcb = NULL; + sess->debug = debuglevel; + sess->debugcb = defaultdebugcb; + + sess->modlistv = NULL; /* * Default to SNAC login unless XORLOGIN is explicitly set. @@ -763,6 +770,39 @@ */ aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL); + + /* + * 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; +} + +/** + * aim_session_kill - Deallocate a session + * @sess: Session to kill + * + * + */ +faim_export void aim_session_kill(struct aim_session_t *sess) +{ + + aim_logoff(sess); + + aim__shutdownmodules(sess); + return; }
--- a/libfaim/im.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/im.c Tue Mar 27 00:51:09 2001 +0000 @@ -185,11 +185,10 @@ 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 @@ 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 @@ 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 @@ 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 <warmenhoven@linux.com> (of GAIM) + * for pointing some of this out to me. In fact, a lot of + * the client-to-client info comes from the work of the GAIM + * developers. Thanks! + * + * Read off one capability string and we should have it ID'd. + * + */ + 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 @@ * 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 @@ * connection negotiations come from. * */ - channel = aimutil_get16(command->data+i); + channel = aimutil_get16(data+i); i += 2; /* @@ -328,468 +709,28 @@ * 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 <warmenhoven@linux.com> (of GAIM) - * for pointing some of this out to me. In fact, a lot of - * the client-to-client info comes from the work of the GAIM - * developers. Thanks! - * - * Read off one capability string and we should have it ID'd. - * - */ - 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 @@ 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 @@ 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; + + defflags = aimutil_get32(data+i); + i += 4; - 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; + maxicbmlen = aimutil_get16(data+i); + i += 2; - reason = aimutil_get16(command->data+10); + maxsenderwarn = 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); - } + maxrecverwarn = aimutil_get16(data+i); + i += 2; - return ret; + minmsginterval = aimutil_get32(data+i); + i += 4; + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, maxchannel, defflags, maxicbmlen, maxsenderwarn, maxrecverwarn, minmsginterval); + + return 0; } - -faim_internal int aim_parse_missedcall(struct aim_session_t *sess, - struct command_rx_struct *command) +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 @@ /* * 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; + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, channel, &userinfo, nummissed, reason); + + 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; - /* - * Call client. - */ - userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x000a); - if (userfunc) - ret = userfunc(sess, command, channel, &userinfo, nummissed, reason); - else - ret = 0; - - return ret; + 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; +}
--- a/libfaim/info.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/info.c Tue Mar 27 00:51:09 2001 +0000 @@ -14,17 +14,21 @@ 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 @@ 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; } /* @@ -462,136 +422,6 @@ } /* - * Oncoming Buddy notifications contain a subset of the - * user information structure. Its close enough to run - * through aim_extractuserinfo() however. - * - */ -faim_internal int aim_parse_oncoming_middle(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - struct aim_userinfo_s userinfo; - u_int i = 0; - rxcallback_t userfunc=NULL; - - i = 10; - i += aim_extractuserinfo(sess, command->data+i, &userinfo); - - userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING); - if (userfunc) - i = userfunc(sess, command, &userinfo); - - return 1; -} - -/* - * Offgoing Buddy notifications contain no useful - * information other than the name it applies to. - * - */ -faim_internal int aim_parse_offgoing_middle(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - char sn[MAXSNLEN+1]; - u_int i = 0; - rxcallback_t userfunc=NULL; - - strncpy(sn, (char *)command->data+11, (int)command->data[10]); - sn[(int)command->data[10]] = '\0'; - - userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING); - if (userfunc) - i = userfunc(sess, command, sn); - - return 1; -} - -/* - * 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() */ faim_internal int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info) @@ -696,3 +526,127 @@ return 0; } +faim_export int aim_0002_000b(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn) +{ + struct command_tx_struct *tx; + int i = 0; + + if (!sess || !conn || !sn) + return 0; + + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+1+strlen(sn)))) + return -1; + + tx->lock = 1; + + i = aim_putsnac(tx->data, 0x0002, 0x000b, 0x0000, sess->snac_nextid); + i += aimutil_put8(tx->data+i, strlen(sn)); + i += aimutil_putstr(tx->data+i, sn, strlen(sn)); + + tx->commandlen = i; + tx->lock = 0; + aim_tx_enqueue(sess, tx); + + 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; +}
--- a/libfaim/login.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/login.c Tue Mar 27 00:51:09 2001 +0000 @@ -10,7 +10,6 @@ #include "md5.h" -static int aim_encode_password_md5(const char *password, const char *key, md5_byte_t *digest); static int aim_encode_password(const char *password, unsigned char *encoded); faim_export int aim_sendconnack(struct aim_session_t *sess, @@ -137,6 +136,16 @@ * lang = "en" * country = "us" * unknown4a = 0x01 + * + * Latest WinAIM that libfaim can emulate without server-side buddylists: + * clientstring = "AOL Instant Messenger (SM), version 3.5.1670/WIN32" + * major2 = 0x0004 + * major = 0x0003 + * minor = 0x0005 + * minor2 = 0x0000 + * build = 0x0686 + * unknown =0x0000002a + * */ faim_export int aim_send_login (struct aim_session_t *sess, struct aim_conn_t *conn, @@ -167,7 +176,7 @@ curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn); if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { - md5_byte_t digest[16]; + unsigned char digest[16]; aim_encode_password_md5(password, key, digest); curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0025, 16, (char *)digest); @@ -180,20 +189,16 @@ free(password_encoded); } - /* XXX is clientstring required by oscar? */ - if (strlen(clientinfo->clientstring)) - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring); + curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring); if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { + curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, (unsigned short)clientinfo->major2); curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, (unsigned short)clientinfo->major); curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, (unsigned short)clientinfo->minor); curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, (unsigned short)clientinfo->minor2); curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, (unsigned short)clientinfo->build); - curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, clientinfo->unknown); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015); - curbyte += aim_puttlv_8(newpacket->data+curbyte, 0x004a, 0x00); } else { /* Use very specific version numbers, to further indicate the hack. */ curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, 0x010a); @@ -204,23 +209,21 @@ curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, 0x00000055); } - if (strlen(clientinfo->country)) - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000e, strlen(clientinfo->country), clientinfo->country); - else - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000e, 2, "us"); + curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000e, strlen(clientinfo->country), clientinfo->country); + curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000f, strlen(clientinfo->lang), clientinfo->lang); + + if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { + curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, clientinfo->unknown); + curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015); + } - if (strlen(clientinfo->lang)) - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000f, strlen(clientinfo->lang), clientinfo->lang); - else - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000f, 2, "en"); - newpacket->commandlen = curbyte; newpacket->lock = 0; return aim_tx_enqueue(sess, newpacket); } -static int aim_encode_password_md5(const char *password, const char *key, md5_byte_t *digest) +faim_export int aim_encode_password_md5(const char *password, const char *key, unsigned char *digest) { md5_state_t state; @@ -275,182 +278,6 @@ } /* - * This is sent back as a general response to the login command. - * It can be either an error or a success, depending on the - * precense of certain TLVs. - * - * The client should check the value passed as errorcode. If - * its nonzero, there was an error. - * - */ -faim_internal int aim_authparse(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - struct aim_tlvlist_t *tlvlist; - int ret = 1; - rxcallback_t userfunc = NULL; - char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL; - unsigned char *cookie = NULL; - int errorcode = 0, regstatus = 0; - int latestbuild = 0, latestbetabuild = 0; - char *latestrelease = NULL, *latestbeta = NULL; - char *latestreleaseurl = NULL, *latestbetaurl = NULL; - char *latestreleaseinfo = NULL, *latestbetainfo = NULL; - - /* - * Read block of TLVs. All further data is derived - * from what is parsed here. - * - * For SNAC login, there's a 17/3 SNAC header in front. - * - */ - if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) - tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10); - else - tlvlist = aim_readtlvchain(command->data, command->commandlen); - - /* - * No matter what, we should have a screen name. - */ - memset(sess->sn, 0, sizeof(sess->sn)); - if (aim_gettlv(tlvlist, 0x0001, 1)) { - sn = aim_gettlv_str(tlvlist, 0x0001, 1); - strncpy(sess->sn, sn, sizeof(sess->sn)); - } - - /* - * Check for an error code. If so, we should also - * have an error url. - */ - if (aim_gettlv(tlvlist, 0x0008, 1)) - errorcode = aim_gettlv16(tlvlist, 0x0008, 1); - if (aim_gettlv(tlvlist, 0x0004, 1)) - errurl = aim_gettlv_str(tlvlist, 0x0004, 1); - - /* - * BOS server address. - */ - if (aim_gettlv(tlvlist, 0x0005, 1)) - bosip = aim_gettlv_str(tlvlist, 0x0005, 1); - - /* - * Authorization cookie. - */ - if (aim_gettlv(tlvlist, 0x0006, 1)) { - struct aim_tlv_t *tmptlv; - - tmptlv = aim_gettlv(tlvlist, 0x0006, 1); - - if ((cookie = malloc(tmptlv->length))) - memcpy(cookie, tmptlv->value, tmptlv->length); - } - - /* - * The email address attached to this account - * Not available for ICQ logins. - */ - if (aim_gettlv(tlvlist, 0x0011, 1)) - email = aim_gettlv_str(tlvlist, 0x0011, 1); - - /* - * The registration status. (Not real sure what it means.) - * Not available for ICQ logins. - * - * 1 = No disclosure - * 2 = Limited disclosure - * 3 = Full disclosure - * - * This has to do with whether your email address is available - * to other users or not. AFAIK, this feature is no longer used. - * - */ - if (aim_gettlv(tlvlist, 0x0013, 1)) - regstatus = aim_gettlv16(tlvlist, 0x0013, 1); - - if (aim_gettlv(tlvlist, 0x0040, 1)) - latestbetabuild = aim_gettlv32(tlvlist, 0x0040, 1); - if (aim_gettlv(tlvlist, 0x0041, 1)) - latestbetaurl = aim_gettlv_str(tlvlist, 0x0041, 1); - if (aim_gettlv(tlvlist, 0x0042, 1)) - latestbetainfo = aim_gettlv_str(tlvlist, 0x0042, 1); - if (aim_gettlv(tlvlist, 0x0043, 1)) - latestbeta = aim_gettlv_str(tlvlist, 0x0043, 1); - if (aim_gettlv(tlvlist, 0x0048, 1)) - ; /* no idea what this is */ - - if (aim_gettlv(tlvlist, 0x0044, 1)) - latestbuild = aim_gettlv32(tlvlist, 0x0044, 1); - if (aim_gettlv(tlvlist, 0x0045, 1)) - latestreleaseurl = aim_gettlv_str(tlvlist, 0x0045, 1); - if (aim_gettlv(tlvlist, 0x0046, 1)) - latestreleaseinfo = aim_gettlv_str(tlvlist, 0x0046, 1); - if (aim_gettlv(tlvlist, 0x0047, 1)) - latestrelease = aim_gettlv_str(tlvlist, 0x0047, 1); - if (aim_gettlv(tlvlist, 0x0049, 1)) - ; /* no idea what this is */ - - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0017, 0x0003))) - ret = userfunc(sess, command, sn, errorcode, errurl, regstatus, email, bosip, cookie, latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo, latestbeta, latestbetabuild, latestbetaurl, latestbetainfo); - - - if (sn) - free(sn); - if (bosip) - free(bosip); - if (errurl) - free(errurl); - if (email) - free(email); - if (cookie) - free(cookie); - if (latestrelease) - free(latestrelease); - if (latestreleaseurl) - free(latestreleaseurl); - if (latestbeta) - free(latestbeta); - if (latestbetaurl) - free(latestbetaurl); - if (latestreleaseinfo) - free(latestreleaseinfo); - if (latestbetainfo) - free(latestbetainfo); - - aim_freetlvchain(&tlvlist); - - return ret; -} - -/* - * Middle handler for 0017/0007 SNACs. Contains the auth key prefixed - * by only its length in a two byte word. - * - * Calls the client, which should then use the value to call aim_send_login. - * - */ -faim_internal int aim_authkeyparse(struct aim_session_t *sess, struct command_rx_struct *command) -{ - unsigned char *key; - int keylen; - int ret = 1; - rxcallback_t userfunc; - - keylen = aimutil_get16(command->data+10); - if (!(key = malloc(keylen+1))) - return ret; - memcpy(key, command->data+12, keylen); - key[keylen] = '\0'; - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0017, 0x0007))) - ret = userfunc(sess, command, (char *)key); - - free(key); - - return ret; -} - -/* * Generate an authorization response. * * You probably don't want this unless you're writing an AIM server. @@ -571,3 +398,285 @@ 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; +}
--- a/libfaim/md5.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/md5.c Tue Mar 27 00:51:09 2001 +0000 @@ -21,7 +21,7 @@ ghost@aladdin.com */ -/*$Id: md5.c 899 2000-09-12 20:21:36Z warmenhoven $ */ +/*$Id: md5.c 1659 2001-03-27 00:51:09Z mid $ */ /* Independent implementation of MD5 (RFC 1321).
--- a/libfaim/meta.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/meta.c Tue Mar 27 00:51:09 2001 +0000 @@ -16,17 +16,17 @@ 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, ...)
--- a/libfaim/misc.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/misc.c Tue Mar 27 00:51:09 2001 +0000 @@ -215,10 +215,10 @@ return -1; i += aim_putsnac(newpacket->data, 0x0002, 0x004, 0x0000, sess->snac_nextid); - i += aim_puttlv_str(newpacket->data+i, 0x0001, strlen("text/x-aolrtf; charset=\"us-ascii\""), "text/x-aolrtf; charset=\"us-ascii\""); + i += aim_puttlv_str(newpacket->data+i, 0x0001, strlen("text/aolrtf; charset=\"us-ascii\""), "text/x-aolrtf; charset=\"us-ascii\""); i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(profile), profile); /* why do we send this twice? */ - i += aim_puttlv_str(newpacket->data+i, 0x0003, strlen("text/x-aolrtf; charset=\"us-ascii\""), "text/x-aolrtf; charset=\"us-ascii\""); + i += aim_puttlv_str(newpacket->data+i, 0x0003, strlen("text/aolrtf; charset=\"us-ascii\""), "text/x-aolrtf; charset=\"us-ascii\""); /* Away message -- we send this no matter what, even if its blank */ if (awaymsg) @@ -239,58 +239,6 @@ return (sess->snac_nextid++); } -/* - * aim_bos_setgroupperm(mask) - * - * Set group permisson mask. Normally 0x1f (all classes). - * - * The group permission mask allows you to keep users of a certain - * class or classes from talking to you. The mask should be - * a bitwise OR of all the user classes you want to see you. - * - */ -faim_export unsigned long aim_bos_setgroupperm(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_long mask) -{ - return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask); -} - -faim_internal int aim_parse_bosrights(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - rxcallback_t userfunc = NULL; - int ret=1; - struct aim_tlvlist_t *tlvlist; - unsigned short maxpermits = 0, maxdenies = 0; - - /* - * TLVs follow - */ - if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10))) - return ret; - - /* - * TLV type 0x0001: Maximum number of buddies on permit list. - */ - if (aim_gettlv(tlvlist, 0x0001, 1)) - maxpermits = aim_gettlv16(tlvlist, 0x0001, 1); - - /* - * TLV type 0x0002: Maximum number of buddies on deny list. - * - */ - if (aim_gettlv(tlvlist, 0x0002, 1)) - maxdenies = aim_gettlv16(tlvlist, 0x0002, 1); - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0009, 0x0003))) - ret = userfunc(sess, command, maxpermits, maxdenies); - - aim_freetlvchain(&tlvlist); - - return ret; -} - /* * aim_bos_clientready() * @@ -413,7 +361,7 @@ struct command_tx_struct *newpacket; int i; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + (4*12)))) + if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + (4*16)))) return -1; newpacket->lock = 1; @@ -424,9 +372,6 @@ i += aimutil_put16(newpacket->data+i, 0x0001); i += aimutil_put16(newpacket->data+i, 0x0003); - i += aimutil_put16(newpacket->data+i, 0x0013); - i += aimutil_put16(newpacket->data+i, 0x0001); - i += aimutil_put16(newpacket->data+i, 0x0002); i += aimutil_put16(newpacket->data+i, 0x0001); @@ -449,9 +394,15 @@ i += aimutil_put16(newpacket->data+i, 0x0001); i += aimutil_put16(newpacket->data+i, 0x000b); + i += aimutil_put16(newpacket->data+i, 0x0002); + + i += aimutil_put16(newpacket->data+i, 0x000c); i += aimutil_put16(newpacket->data+i, 0x0001); - i += aimutil_put16(newpacket->data+i, 0x000c); + i += aimutil_put16(newpacket->data+i, 0x0013); + i += aimutil_put16(newpacket->data+i, 0x0001); + + i += aimutil_put16(newpacket->data+i, 0x0015); i += aimutil_put16(newpacket->data+i, 0x0001); newpacket->commandlen = i; @@ -870,3 +821,56 @@ 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; +}
--- a/libfaim/rxhandlers.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/rxhandlers.c Tue Mar 27 00:51:09 2001 +0000 @@ -10,6 +10,118 @@ #define FAIM_INTERNAL #include <aim.h> +static aim_module_t *findmodule(struct aim_session_t *sess, const char *name) +{ + aim_module_t *cur; + + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + if (strcmp(name, cur->name) == 0) + return cur; + } + + return NULL; +} + +faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst)(struct aim_session_t *, aim_module_t *)) +{ + aim_module_t *mod; + + if (!sess || !modfirst) + return -1; + + if (!(mod = malloc(sizeof(aim_module_t)))) + return -1; + memset(mod, 0, sizeof(aim_module_t)); + + if (modfirst(sess, mod) == -1) { + free(mod); + return -1; + } + + if (findmodule(sess, mod->name)) { + if (mod->shutdown) + mod->shutdown(sess, mod); + free(mod); + return -1; + } + + mod->next = (aim_module_t *)sess->modlistv; + (aim_module_t *)sess->modlistv = mod; + + faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family); + + return 0; +} + +faim_internal void aim__shutdownmodules(struct aim_session_t *sess) +{ + aim_module_t *cur; + + for (cur = (aim_module_t *)sess->modlistv; cur; ) { + aim_module_t *tmp; + + tmp = cur->next; + + if (cur->shutdown) + cur->shutdown(sess, cur); + + free(cur); + + cur = tmp; + } + + sess->modlistv = NULL; + + return; +} + +static int consumesnac(struct aim_session_t *sess, struct command_rx_struct *rx) +{ + aim_module_t *cur; + aim_modsnac_t snac; + + snac.family = aimutil_get16(rx->data+0); + snac.subtype = aimutil_get16(rx->data+2); + snac.flags = aimutil_get16(rx->data+4); + snac.id = aimutil_get32(rx->data+6); + + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + + if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && + (cur->family != snac.family)) + continue; + + if (cur->snachandler(sess, cur, rx, &snac, rx->data+10, rx->commandlen-10)) + return 1; + + } + + return 0; +} + +static int consumenonsnac(struct aim_session_t *sess, struct command_rx_struct *rx, unsigned short family, unsigned short subtype) +{ + aim_module_t *cur; + aim_modsnac_t snac; + + snac.family = family; + snac.subtype = subtype; + snac.flags = snac.id = 0; + + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + + if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && + (cur->family != snac.family)) + continue; + + if (cur->snachandler(sess, cur, rx, &snac, rx->data, rx->commandlen)) + return 1; + + } + + return 0; +} + /* * Bleck functions get called when there's no non-bleck functions * around to cleanup the mess... @@ -308,10 +420,15 @@ { int i = 0; struct command_rx_struct *workingPtr = NULL; + static int critical = 0; + if (critical) + return 0; /* don't call recursively! */ + + critical = 1; + if (sess->queue_incoming == NULL) { faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n"); - return 0; } else { workingPtr = sess->queue_incoming; for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) { @@ -366,152 +483,18 @@ workingPtr->handled = aim_negchan_middle(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 (subtype == 0x0003) - workingPtr->handled = aim_parse_buddyrights(sess, workingPtr); - else if (subtype == 0x000b) - workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr); - else if (subtype == 0x000c) - workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, 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 == 0x0007) { - if (subtype == 0x0003) - workingPtr->handled = aim_parse_infochange(sess, workingPtr); - else if (subtype == 0x0005) - workingPtr->handled = aim_parse_infochange(sess, workingPtr); - else if (subtype == 0x0007) - workingPtr->handled = aim_parse_accountconfirm(sess, workingPtr); - break; - - } else if (family == 0x0009) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_parse_bosrights(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr); - - } else if (family == 0x000a) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_searcherror(sess, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_parse_searchreply(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr); - - } else if (family == 0x000b) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); - else if (subtype == 0x0002) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr); - - } else if (family == 0x000d) { + if ((workingPtr->handled = consumesnac(sess, workingPtr))) + continue; + + if (!workingPtr->handled) { + family = aimutil_get16(workingPtr->data); + subtype = aimutil_get16(workingPtr->data+2); - 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 == 0x0017) { /* New login protocol */ - - if (subtype == 0x0001) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_authparse(sess, workingPtr); - else if (subtype == 0x0007) - workingPtr->handled = aim_authkeyparse(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr); - - } else if (family == AIM_CB_FAM_SPECIAL) { - - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); - + faimdprintf(sess, 1, "warning: unhandled packet %04x/%04x\n", family, subtype); + consumenonsnac(sess, workingPtr, 0xffff, 0xffff); /* last chance! */ + workingPtr->handled = 1; } - - /* Try it raw and see if we can get it to happen... */ - if (!workingPtr->handled) /* XXX this is probably bad. */ - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); - } } @@ -522,342 +505,12 @@ * you'll have :) */ aim_purge_rxqueue(sess); + + critical = 0; 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_accountconfirm(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - rxcallback_t userfunc = NULL; - int ret = 1; - int status = -1; - - status = aimutil_get16(command->data+10); - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, 0x0007))) - ret = userfunc(sess, command, status); - - return ret; -} - -faim_internal int aim_parse_infochange(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - unsigned short subtype; /* called for both reply and change-reply */ - int i; - - subtype = aimutil_get16(command->data+2); - - /* - * struct { - * unsigned short perms; - * unsigned short tlvcount; - * aim_tlv_t tlvs[tlvcount]; - * } admin_info[n]; - */ - for (i = 10; i < command->commandlen; ) { - int perms, tlvcount; - - perms = aimutil_get16(command->data+i); - i += 2; - - tlvcount = aimutil_get16(command->data+i); - i += 2; - - while (tlvcount) { - rxcallback_t userfunc; - struct aim_tlv_t *tlv; - int str = 0; - - if ((aimutil_get16(command->data+i) == 0x0011) || - (aimutil_get16(command->data+i) == 0x0004)) - str = 1; - - if (str) - tlv = aim_grabtlvstr(command->data+i); - else - tlv = aim_grabtlv(command->data+i); - - /* XXX fix so its only called once for the entire packet */ - if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, subtype))) - userfunc(sess, command, perms, tlv->type, tlv->length, tlv->value, str); - - if (tlv) - i += 2+2+tlv->length; - - if (tlv && tlv->value) - free(tlv->value); - if (tlv) - free(tlv); - - tlvcount--; - } - } - - return 1; -} - -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, ...) { @@ -894,7 +547,7 @@ /* Used only by the older login protocol */ /* XXX remove this special case? */ if (command->conn->type == AIM_CONN_TYPE_AUTH) - return aim_authparse(sess, command); + return consumenonsnac(sess, command, 0x0017, 0x0003); tlvlist = aim_readtlvchain(command->data, command->commandlen); @@ -905,7 +558,7 @@ msg = aim_gettlv_str(tlvlist, 0x000b, 1); if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) - ret = userfunc(sess, command, code, msg); + ret = userfunc(sess, command, code, msg); aim_freetlvchain(&tlvlist); @@ -915,32 +568,3 @@ 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; -} - - -
--- a/libfaim/search.c Mon Mar 26 10:29:06 2001 +0000 +++ b/libfaim/search.c Tue Mar 27 00:51:09 2001 +0000 @@ -34,59 +34,47 @@ return sess->snac_nextid; } - -faim_internal unsigned long aim_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command) +/* 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) { - u_int i, ret; - int snacid; + int ret = 0; rxcallback_t userfunc; - struct aim_snac_t *snac; + struct aim_snac_t *snac2; - i = 6; - - snacid = aimutil_get32(command->data+i); - i += 4; - - if(!(snac = aim_remsnac(sess, snacid))) { - faimdprintf(sess, 2, "faim: couldn't get a snac for %d, probably should crash.\n", snacid); + /* XXX the modules interface should have already retrieved this for us */ + if(!(snac2 = aim_remsnac(sess, snac->id))) { + faimdprintf(sess, 2, "couldn't get a snac for 0x%08lx\n", snac->id); return 0; } - if((userfunc = aim_callhandler(sess, command->conn, 0x000a, 0x0001))) - ret = userfunc(sess, command, snac->data /* address */); - else - ret = 0; + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, snac2->data /* address */); - if(snac) { - if(snac->data) - free(snac->data); - free(snac); + /* XXX freesnac()? */ + if (snac2) { + if(snac2->data) + free(snac2->data); + free(snac2); } return ret; } - - -faim_internal unsigned long aim_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command) + +static int reply(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, j, m, ret; - int snacid; + unsigned int j, m, ret = 0; struct aim_tlvlist_t *tlvlist; char *cur = NULL, *buf = NULL; rxcallback_t userfunc; - struct aim_snac_t *snac; - - i = 6; + struct aim_snac_t *snac2; - snacid = aimutil_get32(command->data+i); - i += 4; - - if(!(snac = aim_remsnac(sess, snacid))) { - faimdprintf(sess, 2, "faim: couldn't get a snac for %d, probably should crash.\n", snacid); + if (!(snac2 = aim_remsnac(sess, snac->id))) { + faimdprintf(sess, 2, "faim: couldn't get a snac for 0x%08lx\n", snac->id); return 0; } - tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); + if (!(tlvlist = aim_readtlvchain(data, datalen))) + return 0; j = 0; @@ -104,15 +92,14 @@ aim_freetlvchain(&tlvlist); - if((userfunc = aim_callhandler(sess, command->conn, 0x000a, 0x0003))) - ret = userfunc(sess, command, snac->data /* address */, j, buf); - else - ret = 0; + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, snac2->data /* address */, j, buf); - if(snac) { - if(snac->data) - free(snac->data); - free(snac); + /* XXX freesnac()? */ + if(snac2) { + if(snac2->data) + free(snac2->data); + free(snac2); } if(buf) @@ -120,3 +107,26 @@ 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 error(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0003) + return reply(sess, mod, rx, snac, data, datalen); + + return 0; +} + +faim_internal int search_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0x000a; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "search", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfaim/stats.c Tue Mar 27 00:51:09 2001 +0000 @@ -0,0 +1,37 @@ + +#define FAIM_INTERNAL +#include <aim.h> + +static int reportinterval(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + unsigned short interval; + rxcallback_t userfunc; + + interval = aimutil_get16(data); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, interval); + + 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 == 0x0002) + return reportinterval(sess, mod, rx, snac, data, datalen); + + return 0; +} + +faim_internal int stats_modfirst(struct aim_session_t *sess, aim_module_t *mod) +{ + + mod->family = 0x000b; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "stats", sizeof(mod->name)); + mod->snachandler = snachandler; + + return 0; +}
--- a/src/oscar.c Mon Mar 26 10:29:06 2001 +0000 +++ b/src/oscar.c Tue Mar 27 00:51:09 2001 +0000 @@ -466,7 +466,7 @@ gdk_input_remove(odata->cnpa); if (odata->paspa > 0) gdk_input_remove(odata->paspa); - aim_logoff(odata->sess); + aim_session_kill(odata->sess); g_free(odata->sess); odata->sess = NULL; g_free(gc->proto_data); @@ -603,7 +603,11 @@ int gaim_parse_login(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +#if 0 struct client_info_s info = {"gaim", 4, 1, 2010, "us", "en", 0x0004, 0x0000, 0x04b}; +#else + struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD; +#endif char *key; va_list ap; struct gaim_connection *gc = sess->aux_data; @@ -804,15 +808,15 @@ int gaim_parse_offgoing(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - char *sn; + struct aim_userinfo_s *info; va_list ap; struct gaim_connection *gc = sess->aux_data; va_start(ap, command); - sn = va_arg(ap, char *); + info = va_arg(ap, struct aim_userinfo_s *); va_end(ap); - serv_got_update(gc, sn, 0, 0, 0, 0, 0, 0); + serv_got_update(gc, info->sn, 0, 0, 0, 0, 0, 0); return 1; } @@ -1326,8 +1330,8 @@ char buf[1024]; va_start(ap, command); + reason = (u_short)va_arg(ap, u_int); destn = va_arg(ap, char *); - reason = (u_short)va_arg(ap, u_int); va_end(ap); sprintf(buf, _("Your message to %s did not get sent: %s"), destn, @@ -1345,8 +1349,8 @@ char buf[1024]; va_start(ap, command); + reason = (u_short)va_arg(ap, u_int); destn = va_arg(ap, char *); - reason = (u_short)va_arg(ap, u_int); va_end(ap); sprintf(buf, _("User information for %s unavailable: %s"), destn, @@ -1418,18 +1422,23 @@ char *msg; u_short id; va_list ap; + char buildbuf[150]; va_start(ap, command); id = (u_short)va_arg(ap, u_int); msg = va_arg(ap, char *); va_end(ap); + aim_getbuildstring(buildbuf, sizeof(buildbuf)); + debug_printf("MOTD: %s (%d)\n", msg, id); - debug_printf("Gaim %s / Libfaim %s\n", VERSION, aim_getbuildstring()); + debug_printf("Gaim %s / Libfaim %s\n", VERSION, buildbuf); if (id != 4) do_error_dialog(_("Your connection may be lost."), _("AOL error")); + aim_0001_0020(sess, command->conn); + return 1; }