From: mid Date: Fri, 23 Mar 2001 05:52:31 +0000 (+0000) Subject: - Fri Mar 23 05:42:11 UTC 2001 X-Git-Tag: rel_0_99_2~58 X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/commitdiff_plain/9f1a40132a2c6642e3544205c31c091051127ae0 - 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... --- diff --git a/CHANGES b/CHANGES index a0ab8aa..27c976f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,15 @@ No release numbers ------------------ + - 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) diff --git a/include/aim.h b/include/aim.h index bad2b54..8d57fc2 100644 --- a/include/aim.h +++ b/include/aim.h @@ -352,6 +352,8 @@ struct aim_session_t { 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 */ @@ -456,6 +458,7 @@ typedef int (*rxcallback_t)(struct aim_session_t *, struct command_rx_struct *, 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); @@ -495,6 +498,7 @@ faim_export int aim_conn_isconnecting(struct aim_conn_t *conn); 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); diff --git a/include/aim_internal.h b/include/aim_internal.h index b8f8509..0682b2d 100644 --- a/include/aim_internal.h +++ b/include/aim_internal.h @@ -7,11 +7,42 @@ #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 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); @@ -25,8 +56,6 @@ faim_internal int aim_tx_enqueue(struct aim_session_t *, struct command_tx_struc 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,7 +87,6 @@ faim_internal int aim_oft_buildheader(unsigned char *,struct aim_fileheader_t *) faim_internal int aim_listenestablish(u_short); faim_internal int aim_tx_destroy(struct command_tx_struct *); -faim_internal int aim_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, ...); @@ -88,7 +116,6 @@ faim_internal int aim_parse_incoming_im_middle(struct aim_session_t *, struct co 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]; @@ -105,16 +132,9 @@ faim_internal int aim_cookie_free(struct aim_session_t *sess, struct aim_msgcook 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); diff --git a/src/.cvsignore b/src/.cvsignore index 417f3f6..396846a 100644 --- a/src/.cvsignore +++ b/src/.cvsignore @@ -1,8 +1,10 @@ Makefile.in Makefile .deps +admin.lo adverts.lo auth.lo +bos.lo buddylist.lo chat.lo chatnav.lo @@ -18,6 +20,7 @@ rxhandlers.lo rxqueue.lo search.lo snac.lo +stats.lo tlv.lo txqueue.lo util.lo diff --git a/src/Makefile.am b/src/Makefile.am index c6f010a..9b739bc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,8 +1,10 @@ lib_LTLIBRARIES = libfaim.la -libfaim_la_SOURCES = adverts.c \ +libfaim_la_SOURCES = admin.c \ + adverts.c \ auth.c \ + bos.c \ buddylist.c \ chat.c \ chatnav.c \ @@ -18,6 +20,7 @@ libfaim_la_SOURCES = adverts.c \ rxqueue.c \ search.c \ snac.c \ + stats.c \ tlv.c \ txqueue.c \ util.c \ diff --git a/src/admin.c b/src/admin.c new file mode 100644 index 0000000..22419d8 --- /dev/null +++ b/src/admin.c @@ -0,0 +1,254 @@ + +#define FAIM_INTERNAL +#include + +/* 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) +{ + + faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); + + if (snac->family != mod->family) + return 0; + + if (snac->subtype == 0x0001) + ; + else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0005)) + 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; +} diff --git a/src/auth.c b/src/auth.c index 621c269..629d755 100644 --- a/src/auth.c +++ b/src/auth.c @@ -30,156 +30,202 @@ faim_export int aim_auth_sendcookie(struct aim_session_t *sess, 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); - - 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); + 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); + + /* + * 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)); } - 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); + /* + * 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); + } - 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); + + /* + * 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, 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); + + + 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; } /* - * 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); -/* - * 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; + free(key); - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + 4))) - return -1; + return ret; +} - newpacket->lock = 1; +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) +{ - i = aim_putsnac(newpacket->data, 0x0007, 0x0002, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0002, 0x0002, 0x0000, NULL, 0); + faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); - i += aimutil_put16(newpacket->data+i, info); - i += aimutil_put16(newpacket->data+i, 0x0000); + if (snac->family != mod->family) + return 0; - newpacket->commandlen = i; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + if (snac->subtype == 0x0001) + ; + else 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); - 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); - - i += aim_puttlv_str(newpacket->data+i, 0x0011, strlen(newemail), newemail); - aim_tx_enqueue(sess, newpacket); + mod->family = 0x0017; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "auth", sizeof(mod->name)); + mod->snachandler = snachandler; - return sess->snac_nextid; + return 0; } diff --git a/src/bos.c b/src/bos.c new file mode 100644 index 0000000..829788b --- /dev/null +++ b/src/bos.c @@ -0,0 +1,82 @@ + +#define FAIM_INTERNAL +#include + +/* + * 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); +} + +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) +{ + + faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); + + if (snac->family != mod->family) + return 0; + + if (snac->subtype == 0x0001) + ; + else if (snac->subtype == 0x0003) + 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; +} diff --git a/src/buddylist.c b/src/buddylist.c index 55a3571..28492aa 100644 --- a/src/buddylist.c +++ b/src/buddylist.c @@ -2,6 +2,111 @@ #define FAIM_INTERNAL #include +/* + * Oncoming Buddy notifications contain a subset of the + * user information structure. Its close enough to run + * through aim_extractuserinfo() however. + * + */ +static int oncoming(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; +} + +/* + * Offgoing Buddy notifications contain no useful + * information other than the name it applies to. + * + */ +static int offgoing(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + char sn[MAXSNLEN+1]; + rxcallback_t userfunc; + + strncpy(sn, (char *)data+1, (int)*data); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, sn); + + 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) +{ + + faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); + + if (snac->family != mod->family) + return 0; + + if (snac->subtype == 0x0001) + ; + else if (snac->subtype == 0x0003) + return rights(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x000b) + return oncoming(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x000c) + return offgoing(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() * @@ -68,39 +173,3 @@ faim_export unsigned long aim_remove_buddy(struct aim_session_t *sess, 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; -} diff --git a/src/conn.c b/src/conn.c index 1482dba..c64d33a 100644 --- a/src/conn.c +++ b/src/conn.c @@ -722,6 +722,11 @@ faim_export void aim_setupproxy(struct aim_session_t *sess, char *server, char * 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 @@ -748,7 +753,9 @@ faim_export void aim_session_init(struct aim_session_t *sess, unsigned long flag sess->flags = 0; sess->debug = 0; - sess->debugcb = NULL; + sess->debugcb = defaultdebugcb; + + sess->modlistv = NULL; /* * Default to SNAC login unless XORLOGIN is explicitly set. @@ -763,6 +770,33 @@ faim_export void aim_session_init(struct aim_session_t *sess, unsigned long flag */ aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL); + + /* + * Register all the modules for this session... + */ + 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); + + 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; } diff --git a/src/info.c b/src/info.c index de05b79..ee140fe 100644 --- a/src/info.c +++ b/src/info.c @@ -461,51 +461,6 @@ faim_internal int aim_extractuserinfo(struct aim_session_t *sess, unsigned char return i; } -/* - * 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). diff --git a/src/login.c b/src/login.c index 6b06863..3e6e9cd 100644 --- a/src/login.c +++ b/src/login.c @@ -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, @@ -177,7 +176,7 @@ faim_export int aim_send_login (struct aim_session_t *sess, 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); @@ -231,7 +230,7 @@ faim_export int aim_send_login (struct aim_session_t *sess, 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; @@ -285,182 +284,6 @@ static int aim_encode_password(const char *password, unsigned char *encoded) return 0; } -/* - * 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. * diff --git a/src/misc.c b/src/misc.c index 252d41e..c8f8a80 100644 --- a/src/misc.c +++ b/src/misc.c @@ -239,58 +239,6 @@ faim_export unsigned long aim_bos_setprofile(struct aim_session_t *sess, 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() * diff --git a/src/rxhandlers.c b/src/rxhandlers.c index 2241f71..493d040 100644 --- a/src/rxhandlers.c +++ b/src/rxhandlers.c @@ -10,6 +10,118 @@ #define FAIM_INTERNAL #include +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, 0, "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... @@ -371,10 +483,13 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) workingPtr->handled = aim_negchan_middle(sess, workingPtr); continue; } + + if ((workingPtr->handled = consumesnac(sess, workingPtr))) + continue; family = aimutil_get16(workingPtr->data); subtype = aimutil_get16(workingPtr->data+2); - + if (family == 0x0001) { if (subtype == 0x0001) @@ -413,14 +528,6 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) 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) { @@ -439,43 +546,6 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) 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 (subtype == 0x0009) @@ -496,17 +566,6 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) 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); @@ -726,78 +785,6 @@ faim_internal int aim_parse_hostonline(struct aim_session_t *sess, 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, ...) { @@ -896,7 +883,7 @@ faim_internal int aim_negchan_middle(struct aim_session_t *sess, /* 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); @@ -907,7 +894,7 @@ faim_internal int aim_negchan_middle(struct aim_session_t *sess, 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); diff --git a/src/search.c b/src/search.c index 649a9fc..a102412 100644 --- a/src/search.c +++ b/src/search.c @@ -35,58 +35,46 @@ faim_export unsigned long aim_usersearch_address(struct aim_session_t *sess, } -faim_internal unsigned long aim_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command) +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 @@ faim_internal unsigned long aim_parse_searchreply(struct aim_session_t *sess, st 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,31 @@ faim_internal unsigned long aim_parse_searchreply(struct aim_session_t *sess, st 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) +{ + + faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); + + if (snac->family != mod->family) + return 0; + + if (snac->subtype == 0x0001) + return error(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x0003) + 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; +} diff --git a/src/stats.c b/src/stats.c new file mode 100644 index 0000000..4f7f741 --- /dev/null +++ b/src/stats.c @@ -0,0 +1,44 @@ + +#define FAIM_INTERNAL +#include + +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) +{ + + faimdprintf(sess, 0, "%s: snachandler: got %x/%x\n", mod->name, snac->family, snac->subtype); + + if (snac->family != mod->family) + return 0; + + if (snac->subtype == 0x0001) + ; + else if (snac->subtype == 0x0002) + 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; +} diff --git a/utils/faimtest/faimtest.c b/utils/faimtest/faimtest.c index bccad2b..a2976af 100644 --- a/utils/faimtest/faimtest.c +++ b/utils/faimtest/faimtest.c @@ -169,10 +169,15 @@ static void faimtest_debugcb(struct aim_session_t *sess, int level, const char * int faimtest_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - if (command->data) { - dvprintf("aim: minimum report interval: %d (seconds?)\n", aimutil_get16(command->data+10)); - } else - dprintf("aim: NULL minimum report interval!\n"); + va_list ap; + unsigned short interval = 0; + + va_start(ap, command); + interval = va_arg(ap, int); + va_end(ap); + + dvprintf("aim: minimum report interval: %d (seconds?)\n", interval); + return 1; } @@ -256,7 +261,7 @@ int logout(void) if (ohcaptainmycaptain) aim_send_im(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), ohcaptainmycaptain, 0, "ta ta..."); - aim_logoff(&aimsess); + aim_session_kill(&aimsess); if (faimtest_init() == -1) dprintf("faimtest_init failed\n"); @@ -396,7 +401,7 @@ int main(int argc, char **argv) waitingconn = aim_select(&aimsess, NULL, &selstat); if (selstat == -1) { /* error */ - keepgoing = 0; /* fall through and hit the aim_logoff() */ + keepgoing = 0; /* fall through */ } else if (selstat == 0) { /* no events pending */ keepgoing = 0; } else if (selstat == 1) { /* outgoing data pending */ @@ -433,7 +438,7 @@ int main(int argc, char **argv) } /* close up all connections, dead or no */ - aim_logoff(&aimsess); + aim_session_kill(&aimsess); if (faimtest_mode < 2) { printf("\n");