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)
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 */
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);
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);
#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);
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);
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_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 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);
Makefile.in
Makefile
.deps
+admin.lo
adverts.lo
auth.lo
+bos.lo
buddylist.lo
chat.lo
chatnav.lo
rxqueue.lo
search.lo
snac.lo
+stats.lo
tlv.lo
txqueue.lo
util.lo
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 \
rxqueue.c \
search.c \
snac.c \
+ stats.c \
tlv.c \
txqueue.c \
util.c \
--- /dev/null
+
+#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)
+{
+
+ 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;
+}
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;
}
--- /dev/null
+
+#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);
+}
+
+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;
+}
#define FAIM_INTERNAL
#include <aim.h>
+/*
+ * 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()
*
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;
-}
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
sess->flags = 0;
sess->debug = 0;
- sess->debugcb = NULL;
+ sess->debugcb = defaultdebugcb;
+
+ sess->modlistv = NULL;
/*
* Default to SNAC login unless XORLOGIN is explicitly set.
*/
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;
}
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).
#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,
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);
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;
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.
*
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()
*
#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, 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...
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)
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) {
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)
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);
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, ...)
{
/* 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);
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);
}
-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;
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)
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;
+}
--- /dev/null
+
+#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)
+{
+
+ 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;
+}
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;
}
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");
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 */
}
/* close up all connections, dead or no */
- aim_logoff(&aimsess);
+ aim_session_kill(&aimsess);
if (faimtest_mode < 2) {
printf("\n");