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