# HG changeset patch # User Eric Warmenhoven # Date 1000030034 0 # Node ID 933346315b9bd448901e3a247e94dca75218cd8f # Parent 31157c54fe6ebad47d700f8ae693f2b320e9b2eb [gaim-migrate @ 2256] heh. committer: Tailor Script diff -r 31157c54fe6e -r 933346315b9b ChangeLog --- a/ChangeLog Sun Sep 09 06:33:54 2001 +0000 +++ b/ChangeLog Sun Sep 09 10:07:14 2001 +0000 @@ -11,6 +11,7 @@ * Added a spiffy Help button * Wrote a plugin for all those people who miss having the chat rooms in their buddy lists (chatlist.so) + * Updated libfaim version 0.43 (09/06/2001): * Updated German Translation (thanks Daniel Seifert) diff -r 31157c54fe6e -r 933346315b9b src/conversation.c --- a/src/conversation.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/conversation.c Sun Sep 09 10:07:14 2001 +0000 @@ -415,6 +415,13 @@ gtkspell_detach(GTK_TEXT(c->entry)); if (!c->is_chat) { + GSList *cn = connections; + while (cn) { + struct gaim_connection *gc = cn->data; + cn = cn->next; + if (gc->prpl->convo_closed) + (*gc->prpl->convo_closed)(gc, c->name); + } remove_icon(c); remove_checkbox(c); if (display_options & OPT_DISP_ONE_WINDOW) { diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/BUGS --- a/src/protocols/oscar/BUGS Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/BUGS Sun Sep 09 10:07:14 2001 +0000 @@ -3,35 +3,14 @@ ----- - Needs a bit of cleaning -aim_auth.c ----------- - - Login doesn't take advantage of aim_conn constructs where it could - - Login should allow for multiple BOS connections - -aim_chat.c ----------- - - Needs to be implemented. - -aim_chatnav.c -------------- - - Needs to be implemented. - -aim_conn.c ----------- - - Does not work with proxies. - -aim_search.c +search.c ------------ - Still need aim_usersearch_name() -aim_snac.c +snac.c ---------- - Should implement better SNAC handling -aim_tlv.c ---------- - - Newer TLV bulk-read routines most likely have leakage somewhere. - -aim_rxhandlers.c +rxhandlers.c ---------------- - Need a better solution than sleep() diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/CHANGES --- a/src/protocols/oscar/CHANGES Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/CHANGES Sun Sep 09 10:07:14 2001 +0000 @@ -1,6 +1,91 @@ No release numbers ------------------ + - Sat Sep 8 21:26:27 PDT 2001 + - Minor bug directim_connect + + - Sat Sep 8 20:18:34 PDT 2001 + - Split up the ICBM Channel 2 handlers a bit more + - Add a stub parser for recieving buddy lists. It will stay that way until + someone decides on a good API for passing lists like this to the client. + In case someone does, the same standard will be used for setbuddylist and + the as yet nonexistant support for server-side buddy lists. + - Make infochange work again. I still don't like it, but I don't want to + fix it. + + - Sat Sep 8 19:05:05 PDT 2001 + - Redo ICQ login + - Fix search by email (oops). + + - Sat Sep 8 17:07:09 PDT 2001 + - Fix directim so you can do it more than once without crashing. + - This removes the connect/disconnect callbacks. They were pointless, as + you can get the same information at a better spot by looking for when + aim_getcommand returns -1, just like is done for FLAP connections. + - (This was causing aim_conn_kill to be called twice for the same connect, + once in the client callback, and once more when aim_getcommand returned + the -1). + - Add aim_conn_(close|kill)_rend(). This is for destroying the cookie and + the internal data sections in one spot. + - Fix a bug in aim_connrst (and hence aim_logout()) that caused intdata/priv + to not be freed in those cases. Evil. + + - Sat Sep 8 07:32:27 PDT 2001 + - Clean up ft.c slightly. Direct IM now works. In both directions. + - This could still use a lot more help. It should use bstreams more. + + - Sat Sep 8 00:55:46 PDT 2001 + - Chatnav loop fix. (Err. I shouldn't code when I'm that tired.) + - Remove some things from BUGS + - Remove USE_MACROS from faimconfig.h. Not used, and frivelous when it was. + + - Fri Sep 7 21:18:51 PDT 2001 + - Make icon field names uniform + - Add AIM_IMFLAGS_CUSTOMFEATURES. This allows the client to send/recieve + the field in IMs that show client information. + - This can be used to identify other open source OSCAR clients, if any + one is interested. + - Increase the size of args->icbmflags to 32bits + - Make sure that extended-only flags are not set for aim_send_im() + + - Fri Sep 7 19:59:43 PDT 2001 + - Fix buddyicons. Yay! (checksums are 32bits all the time. duh.) + + - Mon Sep 3 18:48:26 PDT 2001 + - Reformat everything to use real tabs (and to my latest coding style) + - Abstract out the numerical data types to fu8/16/32_t for portability. + - AIM_FRAMETYPE_OSCAR -> AIM_FRAMETYPE_FLAP. This makes more sense. + - aim_conn_t's FLAP sequence number was a signed int. Oops. + - Get rid of the 'struct' on all types suffixed with _t. That's been + annoying me for a while. They're all real typedefs now. + - Yes, client people are going to be rather annoyed by this. But it + doesn't stop there. Keep reading. + - Make the 'struct aim_rxcblist_t' type local to rxhandlers.c. + - Combine the command_tx_struct and command_rx_struct into aim_frame_t. + - Mostly aim_frame_t is command_rx_struct. For command_tx_struct, the + same structure is used, except where ->sent was, ->handled is now + used. + - This makes things a lot easier, everywhere. + - Get rid of ->lock. Pointless. If libfaim is ever preemptible, it + has much more important problems than that. + - Welcome to aim_bstream_t. No more direct buffer accesses. Anywhere. + - In fact I plan on getting rid of the aimutil macros completly. + - This isn't complete yet. It will be better later. Believe me. Maybe + even make more sense. + - More advanced and configurable boundschecking is coming, too. + - Clean up lots of stuff, everywhere. + - Rearrange the implementation of the TLV functions, saving lots of code. + - I'm rather pleased with the way some things got implemented with this, + particularly in places where TLVs contain TLVs. + - Get rid of aim_puttlv_() functions. Those were gross. Use tlvchains. + - XOR login is temporarily broken. I'll fix it someday. ("Someone" needs it.) + - Fix the return values of most everything -- OSCAR functions should all + return 0 on sucess, negative errno on failure. + - There are several things braced with #ifdef MID_REWROTE_ALL_THE_CRAP. + Consider that code broken and nonfunctional for now. + - I think I may have broken buddy icons. Remind me to fix that. + - Renovate faimtest substantially. Reformat, split up, update to new types. + - Wed Aug 29 16:59:24 PDT 2001 - Pass up entire icon triplet (checksum/length/timestamp) in all cases that it is recieved. diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/admin.c --- a/src/protocols/oscar/admin.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/admin.c Sun Sep 09 10:07:14 2001 +0000 @@ -3,180 +3,163 @@ #include /* called for both reply and change-reply */ -static int infochange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int infochange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - int i; - /* - * struct { - * unsigned short perms; - * unsigned short tlvcount; - * aim_tlv_t tlvs[tlvcount]; - * } admin_info[n]; - */ - for (i = 0; i < datalen; ) { - int perms, tlvcount; + /* + * struct { + * unsigned short perms; + * unsigned short tlvcount; + * aim_tlv_t tlvs[tlvcount]; + * } admin_info[n]; + */ + while (aim_bstream_empty(bs)) { + fu16_t perms, tlvcount; - perms = aimutil_get16(data+i); - i += 2; + perms = aimbs_get16(bs); + tlvcount = aimbs_get16(bs); - tlvcount = aimutil_get16(data+i); - i += 2; - - while (tlvcount) { - aim_rxcallback_t userfunc; - struct aim_tlv_t *tlv; - int str = 0; + while (tlvcount && aim_bstream_empty(bs)) { + aim_rxcallback_t userfunc; + fu16_t type, len; + fu8_t *val; + int str = 0; - if ((aimutil_get16(data+i) == 0x0011) || - (aimutil_get16(data+i) == 0x0004)) - str = 1; + type = aimbs_get16(bs); + len = aimbs_get16(bs); - if (str) - tlv = aim_grabtlvstr(data+i); - else - tlv = aim_grabtlv(data+i); + if ((type == 0x0011) || (type == 0x0004)) + str = 1; - /* XXX fix so its only called once for the entire packet */ - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - userfunc(sess, rx, perms, tlv->type, tlv->length, tlv->value, str); + if (str) + val = aimbs_getstr(bs, len); + else + val = aimbs_getraw(bs, len); - if (tlv) - i += 2+2+tlv->length; + /* XXX fix so its only called once for the entire packet */ + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + userfunc(sess, rx, (snac->subtype == 0x0005) ? 1 : 0, perms, type, len, val, str); + + free(val); - if (tlv && tlv->value) - free(tlv->value); - if (tlv) - free(tlv); + tlvcount--; + } + } - tlvcount--; - } - } - - return 1; + return 1; } -static int accountconfirm(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int accountconfirm(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - aim_rxcallback_t userfunc; - int status; + aim_rxcallback_t userfunc; + fu16_t status; - status = aimutil_get16(data); + status = aimbs_get16(bs); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - return userfunc(sess, rx, status); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, status); - return 0; + 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) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - 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); + if ((snac->subtype == 0x0003) || (snac->subtype == 0x0005)) + return infochange(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0007) + return accountconfirm(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int admin_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x0007; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "admin", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x0007; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "admin", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } -faim_export unsigned long aim_auth_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_auth_clientready(aim_session_t *sess, aim_conn_t *conn) { - struct aim_tool_version tools[] = { - {0x0001, 0x0003, AIM_TOOL_NEWWIN, 0x0361}, - {0x0007, 0x0001, AIM_TOOL_NEWWIN, 0x0361}, - }; - int i,j; - struct command_tx_struct *newpacket; - int toolcount = sizeof(tools)/sizeof(struct aim_tool_version); + static const struct aim_tool_version tools[] = { + {0x0001, 0x0003, AIM_TOOL_NEWWIN, 0x0361}, + {0x0007, 0x0001, AIM_TOOL_NEWWIN, 0x0361}, + }; + int j; + aim_frame_t *tx; + int toolcount = sizeof(tools) / sizeof(struct aim_tool_version); + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) - return -1; - - newpacket->lock = 1; + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 1152))) + return -ENOMEM; - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&tx->data, 0x0001, 0x0002, 0x0000, snacid); - for (j = 0; j < toolcount; j++) { - i += aimutil_put16(newpacket->data+i, tools[j].group); - i += aimutil_put16(newpacket->data+i, tools[j].version); - i += aimutil_put16(newpacket->data+i, tools[j].tool); - i += aimutil_put16(newpacket->data+i, tools[j].toolversion); - } + for (j = 0; j < toolcount; j++) { + aimbs_put16(&tx->data, tools[j].group); + aimbs_put16(&tx->data, tools[j].version); + aimbs_put16(&tx->data, tools[j].tool); + aimbs_put16(&tx->data, tools[j].toolversion); + } - newpacket->commandlen = i; - newpacket->lock = 0; + aim_tx_enqueue(sess, tx); - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + return 0; } -faim_export unsigned long aim_auth_changepasswd(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *new, char *current) +faim_export int aim_auth_changepasswd(aim_session_t *sess, aim_conn_t *conn, const char *newpw, const char *curpw) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *tx; + aim_tlvlist_t *tl = NULL; + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+4+strlen(current)+4+strlen(new)))) - return -1; + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+strlen(curpw)+4+strlen(newpw)))) + return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid); - i = aim_putsnac(newpacket->data, 0x0007, 0x0004, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + /* new password TLV t(0002) */ + aim_addtlvtochain_raw(&tl, 0x0002, strlen(newpw), newpw); - /* new password TLV t(0002) */ - i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(new), new); + /* current password TLV t(0012) */ + aim_addtlvtochain_raw(&tl, 0x0012, strlen(curpw), curpw); - /* current password TLV t(0012) */ - i += aim_puttlv_str(newpacket->data+i, 0x0012, strlen(current), current); + aim_writetlvchain(&tx->data, &tl); + aim_freetlvchain(&tl); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, tx); - return sess->snac_nextid; + return 0; } -faim_export unsigned long aim_auth_setversions(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_auth_setversions(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *tx; + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + (4*2)))) - return -1; - - newpacket->lock = 1; + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 18))) + return -ENOMEM; - i = aim_putsnac(newpacket->data, 0x0001, 0x0017, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); + snacid = aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); + aim_putsnac(&tx->data, 0x0001, 0x0017, 0x0000, snacid); - i += aimutil_put16(newpacket->data+i, 0x0001); - i += aimutil_put16(newpacket->data+i, 0x0003); + aimbs_put16(&tx->data, 0x0001); + aimbs_put16(&tx->data, 0x0003); - i += aimutil_put16(newpacket->data+i, 0x0007); - i += aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&tx->data, 0x0007); + aimbs_put16(&tx->data, 0x0001); - newpacket->commandlen = i; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, tx); - return sess->snac_nextid; + return 0; } /* @@ -187,10 +170,9 @@ * get the TRIAL flag removed from your account. * */ -faim_export unsigned long aim_auth_reqconfirm(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_auth_reqconfirm(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0007, 0x0006); + return aim_genericreq_n(sess, conn, 0x0007, 0x0006); } /* @@ -199,49 +181,43 @@ * The only known valid tag is 0x0011 (email address). * */ -faim_export unsigned long aim_auth_getinfo(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned short info) +faim_export int aim_auth_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *tx; + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + 4))) - return -1; - - newpacket->lock = 1; + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 14))) + return -ENOMEM; - i = aim_putsnac(newpacket->data, 0x0007, 0x0002, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0002, 0x0002, 0x0000, NULL, 0); - - i += aimutil_put16(newpacket->data+i, info); - i += aimutil_put16(newpacket->data+i, 0x0000); + snacid = aim_cachesnac(sess, 0x0002, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&tx->data, 0x0007, 0x0002, 0x0000, snacid); - newpacket->commandlen = i; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aimbs_put16(&tx->data, info); + aimbs_put16(&tx->data, 0x0000); - return sess->snac_nextid; + aim_tx_enqueue(sess, tx); + + return 0; } -faim_export unsigned long aim_auth_setemail(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *newemail) +faim_export int aim_auth_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *tx; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+2+strlen(newemail)))) - return -1; + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newemail)))) + return -ENOMEM; - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0007, 0x0004, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid); - i += aim_puttlv_str(newpacket->data+i, 0x0011, strlen(newemail), newemail); + aim_addtlvtochain_raw(&tl, 0x0011, strlen(newemail), newemail); + + aim_writetlvchain(&tx->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, tx); - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + return 0; } diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/adverts.c --- a/src/protocols/oscar/adverts.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/adverts.c Sun Sep 09 10:07:14 2001 +0000 @@ -6,38 +6,34 @@ #define FAIM_INTERNAL #include -faim_export unsigned long aim_ads_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_ads_clientready(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 0x1a))) + return -ENOMEM; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 0x1a))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0002); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0002); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0013); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0013); - i+= aimutil_put16(newpacket->data+i, 0x0005); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&fr->data, 0x0005); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0001); - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return (sess->snac_nextid++); + return 0; } -faim_export unsigned long aim_ads_requestads(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_ads_requestads(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0005, 0x0002); + return aim_genericreq_n(sess, conn, 0x0005, 0x0002); } diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/aim.h --- a/src/protocols/oscar/aim.h Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/aim.h Sun Sep 09 10:07:14 2001 +0000 @@ -39,6 +39,13 @@ #include #endif +/* XXX adjust these based on autoconf-detected platform */ +typedef unsigned char fu8_t; +typedef unsigned short fu16_t; +typedef unsigned long fu32_t; +typedef fu32_t aim_snacid_t; +typedef fu16_t flap_seqnum_t; + #ifdef FAIM_USEPTHREADS #include #define faim_mutex_t pthread_mutex_t @@ -53,14 +60,20 @@ * means we don't have to do real locking. The * macros below do nothing really. They're a joke. * But they get it to compile. + * + * XXX NOTE that locking hasn't really been tested in a long time, + * and most code written after dec2000 --is not thread safe--. You'll + * want to audit locking use before you use less-than-library level + * concurrency. + * */ -#define faim_mutex_t char +#define faim_mutex_t fu8_t #define faim_mutex_init(x) *x = 0 #define faim_mutex_lock(x) while(*x != 0) {/* spin */}; *x = 1; #define faim_mutex_unlock(x) while(*x != 0) {/* spin spin spin */}; *x = 0; #define faim_mutex_destroy(x) while(*x != 0) {/* spiiiinnn */}; *x = 0; #elif defined(FAIM_USENOPLOCKS) -#define faim_mutex_t char +#define faim_mutex_t fu8_t #define faim_mutex_init(x) #define faim_mutex_lock(x) #define faim_mutex_unlock(x) @@ -164,39 +177,39 @@ * */ struct client_info_s { - char clientstring[100]; /* arbitrary size */ - int major; - int minor; - int build; - char country[3]; - char lang[3]; - int major2; - int minor2; - long unknown; + char clientstring[100]; /* arbitrary size */ + int major; + int minor; + int build; + char country[3]; + char lang[3]; + int major2; + int minor2; + long unknown; }; #define AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 { \ - "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \ - 0x0003, \ - 0x0005, \ - 0x0686, \ - "us", \ - "en", \ - 0x0004, \ - 0x0000, \ - 0x0000002a, \ + "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \ + 0x0003, \ + 0x0005, \ + 0x0686, \ + "us", \ + "en", \ + 0x0004, \ + 0x0000, \ + 0x0000002a, \ } #define AIM_CLIENTINFO_KNOWNGOOD_4_1_2010 { \ - "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \ - 0x0004, \ - 0x0001, \ - 0x07da, \ - "us", \ - "en", \ - 0x0004, \ - 0x0000, \ - 0x0000004b, \ + "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \ + 0x0004, \ + 0x0001, \ + 0x07da, \ + "us", \ + "en", \ + 0x0004, \ + 0x0000, \ + 0x0000004b, \ } /* @@ -224,7 +237,7 @@ #define AIM_CONN_TYPE_CHATNAV 0x000d /* they start getting arbitrary in rendezvous stuff =) */ -#define AIM_CONN_TYPE_RENDEZVOUS 0x0101 /* these do not speak OSCAR! */ +#define AIM_CONN_TYPE_RENDEZVOUS 0x0101 /* these do not speak FLAP! */ #define AIM_CONN_TYPE_RENDEZVOUS_OUT 0x0102 /* socket waiting for accept() */ /* @@ -245,145 +258,155 @@ #define AIM_CONN_STATUS_CONNERR 0x0080 #define AIM_CONN_STATUS_INPROGRESS 0x0100 -#define AIM_FRAMETYPE_OSCAR 0x0000 -#define AIM_FRAMETYPE_OFT 0x0001 +#define AIM_FRAMETYPE_FLAP 0x0000 +#define AIM_FRAMETYPE_OFT 0x0001 -struct aim_conn_t { - int fd; - unsigned short type; - unsigned short subtype; - int seqnum; - int status; - void *priv; /* misc data the client may want to store */ - time_t lastactivity; /* time of last transmit */ - int forcedlatency; - struct aim_rxcblist_t *handlerlist; - faim_mutex_t active; /* lock around read/writes */ - faim_mutex_t seqnum_lock; /* lock around ->seqnum changes */ - void *sessv; - struct aim_conn_t *next; -}; +typedef struct aim_conn_s { + int fd; + fu16_t type; + fu16_t subtype; + flap_seqnum_t seqnum; + fu32_t status; + void *priv; /* misc data the client may want to store */ + void *internal; /* internal conn-specific libfaim data */ + time_t lastactivity; /* time of last transmit */ + int forcedlatency; + void *handlerlist; + faim_mutex_t active; /* lock around read/writes */ + faim_mutex_t seqnum_lock; /* lock around ->seqnum changes */ + void *sessv; /* pointer to parent session */ + struct aim_conn_s *next; +} aim_conn_t; -/* struct for incoming commands */ -struct command_rx_struct { - unsigned char hdrtype; /* defines which piece of the union to use */ - union { - struct { - char type; - unsigned short seqnum; - } oscar; - struct { - unsigned short type; - unsigned char magic[4]; /* ODC2 OFT2 */ - unsigned short hdr2len; - unsigned char *hdr2; /* rest of bloated header */ - } oft; - } hdr; - unsigned short commandlen; /* total payload length */ - unsigned char *data; /* packet data (from 7 byte on) */ - unsigned char lock; /* 0 = open, !0 = locked */ - unsigned char handled; /* 0 = new, !0 = been handled */ - unsigned char nofree; /* 0 = free data on purge, 1 = only unlink */ - struct aim_conn_t *conn; /* the connection it came in on... */ - struct command_rx_struct *next; /* ptr to next struct in list */ -}; +/* + * Byte Stream type. Sort of. + * + * Use of this type serves a couple purposes: + * - Buffer/buflen pairs are passed all around everywhere. This turns + * that into one value, as well as abstracting it slightly. + * - Through the abstraction, it is possible to enable bounds checking + * for robustness at the cost of performance. But a clean failure on + * weird packets is much better than a segfault. + * - I like having variables named "bs". + * + * Don't touch the insides of this struct. Or I'll have to kill you. + * + */ +typedef struct aim_bstream_s { + fu8_t *data; + fu16_t len; + fu16_t offset; +} aim_bstream_t; -/* struct for outgoing commands */ -struct command_tx_struct { - unsigned char hdrtype; /* defines which piece of the union to use */ - union { - struct { - unsigned char type; - unsigned short seqnum; - } oscar; - struct { - unsigned short type; - unsigned char magic[4]; /* ODC2 OFT2 */ - unsigned short hdr2len; - unsigned char *hdr2; - } oft; - } hdr; - u_int commandlen; - u_char *data; - u_int lock; /* 0 = open, !0 = locked */ - u_int sent; /* 0 = pending, !0 = has been sent */ - struct aim_conn_t *conn; - struct command_tx_struct *next; /* ptr to next struct in list */ -}; +typedef struct aim_frame_s { + fu8_t hdrtype; /* defines which piece of the union to use */ + union { + struct { + fu8_t type; + flap_seqnum_t seqnum; + } flap; + struct { + fu16_t type; + fu8_t magic[4]; /* ODC2 OFT2 */ + fu16_t hdr2len; + fu8_t *hdr2; /* rest of bloated header */ + } oft; + } hdr; + aim_bstream_t data; /* payload stream */ + fu8_t handled; /* 0 = new, !0 = been handled */ + fu8_t nofree; /* 0 = free data on purge, 1 = only unlink */ + aim_conn_t *conn; /* the connection it came in on... */ + struct aim_frame_s *next; +} aim_frame_t; + +typedef struct aim_msgcookie_s { + unsigned char cookie[8]; + int type; + void *data; + time_t addtime; + struct aim_msgcookie_s *next; +} aim_msgcookie_t; /* * AIM Session: The main client-data interface. * */ -struct aim_session_t { +typedef struct aim_session_s { + + /* ---- Client Accessible ------------------------ */ + + /* Our screen name. */ + char sn[MAXSNLEN+1]; + + /* + * Pointer to anything the client wants to + * explicitly associate with this session. + * + * This is for use in the callbacks mainly. In any + * callback, you can access this with sess->aux_data. + * + */ + void *aux_data; - /* ---- Client Accessible ------------------------ */ - /* - * Our screen name. - * - */ - char sn[MAXSNLEN+1]; - - /* - * Pointer to anything the client wants to - * explicitly associate with this session. - * - * This is for use in the callbacks mainly. In any - * callback, you can access this with sess->aux_data. - * - */ - void *aux_data; + /* ---- Internal Use Only ------------------------ */ + + /* Connection information */ + aim_conn_t *connlist; + faim_mutex_t connlistlock; + + /* + * Transmit/receive queues. + * + * These are only used when you don't use your own lowlevel + * I/O. I don't suggest that you use libfaim's internal I/O. + * Its really bad and the API/event model is quirky at best. + * + */ + aim_frame_t *queue_outgoing; + aim_frame_t *queue_incoming; - /* ---- Internal Use Only ------------------------ */ - /* - * Connection information - */ - struct aim_conn_t *connlist; - faim_mutex_t connlistlock; - - /* - * TX/RX queues - */ - struct command_tx_struct *queue_outgoing; - struct command_rx_struct *queue_incoming; - - /* - * Tx Enqueuing function - */ - int (*tx_enqueue)(struct aim_session_t *, struct command_tx_struct *); + /* + * Tx Enqueuing function. + * + * This is how you override the transmit direction of libfaim's + * internal I/O. This function will be called whenever it needs + * to send something. + * + */ + int (*tx_enqueue)(struct aim_session_s *, aim_frame_t *); + + /* + * This is a dreadful solution to the what-room-are-we-joining + * problem. (There's no connection between the service + * request and the resulting redirect.) + */ + char *pendingjoin; + fu16_t pendingjoinexchange; - /* - * This is a dreadful solution to the what-room-are-we-joining - * problem. (There's no connection between the service - * request and the resulting redirect.) - */ - char *pendingjoin; - unsigned short pendingjoinexchange; + /* + * Outstanding snac handling + * + * XXX: Should these be per-connection? -mid + */ + void *snac_hash[FAIM_SNAC_HASH_SIZE]; + faim_mutex_t snac_hash_locks[FAIM_SNAC_HASH_SIZE]; + aim_snacid_t snacid_next; - /* - * Outstanding snac handling - * - * XXX: Should these be per-connection? -mid - */ - struct aim_snac_t *snac_hash[FAIM_SNAC_HASH_SIZE]; - faim_mutex_t snac_hash_locks[FAIM_SNAC_HASH_SIZE]; - unsigned long snac_nextid; + struct { + char server[128]; + char username[128]; + char password[128]; + } socksproxy; + + fu32_t flags; /* AIM_SESS_FLAGS_ */ - struct { - char server[128]; - char username[128]; - char password[128]; - } socksproxy; - - unsigned long flags; + int debug; + void (*debugcb)(struct aim_session_s *sess, int level, const char *format, va_list va); /* same as faim_debugging_callback_t */ - int debug; - void (*debugcb)(struct aim_session_t *sess, int level, const char *format, va_list va); /* same as faim_debugging_callback_t */ + aim_msgcookie_t *msgcookies; - struct aim_msgcookie_t *msgcookies; - - void *modlistv; -}; + void *modlistv; +} aim_session_t; /* Values for sess->flags */ #define AIM_SESS_FLAGS_SNACLOGIN 0x00000001 @@ -394,19 +417,19 @@ * AIM User Info, Standard Form. */ struct aim_userinfo_s { - char sn[MAXSNLEN+1]; - u_short warnlevel; - u_short idletime; - u_short flags; - u_long membersince; - u_long onlinesince; - u_long sessionlen; - u_short capabilities; - struct { - unsigned short status; - unsigned int ipaddr; - char crap[0x25]; /* until we figure it out... */ - } icqinfo; + char sn[MAXSNLEN+1]; + fu16_t warnlevel; + fu16_t idletime; + fu16_t flags; + fu32_t membersince; + fu32_t onlinesince; + fu32_t sessionlen; + fu16_t capabilities; + struct { + fu16_t status; + fu32_t ipaddr; + fu8_t crap[0x25]; /* until we figure it out... */ + } icqinfo; }; #define AIM_FLAG_UNCONFIRMED 0x0001 /* "damned transients" */ @@ -427,112 +450,114 @@ */ /* Generic TLV structure. */ -struct aim_tlv_t { - u_short type; - u_short length; - u_char *value; -}; +typedef struct aim_tlv_s { + fu16_t type; + fu16_t length; + fu8_t *value; +} aim_tlv_t; /* List of above. */ -struct aim_tlvlist_t { - struct aim_tlv_t *tlv; - struct aim_tlvlist_t *next; -}; +typedef struct aim_tlvlist_s { + aim_tlv_t *tlv; + struct aim_tlvlist_s *next; +} aim_tlvlist_t; /* TLV-handling functions */ -faim_internal struct aim_tlvlist_t *aim_readtlvchain(const unsigned char *buf, const int maxlen); -faim_internal void aim_freetlvchain(struct aim_tlvlist_t **list); -faim_internal struct aim_tlv_t *aim_grabtlv(const unsigned char *src); -faim_internal struct aim_tlv_t *aim_grabtlvstr(const unsigned char *src); -faim_internal struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *, const unsigned short, const int); -faim_internal char *aim_gettlv_str(struct aim_tlvlist_t *, const unsigned short, const int); -faim_internal unsigned char aim_gettlv8(struct aim_tlvlist_t *list, const unsigned short type, const int num); -faim_internal unsigned short aim_gettlv16(struct aim_tlvlist_t *list, const unsigned short type, const int num); -faim_internal unsigned long aim_gettlv32(struct aim_tlvlist_t *list, const unsigned short type, const int num); -faim_internal int aim_puttlv (unsigned char *dest, struct aim_tlv_t *newtlv); -faim_internal struct aim_tlv_t *aim_createtlv(void); -faim_internal int aim_freetlv(struct aim_tlv_t **oldtlv); -faim_internal int aim_puttlv_8(unsigned char *buf, const unsigned short t, const unsigned char v); -faim_internal int aim_puttlv_16(unsigned char *, const unsigned short, const unsigned short); -faim_internal int aim_puttlv_32(unsigned char *, const unsigned short, const unsigned long); -faim_internal int aim_puttlv_str(u_char *buf, const unsigned short t, const int l, const char *v); -faim_internal int aim_writetlvchain(unsigned char *buf, const int buflen, struct aim_tlvlist_t **list); -faim_internal int aim_addtlvtochain16(struct aim_tlvlist_t **list, const unsigned short type, const unsigned short val); -faim_internal int aim_addtlvtochain32(struct aim_tlvlist_t **list, const unsigned short type, const unsigned long val); -faim_internal int aim_addtlvtochain_str(struct aim_tlvlist_t **list, const unsigned short type, const char *str, const int len); -faim_internal int aim_addtlvtochain_caps(struct aim_tlvlist_t **list, const unsigned short type, const unsigned short caps); -faim_internal int aim_addtlvtochain_noval(struct aim_tlvlist_t **list, const unsigned short type); -faim_internal int aim_counttlvchain(struct aim_tlvlist_t **list); + +#if 0 +/* Very, very raw TLV handling. */ +faim_internal int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v); +faim_internal int aim_puttlv_16(fu8_t *buf, const fu16_t t, const fu16_t v); +faim_internal int aim_puttlv_32(fu8_t *buf, const fu16_t t, const fu32_t v); +faim_internal int aim_puttlv_raw(fu8_t *buf, const fu16_t t, const fu16_t l, const fu8_t *v); +#endif + +/* TLV list handling. */ +faim_internal aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs); +faim_internal void aim_freetlvchain(aim_tlvlist_t **list); +faim_internal aim_tlv_t *aim_gettlv(aim_tlvlist_t *, fu16_t t, const int n); +faim_internal char *aim_gettlv_str(aim_tlvlist_t *, const fu16_t t, const int n); +faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t type, const int num); +faim_internal fu16_t aim_gettlv16(aim_tlvlist_t *list, const fu16_t t, const int n); +faim_internal fu32_t aim_gettlv32(aim_tlvlist_t *list, const fu16_t t, const int n); +faim_internal int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list); +faim_internal int aim_addtlvtochain16(aim_tlvlist_t **list, const fu16_t t, const fu16_t v); +faim_internal int aim_addtlvtochain32(aim_tlvlist_t **list, const fu16_t type, const fu32_t v); +faim_internal int aim_addtlvtochain_raw(aim_tlvlist_t **list, const fu16_t t, const fu16_t l, const fu8_t *v); +faim_internal int aim_addtlvtochain_caps(aim_tlvlist_t **list, const fu16_t t, const fu16_t caps); +faim_internal int aim_addtlvtochain_noval(aim_tlvlist_t **list, const fu16_t type); +faim_internal int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl); +faim_internal int aim_counttlvchain(aim_tlvlist_t **list); +faim_export int aim_sizetlvchain(aim_tlvlist_t **list); #endif /* FAIM_INTERNAL */ /* - * Get command from connections / Dispatch commands - * already in queue. + * Get command from connections + * + * aim_get_commmand() is the libfaim lowlevel I/O in the receive direction. + * XXX Make this easily overridable. + * */ -faim_export int aim_get_command(struct aim_session_t *, struct aim_conn_t *); -int aim_rxdispatch(struct aim_session_t *); +faim_export int aim_get_command(aim_session_t *, aim_conn_t *); -faim_export unsigned long aim_debugconn_sendconnect(struct aim_session_t *sess, struct aim_conn_t *conn); +/* + * Dispatch commands that are in the rx queue. + */ +faim_export void aim_rxdispatch(aim_session_t *); -faim_export int aim_logoff(struct aim_session_t *); +faim_export int aim_debugconn_sendconnect(aim_session_t *sess, aim_conn_t *conn); + +faim_export int aim_logoff(aim_session_t *); #if !defined(FAIM_INTERNAL) || defined(FAIM_INTERNAL_INSANE) /* the library should never call aim_conn_kill */ -faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn); +faim_export void aim_conn_kill(aim_session_t *sess, aim_conn_t **deadconn); #endif -typedef int (*aim_rxcallback_t)(struct aim_session_t *, struct command_rx_struct *, ...); +typedef int (*aim_rxcallback_t)(aim_session_t *, aim_frame_t *, ...); /* aim_login.c */ -faim_export int aim_sendflapver(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export int aim_request_login (struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn); -faim_export int aim_send_login (struct aim_session_t *, struct aim_conn_t *, char *, char *, struct client_info_s *, char *key); +faim_export int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn); +faim_export int aim_send_login(aim_session_t *, aim_conn_t *, const char *, const char *, struct client_info_s *, const char *key); faim_export int aim_encode_password_md5(const char *password, const char *key, unsigned char *digest); -faim_export unsigned long aim_sendauthresp(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, int errorcode, char *errorurl, char *bosip, char *cookie, char *email, int regstatus); +faim_export int aim_sendauthresp(aim_session_t *sess, aim_conn_t *conn, const char *sn, int errorcode, const char *errorurl, const char *bosip, const char *cookie, const char *email, int regstatus); faim_export int aim_gencookie(unsigned char *buf); -faim_export int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_sendredirect(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short servid, char *ip, char *cookie); -faim_export void aim_purge_rxqueue(struct aim_session_t *); +faim_export int aim_sendserverready(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_sendredirect(aim_session_t *sess, aim_conn_t *conn, fu16_t servid, const char *ip, const char *cookie); +faim_export void aim_purge_rxqueue(aim_session_t *); #define AIM_TX_QUEUED 0 /* default */ #define AIM_TX_IMMEDIATE 1 #define AIM_TX_USER 2 -faim_export int aim_tx_setenqueue(struct aim_session_t *sess, int what, int (*func)(struct aim_session_t *, struct command_tx_struct *)); +faim_export int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *)); -faim_export int aim_tx_flushqueue(struct aim_session_t *); -faim_export void aim_tx_purgequeue(struct aim_session_t *); +faim_export int aim_tx_flushqueue(aim_session_t *); +faim_export void aim_tx_purgequeue(aim_session_t *); -struct aim_rxcblist_t { - u_short family; - u_short type; - aim_rxcallback_t handler; - u_short flags; - struct aim_rxcblist_t *next; -}; +faim_export int aim_conn_setlatency(aim_conn_t *conn, int newval); -faim_export int aim_conn_setlatency(struct aim_conn_t *conn, int newval); - -faim_export int aim_conn_addhandler(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short type, aim_rxcallback_t newhandler, u_short flags); -faim_export int aim_clearhandlers(struct aim_conn_t *conn); +faim_export int aim_conn_addhandler(aim_session_t *, aim_conn_t *conn, u_short family, u_short type, aim_rxcallback_t newhandler, u_short flags); +faim_export int aim_clearhandlers(aim_conn_t *conn); -faim_export struct aim_session_t *aim_conn_getsess(struct aim_conn_t *conn); -faim_export void aim_conn_close(struct aim_conn_t *deadconn); -faim_export struct aim_conn_t *aim_newconn(struct aim_session_t *, int type, char *dest); -faim_export int aim_conngetmaxfd(struct aim_session_t *); -faim_export struct aim_conn_t *aim_select(struct aim_session_t *, struct timeval *, int *); -faim_export int aim_conn_isready(struct aim_conn_t *); -faim_export int aim_conn_setstatus(struct aim_conn_t *, int); -faim_export int aim_conn_completeconnect(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export int aim_conn_isconnecting(struct aim_conn_t *conn); +faim_export aim_session_t *aim_conn_getsess(aim_conn_t *conn); +faim_export void aim_conn_close(aim_conn_t *deadconn); +faim_export aim_conn_t *aim_newconn(aim_session_t *, int type, const char *dest); +faim_export int aim_conngetmaxfd(aim_session_t *); +faim_export aim_conn_t *aim_select(aim_session_t *, struct timeval *, int *); +faim_export int aim_conn_isready(aim_conn_t *); +faim_export int aim_conn_setstatus(aim_conn_t *, int); +faim_export int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_conn_isconnecting(aim_conn_t *conn); -typedef void (*faim_debugging_callback_t)(struct aim_session_t *sess, int level, const char *format, va_list va); -faim_export int aim_setdebuggingcb(struct aim_session_t *sess, faim_debugging_callback_t); -faim_export void aim_session_init(struct aim_session_t *, unsigned long flags, int debuglevel); -faim_export void aim_session_kill(struct aim_session_t *); -faim_export void aim_setupproxy(struct aim_session_t *sess, char *server, char *username, char *password); -faim_export struct aim_conn_t *aim_getconn_type(struct aim_session_t *, int type); -faim_export struct aim_conn_t *aim_getconn_type_all(struct aim_session_t *, int type); -faim_export struct aim_conn_t *aim_getconn_fd(struct aim_session_t *, int fd); +typedef void (*faim_debugging_callback_t)(aim_session_t *sess, int level, const char *format, va_list va); +faim_export int aim_setdebuggingcb(aim_session_t *sess, faim_debugging_callback_t); +faim_export void aim_session_init(aim_session_t *, unsigned long flags, int debuglevel); +faim_export void aim_session_kill(aim_session_t *); +faim_export void aim_setupproxy(aim_session_t *sess, const char *server, const char *username, const char *password); +faim_export aim_conn_t *aim_getconn_type(aim_session_t *, int type); +faim_export aim_conn_t *aim_getconn_type_all(aim_session_t *, int type); +faim_export aim_conn_t *aim_getconn_fd(aim_session_t *, int fd); /* aim_misc.c */ @@ -546,36 +571,29 @@ #define AIM_WARN_ANON 0x01 -faim_export int aim_send_warning(struct aim_session_t *sess, struct aim_conn_t *conn, const char *destsn, unsigned long flags); -faim_export unsigned long aim_bos_nop(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_flap_nop(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_bos_setidle(struct aim_session_t *, struct aim_conn_t *, u_long); -faim_export unsigned long aim_bos_changevisibility(struct aim_session_t *, struct aim_conn_t *, int, char *); -faim_export unsigned long aim_bos_setbuddylist(struct aim_session_t *, struct aim_conn_t *, char *); -faim_export unsigned long aim_bos_setprofile(struct aim_session_t *sess, struct aim_conn_t *conn, const char *profile, const char *awaymsg, unsigned short caps); -faim_export unsigned long aim_bos_setgroupperm(struct aim_session_t *, struct aim_conn_t *, u_long); -faim_export unsigned long aim_bos_clientready(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_reqrate(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_ackrateresp(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_setprivacyflags(struct aim_session_t *, struct aim_conn_t *, u_long); -faim_export unsigned long aim_bos_reqpersonalinfo(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_reqservice(struct aim_session_t *, struct aim_conn_t *, u_short); -faim_export unsigned long aim_bos_reqrights(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_reqbuddyrights(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_reqlocaterights(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_setversions(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_auth_setversions(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_auth_reqconfirm(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_auth_getinfo(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short info); -faim_export unsigned long aim_auth_setemail(struct aim_session_t *sess, struct aim_conn_t *conn, char *newemail); -faim_export unsigned long aim_setdirectoryinfo(struct aim_session_t *sess, struct aim_conn_t *conn, char *first, char *middle, char *last, char *maiden, char *nickname, char *street, char *city, char *state, char *zip, int country, unsigned short privacy); -faim_export unsigned long aim_setuserinterests(struct aim_session_t *sess, struct aim_conn_t *conn, char *interest1, char *interest2, char *interest3, char *interest4, char *interest5, unsigned short privacy); -faim_export unsigned long aim_icq_setstatus(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long status); +faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags); +faim_export int aim_bos_nop(aim_session_t *, aim_conn_t *); +faim_export int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_bos_setidle(aim_session_t *, aim_conn_t *, fu32_t); +faim_export int aim_bos_changevisibility(aim_session_t *, aim_conn_t *, int, const char *); +faim_export int aim_bos_setbuddylist(aim_session_t *, aim_conn_t *, const char *); +faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu16_t caps); +faim_export int aim_bos_setgroupperm(aim_session_t *, aim_conn_t *, fu32_t mask); +faim_export int aim_bos_clientready(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_reqrate(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_ackrateresp(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_setprivacyflags(aim_session_t *, aim_conn_t *, fu32_t); +faim_export int aim_bos_reqpersonalinfo(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_reqservice(aim_session_t *, aim_conn_t *, fu16_t); +faim_export int aim_bos_reqrights(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_reqbuddyrights(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_reqlocaterights(aim_session_t *, aim_conn_t *); +faim_export int aim_setversions(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_setdirectoryinfo(aim_session_t *sess, aim_conn_t *conn, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, fu16_t privacy); +faim_export int aim_setuserinterests(aim_session_t *sess, aim_conn_t *conn, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, fu16_t privacy); +faim_export int aim_icq_setstatus(aim_session_t *sess, aim_conn_t *conn, fu32_t status); -faim_export struct aim_fileheader_t *aim_getlisting(struct aim_session_t *sess, FILE *); - -/* aim_rxhandlers.c */ -faim_export int aim_rxdispatch(struct aim_session_t *); +faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *); #define AIM_CLIENTTYPE_UNKNOWN 0x0000 #define AIM_CLIENTTYPE_MC 0x0001 @@ -588,49 +606,44 @@ #define AIM_RATE_CODE_WARNING 0x0002 #define AIM_RATE_CODE_LIMIT 0x0003 #define AIM_RATE_CODE_CLEARLIMIT 0x0004 -faim_export unsigned long aim_ads_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_ads_requestads(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_export int aim_ads_clientready(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_ads_requestads(aim_session_t *sess, aim_conn_t *conn); /* aim_im.c */ -struct aim_directim_priv { - unsigned char cookie[8]; - char sn[MAXSNLEN+1]; - char ip[30]; -}; struct aim_fileheader_t { #if 0 - char magic[4]; /* 0 */ - short hdrlen; /* 4 */ - short hdrtype; /* 6 */ + char magic[4]; /* 0 */ + short hdrlen; /* 4 */ + short hdrtype; /* 6 */ #endif - char bcookie[8]; /* 8 */ - short encrypt; /* 16 */ - short compress; /* 18 */ - short totfiles; /* 20 */ - short filesleft; /* 22 */ - short totparts; /* 24 */ - short partsleft; /* 26 */ - long totsize; /* 28 */ - long size; /* 32 */ - long modtime; /* 36 */ - long checksum; /* 40 */ - long rfrcsum; /* 44 */ - long rfsize; /* 48 */ - long cretime; /* 52 */ - long rfcsum; /* 56 */ - long nrecvd; /* 60 */ - long recvcsum; /* 64 */ - char idstring[32]; /* 68 */ - char flags; /* 100 */ - char lnameoffset; /* 101 */ - char lsizeoffset; /* 102 */ - char dummy[69]; /* 103 */ - char macfileinfo[16]; /* 172 */ - short nencode; /* 188 */ - short nlanguage; /* 190 */ - char name[64]; /* 192 */ - /* 256 */ + char bcookie[8]; /* 8 */ + short encrypt; /* 16 */ + short compress; /* 18 */ + short totfiles; /* 20 */ + short filesleft; /* 22 */ + short totparts; /* 24 */ + short partsleft; /* 26 */ + long totsize; /* 28 */ + long size; /* 32 */ + long modtime; /* 36 */ + long checksum; /* 40 */ + long rfrcsum; /* 44 */ + long rfsize; /* 48 */ + long cretime; /* 52 */ + long rfcsum; /* 56 */ + long nrecvd; /* 60 */ + long recvcsum; /* 64 */ + char idstring[32]; /* 68 */ + char flags; /* 100 */ + char lnameoffset; /* 101 */ + char lsizeoffset; /* 102 */ + char dummy[69]; /* 103 */ + char macfileinfo[16]; /* 172 */ + short nencode; /* 188 */ + short nlanguage; /* 190 */ + char name[64]; /* 192 */ + /* 256 */ }; struct aim_filetransfer_priv { @@ -647,52 +660,73 @@ unsigned short instance; }; -#define AIM_IMFLAGS_AWAY 0x01 /* mark as an autoreply */ -#define AIM_IMFLAGS_ACK 0x02 /* request a receipt notice */ -#define AIM_IMFLAGS_UNICODE 0x04 -#define AIM_IMFLAGS_ISO_8859_1 0x08 -#define AIM_IMFLAGS_BUDDYREQ 0x10 /* buddy icon requested */ -#define AIM_IMFLAGS_HASICON 0x20 /* already has icon (timestamp included) */ -#define AIM_IMFLAGS_SUBENC_MACINTOSH 0x40 /* damn that Steve Jobs! */ +#define AIM_IMFLAGS_AWAY 0x0001 /* mark as an autoreply */ +#define AIM_IMFLAGS_ACK 0x0002 /* request a receipt notice */ +#define AIM_IMFLAGS_UNICODE 0x0004 +#define AIM_IMFLAGS_ISO_8859_1 0x0008 +#define AIM_IMFLAGS_BUDDYREQ 0x0010 /* buddy icon requested */ +#define AIM_IMFLAGS_HASICON 0x0020 /* already has icon */ +#define AIM_IMFLAGS_SUBENC_MACINTOSH 0x0040 /* damn that Steve Jobs! */ +#define AIM_IMFLAGS_CUSTOMFEATURES 0x0080 /* features field present */ +#define AIM_IMFLAGS_EXTDATA 0x0100 struct aim_sendimext_args { + + /* These are _required_ */ const char *destsn; - unsigned short flags; + fu32_t flags; const char *msg; int msglen; - int iconlen; + + /* Only used if AIM_IMFLAGS_HASICON is set */ + fu32_t iconlen; time_t iconstamp; - unsigned short iconsum; + fu32_t iconsum; + + /* Only used if AIM_IMFLAGS_CUSTOMFEATURES is set */ + fu8_t *features; + fu8_t featureslen; }; struct aim_incomingim_ch1_args { + + /* Always provided */ char *msg; int msglen; - unsigned long icbmflags; - unsigned short flag1; - unsigned short flag2; - int finlen; - unsigned char fingerprint[10]; + fu32_t icbmflags; + fu16_t flag1; + fu16_t flag2; + + /* Only provided if AIM_IMFLAGS_HASICON is set */ time_t iconstamp; - unsigned long iconlength; - unsigned long iconchecksum; - int extdatalen; - unsigned char *extdata; + fu32_t iconlen; + fu32_t iconsum; + + /* Only provided if AIM_IMFLAGS_CUSTOMFEATURES is set */ + fu8_t *features; + fu8_t featureslen; + + /* Only provided if AIM_IMFLAGS_EXTDATA is set */ + fu8_t extdatalen; + fu8_t *extdata; }; struct aim_incomingim_ch2_args { - unsigned short reqclass; - unsigned short status; + fu8_t cookie[8]; + fu16_t reqclass; + fu16_t status; union { struct { - unsigned long checksum; - unsigned int length; + fu32_t checksum; + fu32_t length; time_t timestamp; - unsigned char *icon; + fu8_t *icon; } icon; struct { } voice; - struct aim_directim_priv *directim; + struct { + fu8_t ip[22]; /* xxx.xxx.xxx.xxx:xxxxx\0 */ + } imimage; struct { char *msg; char *encoding; @@ -708,18 +742,19 @@ } info; }; -faim_export int aim_send_im_ext(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_sendimext_args *args); -faim_export int aim_send_im(struct aim_session_t *, struct aim_conn_t *, const char *destsn, unsigned short flags, const char *msg); -faim_export int aim_send_icon(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn, const unsigned char *icon, int iconlen, time_t stamp, unsigned short iconsum); -faim_export unsigned short aim_iconsum(const unsigned char *buf, int buflen); -faim_export int aim_send_im_direct(struct aim_session_t *, struct aim_conn_t *, char *); -faim_export struct aim_conn_t * aim_directim_initiate(struct aim_session_t *, struct aim_conn_t *, struct aim_directim_priv *, char *destsn); -faim_export struct aim_conn_t *aim_directim_connect(struct aim_session_t *, struct aim_conn_t *, struct aim_directim_priv *); +faim_export int aim_send_im_ext(aim_session_t *sess, aim_conn_t *conn, struct aim_sendimext_args *args); +faim_export int aim_send_im(aim_session_t *, aim_conn_t *, const char *destsn, unsigned short flags, const char *msg); +faim_export int aim_send_icon(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu32_t iconsum); +faim_export fu32_t aim_iconsum(const fu8_t *buf, int buflen); +faim_export int aim_send_im_direct(aim_session_t *, aim_conn_t *, const char *msg); +faim_export const char *aim_directim_getsn(aim_conn_t *conn); +faim_export aim_conn_t *aim_directim_initiate(aim_session_t *, aim_conn_t *, const char *destsn); +faim_export aim_conn_t *aim_directim_connect(aim_session_t *, const char *sn, const char *addr, const fu8_t *cookie); -faim_export struct aim_conn_t *aim_getfile_initiate(struct aim_session_t *sess, struct aim_conn_t *conn, char *destsn); -faim_export int aim_oft_getfile_request(struct aim_session_t *sess, struct aim_conn_t *conn, const unsigned char *name, const int size); -faim_export int aim_oft_getfile_ack(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export int aim_oft_getfile_end(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn); +faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size); +faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_oft_getfile_end(aim_session_t *sess, aim_conn_t *conn); /* aim_info.c */ #define AIM_CAPS_BUDDYICON 0x0001 @@ -734,29 +769,21 @@ #define AIM_CAPS_GAMES2 0x0200 #define AIM_CAPS_LAST 0x8000 -faim_export int aim_0002_000b(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn); +faim_export int aim_0002_000b(aim_session_t *sess, aim_conn_t *conn, const char *sn); #define AIM_SENDMEMBLOCK_FLAG_ISREQUEST 0 #define AIM_SENDMEMBLOCK_FLAG_ISHASH 1 -faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag); +faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag); #define AIM_GETINFO_GENERALINFO 0x00001 #define AIM_GETINFO_AWAYMESSAGE 0x00003 -struct aim_msgcookie_t { - unsigned char cookie[8]; - int type; - void *data; - time_t addtime; - struct aim_msgcookie_t *next; -}; - struct aim_invite_priv { - char *sn; - char *roomname; - int exchange; - int instance; + char *sn; + char *roomname; + fu16_t exchange; + fu16_t instance; }; #define AIM_COOKIETYPE_UNKNOWN 0x00 @@ -776,17 +803,17 @@ #define AIM_COOKIETYPE_OFTIMAGE 0x14 #define AIM_COOKIETYPE_OFTICON 0x15 -faim_export int aim_handlerendconnect(struct aim_session_t *sess, struct aim_conn_t *cur); +faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur); #define AIM_TRANSFER_DENY_NOTSUPPORTED 0x0000 #define AIM_TRANSFER_DENY_DECLINE 0x0001 #define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002 -faim_export int aim_denytransfer(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sender, const 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 int aim_denytransfer(aim_session_t *sess, aim_conn_t *conn, const char *sender, const char *cookie, unsigned short code); +faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *cookie, const fu8_t *ip, fu16_t listingfiles, fu16_t listingtotsize, fu16_t listingsize, fu32_t listingchecksum, fu16_t rendid); -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); +faim_export int aim_getinfo(aim_session_t *, aim_conn_t *, const char *, unsigned short); +faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *info); +faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn); #define AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED 0x00000001 #define AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED 0x00000002 @@ -819,79 +846,78 @@ unsigned long minmsginterval; /* in milliseconds? */ }; -faim_export unsigned long aim_reqicbmparams(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_seticbmparam(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_icbmparameters *params); +faim_export int aim_reqicbmparams(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_seticbmparam(aim_session_t *sess, aim_conn_t *conn, struct aim_icbmparameters *params); -/* aim_auth.c */ -faim_export int aim_auth_sendcookie(struct aim_session_t *, struct aim_conn_t *, u_char *); -faim_export u_long aim_auth_clientready(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_auth_changepasswd(struct aim_session_t *, struct aim_conn_t *, char *, char *); +/* auth.c */ +faim_export int aim_auth_sendcookie(aim_session_t *, aim_conn_t *, const fu8_t *); + +faim_export int aim_auth_clientready(aim_session_t *, aim_conn_t *); +faim_export int aim_auth_changepasswd(aim_session_t *, aim_conn_t *, const char *newpw, const char *curpw); +faim_export int aim_auth_setversions(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_auth_reqconfirm(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_auth_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info); +faim_export int aim_auth_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail); /* aim_buddylist.c */ -faim_export unsigned long aim_add_buddy(struct aim_session_t *, struct aim_conn_t *, char *); -faim_export unsigned long aim_remove_buddy(struct aim_session_t *, struct aim_conn_t *, char *); +faim_export int aim_add_buddy(aim_session_t *, aim_conn_t *, const char *); +faim_export int aim_remove_buddy(aim_session_t *, aim_conn_t *, const char *); /* aim_search.c */ -faim_export u_long aim_usersearch_address(struct aim_session_t *, struct aim_conn_t *, char *); +faim_export int aim_usersearch_address(aim_session_t *, aim_conn_t *, const char *); struct aim_chat_exchangeinfo { - u_short number; - char *name; - char *charset1; - char *lang1; - char *charset2; - char *lang2; + fu16_t number; + char *name; + char *charset1; + char *lang1; + char *charset2; + char *lang2; }; #define AIM_CHATFLAGS_NOREFLECT 0x0001 #define AIM_CHATFLAGS_AWAY 0x0002 -faim_export unsigned long aim_chat_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short flags, const char *msg, int msglen); -faim_export unsigned long aim_chat_join(struct aim_session_t *sess, struct aim_conn_t *conn, u_short exchange, const char *roomname); -faim_export unsigned long aim_chat_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export int aim_chat_attachname(struct aim_conn_t *conn, char *roomname); -faim_export char *aim_chat_getname(struct aim_conn_t *conn); -faim_export struct aim_conn_t *aim_chat_getconn(struct aim_session_t *, char *name); +faim_export int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, fu16_t flags, const char *msg, int msglen); +faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance); +faim_export int aim_chat_clientready(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_chat_attachname(aim_conn_t *conn, const char *roomname); +faim_export char *aim_chat_getname(aim_conn_t *conn); +faim_export aim_conn_t *aim_chat_getconn(aim_session_t *, const char *name); -faim_export unsigned long aim_chatnav_reqrights(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_chatnav_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_chatnav_clientready(aim_session_t *sess, aim_conn_t *conn); -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_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance); -faim_export u_long aim_chatnav_createroom(struct aim_session_t *sess, struct aim_conn_t *conn, char *name, u_short exchange); -faim_export int aim_chat_leaveroom(struct aim_session_t *sess, char *name); +faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange); +faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name); /* aim_util.c */ -#ifdef AIMUTIL_USEMACROS /* * These are really ugly. You'd think this was LISP. I wish it was. + * + * XXX With the advent of bstream's, these should be removed to enforce + * their use. + * */ #define aimutil_put8(buf, data) ((*(buf) = (u_char)(data)&0xff),1) #define aimutil_get8(buf) ((*(buf))&0xff) #define aimutil_put16(buf, data) ( \ - (*(buf) = (u_char)((data)>>8)&0xff), \ - (*((buf)+1) = (u_char)(data)&0xff), \ - 2) + (*(buf) = (u_char)((data)>>8)&0xff), \ + (*((buf)+1) = (u_char)(data)&0xff), \ + 2) #define aimutil_get16(buf) ((((*(buf))<<8)&0xff00) + ((*((buf)+1)) & 0xff)) #define aimutil_put32(buf, data) ( \ - (*((buf)) = (u_char)((data)>>24)&0xff), \ - (*((buf)+1) = (u_char)((data)>>16)&0xff), \ - (*((buf)+2) = (u_char)((data)>>8)&0xff), \ - (*((buf)+3) = (u_char)(data)&0xff), \ - 4) + (*((buf)) = (u_char)((data)>>24)&0xff), \ + (*((buf)+1) = (u_char)((data)>>16)&0xff), \ + (*((buf)+2) = (u_char)((data)>>8)&0xff), \ + (*((buf)+3) = (u_char)(data)&0xff), \ + 4) #define aimutil_get32(buf) ((((*(buf))<<24)&0xff000000) + \ - (((*((buf)+1))<<16)&0x00ff0000) + \ - (((*((buf)+2))<< 8)&0x0000ff00) + \ - (((*((buf)+3) )&0x000000ff))) -#else -#warning Not using aimutil macros. May have performance problems. -int aimutil_put8(u_char *, u_char); -u_char aimutil_get8(u_char *buf); -int aimutil_put16(u_char *, u_short); -u_short aimutil_get16(u_char *); -int aimutil_put32(u_char *, u_long); -u_long aimutil_get32(u_char *); -#endif + (((*((buf)+1))<<16)&0x00ff0000) + \ + (((*((buf)+2))<< 8)&0x0000ff00) + \ + (((*((buf)+3) )&0x000000ff))) faim_export int aimutil_putstr(u_char *, const char *, int); faim_export int aimutil_tokslen(char *toSearch, int index, char dl); diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/aim_internal.h --- a/src/protocols/oscar/aim_internal.h Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/aim_internal.h Sun Sep 09 10:07:14 2001 +0000 @@ -8,88 +8,109 @@ #define __AIM_INTERNAL_H__ 1 typedef struct { - unsigned short family; - unsigned short subtype; - unsigned short flags; - unsigned long id; + fu16_t family; + fu16_t subtype; + fu16_t flags; + fu32_t id; } aim_modsnac_t; #define AIM_MODULENAME_MAXLEN 16 #define AIM_MODFLAG_MULTIFAMILY 0x0001 typedef struct aim_module_s { - unsigned short family; - unsigned short flags; - unsigned short version; - char name[AIM_MODULENAME_MAXLEN+1]; - int (*snachandler)(struct aim_session_t *sess, struct aim_module_s *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen); - void (*shutdown)(struct aim_session_t *sess, struct aim_module_s *mod); - void *priv; - struct aim_module_s *next; + unsigned short family; + unsigned short flags; + unsigned short version; + char name[AIM_MODULENAME_MAXLEN+1]; + int (*snachandler)(aim_session_t *sess, struct aim_module_s *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs); + void (*shutdown)(aim_session_t *sess, struct aim_module_s *mod); + void *priv; + struct aim_module_s *next; } aim_module_t; -faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst)(struct aim_session_t *, aim_module_t *)); -faim_internal void aim__shutdownmodules(struct aim_session_t *sess); +faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *)); +faim_internal void aim__shutdownmodules(aim_session_t *sess); -faim_internal int buddylist_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int admin_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int bos_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int search_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int stats_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int auth_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int msg_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int misc_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int chatnav_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int chat_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int locate_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int general_modfirst(struct aim_session_t *sess, aim_module_t *mod); +faim_internal int buddylist_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int bos_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int search_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int stats_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int auth_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int misc_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int chatnav_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int chat_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int locate_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod); + +faim_internal int aim_genericreq_n(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype); +faim_internal int aim_genericreq_n_snacid(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype); +faim_internal int aim_genericreq_l(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype, fu32_t *); +faim_internal int aim_genericreq_s(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype, fu16_t *); + +#define AIMBS_CURPOSPAIR(x) ((x)->data + (x)->offset), ((x)->len - (x)->offset) -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_n_snacid(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype); -faim_internal unsigned long aim_genericreq_l(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype, u_long *); -faim_internal unsigned long aim_genericreq_s(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype, u_short *); - -faim_internal void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn); faim_internal int aim_recv(int fd, void *buf, size_t count); - -faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count); +faim_internal int aim_bstream_init(aim_bstream_t *bs, fu8_t *data, int len); +faim_internal int aim_bstream_empty(aim_bstream_t *bs); +faim_internal int aim_bstream_curpos(aim_bstream_t *bs); +faim_internal int aim_bstream_setpos(aim_bstream_t *bs, int off); +faim_internal void aim_bstream_rewind(aim_bstream_t *bs); +faim_internal int aim_bstream_advance(aim_bstream_t *bs, int n); +faim_internal fu8_t aimbs_get8(aim_bstream_t *bs); +faim_internal fu16_t aimbs_get16(aim_bstream_t *bs); +faim_internal fu32_t aimbs_get32(aim_bstream_t *bs); +faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v); +faim_internal int aimbs_put16(aim_bstream_t *bs, fu16_t v); +faim_internal int aimbs_put32(aim_bstream_t *bs, fu32_t v); +faim_internal int aimbs_getrawbuf(aim_bstream_t *bs, fu8_t *buf, int len); +faim_internal fu8_t *aimbs_getraw(aim_bstream_t *bs, int len); +faim_internal char *aimbs_getstr(aim_bstream_t *bs, int len); +faim_internal int aimbs_putraw(aim_bstream_t *bs, const fu8_t *v, int len); +faim_internal int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len); -faim_internal int aim_tx_sendframe(struct aim_session_t *sess, struct command_tx_struct *cur); -faim_internal unsigned int aim_get_next_txseqnum(struct aim_conn_t *); -faim_internal struct command_tx_struct *aim_tx_new(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned char framing, int chan, int datalen); -faim_internal int aim_tx_enqueue(struct aim_session_t *, struct command_tx_struct *); -faim_internal int aim_tx_printqueue(struct aim_session_t *); -faim_internal int aim_tx_cleanqueue(struct aim_session_t *, struct aim_conn_t *); +faim_internal int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn); -faim_internal aim_rxcallback_t aim_callhandler(struct aim_session_t *sess, struct aim_conn_t *conn, u_short family, u_short type); -faim_internal int aim_callhandler_noparam(struct aim_session_t *sess, struct aim_conn_t *conn, u_short family, u_short type, struct command_rx_struct *ptr); +faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *cur); +faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *); +faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen); +faim_internal void aim_frame_destroy(aim_frame_t *); +faim_internal int aim_tx_enqueue(aim_session_t *, aim_frame_t *); +faim_internal int aim_tx_printqueue(aim_session_t *); +faim_internal void aim_tx_cleanqueue(aim_session_t *, aim_conn_t *); + +faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, u_short family, u_short type); +faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_frame_t *ptr); /* * Generic SNAC structure. Rarely if ever used. */ -struct aim_snac_t { - u_long id; - u_short family; - u_short type; - u_short flags; - void *data; - time_t issuetime; - struct aim_snac_t *next; -}; -faim_internal void aim_initsnachash(struct aim_session_t *sess); -faim_internal unsigned long aim_newsnac(struct aim_session_t *, struct aim_snac_t *newsnac); -faim_internal unsigned long aim_cachesnac(struct aim_session_t *sess, const unsigned short family, const unsigned short type, const unsigned short flags, const void *data, const int datalen); -faim_internal struct aim_snac_t *aim_remsnac(struct aim_session_t *, u_long id); -faim_internal int aim_cleansnacs(struct aim_session_t *, int maxage); -faim_internal int aim_putsnac(u_char *, int, int, int, u_long); +typedef struct aim_snac_s { + aim_snacid_t id; + fu16_t family; + fu16_t type; + fu16_t flags; + void *data; + time_t issuetime; + struct aim_snac_s *next; +} aim_snac_t; -faim_internal struct aim_conn_t *aim_cloneconn(struct aim_session_t *sess, struct aim_conn_t *src); +faim_internal void aim_initsnachash(aim_session_t *sess); +faim_internal aim_snacid_t aim_newsnac(aim_session_t *, aim_snac_t *newsnac); +faim_internal aim_snacid_t aim_cachesnac(aim_session_t *sess, const fu16_t family, const fu16_t type, const fu16_t flags, const void *data, const int datalen); +faim_internal aim_snac_t *aim_remsnac(aim_session_t *, aim_snacid_t id); +faim_internal void aim_cleansnacs(aim_session_t *, int maxage); +faim_internal int aim_putsnac(aim_bstream_t *, fu16_t family, fu16_t type, fu16_t flags, aim_snacid_t id); + +faim_internal aim_conn_t *aim_cloneconn(aim_session_t *sess, aim_conn_t *src); +faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src); faim_internal int aim_oft_buildheader(unsigned char *,struct aim_fileheader_t *); -faim_internal int aim_listenestablish(u_short); -faim_internal int aim_tx_destroy(struct command_tx_struct *); -faim_internal int aim_parse_unknown(struct aim_session_t *, struct command_rx_struct *, ...); +faim_internal int aim_parse_unknown(aim_session_t *, aim_frame_t *, ...); /* these are used by aim_*_clientready */ #define AIM_TOOL_JAVA 0x0001 @@ -100,35 +121,35 @@ #define AIM_TOOL_MACPPC 0x0006 #define AIM_TOOL_NEWWIN 0x0010 struct aim_tool_version { - unsigned short group; - unsigned short version; - unsigned short tool; - unsigned short toolversion; + fu16_t group; + fu16_t version; + fu16_t tool; + fu16_t toolversion; }; -faim_internal int aim_negchan_middle(struct aim_session_t *sess, struct command_rx_struct *command); +faim_internal fu16_t aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len); +faim_internal int aim_putcap(aim_bstream_t *bs, fu16_t caps); -faim_internal unsigned short aim_getcap(struct aim_session_t *sess, unsigned char *capblock, int buflen); -faim_internal int aim_putcap(unsigned char *capblock, int buflen, unsigned short caps); +faim_internal int aim_cachecookie(aim_session_t *sess, aim_msgcookie_t *cookie); +faim_internal aim_msgcookie_t *aim_uncachecookie(aim_session_t *sess, fu8_t *cookie, int type); +faim_internal aim_msgcookie_t *aim_mkcookie(fu8_t *, int, void *); +faim_internal aim_msgcookie_t *aim_checkcookie(aim_session_t *, const unsigned char *, const int); +faim_internal int aim_freecookie(aim_session_t *sess, aim_msgcookie_t *cookie); +faim_internal int aim_msgcookie_gettype(int reqclass); +faim_internal int aim_cookie_free(aim_session_t *sess, aim_msgcookie_t *cookie); -faim_internal int aim_cachecookie(struct aim_session_t *sess, struct aim_msgcookie_t *cookie); -faim_internal struct aim_msgcookie_t *aim_uncachecookie(struct aim_session_t *sess, unsigned char *cookie, int type); -faim_internal struct aim_msgcookie_t *aim_mkcookie(unsigned char *, int, void *); -faim_internal struct aim_msgcookie_t *aim_checkcookie(struct aim_session_t *, const unsigned char *, const int); -faim_internal int aim_freecookie(struct aim_session_t *sess, struct aim_msgcookie_t *cookie); -faim_internal int aim_msgcookie_gettype(int reqclass); -faim_internal int aim_cookie_free(struct aim_session_t *sess, struct aim_msgcookie_t *cookie); +faim_internal int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, struct aim_userinfo_s *); +faim_internal int aim_putuserinfo(aim_bstream_t *bs, struct aim_userinfo_s *info); + +faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo); -faim_internal int aim_extractuserinfo(struct aim_session_t *sess, unsigned char *, struct aim_userinfo_s *); -faim_internal int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info); +faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...); -faim_internal int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo); +faim_internal void aim_conn_close_rend(aim_session_t *sess, aim_conn_t *conn); +faim_internal void aim_conn_kill_rend(aim_session_t *sess, aim_conn_t *conn); -faim_internal void faimdprintf(struct aim_session_t *sess, int dlevel, const char *format, ...); #ifndef FAIM_INTERNAL_INSANE -/* why the hell wont cpp let you use #error inside #define's? */ -/* isn't it single-pass? so the #error would get passed to the compiler --jbm */ #define printf() printf called inside libfaim #define sprintf() unbounded sprintf used inside libfaim #endif diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/auth.c --- a/src/protocols/oscar/auth.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/auth.c Sun Sep 09 10:07:14 2001 +0000 @@ -1,33 +1,30 @@ /* - aim_auth.c - - Deals with the authorizer. - + * aim_auth.c + * + * Deals with the authorizer. + * */ #define FAIM_INTERNAL #include /* this just pushes the passed cookie onto the passed connection -- NO SNAC! */ -faim_export int aim_auth_sendcookie(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned char *chipsahoy) +faim_export int aim_auth_sendcookie(aim_session_t *sess, aim_conn_t *conn, const fu8_t *chipsahoy) { - struct command_tx_struct *newpacket; - int curbyte=0; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0001, 4+2+2+AIM_COOKIELEN))) - return -1; + aim_frame_t *fr; + aim_tlvlist_t *tl = NULL; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0001, 4+2+2+AIM_COOKIELEN))) + return -ENOMEM; - newpacket->lock = 1; + aimbs_put32(&fr->data, 0x00000001); + aim_addtlvtochain_raw(&tl, 0x0006, AIM_COOKIELEN, chipsahoy); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0006); - curbyte += aimutil_put16(newpacket->data+curbyte, AIM_COOKIELEN); - memcpy(newpacket->data+curbyte, chipsahoy, AIM_COOKIELEN); + aim_tx_enqueue(sess, fr); - return aim_tx_enqueue(sess, newpacket); + return 0; } /* @@ -39,137 +36,126 @@ * its nonzero, there was an error. * */ -static int parse(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int parse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_tlvlist_t *tlvlist; - int ret = 0; - aim_rxcallback_t userfunc; - char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL; - unsigned char *cookie = NULL; - int errorcode = 0, regstatus = 0; - int latestbuild = 0, latestbetabuild = 0; - char *latestrelease = NULL, *latestbeta = NULL; - char *latestreleaseurl = NULL, *latestbetaurl = NULL; - char *latestreleaseinfo = NULL, *latestbetainfo = NULL; + aim_tlvlist_t *tlvlist; + int ret = 0; + aim_rxcallback_t userfunc; + char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL; + unsigned char *cookie = NULL; + int errorcode = 0, regstatus = 0; + int latestbuild = 0, latestbetabuild = 0; + char *latestrelease = NULL, *latestbeta = NULL; + char *latestreleaseurl = NULL, *latestbetaurl = NULL; + char *latestreleaseinfo = NULL, *latestbetainfo = NULL; - /* - * Read block of TLVs. All further data is derived - * from what is parsed here. - * - */ - tlvlist = aim_readtlvchain(data, datalen); + /* + * Read block of TLVs. All further data is derived + * from what is parsed here. + */ + tlvlist = aim_readtlvchain(bs); - /* - * No matter what, we should have a screen name. - */ - memset(sess->sn, 0, sizeof(sess->sn)); - if (aim_gettlv(tlvlist, 0x0001, 1)) { - sn = aim_gettlv_str(tlvlist, 0x0001, 1); - strncpy(sess->sn, sn, sizeof(sess->sn)); - } + /* + * No matter what, we should have a screen name. + */ + memset(sess->sn, 0, sizeof(sess->sn)); + if (aim_gettlv(tlvlist, 0x0001, 1)) { + sn = aim_gettlv_str(tlvlist, 0x0001, 1); + strncpy(sess->sn, sn, sizeof(sess->sn)); + } - /* - * Check for an error code. If so, we should also - * have an error url. - */ - if (aim_gettlv(tlvlist, 0x0008, 1)) - errorcode = aim_gettlv16(tlvlist, 0x0008, 1); - if (aim_gettlv(tlvlist, 0x0004, 1)) - errurl = aim_gettlv_str(tlvlist, 0x0004, 1); + /* + * Check for an error code. If so, we should also + * have an error url. + */ + if (aim_gettlv(tlvlist, 0x0008, 1)) + errorcode = aim_gettlv16(tlvlist, 0x0008, 1); + if (aim_gettlv(tlvlist, 0x0004, 1)) + errurl = aim_gettlv_str(tlvlist, 0x0004, 1); - /* - * BOS server address. - */ - if (aim_gettlv(tlvlist, 0x0005, 1)) - bosip = aim_gettlv_str(tlvlist, 0x0005, 1); + /* + * BOS server address. + */ + if (aim_gettlv(tlvlist, 0x0005, 1)) + bosip = aim_gettlv_str(tlvlist, 0x0005, 1); - /* - * Authorization cookie. - */ - if (aim_gettlv(tlvlist, 0x0006, 1)) { - struct aim_tlv_t *tmptlv; + /* + * Authorization cookie. + */ + if (aim_gettlv(tlvlist, 0x0006, 1)) { + aim_tlv_t *tmptlv; - tmptlv = aim_gettlv(tlvlist, 0x0006, 1); + tmptlv = aim_gettlv(tlvlist, 0x0006, 1); - if ((cookie = malloc(tmptlv->length))) - memcpy(cookie, tmptlv->value, tmptlv->length); - } + if ((cookie = malloc(tmptlv->length))) + memcpy(cookie, tmptlv->value, tmptlv->length); + } - /* - * The email address attached to this account - * Not available for ICQ logins. - */ - if (aim_gettlv(tlvlist, 0x0011, 1)) - email = aim_gettlv_str(tlvlist, 0x0011, 1); + /* + * The email address attached to this account + * Not available for ICQ logins. + */ + if (aim_gettlv(tlvlist, 0x0011, 1)) + email = aim_gettlv_str(tlvlist, 0x0011, 1); - /* - * The registration status. (Not real sure what it means.) - * Not available for ICQ logins. - * - * 1 = No disclosure - * 2 = Limited disclosure - * 3 = Full disclosure - * - * This has to do with whether your email address is available - * to other users or not. AFAIK, this feature is no longer used. - * - */ - if (aim_gettlv(tlvlist, 0x0013, 1)) - regstatus = aim_gettlv16(tlvlist, 0x0013, 1); + /* + * The registration status. (Not real sure what it means.) + * Not available for ICQ logins. + * + * 1 = No disclosure + * 2 = Limited disclosure + * 3 = Full disclosure + * + * This has to do with whether your email address is available + * to other users or not. AFAIK, this feature is no longer used. + * + */ + if (aim_gettlv(tlvlist, 0x0013, 1)) + regstatus = aim_gettlv16(tlvlist, 0x0013, 1); - if (aim_gettlv(tlvlist, 0x0040, 1)) - latestbetabuild = aim_gettlv32(tlvlist, 0x0040, 1); - if (aim_gettlv(tlvlist, 0x0041, 1)) - latestbetaurl = aim_gettlv_str(tlvlist, 0x0041, 1); - if (aim_gettlv(tlvlist, 0x0042, 1)) - latestbetainfo = aim_gettlv_str(tlvlist, 0x0042, 1); - if (aim_gettlv(tlvlist, 0x0043, 1)) - latestbeta = aim_gettlv_str(tlvlist, 0x0043, 1); - if (aim_gettlv(tlvlist, 0x0048, 1)) - ; /* no idea what this is */ + if (aim_gettlv(tlvlist, 0x0040, 1)) + latestbetabuild = aim_gettlv32(tlvlist, 0x0040, 1); + if (aim_gettlv(tlvlist, 0x0041, 1)) + latestbetaurl = aim_gettlv_str(tlvlist, 0x0041, 1); + if (aim_gettlv(tlvlist, 0x0042, 1)) + latestbetainfo = aim_gettlv_str(tlvlist, 0x0042, 1); + if (aim_gettlv(tlvlist, 0x0043, 1)) + latestbeta = aim_gettlv_str(tlvlist, 0x0043, 1); + if (aim_gettlv(tlvlist, 0x0048, 1)) + ; /* no idea what this is */ - if (aim_gettlv(tlvlist, 0x0044, 1)) - latestbuild = aim_gettlv32(tlvlist, 0x0044, 1); - if (aim_gettlv(tlvlist, 0x0045, 1)) - latestreleaseurl = aim_gettlv_str(tlvlist, 0x0045, 1); - if (aim_gettlv(tlvlist, 0x0046, 1)) - latestreleaseinfo = aim_gettlv_str(tlvlist, 0x0046, 1); - if (aim_gettlv(tlvlist, 0x0047, 1)) - latestrelease = aim_gettlv_str(tlvlist, 0x0047, 1); - if (aim_gettlv(tlvlist, 0x0049, 1)) - ; /* no idea what this is */ + if (aim_gettlv(tlvlist, 0x0044, 1)) + latestbuild = aim_gettlv32(tlvlist, 0x0044, 1); + if (aim_gettlv(tlvlist, 0x0045, 1)) + latestreleaseurl = aim_gettlv_str(tlvlist, 0x0045, 1); + if (aim_gettlv(tlvlist, 0x0046, 1)) + latestreleaseinfo = aim_gettlv_str(tlvlist, 0x0046, 1); + if (aim_gettlv(tlvlist, 0x0047, 1)) + latestrelease = aim_gettlv_str(tlvlist, 0x0047, 1); + if (aim_gettlv(tlvlist, 0x0049, 1)) + ; /* no idea what this is */ - if ((userfunc = aim_callhandler(sess, rx->conn, snac?snac->family:0x0017, snac?snac->subtype:0x0003))) - ret = userfunc(sess, rx, sn, errorcode, errurl, regstatus, email, bosip, cookie, latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo, latestbeta, latestbetabuild, latestbetaurl, latestbetainfo); - + if ((userfunc = aim_callhandler(sess, rx->conn, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003))) { + /* XXX return as a struct? */ + ret = userfunc(sess, rx, sn, errorcode, errurl, regstatus, email, bosip, cookie, latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo, latestbeta, latestbetabuild, latestbetaurl, latestbetainfo); + } - if (sn) - free(sn); - if (bosip) - free(bosip); - if (errurl) - free(errurl); - if (email) - free(email); - if (cookie) - free(cookie); - if (latestrelease) - free(latestrelease); - if (latestreleaseurl) - free(latestreleaseurl); - if (latestbeta) - free(latestbeta); - if (latestbetaurl) - free(latestbetaurl); - if (latestreleaseinfo) - free(latestreleaseinfo); - if (latestbetainfo) - free(latestbetainfo); + free(sn); + free(bosip); + free(errurl); + free(email); + free(cookie); + free(latestrelease); + free(latestreleaseurl); + free(latestbeta); + free(latestbetaurl); + free(latestreleaseinfo); + free(latestbetainfo); - aim_freetlvchain(&tlvlist); + aim_freetlvchain(&tlvlist); - return ret; + return ret; } /* @@ -179,46 +165,43 @@ * Calls the client, which should then use the value to call aim_send_login. * */ -static int keyparse(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int keyparse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - unsigned char *key; - int keylen; - int ret = 1; - aim_rxcallback_t userfunc; + int keylen, ret = 1; + aim_rxcallback_t userfunc; + char *keystr; - keylen = aimutil_get16(data); - if (!(key = malloc(keylen+1))) - return ret; - memcpy(key, data+2, keylen); - key[keylen] = '\0'; - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, (char *)key); + keylen = aimbs_get16(bs); + keystr = aimbs_getstr(bs, keylen); - free(key); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, keystr); - return ret; + free(keystr); + + 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) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - 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); + if (snac->subtype == 0x0003) + return parse(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0007) + return keyparse(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int auth_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int auth_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x0017; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "auth", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x0017; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "auth", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } + diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/bos.c --- a/src/protocols/oscar/bos.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/bos.c Sun Sep 09 10:07:14 2001 +0000 @@ -12,64 +12,62 @@ * a bitwise OR of all the user classes you want to see you. * */ -faim_export unsigned long aim_bos_setgroupperm(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_long mask) +faim_export int aim_bos_setgroupperm(aim_session_t *sess, aim_conn_t *conn, fu32_t mask) { - return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask); + return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask); } -static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - aim_rxcallback_t userfunc; - int ret = 0; - struct aim_tlvlist_t *tlvlist; - unsigned short maxpermits = 0, maxdenies = 0; + aim_rxcallback_t userfunc; + aim_tlvlist_t *tlvlist; + fu16_t maxpermits = 0, maxdenies = 0; + int ret = 0; - /* - * TLVs follow - */ - if (!(tlvlist = aim_readtlvchain(data, datalen))) - return 0; + /* + * TLVs follow + */ + tlvlist = aim_readtlvchain(bs); - /* - * TLV type 0x0001: Maximum number of buddies on permit list. - */ - if (aim_gettlv(tlvlist, 0x0001, 1)) - maxpermits = aim_gettlv16(tlvlist, 0x0001, 1); + /* + * TLV type 0x0001: Maximum number of buddies on permit list. + */ + if (aim_gettlv(tlvlist, 0x0001, 1)) + maxpermits = aim_gettlv16(tlvlist, 0x0001, 1); - /* - * TLV type 0x0002: Maximum number of buddies on deny list. - * - */ - if (aim_gettlv(tlvlist, 0x0002, 1)) - maxdenies = aim_gettlv16(tlvlist, 0x0002, 1); - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, maxpermits, maxdenies); + /* + * TLV type 0x0002: Maximum number of buddies on deny list. + */ + if (aim_gettlv(tlvlist, 0x0002, 1)) + maxdenies = aim_gettlv16(tlvlist, 0x0002, 1); - aim_freetlvchain(&tlvlist); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, maxpermits, maxdenies); - return ret; + aim_freetlvchain(&tlvlist); + + return ret; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0003) - return rights(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0003) + return rights(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int bos_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int bos_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x0009; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "bos", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x0009; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "bos", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } + + diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/buddylist.c --- a/src/protocols/oscar/buddylist.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/buddylist.c Sun Sep 09 10:07:14 2001 +0000 @@ -11,76 +11,77 @@ * it is still in a format parsable by extractuserinfo. * */ -static int buddychange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int buddychange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_userinfo_s userinfo; - aim_rxcallback_t userfunc; + struct aim_userinfo_s userinfo; + aim_rxcallback_t userfunc; - aim_extractuserinfo(sess, data, &userinfo); + aim_extractuserinfo(sess, bs, &userinfo); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - return userfunc(sess, rx, &userinfo); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, &userinfo); - return 0; + 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) +static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - aim_rxcallback_t userfunc; - struct aim_tlvlist_t *tlvlist; - unsigned short maxbuddies = 0, maxwatchers = 0; - int ret = 0; + aim_rxcallback_t userfunc; + aim_tlvlist_t *tlvlist; + fu16_t maxbuddies = 0, maxwatchers = 0; + int ret = 0; - /* - * TLVs follow - */ - if (!(tlvlist = aim_readtlvchain(data, datalen))) - return 0; + /* + * TLVs follow + */ + tlvlist = aim_readtlvchain(bs); + + /* + * TLV type 0x0001: Maximum number of buddies. + */ + if (aim_gettlv(tlvlist, 0x0001, 1)) + maxbuddies = aim_gettlv16(tlvlist, 0x0001, 1); - /* - * TLV type 0x0001: Maximum number of buddies. - */ - if (aim_gettlv(tlvlist, 0x0001, 1)) - maxbuddies = aim_gettlv16(tlvlist, 0x0001, 1); + /* + * TLV type 0x0002: Maximum number of watchers. + * + * Watchers are other users who have you on their buddy + * list. (This is called the "reverse list" by a certain + * other IM protocol.) + * + */ + if (aim_gettlv(tlvlist, 0x0002, 1)) + maxwatchers = aim_gettlv16(tlvlist, 0x0002, 1); - /* - * TLV type 0x0002: Maximum number of watchers. - * - * XXX: what the hell is a watcher? - * - */ - if (aim_gettlv(tlvlist, 0x0002, 1)) - maxwatchers = aim_gettlv16(tlvlist, 0x0002, 1); - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, maxbuddies, maxwatchers); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, maxbuddies, maxwatchers); - aim_freetlvchain(&tlvlist); + aim_freetlvchain(&tlvlist); - return ret; + 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) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0003) - return rights(sess, mod, rx, snac, data, datalen); - else if ((snac->subtype == 0x000b) || (snac->subtype == 0x000c)) - return buddychange(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0003) + return rights(sess, mod, rx, snac, bs); + else if ((snac->subtype == 0x000b) || (snac->subtype == 0x000c)) + return buddychange(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int buddylist_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int buddylist_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x0003; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "buddylist", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x0003; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "buddylist", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } /* @@ -91,30 +92,26 @@ * XXX this should just be an extension of setbuddylist() * */ -faim_export unsigned long aim_add_buddy(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *sn ) +faim_export int aim_add_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; - if(!sn) - return -1; + if (!sn || !strlen(sn)) + return -EINVAL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+1+strlen(sn)))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)))) + return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1); + aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid); - i = aim_putsnac(newpacket->data, 0x0003, 0x0004, 0x0000, sess->snac_nextid); - i += aimutil_put8(newpacket->data+i, strlen(sn)); - i += aimutil_putstr(newpacket->data+i, sn, strlen(sn)); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - aim_tx_enqueue(sess, newpacket ); + aim_tx_enqueue(sess, fr); - aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1); - - return sess->snac_nextid; + return 0; } /* @@ -122,30 +119,25 @@ * the same as setbuddylist() but with a different snac subtype). * */ -faim_export unsigned long aim_remove_buddy(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *sn ) +faim_export int aim_remove_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; - if(!sn) - return -1; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+1+strlen(sn)))) - return -1; + if (!sn || !strlen(sn)) + return -EINVAL; - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+1+strlen(sn)))) + return -ENOMEM; - i = aim_putsnac(newpacket->data, 0x0003, 0x0005, 0x0000, sess->snac_nextid); + snacid = aim_cachesnac(sess, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1); + aim_putsnac(&fr->data, 0x0003, 0x0005, 0x0000, snacid); - i += aimutil_put8(newpacket->data+i, strlen(sn)); - i += aimutil_putstr(newpacket->data+i, sn, strlen(sn)); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - aim_cachesnac(sess, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1); - - return sess->snac_nextid; + return 0; } diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/chat.c --- a/src/protocols/oscar/chat.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/chat.c Sun Sep 09 10:07:14 2001 +0000 @@ -8,47 +8,50 @@ #define FAIM_INTERNAL #include -faim_export char *aim_chat_getname(struct aim_conn_t *conn) +faim_export char *aim_chat_getname(aim_conn_t *conn) { - if (!conn) - return NULL; - if (conn->type != AIM_CONN_TYPE_CHAT) - return NULL; + + if (!conn) + return NULL; + + if (conn->type != AIM_CONN_TYPE_CHAT) + return NULL; - return (char *)conn->priv; /* yuck ! */ + return (char *)conn->priv; /* yuck ! */ } -faim_export struct aim_conn_t *aim_chat_getconn(struct aim_session_t *sess, char *name) +faim_export aim_conn_t *aim_chat_getconn(aim_session_t *sess, const char *name) { - struct aim_conn_t *cur; - - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->type != AIM_CONN_TYPE_CHAT) - continue; - if (!cur->priv) { - faimdprintf(sess, 0, "faim: chat: chat connection with no name! (fd = %d)\n", cur->fd); - continue; - } - if (strcmp((char *)cur->priv, name) == 0) - break; - } - faim_mutex_unlock(&sess->connlistlock); + aim_conn_t *cur; - return cur; + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (cur->type != AIM_CONN_TYPE_CHAT) + continue; + if (!cur->priv) { + faimdprintf(sess, 0, "faim: chat: chat connection with no name! (fd = %d)\n", cur->fd); + continue; + } + if (strcmp((char *)cur->priv, name) == 0) + break; + } + faim_mutex_unlock(&sess->connlistlock); + + return cur; } -faim_export int aim_chat_attachname(struct aim_conn_t *conn, char *roomname) +faim_export int aim_chat_attachname(aim_conn_t *conn, const char *roomname) { - if (!conn || !roomname) - return -1; + + if (!conn || !roomname) + return -EINVAL; - if (conn->priv) - free(conn->priv); + if (conn->priv) + free(conn->priv); - conn->priv = strdup(roomname); + conn->priv = strdup(roomname); - return 0; + return 0; } /* @@ -63,331 +66,317 @@ * * XXX convert this to use tlvchains */ -faim_export unsigned long aim_chat_send_im(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned short flags, - const char *msg, - int msglen) +faim_export int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, fu16_t flags, const char *msg, int msglen) { + int i; + aim_frame_t *fr; + aim_msgcookie_t *cookie; + aim_snacid_t snacid; + fu8_t ckstr[8]; + aim_tlvlist_t *otl = NULL, *itl = NULL; - int curbyte,i; - struct command_tx_struct *newpacket; - struct aim_msgcookie_t *cookie; + if (!sess || !conn || !msg || (msglen <= 0)) + return 0; - if (!sess || !conn || !msg || (msglen <= 0)) - return 0; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) + return -ENOMEM; - newpacket->lock = 1; /* lock struct */ + snacid = aim_cachesnac(sess, 0x000e, 0x0005, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x000e, 0x0005, 0x0000, snacid); + - curbyte = 0; - curbyte += aim_putsnac(newpacket->data+curbyte, - 0x000e, 0x0005, 0x0000, sess->snac_nextid); + /* + * Generate a random message cookie. + * + * XXX mkcookie should generate the cookie and cache it in one + * operation to preserve uniqueness. + * + */ + for (i = 0; i < sizeof(ckstr); i++) + aimutil_put8(ckstr+i, (fu8_t) rand()); - /* - * Generate a random message cookie - */ - for (i=0;i<8;i++) - curbyte += aimutil_put8(newpacket->data+curbyte, (u_char) rand()); + cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL); + cookie->data = strdup(conn->priv); /* chat hack dependent */ + + aim_cachecookie(sess, cookie); - cookie = aim_mkcookie(newpacket->data+curbyte-8, AIM_COOKIETYPE_CHAT, NULL); - cookie->data = strdup(conn->priv); /* chat hack dependent */ + for (i = 0; i < sizeof(ckstr); i++) + aimbs_put8(&fr->data, ckstr[i]); - aim_cachecookie(sess, cookie); - /* - * Channel ID. - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); + /* + * Channel ID. + */ + aimbs_put16(&fr->data, 0x0003); + + + /* + * Type 1: Flag meaning this message is destined to the room. + */ + aim_addtlvtochain_noval(&otl, 0x0001); - /* - * Type 1: Flag meaning this message is destined to the room. - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - - /* - * Type 6: Reflect - */ - if (!(flags & AIM_CHATFLAGS_NOREFLECT)) { - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0006); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - } + /* + * Type 6: Reflect + */ + if (!(flags & AIM_CHATFLAGS_NOREFLECT)) + aim_addtlvtochain_noval(&otl, 0x0006); + + /* + * Type 7: Autoresponse + */ + if (flags & AIM_CHATFLAGS_AWAY) + aim_addtlvtochain_noval(&otl, 0x0007); - /* - * Type 7: Autoresponse - */ - if (flags & AIM_CHATFLAGS_AWAY) { - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0007); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - } + /* + * SubTLV: Type 1: Message + */ + aim_addtlvtochain_raw(&itl, 0x0001, strlen(msg), msg); + + /* + * Type 5: Message block. Contains more TLVs. + * + * This could include other information... We just + * put in a message TLV however. + * + */ + aim_addtlvtochain_frozentlvlist(&otl, 0x0005, &itl); - /* - * Type 5: Message block. Contains more TLVs. - * - * This could include other information... We just - * put in a message TLV however. - * - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); - curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg)+4); + aim_writetlvchain(&fr->data, &otl); + + aim_freetlvchain(&itl); + aim_freetlvchain(&otl); + + aim_tx_enqueue(sess, fr); + + return 0; +} + +static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance) +{ + fu8_t *buf; + int buflen; + aim_bstream_t bs; - /* - * SubTLV: Type 1: Message - */ - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(msg), msg); - - newpacket->commandlen = curbyte; + buflen = 2 + 1 + strlen(roomname) + 2; + + if (!(buf = malloc(buflen))) + return 0; + + aim_bstream_init(&bs, buf, buflen); - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aimbs_put16(&bs, exchange); + aimbs_put8(&bs, strlen(roomname)); + aimbs_putraw(&bs, roomname, strlen(roomname)); + aimbs_put16(&bs, instance); - return (sess->snac_nextid++); + aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); + + free(buf); + + return 0; } /* - * Join a room of name roomname. This is the first - * step to joining an already created room. It's - * basically a Service Request for family 0x000e, - * with a little added on to specify the exchange - * and room name. - * + * Join a room of name roomname. This is the first step to joining an + * already created room. It's basically a Service Request for + * family 0x000e, with a little added on to specify the exchange and room + * name. */ -faim_export unsigned long aim_chat_join(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short exchange, - const char *roomname) +faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + + if (!sess || !conn || !roomname || !strlen(roomname)) + return -EINVAL; - if (!sess || !conn || !roomname) - return 0; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+9+strlen(roomname)+2))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+9+strlen(roomname)+2))) + return -ENOMEM; - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0004, 0x0000, sess->snac_nextid); - i+= aimutil_put16(newpacket->data+i, 0x000e); + snacid = aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, roomname, strlen(roomname)+1); + aim_putsnac(&fr->data, 0x0001, 0x0004, 0x0000, snacid); - /* - * this is techinally a TLV, but we can't use normal functions - * because we need the extraneous nulls and other weird things. - */ - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 2+1+strlen(roomname)+2); - i+= aimutil_put16(newpacket->data+i, exchange); - i+= aimutil_put8(newpacket->data+i, strlen(roomname)); - i+= aimutil_putstr(newpacket->data+i, roomname, strlen(roomname)); - i+= aimutil_put16(newpacket->data+i, 0x0000); /* instance? */ + /* + * Requesting service chat (0x000e) + */ + aimbs_put16(&fr->data, 0x000e); + + aim_addtlvtochain_chatroom(&tl, 0x0001, exchange, roomname, instance); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); - /* - * Chat hack. - * - * XXX: A problem occurs here if we request a channel - * join but it fails....pendingjoin will be nonnull - * even though the channel is never going to get a - * redirect! - * - */ - sess->pendingjoin = strdup(roomname); - sess->pendingjoinexchange = exchange; + /* + * Chat hack. + * + * XXX: A problem occurs here if we request a channel + * join but it fails....pendingjoin will be nonnull + * even though the channel is never going to get a + * redirect! + * + */ + sess->pendingjoin = strdup(roomname); + sess->pendingjoinexchange = exchange; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, roomname, strlen(roomname)+1); - - return sess->snac_nextid; + return 0; } -faim_internal int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo) +faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo) { - int namelen = 0; - int i = 0; + int namelen; - if (!buf || !outinfo) - return 0; - - outinfo->exchange = aimutil_get16(buf+i); - i += 2; + if (!bs || !outinfo) + return 0; - namelen = aimutil_get8(buf+i); - i += 1; + outinfo->exchange = aimbs_get16(bs); + namelen = aimbs_get8(bs); + outinfo->name = aimbs_getstr(bs, namelen); + outinfo->instance = aimbs_get16(bs); - outinfo->name = (char *)malloc(namelen+1); - memcpy(outinfo->name, buf+i, namelen); - outinfo->name[namelen] = '\0'; - i += namelen; - - outinfo->instance = aimutil_get16(buf+i); - i += 2; - - return i; + return 0; } -faim_export unsigned long aim_chat_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_chat_clientready(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 0x20))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 0x20))) + return -ENOMEM; - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid); - i+= aimutil_put16(newpacket->data+i, 0x000e); - i+= aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&fr->data, 0x000e); + aimbs_put16(&fr->data, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0004); - i+= aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0003); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0003); - i+= aimutil_put16(newpacket->data+i, 0x0004); - i+= aimutil_put16(newpacket->data+i, 0x0686); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0686); - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return (sess->snac_nextid++); + return 0; } -faim_export int aim_chat_leaveroom(struct aim_session_t *sess, char *name) +faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name) { - struct aim_conn_t *conn; + aim_conn_t *conn; - if ((conn = aim_chat_getconn(sess, name))) - aim_conn_close(conn); + if (!(conn = aim_chat_getconn(sess, name))) + return -ENOENT; - if (!conn) - return -1; - return 0; + aim_conn_close(conn); + + 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_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance) { - struct command_tx_struct *newpacket; - int i,curbyte=0; - struct aim_msgcookie_t *cookie; - struct aim_invite_priv *priv; + int i; + aim_frame_t *fr; + aim_msgcookie_t *cookie; + struct aim_invite_priv *priv; + fu8_t ckstr[8]; + aim_snacid_t snacid; + aim_tlvlist_t *otl = NULL, *itl = NULL; + fu8_t *hdr; + int hdrlen; + aim_bstream_t hdrbs; + + if (!sess || !conn || !sn || !msg || !roomname) + return -EINVAL; - if (!sess || !conn || !sn || !msg || !roomname) - return -1; - - if (conn->type != AIM_CONN_TYPE_BOS) - return -1; + if (conn->type != AIM_CONN_TYPE_BOS) + return -EINVAL; - 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); + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) + return -ENOMEM; - /* - * Cookie - */ - for (i=0;i<8;i++) - curbyte += aimutil_put8(newpacket->data+curbyte, (u_char)rand()); + snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1); + aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); + - /* 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; + /* + * Cookie + */ + for (i = 0; i < sizeof(ckstr); i++) + aimutil_put8(ckstr, (fu8_t) rand()); - if(!(cookie = aim_mkcookie(newpacket->data+curbyte-8, AIM_COOKIETYPE_INVITE, priv))) - return -1; - aim_cachecookie(sess, cookie); + /* XXX should be uncached by an unwritten 'invite accept' handler */ + if ((priv = malloc(sizeof(struct aim_invite_priv)))) { + priv->sn = strdup(sn); + priv->roomname = strdup(roomname); + priv->exchange = exchange; + priv->instance = instance; + } - /* - * Channel (2) - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); + if ((cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_INVITE, priv))) + aim_cachecookie(sess, cookie); + else + free(priv); - /* - * Dest sn - */ - curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sn)); - curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn)); + for (i = 0; i < sizeof(ckstr); i++) + aimbs_put8(&fr->data, ckstr[i]); - /* - * 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); + + /* + * Channel (2) + */ + aimbs_put16(&fr->data, 0x0002); + + /* + * Dest sn + */ + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - /* - * 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); + /* + * TLV t(0005) + * + * Everything else is inside this TLV. + * + * Sigh. AOL was rather inconsistent right here. So we have + * to play some minor tricks. Right inside the type 5 is some + * raw data, followed by a series of TLVs. + * + */ + hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2; + hdr = malloc(hdrlen); + aim_bstream_init(&hdrbs, hdr, hdrlen); + + aimbs_put16(&hdrbs, 0x0000); /* Unknown! */ + aimbs_putraw(&hdrbs, ckstr, sizeof(ckstr)); /* I think... */ + aim_putcap(&hdrbs, AIM_CAPS_CHAT); - newpacket->commandlen = curbyte; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_addtlvtochain16(&itl, 0x000a, 0x0001); + aim_addtlvtochain_noval(&itl, 0x000f); + aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg); + aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance); + aim_writetlvchain(&hdrbs, &itl); + + aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); - return (sess->snac_nextid++); + aim_writetlvchain(&fr->data, &otl); + + free(hdr); + aim_freetlvchain(&itl); + aim_freetlvchain(&otl); + + aim_tx_enqueue(sess, fr); + + return 0; } /* @@ -399,43 +388,38 @@ * * SNAC 000e/0002 */ -static int infoupdate(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { struct aim_userinfo_s *userinfo = NULL; - aim_rxcallback_t userfunc=NULL; - int ret = 0, i = 0; + aim_rxcallback_t userfunc; + int ret = 0; int usercount = 0; - unsigned char detaillevel = 0; + fu8_t detaillevel = 0; char *roomname = NULL; struct aim_chat_roominfo roominfo; - unsigned short tlvcount = 0; - struct aim_tlvlist_t *tlvlist; + fu16_t tlvcount = 0; + aim_tlvlist_t *tlvlist; char *roomdesc = NULL; - unsigned short unknown_c9 = 0; - unsigned long creationtime = 0; - unsigned short maxmsglen = 0, maxvisiblemsglen = 0; - unsigned short unknown_d2 = 0, unknown_d5 = 0; + fu16_t unknown_c9 = 0; + fu32_t creationtime = 0; + fu16_t maxmsglen = 0, maxvisiblemsglen = 0; + fu16_t unknown_d2 = 0, unknown_d5 = 0; - i += aim_chat_readroominfo(data+i, &roominfo); + aim_chat_readroominfo(bs, &roominfo); - detaillevel = aimutil_get8(data+i); - i++; + detaillevel = aimbs_get8(bs); if (detaillevel != 0x02) { - if (detaillevel == 0x01) - faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level 1 not supported\n"); - else - faimdprintf(sess, 0, "faim: chat_roomupdateinfo: unknown detail level %d\n", detaillevel); + faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel); return 1; } - tlvcount = aimutil_get16(data+i); - i += 2; + tlvcount = aimbs_get16(bs); /* * Everything else are TLVs. */ - tlvlist = aim_readtlvchain(data+i, datalen-i); + tlvlist = aim_readtlvchain(bs); /* * TLV type 0x006a is the room name in Human Readable Form. @@ -454,15 +438,18 @@ */ if (aim_gettlv(tlvlist, 0x0073, 1)) { int curoccupant = 0; - struct aim_tlv_t *tmptlv; + aim_tlv_t *tmptlv; + aim_bstream_t occbs; tmptlv = aim_gettlv(tlvlist, 0x0073, 1); /* Allocate enough userinfo structs for all occupants */ userinfo = calloc(usercount, sizeof(struct aim_userinfo_s)); - for (i = 0; curoccupant < usercount; ) - i += aim_extractuserinfo(sess, tmptlv->value+i, &userinfo[curoccupant++]); + aim_bstream_init(&occbs, tmptlv->value, tmptlv->length); + + while (curoccupant < usercount) + aim_extractuserinfo(sess, &occbs, &userinfo[curoccupant++]); } /* @@ -563,24 +550,24 @@ return ret; } -static int userlistchange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int userlistchange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_userinfo_s *userinfo = NULL; - aim_rxcallback_t userfunc; - int i = 0, curcount = 0, ret = 0; + struct aim_userinfo_s *userinfo = NULL; + aim_rxcallback_t userfunc; + int curcount = 0, ret = 0; - while (i < datalen) { - curcount++; - userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); - i += aim_extractuserinfo(sess, data+i, &userinfo[curcount-1]); - } + while (aim_bstream_empty(bs)) { + curcount++; + userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); + aim_extractuserinfo(sess, bs, &userinfo[curcount-1]); + } - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, curcount, userinfo); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, curcount, userinfo); - free(userinfo); + free(userinfo); - return ret; + return ret; } /* @@ -606,118 +593,124 @@ * possibly others * */ -static int incomingmsg(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int incomingmsg(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_userinfo_s userinfo; - aim_rxcallback_t userfunc=NULL; - int ret = 0, i = 0; - unsigned char cookie[8]; - int channel; - struct aim_tlvlist_t *outerlist; - char *msg = NULL; - struct aim_msgcookie_t *ck; + struct aim_userinfo_s userinfo; + aim_rxcallback_t userfunc; + int ret = 0; + fu8_t *cookie; + fu16_t channel; + aim_tlvlist_t *otl; + char *msg = NULL; + aim_msgcookie_t *ck; - memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); + memset(&userinfo, 0, sizeof(struct aim_userinfo_s)); - /* - * ICBM Cookie. Cache it. - */ - memcpy(cookie, data, 8); - i += 8; + /* + * ICBM Cookie. Uncache it. + */ + cookie = aimbs_getraw(bs, 8); - if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) { - if (ck->data) - free(ck->data); - free(ck); - } + if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) { + free(ck->data); + free(ck); + } - /* - * Channel ID - * - * Channels 1 and 2 are implemented in the normal ICBM - * parser. - * - * We only do channel 3 here. - * - */ - channel = aimutil_get16(data+i); - i += 2; + /* + * Channel ID + * + * Channels 1 and 2 are implemented in the normal ICBM + * parser. + * + * We only do channel 3 here. + * + */ + channel = aimbs_get16(bs); - if (channel != 0x0003) { - faimdprintf(sess, 0, "faim: chat_incoming: unknown channel! (0x%04x)\n", channel); - return 0; - } + if (channel != 0x0003) { + faimdprintf(sess, 0, "faim: chat_incoming: unknown channel! (0x%04x)\n", channel); + return 0; + } + + /* + * Start parsing TLVs right away. + */ + otl = aim_readtlvchain(bs); - /* - * Start parsing TLVs right away. - */ - outerlist = aim_readtlvchain(data+8+2, datalen-8-2); - - /* - * Type 0x0003: Source User Information - */ - if (aim_gettlv(outerlist, 0x0003, 1)) { - struct aim_tlv_t *userinfotlv; - - userinfotlv = aim_gettlv(outerlist, 0x0003, 1); - aim_extractuserinfo(sess, userinfotlv->value, &userinfo); - } + /* + * Type 0x0003: Source User Information + */ + if (aim_gettlv(otl, 0x0003, 1)) { + aim_tlv_t *userinfotlv; + aim_bstream_t tbs; + + userinfotlv = aim_gettlv(otl, 0x0003, 1); - /* - * Type 0x0001: Unknown. - */ - if (aim_gettlv(outerlist, 0x0001, 1)) - ; + aim_bstream_init(&tbs, userinfotlv->value, userinfotlv->length); + aim_extractuserinfo(sess, &tbs, &userinfo); + } + + /* + * Type 0x0001: If present, it means it was a message to the + * room (as opposed to a whisper). + */ + if (aim_gettlv(otl, 0x0001, 1)) + ; - /* - * Type 0x0005: Message Block. Conains more TLVs. - */ - if (aim_gettlv(outerlist, 0x0005, 1)) { - struct aim_tlvlist_t *innerlist; - struct aim_tlv_t *msgblock; + /* + * Type 0x0005: Message Block. Conains more TLVs. + */ + if (aim_gettlv(otl, 0x0005, 1)) { + aim_tlvlist_t *itl; + aim_tlv_t *msgblock; + aim_bstream_t tbs; + + msgblock = aim_gettlv(otl, 0x0005, 1); + aim_bstream_init(&tbs, msgblock->value, msgblock->length); + itl = aim_readtlvchain(&tbs); - 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(itl, 0x0001, 1)) + msg = aim_gettlv_str(itl, 0x0001, 1); + + aim_freetlvchain(&itl); + } - aim_freetlvchain(&innerlist); - } + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, &userinfo, msg); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, &userinfo, msg); + free(cookie); + free(msg); + aim_freetlvchain(&otl); - free(msg); - aim_freetlvchain(&outerlist); - - return ret; + 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) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - 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 (snac->subtype == 0x0002) + return infoupdate(sess, mod, rx, snac, bs); + else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004)) + return userlistchange(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0006) + return incomingmsg(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int chat_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int chat_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x000e; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "chat", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x000e; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "chat", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } + + diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/chatnav.c --- a/src/protocols/oscar/chatnav.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/chatnav.c Sun Sep 09 10:07:14 2001 +0000 @@ -13,400 +13,387 @@ /* * conn must be a chatnav connection! */ -faim_export unsigned long aim_chatnav_reqrights(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn) { - - return aim_genericreq_n_snacid(sess, conn, 0x000d, 0x0002); + return aim_genericreq_n_snacid(sess, conn, 0x000d, 0x0002); } -faim_export unsigned long aim_chatnav_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_chatnav_clientready(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 0x20))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 0x20))) + return -ENOMEM; - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid); - i+= aimutil_put16(newpacket->data+i, 0x000d); - i+= aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&fr->data, 0x000d); + aimbs_put16(&fr->data, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0004); - i+= aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0003); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0003); - i+= aimutil_put16(newpacket->data+i, 0x0004); - i+= aimutil_put16(newpacket->data+i, 0x0686); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0686); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return (sess->snac_nextid++); + return 0; } -faim_export unsigned long aim_chatnav_createroom(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *name, - u_short exchange) +faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+12+strlen("invite")+strlen(name)))) + return -ENOMEM; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+12+strlen("invite")+strlen(name)))) - return -1; - - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x000d, 0x0008, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x000d, 0x0008, 0x0000, snacid); - i = aim_putsnac(newpacket->data, 0x000d, 0x0008, 0x0000, sess->snac_nextid); + /* exchange */ + aimbs_put16(&fr->data, exchange); - /* exchange */ - i+= aimutil_put16(newpacket->data+i, exchange); + /* room cookie */ + aimbs_put8(&fr->data, strlen("invite")); + aimbs_putraw(&fr->data, "invite", strlen("invite")); - /* room cookie */ - i+= aimutil_put8(newpacket->data+i, strlen("invite")); - i+= aimutil_putstr(newpacket->data+i, "invite", strlen("invite")); + /* + * instance + * + * Setting this to 0xffff apparently assigns the last instance. + * + */ + aimbs_put16(&fr->data, 0xffff); + + /* detail level */ + aimbs_put8(&fr->data, 0x01); - /* instance */ - i+= aimutil_put16(newpacket->data+i, 0xffff); - - /* detail level */ - i+= aimutil_put8(newpacket->data+i, 0x01); - - /* tlvcount */ - i+= aimutil_put16(newpacket->data+i, 0x0001); + /* room name */ + aim_addtlvtochain_raw(&tl, 0x00d3, strlen(name), name); - /* room name */ - i+= aim_puttlv_str(newpacket->data+i, 0x00d3, strlen(name), name); + /* tlvcount */ + aimbs_put16(&fr->data, aim_counttlvchain(&tl)); + aim_writetlvchain(&fr->data, &tl); - aim_cachesnac(sess, 0x000d, 0x0008, 0x0000, NULL, 0); + aim_freetlvchain(&tl); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid; + return 0; } -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) +static int parseinfo_perms(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs, aim_snac_t *snac2) { - aim_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; + aim_rxcallback_t userfunc; + int ret = 0; + struct aim_chat_exchangeinfo *exchanges = NULL; + int curexchange; + aim_tlv_t *exchangetlv; + fu8_t maxrooms = 0; + aim_tlvlist_t *tlvlist, *innerlist; - tlvlist = aim_readtlvchain(data, datalen); + tlvlist = aim_readtlvchain(bs); - /* - * Type 0x0002: Maximum concurrent rooms. - */ - if (aim_gettlv(tlvlist, 0x0002, 1)) - maxrooms = aim_gettlv8(tlvlist, 0x0002, 1); + /* + * 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 0x0003: Exchange information + * + * There can be any number of these, each one + * representing another exchange. + * + */ + for (curexchange = 0; ((exchangetlv = aim_gettlv(tlvlist, 0x0003, curexchange+1))); ) { + aim_bstream_t tbs; - /* - * Type 0x000d: Unknown. - */ - if (aim_gettlv(innerlist, 0x000d, 1)) - ; + aim_bstream_init(&tbs, exchangetlv->value, exchangetlv->length); + + curexchange++; + + exchanges = realloc(exchanges, curexchange * sizeof(struct aim_chat_exchangeinfo)); + + /* exchange number */ + exchanges[curexchange-1].number = aimbs_get16(&tbs); + innerlist = aim_readtlvchain(&tbs); - /* - * Type 0x0004: Unknown - */ - if (aim_gettlv(innerlist, 0x0004, 1)) - ; + /* + * Type 0x000d: Unknown. + */ + if (aim_gettlv(innerlist, 0x000d, 1)) + ; - /* - * Type 0x0002: Unknown - */ - if (aim_gettlv(innerlist, 0x0002, 1)) { - unsigned short classperms; + /* + * Type 0x0004: Unknown + */ + if (aim_gettlv(innerlist, 0x0004, 1)) + ; - classperms = aim_gettlv16(innerlist, 0x0002, 1); - - faimdprintf(sess, 1, "faim: class permissions %x\n", classperms); - } + /* + * Type 0x0002: Unknown + */ + if (aim_gettlv(innerlist, 0x0002, 1)) { + fu16_t 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)) - ; + classperms = aim_gettlv16(innerlist, 0x0002, 1); + + faimdprintf(sess, 1, "faim: class permissions %x\n", classperms); + } - /* - * Type 0x00d1: Maximum Message length - */ - if (aim_gettlv(innerlist, 0x00d1, 1)) - ; + /* + * 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 0x00d2: Maximum Occupancy? - */ - if (aim_gettlv(innerlist, 0x00d2, 1)) - ; + /* + * Type 0x00d1: Maximum Message length + */ + if (aim_gettlv(innerlist, 0x00d1, 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 0x00d2: Maximum Occupancy? + */ + if (aim_gettlv(innerlist, 0x00d2, 1)) + ; - /* - * 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; + /* + * 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; - createperms = aim_gettlv8(innerlist, 0x00d5, 1); - } + /* + * Type 0x00d5: Creation Permissions + * + * 0 Creation not allowed + * 1 Room creation allowed + * 2 Exchange creation allowed + * + */ + if (aim_gettlv(innerlist, 0x00d5, 1)) { + fu8_t 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 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 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); - } + /* + * 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); + /* + * Call client. + */ + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, snac2->type, maxrooms, curexchange, exchanges); - return ret; + for (curexchange--; curexchange >= 0; curexchange--) { + free(exchanges[curexchange].name); + free(exchanges[curexchange].charset1); + free(exchanges[curexchange].lang1); + free(exchanges[curexchange].charset2); + free(exchanges[curexchange].lang2); + } + 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) +static int parseinfo_create(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs, aim_snac_t *snac2) { - aim_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; + aim_rxcallback_t userfunc; + aim_tlvlist_t *tlvlist, *innerlist; + char *ck = NULL, *fqcn = NULL, *name = NULL; + fu16_t exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0; + fu32_t createtime = 0; + fu8_t createperms = 0, detaillevel; + int cklen; + aim_tlv_t *bigblock; + int ret = 0; + aim_bstream_t bbbs; - if (!(tlvlist = aim_readtlvchain(data, datalen))) { - faimdprintf(sess, 0, "unable to read top tlv in create room response\n"); - return 0; - } + tlvlist = aim_readtlvchain(bs); - 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; - } + 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; + aim_bstream_init(&bbbs, bigblock->value, bigblock->length); - cklen = aimutil_get8(bigblock->value+i); - i++; + exchange = aimbs_get16(&bbbs); + cklen = aimbs_get8(&bbbs); + ck = aimbs_getstr(&bbbs, cklen); + instance = aimbs_get16(&bbbs); + detaillevel = aimbs_get8(&bbbs); - ck = malloc(cklen+1); - memcpy(ck, bigblock->value+i, cklen); - ck[cklen] = '\0'; - i += cklen; - - instance = aimutil_get16(bigblock->value+i); - i += 2; + if (detaillevel != 0x02) { + faimdprintf(sess, 0, "unknown detaillevel in create room response (0x%02x)\n", detaillevel); + aim_freetlvchain(&tlvlist); + free(ck); + return 0; + } - 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; + unknown = aimbs_get16(&bbbs); + + innerlist = aim_readtlvchain(&bbbs); + + if (aim_gettlv(innerlist, 0x006a, 1)) + fqcn = aim_gettlv_str(innerlist, 0x006a, 1); - 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, 0x00c9, 1)) + flags = aim_gettlv16(innerlist, 0x00c9, 1); - if (aim_gettlv(innerlist, 0x006a, 1)) - fqcn = aim_gettlv_str(innerlist, 0x006a, 1); + if (aim_gettlv(innerlist, 0x00ca, 1)) + createtime = aim_gettlv32(innerlist, 0x00ca, 1); - if (aim_gettlv(innerlist, 0x00c9, 1)) - flags = aim_gettlv16(innerlist, 0x00c9, 1); + if (aim_gettlv(innerlist, 0x00d1, 1)) + maxmsglen = aim_gettlv16(innerlist, 0x00d1, 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, 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, 0x00d3, 1)) - name = aim_gettlv_str(innerlist, 0x00d3, 1); + if (aim_gettlv(innerlist, 0x00d5, 1)) + createperms = aim_gettlv8(innerlist, 0x00d5, 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); + 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); + free(ck); + free(name); + free(fqcn); + aim_freetlvchain(&innerlist); + aim_freetlvchain(&tlvlist); - return ret; + return ret; } /* - * Since multiple things can trigger this callback, - * we must lookup the snacid to determine the original - * snac subtype that was called. + * 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) +static int parseinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_snac_t *snac2; - int ret = 0; + 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; - } + 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); + /* + * We now know what the original SNAC subtype was. + */ + if (snac2->type == 0x0002) /* request chat rights */ + ret = parseinfo_perms(sess, mod, rx, snac, bs, 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, bs, snac2); + else + faimdprintf(sess, 0, "chatnav_parse_info: unknown request subtype (%04x)\n", snac2->type); - if (snac2) - free(snac2->data); - free(snac2); - - return ret; + 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) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0009) - return parseinfo(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0009) + return parseinfo(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int chatnav_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int chatnav_modfirst(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; + mod->family = 0x000d; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "chatnav", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/conn.c --- a/src/protocols/oscar/conn.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/conn.c Sun Sep 09 10:07:14 2001 +0000 @@ -15,6 +15,35 @@ #include #endif +static void connkill_real(aim_session_t *sess, aim_conn_t **deadconn) +{ + + aim_rxqueue_cleanbyconn(sess, *deadconn); + aim_tx_cleanqueue(sess, *deadconn); + + if ((*deadconn)->fd != -1) + aim_conn_close(*deadconn); + + /* + * XXX ->priv should never be touched by the library. I know + * it used to be, but I'm getting rid of all that. Use + * ->internal instead. + */ + if ((*deadconn)->priv) + free((*deadconn)->priv); + + /* + * This will free ->internal if it necessary... + */ + if ((*deadconn)->type == AIM_CONN_TYPE_RENDEZVOUS) + aim_conn_kill_rend(sess, *deadconn); + + free(*deadconn); + deadconn = NULL; + + return; +} + /** * aim_connrst - Clears out connection list, killing remaining connections. * @sess: Session to be cleared @@ -22,21 +51,25 @@ * Clears out the connection list and kills any connections left. * */ -static void aim_connrst(struct aim_session_t *sess) +static void aim_connrst(aim_session_t *sess) { - faim_mutex_init(&sess->connlistlock); - if (sess->connlist) { - struct aim_conn_t *cur = sess->connlist, *tmp; + + faim_mutex_init(&sess->connlistlock); + + if (sess->connlist) { + aim_conn_t *cur = sess->connlist, *tmp; - while(cur) { - tmp = cur->next; - aim_conn_close(cur); - free(cur); - cur = tmp; - } - } - sess->connlist = NULL; - return; + while (cur) { + tmp = cur->next; + aim_conn_close(cur); + connkill_real(sess, &cur); + cur = tmp; + } + } + + sess->connlist = NULL; + + return; } /** @@ -46,23 +79,24 @@ * Initializes and/or resets a connection structure. * */ -static void aim_conn_init(struct aim_conn_t *deadconn) +static void aim_conn_init(aim_conn_t *deadconn) { - if (!deadconn) - return; + + if (!deadconn) + return; - deadconn->fd = -1; - deadconn->subtype = -1; - deadconn->type = -1; - deadconn->seqnum = 0; - deadconn->lastactivity = 0; - deadconn->forcedlatency = 0; - deadconn->handlerlist = NULL; - deadconn->priv = NULL; - faim_mutex_init(&deadconn->active); - faim_mutex_init(&deadconn->seqnum_lock); - - return; + deadconn->fd = -1; + deadconn->subtype = -1; + deadconn->type = -1; + deadconn->seqnum = 0; + deadconn->lastactivity = 0; + deadconn->forcedlatency = 0; + deadconn->handlerlist = NULL; + deadconn->priv = NULL; + faim_mutex_init(&deadconn->active); + faim_mutex_init(&deadconn->seqnum_lock); + + return; } /** @@ -72,28 +106,20 @@ * Allocate a new empty connection structure. * */ -static struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess) +static aim_conn_t *aim_conn_getnext(aim_session_t *sess) { - struct aim_conn_t *newconn, *cur; - - if (!(newconn = malloc(sizeof(struct aim_conn_t)))) - return NULL; - - memset(newconn, 0, sizeof(struct aim_conn_t)); - aim_conn_init(newconn); - newconn->next = NULL; + aim_conn_t *newconn; - faim_mutex_lock(&sess->connlistlock); - if (sess->connlist == NULL) - sess->connlist = newconn; - else { - for (cur = sess->connlist; cur->next; cur = cur->next) - ; - cur->next = newconn; - } - faim_mutex_unlock(&sess->connlistlock); + if (!(newconn = malloc(sizeof(aim_conn_t)))) + return NULL; + memset(newconn, 0, sizeof(aim_conn_t)); - return newconn; + aim_conn_init(newconn); + + newconn->next = sess->connlist; + sess->connlist = newconn; + + return newconn; } /** @@ -105,44 +131,27 @@ * called from within libfaim. * */ -faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn) +faim_export void aim_conn_kill(aim_session_t *sess, aim_conn_t **deadconn) { - struct aim_conn_t *cur; + aim_conn_t *cur, **prev; - if (!deadconn || !*deadconn) - return; - - aim_tx_cleanqueue(sess, *deadconn); + if (!deadconn || !*deadconn) + return; - faim_mutex_lock(&sess->connlistlock); - if (sess->connlist == NULL) - ; - else if (sess->connlist->next == NULL) { - if (sess->connlist == *deadconn) - sess->connlist = NULL; - } else { - cur = sess->connlist; - while (cur->next) { - if (cur->next == *deadconn) { - cur->next = cur->next->next; - break; - } - cur = cur->next; - } - } - faim_mutex_unlock(&sess->connlistlock); + for (prev = &sess->connlist; (cur = *prev); ) { + if (cur == *deadconn) { + *prev = cur->next; + break; + } + prev = &cur->next; + } - /* XXX: do we need this for txqueue too? */ - aim_rxqueue_cleanbyconn(sess, *deadconn); + if (!cur) + return; /* oops */ - if ((*deadconn)->fd != -1) - aim_conn_close(*deadconn); - if ((*deadconn)->priv) - free((*deadconn)->priv); - free(*deadconn); - deadconn = NULL; + connkill_real(sess, &cur); - return; + return; } /** @@ -153,21 +162,24 @@ * * This leaves everything untouched except for clearing the * handler list and setting the fd to -1 (used to recognize - * dead connections). + * dead connections). It will also remove cookies if necessary. * */ -faim_export void aim_conn_close(struct aim_conn_t *deadconn) +faim_export void aim_conn_close(aim_conn_t *deadconn) { - faim_mutex_destroy(&deadconn->active); - faim_mutex_destroy(&deadconn->seqnum_lock); - if (deadconn->fd >= 3) - close(deadconn->fd); - deadconn->fd = -1; - if (deadconn->handlerlist) - aim_clearhandlers(deadconn); + faim_mutex_destroy(&deadconn->active); + faim_mutex_destroy(&deadconn->seqnum_lock); + if (deadconn->fd >= 3) + close(deadconn->fd); + deadconn->fd = -1; + if (deadconn->handlerlist) + aim_clearhandlers(deadconn); + if (deadconn->type == AIM_CONN_TYPE_RENDEZVOUS) + aim_conn_close_rend((aim_session_t *)deadconn->sessv, deadconn); - return; + + return; } /** @@ -180,50 +192,48 @@ * type found. * */ -faim_export struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess, - int type) +faim_export aim_conn_t *aim_getconn_type(aim_session_t *sess, int type) { - struct aim_conn_t *cur; + aim_conn_t *cur; - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if ((cur->type == type) && !(cur->status & AIM_CONN_STATUS_INPROGRESS)) - break; - } - faim_mutex_unlock(&sess->connlistlock); + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if ((cur->type == type) && + !(cur->status & AIM_CONN_STATUS_INPROGRESS)) + break; + } + faim_mutex_unlock(&sess->connlistlock); - return cur; + return cur; } -faim_export struct aim_conn_t *aim_getconn_type_all(struct aim_session_t *sess, - int type) +faim_export aim_conn_t *aim_getconn_type_all(aim_session_t *sess, int type) { - struct aim_conn_t *cur; + aim_conn_t *cur; - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->type == type) - break; - } - faim_mutex_unlock(&sess->connlistlock); + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (cur->type == type) + break; + } + faim_mutex_unlock(&sess->connlistlock); - return cur; + return cur; } /* If you pass -1 for the fd, you'll get what you ask for. Gibberish. */ -faim_export struct aim_conn_t *aim_getconn_fd(struct aim_session_t *sess, - int fd) +faim_export aim_conn_t *aim_getconn_fd(aim_session_t *sess, int fd) { - struct aim_conn_t *cur; + aim_conn_t *cur; - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->fd == fd) - break; - } - faim_mutex_unlock(&sess->connlistlock); + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (cur->fd == fd) + break; + } + faim_mutex_unlock(&sess->connlistlock); - return cur; + return cur; } /** @@ -237,161 +247,162 @@ * proxy settings, if present. If no proxy is configured for * this session, the connection is done directly. * + * XXX this is really awful. + * */ -static int aim_proxyconnect(struct aim_session_t *sess, - char *host, unsigned short port, - int *statusret) +static int aim_proxyconnect(aim_session_t *sess, const char *host, fu16_t port, fu32_t *statusret) { - int fd = -1; + int fd = -1; - if (strlen(sess->socksproxy.server)) { /* connecting via proxy */ - int i; - unsigned char buf[512]; - struct sockaddr_in sa; - struct hostent *hp; - char *proxy; - unsigned short proxyport = 1080; + if (strlen(sess->socksproxy.server)) { /* connecting via proxy */ + int i; + unsigned char buf[512]; + struct sockaddr_in sa; + struct hostent *hp; + char *proxy; + unsigned short proxyport = 1080; - for(i=0;i<(int)strlen(sess->socksproxy.server);i++) { - if (sess->socksproxy.server[i] == ':') { - proxyport = atoi(&(sess->socksproxy.server[i+1])); - break; - } - } - proxy = (char *)malloc(i+1); - strncpy(proxy, sess->socksproxy.server, i); - proxy[i] = '\0'; + for(i=0;i<(int)strlen(sess->socksproxy.server);i++) { + if (sess->socksproxy.server[i] == ':') { + proxyport = atoi(&(sess->socksproxy.server[i+1])); + break; + } + } + + proxy = (char *)malloc(i+1); + strncpy(proxy, sess->socksproxy.server, i); + proxy[i] = '\0'; - if (!(hp = gethostbyname(proxy))) { - faimdprintf(sess, 0, "proxyconnect: unable to resolve proxy name\n"); - *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); - return -1; - } - free(proxy); + if (!(hp = gethostbyname(proxy))) { + faimdprintf(sess, 0, "proxyconnect: unable to resolve proxy name\n"); + *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); + return -1; + } + free(proxy); + + memset(&sa.sin_zero, 0, 8); + sa.sin_port = htons(proxyport); + memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); + sa.sin_family = hp->h_addrtype; - memset(&sa.sin_zero, 0, 8); - sa.sin_port = htons(proxyport); - memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); - sa.sin_family = hp->h_addrtype; - - fd = socket(hp->h_addrtype, SOCK_STREAM, 0); - if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { - faimdprintf(sess, 0, "proxyconnect: unable to connect to proxy\n"); - close(fd); - return -1; - } + fd = socket(hp->h_addrtype, SOCK_STREAM, 0); + if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { + faimdprintf(sess, 0, "proxyconnect: unable to connect to proxy\n"); + close(fd); + return -1; + } - i = 0; - buf[0] = 0x05; /* SOCKS version 5 */ - if (strlen(sess->socksproxy.username)) { - buf[1] = 0x02; /* two methods */ - buf[2] = 0x00; /* no authentication */ - buf[3] = 0x02; /* username/password authentication */ - i = 4; - } else { - buf[1] = 0x01; - buf[2] = 0x00; - i = 3; - } + i = 0; + buf[0] = 0x05; /* SOCKS version 5 */ + if (strlen(sess->socksproxy.username)) { + buf[1] = 0x02; /* two methods */ + buf[2] = 0x00; /* no authentication */ + buf[3] = 0x02; /* username/password authentication */ + i = 4; + } else { + buf[1] = 0x01; + buf[2] = 0x00; + i = 3; + } - if (write(fd, buf, i) < i) { - *statusret = errno; - close(fd); - return -1; - } + if (write(fd, buf, i) < i) { + *statusret = errno; + close(fd); + return -1; + } - if (read(fd, buf, 2) < 2) { - *statusret = errno; - close(fd); - return -1; - } + if (read(fd, buf, 2) < 2) { + *statusret = errno; + close(fd); + return -1; + } - if ((buf[0] != 0x05) || (buf[1] == 0xff)) { - *statusret = EINVAL; - close(fd); - return -1; - } + if ((buf[0] != 0x05) || (buf[1] == 0xff)) { + *statusret = EINVAL; + close(fd); + return -1; + } - /* check if we're doing username authentication */ - if (buf[1] == 0x02) { - i = aimutil_put8(buf, 0x01); /* version 1 */ - i += aimutil_put8(buf+i, strlen(sess->socksproxy.username)); - i += aimutil_putstr(buf+i, sess->socksproxy.username, strlen(sess->socksproxy.username)); - i += aimutil_put8(buf+i, strlen(sess->socksproxy.password)); - i += aimutil_putstr(buf+i, sess->socksproxy.password, strlen(sess->socksproxy.password)); - if (write(fd, buf, i) < i) { - *statusret = errno; - close(fd); - return -1; - } - if (read(fd, buf, 2) < 2) { - *statusret = errno; - close(fd); - return -1; - } - if ((buf[0] != 0x01) || (buf[1] != 0x00)) { - *statusret = EINVAL; - close(fd); - return -1; - } - } + /* check if we're doing username authentication */ + if (buf[1] == 0x02) { + i = aimutil_put8(buf, 0x01); /* version 1 */ + i += aimutil_put8(buf+i, strlen(sess->socksproxy.username)); + i += aimutil_putstr(buf+i, sess->socksproxy.username, strlen(sess->socksproxy.username)); + i += aimutil_put8(buf+i, strlen(sess->socksproxy.password)); + i += aimutil_putstr(buf+i, sess->socksproxy.password, strlen(sess->socksproxy.password)); + if (write(fd, buf, i) < i) { + *statusret = errno; + close(fd); + return -1; + } + if (read(fd, buf, 2) < 2) { + *statusret = errno; + close(fd); + return -1; + } + if ((buf[0] != 0x01) || (buf[1] != 0x00)) { + *statusret = EINVAL; + close(fd); + return -1; + } + } - i = aimutil_put8(buf, 0x05); - i += aimutil_put8(buf+i, 0x01); /* CONNECT */ - i += aimutil_put8(buf+i, 0x00); /* reserved */ - i += aimutil_put8(buf+i, 0x03); /* address type: host name */ - i += aimutil_put8(buf+i, strlen(host)); - i += aimutil_putstr(buf+i, host, strlen(host)); - i += aimutil_put16(buf+i, port); + i = aimutil_put8(buf, 0x05); + i += aimutil_put8(buf+i, 0x01); /* CONNECT */ + i += aimutil_put8(buf+i, 0x00); /* reserved */ + i += aimutil_put8(buf+i, 0x03); /* address type: host name */ + i += aimutil_put8(buf+i, strlen(host)); + i += aimutil_putstr(buf+i, host, strlen(host)); + i += aimutil_put16(buf+i, port); - if (write(fd, buf, i) < i) { - *statusret = errno; - close(fd); - return -1; - } - if (read(fd, buf, 10) < 10) { - *statusret = errno; - close(fd); - return -1; - } - if ((buf[0] != 0x05) || (buf[1] != 0x00)) { - *statusret = EINVAL; - close(fd); - return -1; - } + if (write(fd, buf, i) < i) { + *statusret = errno; + close(fd); + return -1; + } + if (read(fd, buf, 10) < 10) { + *statusret = errno; + close(fd); + return -1; + } + if ((buf[0] != 0x05) || (buf[1] != 0x00)) { + *statusret = EINVAL; + close(fd); + return -1; + } - } else { /* connecting directly */ - struct sockaddr_in sa; - struct hostent *hp; + } else { /* connecting directly */ + struct sockaddr_in sa; + struct hostent *hp; - if (!(hp = gethostbyname(host))) { - *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); - return -1; - } + if (!(hp = gethostbyname(host))) { + *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); + return -1; + } - memset(&sa, 0, sizeof(struct sockaddr_in)); - sa.sin_port = htons(port); - memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); - sa.sin_family = hp->h_addrtype; - - fd = socket(hp->h_addrtype, SOCK_STREAM, 0); + memset(&sa, 0, sizeof(struct sockaddr_in)); + sa.sin_port = htons(port); + memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); + sa.sin_family = hp->h_addrtype; + + fd = socket(hp->h_addrtype, SOCK_STREAM, 0); - if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) - fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */ + if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) + fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */ - if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { - if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) { - if ((errno == EINPROGRESS) || (errno == EINTR)) { - if (statusret) - *statusret |= AIM_CONN_STATUS_INPROGRESS; - return fd; + if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { + if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) { + if ((errno == EINPROGRESS) || (errno == EINTR)) { + if (statusret) + *statusret |= AIM_CONN_STATUS_INPROGRESS; + return fd; + } + } + close(fd); + fd = -1; + } } - } - close(fd); - fd = -1; - } - } - return fd; + return fd; } /** @@ -407,35 +418,29 @@ * This function returns a pointer to the new aim_conn_t, or %NULL on * error */ -faim_internal struct aim_conn_t *aim_cloneconn(struct aim_session_t *sess, - struct aim_conn_t *src) +faim_internal aim_conn_t *aim_cloneconn(aim_session_t *sess, aim_conn_t *src) { - struct aim_conn_t *conn; - struct aim_rxcblist_t *cur; + aim_conn_t *conn; - if (!(conn = aim_conn_getnext(sess))) - return NULL; + if (!(conn = aim_conn_getnext(sess))) + return NULL; - faim_mutex_lock(&conn->active); + faim_mutex_lock(&conn->active); - conn->fd = src->fd; - conn->type = src->type; - conn->subtype = src->subtype; - conn->seqnum = src->seqnum; - conn->priv = src->priv; - conn->lastactivity = src->lastactivity; - conn->forcedlatency = src->forcedlatency; - conn->sessv = src->sessv; + conn->fd = src->fd; + conn->type = src->type; + conn->subtype = src->subtype; + conn->seqnum = src->seqnum; + conn->priv = src->priv; + conn->internal = src->internal; + conn->lastactivity = src->lastactivity; + conn->forcedlatency = src->forcedlatency; + conn->sessv = src->sessv; + aim_clonehandlers(sess, conn, src); - /* clone handler list */ - for (cur = src->handlerlist; cur; cur = cur->next) { - aim_conn_addhandler(sess, conn, cur->family, cur->type, - cur->handler, cur->flags); - } + faim_mutex_unlock(&conn->active); - faim_mutex_unlock(&conn->active); - - return conn; + return conn; } /** @@ -452,63 +457,62 @@ * FIXME: Return errors in a more sane way. * */ -faim_export struct aim_conn_t *aim_newconn(struct aim_session_t *sess, - int type, char *dest) +faim_export aim_conn_t *aim_newconn(aim_session_t *sess, int type, const char *dest) { - struct aim_conn_t *connstruct; - int ret; - u_short port = FAIM_LOGIN_PORT; - char *host = NULL; - int i=0; + aim_conn_t *connstruct; + fu16_t port = FAIM_LOGIN_PORT; + char *host; + int i, ret; - if ((connstruct=aim_conn_getnext(sess))==NULL) - return NULL; + if (!(connstruct = aim_conn_getnext(sess))) + return NULL; - faim_mutex_lock(&connstruct->active); + faim_mutex_lock(&connstruct->active); - connstruct->sessv = (void *)sess; - connstruct->type = type; + connstruct->sessv = (void *)sess; + connstruct->type = type; - if (!dest) { /* just allocate a struct */ - connstruct->fd = -1; - connstruct->status = 0; - faim_mutex_unlock(&connstruct->active); - return connstruct; - } + if (!dest) { /* just allocate a struct */ + connstruct->fd = -1; + connstruct->status = 0; + faim_mutex_unlock(&connstruct->active); + return connstruct; + } - /* - * As of 23 Jul 1999, AOL now sends the port number, preceded by a - * colon, in the BOS redirect. This fatally breaks all previous - * libfaims. Bad, bad AOL. - * - * We put this here to catch every case. - * - */ + /* + * As of 23 Jul 1999, AOL now sends the port number, preceded by a + * colon, in the BOS redirect. This fatally breaks all previous + * libfaims. Bad, bad AOL. + * + * We put this here to catch every case. + * + */ + + for(i = 0; i < (int)strlen(dest); i++) { + if (dest[i] == ':') { + port = atoi(&(dest[i+1])); + break; + } + } - for(i=0;i<(int)strlen(dest);i++) { - if (dest[i] == ':') { - port = atoi(&(dest[i+1])); - break; - } - } - host = (char *)malloc(i+1); - strncpy(host, dest, i); - host[i] = '\0'; + host = (char *)malloc(i+1); + strncpy(host, dest, i); + host[i] = '\0'; - if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) { - connstruct->fd = -1; - connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); - free(host); - faim_mutex_unlock(&connstruct->active); - return connstruct; - } else - connstruct->fd = ret; - - faim_mutex_unlock(&connstruct->active); + if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) { + connstruct->fd = -1; + connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); + free(host); + faim_mutex_unlock(&connstruct->active); + return connstruct; + } else + connstruct->fd = ret; - free(host); + faim_mutex_unlock(&connstruct->active); - return connstruct; + free(host); + + return connstruct; } /** @@ -519,19 +523,19 @@ * connections in @sess. * */ -faim_export int aim_conngetmaxfd(struct aim_session_t *sess) +faim_export int aim_conngetmaxfd(aim_session_t *sess) { - int j = 0; - struct aim_conn_t *cur; + int j; + aim_conn_t *cur; - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->fd > j) - j = cur->fd; - } - faim_mutex_unlock(&sess->connlistlock); + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist, j = 0; cur; cur = cur->next) { + if (cur->fd > j) + j = cur->fd; + } + faim_mutex_unlock(&sess->connlistlock); - return j; + return j; } /** @@ -543,18 +547,20 @@ * zero otherwise. * */ -faim_export int aim_conn_in_sess(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_conn_in_sess(aim_session_t *sess, aim_conn_t *conn) { - struct aim_conn_t *cur; + aim_conn_t *cur; - faim_mutex_lock(&sess->connlistlock); - for(cur = sess->connlist; cur; cur = cur->next) - if(cur == conn) { - faim_mutex_unlock(&sess->connlistlock); - return 1; - } - faim_mutex_unlock(&sess->connlistlock); - return 0; + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (cur == conn) { + faim_mutex_unlock(&sess->connlistlock); + return 1; + } + } + faim_mutex_unlock(&sess->connlistlock); + + return 0; } /** @@ -575,126 +581,80 @@ * XXX: we could probably stand to do a little courser locking here. * */ -faim_export struct aim_conn_t *aim_select(struct aim_session_t *sess, - struct timeval *timeout, - int *status) +faim_export aim_conn_t *aim_select(aim_session_t *sess, struct timeval *timeout, int *status) { - struct aim_conn_t *cur; - fd_set fds, wfds; - int maxfd = 0; - int i, haveconnecting = 0; + aim_conn_t *cur; + fd_set fds, wfds; + int maxfd, i, haveconnecting = 0; - faim_mutex_lock(&sess->connlistlock); - if (sess->connlist == NULL) { - faim_mutex_unlock(&sess->connlistlock); - *status = -1; - return NULL; - } - faim_mutex_unlock(&sess->connlistlock); + faim_mutex_lock(&sess->connlistlock); + if (!sess->connlist) { + faim_mutex_unlock(&sess->connlistlock); + *status = -1; + return NULL; + } + faim_mutex_unlock(&sess->connlistlock); - FD_ZERO(&fds); - FD_ZERO(&wfds); - maxfd = 0; + FD_ZERO(&fds); + FD_ZERO(&wfds); - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->fd == -1) { - /* don't let invalid/dead connections sit around */ - *status = 2; - faim_mutex_unlock(&sess->connlistlock); - return cur; - } else if (cur->status & AIM_CONN_STATUS_INPROGRESS) { - FD_SET(cur->fd, &wfds); - - haveconnecting++; - } - FD_SET(cur->fd, &fds); - if (cur->fd > maxfd) - maxfd = cur->fd; - } - faim_mutex_unlock(&sess->connlistlock); + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist, maxfd = 0; cur; cur = cur->next) { + if (cur->fd == -1) { + /* don't let invalid/dead connections sit around */ + *status = 2; + faim_mutex_unlock(&sess->connlistlock); + return cur; + } else if (cur->status & AIM_CONN_STATUS_INPROGRESS) { + FD_SET(cur->fd, &wfds); - /* - * If we have data waiting to be sent, return - * - * We have to not do this if theres at least one - * connection thats still connecting, since that connection - * may have queued data and this return would prevent - * the connection from ever completing! This is a major - * inadequacy of the libfaim way of doing things. It means - * that nothing can transmit as long as there's connecting - * sockets. Evil. - * - * But its still better than having blocking connects. - * - */ - if (!haveconnecting && (sess->queue_outgoing != NULL)) { - *status = 1; - return NULL; - } + haveconnecting++; + } + FD_SET(cur->fd, &fds); + if (cur->fd > maxfd) + maxfd = cur->fd; + } + faim_mutex_unlock(&sess->connlistlock); - if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) { - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if ((FD_ISSET(cur->fd, &fds)) || - ((cur->status & AIM_CONN_STATUS_INPROGRESS) && - FD_ISSET(cur->fd, &wfds))) { - *status = 2; - faim_mutex_unlock(&sess->connlistlock); - return cur; /* XXX race condition here -- shouldnt unlock connlist */ - } - } - *status = 0; /* shouldn't happen */ - } else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */ - *status = 0; - else - *status = i; /* can be 0 or -1 */ - - faim_mutex_unlock(&sess->connlistlock); - - return NULL; /* no waiting or error, return */ -} + /* + * If we have data waiting to be sent, return + * + * We have to not do this if theres at least one + * connection thats still connecting, since that connection + * may have queued data and this return would prevent + * the connection from ever completing! This is a major + * inadequacy of the libfaim way of doing things. It means + * that nothing can transmit as long as there's connecting + * sockets. Evil. + * + * But its still better than having blocking connects. + * + */ + if (!haveconnecting && sess->queue_outgoing) { + *status = 1; + return NULL; + } -/** - * aim_conn_isready - Test if a connection is marked ready - * @conn: Connection to test - * - * Returns true if the connection is ready, false otherwise. - * Returns -1 if the connection is invalid. - * - * XXX: This is deprecated. - * - */ -faim_export int aim_conn_isready(struct aim_conn_t *conn) -{ - if (conn) - return (conn->status & 0x0001); - return -1; -} + if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) { + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if ((FD_ISSET(cur->fd, &fds)) || + ((cur->status & AIM_CONN_STATUS_INPROGRESS) && + FD_ISSET(cur->fd, &wfds))) { + *status = 2; + faim_mutex_unlock(&sess->connlistlock); + return cur; /* XXX race condition here -- shouldnt unlock connlist */ + } + } + *status = 0; /* shouldn't happen */ + } else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */ + *status = 0; + else + *status = i; /* can be 0 or -1 */ -/** - * aim_conn_setstatus - Set the status of a connection - * @conn: Connection - * @status: New status - * - * @newstatus is %XOR'd with the previous value of the connection - * status and returned. Returns -1 if the connection is invalid. - * - * This isn't real useful. - * - */ -faim_export int aim_conn_setstatus(struct aim_conn_t *conn, int status) -{ - int val; + faim_mutex_unlock(&sess->connlistlock); - if (!conn) - return -1; - - faim_mutex_lock(&conn->active); - val = conn->status ^= status; - faim_mutex_unlock(&conn->active); - - return val; + return NULL; /* no waiting or error, return */ } /** @@ -711,17 +671,18 @@ * backs off like the real rate limiting does. * */ -faim_export int aim_conn_setlatency(struct aim_conn_t *conn, int newval) +faim_export int aim_conn_setlatency(aim_conn_t *conn, int newval) { - if (!conn) - return -1; + + if (!conn) + return -1; - faim_mutex_lock(&conn->active); - conn->forcedlatency = newval; - conn->lastactivity = 0; /* reset this just to make sure */ - faim_mutex_unlock(&conn->active); + faim_mutex_lock(&conn->active); + conn->forcedlatency = newval; + conn->lastactivity = 0; /* reset this just to make sure */ + faim_mutex_unlock(&conn->active); - return 0; + return 0; } /** @@ -738,27 +699,31 @@ * Set username and password to %NULL if not applicable. * */ -faim_export void aim_setupproxy(struct aim_session_t *sess, char *server, char *username, char *password) +faim_export void aim_setupproxy(aim_session_t *sess, const char *server, const char *username, const char *password) { - /* clear out the proxy info */ - if (!server || !strlen(server)) { - memset(sess->socksproxy.server, 0, sizeof(sess->socksproxy.server)); - memset(sess->socksproxy.username, 0, sizeof(sess->socksproxy.username)); - memset(sess->socksproxy.password, 0, sizeof(sess->socksproxy.password)); - return; - } + /* clear out the proxy info */ + if (!server || !strlen(server)) { + memset(sess->socksproxy.server, 0, sizeof(sess->socksproxy.server)); + memset(sess->socksproxy.username, 0, sizeof(sess->socksproxy.username)); + memset(sess->socksproxy.password, 0, sizeof(sess->socksproxy.password)); + return; + } - strncpy(sess->socksproxy.server, server, sizeof(sess->socksproxy.server)); - if (username && strlen(username)) - strncpy(sess->socksproxy.username, username, sizeof(sess->socksproxy.username)); - if (password && strlen(password)) - strncpy(sess->socksproxy.password, password, sizeof(sess->socksproxy.password)); - return; + strncpy(sess->socksproxy.server, server, sizeof(sess->socksproxy.server)); + if (username && strlen(username)) + strncpy(sess->socksproxy.username, username, sizeof(sess->socksproxy.username)); + if (password && strlen(password)) + strncpy(sess->socksproxy.password, password, sizeof(sess->socksproxy.password)); + + return; } -static void defaultdebugcb(struct aim_session_t *sess, int level, const char *format, va_list va) +static void defaultdebugcb(aim_session_t *sess, int level, const char *format, va_list va) { - vfprintf(stderr, format, va); + + vfprintf(stderr, format, va); + + return; } /** @@ -770,74 +735,74 @@ * Sets up the initial values for a session. * */ -faim_export void aim_session_init(struct aim_session_t *sess, unsigned long flags, int debuglevel) +faim_export void aim_session_init(aim_session_t *sess, fu32_t flags, int debuglevel) { - if (!sess) - return; + + if (!sess) + return; - memset(sess, 0, sizeof(struct aim_session_t)); - aim_connrst(sess); - sess->queue_outgoing = NULL; - sess->queue_incoming = NULL; - sess->pendingjoin = NULL; - sess->pendingjoinexchange = 0; - aim_initsnachash(sess); - sess->msgcookies = NULL; - sess->snac_nextid = 0x00000001; + memset(sess, 0, sizeof(aim_session_t)); + aim_connrst(sess); + sess->queue_outgoing = NULL; + sess->queue_incoming = NULL; + sess->pendingjoin = NULL; + sess->pendingjoinexchange = 0; + aim_initsnachash(sess); + sess->msgcookies = NULL; + sess->snacid_next = 0x00000001; - sess->flags = 0; - sess->debug = debuglevel; - sess->debugcb = defaultdebugcb; + sess->flags = 0; + sess->debug = debuglevel; + sess->debugcb = defaultdebugcb; - sess->modlistv = NULL; + sess->modlistv = NULL; - /* - * Default to SNAC login unless XORLOGIN is explicitly set. - */ - if (!(flags & AIM_SESS_FLAGS_XORLOGIN)) - sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; - sess->flags |= flags; + /* + * Default to SNAC login unless XORLOGIN is explicitly set. + */ + if (!(flags & AIM_SESS_FLAGS_XORLOGIN)) + sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; + sess->flags |= flags; - /* - * This must always be set. Default to the queue-based - * version for back-compatibility. - */ - aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL); + /* + * This must always be set. Default to the queue-based + * version for back-compatibility. + */ + aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL); - /* - * Register all the modules for this session... - */ - aim__registermodule(sess, misc_modfirst); /* load the catch-all first */ - aim__registermodule(sess, buddylist_modfirst); - aim__registermodule(sess, admin_modfirst); - aim__registermodule(sess, bos_modfirst); - aim__registermodule(sess, search_modfirst); - aim__registermodule(sess, stats_modfirst); - aim__registermodule(sess, auth_modfirst); - aim__registermodule(sess, msg_modfirst); - aim__registermodule(sess, chatnav_modfirst); - aim__registermodule(sess, chat_modfirst); - aim__registermodule(sess, locate_modfirst); - aim__registermodule(sess, general_modfirst); + /* + * 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; } /** * aim_session_kill - Deallocate a session * @sess: Session to kill * - * */ -faim_export void aim_session_kill(struct aim_session_t *sess) +faim_export void aim_session_kill(aim_session_t *sess) { - aim_logoff(sess); + aim_logoff(sess); - aim__shutdownmodules(sess); + aim__shutdownmodules(sess); - return; + return; } /** @@ -850,15 +815,15 @@ * the value faimdprintf was called with. * */ -faim_export int aim_setdebuggingcb(struct aim_session_t *sess, faim_debugging_callback_t cb) +faim_export int aim_setdebuggingcb(aim_session_t *sess, faim_debugging_callback_t cb) { - if (!sess) - return -1; + if (!sess) + return -1; - sess->debugcb = cb; + sess->debugcb = cb; - return 0; + return 0; } /** @@ -870,76 +835,81 @@ * has yet to be called on it). * */ -faim_export int aim_conn_isconnecting(struct aim_conn_t *conn) +faim_export int aim_conn_isconnecting(aim_conn_t *conn) { - if (!conn) - return 0; - return (conn->status & AIM_CONN_STATUS_INPROGRESS)?1:0; + + if (!conn) + return 0; + + return !!(conn->status & AIM_CONN_STATUS_INPROGRESS); } -faim_export int aim_conn_completeconnect(struct aim_session_t *sess, struct aim_conn_t *conn) +/* + * XXX this is nearly as ugly as proxyconnect(). + */ +faim_export int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn) { - fd_set fds, wfds; - struct timeval tv; - int res, error = ETIMEDOUT; - aim_rxcallback_t userfunc; - - if (!conn || (conn->fd == -1)) - return -1; + fd_set fds, wfds; + struct timeval tv; + int res, error = ETIMEDOUT; + aim_rxcallback_t userfunc; - if (!(conn->status & AIM_CONN_STATUS_INPROGRESS)) - return -1; + if (!conn || (conn->fd == -1)) + return -1; + + if (!(conn->status & AIM_CONN_STATUS_INPROGRESS)) + return -1; - FD_ZERO(&fds); - FD_SET(conn->fd, &fds); - FD_ZERO(&wfds); - FD_SET(conn->fd, &wfds); - tv.tv_sec = 0; - tv.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(conn->fd, &fds); + FD_ZERO(&wfds); + FD_SET(conn->fd, &wfds); + tv.tv_sec = 0; + tv.tv_usec = 0; - if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) { - error = errno; - aim_conn_close(conn); - errno = error; - return -1; - } else if (res == 0) { - faimdprintf(sess, 0, "aim_conn_completeconnect: false alarm on %d\n", conn->fd); - return 0; /* hasn't really completed yet... */ - } + if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) { + error = errno; + aim_conn_close(conn); + errno = error; + return -1; + } else if (res == 0) { + faimdprintf(sess, 0, "aim_conn_completeconnect: false alarm on %d\n", conn->fd); + return 0; /* hasn't really completed yet... */ + } - if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) { - int len = sizeof(error); + if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) { + int len = sizeof(error); - if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) - error = errno; - } + if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) + error = errno; + } - if (error) { - aim_conn_close(conn); - errno = error; - return -1; - } + if (error) { + aim_conn_close(conn); + errno = error; + return -1; + } - fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */ + fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */ - conn->status &= ~AIM_CONN_STATUS_INPROGRESS; + conn->status &= ~AIM_CONN_STATUS_INPROGRESS; - if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE))) - userfunc(sess, NULL, conn); + if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE))) + userfunc(sess, NULL, conn); - /* Flush out the queues if there was something waiting for this conn */ - aim_tx_flushqueue(sess); + /* Flush out the queues if there was something waiting for this conn */ + aim_tx_flushqueue(sess); - return 0; + return 0; } -faim_export struct aim_session_t *aim_conn_getsess(struct aim_conn_t *conn) +faim_export aim_session_t *aim_conn_getsess(aim_conn_t *conn) { - if (!conn) - return NULL; + if (!conn) + return NULL; - return (struct aim_session_t *)conn->sessv; + return (aim_session_t *)conn->sessv; } /* @@ -948,12 +918,12 @@ * Closes -ALL- open connections. * */ -faim_export int aim_logoff(struct aim_session_t *sess) +faim_export int aim_logoff(aim_session_t *sess) { - aim_connrst(sess); /* in case we want to connect again */ + aim_connrst(sess); /* in case we want to connect again */ - return 0; + return 0; } diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/faimconfig.h --- a/src/protocols/oscar/faimconfig.h Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/faimconfig.h Sun Sep 09 10:07:14 2001 +0000 @@ -40,16 +40,6 @@ #define FAIM_LOGIN_PORT 5190 /* - * The integer extraction/copying functions in aim_util.c have - * both a function version and a macro version. The macro - * version is suggested. Since the function version is more - * readable, I leave both around for reference. - * - * Default: defined. - */ -#define AIMUTIL_USEMACROS - -/* * What type of synchronisation to use. * * We don't actually use threads, but can use the POSIX mutex @@ -83,7 +73,7 @@ #define FAIM_SNAC_HASH_SIZE 16 /* - * If building on Win32,define WIN32_STATIC if you don't want + * If building on Win32, define WIN32_STATIC if you don't want * to compile libfaim as a DLL (and instead link it right into * your app). */ diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/ft.c --- a/src/protocols/oscar/ft.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/ft.c Sun Sep 09 10:07:14 2001 +0000 @@ -21,10 +21,17 @@ o look for memory leaks.. there's going to be shitloads, i'm sure. */ +struct aim_directim_intdata { + fu8_t cookie[8]; + char sn[MAXSNLEN+1]; + char ip[22]; +}; + +static int listenestablish(fu16_t portnum); static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr); /** - * aim_handlerendconnect - call this to accept OFT connections and set up the requisite structures + * aim_handlerendconnect - call this to accept OFT connections and set up the required structures * @sess: the session * @cur: the conn the incoming connection is on * @@ -34,82 +41,70 @@ * listener conn are both returned to the client in the * %AIM_CB_FAM_OFT, %AIM_CB_OFT_INITIATE callback. */ -faim_export int aim_handlerendconnect(struct aim_session_t *sess, struct aim_conn_t *cur) +faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur) { - int acceptfd = 0; - aim_rxcallback_t userfunc; - struct sockaddr cliaddr; - int clilen = sizeof(cliaddr); - int ret = 0; - struct aim_conn_t *newconn; + int acceptfd = 0; + struct sockaddr cliaddr; + int clilen = sizeof(cliaddr); + int ret = 0; + aim_conn_t *newconn; - if ( (acceptfd = accept(cur->fd, &cliaddr, &clilen)) == -1) - return -1; - if (cliaddr.sa_family != AF_INET) { /* just in case IPv6 really is happening */ - close(acceptfd); - aim_conn_close(cur); - return -1; - } + if ((acceptfd = accept(cur->fd, &cliaddr, &clilen)) == -1) + return 0; /* not an error */ - /* safe? maybe cur->priv should be NULLed after this. --mid */ - - /* That would be bad. very bad. we want cur->priv->sn to make it up - to the client-level for conn management and such. even though - that is abusing the interface --jbm */ + if (cliaddr.sa_family != AF_INET) { /* just in case IPv6 really is happening */ + close(acceptfd); + aim_conn_close(cur); + return -1; + } - if (!(newconn = aim_cloneconn(sess, cur))) { - close(acceptfd); - aim_conn_close(cur); - return -1; - } + if (!(newconn = aim_cloneconn(sess, cur))) { + close(acceptfd); + aim_conn_close(cur); + return -1; + } - newconn->type = AIM_CONN_TYPE_RENDEZVOUS; - newconn->fd = acceptfd; + newconn->type = AIM_CONN_TYPE_RENDEZVOUS; + newconn->fd = acceptfd; - switch(newconn->subtype) { - case AIM_CONN_SUBTYPE_OFT_DIRECTIM: { - struct aim_directim_priv *priv; - - priv = cur->priv; + if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { + struct aim_directim_intdata *priv; + aim_rxcallback_t userfunc; - newconn->priv = cur->priv; - - cur->priv = NULL; + priv = (struct aim_directim_intdata *)(newconn->internal = cur->internal); + cur->internal = NULL; - snprintf(priv->ip, sizeof(priv->ip), "%s:%u", - inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), - ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); + snprintf(priv->ip, sizeof(priv->ip), "%s:%u", + inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), + ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); - if ( (userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE))) - ret = userfunc(sess, NULL, newconn, cur); + if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE))) + ret = userfunc(sess, NULL, newconn, cur); - break; - } - case AIM_CONN_SUBTYPE_OFT_GETFILE: { - struct aim_filetransfer_priv *priv; + } else if (newconn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) { +#if 0 + struct aim_filetransfer_priv *priv; + aim_rxcallback_t userfunc; - newconn->priv = cur->priv; - cur->priv = NULL; - priv = (struct aim_filetransfer_priv *)newconn->priv; + newconn->priv = cur->priv; + cur->priv = NULL; + priv = (struct aim_filetransfer_priv *)newconn->priv; - snprintf(priv->ip, sizeof(priv->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); - - if ( (userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE))) - ret = userfunc(sess, NULL, newconn, cur); + snprintf(priv->ip, sizeof(priv->ip), "%s:%u", inet_ntoa(((struct sockaddr_in *)&cliaddr)->sin_addr), ntohs(((struct sockaddr_in *)&cliaddr)->sin_port)); - break; - } - default: { - faimdprintf(sess, 1,"Got a Connection on a listener that's not Rendezvous(??!) Closing conn.\n"); - aim_conn_close(newconn); - break; - } - } + if ((userfunc = aim_callhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE))) + ret = userfunc(sess, NULL, newconn, cur); +#endif + } else { + faimdprintf(sess, 1,"Got a Connection on a listener that's not Rendezvous(??!) Closing conn.\n"); + aim_conn_close(newconn); + ret = -1; + } - return ret; + return ret; } - + /** * aim_send_im_direct - send IM client-to-client over established connection * @sess: session to conn @@ -119,105 +114,176 @@ * Call this just like you would aim_send_im, to send a directim. You * _must_ have previously established the directim connection. */ -faim_export int aim_send_im_direct(struct aim_session_t *sess, struct aim_conn_t *conn, char *msg) +faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg) { - struct command_tx_struct *newpacket; - struct aim_directim_priv *priv = NULL; - int i; - - if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !conn->priv) { - faimdprintf(sess, 2,"faim: directim: invalid arguments\n"); - return -1; - } + struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal; + aim_frame_t *fr; + aim_bstream_t hdrbs; /* XXX this should be within aim_frame_t */ - priv = (struct aim_directim_priv *)conn->priv; + if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS)) + return -EINVAL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0001, strlen(msg)))) { - faimdprintf(sess, 2,"faim: directim: tx_new failed\n"); - return -1; - } - - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x01, strlen(msg)))) + return -ENOMEM; - /* if msg is non-null, we'resending an IM, else a "typing" notice */ - if (msg) { - if (strlen(msg) >= MAXMSGLEN) - return -1; - newpacket->hdr.oft.hdr2len = 0x54; - if (!(newpacket->hdr.oft.hdr2 = calloc(1,newpacket->hdr.oft.hdr2len))) { - newpacket->lock = 0; - aim_tx_destroy(newpacket); - return -1; - } - } else { - newpacket->hdr.oft.hdr2len = 0x44; - if (!(newpacket->hdr.oft.hdr2 = calloc(1,newpacket->hdr.oft.hdr2len))) { - newpacket->lock = 0; - aim_tx_destroy(newpacket); - return -1; - } - } + memcpy(fr->hdr.oft.magic, "ODC2", 4); + + fr->hdr.oft.hdr2len = 0x44; + + if (!(fr->hdr.oft.hdr2 = calloc(1, fr->hdr.oft.hdr2len))) { + aim_frame_destroy(fr); + return -ENOMEM; + } + + aim_bstream_init(&hdrbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len); - memcpy(newpacket->hdr.oft.magic, "ODC2", 4); - newpacket->data = NULL; + aimbs_put16(&hdrbs, 0x0006); + aimbs_put16(&hdrbs, 0x0000); + aimbs_putraw(&hdrbs, intdata->cookie, 8); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put32(&hdrbs, strlen(msg)); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); - i = 0; - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0006); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, (char *)priv->cookie, 8); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put32(newpacket->hdr.oft.hdr2+i, strlen(msg)); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); + /* flags -- 0x000e for "typing", 0x0000 for message */ + aimbs_put16(&hdrbs, msg ? 0x0000 : 0x000e); + + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); + aimbs_putraw(&hdrbs, sess->sn, strlen(sess->sn)); + + aim_bstream_setpos(&hdrbs, 52); /* bleeehh */ - /* flags -- 0x000e for "typing", 0x0000 for message */ - if (msg) - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - else - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000e); - - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, sess->sn, strlen(sess->sn)); - i = 52; + aimbs_put8(&hdrbs, 0x00); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); + aimbs_put16(&hdrbs, 0x0000); - i += aimutil_put8(newpacket->hdr.oft.hdr2+i, 0x00); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - - /* end of hdr2 */ + /* end of hdr2 */ - if (msg) { - /* values grabbed from a dump */ - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e); - i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8); - if(!(newpacket->data = strdup(msg))) - return -1; - } - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); - return 0; + if (msg) { +#if 0 /* XXX this is how you send buddy icon info... */ + i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0008); + i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x000c); + i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000); + i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x1466); + i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0001); + i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x2e0f); + i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x393e); + i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0xcac8); +#endif + aimbs_putraw(&fr->data, msg, strlen(msg)); + } + + aim_tx_enqueue(sess, fr); + + return 0; } /* XXX: give the client author the responsibility of setting up a * listener, then we no longer have a libfaim problem with broken * solaris *innocent smile* -jbm */ +static int getlocalip(fu8_t *ip) +{ + struct hostent *hptr; + char localhost[129]; + + /* XXX if available, use getaddrinfo() */ + /* XXX allow client to specify which IP to use for multihomed boxes */ + + if (gethostname(localhost, 128) < 0) + return -1; + + if (!(hptr = gethostbyname(localhost))) + return -1; + + memcpy(ip, hptr->h_addr_list[0], 4); + + return 0; +} + +/* XXX this should probably go in im.c */ +static int aim_request_directim(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu8_t *ip, fu16_t port, fu8_t *ckret) +{ + fu8_t ck[8]; + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL, *itl = NULL; + int hdrlen, i; + fu8_t *hdr; + aim_bstream_t hdrbs; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 256+strlen(destsn)))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); + + /* + * Generate a random message cookie + * + * This cookie needs to be alphanumeric and NULL-terminated to be + * TOC-compatible. + * + * XXX have I mentioned these should be generated in msgcookie.c? + * + */ + for (i = 0; i < 7; i++) + ck[i] = 0x30 + ((fu8_t) rand() % 10); + ck[7] = '\0'; + + if (ckret) + memcpy(ckret, ck, 8); + + /* Cookie */ + aimbs_putraw(&fr->data, ck, 8); + + /* Channel */ + aimbs_put16(&fr->data, 0x0002); + + /* Destination SN */ + aimbs_put8(&fr->data, strlen(destsn)); + aimbs_putraw(&fr->data, destsn, strlen(destsn)); + + aim_addtlvtochain_noval(&tl, 0x0003); + + hdrlen = 2+8+16+6+8+6+4; + hdr = malloc(hdrlen); + aim_bstream_init(&hdrbs, hdr, hdrlen); + + aimbs_put16(&hdrbs, 0x0000); + aimbs_putraw(&hdrbs, ck, 8); + aim_putcap(&hdrbs, AIM_CAPS_IMIMAGE); + + aim_addtlvtochain16(&itl, 0x000a, 0x0001); + aim_addtlvtochain_raw(&itl, 0x0003, 4, ip); + aim_addtlvtochain16(&itl, 0x0005, port); + aim_addtlvtochain_noval(&itl, 0x000f); + + aim_writetlvchain(&hdrbs, &itl); + + aim_addtlvtochain_raw(&tl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); + + aim_writetlvchain(&fr->data, &tl); + + free(hdr); + aim_freetlvchain(&itl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); + + return 0; +} + /** * aim_directim_intitiate - For those times when we want to open up the directim channel ourselves. * @sess: your session, @@ -226,131 +292,58 @@ * @destsn: the SN to connect to. * */ -faim_export struct aim_conn_t *aim_directim_initiate(struct aim_session_t *sess, - struct aim_conn_t *conn, - struct aim_directim_priv *priv, - char *destsn) +faim_export aim_conn_t *aim_directim_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn) { - - struct command_tx_struct *newpacket; - struct aim_conn_t *newconn; - struct aim_msgcookie_t *cookie; - int curbyte, i, listenfd; - short port = 4443; - struct hostent *hptr; - char localhost[129]; - unsigned char cap[16]; - char d[4]; /* IPv6 is a bit bigger... */ - - /* XXX: TLVlist-ize this */ - - /* Open our socket */ - - if ( (listenfd = aim_listenestablish(port)) == -1) - return NULL; + aim_conn_t *newconn; + aim_msgcookie_t *cookie; + struct aim_directim_intdata *priv; + int listenfd; + fu16_t port = 4443; + fu8_t localip[4]; + fu8_t ck[8]; - /* get our local IP */ - /* XXX if available, use getaddrinfo() */ - /* XXX allow client to specify which IP to use for multihomed boxes */ - if (gethostname(localhost, 128) < 0) - return NULL; - if ( (hptr = gethostbyname(localhost)) == NULL) - return NULL; - memcpy(&d, hptr->h_addr_list[0], 4); + if (getlocalip(localip) == -1) + return NULL; - aim_putcap(cap, 16, AIM_CAPS_IMIMAGE); - - /* create the OSCAR packet */ + if ((listenfd = listenestablish(port)) == -1) + return NULL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(destsn)+4+4+0x32))) - return NULL; - newpacket->lock = 1; - - curbyte = 0; - curbyte += aim_putsnac(newpacket->data+curbyte, 0x0004, 0x0006, 0x0000, sess->snac_nextid); + aim_request_directim(sess, conn, destsn, localip, port, ck); - /* Generate a random message cookie */ - /* This cookie needs to be alphanumeric and NULL-terminated to be TOC-compatible. */ - for (i=0; i<7; i++) - curbyte += aimutil_put8(newpacket->data+curbyte, 0x30 + ((u_char) rand() % 20)); + cookie = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)); + memcpy(cookie->cookie, ck, 8); + cookie->type = AIM_COOKIETYPE_OFTIM; - curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); - - /* grab all the data for cookie caching */ - cookie = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t)); - memcpy(cookie->cookie, newpacket->data+curbyte-8, 8); - cookie->type = AIM_COOKIETYPE_OFTIM; - priv = cookie->data; + priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata)); - if (!priv) - priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv)); - - memcpy(priv->cookie, cookie, 8); - memcpy(priv->sn, destsn, sizeof(priv->sn)); - cookie->data = priv; - aim_cachecookie(sess, cookie); - - /* Channel ID */ - curbyte += aimutil_put16(newpacket->data+curbyte,0x0002); + memcpy(priv->cookie, ck, 8); + strncpy(priv->sn, destsn, sizeof(priv->sn)); + cookie->data = priv; + aim_cachecookie(sess, cookie); - /* Destination SN (prepended with byte length)*/ - curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn)); - curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn)); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - - /* enTLV start */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0032); - - /* Flag data / ICBM Parameters */ - curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x00); - - /* Cookie */ - curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cookie, 8); - - /*Capability String */ - curbyte += aimutil_putstr(newpacket->data+curbyte, (char *)cap, 0x10); + /* XXX switch to aim_cloneconn()? */ + if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) { + close(listenfd); + return NULL; + } - /* 000a/0002 : 0001 */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + /* this one is for the conn */ + priv = (struct aim_directim_intdata *)calloc(1, sizeof(struct aim_directim_intdata)); - /* 0003/0004: IP address */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004); - for(i = 0;i < 4; i++) - curbyte += aimutil_put8(newpacket->data+curbyte, d[i]); - - /* 0005/0002: Port */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); - curbyte += aimutil_put16(newpacket->data+curbyte, port); + memcpy(priv->cookie, ck, 8); + strncpy(priv->sn, destsn, sizeof(priv->sn)); - /* 000f/0000: ?? */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - newpacket->commandlen = curbyte; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); - + newconn->fd = listenfd; + newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; + newconn->internal = priv; + newconn->lastactivity = time(NULL); - /* XXX switch to aim_cloneconn()? */ - if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS_OUT, NULL))) - return NULL; + faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); - newconn->fd = listenfd; - newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; - newconn->priv = priv; - newconn->lastactivity = time(NULL); - - faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); - - return newconn; + return newconn; } +#if 0 /** * unsigned int aim_oft_listener_clean - close up old listeners * @sess: session to clean up in @@ -381,35 +374,71 @@ faim_mutex_unlock(&sess->connlistlock); return hit; } +#endif + +faim_export const char *aim_directim_getsn(aim_conn_t *conn) +{ + struct aim_directim_intdata *intdata; + + if (!conn) + return NULL; + + if ((conn->type != AIM_CONN_TYPE_RENDEZVOUS) || + (conn->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) + return NULL; + + if (!conn->internal) + return NULL; + + intdata = (struct aim_directim_intdata *)conn->internal; + + return intdata->sn; +} /** * aim_directim_connect - connect to buddy for directim * @sess: the session to append the conn to, - * @conn: the BOS connection, - * @priv: the filled-in priv data structure for the connection + * @sn: the SN we're connecting to + * @addr: address to connect to + * + * This is a wrapper for aim_newconn. + * + * If addr is NULL, the socket is not created, but the connection is + * allocated and setup to connect. * - * returns conn if connected, %NULL on error */ -faim_export struct aim_conn_t *aim_directim_connect(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_directim_priv *priv) +faim_export aim_conn_t *aim_directim_connect(aim_session_t *sess, const char *sn, const char *addr, const fu8_t *cookie) { - struct aim_conn_t *newconn = NULL; + aim_conn_t *newconn; + struct aim_directim_intdata *intdata; + + if (!sess || !sn) + return NULL; + + if (!(intdata = malloc(sizeof(struct aim_directim_intdata)))) + return NULL; + memset(intdata, 0, sizeof(struct aim_directim_intdata)); - if (!sess || !conn || !priv) - return NULL; - - /* XXX verify that non-blocking connects actually work */ - newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, priv->ip); - if (!newconn || (newconn->fd == -1)) { - faimdprintf(sess, 2, "could not connect to %s\n", priv->ip); - perror("aim_newconn"); - return newconn; - } + memcpy(intdata->cookie, cookie, 8); + strncpy(intdata->sn, sn, sizeof(intdata->sn)); + if (addr) + strncpy(intdata->ip, addr, sizeof(intdata->ip)); - newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; - newconn->priv = priv; - faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd); + /* XXX verify that non-blocking connects actually work */ + if (!(newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr))) { + free(intdata); + return NULL; + } - return newconn; + if (!newconn) { + free(intdata); + return newconn; + } + + newconn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; + newconn->internal = intdata; + + return newconn; } /** @@ -420,24 +449,26 @@ * returns conn for directim with name, %NULL if none found. * */ -faim_export struct aim_conn_t *aim_directim_getconn(struct aim_session_t *sess, const char *name) +faim_export aim_conn_t *aim_directim_getconn(aim_session_t *sess, const char *name) { - struct aim_conn_t *cur; - struct aim_directim_priv *priv; + aim_conn_t *cur; - if (!sess || !name) - return NULL; + if (!sess || !name || !strlen(name)) + return NULL; - faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + struct aim_directim_intdata *intdata; + + if ((cur->type != AIM_CONN_TYPE_RENDEZVOUS) || (cur->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM)) + continue; - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->type != AIM_CONN_TYPE_RENDEZVOUS || cur->subtype != AIM_CONN_SUBTYPE_OFT_DIRECTIM) - continue; - priv = cur->priv; - if (aim_sncmp(priv->sn, name) == 0) - break; - } faim_mutex_unlock(&sess->connlistlock); - return cur; + intdata = cur->internal; + + if (aim_sncmp(intdata->sn, name) == 0) + break; + } + + return cur; } /** @@ -454,17 +485,21 @@ * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE) * * Returns new connection or %NULL on error. + * + * XXX this should take a struct. */ -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 aim_conn_t *aim_accepttransfer(aim_session_t *sess, + aim_conn_t *conn, + const char *sn, const fu8_t *cookie, + const fu8_t *ip, + fu16_t listingfiles, + fu16_t listingtotsize, + fu16_t listingsize, + fu32_t listingchecksum, + fu16_t rendid) +{ + return NULL; +#if 0 struct command_tx_struct *newpacket, *newoft; struct aim_conn_t *newconn; struct aim_fileheader_t *fh; @@ -547,7 +582,7 @@ if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); /* XXX: conn leak */ perror("calloc (1)"); return NULL; @@ -609,6 +644,7 @@ aim_tx_enqueue(sess, newpacket); return newconn; +#endif } /** @@ -621,9 +657,10 @@ * guess. * */ - -faim_export struct aim_fileheader_t *aim_getlisting(struct aim_session_t *sess, FILE *file) +faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *file) { + return NULL; +#if 0 struct aim_fileheader_t *fh; u_long totsize = 0, size = 0, checksum = 0xffff0000; short totfiles = 0; @@ -727,6 +764,7 @@ faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name)))); return fh; +#endif } /** @@ -736,80 +774,580 @@ * you need to call accept() when it's connected. returns your fd * */ -faim_export int aim_listenestablish(u_short portnum) +static int listenestablish(fu16_t portnum) { #if defined(__linux__) - /* XXX what other OS's support getaddrinfo? */ - int listenfd; - const int on = 1; - struct addrinfo hints, *res, *ressave; - char serv[5]; + /* XXX what other OS's support getaddrinfo? */ + int listenfd; + const int on = 1; + struct addrinfo hints, *res, *ressave; + char serv[5]; - snprintf(serv, sizeof(serv), "%d", portnum); - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_flags = AI_PASSIVE; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - if (getaddrinfo(NULL /*any IP*/, serv, &hints, &res) != 0) { - perror("getaddrinfo"); - return -1; - } - ressave = res; - do { - listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (listenfd < 0) - continue; - setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) - break; - /* success */ - close(listenfd); - } while ( (res = res->ai_next) ); + snprintf(serv, sizeof(serv), "%d", portnum); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(NULL /*any IP*/, serv, &hints, &res) != 0) { + perror("getaddrinfo"); + return -1; + } + ressave = res; + do { + listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (listenfd < 0) + continue; + setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) + break; + /* success */ + close(listenfd); + } while ( (res = res->ai_next) ); + + if (!res) + return -1; - if (!res) - return -1; - - if (listen(listenfd, 1024)!=0) { - perror("listen"); - return -1; - } + if (listen(listenfd, 1024)!=0) { + perror("listen"); + return -1; + } - freeaddrinfo(ressave); - return listenfd; + freeaddrinfo(ressave); + return listenfd; #else - int listenfd; - const int on = 1; - struct sockaddr_in sockin; + int listenfd; + const int on = 1; + struct sockaddr_in sockin; - if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket(listenfd)"); - return -1; - } + if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket(listenfd)"); + return -1; + } - if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on) != 0)) { - perror("setsockopt(listenfd)"); - close(listenfd); - return -1; - } - - memset(&sockin, 0, sizeof(struct sockaddr_in)); - sockin.sin_family = AF_INET; - sockin.sin_port = htons(portnum); + if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on) != 0)) { + perror("setsockopt(listenfd)"); + close(listenfd); + return -1; + } + + memset(&sockin, 0, sizeof(struct sockaddr_in)); + sockin.sin_family = AF_INET; + sockin.sin_port = htons(portnum); - if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { - perror("bind(listenfd)"); - close(listenfd); - return -1; - } - if (listen(listenfd, 4) != 0) { - perror("listen(listenfd)"); - close(listenfd); - return -1; - } - return listenfd; + if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { + perror("bind(listenfd)"); + close(listenfd); + return -1; + } + if (listen(listenfd, 4) != 0) { + perror("listen(listenfd)"); + close(listenfd); + return -1; + } + return listenfd; #endif } +static int getcommand_getfile(aim_session_t *sess, aim_conn_t *conn) +{ +#if 0 + struct aim_filetransfer_priv *ft; + aim_rxcallback_t userfunc; + + ft = conn->priv; + if (ft->state == 2) { + /* waiting on listing data */ + int ret = 0; + char *listing; + struct command_tx_struct *newoft; + + if (!(listing = malloc(ft->fh.size))) + return -1; + + ft->state = 0; + if (aim_recv(conn->fd, listing, ft->fh.size) != ft->fh.size) + faimdprintf(sess, 2, "OFT get: file %s was short. (0x%lx)\n", ft->fh.name, ft->fh.size); + + if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120b, 0))) { + faimdprintf(sess, 2, "faim: aim_get_command_rendezvous: getfile listing: tx_new OFT failed\n"); + faim_mutex_unlock(&conn->active); + free(listing); + aim_conn_close(conn); + return -1; + } + + memcpy(newoft->hdr.oft.magic, "OFT2", 4); + newoft->hdr.oft.hdr2len = 0x100 - 8; + + /* Protocol BS - set nrecvd to size of listing, recvcsum to listing checksum, flags to 0 */ + + ft->fh.nrecvd = ft->fh.size; + ft->fh.recvcsum = ft->fh.checksum; + ft->fh.flags = 0; + + if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { + aim_frame_destroy(newoft); + free(listing); + return -1; + } + + if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) + faimdprintf(sess, 2, "eek! bh fail listing\n"); + + /* send the 120b */ + aim_tx_enqueue(sess, newoft); + if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING)) ) + ret = userfunc(sess, NULL, conn, ft, listing); + + free(listing); + return ret; + } + + if (ft->state == 3) { + /* waiting on file data */ + if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE)) ) + return userfunc(sess, NULL, conn, ft); + return 0; + } + + if (ft->state == 4) { + if( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4)) ) + return userfunc(sess, NULL, conn); + aim_conn_close(conn); + return 0; + } + + return 0; +#else + return -1; +#endif +} + +static void connclose_sendfile(aim_session_t *sess, aim_conn_t *conn) +{ + aim_msgcookie_t *cook; + struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->priv; + + cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTSEND); + aim_cookie_free(sess, cook); + + return; +} + +static void connkill_sendfile(aim_session_t *sess, aim_conn_t *conn) +{ + + free(conn->internal); + + return; +} + +static void connclose_getfile(aim_session_t *sess, aim_conn_t *conn) +{ + aim_msgcookie_t *cook; + struct aim_filetransfer_priv *priv = (struct aim_filetransfer_priv *)conn->priv; + + cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTGET); + aim_cookie_free(sess, cook); + + return; +} + +static void connkill_getfile(aim_session_t *sess, aim_conn_t *conn) +{ + + free(conn->internal); + + return; +} + +static void connclose_directim(aim_session_t *sess, aim_conn_t *conn) +{ + struct aim_directim_intdata *intdata = (struct aim_directim_intdata *)conn->internal; + aim_msgcookie_t *cook; + + cook = aim_uncachecookie(sess, intdata->cookie, AIM_COOKIETYPE_OFTIM); + aim_cookie_free(sess, cook); + + return; +} + +static void connkill_directim(aim_session_t *sess, aim_conn_t *conn) +{ + + free(conn->internal); + + return; +} + +faim_internal void aim_conn_close_rend(aim_session_t *sess, aim_conn_t *conn) +{ + + if (conn->type != AIM_CONN_TYPE_RENDEZVOUS) + return; + + if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) + connclose_sendfile(sess, conn); + else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) + connclose_getfile(sess, conn); + else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) + connclose_directim(sess, conn); + + return; +} + +faim_internal void aim_conn_kill_rend(aim_session_t *sess, aim_conn_t *conn) +{ + + if (conn->type != AIM_CONN_TYPE_RENDEZVOUS) + return; + + if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) + connkill_sendfile(sess, conn); + else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) + connkill_getfile(sess, conn); + else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) + connkill_directim(sess, conn); + + return; +} + +static int handlehdr_directim(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) +{ + aim_frame_t fr; + aim_rxcallback_t userfunc; + fu32_t payloadlength; + fu16_t flags; + char *snptr = NULL; + + fr.conn = conn; + + payloadlength = aimutil_get32(hdr+22); + flags = aimutil_get16(hdr+32); + snptr = (char *)hdr+38; + + faimdprintf(sess, 2, "faim: OFT frame: handlehdr_directim: %04x / %04x / %s\n", payloadlength, flags, snptr); + + if (flags == 0x000e) { + int ret = 0; + + if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING))) + ret = userfunc(sess, &fr, snptr); + + return ret; + + } else if ((flags == 0x0000) && payloadlength) { + char *msg; + int ret = 0; + + if (!(msg = calloc(1, payloadlength+1))) + return -1; + + if (aim_recv(conn->fd, msg, payloadlength) < payloadlength) { + free(msg); + return -1; + } + + msg[payloadlength] = '\0'; + + if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) ) + ret = userfunc(sess, &fr, snptr, msg); + + free(msg); + + return ret; + } + + return 0; +} + +static int handlehdr_getfile_listing(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) +{ +#if 0 + struct aim_filetransfer_priv *ft; + struct aim_fileheader_t *fh; + struct aim_msgcookie_t *cook; + struct command_tx_struct *newoft; + aim_rxcallback_t userfunc; + + faimdprintf(sess, 2,"faim: rend: fileget 0x1108\n"); + fh = aim_oft_getfh(hdr); + + faim_mutex_unlock(&conn->active); + + if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { + free(fh); + return -1; + } + + ft = cook->data; + + /* we're waaaaiiiting.. for listing.txt */ + ft->state = 2; + + memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); + free(fh); + + if(aim_cachecookie(sess, cook) == -1) { + faimdprintf(sess, 1, "error caching cookie\n"); + return -1; + } + + if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x1209, 0))) { + aim_conn_close(conn); + return -1; + } + + memcpy(newoft->hdr.oft.magic, "OFT2", 4); + newoft->hdr.oft.hdr2len = 0x100 - 8; + + if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { + newoft->lock = 0; + aim_frame_destroy(newoft); + return -1; + } + + if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { + newoft->lock = 0; + aim_frame_destroy(newoft); + return -1; + } + + newoft->lock = 0; + aim_tx_enqueue(sess, newoft); +#endif + return -1; +} + +static int handlehdr_getfile_listing2(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) +{ +#if 0 + struct aim_filetransfer_priv *ft; + struct aim_fileheader_t *fh; + struct aim_msgcookie_t *cook; + int ret = 0; + aim_rxcallback_t userfunc; + + fh = aim_oft_getfh(hdr); + + if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) + faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", AIM_COOKIETYPE_OFTGET, fh->bcookie); + + ft = cook->data; + + if (ft->fh.size != fh->size) + faimdprintf(sess, 2, "hrm. ft->fh.size (%ld) != fh->size (%ld). um. using ft->fh.size\n", ft->fh.size, fh->size); + + if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ))) + ret = userfunc(sess, NULL, conn, fh); + + faimdprintf(sess, 2, "faim: get_command_rendezvous: hit end of 1209\n"); + + free(fh); + + return ret; +#else + return -1; +#endif +} + +static int handlehdr_getfile_listing3(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) +{ +#if 0 + struct aim_filetransfer_priv *ft; + struct aim_msgcookie_t *cook; + struct aim_fileheader_t *fh; + aim_rxcallback_t userfunc; + + fh = aim_oft_getfh(hdr); + + if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { + free(fh); + return -1; + } + + free(fh); + + ft = cook->data; + + if (aim_cachecookie(sess, cook) == -1) + return -1; + + if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGRXCONFIRM))) + return userfunc(sess, NULL, conn); +#endif + return -1; +} + +static int handlehdr_getfile_request(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) +{ +#if 0 + struct aim_filetransfer_priv *ft; + struct aim_msgcookie_t *cook; + struct aim_fileheader_t *fh; + struct command_tx_struct *newoft; + int i = 0; + aim_rxcallback_t userfunc; + + fh = aim_oft_getfh(hdr); + + if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { + free(fh); + return -1; + } + + ft = cook->data; + memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); + free(fh); + + aim_cachecookie(sess, cook); + + faimdprintf(sess, 2, "faim: fileget: %s seems to want %s\n", ft->sn, ft->fh.name); + + if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) ) + i = userfunc(sess, NULL, conn, &(ft->fh), cook->cookie); + + if (i < 0) + return i; + + if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0101, 0))) { + faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n"); + return -1; + } + + newoft->lock = 1; + memcpy(newoft->hdr.oft.magic, "OFT2", 4); + newoft->hdr.oft.hdr2len = 0x100 - 8; + + if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) { + aim_frame_destroy(newoft); + return -1; + } + + /* protocol BS: nrecvd, recvcsum to 0, flags to 0x20. */ + ft->fh.nrecvd = 0; + ft->fh.recvcsum = 0; + ft->fh.flags = 0x20; + + aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)); + + newoft->lock = 0; + aim_tx_enqueue(sess, newoft); + + faimdprintf(sess, 2, "faim: OFT: OFT file header enqueued.\n"); + + return i; +#else + return -1; +#endif +} + +static int handlehdr_getfile_sending(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) +{ +#if 0 + struct aim_fileheader_t *fh; + struct aim_filetransfer_priv *ft; + struct aim_msgcookie_t *cook; + struct command_tx_struct *newoft; + aim_rxcallback_t userfunc; + + fh = aim_oft_getfh(hdr); + + if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { + free(fh); + return -1; + } + + free(fh); + + ft = cook->data; + + ft->state = 3; + + if (aim_cachecookie(sess, cook) == -1) + return -1; + + faimdprintf(sess, 2, "faim: fileget: %s seems to want to send %s\n", ft->sn, ft->fh.name); + + if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) { + faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n"); + return -1; + } + + newoft->lock = 1; + memcpy(newoft->hdr.oft.magic, "OFT2", 4); + + newoft->hdr.oft.hdr2len = 0x100 - 8; + + if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) { + aim_frame_destroy(newoft); + return -1; + } + + aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)); + + newoft->lock = 0; + aim_tx_enqueue(sess, newoft); + + faimdprintf(sess, 2, "faim: OFT: OFT 0x0202 enqueued.\n"); + + if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) == NULL) + return 1; +#else + return -1; +#endif +} + +static int handlehdr_getfile_recv(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) +{ +#if 0 + struct aim_fileheader_t *fh; + struct aim_filetransfer_priv *ft; + struct aim_msgcookie_t *cook; + int ret = 1; + aim_rxcallback_t userfunc; + + fh = aim_oft_getfh(hdr); + + if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { + free(fh); + return -1; + } + + ft = cook->data; + + faimdprintf(sess, 2, "faim: get_rend: looks like we're ready to send data.(oft 0x0202)\n"); + + if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND)) ) + ret = userfunc(sess, NULL, conn, fh); + + free(fh); + + return ret; +#else + return -1; +#endif +} + +static int handlehdr_getfile_finish(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) +{ +#if 0 + struct aim_fileheader_t *fh; + aim_rxcallback_t userfunc; + + fh = aim_oft_getfh(hdr); + + faimdprintf(sess, 2, "faim: get_rend: looks like we're done with a transfer (oft 0x0204)\n"); + + if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE)) ) + userfunc(sess, NULL, conn, fh); + + free(fh); +#endif + + return -1; +} + /** * aim_get_command_rendezvous - OFT equivalent of aim_get_command * @sess: session to work on @@ -818,576 +1356,76 @@ * this reads and handles data from conn->fd. currently a little rough * around the edges */ -faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_internal int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn) { - unsigned char hdrbuf1[6]; - unsigned char *hdr = NULL; - int hdrlen, hdrtype; - int flags = 0; - aim_rxcallback_t userfunc = NULL; - - if (!sess || !conn || !conn->priv) - return -1; - - memset(hdrbuf1, 0, sizeof(hdrbuf1)); - faim_mutex_lock(&conn->active); - - /* gets locked down for the entirety */ - - if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE ) { - struct aim_filetransfer_priv *ft; - ft = conn->priv; - if (ft->state == 2) { - /* waiting on listing data */ - int ret = 0; - char *listing; - struct command_tx_struct *newoft; - if (!(listing = malloc(ft->fh.size))) { - faim_mutex_unlock(&conn->active); - return -1; - } - - ft->state = 0; - if (aim_recv(conn->fd, listing, ft->fh.size) != ft->fh.size) - faimdprintf(sess, 2, "OFT get: file %s was short. (0x%lx)\n", ft->fh.name, ft->fh.size); - - if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120b, 0))) { - faimdprintf(sess, 2, "faim: aim_get_command_rendezvous: getfile listing: tx_new OFT failed\n"); - faim_mutex_unlock(&conn->active); - free(listing); - aim_conn_close(conn); - return -1; - } - - newoft->lock = 1; - - memcpy(newoft->hdr.oft.magic, "OFT2", 4); - newoft->hdr.oft.hdr2len = 0x100 - 8; - - /* Protocol BS - set nrecvd to size of listing, recvcsum to - listing checksum, flags to 0 */ - - ft->fh.nrecvd = ft->fh.size; - ft->fh.recvcsum = ft->fh.checksum; - ft->fh.flags = 0; - - if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { - newoft->lock = 0; - aim_tx_destroy(newoft); - free(listing); - faim_mutex_unlock(&conn->active); - return -1; - } - - if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) - faimdprintf(sess, 2, "eek! bh fail listing\n"); + fu8_t hdrbuf1[6]; + fu8_t *hdr = NULL; + int hdrlen, hdrtype; + int ret = -1; - /* send the 120b */ - newoft->lock = 0; - aim_tx_enqueue(sess, newoft); - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING)) ) - ret = userfunc(sess, NULL, conn, ft, listing); - - faim_mutex_unlock(&conn->active); - free(listing); - return ret; - } - if (ft->state == 3) { - /* waiting on file data */ - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE)) ) { - faim_mutex_unlock(&conn->active); - return userfunc(sess, NULL, conn, ft); - } - faim_mutex_unlock(&conn->active); - return 0; - } - if(ft->state == 4) { - if( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4)) ) { - faim_mutex_unlock(&conn->active); - return userfunc(sess, NULL, conn); - } - faim_mutex_unlock(&conn->active); - aim_conn_close(conn); - return 0; - } - } - - if ( (hdrlen = aim_recv(conn->fd, hdrbuf1, 6)) < 6) { - faimdprintf(sess, 2, "faim: rend: read error (fd: %i) %02x%02x%02x%02x%02x%02x (%i)\n", - conn->fd, hdrbuf1[0],hdrbuf1[1],hdrbuf1[2],hdrbuf1[3],hdrbuf1[4],hdrbuf1[5],hdrlen); - faim_mutex_unlock(&conn->active); - if (hdrlen < 0) - perror("read"); - else { /* disconnected */ - char *screenname = NULL; - int ret; - struct aim_msgcookie_t *cook; + if (!sess || !conn) + return -1; - switch(conn->subtype) { - case AIM_CONN_SUBTYPE_OFT_DIRECTIM: { - struct aim_directim_priv *priv = NULL; - if (!(priv = (struct aim_directim_priv *)conn->priv) ) - return -1; - - screenname = strdup(priv->sn); - - cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTIM); - aim_cookie_free(sess, cook); - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT)) ) { - aim_conn_close(conn); - ret = userfunc(sess, NULL, conn, screenname); - free(screenname); - return ret; - } - break; - } - case AIM_CONN_SUBTYPE_OFT_GETFILE: { - struct aim_filetransfer_priv *priv; - if (!(priv = (struct aim_filetransfer_priv *)conn->priv)) - return -1; - screenname = strdup(priv->sn); - - cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTGET); - - aim_cookie_free(sess, cook); + memset(hdrbuf1, 0, sizeof(hdrbuf1)); - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT)) ) { - aim_conn_close(conn); - ret = userfunc(sess, NULL, conn, screenname); - free(screenname); - return ret; - } - break; - } - case AIM_CONN_SUBTYPE_OFT_SENDFILE: { - struct aim_filetransfer_priv *priv; - if (!(priv = (struct aim_filetransfer_priv *)conn->priv)) - return -1; - - screenname = strdup(priv->sn); - - cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTSEND); - aim_cookie_free(sess, cook); - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_SENDFILEDISCONNECT)) ) { - aim_conn_close(conn); - ret = userfunc(sess, NULL, conn, screenname); - free(screenname); - return ret; - } - break; - } - } - - aim_conn_close(conn); - return -1; - } - } - - hdrlen = aimutil_get16(hdrbuf1+4); - hdrlen -= 6; + /* I guess? I didn't understand any of that mess... */ + if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) + return getcommand_getfile(sess, conn); - if (!(hdr = malloc(hdrlen))) { - faim_mutex_unlock(&conn->active); - return -1; - } - - if (aim_recv(conn->fd, hdr, hdrlen) < hdrlen) { - perror("read"); - faimdprintf(sess, 2,"faim: rend: read2 error on %d (%d)\n", conn->fd, hdrlen); - free(hdr); - faim_mutex_unlock(&conn->active); - aim_conn_close(conn); - return -1; - } - hdrtype = aimutil_get16(hdr); + /* XXX fix all the error cases here */ + if (aim_recv(conn->fd, hdrbuf1, 6) < 6) { - switch (hdrtype) { - case 0x0001: { /* directim */ - int payloadlength = 0; - char *snptr = NULL; - struct aim_directim_priv *priv; - int i; - - if (!(priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv)))) { - faim_mutex_unlock(&conn->active); - free(hdr); - return -1; - } - - payloadlength = aimutil_get32(hdr+22); - flags = aimutil_get16(hdr+32); - snptr = (char *)hdr+38; - strncpy(priv->sn, snptr, MAXSNLEN); - - faimdprintf(sess, 2, "faim: OFT frame: %04x / %04x / %04x / %s\n", hdrtype, payloadlength, flags, priv->sn); - - free(hdr); - hdr = NULL; + faimdprintf(sess, 2, "faim: rend: read error (fd: %i)\n", conn->fd); - if (flags == 0x000e) { - faim_mutex_unlock(&conn->active); - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING)) ) - return userfunc(sess, NULL, conn); - } else { - - if ((flags == 0x0000) && payloadlength) { - unsigned char *msg; - - if (!(msg = calloc(1, payloadlength+1))) { - faim_mutex_unlock(&conn->active); - return -1; - } + aim_conn_close(conn); - if (aim_recv(conn->fd, msg, payloadlength) < payloadlength) { - perror("read"); - faimdprintf(sess, 2,"faim: rend: read3 error\n"); - free(msg); - faim_mutex_unlock(&conn->active); - aim_conn_close(conn); - return -1; - } - - faim_mutex_unlock(&conn->active); - msg[payloadlength] = 0x00; - faimdprintf(sess, 2, "faim: directim: %s/%04x/%04x/%s\n", priv->sn, payloadlength, flags, msg); - - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING)) ) - i = userfunc(sess, NULL, conn, msg); - else { - faimdprintf(sess, 0, "directim: %s/%04x/%04x/%s\n", priv->sn, payloadlength, flags, msg); - i = 1; - } - - free(msg); + return -1; + } - return i; - } - } - break; - } - case 0x1108: { /* getfile listing.txt incoming tx->rx */ - struct aim_filetransfer_priv *ft; - struct aim_fileheader_t *fh; - struct aim_msgcookie_t *cook; - struct command_tx_struct *newoft; - - faimdprintf(sess, 2,"faim: rend: fileget 0x1108\n"); - fh = aim_oft_getfh(hdr); - - free(hdr); - hdr = NULL; - - faim_mutex_unlock(&conn->active); + hdrlen = aimutil_get16(hdrbuf1+4); + hdrlen -= 6; - if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { - faim_mutex_unlock(&conn->active); - free(fh); - return -1; - } - - ft = cook->data; - - /* we're waaaaiiiting.. for listing.txt */ - ft->state = 2; - - memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); - free(fh); - - if(aim_cachecookie(sess, cook) == -1) { - faimdprintf(sess, 1, "error caching cookie\n"); - return -1; - } - - if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x1209, 0))) { - aim_conn_close(conn); - return -1; - } + hdr = malloc(hdrlen); - memcpy(newoft->hdr.oft.magic, "OFT2", 4); - newoft->hdr.oft.hdr2len = 0x100 - 8; - - if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { - newoft->lock = 0; - aim_tx_destroy(newoft); - return -1; - } - - if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { - newoft->lock = 0; - aim_tx_destroy(newoft); - return -1; - } - - newoft->lock = 0; - aim_tx_enqueue(sess, newoft); - break; - - } - case 0x1209: { /* get file listing ack rx->tx */ - struct aim_filetransfer_priv *ft; - struct aim_fileheader_t *fh; - struct aim_msgcookie_t *cook; - int ret = 0; - - if(!(fh = aim_oft_getfh(hdr))) { - perror("getfh"); - free(hdr); - return -1; - } - - free(hdr); - hdr = NULL; - - faim_mutex_unlock(&conn->active); - - if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) - faimdprintf(sess, 2, "shit, no cookie in 0x1209. (%i/%s)going to crash..\n", - AIM_COOKIETYPE_OFTGET, fh->bcookie); - - ft = cook->data; - - if (ft->fh.size != fh->size) - faimdprintf(sess, 2, "hrm. ft->fh.size (%ld) != fh->size (%ld). um. using ft->fh.size\n", - ft->fh.size, fh->size); - - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ))) - ret = userfunc(sess, NULL, conn, fh); - - faimdprintf(sess, 2, "faim: get_command_rendezvous: hit end of 1209\n"); - - free(fh); - - return ret; - - break; - } - case 0x120b: { /* getfile listing.txt rx confirm */ - struct aim_filetransfer_priv *ft; - struct aim_msgcookie_t *cook; - struct aim_fileheader_t *fh; - - fh = aim_oft_getfh(hdr); - - free(hdr); - hdr = NULL; - - faim_mutex_unlock(&conn->active); + if (aim_recv(conn->fd, hdr, hdrlen) < hdrlen) { + faimdprintf(sess, 2, "faim: rend: read2 error on %d (%d)\n", conn->fd, hdrlen); + free(hdr); + aim_conn_close(conn); + return -1; + } - if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { - free(fh); - return -1; - } - - free(fh); - - ft = cook->data; - - if (aim_cachecookie(sess, cook) == -1) { - return -1; - } - - if((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGRXCONFIRM))) - return userfunc(sess, NULL, conn); - - break; - } - case 0x120c: { /* getfile file request */ - struct aim_filetransfer_priv *ft; - struct aim_msgcookie_t *cook; - struct aim_fileheader_t *fh; - struct command_tx_struct *newoft; - int i = 0; - - fh = aim_oft_getfh(hdr); - - free(hdr); - hdr = NULL; - - faim_mutex_unlock(&conn->active); - - if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { - faimdprintf(sess, 2, "no cookie in 120c\n"); - return -1; - } - - ft = cook->data; - memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); - free(fh); - - aim_cachecookie(sess, cook); - - faimdprintf(sess, 2, "faim: fileget: %s seems to want %s\n", ft->sn, ft->fh.name); - - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) ) - i = userfunc(sess, NULL, conn, &(ft->fh), cook->cookie); - - if (i < 0) - return i; - - if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0101, 0))) { - faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n"); - return -1; - } - - newoft->lock = 1; - memcpy(newoft->hdr.oft.magic, "OFT2", 4); - newoft->hdr.oft.hdr2len = 0x100 - 8; - - if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) { - newoft->lock = 0; - aim_tx_destroy(newoft); - return -1; - } - - /* protocol BS: nrecvd, recvcsum to 0, flags to 0x20. */ - ft->fh.nrecvd = 0; - ft->fh.recvcsum = 0; - ft->fh.flags = 0x20; - - aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)); + hdrtype = aimutil_get16(hdr); - newoft->lock = 0; - aim_tx_enqueue(sess, newoft); - - faimdprintf(sess, 2, "faim: OFT: OFT file header enqueued.\n"); - - return i; - - break; - } - case 0x0101: { /* getfile: sending data */ - struct aim_fileheader_t *fh; - struct aim_filetransfer_priv *ft; - struct aim_msgcookie_t *cook; - struct command_tx_struct *newoft; - - fh = aim_oft_getfh(hdr); - - free(hdr); - hdr = NULL; - - faim_mutex_unlock(&conn->active); - - if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { - free(fh); - return -1; - } - free(fh); - - ft = cook->data; - - ft->state = 3; - - if (aim_cachecookie(sess, cook) == -1) { - perror("aim_cachecookie"); - return -1; - } - - faimdprintf(sess, 2, "faim: fileget: %s seems to want to send %s\n", ft->sn, ft->fh.name); - - if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x0202, 0))) { - aim_conn_close(conn); - faimdprintf(sess, 2, "faim: send_final_transfer: tx_new OFT failed\n"); - return -1; - } - - newoft->lock = 1; - memcpy(newoft->hdr.oft.magic, "OFT2", 4); - - newoft->hdr.oft.hdr2len = 0x100 - 8; - - if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) { - newoft->lock = 0; - aim_tx_destroy(newoft); - return -1; - } - - aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)); - - newoft->lock = 0; - aim_tx_enqueue(sess, newoft); - - faimdprintf(sess, 2, "faim: OFT: OFT 0x0202 enqueued.\n"); - - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) == NULL) - return 1; + if (hdrtype == 0x0001) + ret = handlehdr_directim(sess, conn, hdr); + else if (hdrtype == 0x1108) /* getfile listing.txt incoming tx->rx */ + ret = handlehdr_getfile_listing(sess, conn, hdr); + else if (hdrtype == 0x1209) /* get file listing ack rx->tx */ + ret = handlehdr_getfile_listing2(sess, conn, hdr); + else if (hdrtype == 0x120b) /* get file listing rx confirm */ + ret = handlehdr_getfile_listing3(sess, conn, hdr); + else if (hdrtype == 0x120c) /* getfile request */ + ret = handlehdr_getfile_request(sess, conn, hdr); + else if (hdrtype == 0x0101) /* getfile sending data */ + ret = handlehdr_getfile_sending(sess, conn, hdr); + else if (hdrtype == 0x0202) /* getfile recv data */ + ret = handlehdr_getfile_recv(sess, conn, hdr); + else if (hdrtype == 0x0204) /* getfile finished */ + ret = handlehdr_getfile_finish(sess, conn, hdr); + else { + faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype); + ret = -1; + } + + free(hdr); - break; - } - case 0x0202: { /* get file: ready to receive data */ - struct aim_fileheader_t *fh; - struct aim_filetransfer_priv *ft; - struct aim_msgcookie_t *cook; - int ret = 1; - - fh = aim_oft_getfh(hdr); - - free(hdr); - hdr = NULL; - - faim_mutex_unlock(&conn->active); - - if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { - free(fh); - return -1; - } - - ft = cook->data; - - faimdprintf(sess, 2, "faim: get_rend: looks like we're ready to send data.(oft 0x0202)\n"); - - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND)) ) - ret = userfunc(sess, NULL, conn, fh); - - free(fh); - - return ret; - break; - } - case 0x0204: { /* get file: finished. close it up */ - int i; - struct aim_fileheader_t *fh; + if (ret == -1) + aim_conn_close(conn); - if(!(fh = aim_oft_getfh(hdr))) - return -1; - - free(hdr); - hdr = NULL; - - faim_mutex_unlock(&conn->active); - - faimdprintf(sess, 2, "faim: get_rend: looks like we're done with a transfer (oft 0x0204)\n"); - - if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE)) ) - i = userfunc(sess, NULL, conn, fh); - else - i = 1; - - if (conn) - aim_conn_close(conn); - - free(fh); + return ret; +} - return i; - break; - } - default: { - free(hdr); - hdr = NULL; - faimdprintf(sess, 2,"faim: OFT frame: uknown type %04x\n", hdrtype); - faim_mutex_unlock(&conn->active); - break; - } - } /* switch */ - - if (hdr) { - faimdprintf(sess, 0, "hdr wasn't freed by a rendezvous switch case (hdrtype: %0x04x)!\n", hdrtype); - free(hdr); - hdr = NULL; - } - return 0; -} - +#if 0 /** * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr. * @hdr: buffer to extract header from @@ -1458,6 +1496,7 @@ i += 64; return fh; } +#endif /** * aim_oft_checksum - calculate oft checksum of buffer @@ -1477,10 +1516,13 @@ * Also, it's been said that this is incorrect as currently * written. You were warned. */ -faim_export int aim_oft_checksum(struct aim_session_t *sess, char *buffer, int bufsize, int *checksum) +faim_export fu32_t aim_oft_checksum(aim_session_t *sess, const char *buffer, int bufsize, fu32_t *checksum) { - short check0, check1; + return 0xdeadbeef; +#if 0 + fu16_t check0, check1; int i; + check0 = ((*checksum & 0xFF000000) >> 16); check1 = ((*checksum & 0x00ff0000) >> 16); for(i = 0; i < bufsize; i++) { @@ -1524,8 +1566,10 @@ *checksum = ((check0 * 0x1000000) + (check1 * 0x10000)); return *checksum; +#endif } +#if 0 /** * aim_oft_buildheader - fills a buffer with network-order fh data * @dest: buffer to fill -- pre-alloced @@ -1535,7 +1579,7 @@ * DOES NOT DO BOUNDS CHECKING! * */ -faim_internal int aim_oft_buildheader(unsigned char *dest,struct aim_fileheader_t *fh) +static int oft_buildheader(unsigned char *dest, struct aim_fileheader_t *fh) { int i, curbyte; if (!dest || !fh) @@ -1577,26 +1621,7 @@ curbyte += 64; return curbyte; } - - -/** - * aim_tx_destroy - free's tx_command_t's - * @command: the command to free - * - * if command is locked, doesn't free. - * returns -1 on error (locked struct); 0 on success. - * - */ -faim_internal int aim_tx_destroy(struct command_tx_struct *command){ - if (command->lock) - return -1; - if (command->data) - free(command->data); - if (command->hdrtype == AIM_FRAMETYPE_OFT && command->hdr.oft.hdr2) - free(command->hdr.oft.hdr2); - free(command); - return 0; -} +#endif /** * aim_getfile_intitiate - Request an OFT getfile session @@ -1606,8 +1631,10 @@ * * returns a new &aim_conn_t on success, %NULL on error */ -faim_export struct aim_conn_t *aim_getfile_initiate(struct aim_session_t *sess, struct aim_conn_t *conn, char *destsn) +faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn) { + return NULL; +#if 0 struct command_tx_struct *newpacket; struct aim_conn_t *newconn; struct aim_filetransfer_priv *priv; @@ -1745,6 +1772,7 @@ faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); return newconn; +#endif } /** @@ -1757,8 +1785,10 @@ * * returns -1 on error, 0 on successful enqueuing */ -faim_export int aim_oft_getfile_request(struct aim_session_t *sess, struct aim_conn_t *conn, const unsigned char *name, const int size) +faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size) { + return -EINVAL; +#if 0 struct command_tx_struct *newoft; struct aim_filetransfer_priv *ft; if (!sess || !conn || !conn->priv || !name) @@ -1787,13 +1817,13 @@ if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1801,6 +1831,7 @@ aim_tx_enqueue(sess, newoft); return 0; +#endif } /** @@ -1812,8 +1843,10 @@ * filetransfer. Returns -1 on error, 0 on apparent success * */ -faim_export int aim_oft_getfile_ack(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn) { + return -EINVAL; +#if 0 struct command_tx_struct *newoft; struct aim_filetransfer_priv *ft; @@ -1832,7 +1865,7 @@ if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1840,13 +1873,14 @@ if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } newoft->lock = 0; aim_tx_enqueue(sess, newoft); return 0; +#endif } /** @@ -1857,8 +1891,10 @@ * call this before you close the getfile connection if you're on the * receiving/requesting end. */ -faim_export int aim_oft_getfile_end(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_oft_getfile_end(aim_session_t *sess, aim_conn_t *conn) { + return -EINVAL; +#if 0 struct command_tx_struct *newoft; struct aim_filetransfer_priv *ft; @@ -1877,7 +1913,7 @@ if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1889,7 +1925,7 @@ if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1897,4 +1933,6 @@ aim_tx_enqueue(sess, newoft); return 0; +#endif /* 0 */ } + diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/im.c --- a/src/protocols/oscar/im.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/im.c Sun Sep 09 10:07:14 2001 +0000 @@ -38,29 +38,33 @@ * 0501 0004 0101 0102 0101 WinAIM 4.1.2010, libfaim (right here) * 0501 0001 0101 01 AOL v6.0, CompuServe 2000 v6.0, any * TOC client + * + * Note that in this function, only the feature bytes are tested, since + * the rest will always be the same. + * */ -faim_export unsigned short aim_fingerprintclient(unsigned char *msghdr, int len) +faim_export fu16_t aim_fingerprintclient(fu8_t *msghdr, int len) { static const struct { - unsigned short clientid; + fu16_t clientid; int len; - unsigned char data[10]; + fu8_t data[10]; } fingerprints[] = { /* AOL Mobile Communicator, WinAIM 1.0.414 */ { AIM_CLIENTTYPE_MC, - 9, {0x05, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01}}, + 3, {0x01, 0x01, 0x01}}, /* WinAIM 2.0.847, 2.1.1187, 3.0.1464, 4.3.2229, 4.4.2286 */ { AIM_CLIENTTYPE_WINAIM, - 9, {0x05, 0x01, 0x00, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01}}, + 3, {0x01, 0x01, 0x02}}, /* WinAIM 4.1.2010, libfaim */ { AIM_CLIENTTYPE_WINAIM41, - 10, {0x05, 0x01, 0x00, 0x04, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01}}, + 4, {0x01, 0x01, 0x01, 0x02}}, /* AOL v6.0, CompuServe 2000 v6.0, any TOC client */ { AIM_CLIENTTYPE_AOL_TOC, - 7, {0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01}}, + 1, {0x01}}, { 0, 0} }; @@ -80,9 +84,9 @@ } /* This should be endian-safe now... but who knows... */ -faim_export unsigned short aim_iconsum(const unsigned char *buf, int buflen) +faim_export fu32_t aim_iconsum(const fu8_t *buf, int buflen) { - unsigned long sum; + fu32_t sum; int i; for (i = 0, sum = 0; i < buflen; i += 2) @@ -90,7 +94,7 @@ sum = ((sum & 0xffff0000) >> 16) + (sum & 0x0000ffff); - return sum & 0xffff; + return sum; } /* @@ -128,14 +132,26 @@ * representation of the UNICODE index (in this case, UNICODE * "Horizontal Ellipsis", or 133 in in ASCII8). * + * Implementation note: Since this is one of the most-used functions + * in all of libfaim, it is written with performance in mind. As such, + * it is not as clear as it could be in respect to how this message is + * supposed to be layed out. Most obviously, tlvlists should be used + * instead of writing out the bytes manually. + * + * XXX support multipart + * */ -faim_export int aim_send_im_ext(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_sendimext_args *args) +faim_export int aim_send_im_ext(aim_session_t *sess, aim_conn_t *conn, struct aim_sendimext_args *args) { - int curbyte,i; - struct command_tx_struct *newpacket; + static const fu8_t deffeatures[] = { + 0x01, 0x01, 0x01, 0x02, 0x42, + }; + int i, msgtlvlen; + aim_frame_t *fr; + aim_snacid_t snacid; if (!sess || !conn || !args) - return -EINVAL; + return -EINVAL; if (!args->msg || (args->msglen <= 0)) return -EINVAL; @@ -143,14 +159,18 @@ if (args->msglen >= MAXMSGLEN) return -E2BIG; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, args->msglen+512))) + msgtlvlen = 12 + args->msglen; + if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) + msgtlvlen += args->featureslen; + else + msgtlvlen += sizeof(deffeatures); + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, args->msglen+512))) return -ENOMEM; - newpacket->lock = 1; /* lock struct */ - - curbyte = 0; - curbyte += aim_putsnac(newpacket->data+curbyte, - 0x0004, 0x0006, 0x0000, sess->snac_nextid); + /* XXX should be optional */ + snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); + aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); /* * Generate a random message cookie @@ -161,113 +181,103 @@ * SNAC ID. * */ - for (i = 0; i < 8; i++) { - curbyte += aimutil_put8(newpacket->data+curbyte, - (unsigned char) rand()); - } + for (i = 0; i < 8; i++) + aimbs_put8(&fr->data, (fu8_t) rand()); /* * Channel ID */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + aimbs_put16(&fr->data, 0x0001); /* * Destination SN (prepended with byte length) */ - curbyte += aimutil_put8(newpacket->data+curbyte, strlen(args->destsn)); - curbyte += aimutil_putstr(newpacket->data+curbyte, - args->destsn, strlen(args->destsn)); + aimbs_put8(&fr->data, strlen(args->destsn)); + aimbs_putraw(&fr->data, args->destsn, strlen(args->destsn)); /* * metaTLV start. */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); - curbyte += aimutil_put16(newpacket->data+curbyte, args->msglen + 0x10); + aimbs_put16(&fr->data, 0x0002); + aimbs_put16(&fr->data, msgtlvlen); /* - * Flag data / ICBM Parameters? - * - * I don't know what these are... + * Features * */ - curbyte += aimutil_put8(newpacket->data+curbyte, 0x05); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); + aimbs_put8(&fr->data, 0x05); + aimbs_put8(&fr->data, 0x01); - /* number of bytes to follow */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x02); + if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) { + aimbs_put16(&fr->data, args->featureslen); + aimbs_putraw(&fr->data, args->features, args->featureslen); + } else { + aimbs_put16(&fr->data, sizeof(deffeatures)); + aimbs_putraw(&fr->data, deffeatures, sizeof(deffeatures)); + } - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0101); + aimbs_put16(&fr->data, 0x0101); /* * Message block length. */ - curbyte += aimutil_put16(newpacket->data+curbyte, args->msglen + 0x04); + aimbs_put16(&fr->data, args->msglen + 0x04); /* * Character set. */ if (args->flags & AIM_IMFLAGS_UNICODE) - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); + aimbs_put16(&fr->data, 0x0002); else if (args->flags & AIM_IMFLAGS_ISO_8859_1) - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); + aimbs_put16(&fr->data, 0x0003); else - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + aimbs_put16(&fr->data, 0x0000); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + aimbs_put16(&fr->data, 0x0000); /* * Message. Not terminated. */ - curbyte += aimutil_putstr(newpacket->data+curbyte, - args->msg, args->msglen); + aimbs_putraw(&fr->data, args->msg, args->msglen); /* * Set the Request Acknowledge flag. */ if (args->flags & AIM_IMFLAGS_ACK) { - curbyte += aimutil_put16(newpacket->data+curbyte,0x0003); - curbyte += aimutil_put16(newpacket->data+curbyte,0x0000); + aimbs_put16(&fr->data, 0x0003); + aimbs_put16(&fr->data, 0x0000); } - + /* * Set the Autoresponse flag. */ if (args->flags & AIM_IMFLAGS_AWAY) { - curbyte += aimutil_put16(newpacket->data+curbyte,0x0004); - curbyte += aimutil_put16(newpacket->data+curbyte,0x0000); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0000); } /* * Set the Buddy Icon Requested flag. */ if (args->flags & AIM_IMFLAGS_BUDDYREQ) { - curbyte += aimutil_put16(newpacket->data+curbyte,0x0009); - curbyte += aimutil_put16(newpacket->data+curbyte,0x0000); + aimbs_put16(&fr->data, 0x0009); + aimbs_put16(&fr->data, 0x0000); } /* - * Set the I HAVE A REALLY PURTY ICON flag (with timestamp). + * Set the I HAVE A REALLY PURTY ICON flag. */ if (args->flags & AIM_IMFLAGS_HASICON) { - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0008); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c); - curbyte += aimutil_put32(newpacket->data+curbyte, args->iconlen); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket->data+curbyte, args->iconsum); - curbyte += aimutil_put32(newpacket->data+curbyte, args->iconstamp); + aimbs_put16(&fr->data, 0x0008); + aimbs_put16(&fr->data, 0x000c); + aimbs_put32(&fr->data, args->iconlen); + aimbs_put32(&fr->data, args->iconsum); + aimbs_put32(&fr->data, args->iconstamp); } - newpacket->commandlen = curbyte; - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); #if 1 /* XXX do this with autoconf or something... */ - aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); aim_cleansnacs(sess, 60); /* clean out all SNACs over 60sec old */ #endif @@ -284,7 +294,7 @@ * that requires an explicit message length. Use aim_send_im_ext(). * */ -faim_export int aim_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, const char *destsn, unsigned short flags, const char *msg) +faim_export int aim_send_im(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu16_t flags, const char *msg) { struct aim_sendimext_args args; @@ -293,158 +303,164 @@ args.msg = msg; args.msglen = strlen(msg); + /* Make these don't get set by accident -- they need aim_send_im_ext */ + args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON); + return aim_send_im_ext(sess, conn, &args); } -faim_export int aim_send_icon(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn, const unsigned char *icon, int iconlen, time_t stamp, unsigned short iconsum) +/* + * This is also performance sensative. (If you can believe it...) + * + */ +faim_export int aim_send_icon(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu32_t iconsum) { - struct command_tx_struct *np; - int i, curbyte = 0; - unsigned char ck[8]; + int i; + fu8_t ck[8]; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!sess || !conn || !sn || !icon || - (iconlen <= 0) || (iconlen >= MAXICONLEN)) - return -EINVAL; + if (!sess || !conn || !sn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN)) + return -EINVAL; if (conn->type != AIM_CONN_TYPE_BOS) return -EINVAL; - for (i = 0, curbyte = 0; i < 8; i++) - curbyte += aimutil_put8(ck+curbyte, (u_char)rand()); + for (i = 0; i < 8; i++) + aimutil_put8(ck+i, (fu8_t) rand()); - if (!(np = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2))) return -ENOMEM; - np->lock = 1; - - curbyte = aim_putsnac(np->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid); + snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); /* * Cookie */ - memcpy(np->data+curbyte, ck, 8); - curbyte += 8; + aimbs_putraw(&fr->data, ck, 8); /* * Channel (2) */ - curbyte += aimutil_put16(np->data+curbyte, 0x0002); + aimbs_put16(&fr->data, 0x0002); /* * Dest sn */ - curbyte += aimutil_put8(np->data+curbyte, strlen(sn)); - curbyte += aimutil_putstr(np->data+curbyte, sn, strlen(sn)); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); /* * TLV t(0005) + * + * Encompasses everything below. */ - curbyte += aimutil_put16(np->data+curbyte, 0x0005); - curbyte += aimutil_put16(np->data+curbyte, 2+8+16+6+4+4+iconlen+4+4+4+strlen(AIM_ICONIDENT)); + aimbs_put16(&fr->data, 0x0005); + aimbs_put16(&fr->data, 2+8+16+6+4+4+iconlen+4+4+4+strlen(AIM_ICONIDENT)); - curbyte += aimutil_put16(np->data+curbyte, 0x0000); - - memcpy(np->data+curbyte, ck, 8); - curbyte += 8; - - curbyte += aim_putcap(np->data+curbyte, 16, AIM_CAPS_BUDDYICON); + aimbs_put16(&fr->data, 0x0000); + aimbs_putraw(&fr->data, ck, 8); + aim_putcap(&fr->data, AIM_CAPS_BUDDYICON); /* TLV t(000a) */ - curbyte += aimutil_put16(np->data+curbyte, 0x000a); - curbyte += aimutil_put16(np->data+curbyte, 0x0002); - curbyte += aimutil_put16(np->data+curbyte, 0x0001); + aimbs_put16(&fr->data, 0x000a); + aimbs_put16(&fr->data, 0x0002); + aimbs_put16(&fr->data, 0x0001); /* TLV t(000f) */ - curbyte += aimutil_put16(np->data+curbyte, 0x000f); - curbyte += aimutil_put16(np->data+curbyte, 0x0000); + aimbs_put16(&fr->data, 0x000f); + aimbs_put16(&fr->data, 0x0000); /* TLV t(2711) */ - curbyte += aimutil_put16(np->data+curbyte, 0x2711); - curbyte += aimutil_put16(np->data+curbyte, 4+4+4+iconlen+strlen(AIM_ICONIDENT)); - curbyte += aimutil_put16(np->data+curbyte, 0x0000); - curbyte += aimutil_put16(np->data+curbyte, iconsum); - curbyte += aimutil_put32(np->data+curbyte, iconlen); - curbyte += aimutil_put32(np->data+curbyte, stamp); - memcpy(np->data+curbyte, icon, iconlen); - curbyte += iconlen; - memcpy(np->data+curbyte, AIM_ICONIDENT, strlen(AIM_ICONIDENT)); - curbyte += strlen(AIM_ICONIDENT); + aimbs_put16(&fr->data, 0x2711); + aimbs_put16(&fr->data, 4+4+4+iconlen+strlen(AIM_ICONIDENT)); + aimbs_put32(&fr->data, iconsum); + aimbs_put32(&fr->data, iconlen); + aimbs_put32(&fr->data, stamp); + aimbs_putraw(&fr->data, icon, iconlen); + aimbs_putraw(&fr->data, AIM_ICONIDENT, strlen(AIM_ICONIDENT)); /* TLV t(0003) */ - curbyte += aimutil_put16(np->data+curbyte, 0x0003); - curbyte += aimutil_put16(np->data+curbyte, 0x0000); + aimbs_put16(&fr->data, 0x0003); + aimbs_put16(&fr->data, 0x0000); - np->commandlen = curbyte; - np->lock = 0; - aim_tx_enqueue(sess, np); + aim_tx_enqueue(sess, fr); return 0; } -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) +static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - unsigned int i, ret = 0; + int i, ret = 0; aim_rxcallback_t userfunc; - unsigned char cookie[8]; - int channel; - struct aim_tlvlist_t *tlvlist; - char sn[MAXSNLEN]; - unsigned short icbmflags = 0; - unsigned char flag1 = 0, flag2 = 0; - unsigned char *msgblock = NULL, *msg = NULL; + fu8_t cookie[8]; + fu16_t channel; + aim_tlvlist_t *tlvlist; + char *sn; + int snlen; + fu16_t icbmflags = 0; + fu8_t flag1 = 0, flag2 = 0; + fu8_t *msg = NULL; + aim_tlv_t *msgblock; /* ICBM Cookie. */ for (i = 0; i < 8; i++) - cookie[i] = aimutil_get8(data+i); + cookie[i] = aimbs_get8(bs); /* Channel ID */ - channel = aimutil_get16(data+i); - i += 2; + channel = aimbs_get16(bs); if (channel != 0x01) { faimdprintf(sess, 0, "icbm: ICBM recieved on unsupported channel. Ignoring. (chan = %04x)\n", channel); - return 1; + return 0; } - strncpy(sn, (char *) data+i+1, (int) *(data+i)); - i += 1 + (int) *(data+i); + snlen = aimbs_get8(bs); + sn = aimbs_getstr(bs, snlen); - tlvlist = aim_readtlvchain(data+i, datalen-i); + tlvlist = aim_readtlvchain(bs); if (aim_gettlv(tlvlist, 0x0003, 1)) icbmflags |= AIM_IMFLAGS_ACK; if (aim_gettlv(tlvlist, 0x0004, 1)) icbmflags |= AIM_IMFLAGS_AWAY; - if ((msgblock = (unsigned char *)aim_gettlv_str(tlvlist, 0x0002, 1))) { - int j = 0; + if ((msgblock = aim_gettlv(tlvlist, 0x0002, 1))) { + aim_bstream_t mbs; + int featurelen, msglen; - /* no, this really is correct. I'm not high or anything either. */ - j += 2; - j += 2 + aimutil_get16(msgblock+j); - j += 2; + aim_bstream_init(&mbs, msgblock->value, msgblock->length); - j += 2; /* final block length */ + aimbs_get8(&mbs); + aimbs_get8(&mbs); + for (featurelen = aimbs_get16(&mbs); featurelen; featurelen--) + aimbs_get8(&mbs); + aimbs_get8(&mbs); + aimbs_get8(&mbs); - flag1 = aimutil_get16(msgblock); - j += 2; - flag2 = aimutil_get16(msgblock); - j += 2; + msglen = aimbs_get16(&mbs) - 4; /* final block length */ - msg = msgblock+j; + flag1 = aimbs_get16(&mbs); + flag2 = aimbs_get16(&mbs); + + msg = aimbs_getstr(&mbs, msglen); } if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, channel, sn, msg, icbmflags, flag1, flag2); - free(msgblock); + free(sn); aim_freetlvchain(&tlvlist); return ret; } /* - * A multipart IM: + * + * This should use tlvlists, but doesn't for performance reasons. + * + * XXX support multipart IMs: * * 0004 0007 0000 8f08 d295 * 0031 6520 3b7b f9fd @@ -464,12 +480,13 @@ * 0101 000b 0000 0000 3c2f 4854 4d4c 3e another ASCII part * */ -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, unsigned char *data, int datalen, unsigned char *cookie) +static int incomingim_ch1(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, fu16_t channel, struct aim_userinfo_s *userinfo, aim_bstream_t *bs, fu8_t *cookie) { - unsigned short type, length; + fu16_t type, length; aim_rxcallback_t userfunc; - int i, ret = 0; + int ret = 0; struct aim_incomingim_ch1_args args; + int endpos; memset(&args, 0, sizeof(args)); @@ -478,54 +495,41 @@ * I've changed it to process the TLVs in-place. This avoids lots * of per-IM memory allocations. */ - for (i = 0; i < datalen; ) { + while (aim_bstream_empty(bs)) { - type = aimutil_get16(data+i); - i += 2; - - length = aimutil_get16(data+i); - i += 2; + type = aimbs_get16(bs); + length = aimbs_get16(bs); + + endpos = aim_bstream_curpos(bs) + length; if (type == 0x0002) { /* Message Block */ - unsigned short wastebits; - unsigned char *msgblock; - int j = 0, y = 0, z = 0; - msgblock = data+i; - /* - * 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?" + * This TLV consists of the following: + * - 0501 -- Unknown + * - Features: Don't know how to interpret these + * - 0101 -- Unknown + * - Message * */ - 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++); + aimbs_get8(bs); /* 05 */ + aimbs_get8(bs); /* 01 */ - args.finlen = j; - if (args.finlen > sizeof(args.fingerprint)) - args.finlen = sizeof(args.fingerprint); - memcpy(args.fingerprint, msgblock, args.finlen); + args.featureslen = aimbs_get16(bs); + /* XXX XXX this is all evil! */ + args.features = bs->data + bs->offset; + aim_bstream_advance(bs, args.featureslen); + args.icbmflags |= AIM_IMFLAGS_CUSTOMFEATURES; + + aimbs_get8(bs); /* 01 */ + aimbs_get8(bs); /* 01 */ /* Message string length, including flag words. */ - args.msglen = aimutil_get16(msgblock+j); - j += 2; + args.msglen = aimbs_get16(bs); /* Flag words. */ - args.flag1 = aimutil_get16(msgblock+j); + args.flag1 = aimbs_get16(bs); if (args.flag1 == 0x0000) ; /* ASCII */ else if (args.flag1 == 0x0002) @@ -534,17 +538,16 @@ args.icbmflags |= AIM_IMFLAGS_ISO_8859_1; else if (args.flag1 == 0xffff) ; /* no encoding (yeep!) */ - j += 2; - args.flag2 = aimutil_get16(msgblock+j); + args.flag2 = aimbs_get16(bs); if (args.flag2 == 0x0000) ; /* standard subencoding? */ else if (args.flag2 == 0x000b) args.icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH; else if (args.flag2 == 0xffff) ; /* no subencoding */ - j += 2; - + + /* XXX this isn't really necesary... */ if ( ((args.flag1 != 0x0000) && (args.flag1 != 0x0002) && (args.flag1 != 0x0003) && @@ -555,18 +558,22 @@ faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", args.flag1, args.flag2); } - /* Message string. */ + /* Message. */ args.msglen -= 4; if (args.icbmflags & AIM_IMFLAGS_UNICODE) { + fu8_t *umsg; + + /* Can't use getstr because of wide null */ + umsg = aimbs_getraw(bs, args.msglen); args.msg = malloc(args.msglen+2); - memcpy(args.msg, msgblock+j, args.msglen); + memcpy(args.msg, umsg, args.msglen); args.msg[args.msglen] = '\0'; /* wide NULL */ args.msg[args.msglen+1] = '\0'; - } else { - args.msg = malloc(args.msglen+1); - memcpy(args.msg, msgblock+j, args.msglen); - args.msg[args.msglen] = '\0'; - } + + free(umsg); + + } else + args.msg = aimbs_getstr(bs, args.msglen); } else if (type == 0x0003) { /* Server Ack Requested */ @@ -576,11 +583,11 @@ args.icbmflags |= AIM_IMFLAGS_AWAY; - } else if ((type == 0x0008) && (length == 0x000c)) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */ + } else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */ - args.iconchecksum = aimutil_get32(data+i); - args.iconlength = aimutil_get32(data+i+4); - args.iconstamp = aimutil_get32(data+i+8); + args.iconsum = aimbs_get32(bs); + args.iconlen = aimbs_get32(bs); + args.iconstamp = aimbs_get32(bs); args.icbmflags |= AIM_IMFLAGS_HASICON; } else if (type == 0x0009) { @@ -590,31 +597,351 @@ } else if (type == 0x0017) { args.extdatalen = length; - args.extdata = data+i; + args.extdata = aimbs_getraw(bs, args.extdatalen); } else { faimdprintf(sess, 0, "incomingim_ch1: unknown TLV 0x%04x (len %d)\n", type, length); } - i += length; + /* + * This is here to protect ourselves from ourselves. That + * is, if something above doesn't completly parse its value + * section, or, worse, overparses it, this will set the + * stream where it needs to be in order to land on the next + * TLV when the loop continues. + * + */ + aim_bstream_setpos(bs, endpos); } if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, channel, userinfo, &args); + free(args.extdata); free(args.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) +static int incomingim_ch2_buddylist(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args, aim_tlvlist_t *list2) +{ + aim_rxcallback_t userfunc; + int ret = 0; + aim_tlv_t *tse; + aim_bstream_t tbs; + + if (args->status != 0x0000) + return 1; /* ignore it -- not sure what it means */ + + tse = aim_gettlv(list2, 0x2711, 1); + aim_bstream_init(&tbs, tse->value, tse->length); + + /* + * This goes like this... + * + * group name length + * group name + * num of buddies in group + * buddy name length + * buddy name + * buddy name length + * buddy name + * ... + * group name length + * group name + * num of buddies in group + * buddy name length + * buddy name + * ... + * ... + */ + while (aim_bstream_empty(&tbs)) { + fu16_t gnlen, numb; + int i; + char *gn; + + gnlen = aimbs_get16(&tbs); + gn = aimbs_getstr(&tbs, gnlen); + numb = aimbs_get16(&tbs); + + for (i = 0; i < numb; i++) { + fu16_t bnlen; + char *bn; + + bnlen = aimbs_get16(&tbs); + bn = aimbs_getstr(&tbs, bnlen); + + faimdprintf(sess, 0, "got a buddy list from %s: group %s, buddy %s\n", userinfo->sn, gn, bn); + + free(bn); + } + + free(gn); + } + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, 0x0002, userinfo, args); + + return ret; +} + +static int incomingim_ch2_buddyicon(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args, aim_tlvlist_t *list2) { aim_rxcallback_t userfunc; - struct aim_tlv_t *block1; - struct aim_tlvlist_t *list2; + int ret = 0; + aim_tlv_t *miscinfo; + aim_bstream_t tbs; + + miscinfo = aim_gettlv(list2, 0x2711, 1); + aim_bstream_init(&tbs, miscinfo->value, miscinfo->length); + + args->info.icon.checksum = aimbs_get32(&tbs); + args->info.icon.length = aimbs_get32(&tbs); + args->info.icon.timestamp = aimbs_get32(&tbs); + args->info.icon.icon = aimbs_getraw(&tbs, args->info.icon.length); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, 0x0002, userinfo, args); + + free(args->info.icon.icon); + + return ret; +} + +static int incomingim_ch2_voice(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args, aim_tlvlist_t *list2) +{ + aim_msgcookie_t *cachedcook; + int ret = 0; + aim_rxcallback_t userfunc; + + faimdprintf(sess, 1, "rend: voice!\n"); + + if (!(cachedcook = (aim_msgcookie_t*)calloc(1, sizeof(aim_msgcookie_t)))) + return 0; + + memcpy(cachedcook->cookie, args->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, 0x0002, userinfo, &args); + + return ret; +} + +static int incomingim_ch2_chat(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args, aim_tlvlist_t *list2) +{ + aim_tlv_t *miscinfo; + aim_bstream_t tbs; + aim_rxcallback_t userfunc; + int ret = 0; + + miscinfo = aim_gettlv(list2, 0x2711, 1); + aim_bstream_init(&tbs, miscinfo->value, miscinfo->length); + + aim_chat_readroominfo(&tbs, &args->info.chat.roominfo); + + if (aim_gettlv(list2, 0x000c, 1)) + args->info.chat.msg = aim_gettlv_str(list2, 0x000c, 1); + + if (aim_gettlv(list2, 0x000d, 1)) + args->info.chat.encoding = aim_gettlv_str(list2, 0x000d, 1); + + if (aim_gettlv(list2, 0x000e, 1)) + args->info.chat.lang = aim_gettlv_str(list2, 0x000e, 1); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, 0x0002, userinfo, &args); + + /* XXX free_roominfo */ + free(args->info.chat.roominfo.name); + free(args->info.chat.msg); + free(args->info.chat.encoding); + free(args->info.chat.lang); + + return ret; +} + +static int incomingim_ch2_getfile(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args, aim_tlvlist_t *list2) +{ + char ip[30]; + aim_msgcookie_t *cachedcook; + aim_tlv_t *miscinfo; + aim_tlv_t *iptlv, *porttlv; + int ret = 0; + aim_rxcallback_t userfunc; + + memset(ip, 0, 30); + + if (!(cachedcook = calloc(1, sizeof(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); + + args->info.getfile.ip = ip; + memcpy(args->info.getfile.cookie, args->cookie, 8); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, 0x0002, userinfo, &args); + + return ret; +} + +static int incomingim_ch2_sendfile(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args, aim_tlvlist_t *list2) +{ +#if 0 + char ip[30]; + aim_msgcookie_t *cachedcook; + aim_tlv_t *miscinfo; + aim_tlv_t *iptlv, *porttlv; + int ret =0; + aim_rxcallback_t userfunc; + char *desc = NULL; + + memset(ip, 0, 30); + + if (!(cachedcook = calloc(1, sizeof(aim_msgcookie_t)))) + 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); + + 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: %s (%s)\n", + userinfo->sn, desc, ip); + + memcpy(cachedcook->cookie, args->cookie, 8); + + ft = malloc(sizeof(struct aim_filetransfer_priv)); /* XXX */ + 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, 0x0002, userinfo, &args); +#endif + return 0; +} + +static int incomingim_ch2_imimage(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args, aim_tlvlist_t *list2) +{ + aim_rxcallback_t userfunc; + int ret = 0; + + /* Primary IP address */ + if (aim_gettlv(list2, 0x0003, 1)) { + aim_tlv_t *tlv; + + tlv = aim_gettlv(list2, 0x0003, 1); + + snprintf(args->info.imimage.ip, sizeof(args->info.imimage.ip), + "%d.%d.%d.%d:4443", + tlv->value[0], + tlv->value[1], + tlv->value[2], + tlv->value[3]); + } + + /* + * Alternate IP address + * + * Sort of. The peer doesn't send this -- the OSCAR + * server does. So it will be the IP address that the + * peer is directly connected to the internet with, which + * may not be the same as the IP above. If these two + * values differ, it's rather unlikely that this + * rendezvous is going to happen... + * + */ + if (aim_gettlv(list2, 0x0004, 1)) + ; + + /* Port number (not correct -- ignore) */ + if (aim_gettlv(list2, 0x0005, 1)) + ; + + /* Unknown -- two bytes = 0x0001 */ + if (aim_gettlv(list2, 0x000a, 1)) + ; + + /* Unknown -- no value */ + if (aim_gettlv(list2, 0x000f, 1)) + ; + + faimdprintf(sess, 1, "rend: directIM request from %s (%s)\n", userinfo->sn, args->info.imimage.ip); + + /* + * XXX: there are a couple of different request packets for + * different things + */ + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, 0x0002, userinfo, args); + + return ret; +} + +/* XXX Ugh. I think its obvious. */ +static int incomingim_ch2(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, fu16_t channel, struct aim_userinfo_s *userinfo, aim_tlvlist_t *tlvlist, fu8_t *cookie) +{ + aim_tlv_t *block1; + aim_tlvlist_t *list2; int ret = 0; struct aim_incomingim_ch2_args args; + aim_bstream_t bbs; + fu8_t *cookie2; memset(&args, 0, sizeof(args)); @@ -626,18 +953,23 @@ return 0; } + aim_bstream_init(&bbs, block1->value, block1->length); + /* * First two bytes represent the status of the connection. * * 0 is a request, 2 is an accept */ - args.status = aimutil_get16(block1->value+0); + args.status = aimbs_get16(&bbs); /* * Next comes the cookie. Should match the ICBM cookie. */ - if (memcmp(block1->value+2, cookie, 8) != 0) + cookie2 = aimbs_getraw(&bbs, 8); + if (memcmp(cookie, cookie2, 8) != 0) faimdprintf(sess, 0, "rend: warning cookies don't match!\n"); + memcpy(args.cookie, cookie2, 8); + free(cookie2); /* * The next 16bytes are a capability block so we can @@ -651,7 +983,7 @@ * Read off one capability string and we should have it ID'd. * */ - if ((args.reqclass = aim_getcap(sess, block1->value+2+8, 0x10)) == 0x0000) { + if ((args.reqclass = aim_getcap(sess, &bbs, 0x10)) == 0x0000) { faimdprintf(sess, 0, "rend: no ID block\n"); return 0; } @@ -662,18 +994,19 @@ * * Ack packets for instance have nothing more to them. */ - list2 = aim_readtlvchain(block1->value+2+8+16, block1->length-2-8-16); + list2 = aim_readtlvchain(&bbs); +#if 0 /* this should be in the per-type blocks */ if (!list2 || ((args.reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) { - struct aim_msgcookie_t *cook; + aim_msgcookie_t *cook; int type; type = aim_msgcookie_gettype(args.reqclass); /* XXX: fix this shitty code */ if ((cook = aim_checkcookie(sess, cookie, type)) == NULL) { faimdprintf(sess, 0, "non-data rendezvous thats not in cache (type %d)\n", type); - aim_freetlvchain(&list2); - return 1; + aim_freetlvchain(&list2); + return 1; } if (cook->type == AIM_COOKIETYPE_OFTGET) { @@ -686,14 +1019,14 @@ if (args.status != 0x0002) { - if (aim_gettlv(list2, 0x000b, 1)) - errorcode = aim_gettlv16(list2, 0x000b, 1); + 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); + /* 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); } /* args.status != 0x0002 */ - + } else { faimdprintf(sess, 0, "no data attached to file transfer\n"); } /* !cook->data */ @@ -711,210 +1044,26 @@ return 1; } +#endif /* * The rest of the handling depends on what type it is. */ - if (args.reqclass & AIM_CAPS_BUDDYICON) { - struct aim_tlv_t *miscinfo; - int curpos = 0; - - miscinfo = aim_gettlv(list2, 0x2711, 1); - - args.info.icon.checksum = aimutil_get32(miscinfo->value+curpos); - curpos += 4; - args.info.icon.length = aimutil_get32(miscinfo->value+curpos); - curpos += 4; - args.info.icon.timestamp = aimutil_get32(miscinfo->value+curpos); - curpos += 4; - args.info.icon.icon = malloc(args.info.icon.length); - memcpy(args.info.icon.icon, miscinfo->value+curpos, args.info.icon.length); - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, channel, userinfo, &args); - - free(args.info.icon.icon); - - } else if (args.reqclass & AIM_CAPS_VOICE) { - struct aim_msgcookie_t *cachedcook; - - faimdprintf(sess, 1, "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, userinfo, &args); - - } else if (args.reqclass & AIM_CAPS_IMIMAGE) { - 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, 1, "rend: directIM request from %s (%s)\n", - userinfo->sn, ip); - - /* - * XXX: there are a couple of different request packets for - * different things - */ - - args.info.directim = priv = (struct aim_directim_priv *)calloc(1, sizeof(struct aim_directim_priv)); /* XXX error */ - 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, userinfo, &args); - - } else if (args.reqclass & AIM_CAPS_CHAT) { - struct aim_tlv_t *miscinfo; - - miscinfo = aim_gettlv(list2, 0x2711, 1); - aim_chat_readroominfo(miscinfo->value, &args.info.chat.roominfo); - - if (aim_gettlv(list2, 0x000c, 1)) - args.info.chat.msg = aim_gettlv_str(list2, 0x000c, 1); - - if (aim_gettlv(list2, 0x000d, 1)) - args.info.chat.encoding = aim_gettlv_str(list2, 0x000d, 1); - - if (aim_gettlv(list2, 0x000e, 1)) - args.info.chat.lang = aim_gettlv_str(list2, 0x000e, 1); - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, channel, userinfo, &args); - - free(args.info.chat.roominfo.name); - free(args.info.chat.msg); - free(args.info.chat.encoding); - free(args.info.chat.lang); - - } else if (args.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); - - args.info.getfile.ip = ip; - args.info.getfile.cookie = cookie; - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, channel, userinfo, &args); - - } else if (args.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: %s (%s)\n", - userinfo->sn, desc, ip); - - memcpy(cachedcook->cookie, cookie, 8); - - ft = malloc(sizeof(struct aim_filetransfer_priv)); /* XXX */ - 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, userinfo, &args); - -#endif - } else + if (args.reqclass & AIM_CAPS_BUDDYICON) + ret = incomingim_ch2_buddyicon(sess, mod, rx, snac, userinfo, &args, list2); + else if (args.reqclass & AIM_CAPS_SENDBUDDYLIST) + ret = incomingim_ch2_buddylist(sess, mod, rx, snac, userinfo, &args, list2); + else if (args.reqclass & AIM_CAPS_VOICE) + ret = incomingim_ch2_voice(sess, mod, rx, snac, userinfo, &args, list2); + else if (args.reqclass & AIM_CAPS_IMIMAGE) + ret = incomingim_ch2_imimage(sess, mod, rx, snac, userinfo, &args, list2); + else if (args.reqclass & AIM_CAPS_CHAT) + ret = incomingim_ch2_chat(sess, mod, rx, snac, userinfo, &args, list2); + else if (args.reqclass & AIM_CAPS_GETFILE) + ret = incomingim_ch2_getfile(sess, mod, rx, snac, userinfo, &args, list2); + else if (args.reqclass & AIM_CAPS_SENDFILE) + ret = incomingim_ch2_sendfile(sess, mod, rx, snac, userinfo, &args, list2); + else faimdprintf(sess, 0, "rend: unknown rendezvous 0x%04x\n", args.reqclass); aim_freetlvchain(&list2); @@ -933,11 +1082,11 @@ * I have access to. Its not fast, its not clean. But it works. * */ -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) +static int incomingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int i, ret = 0; - unsigned char cookie[8]; - int channel; + fu8_t cookie[8]; + fu16_t channel; struct aim_userinfo_s userinfo; memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); @@ -946,7 +1095,7 @@ * Read ICBM Cookie. And throw away. */ for (i = 0; i < 8; i++) - cookie[i] = aimutil_get8(data+i); + cookie[i] = aimbs_get8(bs); /* * Channel ID. @@ -961,15 +1110,14 @@ * connection negotiations come from. * */ - channel = aimutil_get16(data+i); - i += 2; + channel = aimbs_get16(bs); /* * Technically Channel 3 in chat could be done here too. */ if ((channel != 0x01) && (channel != 0x02)) { faimdprintf(sess, 0, "icbm: ICBM received on an unsupported channel. Ignoring.\n (chan = %04x)", channel); - return 1; + return 0; } /* @@ -988,7 +1136,7 @@ * never be two TLVs of the same type in one block. * */ - i += aim_extractuserinfo(sess, data+i, &userinfo); + aim_extractuserinfo(sess, bs, &userinfo); /* * From here on, its depends on what channel we're on. @@ -999,16 +1147,16 @@ */ if (channel == 1) { - ret = incomingim_ch1(sess, mod, rx, snac, channel, &userinfo, data+i, datalen-i, cookie); + ret = incomingim_ch1(sess, mod, rx, snac, channel, &userinfo, bs, cookie); } else if (channel == 0x0002) { - struct aim_tlvlist_t *tlvlist; + aim_tlvlist_t *tlvlist; /* * Read block of TLVs (not including the userinfo data). All * further data is derived from what is parsed here. */ - tlvlist = aim_readtlvchain(data+i, datalen-i); + tlvlist = aim_readtlvchain(bs); ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie); @@ -1028,30 +1176,29 @@ * AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers" * */ -faim_export int aim_denytransfer(struct aim_session_t *sess, - struct aim_conn_t *conn, - const char *sender, - const char *cookie, - unsigned short code) +faim_export int aim_denytransfer(aim_session_t *sess, aim_conn_t *conn, const char *sender, const char *cookie, fu16_t code) { - struct command_tx_struct *newpacket; - int curbyte, i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(sender)+6))) + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sender)+6))) return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0004, 0x000b, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0004, 0x000b, 0x0000, snacid); + + aimbs_putraw(&fr->data, cookie, 8); - curbyte = aim_putsnac(newpacket->data, 0x0004, 0x000b, 0x0000, sess->snac_nextid++); - for (i = 0; i < 8; i++) - curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); - curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sender)); - curbyte += aimutil_putstr(newpacket->data+curbyte, sender, strlen(sender)); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0003, code); + aimbs_put16(&fr->data, 0x0002); /* channel */ + aimbs_put8(&fr->data, strlen(sender)); + aimbs_putraw(&fr->data, sender, strlen(sender)); - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_addtlvtochain16(&tl, 0x0003, code); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); return 0; } @@ -1062,96 +1209,77 @@ * Request ICBM parameter information. * */ -faim_export unsigned long aim_reqicbmparams(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_reqicbmparams(aim_session_t *sess, aim_conn_t *conn) { return aim_genericreq_n(sess, conn, 0x0004, 0x0004); } /* * + * I definitly recommend sending this. If you don't, you'll be stuck + * with the rather unreasonable defaults. You don't want those. Send this. + * */ -faim_export unsigned long aim_seticbmparam(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_icbmparameters *params) +faim_export int aim_seticbmparam(aim_session_t *sess, aim_conn_t *conn, struct aim_icbmparameters *params) { - struct command_tx_struct *newpacket; - int curbyte; + aim_frame_t *fr; + aim_snacid_t snacid; if (!sess || !conn || !params) return -EINVAL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+16))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+16))) return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0004, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0004, 0x0002, 0x0000, snacid); - curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0002, 0x0000, sess->snac_nextid++); - - /* This is read-only (in Parameter Reply). Must be set to zero here. */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + /* This is read-only (see Parameter Reply). Must be set to zero here. */ + aimbs_put16(&fr->data, 0x0000); /* These are all read-write */ - curbyte += aimutil_put32(newpacket->data+curbyte, params->flags); - curbyte += aimutil_put16(newpacket->data+curbyte, params->maxmsglen); - curbyte += aimutil_put16(newpacket->data+curbyte, params->maxsenderwarn); - curbyte += aimutil_put16(newpacket->data+curbyte, params->maxrecverwarn); - curbyte += aimutil_put32(newpacket->data+curbyte, params->minmsginterval); + aimbs_put32(&fr->data, params->flags); + aimbs_put16(&fr->data, params->maxmsglen); + aimbs_put16(&fr->data, params->maxsenderwarn); + aimbs_put16(&fr->data, params->maxrecverwarn); + aimbs_put32(&fr->data, params->minmsginterval); - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); return 0; } -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) +static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { struct aim_icbmparameters params; aim_rxcallback_t userfunc; - int i = 0; - params.maxchan = aimutil_get16(data+i); - i += 2; - - params.flags = aimutil_get32(data+i); - i += 4; - - params.maxmsglen = aimutil_get16(data+i); - i += 2; - - params.maxsenderwarn = aimutil_get16(data+i); - i += 2; - - params.maxrecverwarn = aimutil_get16(data+i); - i += 2; - - params.minmsginterval = aimutil_get32(data+i); - i += 4; - + params.maxchan = aimbs_get16(bs); + params.flags = aimbs_get32(bs); + params.maxmsglen = aimbs_get16(bs); + params.maxsenderwarn = aimbs_get16(bs); + params.maxrecverwarn = aimbs_get16(bs); + params.minmsginterval = aimbs_get32(bs); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) return userfunc(sess, rx, ¶ms); 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) +static int missedcall(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - int i, ret = 0; + int ret = 0; aim_rxcallback_t userfunc; - unsigned short channel, nummissed, reason; + fu16_t channel, nummissed, reason; struct aim_userinfo_s userinfo; - - for (i = 0; i < datalen; ) { - /* Channel ID. */ - channel = aimutil_get16(data+i); - i += 2; + while (aim_bstream_empty(bs)) { - /* Extract the standard user info block. */ - i += aim_extractuserinfo(sess, data+i, &userinfo); - - nummissed = aimutil_get16(data+i); - i += 2; - - reason = aimutil_get16(data+i); - i += 2; + channel = aimbs_get16(bs); + aim_extractuserinfo(sess, bs, &userinfo); + nummissed = aimbs_get16(bs); + reason = aimbs_get16(bs); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason); @@ -1160,51 +1288,67 @@ return ret; } -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) +static int clienterr(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) +{ + int ret = 0; + aim_rxcallback_t userfunc; + fu16_t channel, reason; + char *sn; + fu8_t *ck, snlen; + + ck = aimbs_getraw(bs, 8); + channel = aimbs_get16(bs); + snlen = aimbs_get8(bs); + sn = aimbs_getstr(bs, snlen); + reason = aimbs_get16(bs); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, channel, sn, reason); + + return ret; +} + +static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_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; + fu16_t type; + fu8_t snlen, *ck; + char *sn; - type = aimutil_get16(data+i); - i += 2; - - snlen = aimutil_get8(data+i); - i++; - - memset(sn, 0, sizeof(sn)); - strncpy(sn, (char *)data+i, snlen); + ck = aimbs_getraw(bs, 8); + type = aimbs_get16(bs); + snlen = aimbs_get8(bs); + sn = aimbs_getstr(bs, 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); + free(sn); + free(ck); return 0; } -faim_internal int msg_modfirst(struct aim_session_t *sess, aim_module_t *mod) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) +{ + + if (snac->subtype == 0x0005) + return paraminfo(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0006) + return outgoingim(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0007) + return incomingim(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x000a) + return missedcall(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x000b) + return clienterr(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x000c) + return msgack(sess, mod, rx, snac, bs); + + return 0; +} + +faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod) { mod->family = 0x0004; diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/info.c --- a/src/protocols/oscar/info.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/info.c Sun Sep 09 10:07:14 2001 +0000 @@ -2,7 +2,7 @@ * aim_info.c * * The functions here are responsible for requesting and parsing information- - * gathering SNACs. + * gathering SNACs. Or something like that. * */ @@ -10,533 +10,434 @@ #include struct aim_priv_inforeq { - char sn[MAXSNLEN+1]; - unsigned short infotype; + char sn[MAXSNLEN+1]; + fu16_t infotype; }; -faim_export int aim_getinfo(struct aim_session_t *sess, - struct aim_conn_t *conn, - const char *sn, - unsigned short infotype) +faim_export int aim_getinfo(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu16_t infotype) { - struct command_tx_struct *newpacket; - struct aim_priv_inforeq privdata; - int i = 0; + struct aim_priv_inforeq privdata; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!sess || !conn || !sn) - return -1; + if (!sess || !conn || !sn) + return -EINVAL; - if ((infotype != AIM_GETINFO_GENERALINFO) && - (infotype != AIM_GETINFO_AWAYMESSAGE)) - return -1; + if ((infotype != AIM_GETINFO_GENERALINFO) && (infotype != AIM_GETINFO_AWAYMESSAGE)) + return -EINVAL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 12+1+strlen(sn)))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0002, 0x0005, 0x0000, sess->snac_nextid); + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 12+1+strlen(sn)))) + return -ENOMEM; - i += aimutil_put16(newpacket->data+i, infotype); - i += aimutil_put8(newpacket->data+i, strlen(sn)); - i += aimutil_putstr(newpacket->data+i, sn, strlen(sn)); + strncpy(privdata.sn, sn, sizeof(privdata.sn)); + privdata.infotype = infotype; + snacid = aim_cachesnac(sess, 0x0002, 0x0005, 0x0000, &privdata, sizeof(struct aim_priv_inforeq)); + + aim_putsnac(&fr->data, 0x0002, 0x0005, 0x0000, snacid); + aimbs_put16(&fr->data, infotype); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - strncpy(privdata.sn, sn, sizeof(privdata.sn)); - privdata.infotype = infotype; - aim_cachesnac(sess, 0x0002, 0x0005, 0x0000, &privdata, sizeof(struct aim_priv_inforeq)); - - return 0; + return 0; } /* * Capability blocks. */ static const struct { - unsigned short flag; - unsigned char data[16]; + unsigned short flag; + unsigned char data[16]; } aim_caps[] = { - - {AIM_CAPS_BUDDYICON, - {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_VOICE, - {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_BUDDYICON, + {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_VOICE, + {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - {AIM_CAPS_IMIMAGE, - {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_CHAT, - {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_GETFILE, - {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + {AIM_CAPS_IMIMAGE, + {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_CHAT, + {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_GETFILE, + {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - {AIM_CAPS_SENDFILE, - {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + {AIM_CAPS_SENDFILE, + {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - {AIM_CAPS_SAVESTOCKS, - {0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + {AIM_CAPS_SAVESTOCKS, + {0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - /* - * Indeed, there are two of these. The former appears - * to be correct, but in some versions of winaim, the - * second one is set. Either they forgot to fix endianness, - * or they made a typo. It really doesn't matter which. - */ - {AIM_CAPS_GAMES, - {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - {AIM_CAPS_GAMES2, - {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, - 0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + /* + * Indeed, there are two of these. The former appears to be correct, + * but in some versions of winaim, the second one is set. Either they + * forgot to fix endianness, or they made a typo. It really doesn't + * matter which. + */ + {AIM_CAPS_GAMES, + {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + {AIM_CAPS_GAMES2, + {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, + 0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - {AIM_CAPS_SENDBUDDYLIST, - {0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + {AIM_CAPS_SENDBUDDYLIST, + {0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - {AIM_CAPS_LAST} + {AIM_CAPS_LAST} }; -faim_internal unsigned short aim_getcap(struct aim_session_t *sess, unsigned char *capblock, int buflen) +/* + * This still takes a length parameter even with a bstream because capabilities + * are not naturally bounded. + * + */ +faim_internal fu16_t aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len) { - unsigned short flags; - int i; - int offset = 0; - int identified; + fu16_t flags = 0; + int offset; - for (offset = 0, flags = 0; offset < buflen; offset += 0x0010) { + for (offset = 0; aim_bstream_empty(bs) && (offset < len); offset += 0x10) { + fu8_t *cap; + int i, identified; - for (i = 0, identified = 0; !(aim_caps[i].flag & AIM_CAPS_LAST); i++) { + cap = aimbs_getraw(bs, 0x10); - if (memcmp(&aim_caps[i].data, capblock+offset, 0x10) == 0) { - flags |= aim_caps[i].flag; - identified++; - break; /* should only match once... */ - } + for (i = 0, identified = 0; !(aim_caps[i].flag & AIM_CAPS_LAST); i++) { + + if (memcmp(&aim_caps[i].data, cap, 0x10) == 0) { + flags |= aim_caps[i].flag; + identified++; + break; /* should only match once... */ - } + } + } - if (!identified) - faimdprintf(sess, 0, "unknown capability!\n"); + if (!identified) + faimdprintf(sess, 0, "unknown capability!\n"); - } + free(cap); + } - return flags; + return flags; } -faim_internal int aim_putcap(unsigned char *capblock, int buflen, unsigned short caps) +faim_internal int aim_putcap(aim_bstream_t *bs, fu16_t caps) { - int offset, i; + int i; - if (!capblock) - return 0; + if (!bs) + return -EINVAL; + + for (i = 0; aim_bstream_empty(bs); i++) { - for (i = 0, offset = 0; - !(aim_caps[i].flag & AIM_CAPS_LAST) && (offset < buflen); i++) { + if (aim_caps[i].flag == AIM_CAPS_LAST) + break; - if (caps & aim_caps[i].flag) { - memcpy(capblock+offset, aim_caps[i].data, 16); - offset += 16; - } + if (caps & aim_caps[i].flag) + aimbs_putraw(bs, aim_caps[i].data, 0x10); - } + } - return offset; + return 0; } /* - * AIM is fairly regular about providing user info. This - * is a generic routine to extract it in its standard form. + * AIM is fairly regular about providing user info. This is a generic + * routine to extract it in its standard form. */ -faim_internal int aim_extractuserinfo(struct aim_session_t *sess, unsigned char *buf, struct aim_userinfo_s *outinfo) +faim_internal int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, struct aim_userinfo_s *outinfo) { - int i = 0; - int tlvcnt = 0; - int curtlv = 0; - int tlv1 = 0; - u_short curtype; - int lastvalid; + int curtlv, tlvcnt; + fu8_t snlen; + if (!bs || !outinfo) + return -EINVAL; - if (!buf || !outinfo) - return -1; + /* Clear out old data first */ + memset(outinfo, 0x00, sizeof(struct aim_userinfo_s)); - /* Clear out old data first */ - memset(outinfo, 0x00, sizeof(struct aim_userinfo_s)); + /* + * Screen name. Stored as an unterminated string prepended with a + * byte containing its length. + */ + snlen = aimbs_get8(bs); + aimbs_getrawbuf(bs, outinfo->sn, snlen); - /* - * Screen name. Stored as an unterminated string prepended - * with an unsigned byte containing its length. - */ - if (buf[i] < MAXSNLEN) { - memcpy(outinfo->sn, &(buf[i+1]), buf[i]); - outinfo->sn[(int)buf[i]] = '\0'; - } else { - memcpy(outinfo->sn, &(buf[i+1]), MAXSNLEN-1); - outinfo->sn[MAXSNLEN] = '\0'; - } - i = 1 + (int)buf[i]; + /* + * Warning Level. Stored as an unsigned short. + */ + outinfo->warnlevel = aimbs_get16(bs); + + /* + * TLV Count. Unsigned short representing the number of + * Type-Length-Value triples that follow. + */ + tlvcnt = aimbs_get16(bs); - /* - * Warning Level. Stored as an unsigned short. - */ - outinfo->warnlevel = aimutil_get16(&buf[i]); - i += 2; + /* + * Parse out the Type-Length-Value triples as they're found. + */ + for (curtlv = 0; curtlv < tlvcnt; curtlv++) { + int endpos; + fu16_t type, length; - /* - * TLV Count. Unsigned short representing the number of - * Type-Length-Value triples that follow. - */ - tlvcnt = aimutil_get16(&buf[i]); - i += 2; + type = aimbs_get16(bs); + length = aimbs_get16(bs); + + endpos = aim_bstream_curpos(bs) + length; - /* - * Parse out the Type-Length-Value triples as they're found. - */ - while (curtlv < tlvcnt) { - lastvalid = 1; - curtype = aimutil_get16(&buf[i]); - switch (curtype) { - /* - * Type = 0x0000: Invalid - * - * AOL has been trying to throw these in just to break us. - * They're real nice guys over there at AOL. - * - * Just skip the two zero bytes and continue on. (This doesn't - * count towards tlvcnt!) - */ - case 0x0000: - lastvalid = 0; - i += 2; - break; + if (type == 0x0001) { + /* + * Type = 0x0001: User flags + * + * Specified as any of the following ORed together: + * 0x0001 Trial (user less than 60days) + * 0x0002 Unknown bit 2 + * 0x0004 AOL Main Service user + * 0x0008 Unknown bit 4 + * 0x0010 Free (AIM) user + * 0x0020 Away + * + */ + outinfo->flags = aimbs_get16(bs); + + } else if (type == 0x0002) { + /* + * Type = 0x0002: Member-Since date. + * + * The time/date that the user originally registered for + * the service, stored in time_t format. + */ + outinfo->membersince = aimbs_get32(bs); + + } else if (type == 0x0003) { + /* + * Type = 0x0003: On-Since date. + * + * The time/date that the user started their current + * session, stored in time_t format. + */ + outinfo->onlinesince = aimbs_get32(bs); - /* - * Type = 0x0001: User flags - * - * Specified as any of the following bitwise ORed together: - * 0x0001 Trial (user less than 60days) - * 0x0002 Unknown bit 2 - * 0x0004 AOL Main Service user - * 0x0008 Unknown bit 4 - * 0x0010 Free (AIM) user - * 0x0020 Away - * - * In some odd cases, we can end up with more - * than one of these. We only want the first, - * as the others may not be something we want. - * - */ - case 0x0001: - if (tlv1) /* use only the first */ - break; - outinfo->flags = aimutil_get16(&buf[i+4]); - tlv1++; - break; - - /* - * Type = 0x0002: Member-Since date. - * - * The time/date that the user originally - * registered for the service, stored in - * time_t format - */ - case 0x0002: - outinfo->membersince = aimutil_get32(&buf[i+4]); - break; - - /* - * Type = 0x0003: On-Since date. - * - * The time/date that the user started - * their current session, stored in time_t - * format. - */ - case 0x0003: - outinfo->onlinesince = aimutil_get32(&buf[i+4]); - break; - - /* - * Type = 0x0004: Idle time. - * - * Number of seconds since the user - * actively used the service. - */ - case 0x0004: - outinfo->idletime = aimutil_get16(&buf[i+4]); - break; - - /* - * Type = 0x0006: ICQ Online Status - * - * ICQ's Away/DND/etc "enriched" status - * Some decoding of values done by Scott - */ - case 0x0006: - outinfo->icqinfo.status = aimutil_get16(buf+i+2+2+2); - break; + } else if (type == 0x0004) { + /* + * Type = 0x0004: Idle time. + * + * Number of seconds since the user actively used the + * service. + * + * Note that the client tells the server when to start + * counting idle times, so this may or may not be + * related to reality. + */ + outinfo->idletime = aimbs_get16(bs); + } else if (type == 0x0006) { + /* + * Type = 0x0006: ICQ Online Status + * + * ICQ's Away/DND/etc "enriched" status. Some decoding + * of values done by Scott + */ + aimbs_get16(bs); + outinfo->icqinfo.status = aimbs_get16(bs); - /* - * Type = 0x000a - * - * ICQ User IP Address. - * Ahh, the joy of ICQ security. - */ - case 0x000a: - outinfo->icqinfo.ipaddr = aimutil_get32(&buf[i+4]); - break; + } else if (type == 0x000a) { + /* + * Type = 0x000a + * + * ICQ User IP Address. + * Ahh, the joy of ICQ security. + */ + outinfo->icqinfo.ipaddr = aimbs_get32(bs); - /* Type = 0x000c - * - * random crap containing the IP address, - * apparently a port number, and some Other Stuff. - * - */ - case 0x000c: - memcpy(outinfo->icqinfo.crap, &buf[i+4], 0x25); - break; + } else if (type == 0x000c) { + /* + * Type = 0x000c + * + * random crap containing the IP address, + * apparently a port number, and some Other Stuff. + * + */ + aimbs_getrawbuf(bs, outinfo->icqinfo.crap, 0x25); - /* - * Type = 0x000d - * - * Capability information. Not real sure of - * actual decoding. See comment on aim_bos_setprofile() - * in aim_misc.c about the capability block, its the same. - * - */ - case 0x000d: - { - int len; - len = aimutil_get16(buf+i+2); - if (!len) - break; - - outinfo->capabilities = aim_getcap(sess, buf+i+4, len); - } - break; - - /* - * Type = 0x000e - * - * Unknown. Always of zero length, and always only - * on AOL users. - * - * Ignore. - * - */ - case 0x000e: - break; - - /* - * Type = 0x000f: Session Length. (AIM) - * Type = 0x0010: Session Length. (AOL) - * - * The duration, in seconds, of the user's - * current session. - * - * Which TLV type this comes in depends - * on the service the user is using (AIM or AOL). - * - */ - case 0x000f: - case 0x0010: - outinfo->sessionlen = aimutil_get32(&buf[i+4]); - break; - - /* - * Reaching here indicates that either AOL has - * added yet another TLV for us to deal with, - * or the parsing has gone Terribly Wrong. - * - * Either way, inform the owner and attempt - * recovery. - * - */ - default: - { - int len,z = 0, y = 0, x = 0; - char tmpstr[160]; + } else if (type == 0x000d) { + /* + * Type = 0x000d + * + * Capability information. + * + */ + outinfo->capabilities = aim_getcap(sess, bs, length); + + } else if (type == 0x000e) { + /* + * Type = 0x000e + * + * Unknown. Always of zero length, and always only + * on AOL users. + * + * Ignore. + * + */ - faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV:\n"); - faimdprintf(sess, 0, "userinfo: sn =%s\n", outinfo->sn); - faimdprintf(sess, 0, "userinfo: curtlv=0x%04x\n", curtlv); - faimdprintf(sess, 0, "userinfo: type =0x%04x\n",aimutil_get16(&buf[i])); - faimdprintf(sess, 0, "userinfo: length=0x%04x\n", len = aimutil_get16(&buf[i+2])); - faimdprintf(sess, 0, "userinfo: data: \n"); - while (zsessionlen = aimbs_get32(bs); + + } else { + + /* + * Reaching here indicates that either AOL has + * added yet another TLV for us to deal with, + * or the parsing has gone Terribly Wrong. + * + * Either way, inform the owner and attempt + * recovery. + * + */ + faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV:\n"); + faimdprintf(sess, 0, "userinfo: sn =%s\n", outinfo->sn); + faimdprintf(sess, 0, "userinfo: type =0x%04x\n",type); + faimdprintf(sess, 0, "userinfo: length=0x%04x\n", length); + + } + + /* Save ourselves. */ + aim_bstream_setpos(bs, endpos); + } + + return 0; } /* * Inverse of aim_extractuserinfo() */ -faim_internal int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info) +faim_internal int aim_putuserinfo(aim_bstream_t *bs, struct aim_userinfo_s *info) { - int i = 0, numtlv = 0; - struct aim_tlvlist_t *tlvlist = NULL; + aim_tlvlist_t *tlvlist = NULL; - if (!buf || !info) - return 0; + if (!bs || !info) + return -EINVAL; - i += aimutil_put8(buf+i, strlen(info->sn)); - i += aimutil_putstr(buf+i, info->sn, strlen(info->sn)); + aimbs_put8(bs, strlen(info->sn)); + aimbs_putraw(bs, info->sn, strlen(info->sn)); - i += aimutil_put16(buf+i, info->warnlevel); + aimbs_put16(bs, info->warnlevel); - aim_addtlvtochain16(&tlvlist, 0x0001, info->flags); - numtlv++; - - aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince); - numtlv++; - - aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince); - numtlv++; - - aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime); - numtlv++; + aim_addtlvtochain16(&tlvlist, 0x0001, info->flags); + aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince); + aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince); + aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime); #if ICQ_OSCAR_SUPPORT - if(atoi(info->sn) != 0) { - aim_addtlvtochain16(&tlvlist, 0x0006, info->icqinfo.status); - aim_addtlvtochain32(&tlvlist, 0x000a, info->icqinfo.ipaddr); - } + if (atoi(info->sn) != 0) { + aim_addtlvtochain16(&tlvlist, 0x0006, info->icqinfo.status); + aim_addtlvtochain32(&tlvlist, 0x000a, info->icqinfo.ipaddr); + } #endif - aim_addtlvtochain_caps(&tlvlist, 0x000d, info->capabilities); - numtlv++; + aim_addtlvtochain_caps(&tlvlist, 0x000d, info->capabilities); - aim_addtlvtochain32(&tlvlist, (unsigned short)((info->flags)&AIM_FLAG_AOL?0x0010:0x000f), info->sessionlen); - numtlv++; + aim_addtlvtochain32(&tlvlist, (fu16_t)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen); - i += aimutil_put16(buf+i, numtlv); /* tlvcount */ - i += aim_writetlvchain(buf+i, buflen-i, &tlvlist); /* tlvs */ - aim_freetlvchain(&tlvlist); + aimbs_put16(bs, aim_counttlvchain(&tlvlist)); + aim_writetlvchain(bs, &tlvlist); + aim_freetlvchain(&tlvlist); - return i; + return 0; } -faim_export int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info) +faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *info) { - struct command_tx_struct *tx; - int i = 0; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!sess || !conn || !info) - return 0; - - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) - return -1; - - tx->lock = 1; + if (!sess || !conn || !info) + return -EINVAL; - i += aimutil_put16(tx->data+i, 0x0003); - i += aimutil_put16(tx->data+i, 0x000b); - i += aimutil_put16(tx->data+i, 0x0000); - i += aimutil_put16(tx->data+i, 0x0000); - i += aimutil_put16(tx->data+i, 0x0000); + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) + return -ENOMEM; - i += aim_putuserinfo(tx->data+i, tx->commandlen-i, info); + snacid = aim_cachesnac(sess, 0x0003, 0x000b, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0003, 0x000b, 0x0000, snacid); + aim_putuserinfo(&fr->data, info); - tx->commandlen = i; - tx->lock = 0; - aim_tx_enqueue(sess, tx); + aim_tx_enqueue(sess, fr); - return 0; + return 0; } -faim_export int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn) +faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn) { - struct command_tx_struct *tx; - int i = 0; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!sess || !conn || !sn) - return 0; - - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+1+strlen(sn)))) - return -1; - - tx->lock = 1; + if (!sess || !conn || !sn) + return -EINVAL; - i += aimutil_put16(tx->data+i, 0x0003); - i += aimutil_put16(tx->data+i, 0x000c); - i += aimutil_put16(tx->data+i, 0x0000); - i += aimutil_put16(tx->data+i, 0x0000); - i += aimutil_put16(tx->data+i, 0x0000); + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)))) + return -ENOMEM; - i += aimutil_put8(tx->data+i, strlen(sn)); - i += aimutil_putstr(tx->data+i, sn, strlen(sn)); - - tx->lock = 0; - aim_tx_enqueue(sess, tx); + snacid = aim_cachesnac(sess, 0x0003, 0x000c, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0003, 0x000c, 0x0000, snacid); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - return 0; + aim_tx_enqueue(sess, fr); + + return 0; } -faim_export int aim_0002_000b(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn) +/* + * Huh? What is this? + */ +faim_export int aim_0002_000b(aim_session_t *sess, aim_conn_t *conn, const char *sn) { - struct command_tx_struct *tx; - int i = 0; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!sess || !conn || !sn) - return 0; - - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+1+strlen(sn)))) - return -1; + if (!sess || !conn || !sn) + return -EINVAL; - tx->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)))) + return -ENOMEM; - i = aim_putsnac(tx->data, 0x0002, 0x000b, 0x0000, sess->snac_nextid); - i += aimutil_put8(tx->data+i, strlen(sn)); - i += aimutil_putstr(tx->data+i, sn, strlen(sn)); - - tx->commandlen = i; - tx->lock = 0; - aim_tx_enqueue(sess, tx); + snacid = aim_cachesnac(sess, 0x0002, 0x000b, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0002, 0x000b, 0x0000, snacid); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - return 0; + aim_tx_enqueue(sess, fr); + + return 0; } /* @@ -545,14 +446,14 @@ * t(0002) - short - unknown (value = 16) [max MIME type length?] * t(0003) - short - unknown (value = 7) */ -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) +static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_tlvlist_t *tlvlist; + aim_tlvlist_t *tlvlist; aim_rxcallback_t userfunc; int ret = 0; - unsigned short maxsiglen = 0; + fu16_t maxsiglen = 0; - tlvlist = aim_readtlvchain(data, datalen); + tlvlist = aim_readtlvchain(bs); if (aim_gettlv(tlvlist, 0x0001, 1)) maxsiglen = aim_gettlv16(tlvlist, 0x0001, 1); @@ -565,87 +466,83 @@ 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) +static int userinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_userinfo_s userinfo; - char *text_encoding = NULL; - char *text = NULL; - int i = 0; - aim_rxcallback_t userfunc; - struct aim_tlvlist_t *tlvlist; - struct aim_snac_t *origsnac = NULL; - struct aim_priv_inforeq *inforeq; - int ret = 0; + struct aim_userinfo_s userinfo; + char *text_encoding = NULL, *text = NULL; + aim_rxcallback_t userfunc; + aim_tlvlist_t *tlvlist; + aim_snac_t *origsnac = NULL; + struct aim_priv_inforeq *inforeq; + int ret = 0; + + origsnac = aim_remsnac(sess, snac->id); - origsnac = aim_remsnac(sess, snac->id); + if (!origsnac || !origsnac->data) { + faimdprintf(sess, 0, "parse_userinfo_middle: major problem: no snac stored!\n"); + return 0; + } - 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; - 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; + } - 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; - } + aim_extractuserinfo(sess, bs, &userinfo); - i = aim_extractuserinfo(sess, data, &userinfo); - - tlvlist = aim_readtlvchain(data+i, datalen-i); + tlvlist = aim_readtlvchain(bs); - /* - * 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); - } + /* + * 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); + 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); + free(text_encoding); + free(text); - if (origsnac) { - if (origsnac->data) - free(origsnac->data); - free(origsnac); - } + aim_freetlvchain(&tlvlist); - return ret; + if (origsnac) + 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) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - 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); + if (snac->subtype == 0x0003) + return rights(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0006) + return userinfo(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int locate_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int locate_modfirst(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; + mod->family = 0x0002; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "locate", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/login.c --- a/src/protocols/oscar/login.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/login.c Sun Sep 09 10:07:14 2001 +0000 @@ -12,109 +12,152 @@ static int aim_encode_password(const char *password, unsigned char *encoded); -faim_export int aim_sendflapver(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn) { - int curbyte=0; + aim_frame_t *fr; - struct command_tx_struct *newpacket; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0001, 4))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 4))) return -ENOMEM; - newpacket->lock = 1; + aimbs_put32(&fr->data, 0x00000001); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + aim_tx_enqueue(sess, fr); - newpacket->lock = 0; - - return aim_tx_enqueue(sess, newpacket); + return 0; } /* - * In AIM 3.5 protocol, the first stage of login is to request - * login from the Authorizer, passing it the screen name - * for verification. If the name is invalid, a 0017/0003 - * is spit back, with the standard error contents. If valid, - * a 0017/0007 comes back, which is the signal to send - * it the main login command (0017/0002). + * This is a bit confusing. + * + * Normal SNAC login goes like this: + * - connect + * - server sends flap version + * - client sends flap version + * - client sends screen name (17/6) + * - server sends hash key (17/7) + * - client sends auth request (17/2 -- aim_send_login) + * - server yells + * + * XOR login (for ICQ) goes like this: + * - connect + * - server sends flap version + * - client sends auth request which contains flap version (aim_send_login) + * - server yells + * + * For the client API, we make them implement the most complicated version, + * and for the simpler version, we fake it and make it look like the more + * complicated process. + * + * This is done by giving the client a faked key, just so we can convince + * them to call aim_send_login right away, which will detect the session + * flag that says this is XOR login and ignore the key, sending an ICQ + * login request instead of the normal SNAC one. + * + * As soon as AOL makes ICQ log in the same way as AIM, this is /gone/. + * + * XXX This may cause problems if the client relies on callbacks only + * being called from the context of aim_rxdispatch()... + * */ -faim_export int aim_request_login(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn) +static int goddamnicq(aim_session_t *sess, aim_conn_t *conn, const char *sn) { - int curbyte; - struct command_tx_struct *newpacket; + aim_frame_t fr; + aim_rxcallback_t userfunc; + + sess->flags &= ~AIM_SESS_FLAGS_SNACLOGIN; + sess->flags |= AIM_SESS_FLAGS_XORLOGIN; + + fr.conn = conn; + + if ((userfunc = aim_callhandler(sess, conn, 0x0017, 0x0007))) + userfunc(sess, &fr, ""); + + return 0; +} +/* + * In AIM 3.5 protocol, the first stage of login is to request login from the + * Authorizer, passing it the screen name for verification. If the name is + * invalid, a 0017/0003 is spit back, with the standard error contents. If + * valid, a 0017/0007 comes back, which is the signal to send it the main + * login command (0017/0002). + * + * XXX make ICQ logins work again. + */ +faim_export int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn) +{ + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + if (!sess || !conn || !sn) return -EINVAL; - /* - * For ICQ, we enable the ancient horrible login and stuff - * a key packet into the queue to make it look like we got - * a reply back. This is so the client doesn't know we're - * really not doing MD5 login. - * - * This may sound stupid, but I'm not in the best of moods and - * I don't plan to keep support for this crap around much longer. - * Its all AOL's fault anyway, really. I hate AOL. Really. They - * always seem to be able to piss me off by doing the dumbest little - * things. Like disabling MD5 logins for ICQ UINs, or adding - * purposefully wrong TLV lengths, or adding superfluous information - * to host strings, or... I'll stop. - * - */ - if ((sn[0] >= '0') && (sn[0] <= '9')) { - struct command_rx_struct *newrx; - int i; - - /* XXX Uhm why doesn't this use aim_tx_new? */ - if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) - return -ENOMEM; - - memset(newrx, 0x00, sizeof(struct command_rx_struct)); - newrx->lock = 1; - newrx->hdrtype = AIM_FRAMETYPE_OSCAR; - newrx->hdr.oscar.type = 0x02; - newrx->hdr.oscar.seqnum = 0; - newrx->commandlen = 10+2+1; - newrx->nofree = 0; - - if (!(newrx->data = malloc(newrx->commandlen))) { - free(newrx); - return -ENOMEM; - } - - i = aim_putsnac(newrx->data, 0x0017, 0x0007, 0x0000, 0x0000); - i += aimutil_put16(newrx->data+i, 0x01); - i += aimutil_putstr(newrx->data+i, "0", 1); - - newrx->conn = conn; - - newrx->next = sess->queue_incoming; - sess->queue_incoming = newrx; - - newrx->lock = 0; - - sess->flags &= ~AIM_SESS_FLAGS_SNACLOGIN; - - return 0; - } + if ((sn[0] >= '0') || (sn[0] <= '9')) + return goddamnicq(sess, conn, sn); sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; aim_sendflapver(sess, conn); - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+2+strlen(sn)))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(sn)))) return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0017, 0x0006, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0017, 0x0006, 0x0000, snacid); + + aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); + + return 0; +} - curbyte = aim_putsnac(newpacket->data, 0x0017, 0x0006, 0x0000, 0x00010000); - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn); +/* + * Part two of the ICQ hack. Note the ignoring of the key and clientinfo. + */ +static int goddamnicq2(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password) +{ + static const char clientstr[] = {"ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85"}; + static const char lang[] = {"en"}; + static const char country[] = {"us"}; + aim_frame_t *fr; + aim_tlvlist_t *tl = NULL; + char *password_encoded; + + if (!(password_encoded = (char *) malloc(strlen(password)))) + return -ENOMEM; - newpacket->commandlen = curbyte; - newpacket->lock = 0; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 1152))) { + free(password_encoded); + return -ENOMEM; + } + + aim_encode_password(password, password_encoded); - return aim_tx_enqueue(sess, newpacket); + aimbs_put32(&fr->data, 0x00000001); + aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn); + aim_addtlvtochain_raw(&tl, 0x0002, strlen(password), password_encoded); + aim_addtlvtochain_raw(&tl, 0x0003, strlen(clientstr), clientstr); + aim_addtlvtochain16(&tl, 0x0016, 0x010a); + aim_addtlvtochain16(&tl, 0x0017, 0x0004); + aim_addtlvtochain16(&tl, 0x0018, 0x0041); + aim_addtlvtochain16(&tl, 0x0019, 0x0001); + aim_addtlvtochain16(&tl, 0x001a, 0x0cd1); + aim_addtlvtochain32(&tl, 0x0014, 0x00000055); + aim_addtlvtochain_raw(&tl, 0x000f, strlen(lang), lang); + aim_addtlvtochain_raw(&tl, 0x000e, strlen(country), country); + + aim_writetlvchain(&fr->data, &tl); + + free(password_encoded); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); + + return 0; } /* @@ -176,79 +219,62 @@ * serverstore = 0x01 * */ -faim_export int aim_send_login (struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, char *password, struct client_info_s *clientinfo, char *key) +faim_export int aim_send_login(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password, struct client_info_s *clientinfo, const char *key) { - int curbyte=0; - struct command_tx_struct *newpacket; + aim_frame_t *fr; + aim_tlvlist_t *tl = NULL; + fu8_t digest[16]; + aim_snacid_t snacid; if (!clientinfo || !sn || !password) return -EINVAL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) + if (sess->flags & AIM_SESS_FLAGS_XORLOGIN) + return goddamnicq2(sess, conn, sn, password); + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) return -ENOMEM; - newpacket->lock = 1; - - newpacket->hdr.oscar.type = (sess->flags & AIM_SESS_FLAGS_SNACLOGIN)?0x02:0x01; - - if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) - curbyte = aim_putsnac(newpacket->data, 0x0017, 0x0002, 0x0000, 0x00010000); - else { - curbyte = aimutil_put16(newpacket->data, 0x0000); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); - } - - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn); + if (sess->flags & AIM_SESS_FLAGS_XORLOGIN) { + fr->hdr.flap.type = 0x01; - if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { - unsigned char digest[16]; - - aim_encode_password_md5(password, key, digest); - curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0025, 16, (char *)digest); - } else { - char *password_encoded; - - password_encoded = (char *) malloc(strlen(password)); - aim_encode_password(password, password_encoded); - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0002, strlen(password), password_encoded); - free(password_encoded); + /* Use very specific version numbers to further indicate hack */ + clientinfo->major2 = 0x010a; + clientinfo->major = 0x0004; + clientinfo->minor = 0x003c; + clientinfo->minor2 = 0x0001; + clientinfo->build = 0x0cce; + clientinfo->unknown = 0x00000055; } - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring); - - if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { + snacid = aim_cachesnac(sess, 0x0017, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0017, 0x0002, 0x0000, snacid); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, (unsigned short)clientinfo->major2); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, (unsigned short)clientinfo->major); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, (unsigned short)clientinfo->minor); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, (unsigned short)clientinfo->minor2); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, (unsigned short)clientinfo->build); + aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn); + + aim_encode_password_md5(password, key, digest); + aim_addtlvtochain_raw(&tl, 0x0025, 16, digest); - } else { - /* Use very specific version numbers, to further indicate the hack. */ - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, 0x010a); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, 0x0004); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, 0x003c); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, 0x0001); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, 0x0cce); - curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, 0x00000055); - } + aim_addtlvtochain_raw(&tl, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring); + aim_addtlvtochain16(&tl, 0x0016, (fu16_t)clientinfo->major2); + aim_addtlvtochain16(&tl, 0x0017, (fu16_t)clientinfo->major); + aim_addtlvtochain16(&tl, 0x0018, (fu16_t)clientinfo->minor); + aim_addtlvtochain16(&tl, 0x0019, (fu16_t)clientinfo->minor2); + aim_addtlvtochain16(&tl, 0x001a, (fu16_t)clientinfo->build); + aim_addtlvtochain_raw(&tl, 0x000e, strlen(clientinfo->country), clientinfo->country); + aim_addtlvtochain_raw(&tl, 0x000f, strlen(clientinfo->lang), clientinfo->lang); + aim_addtlvtochain16(&tl, 0x0009, 0x0015); - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000e, strlen(clientinfo->country), clientinfo->country); - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000f, strlen(clientinfo->lang), clientinfo->lang); + aim_writetlvchain(&fr->data, &tl); - if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { - curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, clientinfo->unknown); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015); - } + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); - newpacket->commandlen = curbyte; - newpacket->lock = 0; - - return aim_tx_enqueue(sess, newpacket); + return 0; } -faim_export int aim_encode_password_md5(const char *password, const char *key, unsigned char *digest) +faim_export int aim_encode_password_md5(const char *password, const char *key, fu8_t *digest) { md5_state_t state; @@ -278,9 +304,9 @@ * This is only used for the XOR method, not the better MD5 method. * */ -static int aim_encode_password(const char *password, unsigned char *encoded) +static int aim_encode_password(const char *password, fu8_t *encoded) { - unsigned char encoding_table[] = { + fu8_t encoding_table[] = { #if 0 /* old v1 table */ 0xf3, 0xb3, 0x6c, 0x99, 0x95, 0x3f, 0xac, 0xb6, @@ -304,55 +330,51 @@ /* * Generate an authorization response. * - * You probably don't want this unless you're writing an AIM server. + * You probably don't want this unless you're writing an AIM server. Which + * I hope you're not doing. Because it's far more difficult than it looks. * */ -faim_export unsigned long aim_sendauthresp(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *sn, int errorcode, - char *errorurl, char *bosip, - char *cookie, char *email, - int regstatus) +faim_export int aim_sendauthresp(aim_session_t *sess, aim_conn_t *conn, const char *sn, int errorcode, const char *errorurl, const char *bosip, const char *cookie, const char *email, int regstatus) { - struct command_tx_struct *tx; - struct aim_tlvlist_t *tlvlist = NULL; + aim_tlvlist_t *tlvlist = NULL; + aim_frame_t *fr; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0004, 1152))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x04, 1152))) return -ENOMEM; - tx->lock = 1; - if (sn) - aim_addtlvtochain_str(&tlvlist, 0x0001, sn, strlen(sn)); + aim_addtlvtochain_raw(&tlvlist, 0x0001, strlen(sn), sn); else - aim_addtlvtochain_str(&tlvlist, 0x0001, sess->sn, strlen(sess->sn)); + aim_addtlvtochain_raw(&tlvlist, 0x0001, strlen(sess->sn), sess->sn); if (errorcode) { aim_addtlvtochain16(&tlvlist, 0x0008, errorcode); - aim_addtlvtochain_str(&tlvlist, 0x0004, errorurl, strlen(errorurl)); + aim_addtlvtochain_raw(&tlvlist, 0x0004, strlen(errorurl), errorurl); } else { - aim_addtlvtochain_str(&tlvlist, 0x0005, bosip, strlen(bosip)); - aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN); - aim_addtlvtochain_str(&tlvlist, 0x0011, email, strlen(email)); - aim_addtlvtochain16(&tlvlist, 0x0013, (unsigned short)regstatus); + aim_addtlvtochain_raw(&tlvlist, 0x0005, strlen(bosip), bosip); + aim_addtlvtochain_raw(&tlvlist, 0x0006, AIM_COOKIELEN, cookie); + aim_addtlvtochain_raw(&tlvlist, 0x0011, strlen(email), email); + aim_addtlvtochain16(&tlvlist, 0x0013, (fu16_t)regstatus); } - tx->commandlen = aim_writetlvchain(tx->data, tx->commandlen, &tlvlist); - tx->lock = 0; + aim_writetlvchain(&fr->data, &tlvlist); + aim_freetlvchain(&tlvlist); - return aim_tx_enqueue(sess, tx); + aim_tx_enqueue(sess, fr); + + return 0; } /* * Generate a random cookie. (Non-client use only) */ -faim_export int aim_gencookie(unsigned char *buf) +faim_export int aim_gencookie(fu8_t *buf) { int i; srand(time(NULL)); - for (i=0; i < AIM_COOKIELEN; i++) + for (i = 0; i < AIM_COOKIELEN; i++) buf[i] = 1+(int) (256.0*rand()/(RAND_MAX+0.0)); return i; @@ -361,102 +383,97 @@ /* * Send Server Ready. (Non-client) */ -faim_export int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_sendserverready(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *tx; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+0x22))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+0x22))) return -ENOMEM; - tx->lock = 1; - - i = aim_putsnac(tx->data, 0x0001, 0x0003, 0x0000, sess->snac_nextid++); + snacid = aim_cachesnac(sess, 0x0001, 0x0003, 0x0000, NULL, 0); - i += aimutil_put16(tx->data+i, 0x0001); - i += aimutil_put16(tx->data+i, 0x0002); - i += aimutil_put16(tx->data+i, 0x0003); - i += aimutil_put16(tx->data+i, 0x0004); - i += aimutil_put16(tx->data+i, 0x0006); - i += aimutil_put16(tx->data+i, 0x0008); - i += aimutil_put16(tx->data+i, 0x0009); - i += aimutil_put16(tx->data+i, 0x000a); - i += aimutil_put16(tx->data+i, 0x000b); - i += aimutil_put16(tx->data+i, 0x000c); - i += aimutil_put16(tx->data+i, 0x0013); - i += aimutil_put16(tx->data+i, 0x0015); + aim_putsnac(&fr->data, 0x0001, 0x0003, 0x0000, snacid); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0002); + aimbs_put16(&fr->data, 0x0003); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0006); + aimbs_put16(&fr->data, 0x0008); + aimbs_put16(&fr->data, 0x0009); + aimbs_put16(&fr->data, 0x000a); + aimbs_put16(&fr->data, 0x000b); + aimbs_put16(&fr->data, 0x000c); + aimbs_put16(&fr->data, 0x0013); + aimbs_put16(&fr->data, 0x0015); - tx->commandlen = i; - tx->lock = 0; + aim_tx_enqueue(sess, fr); - return aim_tx_enqueue(sess, tx); + return 0; } /* * Send service redirect. (Non-Client) */ -faim_export unsigned long aim_sendredirect(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short servid, char *ip, char *cookie) +faim_export int aim_sendredirect(aim_session_t *sess, aim_conn_t *conn, fu16_t servid, const char *ip, const char *cookie) { - struct command_tx_struct *tx; - struct aim_tlvlist_t *tlvlist = NULL; - int i; + aim_tlvlist_t *tlvlist = NULL; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) return -ENOMEM; - tx->lock = 1; - - i = aim_putsnac(tx->data, 0x0001, 0x0005, 0x0000, 0x00000000); + snacid = aim_cachesnac(sess, 0x0001, 0x0005, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x0005, 0x0000, snacid); aim_addtlvtochain16(&tlvlist, 0x000d, servid); - aim_addtlvtochain_str(&tlvlist, 0x0005, ip, strlen(ip)); - aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN); + aim_addtlvtochain_raw(&tlvlist, 0x0005, strlen(ip), ip); + aim_addtlvtochain_raw(&tlvlist, 0x0006, AIM_COOKIELEN, cookie); - tx->commandlen = aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist)+i; + aim_writetlvchain(&fr->data, &tlvlist); aim_freetlvchain(&tlvlist); - tx->lock = 0; + aim_tx_enqueue(sess, fr); - return aim_tx_enqueue(sess, tx); + return 0; } -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) +static int hostonline(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; int ret = 0; - unsigned short *families; - int famcount, i; + fu16_t *families; + int famcount; - famcount = datalen/2; - - if (!(families = malloc(datalen))) + if (!(families = malloc(aim_bstream_empty(bs)))) return 0; - for (i = 0; i < famcount; i++) - families[i] = aimutil_get16(data+(i*2)); + for (famcount = 0; aim_bstream_empty(bs); famcount++) + families[famcount] = aimbs_get16(bs); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, famcount, families); free(families); - return ret; + 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) +static int redirect(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int serviceid; - unsigned char *cookie; + fu8_t *cookie; char *ip; aim_rxcallback_t userfunc; - struct aim_tlvlist_t *tlvlist; + aim_tlvlist_t *tlvlist; char *chathack = NULL; int chathackex = 0; int ret = 0; - tlvlist = aim_readtlvchain(data, datalen); + tlvlist = aim_readtlvchain(bs); if (!aim_gettlv(tlvlist, 0x000d, 1) || !aim_gettlv(tlvlist, 0x0005, 1) || @@ -542,7 +559,7 @@ */ /* 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) +static int rateresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; @@ -552,33 +569,22 @@ 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) +static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_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; + fu16_t code, rateclass; + fu32_t currentavg, maxavg, windowsize, clear, alert, limit, disconnect; - 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; + code = aimbs_get16(bs); + rateclass = aimbs_get16(bs); + + windowsize = aimbs_get32(bs); + clear = aimbs_get32(bs); + alert = aimbs_get32(bs); + limit = aimbs_get32(bs); + disconnect = aimbs_get32(bs); + currentavg = aimbs_get32(bs); + maxavg = aimbs_get32(bs); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) return userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg); @@ -587,7 +593,7 @@ } /* 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) +static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; @@ -597,20 +603,18 @@ 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) +static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - aim_rxcallback_t userfunc = NULL; - int i = 0; - unsigned short newevil; + aim_rxcallback_t userfunc; + fu16_t newevil; struct aim_userinfo_s userinfo; - newevil = aimutil_get16(data); - i += 2; + memset(&userinfo, 0, sizeof(struct aim_userinfo_s)); + + newevil = aimbs_get16(bs); - memset(&userinfo, 0, sizeof(struct aim_userinfo_s)); - - if (datalen-i) - i += aim_extractuserinfo(sess, data+i, &userinfo); + if (aim_bstream_empty(bs)) + aim_extractuserinfo(sess, bs, &userinfo); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) return userfunc(sess, rx, newevil, &userinfo); @@ -618,13 +622,13 @@ 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) +static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; char *msg = NULL; int ret = 0; - struct aim_tlvlist_t *tlvlist; - unsigned short id; + aim_tlvlist_t *tlvlist; + fu16_t id; /* * Code. @@ -636,13 +640,14 @@ * 4 Nothing's wrong ("top o the world" -- normal) * */ - id = aimutil_get16(data); + id = aimbs_get16(bs); /* * TLVs follow */ - if ((tlvlist = aim_readtlvchain(data+2, datalen-2))) - msg = aim_gettlv_str(tlvlist, 0x000b, 1); + tlvlist = aim_readtlvchain(bs); + + msg = aim_gettlv_str(tlvlist, 0x000b, 1); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, id, msg); @@ -654,15 +659,19 @@ 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) +static int hostversions(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; int vercount; + fu8_t *versions; - vercount = datalen/4; + vercount = aim_bstream_empty(bs)/4; + versions = aimbs_getraw(bs, aim_bstream_empty(bs)); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - return userfunc(sess, rx, vercount, data); + return userfunc(sess, rx, vercount, versions); + + free(versions); return 0; } @@ -704,24 +713,18 @@ * Anyway, neener. We win again. * */ -static int memrequest(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; - unsigned long offset, len; - int i = 0; - struct aim_tlvlist_t *list; - char *modname = NULL; - - offset = aimutil_get32(data); - i += 4; + fu32_t offset, len; + aim_tlvlist_t *list; + char *modname; - len = aimutil_get32(data+4); - i += 4; + offset = aimbs_get32(bs); + len = aimbs_get32(bs); + list = aim_readtlvchain(bs); - list = aim_readtlvchain(data+i, datalen-i); - - if (aim_gettlv(list, 0x0001, 1)) - modname = aim_gettlv_str(list, 0x0001, 1); + modname = aim_gettlv_str(list, 0x0001, 1); faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) of requested\n", offset, len, modname ? modname : "aim.exe"); @@ -734,7 +737,8 @@ return 0; } -static void dumpbox(struct aim_session_t *sess, unsigned char *buf, int len) +#if 0 +static void dumpbox(aim_session_t *sess, unsigned char *buf, int len) { int i; @@ -754,39 +758,42 @@ return; } +#endif -faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag) +faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, fu32_t offset, fu32_t len, const fu8_t *buf, fu8_t flag) { - struct command_tx_struct *tx; - int i = 0; + aim_frame_t *fr; + aim_snacid_t snacid; if (!sess || !conn) return -EINVAL; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+16))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+16))) return -ENOMEM; - tx->lock = 1; + snacid = aim_cachesnac(sess, 0x0001, 0x0020, 0x0000, NULL, 0); - i = aim_putsnac(tx->data, 0x0001, 0x0020, 0x0000, sess->snac_nextid++); - i += aimutil_put16(tx->data+i, 0x0010); /* md5 is always 16 bytes */ + aim_putsnac(&fr->data, 0x0001, 0x0020, 0x0000, snacid); + aimbs_put16(&fr->data, 0x0010); /* md5 is always 16 bytes */ if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && buf && (len == 0x10)) { /* we're getting a hash */ - memcpy(tx->data+i, buf, 0x10); - i += 0x10; + aimbs_putraw(&fr->data, buf, 0x10); } else if (buf && (len > 0)) { /* use input buffer */ md5_state_t state; + md5_byte_t digest[0x10]; md5_init(&state); md5_append(&state, (const md5_byte_t *)buf, len); - md5_finish(&state, (md5_byte_t *)(tx->data+i)); - i += 0x10; + md5_finish(&state, digest); + + aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10); } else if (len == 0) { /* no length, just hash NULL (buf is optional) */ md5_state_t state; - unsigned char nil = '\0'; + fu8_t nil = '\0'; + md5_byte_t digest[0x10]; /* * These MD5 routines are stupid in that you have to have @@ -795,8 +802,9 @@ */ md5_init(&state); md5_append(&state, (const md5_byte_t *)&nil, 0); - md5_finish(&state, (md5_byte_t *)(tx->data+i)); - i += 0x10; + md5_finish(&state, digest); + + aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10); } else { @@ -810,62 +818,60 @@ if ((offset == 0x03ffffff) && (len == 0x03ffffff)) { #if 1 /* with "AnrbnrAqhfzcd" */ - i += aimutil_put32(tx->data+i, 0x44a95d26); - i += aimutil_put32(tx->data+i, 0xd2490423); - i += aimutil_put32(tx->data+i, 0x93b8821f); - i += aimutil_put32(tx->data+i, 0x51c54b01); + aimbs_put32(&fr->data, 0x44a95d26); + aimbs_put32(&fr->data, 0xd2490423); + aimbs_put32(&fr->data, 0x93b8821f); + aimbs_put32(&fr->data, 0x51c54b01); #else /* no filename */ - i += aimutil_put32(tx->data+i, 0x1df8cbae); - i += aimutil_put32(tx->data+i, 0x5523b839); - i += aimutil_put32(tx->data+i, 0xa0e10db3); - i += aimutil_put32(tx->data+i, 0xa46d3b39); + aimbs_put32(&fr->data, 0x1df8cbae); + aimbs_put32(&fr->data, 0x5523b839); + aimbs_put32(&fr->data, 0xa0e10db3); + aimbs_put32(&fr->data, 0xa46d3b39); #endif } else if ((offset == 0x00001000) && (len == 0x00000000)) { - i += aimutil_put32(tx->data+i, 0xd41d8cd9); - i += aimutil_put32(tx->data+i, 0x8f00b204); - i += aimutil_put32(tx->data+i, 0xe9800998); - i += aimutil_put32(tx->data+i, 0xecf8427e); + aimbs_put32(&fr->data, 0xd41d8cd9); + aimbs_put32(&fr->data, 0x8f00b204); + aimbs_put32(&fr->data, 0xe9800998); + aimbs_put32(&fr->data, 0xecf8427e); } else faimdprintf(sess, 0, "sendmemblock: WARNING: unknown hash request\n"); } - tx->commandlen = i; - tx->lock = 0; - aim_tx_enqueue(sess, tx); + aim_tx_enqueue(sess, fr); 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) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { if (snac->subtype == 0x0003) - return hostonline(sess, mod, rx, snac, data, datalen); + return hostonline(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0005) - return redirect(sess, mod, rx, snac, data, datalen); + return redirect(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0007) - return rateresp(sess, mod, rx, snac, data, datalen); + return rateresp(sess, mod, rx, snac, bs); else if (snac->subtype == 0x000a) - return ratechange(sess, mod, rx, snac, data, datalen); + return ratechange(sess, mod, rx, snac, bs); else if (snac->subtype == 0x000f) - return selfinfo(sess, mod, rx, snac, data, datalen); + return selfinfo(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0010) - return evilnotify(sess, mod, rx, snac, data, datalen); + return evilnotify(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0013) - return motd(sess, mod, rx, snac, data, datalen); + return motd(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0018) - return hostversions(sess, mod, rx, snac, data, datalen); + return hostversions(sess, mod, rx, snac, bs); else if (snac->subtype == 0x001f) - return memrequest(sess, mod, rx, snac, data, datalen); + return memrequest(sess, mod, rx, snac, bs); return 0; } -faim_internal int general_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod) { mod->family = 0x0001; diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/meta.c --- a/src/protocols/oscar/meta.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/meta.c Sun Sep 09 10:07:14 2001 +0000 @@ -8,41 +8,42 @@ faim_export char *aim_getbuilddate(void) { - return AIM_BUILDDATE; + return AIM_BUILDDATE; } faim_export char *aim_getbuildtime(void) { - return AIM_BUILDTIME; + return AIM_BUILDTIME; } faim_export int aim_getbuildstring(char *buf, int buflen) { - snprintf(buf, buflen, "%d.%d.%d-%s%s", - FAIM_VERSION_MAJOR, - FAIM_VERSION_MINOR, - FAIM_VERSION_MINORMINOR, - aim_getbuilddate(), - aim_getbuildtime()); + snprintf(buf, buflen, "%d.%d.%d-%s%s", + FAIM_VERSION_MAJOR, + FAIM_VERSION_MINOR, + FAIM_VERSION_MINORMINOR, + aim_getbuilddate(), + aim_getbuildtime()); - return 0; + return 0; } -faim_internal void faimdprintf(struct aim_session_t *sess, int dlevel, const char *format, ...) +faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...) { - if (!sess) { - fprintf(stderr, "faimdprintf: no session! boo! (%d, %s)\n", dlevel, format); - return; - } + if (!sess) { + fprintf(stderr, "faimdprintf: no session! boo! (%d, %s)\n", dlevel, format); + return; + } - if ((dlevel <= sess->debug) && sess->debugcb) { - va_list ap; + if ((dlevel <= sess->debug) && sess->debugcb) { + va_list ap; - va_start(ap, format); - sess->debugcb(sess, dlevel, format, ap); - va_end(ap); - } + va_start(ap, format); + sess->debugcb(sess, dlevel, format, ap); + va_end(ap); + } - return; + return; } + diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/misc.c --- a/src/protocols/oscar/misc.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/misc.c Sun Sep 09 10:07:14 2001 +0000 @@ -22,11 +22,9 @@ * time. * */ -faim_export unsigned long aim_bos_setidle(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_long idletime) +faim_export int aim_bos_setidle(aim_session_t *sess, aim_conn_t *conn, fu32_t idletime) { - return aim_genericreq_l(sess, conn, 0x0001, 0x0011, &idletime); + return aim_genericreq_l(sess, conn, 0x0001, 0x0011, &idletime); } @@ -56,70 +54,58 @@ * - Block the users below: Send an AIM_VISIBILITYCHANGE_DENYADD with * the list of users to be blocked * - * + * XXX ye gods. */ -faim_export unsigned long aim_bos_changevisibility(struct aim_session_t *sess, - struct aim_conn_t *conn, - int changetype, - char *denylist) +faim_export int aim_bos_changevisibility(aim_session_t *sess, aim_conn_t *conn, int changetype, const char *denylist) { - struct command_tx_struct *newpacket; - int packlen = 0; - u_short subtype; + aim_frame_t *fr; + int packlen = 0; + fu16_t subtype; + char *localcpy = NULL, *tmpptr = NULL; + int i; + int listcount; + aim_snacid_t snacid; - char *localcpy = NULL; - char *tmpptr = NULL; - int i,j; - int listcount; - - if (!denylist) - return 0; + if (!denylist) + return -EINVAL; - localcpy = (char *) malloc(strlen(denylist)+1); - memcpy(localcpy, denylist, strlen(denylist)+1); - - listcount = aimutil_itemcnt(localcpy, '&'); - packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, packlen))) - return -1; - - newpacket->lock = 1; + if (changetype == AIM_VISIBILITYCHANGE_PERMITADD) + subtype = 0x05; + else if (changetype == AIM_VISIBILITYCHANGE_PERMITREMOVE) + subtype = 0x06; + else if (changetype == AIM_VISIBILITYCHANGE_DENYADD) + subtype = 0x07; + else if (changetype == AIM_VISIBILITYCHANGE_DENYREMOVE) + subtype = 0x08; + else + return -EINVAL; - switch(changetype) - { - case AIM_VISIBILITYCHANGE_PERMITADD: subtype = 0x05; break; - case AIM_VISIBILITYCHANGE_PERMITREMOVE: subtype = 0x06; break; - case AIM_VISIBILITYCHANGE_DENYADD: subtype = 0x07; break; - case AIM_VISIBILITYCHANGE_DENYREMOVE: subtype = 0x08; break; - default: - free(newpacket->data); - free(newpacket); - return 0; - } + localcpy = strdup(denylist); + + listcount = aimutil_itemcnt(localcpy, '&'); + packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, packlen))) { + free(localcpy); + return -ENOMEM; + } + + snacid = aim_cachesnac(sess, 0x0009, subtype, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0009, subtype, 0x00, snacid); - /* We actually DO NOT send a SNAC ID with this one! */ - aim_putsnac(newpacket->data, 0x0009, subtype, 0x00, 0); - - j = 10; /* the next byte */ - - for (i=0; (i < (listcount - 1)) && (i < 99); i++) - { - tmpptr = aimutil_itemidx(localcpy, i, '&'); + for (i = 0; (i < (listcount - 1)) && (i < 99); i++) { + tmpptr = aimutil_itemidx(localcpy, i, '&'); + + aimbs_put8(&fr->data, strlen(tmpptr)); + aimbs_putraw(&fr->data, tmpptr, strlen(tmpptr)); - newpacket->data[j] = strlen(tmpptr); - memcpy(&(newpacket->data[j+1]), tmpptr, strlen(tmpptr)); - j += strlen(tmpptr)+1; - free(tmpptr); - } - free(localcpy); + free(tmpptr); + } + free(localcpy); - newpacket->lock = 0; + aim_tx_enqueue(sess, fr); - aim_tx_enqueue(sess, newpacket); - - return (sess->snac_nextid); /* dont increment */ - + return 0; } @@ -136,63 +122,50 @@ * XXX: I can't stress the TODO enough. * */ -faim_export unsigned long aim_bos_setbuddylist(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *buddy_list) +faim_export int aim_bos_setbuddylist(aim_session_t *sess, aim_conn_t *conn, const char *buddy_list) { - int i, j; - - struct command_tx_struct *newpacket; - - int len = 0; - - char *localcpy = NULL; - char *tmpptr = NULL; + aim_frame_t *fr; + aim_snacid_t snacid; + int i, len = 0; + char *localcpy = NULL; + char *tmpptr = NULL; - len = 10; /* 10B SNAC headers */ - - if (!buddy_list || !(localcpy = (char *) malloc(strlen(buddy_list)+1))) - return -1; - strncpy(localcpy, buddy_list, strlen(buddy_list)+1); + if (!buddy_list || !(localcpy = strdup(buddy_list))) + return -EINVAL; - i = 0; - tmpptr = strtok(localcpy, "&"); - while ((tmpptr != NULL) && (i < 150)) { - faimdprintf(sess, 2, "---adding %d: %s (%d)\n", i, tmpptr, strlen(tmpptr)); - len += 1+strlen(tmpptr); - i++; - tmpptr = strtok(NULL, "&"); - } - faimdprintf(sess, 2, "*** send buddy list len: %d (%x)\n", len, len); + i = 0; + tmpptr = strtok(localcpy, "&"); + while ((tmpptr != NULL) && (i < 150)) { + faimdprintf(sess, 2, "---adding %d: %s (%d)\n", i, tmpptr, strlen(tmpptr)); + len += 1+strlen(tmpptr); + i++; + tmpptr = strtok(NULL, "&"); + } - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, len))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+len))) + return -ENOMEM; - newpacket->lock = 1; - - aim_putsnac(newpacket->data, 0x0003, 0x0004, 0x0000, 0); - - j = 10; /* the next byte */ + snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid); - strncpy(localcpy, buddy_list, strlen(buddy_list)+1); - i = 0; - tmpptr = strtok(localcpy, "&"); - while ((tmpptr != NULL) & (i < 150)) { - faimdprintf(sess, 2, "---adding %d: %s (%d)\n", i, tmpptr, strlen(tmpptr)); - newpacket->data[j] = strlen(tmpptr); - memcpy(&(newpacket->data[j+1]), tmpptr, strlen(tmpptr)); - j += 1+strlen(tmpptr); - i++; - tmpptr = strtok(NULL, "&"); - } + strncpy(localcpy, buddy_list, strlen(buddy_list)+1); + i = 0; + tmpptr = strtok(localcpy, "&"); + while ((tmpptr != NULL) & (i < 150)) { + faimdprintf(sess, 2, "---adding %d: %s (%d)\n", i, tmpptr, strlen(tmpptr)); + + aimbs_put8(&fr->data, strlen(tmpptr)); + aimbs_putraw(&fr->data, tmpptr, strlen(tmpptr)); + i++; + tmpptr = strtok(NULL, "&"); + } - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - free(localcpy); + free(localcpy); - return (sess->snac_nextid); + return 0; } /* @@ -202,49 +175,38 @@ * * */ -faim_export unsigned long aim_bos_setprofile(struct aim_session_t *sess, - struct aim_conn_t *conn, - const char *profile, - const char *awaymsg, - unsigned short caps) +faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu16_t caps) { - struct command_tx_struct *newpacket; - int i = 0, tmp, caplen; - static const char defencoding[] = {"text/aolrtf; charset=\"us-ascii\""}; - - i = 10; - if (profile) - i += 4+strlen(defencoding)+4+strlen(profile); - if (awaymsg) - i += 4+strlen(defencoding)+4+strlen(awaymsg); - i += 4+512; /* for capabilities */ - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, i))) - return -1; - - i = aim_putsnac(newpacket->data, 0x0002, 0x004, 0x0000, sess->snac_nextid); + static const char defencoding[] = {"text/aolrtf; charset=\"us-ascii\""}; + aim_frame_t *fr; + aim_tlvlist_t *tl = NULL; + aim_snacid_t snacid; - if (profile) { - i += aim_puttlv_str(newpacket->data+i, 0x0001, strlen(defencoding), defencoding); - i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(profile), profile); - } + /* Build to packet first to get real length */ + if (profile) { + aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), defencoding); + aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), profile); + } + + if (awaymsg) { + aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), defencoding); + aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), awaymsg); + } - if (awaymsg) { - i += aim_puttlv_str(newpacket->data+i, 0x0003, strlen(defencoding), defencoding); - i += aim_puttlv_str(newpacket->data+i, 0x0004, strlen(awaymsg), awaymsg); - } + aim_addtlvtochain_caps(&tl, 0x0005, caps); - /* Capability information. */ - - tmp = (i += aimutil_put16(newpacket->data+i, 0x0005)); - i += aimutil_put16(newpacket->data+i, 0x0000); /* rewritten later */ - i += (caplen = aim_putcap(newpacket->data+i, 512, caps)); - aimutil_put16(newpacket->data+tmp, caplen); /* rewrite TLV size */ + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_sizetlvchain(&tl)))) + return -ENOMEM; - newpacket->commandlen = i; - aim_tx_enqueue(sess, newpacket); - - return (sess->snac_nextid++); + snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0002, 0x004, 0x0000, snacid); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); + + return 0; } /* @@ -253,85 +215,75 @@ * Send Client Ready. * */ -faim_export unsigned long aim_bos_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_clientready(aim_session_t *sess, aim_conn_t *conn) { - struct aim_tool_version tools[] = { - {0x0001, 0x0003, AIM_TOOL_WIN32, 0x0686}, - {0x0002, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x0003, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x0004, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x0006, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x0008, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x0009, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x000a, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x000b, 0x0001, AIM_TOOL_WIN32, 0x0001} - }; - int i,j; - struct command_tx_struct *newpacket; - int toolcount = sizeof(tools)/sizeof(struct aim_tool_version); + struct aim_tool_version tools[] = { + {0x0001, 0x0003, AIM_TOOL_WIN32, 0x0686}, + {0x0002, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x0003, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x0004, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x0006, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x0008, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x0009, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x000a, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x000b, 0x0001, AIM_TOOL_WIN32, 0x0001} + }; + int j; + aim_frame_t *fr; + aim_snacid_t snacid; + int toolcount = sizeof(tools)/sizeof(struct aim_tool_version); - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) + return -ENOMEM; - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid); - for (j = 0; j < toolcount; j++) { - i += aimutil_put16(newpacket->data+i, tools[j].group); - i += aimutil_put16(newpacket->data+i, tools[j].version); - i += aimutil_put16(newpacket->data+i, tools[j].tool); - i += aimutil_put16(newpacket->data+i, tools[j].toolversion); - } + for (j = 0; j < toolcount; j++) { + aimbs_put16(&fr->data, tools[j].group); + aimbs_put16(&fr->data, tools[j].version); + aimbs_put16(&fr->data, tools[j].tool); + aimbs_put16(&fr->data, tools[j].toolversion); + } - newpacket->commandlen = i; - newpacket->lock = 0; + aim_tx_enqueue(sess, fr); - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + return 0; } /* * Request Rate Information. * */ -faim_export unsigned long aim_bos_reqrate(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_reqrate(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0001, 0x0006); + return aim_genericreq_n(sess, conn, 0x0001, 0x0006); } /* * Rate Information Response Acknowledge. * */ -faim_export unsigned long aim_bos_ackrateresp(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_ackrateresp(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int packlen = 20, i=0; + aim_frame_t *fr; + aim_snacid_t snacid; - if(!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, packlen))) - return (sess->snac_nextid); - - newpacket->lock = 1; + if(!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+10))) + return -ENOMEM; - i = aim_putsnac(newpacket->data, 0x0001, 0x0008, 0x0000, 0); - i += aimutil_put16(newpacket->data+i, 0x0001); - i += aimutil_put16(newpacket->data+i, 0x0002); - i += aimutil_put16(newpacket->data+i, 0x0003); - i += aimutil_put16(newpacket->data+i, 0x0004); - i += aimutil_put16(newpacket->data+i, 0x0005); + snacid = aim_cachesnac(sess, 0x0001, 0x0008, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0001, 0x0008, 0x0000, snacid); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0002); + aimbs_put16(&fr->data, 0x0003); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0005); - newpacket->commandlen = i; - newpacket->lock = 0; + aim_tx_enqueue(sess, fr); - aim_tx_enqueue(sess, newpacket); - - return (sess->snac_nextid); + return 0; } /* @@ -343,81 +295,58 @@ * Bit 2: Allows other AIM users to see how long you've been a member. * */ -faim_export unsigned long aim_bos_setprivacyflags(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_long flags) +faim_export int aim_bos_setprivacyflags(aim_session_t *sess, aim_conn_t *conn, fu32_t flags) { - return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags); + return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags); } /* * aim_bos_reqpersonalinfo() * - * Requests the current user's information. Can't go generic on this one - * because aparently it uses SNAC flags. - * */ -faim_export unsigned long aim_bos_reqpersonalinfo(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_reqpersonalinfo(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0001, 0x000e); + return aim_genericreq_n(sess, conn, 0x0001, 0x000e); } -faim_export unsigned long aim_setversions(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_setversions(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + (4*16)))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0017, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); - - i += aimutil_put16(newpacket->data+i, 0x0001); - i += aimutil_put16(newpacket->data+i, 0x0003); - - i += aimutil_put16(newpacket->data+i, 0x0002); - i += aimutil_put16(newpacket->data+i, 0x0001); - - i += aimutil_put16(newpacket->data+i, 0x0003); - i += aimutil_put16(newpacket->data+i, 0x0001); - - i += aimutil_put16(newpacket->data+i, 0x0004); - i += aimutil_put16(newpacket->data+i, 0x0001); + aim_frame_t *fr; + aim_snacid_t snacid; + static const struct version { + fu16_t group; + fu16_t version; + } versions[] = { + {0x0001, 0x0003}, + {0x0002, 0x0001}, + {0x0003, 0x0001}, + {0x0004, 0x0001}, + {0x0006, 0x0001}, + {0x0008, 0x0001}, + {0x0009, 0x0001}, + {0x000a, 0x0001}, + {0x000b, 0x0002}, + {0x000c, 0x0001}, + {0x0013, 0x0001}, + {0x0015, 0x0001}, + }; + int numversions = sizeof(versions) / sizeof(struct version); + int i; - i += aimutil_put16(newpacket->data+i, 0x0006); - i += aimutil_put16(newpacket->data+i, 0x0001); - - i += aimutil_put16(newpacket->data+i, 0x0008); - i += aimutil_put16(newpacket->data+i, 0x0001); + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + (4*numversions)))) + return -ENOMEM; - i += aimutil_put16(newpacket->data+i, 0x0009); - i += aimutil_put16(newpacket->data+i, 0x0001); - - i += aimutil_put16(newpacket->data+i, 0x000a); - i += aimutil_put16(newpacket->data+i, 0x0001); - - i += aimutil_put16(newpacket->data+i, 0x000b); - i += aimutil_put16(newpacket->data+i, 0x0002); + snacid = aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); - i += aimutil_put16(newpacket->data+i, 0x000c); - i += aimutil_put16(newpacket->data+i, 0x0001); - - i += aimutil_put16(newpacket->data+i, 0x0013); - i += aimutil_put16(newpacket->data+i, 0x0001); + aim_putsnac(&fr->data, 0x0001, 0x0017, 0x0000, snacid); + for (i = 0; i < numversions; i++) { + aimbs_put16(&fr->data, versions[i].group); + aimbs_put16(&fr->data, versions[i].version); + } - i += aimutil_put16(newpacket->data+i, 0x0015); - i += aimutil_put16(newpacket->data+i, 0x0001); + aim_tx_enqueue(sess, fr); - newpacket->commandlen = i; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + return 0; } @@ -427,11 +356,9 @@ * Service request. * */ -faim_export unsigned long aim_bos_reqservice(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short serviceid) +faim_export int aim_bos_reqservice(aim_session_t *sess, aim_conn_t *conn, fu16_t serviceid) { - return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid); + return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid); } /* @@ -441,10 +368,9 @@ * the connection alive. Its not real necessary. * */ -faim_export unsigned long aim_bos_nop(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_nop(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0001, 0x0016); + return aim_genericreq_n(sess, conn, 0x0001, 0x0016); } /* @@ -453,21 +379,16 @@ * No-op. WinAIM 4.x sends these _every minute_ to keep * the connection alive. */ -faim_export unsigned long aim_flap_nop(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0005, 0))) - return sess->snac_nextid; + aim_frame_t *fr; - newpacket->lock = 1; - newpacket->commandlen = 0; - newpacket->lock = 0; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x05, 0))) + return -ENOMEM; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return (sess->snac_nextid); + return 0; } /* @@ -476,10 +397,9 @@ * Request BOS rights. * */ -faim_export unsigned long aim_bos_reqrights(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_reqrights(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0009, 0x0002); + return aim_genericreq_n(sess, conn, 0x0009, 0x0002); } /* @@ -488,10 +408,9 @@ * Request Buddy List rights. * */ -faim_export unsigned long aim_bos_reqbuddyrights(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_reqbuddyrights(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0003, 0x0002); + return aim_genericreq_n(sess, conn, 0x0003, 0x0002); } /* @@ -503,35 +422,27 @@ * returns -1 on error (couldn't alloc packet), 0 on success. * */ -faim_export int aim_send_warning(struct aim_session_t *sess, struct aim_conn_t *conn, const char *destsn, unsigned long flags) +faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags) { - struct command_tx_struct *newpacket; - int curbyte; - unsigned short outflags = 0x0000; + aim_frame_t *fr; + aim_snacid_t snacid; + fu16_t outflags = 0x0000; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, - strlen(destsn)+13))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(destsn)+13))) + return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1); - curbyte = 0; - curbyte += aim_putsnac(newpacket->data+curbyte, - 0x0004, 0x0008, 0x0000, sess->snac_nextid); + aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid); if (flags & AIM_WARN_ANON) outflags |= 0x0001; - curbyte += aimutil_put16(newpacket->data+curbyte, outflags); - curbyte += aimutil_put8(newpacket->data+curbyte, strlen(destsn)); - curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn)); + aimbs_put16(&fr->data, outflags); + aimbs_put8(&fr->data, strlen(destsn)); + aimbs_putraw(&fr->data, destsn, strlen(destsn)); - newpacket->commandlen = curbyte; - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); - - aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1); + aim_tx_enqueue(sess, fr); return 0; } @@ -541,10 +452,9 @@ * * For aimdebugd. If you don't know what it is, you don't want to. */ -faim_export unsigned long aim_debugconn_sendconnect(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_debugconn_sendconnect(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT); + return aim_genericreq_n(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT); } /* @@ -559,102 +469,81 @@ * back to the single. I don't see any advantage to doing it either way. * */ -faim_internal unsigned long aim_genericreq_n(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short family, u_short subtype) +faim_internal int aim_genericreq_n(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t subtype) { - struct command_tx_struct *newpacket; + aim_frame_t *fr; + aim_snacid_t snacid = 0x00000000; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10))) - return 0; - - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10))) + return -ENOMEM; - aim_putsnac(newpacket->data, family, subtype, 0x0000, 0x00000000); + aim_putsnac(&fr->data, family, subtype, 0x0000, snacid); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid; + return 0; } -faim_internal unsigned long aim_genericreq_n_snacid(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned short family, - unsigned short subtype) +faim_internal int aim_genericreq_n_snacid(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t subtype) { - struct command_tx_struct *newpacket; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10))) - return 0; - - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10))) + return -ENOMEM; - aim_putsnac(newpacket->data, family, subtype, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0); + snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0); + aim_putsnac(&fr->data, family, subtype, 0x0000, snacid); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid++; + return 0; } /* * * */ -faim_internal unsigned long aim_genericreq_l(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short family, u_short subtype, - u_long *longdata) +faim_internal int aim_genericreq_l(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t subtype, fu32_t *longdata) { - struct command_tx_struct *newpacket; - u_long newlong; + aim_frame_t *fr; + aim_snacid_t snacid; - /* If we don't have data, there's no reason to use this function */ - if (!longdata) - return aim_genericreq_n(sess, conn, family, subtype); + if (!longdata) + return aim_genericreq_n(sess, conn, family, subtype); - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+sizeof(u_long)))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4))) + return -ENOMEM; - newpacket->lock = 1; - - aim_putsnac(newpacket->data, family, subtype, 0x0000, 0x00000000); + snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0); - /* copy in data */ - newlong = htonl(*longdata); - memcpy(&(newpacket->data[10]), &newlong, sizeof(u_long)); + aim_putsnac(&fr->data, family, subtype, 0x0000, snacid); + aimbs_put32(&fr->data, *longdata); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid; + return 0; } -faim_internal unsigned long aim_genericreq_s(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short family, u_short subtype, - u_short *shortdata) +faim_internal int aim_genericreq_s(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t subtype, fu16_t *shortdata) { - struct command_tx_struct *newpacket; - u_short newshort; + aim_frame_t *fr; + aim_snacid_t snacid; - /* If we don't have data, there's no reason to use this function */ - if (!shortdata) - return aim_genericreq_n(sess, conn, family, subtype); + if (!shortdata) + return aim_genericreq_n(sess, conn, family, subtype); - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+sizeof(u_short)))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2))) + return -ENOMEM; - newpacket->lock = 1; - - aim_putsnac(newpacket->data, family, subtype, 0x0000, 0x00000000); + snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0); - /* copy in data */ - newshort = htons(*shortdata); - memcpy(&(newpacket->data[10]), &newshort, sizeof(u_short)); + aim_putsnac(&fr->data, family, subtype, 0x0000, snacid); + aimbs_put16(&fr->data, *shortdata); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid; + return 0; } /* @@ -663,202 +552,169 @@ * Request Location services rights. * */ -faim_export unsigned long aim_bos_reqlocaterights(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_reqlocaterights(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0002, 0x0002); + return aim_genericreq_n(sess, conn, 0x0002, 0x0002); } /* * Set directory profile data (not the same as aim_bos_setprofile!) + * + * privacy: 1 to allow searching, 0 to disallow. */ -faim_export unsigned long aim_setdirectoryinfo(struct aim_session_t *sess, struct aim_conn_t *conn, char *first, char *middle, char *last, char *maiden, char *nickname, char *street, char *city, char *state, char *zip, int country, unsigned short privacy) +faim_export int aim_setdirectoryinfo(aim_session_t *sess, aim_conn_t *conn, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, fu16_t privacy) { - struct command_tx_struct *newpacket; - int packlen = 0, i = 0; - - packlen += 2+2+2; - - if(first) /* TLV 0001 */ - packlen += (strlen(first) + 4); - if(middle) - packlen += (strlen(middle) + 4); - if(last) - packlen += (strlen(last) + 4); - if(maiden) - packlen += (strlen(maiden) + 4); - if(nickname) - packlen += (strlen(nickname) + 4); - if(street) - packlen += (strlen(street) + 4); - if(state) - packlen += (strlen(state) + 4); - if(city) - packlen += (strlen(city) + 4); - if(zip) - packlen += (strlen(zip) + 4); - - if(!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, packlen+10))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0002, 0x0009, 0x0000, 0); - - /* 000a/0002: privacy: 1 to allow search/disp, 0 to disallow */ - i += aim_puttlv_16(newpacket->data+i, 0x000a, privacy); + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; - if (first) - i += aim_puttlv_str(newpacket->data+i, 0x0001, strlen(first), first); - if (middle) - i += aim_puttlv_str(newpacket->data+i, 0x0003, strlen(middle), middle); - if (last) - i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(last), last); - if (maiden) - i += aim_puttlv_str(newpacket->data+i, 0x0004, strlen(maiden), maiden); - if (nickname) - i += aim_puttlv_str(newpacket->data+i, 0x000c, strlen(nickname), nickname); - if (street) - i += aim_puttlv_str(newpacket->data+i, 0x0021, strlen(street), street); - if (city) - i += aim_puttlv_str(newpacket->data+i, 0x0008, strlen(city), city); - if (state) - i += aim_puttlv_str(newpacket->data+i, 0x0007, strlen(state), state); - if (zip) - i += aim_puttlv_str(newpacket->data+i, 0x000d, strlen(zip), zip); + aim_addtlvtochain16(&tl, 0x000a, privacy); + + if (first) + aim_addtlvtochain_raw(&tl, 0x0001, strlen(first), first); + if (last) + aim_addtlvtochain_raw(&tl, 0x0002, strlen(last), last); + if (middle) + aim_addtlvtochain_raw(&tl, 0x0003, strlen(middle), middle); + if (maiden) + aim_addtlvtochain_raw(&tl, 0x0004, strlen(maiden), maiden); + + if (state) + aim_addtlvtochain_raw(&tl, 0x0007, strlen(state), state); + if (city) + aim_addtlvtochain_raw(&tl, 0x0008, strlen(city), city); - newpacket->commandlen = i; - newpacket->lock = 0; + if (nickname) + aim_addtlvtochain_raw(&tl, 0x000c, strlen(nickname), nickname); + if (zip) + aim_addtlvtochain_raw(&tl, 0x000d, strlen(zip), zip); + + if (street) + aim_addtlvtochain_raw(&tl, 0x0021, strlen(street), street); - aim_tx_enqueue(sess, newpacket); - - return(sess->snac_nextid); + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl)))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0002, 0x0009, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0002, 0x0009, 0x0000, snacid); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); + + return 0; } -faim_export unsigned long aim_setuserinterests(struct aim_session_t *sess, struct aim_conn_t *conn, char *interest1, char *interest2, char *interest3, char *interest4, char *interest5, unsigned short privacy) +/* XXX pass these in better */ +faim_export int aim_setuserinterests(aim_session_t *sess, aim_conn_t *conn, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, fu16_t privacy) { - struct command_tx_struct *newpacket; - int packlen = 0, i = 0; - - packlen += 2+2+2; + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; - if(interest1) - packlen += (strlen(interest1) + 4); - if(interest2) - packlen += (strlen(interest2) + 4); - if(interest3) - packlen += (strlen(interest3) + 4); - if(interest4) - packlen += (strlen(interest4) + 4); - if(interest5) - packlen += (strlen(interest5) + 4) ; - - - if(!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, packlen+10))) - return -1; + /* ?? privacy ?? */ + aim_addtlvtochain16(&tl, 0x000a, privacy); - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0002, 0x000f, 0x0000, 0); - - /* 000a/0002: 0000 ?? ?privacy? */ - i += aim_puttlv_16(newpacket->data+i, 0x000a, privacy); + if (interest1) + aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest1), interest1); + if (interest2) + aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest2), interest2); + if (interest3) + aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest3), interest3); + if (interest4) + aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest4), interest4); + if (interest5) + aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest5), interest5); - if(interest1) - i += aim_puttlv_str(newpacket->data+i, 0x000b, strlen(interest1), interest1); - if(interest2) - i += aim_puttlv_str(newpacket->data+i, 0x000b, strlen(interest2), interest2); - if(interest3) - i += aim_puttlv_str(newpacket->data+i, 0x000b, strlen(interest3), interest3); - if(interest4) - i += aim_puttlv_str(newpacket->data+i, 0x000b, strlen(interest4), interest4); - if(interest5) - i += aim_puttlv_str(newpacket->data+i, 0x000b, strlen(interest1), interest5); + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl)))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0002, 0x000f, 0x0000, NULL, 0); - newpacket->commandlen = i; - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); - - return(sess->snac_nextid); + aim_putsnac(&fr->data, 0x0002, 0x000f, 0x0000, 0); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); + + return 0; } -faim_export unsigned long aim_icq_setstatus(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned long status) +faim_export int aim_icq_setstatus(aim_session_t *sess, aim_conn_t *conn, fu32_t status) { - struct command_tx_struct *newpacket; - int i; - unsigned long data; - - data = 0x00030000 | status; /* yay for error checking ;^) */ + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + fu32_t data; + + data = 0x00030000 | status; /* yay for error checking ;^) */ - if(!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + 4))) - return -1; - - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4))) + return -ENOMEM; - i = aim_putsnac(newpacket->data, 0x0001, 0x001e, 0x0000, 0x0000001e); - i += aim_puttlv_32(newpacket->data+i, 0x0006, data); + snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid); + + aim_addtlvtochain32(&tl, 0x0006, data); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); - newpacket->commandlen = i; - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); - - return(sess->snac_nextid); + return 0; } /* * 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) +static int generror(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - int ret = 0; - int error = 0; - aim_rxcallback_t userfunc; - struct aim_snac_t *snac2; + int ret = 0; + int error = 0; + aim_rxcallback_t userfunc; + aim_snac_t *snac2; - snac2 = aim_remsnac(sess, snac->id); + snac2 = aim_remsnac(sess, snac->id); - if (datalen) - error = aimutil_get16(data); + if (aim_bstream_empty(bs)) + error = aimbs_get16(bs); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, error, snac2?snac2->data:NULL); + 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); + if (snac2) + free(snac2->data); + free(snac2); - return ret; + 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) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0001) - return generror(sess, mod, rx, snac, data, datalen); - else if ((snac->family == 0xffff) && (snac->subtype == 0xffff)) { - aim_rxcallback_t userfunc; + if (snac->subtype == 0x0001) + return generror(sess, mod, rx, snac, bs); + else if ((snac->family == 0xffff) && (snac->subtype == 0xffff)) { + aim_rxcallback_t userfunc; - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - return userfunc(sess, rx); - } + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx); + } - return 0; + return 0; } -faim_internal int misc_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int misc_modfirst(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; + mod->family = 0xffff; + mod->version = 0x0000; + mod->flags = AIM_MODFLAG_MULTIFAMILY; + strncpy(mod->name, "misc", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/msgcookie.c --- a/src/protocols/oscar/msgcookie.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/msgcookie.c Sun Sep 09 10:07:14 2001 +0000 @@ -27,29 +27,27 @@ * in may be free'd, so don't count on its value after calling this! * */ -faim_internal int aim_cachecookie(struct aim_session_t *sess, - struct aim_msgcookie_t *cookie) +faim_internal int aim_cachecookie(aim_session_t *sess, aim_msgcookie_t *cookie) { - struct aim_msgcookie_t *newcook; + aim_msgcookie_t *newcook; - if (!sess || !cookie) - return -1; + if (!sess || !cookie) + return -EINVAL; - if( (newcook = aim_checkcookie(sess, cookie->cookie, cookie->type)) ) { - if(newcook != cookie) { - aim_cookie_free(sess, newcook); - } else { - newcook->addtime = time(NULL); - return 1; - } - } + newcook = aim_checkcookie(sess, cookie->cookie, cookie->type); + + if (newcook == cookie) { + newcook->addtime = time(NULL); + return 1; + } else if (newcook) + aim_cookie_free(sess, newcook); - cookie->addtime = time(NULL); + cookie->addtime = time(NULL); - cookie->next = sess->msgcookies; - sess->msgcookies = cookie; + cookie->next = sess->msgcookies; + sess->msgcookies = cookie; - return 0; + return 0; } /** @@ -62,23 +60,23 @@ * * if found, returns the struct; if none found (or on error), returns NULL: */ -faim_internal struct aim_msgcookie_t *aim_uncachecookie(struct aim_session_t *sess, unsigned char *cookie, int type) +faim_internal aim_msgcookie_t *aim_uncachecookie(aim_session_t *sess, fu8_t *cookie, int type) { - struct aim_msgcookie_t *cur, **prev; + aim_msgcookie_t *cur, **prev; - if (!cookie || !sess->msgcookies) - return NULL; + if (!cookie || !sess->msgcookies) + return NULL; - for (prev = &sess->msgcookies; (cur = *prev); ) { - if ((cur->type == type) && - (memcmp(cur->cookie, cookie, 8) == 0)) { - *prev = cur->next; - return cur; - } - prev = &cur->next; - } + for (prev = &sess->msgcookies; (cur = *prev); ) { + if ((cur->type == type) && + (memcmp(cur->cookie, cookie, 8) == 0)) { + *prev = cur->next; + return cur; + } + prev = &cur->next; + } - return NULL; + return NULL; } /** @@ -91,21 +89,21 @@ * success. * */ -faim_internal struct aim_msgcookie_t *aim_mkcookie(unsigned char *c, int type, void *data) +faim_internal aim_msgcookie_t *aim_mkcookie(fu8_t *c, int type, void *data) { - struct aim_msgcookie_t *cookie; + aim_msgcookie_t *cookie; - if (!c) - return NULL; + if (!c) + return NULL; - if (!(cookie = calloc(1, sizeof(struct aim_msgcookie_t)))) - return NULL; - - cookie->data = data; - cookie->type = type; - memcpy(cookie->cookie, c, 8); - - return cookie; + if (!(cookie = calloc(1, sizeof(aim_msgcookie_t)))) + return NULL; + + cookie->data = data; + cookie->type = type; + memcpy(cookie->cookie, c, 8); + + return cookie; } /** @@ -119,28 +117,31 @@ * */ -faim_internal struct aim_msgcookie_t *aim_checkcookie(struct aim_session_t *sess, - const unsigned char *cookie, - const int type) +faim_internal aim_msgcookie_t *aim_checkcookie(aim_session_t *sess, const fu8_t *cookie, int type) { - struct aim_msgcookie_t *cur; + aim_msgcookie_t *cur; - for (cur = sess->msgcookies; cur; cur = cur->next) { - if ((cur->type == type) && - (memcmp(cur->cookie, cookie, 8) == 0)) - return cur; - } + for (cur = sess->msgcookies; cur; cur = cur->next) { + if ((cur->type == type) && + (memcmp(cur->cookie, cookie, 8) == 0)) + return cur; + } - return NULL; + return NULL; } #if 0 /* debugging feature */ -faim_internal int aim_dumpcookie(struct aim_msgcookie_t *cookie) +faim_internal int aim_dumpcookie(aim_msgcookie_t *cookie) { - if(!cookie) - return -1; - printf("\tCookie at %p: %d/%s with %p, next %p\n", cookie, cookie->type, cookie->cookie, cookie->data, cookie->next); - return 0; + + if (!cookie) + return -EINVAL; + + printf("\tCookie at %p: %d/%s with %p, next %p\n", + cookie, cookie->type, cookie->cookie, + cookie->data, cookie->next); + + return 0; } #endif @@ -157,56 +158,39 @@ * returns -1 on error, 0 on success. * */ - -faim_internal int aim_cookie_free(struct aim_session_t *sess, - struct aim_msgcookie_t *cookie) +faim_internal int aim_cookie_free(aim_session_t *sess, aim_msgcookie_t *cookie) { - struct aim_msgcookie_t *cur, **prev; + aim_msgcookie_t *cur, **prev; - if (!sess || !cookie) - return -1; - - if(!cookie) - return 0; + if (!sess || !cookie) + return -EINVAL; - for (prev = &sess->msgcookies; (cur = *prev); ) { - if (cur == cookie) { - *prev = cur->next; - } else - prev = &cur->next; - } + for (prev = &sess->msgcookies; (cur = *prev); ) { + if (cur == cookie) + *prev = cur->next; + else + prev = &cur->next; + } - if(cookie->data) - free(cookie->data); + free(cookie->data); + free(cookie); - free(cookie); - - return 0; + return 0; } -faim_internal int aim_msgcookie_gettype(int reqclass) { - /* XXX: hokey-assed. needs fixed. */ - switch(reqclass) { - case AIM_CAPS_BUDDYICON: - return AIM_COOKIETYPE_OFTICON; - break; - case AIM_CAPS_VOICE: - return AIM_COOKIETYPE_OFTVOICE; - break; - case AIM_CAPS_IMIMAGE: - return AIM_COOKIETYPE_OFTIMAGE; - break; - case AIM_CAPS_CHAT: - return AIM_COOKIETYPE_CHAT; - break; - case AIM_CAPS_GETFILE: - return AIM_COOKIETYPE_OFTGET; - break; - case AIM_CAPS_SENDFILE: - return AIM_COOKIETYPE_OFTSEND; - break; - default: - return AIM_COOKIETYPE_UNKNOWN; - break; - } +/* XXX I hate switch */ +faim_internal int aim_msgcookie_gettype(int reqclass) +{ + /* XXX: hokey-assed. needs fixed. */ + switch(reqclass) { + case AIM_CAPS_BUDDYICON: return AIM_COOKIETYPE_OFTICON; + case AIM_CAPS_VOICE: return AIM_COOKIETYPE_OFTVOICE; + case AIM_CAPS_IMIMAGE: return AIM_COOKIETYPE_OFTIMAGE; + case AIM_CAPS_CHAT: return AIM_COOKIETYPE_CHAT; + case AIM_CAPS_GETFILE: return AIM_COOKIETYPE_OFTGET; + case AIM_CAPS_SENDFILE: return AIM_COOKIETYPE_OFTSEND; + default: return AIM_COOKIETYPE_UNKNOWN; + } } + + diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/oscar.c --- a/src/protocols/oscar/oscar.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/oscar.c Sun Sep 09 10:07:14 2001 +0000 @@ -60,8 +60,8 @@ AIM_CAPS_IMIMAGE; struct oscar_data { - struct aim_session_t *sess; - struct aim_conn_t *conn; + aim_session_t *sess; + aim_conn_t *conn; guint cnpa; guint paspa; @@ -85,9 +85,9 @@ struct chat_connection { char *name; char *show; /* AOL did something funny to us */ - int exchange; + fu16_t exchange; /* XXX should have instance here too */ int fd; /* this is redundant since we have the conn below */ - struct aim_conn_t *conn; + aim_conn_t *conn; int inpa; int id; struct gaim_connection *gc; /* i hate this. */ @@ -100,13 +100,14 @@ struct gaim_connection *gc; char name[80]; int watcher; - struct aim_conn_t *conn; + aim_conn_t *conn; }; struct ask_direct { struct gaim_connection *gc; char *sn; - struct aim_directim_priv *priv; + char ip[64]; + fu8_t cookie[8]; }; struct icon_req { @@ -117,7 +118,7 @@ gboolean request; }; -static struct direct_im *find_direct_im(struct oscar_data *od, char *who) { +static struct direct_im *find_direct_im(struct oscar_data *od, const char *who) { GSList *d = od->direct_ims; char *n = g_strdup(normalize(who)); struct direct_im *m = NULL; @@ -176,7 +177,7 @@ } static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc, - struct aim_conn_t *conn) { + aim_conn_t *conn) { GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats; struct chat_connection *c = NULL; @@ -191,42 +192,41 @@ return c; } -static int gaim_parse_auth_resp (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_login (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_server_ready (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_handle_redirect (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_info_change (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_account_confirm (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_oncoming (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_offgoing (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_misses (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_user_info (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_motd (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_chatnav_info (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_chat_join (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_chat_leave (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_chat_info_update (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_chat_incoming_msg(struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_msgack (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_ratechange (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_evilnotify (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_searcherror(struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_searchreply(struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_bosrights (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_rateresp (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_reportinterval (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_msgerr (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_buddyrights(struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_locerr (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_icbm_param_info (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_parse_genericerr (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_memrequest (struct aim_session_t *, struct command_rx_struct *, ...); - -static int gaim_directim_initiate (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_directim_incoming (struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_directim_disconnect(struct aim_session_t *, struct command_rx_struct *, ...); -static int gaim_directim_typing (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_auth_resp (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_login (aim_session_t *, aim_frame_t *, ...); +static int gaim_handle_redirect (aim_session_t *, aim_frame_t *, ...); +static int gaim_info_change (aim_session_t *, aim_frame_t *, ...); +static int gaim_account_confirm (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_oncoming (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_offgoing (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_incoming_im(aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_misses (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_user_info (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_motd (aim_session_t *, aim_frame_t *, ...); +static int gaim_chatnav_info (aim_session_t *, aim_frame_t *, ...); +static int gaim_chat_join (aim_session_t *, aim_frame_t *, ...); +static int gaim_chat_leave (aim_session_t *, aim_frame_t *, ...); +static int gaim_chat_info_update (aim_session_t *, aim_frame_t *, ...); +static int gaim_chat_incoming_msg(aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_msgack (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_ratechange (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_evilnotify (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_searcherror(aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_searchreply(aim_session_t *, aim_frame_t *, ...); +static int gaim_bosrights (aim_session_t *, aim_frame_t *, ...); +static int rateresp_bos (aim_session_t *, aim_frame_t *, ...); +static int rateresp_auth (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_msgerr (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_buddyrights(aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_locerr (aim_session_t *, aim_frame_t *, ...); +static int gaim_icbm_param_info (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_genericerr (aim_session_t *, aim_frame_t *, ...); +static int gaim_memrequest (aim_session_t *, aim_frame_t*, ...); +static int server_ready_bos (aim_session_t *, aim_frame_t*, ...); + +static int gaim_directim_initiate (aim_session_t *, aim_frame_t *, ...); +static int gaim_directim_incoming (aim_session_t *, aim_frame_t *, ...); +static int gaim_directim_typing (aim_session_t *, aim_frame_t *, ...); static char *msgerrreason[] = { "Invalid error", @@ -257,10 +257,36 @@ }; static int msgerrreasonlen = 25; +static void gaim_directim_disconnect(aim_session_t *sess, aim_conn_t *conn) { + struct gaim_connection *gc = sess->aux_data; + struct oscar_data *od = (struct oscar_data *)gc->proto_data; + struct conversation *cnv; + struct direct_im *dim; + char *sn; + char buf[256]; + + sn = g_strdup(aim_directim_getsn(conn)); + + debug_printf("%s disconnected Direct IM.\n", sn); + + dim = find_direct_im(od, sn); + od->direct_ims = g_slist_remove(od->direct_ims, dim); + gaim_input_remove(dim->watcher); + + g_snprintf(buf, sizeof buf, _("Direct IM with %s closed"), sn); + if ((cnv = find_conversation(sn))) + write_to_conv(cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL)); + + g_free(dim); /* I guess? I don't see it anywhere else... -- mid */ + g_free(sn); + + return; +} + static void oscar_callback(gpointer data, gint source, GaimInputCondition condition) { - struct aim_conn_t *conn = (struct aim_conn_t *)data; - struct aim_session_t *sess = aim_conn_getsess(conn); + aim_conn_t *conn = (aim_conn_t *)data; + aim_session_t *sess = aim_conn_getsess(conn); struct gaim_connection *gc = sess ? sess->aux_data : NULL; struct oscar_data *odata; @@ -284,6 +310,7 @@ debug_printf("got information on rendezvous\n"); if (aim_handlerendconnect(odata->sess, conn) < 0) { debug_printf(_("connection error (rend)\n")); + aim_conn_kill(odata->sess, &conn); } } else { if (aim_get_command(odata->sess, conn) >= 0) { @@ -328,8 +355,12 @@ debug_printf("removing authconn input watcher\n"); aim_conn_kill(odata->sess, &conn); } else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) { - debug_printf("No handler for rendezvous disconnect (%d).\n", - source); + if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) + gaim_directim_disconnect(odata->sess, conn); + else { + debug_printf("No handler for rendezvous disconnect (%d).\n", + source); + } aim_conn_kill(odata->sess, &conn); } else { debug_printf("holy crap! generic connection error! %d\n", @@ -341,7 +372,7 @@ } } -static void oscar_debug(struct aim_session_t *sess, int level, const char *format, va_list va) { +static void oscar_debug(aim_session_t *sess, int level, const char *format, va_list va) { char *s = g_strdup_vprintf(format, va); char buf[256]; char *t; @@ -360,8 +391,8 @@ { struct gaim_connection *gc = data; struct oscar_data *odata; - struct aim_session_t *sess; - struct aim_conn_t *conn; + aim_session_t *sess; + aim_conn_t *conn; if (!g_slist_find(connections, gc)) { close(source); @@ -385,8 +416,8 @@ } static void oscar_login(struct aim_user *user) { - struct aim_session_t *sess; - struct aim_conn_t *conn; + aim_session_t *sess; + aim_conn_t *conn; char buf[256]; struct gaim_connection *gc = new_gaim_conn(user); struct oscar_data *odata = gc->proto_data = g_new0(struct oscar_data, 1); @@ -394,7 +425,7 @@ debug_printf(_("Logging in %s\n"), user->username); - sess = g_new0(struct aim_session_t, 1); + sess = g_new0(aim_session_t, 1); aim_session_init(sess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 0); aim_setdebuggingcb(sess, oscar_debug); @@ -476,8 +507,8 @@ static void oscar_bos_connect(gpointer data, gint source, GaimInputCondition cond) { struct gaim_connection *gc = data; struct oscar_data *odata; - struct aim_session_t *sess; - struct aim_conn_t *bosconn; + aim_session_t *sess; + aim_conn_t *bosconn; if (!g_slist_find(connections, gc)) { close(source); @@ -500,12 +531,11 @@ set_login_progress(gc, 4, _("Connection established, cookie sent")); } -int gaim_parse_auth_resp(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - struct aim_conn_t *bosconn = NULL; + aim_conn_t *bosconn = NULL; char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL; - unsigned char *cookie = NULL; + fu8_t *cookie = NULL; int errorcode = 0, regstatus = 0; int latestbuild = 0, latestbetabuild = 0; char *latestrelease = NULL, *latestbeta = NULL; @@ -520,7 +550,7 @@ port = user->proto_opt[USEROPT_AUTHPORT][0] ? atoi(user->proto_opt[USEROPT_AUTHPORT]) : FAIM_LOGIN_PORT, - va_start(ap, command); + va_start(ap, fr); sn = va_arg(ap, char *); errorcode = va_arg(ap, int); errurl = va_arg(ap, char *); @@ -589,7 +619,7 @@ debug_printf("Latest WinAIM released version %s, build %d, at %s (%s)\n", latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo); debug_printf("Closing auth connection...\n"); - aim_conn_kill(sess, &command->conn); + aim_conn_kill(sess, &fr->conn); bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, NULL); if (bosconn == NULL) { @@ -599,12 +629,11 @@ } aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, gaim_bosrights, 0); - aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, gaim_rateresp, 0); /* rate info */ + aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, rateresp_bos, 0); /* rate info */ aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, gaim_server_ready, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, server_ready_bos, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, gaim_handle_redirect, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, gaim_reportinterval, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, gaim_parse_buddyrights, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, gaim_parse_oncoming, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, gaim_parse_offgoing, 0); @@ -652,7 +681,7 @@ unsigned long len; char *modname; int fd; - struct aim_conn_t *conn; + aim_conn_t *conn; unsigned int inpa; }; @@ -719,24 +748,23 @@ /* size of icbmui.ocm, the largest module in AIM 3.5 */ #define AIM_MAX_FILE_SIZE 98304 -int gaim_memrequest(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +int gaim_memrequest(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; struct pieceofcrap *pos; - unsigned long offset, len; + fu32_t offset, len; char *modname; int fd; - va_start(ap, command); - offset = va_arg(ap, unsigned long); - len = va_arg(ap, unsigned long); + va_start(ap, fr); + offset = (fu32_t)va_arg(ap, unsigned long); + len = (fu32_t)va_arg(ap, unsigned long); modname = va_arg(ap, char *); va_end(ap); debug_printf("offset: %d, len: %d, file: %s\n", offset, len, modname ? modname : "aim.exe"); if (len == 0) { debug_printf("len is 0, hashing NULL\n"); - aim_sendmemblock(sess, command->conn, offset, len, NULL, + aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST); return 1; } @@ -769,7 +797,7 @@ pos = g_new0(struct pieceofcrap, 1); pos->gc = sess->aux_data; - pos->conn = command->conn; + pos->conn = fr->conn; pos->offset = offset; pos->len = len; @@ -788,8 +816,7 @@ return 1; } -int gaim_parse_login(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_parse_login(aim_session_t *sess, aim_frame_t *fr, ...) { #if 0 struct client_info_s info = {"gaim", 4, 1, 2010, "us", "en", 0x0004, 0x0000, 0x04b}; #else @@ -799,84 +826,87 @@ va_list ap; struct gaim_connection *gc = sess->aux_data; - va_start(ap, command); + va_start(ap, fr); key = va_arg(ap, char *); va_end(ap); - aim_send_login(sess, command->conn, gc->username, gc->password, &info, key); + aim_send_login(sess, fr->conn, gc->username, gc->password, &info, key); + return 1; } -int gaim_server_ready(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { - static int id = 1; +static int server_ready_auth(aim_session_t *sess, aim_frame_t *fr, ...) { struct gaim_connection *gc = sess->aux_data; struct oscar_data *od = gc->proto_data; - struct chat_connection *chatcon; - switch (command->conn->type) { - case AIM_CONN_TYPE_AUTH: - aim_auth_setversions(sess, command->conn); - aim_bos_reqrate(sess, command->conn); - debug_printf("done with AUTH ServerReady\n"); - if (od->chpass) { - debug_printf("changing password\n"); - aim_auth_changepasswd(sess, command->conn, od->newp, od->oldp); - g_free(od->oldp); - g_free(od->newp); - od->chpass = FALSE; - } - if (od->conf) { - debug_printf("confirming account\n"); - aim_auth_reqconfirm(sess, command->conn); - od->conf = FALSE; - } - if (od->reqemail) { - debug_printf("requesting email\n"); - aim_auth_getinfo(sess, command->conn, 0x0011); - od->reqemail = FALSE; - } - break; - case AIM_CONN_TYPE_BOS: - aim_setversions(sess, command->conn); - aim_bos_reqrate(sess, command->conn); /* request rate info */ - debug_printf("done with BOS ServerReady\n"); - break; - case AIM_CONN_TYPE_CHATNAV: - debug_printf("chatnav: got server ready\n"); - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, gaim_chatnav_info, 0); - aim_bos_reqrate(sess, command->conn); - aim_bos_ackrateresp(sess, command->conn); - aim_chatnav_clientready(sess, command->conn); - aim_chatnav_reqrights(sess, command->conn); - break; - case AIM_CONN_TYPE_CHAT: - debug_printf("chat: got server ready\n"); - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, gaim_chat_join, 0); - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, gaim_chat_leave, 0); - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, gaim_chat_info_update, 0); - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, gaim_chat_incoming_msg, 0); - aim_bos_reqrate(sess, command->conn); - aim_bos_ackrateresp(sess, command->conn); - aim_chat_clientready(sess, command->conn); - chatcon = find_oscar_chat_by_conn(gc, command->conn); - chatcon->id = id; - chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show); - break; - case AIM_CONN_TYPE_RENDEZVOUS: - break; - default: /* huh? */ - debug_printf("server ready: got unexpected connection type %04x\n", command->conn->type); - break; + + aim_auth_setversions(sess, fr->conn); + aim_bos_reqrate(sess, fr->conn); + debug_printf("done with AUTH ServerReady\n"); + if (od->chpass) { + debug_printf("changing password\n"); + aim_auth_changepasswd(sess, fr->conn, od->newp, od->oldp); + g_free(od->oldp); + g_free(od->newp); + od->chpass = FALSE; } + if (od->conf) { + debug_printf("confirming account\n"); + aim_auth_reqconfirm(sess, fr->conn); + od->conf = FALSE; + } + if (od->reqemail) { + debug_printf("requesting email\n"); + aim_auth_getinfo(sess, fr->conn, 0x0011); + od->reqemail = FALSE; + } + + return 1; +} + +static int server_ready_bos(aim_session_t *sess, aim_frame_t *fr, ...) { + aim_setversions(sess, fr->conn); + aim_bos_reqrate(sess, fr->conn); /* request rate info */ + debug_printf("done with BOS ServerReady\n"); + return 1; } -static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition cond) -{ +static int server_ready_chatnav(aim_session_t *sess, aim_frame_t *fr, ...) { + debug_printf("chatnav: got server ready\n"); + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, gaim_chatnav_info, 0); + aim_bos_reqrate(sess, fr->conn); + aim_bos_ackrateresp(sess, fr->conn); + aim_chatnav_clientready(sess, fr->conn); + aim_chatnav_reqrights(sess, fr->conn); + + return 1; +} + +static int server_ready_chat(aim_session_t *sess, aim_frame_t *fr, ...) { + struct gaim_connection *gc = sess->aux_data; + struct chat_connection *chatcon; + static int id = 1; + + debug_printf("chat: got server ready\n"); + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, gaim_chat_join, 0); + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, gaim_chat_leave, 0); + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, gaim_chat_info_update, 0); + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, gaim_chat_incoming_msg, 0); + aim_bos_reqrate(sess, fr->conn); + aim_bos_ackrateresp(sess, fr->conn); + aim_chat_clientready(sess, fr->conn); + chatcon = find_oscar_chat_by_conn(gc, fr->conn); + chatcon->id = id; + chatcon->cnv = serv_got_joined_chat(gc, id++, chatcon->show); + + return 1; +} + +static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition cond) { struct gaim_connection *gc = data; struct oscar_data *odata; - struct aim_session_t *sess; - struct aim_conn_t *tstconn; + aim_session_t *sess; + aim_conn_t *tstconn; if (!g_slist_find(connections, gc)) { close(source); @@ -895,7 +925,7 @@ aim_conn_completeconnect(sess, tstconn); odata->cnpa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, - oscar_callback, tstconn); + oscar_callback, tstconn); debug_printf("chatnav: connected\n"); } @@ -903,8 +933,8 @@ { struct gaim_connection *gc = data; struct oscar_data *odata; - struct aim_session_t *sess; - struct aim_conn_t *tstconn; + aim_session_t *sess; + aim_conn_t *tstconn; if (!g_slist_find(connections, gc)) { close(source); @@ -932,8 +962,8 @@ struct chat_connection *ccon = data; struct gaim_connection *gc = ccon->gc; struct oscar_data *odata; - struct aim_session_t *sess; - struct aim_conn_t *tstconn; + aim_session_t *sess; + aim_conn_t *tstconn; if (!g_slist_find(connections, gc)) { close(source); @@ -963,15 +993,15 @@ aim_chat_attachname(tstconn, ccon->name); } -int gaim_handle_redirect(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +/* Hrmph. I don't know how to make this look better. --mid */ +static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - int serviceid; + fu16_t serviceid; char *ip; - unsigned char *cookie; + fu8_t *cookie; struct gaim_connection *gc = sess->aux_data; struct aim_user *user = gc->user; - struct aim_conn_t *tstconn; + aim_conn_t *tstconn; int i; char *host; int port; @@ -979,10 +1009,10 @@ port = user->proto_opt[USEROPT_AUTHPORT][0] ? atoi(user->proto_opt[USEROPT_AUTHPORT]) : FAIM_LOGIN_PORT, - va_start(ap, command); - serviceid = va_arg(ap, int); - ip = va_arg(ap, char *); - cookie = va_arg(ap, unsigned char *); + va_start(ap, fr); + serviceid = (fu16_t)va_arg(ap, unsigned int); + ip = va_arg(ap, char *); + cookie = (fu8_t *)va_arg(ap, unsigned char *); for (i = 0; i < (int)strlen(ip); i++) { if (ip[i] == ':') { @@ -1001,8 +1031,8 @@ g_free(host); return 1; } - aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0); - aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, gaim_rateresp, 0); + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, server_ready_auth, 0); + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, rateresp_auth, 0); aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, gaim_info_change, 0); aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, gaim_info_change, 0); aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, gaim_account_confirm, 0); @@ -1024,7 +1054,7 @@ g_free(host); return 1; } - aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0); + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, server_ready_chatnav, 0); tstconn->status |= AIM_CONN_STATUS_INPROGRESS; tstconn->fd = proxy_connect(host, port, oscar_chatnav_connect, gc); @@ -1038,9 +1068,13 @@ break; case 0xe: /* Chat */ { - char *roomname = va_arg(ap, char *); - int exchange = va_arg(ap, int); + char *roomname; + fu16_t exchange; struct chat_connection *ccon; + + roomname = va_arg(ap, char *); + exchange = (fu16_t)va_arg(ap, unsigned int); + tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, NULL); if (tstconn == NULL) { debug_printf("unable to connect to chat server\n"); @@ -1048,7 +1082,7 @@ return 1; } - aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0); + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, server_ready_chat, 0); ccon = g_new0(struct chat_connection, 1); ccon->conn = tstconn; ccon->gc = gc; @@ -1083,15 +1117,14 @@ return 1; } -int gaim_parse_oncoming(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) { struct aim_userinfo_s *info; time_t time_idle; int type = 0; struct gaim_connection *gc = sess->aux_data; va_list ap; - va_start(ap, command); + va_start(ap, fr); info = va_arg(ap, struct aim_userinfo_s *); va_end(ap); @@ -1118,13 +1151,12 @@ return 1; } -int gaim_parse_offgoing(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...) { struct aim_userinfo_s *info; va_list ap; struct gaim_connection *gc = sess->aux_data; - va_start(ap, command); + va_start(ap, fr); info = va_arg(ap, struct aim_userinfo_s *); va_end(ap); @@ -1157,8 +1189,12 @@ return; } + if (dim->conn->fd != source) + dim->conn->fd = source; + aim_conn_completeconnect(od->sess, dim->conn); - if (!(cnv = find_conversation(dim->name))) cnv = new_conversation(dim->name); + if (!(cnv = find_conversation(dim->name))) + cnv = new_conversation(dim->name); g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), dim->name); write_to_conv(cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL)); @@ -1186,27 +1222,25 @@ dim->gc = d->gc; g_snprintf(dim->name, sizeof dim->name, "%s", d->sn); - if ((dim->conn = aim_newconn(od->sess, AIM_CONN_TYPE_RENDEZVOUS, NULL)) == NULL) { + dim->conn = aim_directim_connect(od->sess, d->sn, NULL, d->cookie); + if (!dim->conn) { g_free(dim); cancel_direct_im(w, d); return TRUE; } - dim->conn->subtype = AIM_CONN_SUBTYPE_OFT_DIRECTIM; - dim->conn->priv = d->priv; + aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_directim_incoming, 0); - aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, - gaim_directim_disconnect, 0); aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_directim_typing, 0); - for (i = 0; i < (int)strlen(d->priv->ip); i++) { - if (d->priv->ip[i] == ':') { - port = atoi(&(d->priv->ip[i+1])); + for (i = 0; i < (int)strlen(d->ip); i++) { + if (d->ip[i] == ':') { + port = atoi(&(d->ip[i+1])); break; } } - host = g_strndup(d->priv->ip, i); + host = g_strndup(d->ip, i); dim->conn->status |= AIM_CONN_STATUS_INPROGRESS; dim->conn->fd = proxy_connect(host, port, oscar_directim_callback, dim); g_free(host); @@ -1222,151 +1256,169 @@ return TRUE; } -int gaim_parse_incoming_im(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { - int channel; +static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch1_args *args) { + char *tmp = g_malloc(BUF_LONG); + struct gaim_connection *gc = sess->aux_data; + + if (args->icbmflags & AIM_IMFLAGS_HASICON) { + struct oscar_data *od = gc->proto_data; + struct icon_req *ir = NULL; + GSList *h = od->hasicons; + char *who = normalize(userinfo->sn); + debug_printf("%s has an icon\n", userinfo->sn); + while (h) { + ir = h->data; + if (!strcmp(ir->user, who)) + break; + h = h->next; + } + if (!h) { + ir = g_new0(struct icon_req, 1); + ir->user = g_strdup(who); + od->hasicons = g_slist_append(od->hasicons, ir); + } + if ((args->iconlen != ir->length) || + (args->iconsum != ir->checksum) || + (args->iconstamp != ir->timestamp)) + ir->request = TRUE; + ir->length = args->iconlen; + ir->checksum = args->iconsum; + ir->timestamp = args->iconstamp; + } + + if (gc->iconfile && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)) { + FILE *file; + struct stat st; + + if (!stat(gc->iconfile, &st)) { + char *buf = g_malloc(st.st_size); + file = fopen(gc->iconfile, "r"); + if (file) { + fread(buf, 1, st.st_size, file); + aim_send_icon(sess, conn, userinfo->sn, buf, st.st_size, + st.st_mtime, aim_iconsum(buf, st.st_size)); + fclose(file); + } + g_free(buf); + } + } + + /* + * Quickly convert it to eight bit format, replacing + * non-ASCII UNICODE characters with their equivelent + * HTML entity. + */ + if (args->icbmflags & AIM_IMFLAGS_UNICODE) { + int i; + + for (i = 0, tmp[0] = '\0'; i < args->msglen; i += 2) { + unsigned short uni; + + uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff); + + if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */ + + g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "%c", uni); + + } else { /* something else, do UNICODE entity */ + g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "&#%04x;", uni); + } + } + } else + g_snprintf(tmp, BUF_LONG, "%s", args->msg); + + serv_got_im(gc, userinfo->sn, tmp, args->icbmflags & AIM_IMFLAGS_AWAY, time(NULL)); + g_free(tmp); + + return 1; +} + +static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args) { + struct gaim_connection *gc = sess->aux_data; + + if (args->reqclass & AIM_CAPS_CHAT) { + char *name = extract_name(args->info.chat.roominfo.name); + int *exch = g_new0(int, 1); + GList *m = NULL; + m = g_list_append(m, g_strdup(name ? name : args->info.chat.roominfo.name)); + *exch = args->info.chat.roominfo.exchange; + m = g_list_append(m, exch); + serv_got_chat_invite(gc, + name ? name : args->info.chat.roominfo.name, + userinfo->sn, + args->info.chat.msg, + m); + if (name) + g_free(name); + } else if (args->reqclass & AIM_CAPS_SENDFILE) { + } else if (args->reqclass & AIM_CAPS_GETFILE) { + } else if (args->reqclass & AIM_CAPS_VOICE) { + } else if (args->reqclass & AIM_CAPS_BUDDYICON) { + set_icon_data(gc, normalize(userinfo->sn), args->info.icon.icon, + args->info.icon.length); + } else if (args->reqclass & AIM_CAPS_IMIMAGE) { + struct ask_direct *d = g_new0(struct ask_direct, 1); + char buf[256]; + + debug_printf("%s received direct im request from %s (%s)\n", + gc->username, userinfo->sn, args->info.imimage.ip); + + d->gc = gc; + d->sn = g_strdup(userinfo->sn); + strncpy(d->ip, args->info.imimage.ip, sizeof(d->ip)); + memcpy(d->cookie, args->cookie, 8); + g_snprintf(buf, sizeof buf, "%s has just asked to directly connect to %s.", + userinfo->sn, gc->username); + do_ask_dialog(buf, d, accept_direct_im, cancel_direct_im); + } else { + debug_printf("Unknown reqclass %d\n", args->reqclass); + } + + return 1; +} + + +static int gaim_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...) { + int channel, ret = 0; struct aim_userinfo_s *userinfo; va_list ap; - struct gaim_connection *gc = sess->aux_data; - - va_start(ap, command); + + va_start(ap, fr); channel = va_arg(ap, int); userinfo = va_arg(ap, struct aim_userinfo_s *); /* channel 1: standard message */ if (channel == 1) { - char *tmp = g_malloc(BUF_LONG); struct aim_incomingim_ch1_args *args; args = va_arg(ap, struct aim_incomingim_ch1_args *); - va_end(ap); - - if (args->icbmflags & AIM_IMFLAGS_HASICON) { - struct oscar_data *od = gc->proto_data; - struct icon_req *ir = NULL; - GSList *h = od->hasicons; - char *who = normalize(userinfo->sn); - debug_printf("%s has an icon\n", userinfo->sn); - while (h) { - ir = h->data; - if (!strcmp(ir->user, who)) - break; - h = h->next; - } - if (!h) { - ir = g_new0(struct icon_req, 1); - ir->user = g_strdup(who); - od->hasicons = g_slist_append(od->hasicons, ir); - } - if ((args->iconlength != ir->length) || - (args->iconchecksum != ir->checksum) || - (args->iconstamp != ir->timestamp)) - ir->request = TRUE; - ir->length = args->iconlength; - ir->checksum = args->iconchecksum; - ir->timestamp = args->iconstamp; - } - - if (gc->iconfile && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)) { - FILE *file; - struct stat st; - - if (!stat(gc->iconfile, &st)) { - char *buf = g_malloc(st.st_size); - file = fopen(gc->iconfile, "r"); - if (file) { - fread(buf, 1, st.st_size, file); - aim_send_icon(sess, command->conn, userinfo->sn, buf, st.st_size, - st.st_mtime, aim_iconsum(buf, st.st_size)); - fclose(file); - } - g_free(buf); - } - } - - /* - * Quickly convert it to eight bit format, replacing - * non-ASCII UNICODE characters with their equivelent - * HTML entity. - */ - if (args->icbmflags & AIM_IMFLAGS_UNICODE) { - int i; - - for (i = 0, tmp[0] = '\0'; i < args->msglen; i += 2) { - unsigned short uni; - - uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff); - - if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */ - - g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "%c", uni); - - } else { /* something else, do UNICODE entity */ - g_snprintf(tmp+strlen(tmp), BUF_LONG-strlen(tmp), "&#%04x;", uni); - } - } - } else - g_snprintf(tmp, BUF_LONG, "%s", args->msg); - - serv_got_im(gc, userinfo->sn, tmp, args->icbmflags & AIM_IMFLAGS_AWAY, time(NULL)); - g_free(tmp); + + ret = incomingim_chan1(sess, fr->conn, userinfo, args); + } else if (channel == 2) { struct aim_incomingim_ch2_args *args; + args = va_arg(ap, struct aim_incomingim_ch2_args *); - va_end(ap); - if (args->reqclass & AIM_CAPS_CHAT) { - char *name = extract_name(args->info.chat.roominfo.name); - int *exch = g_new0(int, 1); - GList *m = NULL; - m = g_list_append(m, g_strdup(name ? name : args->info.chat.roominfo.name)); - *exch = args->info.chat.roominfo.exchange; - m = g_list_append(m, exch); - serv_got_chat_invite(gc, - name ? name : args->info.chat.roominfo.name, - userinfo->sn, - args->info.chat.msg, - m); - if (name) - g_free(name); - } else if (args->reqclass & AIM_CAPS_SENDFILE) { - } else if (args->reqclass & AIM_CAPS_GETFILE) { - } else if (args->reqclass & AIM_CAPS_VOICE) { - } else if (args->reqclass & AIM_CAPS_BUDDYICON) { - set_icon_data(gc, normalize(userinfo->sn), args->info.icon.icon, - args->info.icon.length); - } else if (args->reqclass & AIM_CAPS_IMIMAGE) { - struct ask_direct *d = g_new0(struct ask_direct, 1); - char buf[256]; - - debug_printf("%s received direct im request from %s (%s)\n", - gc->username, userinfo->sn, args->info.directim->ip); - - d->gc = gc; - d->sn = g_strdup(userinfo->sn); - d->priv = args->info.directim; - g_snprintf(buf, sizeof buf, "%s has just asked to directly connect to %s.", - userinfo->sn, gc->username); - do_ask_dialog(buf, d, accept_direct_im, cancel_direct_im); - } else { - debug_printf("Unknown reqclass %d\n", args->reqclass); - } + + ret = incomingim_chan2(sess, fr->conn, userinfo, args); } - return 1; + va_end(ap); + + return ret; } -int gaim_parse_misses(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - unsigned short chan, nummissed, reason; + fu16_t chan, nummissed, reason; struct aim_userinfo_s *userinfo; char buf[1024]; - va_start(ap, command); - chan = (unsigned short)va_arg(ap, unsigned int); + va_start(ap, fr); + chan = (fu16_t)va_arg(ap, unsigned int); userinfo = va_arg(ap, struct aim_userinfo_s *); - nummissed = (unsigned short)va_arg(ap, unsigned int); - reason = (unsigned short)va_arg(ap, unsigned int); + nummissed = (fu16_t)va_arg(ap, unsigned int); + reason = (fu16_t)va_arg(ap, unsigned int); va_end(ap); switch(reason) { @@ -1431,12 +1483,12 @@ return 1; } -int gaim_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +static int gaim_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - unsigned short reason; - - va_start(ap, command); - reason = va_arg(ap, int); + fu16_t reason; + + va_start(ap, fr); + reason = (fu16_t)va_arg(ap, unsigned int); va_end(ap); debug_printf("snac threw error (reason 0x%04x: %s\n", reason, @@ -1445,15 +1497,14 @@ return 1; } -int gaim_parse_msgerr(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *destn; - unsigned short reason; + fu16_t reason; char buf[1024]; - va_start(ap, command); - reason = (unsigned short)va_arg(ap, unsigned int); + va_start(ap, fr); + reason = (fu16_t)va_arg(ap, unsigned int); destn = va_arg(ap, char *); va_end(ap); @@ -1464,15 +1515,14 @@ return 1; } -int gaim_parse_locerr(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *destn; - unsigned short reason; + fu16_t reason; char buf[1024]; - va_start(ap, command); - reason = (unsigned short)va_arg(ap, unsigned int); + va_start(ap, fr); + reason = (fu16_t)va_arg(ap, unsigned int); destn = va_arg(ap, char *); va_end(ap); @@ -1493,22 +1543,21 @@ return buf; } -int gaim_parse_user_info(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_parse_user_info(aim_session_t *sess, aim_frame_t *fr, ...) { struct aim_userinfo_s *info; char *prof_enc = NULL, *prof = NULL; - unsigned short infotype; + fu16_t infotype; char buf[BUF_LONG]; char legend[BUF_LONG]; struct gaim_connection *gc = sess->aux_data; va_list ap; char *asc; - va_start(ap, command); + va_start(ap, fr); info = va_arg(ap, struct aim_userinfo_s *); prof_enc = va_arg(ap, char *); prof = va_arg(ap, char *); - infotype = (unsigned short)va_arg(ap, unsigned int); + infotype = (fu16_t)va_arg(ap, unsigned int); va_end(ap); if (info->membersince) @@ -1549,22 +1598,21 @@ return 1; } -int gaim_parse_motd(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...) { char *msg; - unsigned short id; + fu16_t id; va_list ap; char buildbuf[150]; - va_start(ap, command); - id = (unsigned short)va_arg(ap, unsigned int); + va_start(ap, fr); + id = (fu16_t)va_arg(ap, unsigned int); msg = va_arg(ap, char *); va_end(ap); aim_getbuildstring(buildbuf, sizeof(buildbuf)); debug_printf("MOTD: %s (%d)\n", msg ? msg : "Unknown", id); - debug_printf("Gaim %s / Libfaim %s\n", VERSION, buildbuf); + debug_printf("Gaim %s / libfaim %s\n", VERSION, buildbuf); if (id < 4) do_error_dialog(_("Your connection may be lost."), _("AOL error")); @@ -1572,23 +1620,22 @@ return 1; } -int gaim_chatnav_info(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - unsigned short type; + fu16_t type; struct gaim_connection *gc = sess->aux_data; struct oscar_data *odata = (struct oscar_data *)gc->proto_data; - va_start(ap, command); - type = (unsigned short)va_arg(ap, unsigned int); + va_start(ap, fr); + type = (fu16_t)va_arg(ap, unsigned int); switch(type) { case 0x0002: { - int maxrooms; + fu8_t maxrooms; struct aim_chat_exchangeinfo *exchanges; - int exchangecount, i = 0; - - maxrooms = (unsigned char)va_arg(ap, unsigned int); + int exchangecount, i; + + maxrooms = (fu8_t)va_arg(ap, unsigned int); exchangecount = va_arg(ap, int); exchanges = va_arg(ap, struct aim_chat_exchangeinfo *); va_end(ap); @@ -1596,11 +1643,11 @@ debug_printf("chat info: Chat Rights:\n"); debug_printf("chat info: \tMax Concurrent Rooms: %d\n", maxrooms); debug_printf("chat info: \tExchange List: (%d total)\n", exchangecount); - while (i < exchangecount) - debug_printf("chat info: \t\t%d\n", exchanges[i++].number); + for (i = 0; i < exchangecount; i++) + debug_printf("chat info: \t\t%d\n", exchanges[i].number); if (odata->create_exchange) { debug_printf("creating room %s\n", odata->create_name); - aim_chatnav_createroom(sess, command->conn, odata->create_name, + aim_chatnav_createroom(sess, fr->conn, odata->create_name, odata->create_exchange); odata->create_exchange = 0; g_free(odata->create_name); @@ -1610,19 +1657,19 @@ break; case 0x0008: { char *fqcn, *name, *ck; - unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange; - unsigned char createperms; - unsigned long createtime; + fu16_t instance, flags, maxmsglen, maxoccupancy, unknown, exchange; + fu8_t createperms; + fu32_t createtime; fqcn = va_arg(ap, char *); - instance = (unsigned short)va_arg(ap, unsigned int); - exchange = (unsigned short)va_arg(ap, unsigned int); - flags = (unsigned short)va_arg(ap, unsigned int); - createtime = va_arg(ap, unsigned long); - maxmsglen = (unsigned short)va_arg(ap, unsigned int); - maxoccupancy = (unsigned short)va_arg(ap, unsigned int); - createperms = (unsigned char)va_arg(ap, int); - unknown = (unsigned short)va_arg(ap, unsigned int); + instance = (fu16_t)va_arg(ap, unsigned int); + exchange = (fu16_t)va_arg(ap, unsigned int); + flags = (fu16_t)va_arg(ap, unsigned int); + createtime = va_arg(ap, fu32_t); + maxmsglen = (fu16_t)va_arg(ap, unsigned int); + maxoccupancy = (fu16_t)va_arg(ap, unsigned int); + createperms = (fu8_t)va_arg(ap, int); + unknown = (fu16_t)va_arg(ap, unsigned int); name = va_arg(ap, char *); ck = va_arg(ap, char *); va_end(ap); @@ -1633,7 +1680,7 @@ createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck); - aim_chat_join(odata->sess, odata->conn, exchange, ck); + aim_chat_join(odata->sess, odata->conn, exchange, ck, instance); } break; default: @@ -1644,79 +1691,76 @@ return 1; } -int gaim_chat_join(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_chat_join(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - int count, i = 0; + int count, i; struct aim_userinfo_s *info; struct gaim_connection *g = sess->aux_data; struct chat_connection *c = NULL; - va_start(ap, command); + va_start(ap, fr); count = va_arg(ap, int); info = va_arg(ap, struct aim_userinfo_s *); va_end(ap); - c = find_oscar_chat_by_conn(g, command->conn); + c = find_oscar_chat_by_conn(g, fr->conn); if (!c) return 1; - while (i < count) - add_chat_buddy(c->cnv, info[i++].sn); + for (i = 0; i < count; i++) + add_chat_buddy(c->cnv, info[i].sn); return 1; } -int gaim_chat_leave(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - int count, i = 0; + int count, i; struct aim_userinfo_s *info; struct gaim_connection *g = sess->aux_data; struct chat_connection *c = NULL; - va_start(ap, command); + va_start(ap, fr); count = va_arg(ap, int); info = va_arg(ap, struct aim_userinfo_s *); va_end(ap); - c = find_oscar_chat_by_conn(g, command->conn); + c = find_oscar_chat_by_conn(g, fr->conn); if (!c) return 1; - while (i < count) - remove_chat_buddy(c->cnv, info[i++].sn); + for (i = 0; i < count; i++) + remove_chat_buddy(c->cnv, info[i].sn); return 1; } -int gaim_chat_info_update(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_chat_info_update(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; struct aim_userinfo_s *userinfo; struct aim_chat_roominfo *roominfo; char *roomname; int usercount; char *roomdesc; - unsigned short unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen; - unsigned long creationtime; + fu16_t unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen; + fu32_t creationtime; struct gaim_connection *gc = sess->aux_data; - struct chat_connection *ccon = find_oscar_chat_by_conn(gc, command->conn); - - va_start(ap, command); + struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn); + + va_start(ap, fr); roominfo = va_arg(ap, struct aim_chat_roominfo *); roomname = va_arg(ap, char *); usercount= va_arg(ap, int); userinfo = va_arg(ap, struct aim_userinfo_s *); roomdesc = va_arg(ap, char *); - unknown_c9 = va_arg(ap, int); - creationtime = va_arg(ap, unsigned long); - maxmsglen = va_arg(ap, int); - unknown_d2 = va_arg(ap, int); - unknown_d5 = va_arg(ap, int); - maxvisiblemsglen = va_arg(ap, int); + unknown_c9 = (fu16_t)va_arg(ap, int); + creationtime = (fu32_t)va_arg(ap, unsigned long); + maxmsglen = (fu16_t)va_arg(ap, int); + unknown_d2 = (fu16_t)va_arg(ap, int); + unknown_d5 = (fu16_t)va_arg(ap, int); + maxvisiblemsglen = (fu16_t)va_arg(ap, int); va_end(ap); debug_printf("inside chat_info_update (maxmsglen = %d, maxvislen = %d)\n", @@ -1728,16 +1772,15 @@ return 1; } -int gaim_chat_incoming_msg(struct aim_session_t *sess, - struct command_rx_struct *command, ...) { +static int gaim_chat_incoming_msg(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; struct aim_userinfo_s *info; char *msg; struct gaim_connection *gc = sess->aux_data; - struct chat_connection *ccon = find_oscar_chat_by_conn(gc, command->conn); + struct chat_connection *ccon = find_oscar_chat_by_conn(gc, fr->conn); char *tmp; - va_start(ap, command); + va_start(ap, fr); info = va_arg(ap, struct aim_userinfo_s *); msg = va_arg(ap, char *); @@ -1749,16 +1792,16 @@ return 1; } - /* - * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option. - */ -int gaim_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +/* + * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option. + */ +static int gaim_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - unsigned short type; - char *sn = NULL; - - va_start(ap, command); - type = (unsigned short)va_arg(ap, unsigned int); + fu16_t type; + char *sn; + + va_start(ap, fr); + type = (fu16_t)va_arg(ap, unsigned int); sn = va_arg(ap, char *); va_end(ap); @@ -1767,27 +1810,28 @@ return 1; } -int gaim_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - static char *codes[5] = {"invalid", - "change", - "warning", - "limit", - "limit cleared"}; +static int gaim_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...) { + static const char *codes[5] = { + "invalid", + "change", + "warning", + "limit", + "limit cleared", + }; va_list ap; - int code; - unsigned long rateclass, windowsize, clear, alert, limit, disconnect; - unsigned long currentavg, maxavg; - - va_start(ap, command); - code = va_arg(ap, int); - rateclass= va_arg(ap, int); - windowsize = va_arg(ap, unsigned long); - clear = va_arg(ap, unsigned long); - alert = va_arg(ap, unsigned long); - limit = va_arg(ap, unsigned long); - disconnect = va_arg(ap, unsigned long); - currentavg = va_arg(ap, unsigned long); - maxavg = va_arg(ap, unsigned long); + fu16_t code, rateclass; + fu32_t windowsize, clear, alert, limit, disconnect, currentavg, maxavg; + + va_start(ap, fr); + code = (fu16_t)va_arg(ap, unsigned int); + rateclass= (fu16_t)va_arg(ap, unsigned int); + windowsize = (fu32_t)va_arg(ap, unsigned long); + clear = (fu32_t)va_arg(ap, unsigned long); + alert = (fu32_t)va_arg(ap, unsigned long); + limit = (fu32_t)va_arg(ap, unsigned long); + disconnect = (fu32_t)va_arg(ap, unsigned long); + currentavg = (fu32_t)va_arg(ap, unsigned long); + maxavg = (fu32_t)va_arg(ap, unsigned long); va_end(ap); debug_printf("rate %s (paramid 0x%04lx): curavg = %ld, maxavg = %ld, alert at %ld, " @@ -1799,28 +1843,29 @@ limit, disconnect, windowsize); + /* XXX fix these values */ if (code == AIM_RATE_CODE_CHANGE) { if (currentavg >= clear) - aim_conn_setlatency(command->conn, 0); + aim_conn_setlatency(fr->conn, 0); } else if (code == AIM_RATE_CODE_WARNING) { - aim_conn_setlatency(command->conn, windowsize/4); + aim_conn_setlatency(fr->conn, windowsize/4); } else if (code == AIM_RATE_CODE_LIMIT) { - aim_conn_setlatency(command->conn, windowsize/2); + aim_conn_setlatency(fr->conn, windowsize/2); } else if (code == AIM_RATE_CODE_CLEARLIMIT) { - aim_conn_setlatency(command->conn, 0); + aim_conn_setlatency(fr->conn, 0); } return 1; } -int gaim_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +static int gaim_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - int newevil; + fu16_t newevil; struct aim_userinfo_s *userinfo; struct gaim_connection *gc = sess->aux_data; - va_start(ap, command); - newevil = va_arg(ap, int); + va_start(ap, fr); + newevil = (fu16_t)va_arg(ap, unsigned int); userinfo = va_arg(ap, struct aim_userinfo_s *); va_end(ap); @@ -1829,51 +1874,46 @@ return 1; } -int gaim_rateresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +static int rateresp_bos(aim_session_t *sess, aim_frame_t *fr, ...) { struct gaim_connection *gc = sess->aux_data; - switch (command->conn->type) { - case AIM_CONN_TYPE_BOS: - aim_bos_ackrateresp(sess, command->conn); - aim_bos_reqpersonalinfo(sess, command->conn); - aim_bos_reqlocaterights(sess, command->conn); - aim_bos_setprofile(sess, command->conn, gc->user->user_info, NULL, gaim_caps); - aim_bos_reqbuddyrights(sess, command->conn); - - account_online(gc); - serv_finish_login(gc); - - if (bud_list_cache_exists(gc)) - do_import(NULL, gc); - - debug_printf("buddy list loaded\n"); - - aim_reqicbmparams(sess, command->conn); - - aim_bos_reqrights(sess, command->conn); - aim_bos_setgroupperm(sess, command->conn, AIM_FLAG_ALLUSERS); - aim_bos_setprivacyflags(sess, command->conn, AIM_PRIVFLAGS_ALLOWIDLE | - AIM_PRIVFLAGS_ALLOWMEMBERSINCE); - - break; - case AIM_CONN_TYPE_AUTH: - aim_bos_ackrateresp(sess, command->conn); - aim_auth_clientready(sess, command->conn); - debug_printf("connected to auth (admin)\n"); - break; - default: - debug_printf("got rate response for unhandled connection type %04x\n", - command->conn->type); - break; - } + + aim_bos_ackrateresp(sess, fr->conn); + aim_bos_reqpersonalinfo(sess, fr->conn); + aim_bos_reqlocaterights(sess, fr->conn); + aim_bos_setprofile(sess, fr->conn, gc->user->user_info, NULL, gaim_caps); + aim_bos_reqbuddyrights(sess, fr->conn); + + account_online(gc); + serv_finish_login(gc); + + if (bud_list_cache_exists(gc)) + do_import(NULL, gc); + + debug_printf("buddy list loaded\n"); + + aim_reqicbmparams(sess, fr->conn); + + aim_bos_reqrights(sess, fr->conn); + aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS); + aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE | + AIM_PRIVFLAGS_ALLOWMEMBERSINCE); return 1; } -int gaim_icbm_param_info(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +static int rateresp_auth(aim_session_t *sess, aim_frame_t *fr, ...) { + aim_bos_ackrateresp(sess, fr->conn); + aim_auth_clientready(sess, fr->conn); + debug_printf("connected to auth (admin)\n"); + + return 1; +} + +static int gaim_icbm_param_info(aim_session_t *sess, aim_frame_t *fr, ...) { struct aim_icbmparameters *params; va_list ap; - va_start(ap, command); + va_start(ap, fr); params = va_arg(ap, struct aim_icbmparameters *); va_end(ap); @@ -1883,36 +1923,23 @@ ((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0, params->minmsginterval); + /* Maybe senderwarn and recverwarn should be user preferences... */ params->maxmsglen = 8000; params->minmsginterval = 0; - aim_seticbmparam(sess, command->conn, params); + aim_seticbmparam(sess, fr->conn, params); return 1; } -int gaim_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +/* XXX this is frivelous... do you really want to know this info? */ +static int gaim_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - unsigned short interval = 0; - - va_start(ap, command); - interval = va_arg(ap, int); - va_end(ap); - - debug_printf("minimum report interval: %d (seconds?)\n", interval); - - aim_reqicbmparams(sess, command->conn); - - return 1; -} - -int gaim_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - va_list ap; - unsigned short maxbuddies, maxwatchers; - - va_start(ap, command); - maxbuddies = (unsigned short)va_arg(ap, unsigned int); - maxwatchers = (unsigned short)va_arg(ap, unsigned int); + fu16_t maxbuddies, maxwatchers; + + va_start(ap, fr); + maxbuddies = (fu16_t)va_arg(ap, unsigned int); + maxwatchers = (fu16_t)va_arg(ap, unsigned int); va_end(ap); debug_printf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers); @@ -1920,32 +1947,32 @@ return 1; } -int gaim_bosrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - unsigned short maxpermits, maxdenies; +static int gaim_bosrights(aim_session_t *sess, aim_frame_t *fr, ...) { + fu16_t maxpermits, maxdenies; va_list ap; - va_start(ap, command); - maxpermits = (unsigned short)va_arg(ap, unsigned int); - maxdenies = (unsigned short)va_arg(ap, unsigned int); + va_start(ap, fr); + maxpermits = (fu16_t)va_arg(ap, unsigned int); + maxdenies = (fu16_t)va_arg(ap, unsigned int); va_end(ap); debug_printf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies); - aim_bos_clientready(sess, command->conn); - - aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV); + aim_bos_clientready(sess, fr->conn); + + aim_bos_reqservice(sess, fr->conn, AIM_CONN_TYPE_CHATNAV); return 1; } -int gaim_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +static int gaim_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *address, *SNs; int i, num; char *buf; int at = 0, len; - va_start(ap, command); + va_start(ap, fr); address = va_arg(ap, char *); num = va_arg(ap, int); SNs = va_arg(ap, char *); @@ -1962,12 +1989,12 @@ return 1; } -int gaim_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +static int gaim_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *address; char buf[BUF_LONG]; - va_start(ap, command); + va_start(ap, fr); address = va_arg(ap, char *); va_end(ap); @@ -1977,14 +2004,14 @@ return 1; } -int gaim_account_confirm(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - int status; +static int gaim_account_confirm(aim_session_t *sess, aim_frame_t *fr, ...) { + fu16_t status; va_list ap; char msg[256]; struct gaim_connection *gc = sess->aux_data; - va_start(ap, command); - status = va_arg(ap, int); /* status code of confirmation request */ + va_start(ap, fr); + status = (fu16_t)va_arg(ap, unsigned int); /* status code of confirmation request */ va_end(ap); debug_printf("account confirmation returned status 0x%04x (%s)\n", status, @@ -1998,25 +2025,23 @@ return 1; } -int gaim_info_change(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - unsigned short change = 0; - int perms, type, length, str; +static int gaim_info_change(aim_session_t *sess, aim_frame_t *fr, ...) { + int change, str; + fu16_t perms, type, length; char *val; va_list ap; char buf[BUF_LONG]; struct gaim_connection *gc = sess->aux_data; - va_start(ap, command); - perms = va_arg(ap, int); - type = va_arg(ap, int); - length = va_arg(ap, int); + va_start(ap, fr); + change = va_arg(ap, int); + perms = (fu16_t)va_arg(ap, unsigned int); + type = (fu16_t)va_arg(ap, unsigned int); + length = (fu16_t)va_arg(ap, unsigned int); val = va_arg(ap, char *); str = va_arg(ap, int); va_end(ap); - if (aimutil_get16(command->data+2) == 0x0005) - change = 1; - debug_printf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change ? " change" : "", perms, type, length, str ? val : "(not string)"); @@ -2047,15 +2072,13 @@ return aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_AWAY, message); else { struct aim_sendimext_args args; - - int flags = AIM_IMFLAGS_ACK; - GSList *h = odata->hasicons; struct icon_req *ir = NULL; char *who = normalize(name); - struct stat st; + args.flags = AIM_IMFLAGS_ACK; + while (h) { ir = h->data; if (ir->request && !strcmp(who, ir->user)) @@ -2064,7 +2087,7 @@ } if (h) { ir->request = FALSE; - flags |= AIM_IMFLAGS_BUDDYREQ; + args.flags |= AIM_IMFLAGS_BUDDYREQ; debug_printf("sending buddy icon request with message\n"); } @@ -2078,7 +2101,7 @@ args.iconsum = aim_iconsum(buf, st.st_size); args.iconstamp = st.st_mtime; - flags |= AIM_IMFLAGS_HASICON; + args.flags |= AIM_IMFLAGS_HASICON; fclose(file); g_free(buf); @@ -2088,7 +2111,6 @@ args.destsn = name; args.msg = message; args.msglen = strlen(message); - args.flags = flags; return aim_send_im_ext(odata->sess, odata->conn, &args); } @@ -2205,7 +2227,7 @@ static void oscar_join_chat(struct gaim_connection *g, GList *data) { struct oscar_data *odata = (struct oscar_data *)g->proto_data; - struct aim_conn_t *cur = NULL; + aim_conn_t *cur; char *name; int *exchange; @@ -2347,112 +2369,74 @@ return NULL; } -static int gaim_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +static int gaim_directim_initiate(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; struct gaim_connection *gc = sess->aux_data; struct oscar_data *od = (struct oscar_data *)gc->proto_data; - struct aim_directim_priv *priv; - struct aim_conn_t *newconn; + aim_conn_t *newconn, *listenerconn; struct conversation *cnv; struct direct_im *dim; char buf[256]; - - va_start(ap, command); - newconn = va_arg(ap, struct aim_conn_t *); + char *sn; + + va_start(ap, fr); + newconn = va_arg(ap, aim_conn_t *); + listenerconn = va_arg(ap, aim_conn_t *); va_end(ap); - priv = (struct aim_directim_priv *)newconn->priv; - - debug_printf("DirectIM: initiate success to %s\n", priv->sn); - dim = find_direct_im(od, priv->sn); - - if (!(cnv = find_conversation(priv->sn))) - cnv = new_conversation(priv->sn); + aim_conn_close(listenerconn); + aim_conn_kill(sess, &listenerconn); + + sn = g_strdup(aim_directim_getsn(newconn)); + + debug_printf("DirectIM: initiate success to %s\n", sn); + dim = find_direct_im(od, sn); + + if (!(cnv = find_conversation(sn))) + cnv = new_conversation(sn); gaim_input_remove(dim->watcher); dim->conn = newconn; dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn); - g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), priv->sn); + g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), sn); + g_free(sn); write_to_conv(cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL)); aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_directim_incoming, 0); - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, - gaim_directim_disconnect, 0); aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_directim_typing, 0); return 1; } -static int gaim_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +static int gaim_directim_incoming(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - char *msg = NULL; - struct aim_conn_t *conn; - struct aim_directim_priv *priv; + char *msg, *sn; struct gaim_connection *gc = sess->aux_data; - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); + va_start(ap, fr); + sn = va_arg(ap, char *); msg = va_arg(ap, char *); va_end(ap); - if (!(priv = conn->priv)) { - return -1; - } - - debug_printf("Got DirectIM message from %s\n", priv->sn); - - serv_got_im(gc, priv->sn, msg, 0, time((time_t)NULL)); + debug_printf("Got DirectIM message from %s\n", sn); + + serv_got_im(gc, sn, msg, 0, time((time_t)NULL)); return 1; } -static int gaim_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...) { +static int gaim_directim_typing(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - struct aim_conn_t *conn; char *sn; - struct gaim_connection *gc = sess->aux_data; - struct oscar_data *od = (struct oscar_data *)gc->proto_data; - struct conversation *cnv; - struct direct_im *dim; - char buf[256]; - - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); + + va_start(ap, fr); sn = va_arg(ap, char *); va_end(ap); - debug_printf("%s disconnected Direct IM.\n", sn); - - dim = find_direct_im(od, sn); - od->direct_ims = g_slist_remove(od->direct_ims, dim); - gaim_input_remove(dim->watcher); - - g_snprintf(buf, sizeof buf, _("Direct IM with %s closed"), sn); - if ((cnv = find_conversation(sn)) != NULL) - write_to_conv(cnv, buf, WFLAG_SYSTEM, NULL, time((time_t)NULL)); - - aim_conn_kill(sess, &conn); - - return 1; -} - -static int gaim_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - va_list ap; - struct aim_conn_t *conn; - struct aim_directim_priv *priv; - - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); - va_end(ap); - - if (!(priv = conn->priv)) { - return -1; - } - /* I had to leave this. It's just too funny. It reminds me of my sister. */ - debug_printf("ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", priv->sn); + debug_printf("ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn); return 1; } @@ -2480,7 +2464,7 @@ dim->gc = gc; g_snprintf(dim->name, sizeof dim->name, "%s", data->who); - dim->conn = aim_directim_initiate(od->sess, od->conn, NULL, data->who); + dim->conn = aim_directim_initiate(od->sess, od->conn, data->who); if (dim->conn != NULL) { od->direct_ims = g_slist_append(od->direct_ims, dim); dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, @@ -2617,7 +2601,7 @@ static void oscar_do_action(struct gaim_connection *gc, char *act) { struct oscar_data *od = gc->proto_data; - struct aim_conn_t *conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH); + aim_conn_t *conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_AUTH); if (!strcmp(act, "Set User Info")) { show_set_info(gc); @@ -2673,6 +2657,20 @@ } } +static void oscar_convo_closed(struct gaim_connection *gc, char *who) +{ + struct oscar_data *od = gc->proto_data; + struct direct_im *dim = find_direct_im(od, who); + + if (!dim) + return; + + od->direct_ims = g_slist_remove(od->direct_ims, dim); + gaim_input_remove(dim->watcher); + aim_conn_kill(od->sess, &dim->conn); + g_free(dim); +} + static struct prpl *my_protocol = NULL; void oscar_init(struct prpl *ret) { @@ -2713,6 +2711,7 @@ ret->chat_whisper = NULL; ret->chat_send = oscar_chat_send; ret->keepalive = oscar_keepalive; + ret->convo_closed = oscar_convo_closed; my_protocol = ret; } diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/rxhandlers.c --- a/src/protocols/oscar/rxhandlers.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/rxhandlers.c Sun Sep 09 10:07:14 2001 +0000 @@ -10,561 +10,564 @@ #define FAIM_INTERNAL #include -static aim_module_t *findmodule(struct aim_session_t *sess, const char *name) -{ - aim_module_t *cur; +struct aim_rxcblist_s { + fu16_t family; + fu16_t type; + aim_rxcallback_t handler; + u_short flags; + struct aim_rxcblist_s *next; +}; - for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { - if (strcmp(name, cur->name) == 0) - return cur; - } +static aim_module_t *findmodule(aim_session_t *sess, const char *name) +{ + aim_module_t *cur; - return NULL; + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + if (strcmp(name, cur->name) == 0) + return cur; + } + + return NULL; } -faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst)(struct aim_session_t *, aim_module_t *)) +faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *)) { - aim_module_t *mod; + aim_module_t *mod; + + if (!sess || !modfirst) + return -1; + + if (!(mod = malloc(sizeof(aim_module_t)))) + return -1; + memset(mod, 0, sizeof(aim_module_t)); - if (!sess || !modfirst) - return -1; + if (modfirst(sess, mod) == -1) { + free(mod); + return -1; + } - if (!(mod = malloc(sizeof(aim_module_t)))) - return -1; - memset(mod, 0, sizeof(aim_module_t)); + if (findmodule(sess, mod->name)) { + if (mod->shutdown) + mod->shutdown(sess, mod); + free(mod); + return -1; + } + + mod->next = (aim_module_t *)sess->modlistv; + (aim_module_t *)sess->modlistv = mod; - if (modfirst(sess, mod) == -1) { - free(mod); - return -1; - } + faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family); + + return 0; +} + +faim_internal void aim__shutdownmodules(aim_session_t *sess) +{ + aim_module_t *cur; + + for (cur = (aim_module_t *)sess->modlistv; cur; ) { + aim_module_t *tmp; - if (findmodule(sess, mod->name)) { - if (mod->shutdown) - mod->shutdown(sess, mod); - free(mod); - return -1; - } + tmp = cur->next; + + if (cur->shutdown) + cur->shutdown(sess, cur); + + free(cur); - mod->next = (aim_module_t *)sess->modlistv; - (aim_module_t *)sess->modlistv = mod; + cur = tmp; + } - faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family); + sess->modlistv = NULL; - return 0; + return; } -faim_internal void aim__shutdownmodules(struct aim_session_t *sess) +static int consumesnac(aim_session_t *sess, aim_frame_t *rx) { - aim_module_t *cur; + aim_module_t *cur; + aim_modsnac_t snac; - for (cur = (aim_module_t *)sess->modlistv; cur; ) { - aim_module_t *tmp; + if (aim_bstream_empty(&rx->data) < 10) + return 0; - tmp = cur->next; + snac.family = aimbs_get16(&rx->data); + snac.subtype = aimbs_get16(&rx->data); + snac.flags = aimbs_get16(&rx->data); + snac.id = aimbs_get32(&rx->data); - if (cur->shutdown) - cur->shutdown(sess, cur); + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { - free(cur); + if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && + (cur->family != snac.family)) + continue; - cur = tmp; - } + if (cur->snachandler(sess, cur, rx, &snac, &rx->data)) + return 1; - sess->modlistv = NULL; + } - return; + return 0; } -static int consumesnac(struct aim_session_t *sess, struct command_rx_struct *rx) +static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, fu16_t family, fu16_t subtype) { - aim_module_t *cur; - aim_modsnac_t snac; + aim_module_t *cur; + aim_modsnac_t snac; - snac.family = aimutil_get16(rx->data+0); - snac.subtype = aimutil_get16(rx->data+2); - snac.flags = aimutil_get16(rx->data+4); - snac.id = aimutil_get32(rx->data+6); + snac.family = family; + snac.subtype = subtype; + snac.flags = snac.id = 0; + + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { - for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { - - if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && - (cur->family != snac.family)) - continue; + if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && + (cur->family != snac.family)) + continue; - if (cur->snachandler(sess, cur, rx, &snac, rx->data+10, rx->commandlen-10)) - return 1; + if (cur->snachandler(sess, cur, rx, &snac, &rx->data)) + return 1; - } + } - return 0; + return 0; } -static int consumenonsnac(struct aim_session_t *sess, struct command_rx_struct *rx, unsigned short family, unsigned short subtype) +static int negchan_middle(aim_session_t *sess, aim_frame_t *fr) { - aim_module_t *cur; - aim_modsnac_t snac; + aim_tlvlist_t *tlvlist; + char *msg = NULL; + fu16_t code = 0; + aim_rxcallback_t userfunc; + int ret = 1; - snac.family = family; - snac.subtype = subtype; - snac.flags = snac.id = 0; - - for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + if (aim_bstream_empty(&fr->data) == 0) { + /* XXX should do something with this */ + return 1; + } - if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && - (cur->family != snac.family)) - continue; + /* Used only by the older login protocol */ + /* XXX remove this special case? */ + if (fr->conn->type == AIM_CONN_TYPE_AUTH) + return consumenonsnac(sess, fr, 0x0017, 0x0003); + + tlvlist = aim_readtlvchain(&fr->data); + + if (aim_gettlv(tlvlist, 0x0009, 1)) + code = aim_gettlv16(tlvlist, 0x0009, 1); - if (cur->snachandler(sess, cur, rx, &snac, rx->data, rx->commandlen)) - return 1; + if (aim_gettlv(tlvlist, 0x000b, 1)) + msg = aim_gettlv_str(tlvlist, 0x000b, 1); + + if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) + ret = userfunc(sess, fr, code, msg); - } + aim_freetlvchain(&tlvlist); - return 0; + free(msg); + + return ret; } /* * Bleck functions get called when there's no non-bleck functions * around to cleanup the mess... */ -faim_internal int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...) +faim_internal int bleck(aim_session_t *sess, aim_frame_t *frame, ...) { - u_short family; - u_short subtype; - - u_short maxf; - u_short maxs; + fu16_t family, subtype; + fu16_t maxf, maxs; - /* XXX: this is ugly. and big just for debugging. */ - char *literals[14][25] = { - {"Invalid", - NULL - }, - {"General", - "Invalid", - "Error", - "Client Ready", - "Server Ready", - "Service Request", - "Redirect", - "Rate Information Request", - "Rate Information", - "Rate Information Ack", - NULL, - "Rate Information Change", - "Server Pause", - NULL, - "Server Resume", - "Request Personal User Information", - "Personal User Information", - "Evil Notification", - NULL, - "Migration notice", - "Message of the Day", - "Set Privacy Flags", - "Well Known URL", - "NOP" - }, - {"Location", - "Invalid", - "Error", - "Request Rights", - "Rights Information", - "Set user information", - "Request User Information", - "User Information", - "Watcher Sub Request", - "Watcher Notification" - }, - {"Buddy List Management", - "Invalid", - "Error", - "Request Rights", - "Rights Information", - "Add Buddy", - "Remove Buddy", - "Watcher List Query", - "Watcher List Response", - "Watcher SubRequest", - "Watcher Notification", - "Reject Notification", - "Oncoming Buddy", - "Offgoing Buddy" - }, - {"Messeging", - "Invalid", - "Error", - "Add ICBM Parameter", - "Remove ICBM Parameter", - "Request Parameter Information", - "Parameter Information", - "Outgoing Message", - "Incoming Message", - "Evil Request", - "Evil Reply", - "Missed Calls", - "Message Error", - "Host Ack" - }, - {"Advertisements", - "Invalid", - "Error", - "Request Ad", - "Ad Data (GIFs)" - }, - {"Invitation / Client-to-Client", - "Invalid", - "Error", - "Invite a Friend", - "Invitation Ack" - }, - {"Administrative", - "Invalid", - "Error", - "Information Request", - "Information Reply", - "Information Change Request", - "Information Chat Reply", - "Account Confirm Request", - "Account Confirm Reply", - "Account Delete Request", - "Account Delete Reply" - }, - {"Popups", - "Invalid", - "Error", - "Display Popup" - }, - {"BOS", - "Invalid", - "Error", - "Request Rights", - "Rights Response", - "Set group permission mask", - "Add permission list entries", - "Delete permission list entries", - "Add deny list entries", - "Delete deny list entries", - "Server Error" - }, - {"User Lookup", - "Invalid", - "Error", - "Search Request", - "Search Response" - }, - {"Stats", - "Invalid", - "Error", - "Set minimum report interval", - "Report Events" - }, - {"Translate", - "Invalid", - "Error", - "Translate Request", - "Translate Reply", - }, - {"Chat Navigation", - "Invalid", - "Error", - "Request rights", - "Request Exchange Information", - "Request Room Information", - "Request Occupant List", - "Search for Room", - "Outgoing Message", - "Incoming Message", - "Evil Request", - "Evil Reply", - "Chat Error", - } - }; + static const char *channels[6] = { + "Invalid (0)", + "FLAP Version", + "SNAC", + "Invalid (3)", + "Negotiation", + "FLAP NOP" + }; + static const int maxchannels = 5; + + /* XXX: this is ugly. and big just for debugging. */ + static const char *literals[14][25] = { + {"Invalid", + NULL + }, + {"General", + "Invalid", + "Error", + "Client Ready", + "Server Ready", + "Service Request", + "Redirect", + "Rate Information Request", + "Rate Information", + "Rate Information Ack", + NULL, + "Rate Information Change", + "Server Pause", + NULL, + "Server Resume", + "Request Personal User Information", + "Personal User Information", + "Evil Notification", + NULL, + "Migration notice", + "Message of the Day", + "Set Privacy Flags", + "Well Known URL", + "NOP" + }, + {"Location", + "Invalid", + "Error", + "Request Rights", + "Rights Information", + "Set user information", + "Request User Information", + "User Information", + "Watcher Sub Request", + "Watcher Notification" + }, + {"Buddy List Management", + "Invalid", + "Error", + "Request Rights", + "Rights Information", + "Add Buddy", + "Remove Buddy", + "Watcher List Query", + "Watcher List Response", + "Watcher SubRequest", + "Watcher Notification", + "Reject Notification", + "Oncoming Buddy", + "Offgoing Buddy" + }, + {"Messeging", + "Invalid", + "Error", + "Add ICBM Parameter", + "Remove ICBM Parameter", + "Request Parameter Information", + "Parameter Information", + "Outgoing Message", + "Incoming Message", + "Evil Request", + "Evil Reply", + "Missed Calls", + "Message Error", + "Host Ack" + }, + {"Advertisements", + "Invalid", + "Error", + "Request Ad", + "Ad Data (GIFs)" + }, + {"Invitation / Client-to-Client", + "Invalid", + "Error", + "Invite a Friend", + "Invitation Ack" + }, + {"Administrative", + "Invalid", + "Error", + "Information Request", + "Information Reply", + "Information Change Request", + "Information Chat Reply", + "Account Confirm Request", + "Account Confirm Reply", + "Account Delete Request", + "Account Delete Reply" + }, + {"Popups", + "Invalid", + "Error", + "Display Popup" + }, + {"BOS", + "Invalid", + "Error", + "Request Rights", + "Rights Response", + "Set group permission mask", + "Add permission list entries", + "Delete permission list entries", + "Add deny list entries", + "Delete deny list entries", + "Server Error" + }, + {"User Lookup", + "Invalid", + "Error", + "Search Request", + "Search Response" + }, + {"Stats", + "Invalid", + "Error", + "Set minimum report interval", + "Report Events" + }, + {"Translate", + "Invalid", + "Error", + "Translate Request", + "Translate Reply", + }, + {"Chat Navigation", + "Invalid", + "Error", + "Request rights", + "Request Exchange Information", + "Request Room Information", + "Request Occupant List", + "Search for Room", + "Outgoing Message", + "Incoming Message", + "Evil Request", + "Evil Reply", + "Chat Error", + } + }; - maxf = sizeof(literals) / sizeof(literals[0]); - maxs = sizeof(literals[0]) / sizeof(literals[0][0]); + maxf = sizeof(literals) / sizeof(literals[0]); + maxs = sizeof(literals[0]) / sizeof(literals[0][0]); - family = aimutil_get16(workingPtr->data+0); - subtype= aimutil_get16(workingPtr->data+2); + if (frame->hdr.flap.type == 0x02) { - if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL)) - faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]); - else - faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (no literal)\n",family,subtype); + family = aimbs_get16(&frame->data); + subtype = aimbs_get16(&frame->data); + + if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL)) + faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->hdr.flap.type], family, subtype, literals[family][subtype+1]); + else + faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->hdr.flap.type], family, subtype); + } else { - return 1; + if (frame->hdr.flap.type <= maxchannels) + faimdprintf(sess, 0, "bleck: channel %s (0x%02x)\n", channels[frame->hdr.flap.type], frame->hdr.flap.type); + else + faimdprintf(sess, 0, "bleck: unknown channel 0x%02x\n", frame->hdr.flap.type); + + } + + return 1; } -faim_export int aim_conn_addhandler(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short family, - u_short type, - aim_rxcallback_t newhandler, - u_short flags) +faim_export int aim_conn_addhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_rxcallback_t newhandler, fu16_t flags) { - struct aim_rxcblist_t *newcb; + struct aim_rxcblist_s *newcb; + + if (!conn) + return -1; - if (!conn) - return -1; + faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type); - faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type); + if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s)))) + return -1; - if (!(newcb = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t)))) - return -1; - newcb->family = family; - newcb->type = type; - newcb->flags = flags; - if (!newhandler) - newcb->handler = &bleck; - else - newcb->handler = newhandler; - newcb->next = NULL; - - if (!conn->handlerlist) - conn->handlerlist = newcb; - else { - struct aim_rxcblist_t *cur; + newcb->family = family; + newcb->type = type; + newcb->flags = flags; + newcb->handler = newhandler ? newhandler : bleck; + newcb->next = NULL; - cur = conn->handlerlist; + if (!conn->handlerlist) + conn->handlerlist = (void *)newcb; + else { + struct aim_rxcblist_s *cur; - while (cur->next) - cur = cur->next; - cur->next = newcb; - } + for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next) + ; + cur->next = newcb; + } - return 0; + return 0; } -faim_export int aim_clearhandlers(struct aim_conn_t *conn) +faim_export int aim_clearhandlers(aim_conn_t *conn) { - struct aim_rxcblist_t *cur; + struct aim_rxcblist_s *cur; - if (!conn) - return -1; + if (!conn) + return -1; - for (cur = conn->handlerlist; cur; ) { - struct aim_rxcblist_t *tmp; + for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) { + struct aim_rxcblist_s *tmp; - tmp = cur->next; - free(cur); - cur = tmp; - } - conn->handlerlist = NULL; + tmp = cur->next; + free(cur); + cur = tmp; + } + conn->handlerlist = NULL; - return 0; + return 0; } -faim_internal aim_rxcallback_t aim_callhandler(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned short family, - unsigned short type) +faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type) { - struct aim_rxcblist_t *cur; + struct aim_rxcblist_s *cur; - if (!conn) - return NULL; + if (!conn) + return NULL; + + faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type); - faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type); - - for (cur = conn->handlerlist; cur; cur = cur->next) { - if ((cur->family == family) && (cur->type == type)) - return cur->handler; - } + for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) { + if ((cur->family == family) && (cur->type == type)) + return cur->handler; + } - if (type == AIM_CB_SPECIAL_DEFAULT) { - faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family); - return NULL; /* prevent infinite recursion */ - } + if (type == AIM_CB_SPECIAL_DEFAULT) { + faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family); + return NULL; /* prevent infinite recursion */ + } - faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type); + faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type); - return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT); + return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT); } -faim_internal int aim_callhandler_noparam(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short family, - u_short type, - struct command_rx_struct *ptr) +faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src) { - aim_rxcallback_t userfunc = NULL; - userfunc = aim_callhandler(sess, conn, family, type); - if (userfunc) - return userfunc(sess, ptr); - return 1; /* XXX */ + struct aim_rxcblist_s *cur; + + for (cur = (struct aim_rxcblist_s *)src->handlerlist; cur; cur = cur->next) { + aim_conn_addhandler(sess, dest, cur->family, cur->type, + cur->handler, cur->flags); + } + + return; +} + +faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn,fu16_t family, fu16_t type, aim_frame_t *ptr) +{ + aim_rxcallback_t userfunc; + + if ((userfunc = aim_callhandler(sess, conn, family, type))) + return userfunc(sess, ptr); + + return 1; /* XXX */ } /* - aim_rxdispatch() - - Basically, heres what this should do: - 1) Determine correct packet handler for this packet - 2) Mark the packet handled (so it can be dequeued in purge_queue()) - 3) Send the packet to the packet handler - 4) Go to next packet in the queue and start over - 5) When done, run purge_queue() to purge handled commands - - Note that any unhandlable packets should probably be left in the - queue. This is the best way to prevent data loss. This means - that a single packet may get looked at by this function multiple - times. This is more good than bad! This behavior may change. - - Aren't queue's fun? - - TODO: Get rid of all the ugly if's. - TODO: Clean up. - TODO: More support for mid-level handlers. - TODO: Allow for NULL handlers. - + * aim_rxdispatch() + * + * Basically, heres what this should do: + * 1) Determine correct packet handler for this packet + * 2) Mark the packet handled (so it can be dequeued in purge_queue()) + * 3) Send the packet to the packet handler + * 4) Go to next packet in the queue and start over + * 5) When done, run purge_queue() to purge handled commands + * + * TODO: Clean up. + * TODO: More support for mid-level handlers. + * TODO: Allow for NULL handlers. + * */ -faim_export int aim_rxdispatch(struct aim_session_t *sess) +faim_export void aim_rxdispatch(aim_session_t *sess) { - int i = 0; - struct command_rx_struct *workingPtr = NULL; - static int critical = 0; - - if (critical) - return 0; /* don't call recursively! */ + int i; + aim_frame_t *cur; - critical = 1; + for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) { + + /* + * XXX: This is still fairly ugly. + */ - if (sess->queue_incoming == NULL) { - faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n"); - } else { - workingPtr = sess->queue_incoming; - for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) { - unsigned short family,subtype; + if (cur->handled) + continue; - /* - * XXX: This is still fairly ugly. - */ - if (workingPtr->handled) - continue; + /* + * This is a debugging/sanity check only and probably + * could/should be removed for stable code. + */ + if (((cur->hdrtype == AIM_FRAMETYPE_OFT) && + (cur->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || + ((cur->hdrtype == AIM_FRAMETYPE_FLAP) && + (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) { + faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", cur->hdrtype, cur->conn->type); + cur->handled = 1; + continue; + } - /* - * This is a debugging/sanity check only and probably could/should be removed - * for stable code. - */ - if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) && - (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || - ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) && - (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) { - faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type); - workingPtr->handled = 1; - continue; - } + if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) { + if (cur->hdrtype != AIM_FRAMETYPE_OFT) { + faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n"); + cur->handled = 1; /* get rid of it */ + } else { + /* XXX: implement this */ + faimdprintf(sess, 0, "faim: OFT frame!\n"); + cur->handled = 1; /* get rid of it */ + } + continue; + } - if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS) { - /* make sure that we only get OFT frames on these connections */ - if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) { - faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n"); - workingPtr->handled = 1; /* get rid of it */ - } else { - /* XXX: implement this */ - faimdprintf(sess, 0, "faim: OFT frame!\n"); - workingPtr->handled = 1; /* get rid of it */ - } - continue; - } + if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { + /* not possible */ + faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n"); + cur->handled = 1; + continue; + } - if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { - /* not possible */ - faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n"); - workingPtr->handled = 1; - continue; - } + if (cur->hdr.flap.type == 0x01) { + + cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */ + + continue; + + } else if (cur->hdr.flap.type == 0x02) { - if ((workingPtr->commandlen == 4) && - (aimutil_get32(workingPtr->data) == 0x00000001)) { - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr); - continue; - } + if ((cur->handled = consumesnac(sess, cur))) + continue; - if (workingPtr->hdr.oscar.type == 0x04) { - workingPtr->handled = aim_negchan_middle(sess, workingPtr); - continue; - } + } else if (cur->hdr.flap.type == 0x04) { - if ((workingPtr->handled = consumesnac(sess, workingPtr))) - continue; - - if (!workingPtr->handled) { - family = aimutil_get16(workingPtr->data); - subtype = aimutil_get16(workingPtr->data+2); + cur->handled = negchan_middle(sess, cur); + continue; - faimdprintf(sess, 1, "warning: unhandled packet %04x/%04x\n", family, subtype); - consumenonsnac(sess, workingPtr, 0xffff, 0xffff); /* last chance! */ - workingPtr->handled = 1; - } - } - } + } else if (cur->hdr.flap.type == 0x05) + ; + + if (!cur->handled) { + consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */ + cur->handled = 1; + } + } - /* - * This doesn't have to be called here. It could easily be done - * by a seperate thread or something. It's an administrative operation, - * and can take a while. Though the less you call it the less memory - * you'll have :) - */ - aim_purge_rxqueue(sess); + /* + * This doesn't have to be called here. It could easily be done + * by a seperate thread or something. It's an administrative operation, + * and can take a while. Though the less you call it the less memory + * you'll have :) + */ + aim_purge_rxqueue(sess); - critical = 0; - - return 0; + return; } -faim_internal int aim_parse_unknown(struct aim_session_t *sess, - struct command_rx_struct *command, ...) +faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...) { - u_int i = 0; + int i; - if (!sess || !command) - return 1; - - faimdprintf(sess, 1, "\nRecieved unknown packet:"); + faimdprintf(sess, 1, "\nRecieved unknown packet:"); - for (i = 0; i < command->commandlen; i++) - { - if ((i % 8) == 0) - faimdprintf(sess, 1, "\n\t"); + for (i = 0; aim_bstream_empty(&frame->data); i++) { + if ((i % 8) == 0) + faimdprintf(sess, 1, "\n\t"); - faimdprintf(sess, 1, "0x%2x ", command->data[i]); - } - - faimdprintf(sess, 1, "\n\n"); + faimdprintf(sess, 1, "0x%2x ", aimbs_get8(&frame->data)); + } - return 1; + faimdprintf(sess, 1, "\n\n"); + + return 1; } -faim_internal int aim_negchan_middle(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - struct aim_tlvlist_t *tlvlist; - char *msg = NULL; - unsigned short code = 0; - aim_rxcallback_t userfunc = NULL; - int ret = 1; - /* Used only by the older login protocol */ - /* XXX remove this special case? */ - if (command->conn->type == AIM_CONN_TYPE_AUTH) - return consumenonsnac(sess, command, 0x0017, 0x0003); - - tlvlist = aim_readtlvchain(command->data, command->commandlen); - - if (aim_gettlv(tlvlist, 0x0009, 1)) - code = aim_gettlv16(tlvlist, 0x0009, 1); - - if (aim_gettlv(tlvlist, 0x000b, 1)) - msg = aim_gettlv_str(tlvlist, 0x000b, 1); - - if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) - ret = userfunc(sess, command, code, msg); - - aim_freetlvchain(&tlvlist); - - if (msg) - free(msg); - - return ret; -} - diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/rxqueue.c --- a/src/protocols/oscar/rxqueue.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/rxqueue.c Sun Sep 09 10:07:14 2001 +0000 @@ -14,161 +14,389 @@ #endif /* - * Since not all implementations support MSG_WAITALL, define - * an alternate guarenteed read function... - * - * We keep recv() for systems that can do it because it means - * a single system call for the entire packet, where read may - * take more for a badly fragmented packet. * */ faim_internal int aim_recv(int fd, void *buf, size_t count) { -#ifdef MSG_WAITALL - return recv(fd, buf, count, MSG_WAITALL); -#else - int left, ret, cur = 0; + int left, cur; + + for (cur = 0, left = count; left; ) { + int ret; + + ret = recv(fd, ((unsigned char *)buf)+cur, left, 0); + if (ret == -1) + return -1; + else if (ret == 0) + return cur; + + cur += ret; + left -= ret; + } + + return cur; +} + +/* + * Read into a byte stream. Will not read more than count, but may read + * less if there is not enough room in the stream buffer. + */ +faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count) +{ + int red = 0; + + if (!bs || (fd < 0) || (count < 0)) + return -1; + + if (count > (bs->len - bs->offset)) + count = bs->len - bs->offset; /* truncate to remaining space */ + + if (count) { + + red = aim_recv(fd, bs->data + bs->offset, count); + + if (red <= 0) + return -1; + } + + bs->offset += red; + + return red; +} + +faim_internal int aim_bstream_init(aim_bstream_t *bs, fu8_t *data, int len) +{ + + if (!bs) + return -1; + + bs->data = data; + bs->len = len; + bs->offset = 0; + + return 0; +} - left = count; +faim_internal int aim_bstream_empty(aim_bstream_t *bs) +{ + return bs->len - bs->offset; +} + +faim_internal int aim_bstream_curpos(aim_bstream_t *bs) +{ + return bs->offset; +} + +faim_internal int aim_bstream_setpos(aim_bstream_t *bs, int off) +{ + + if (off > bs->len) + return -1; + + bs->offset = off; + + return off; +} + +faim_internal void aim_bstream_rewind(aim_bstream_t *bs) +{ + + aim_bstream_setpos(bs, 0); + + return; +} + +faim_internal int aim_bstream_advance(aim_bstream_t *bs, int n) +{ + + if (aim_bstream_empty(bs) < n) + return 0; /* XXX throw an exception */ + + bs->offset += n; + + return n; +} + +faim_internal fu8_t aimbs_get8(aim_bstream_t *bs) +{ + + if (aim_bstream_empty(bs) < 1) + return 0; /* XXX throw an exception */ + + bs->offset++; + + return aimutil_get8(bs->data + bs->offset - 1); +} + +faim_internal fu16_t aimbs_get16(aim_bstream_t *bs) +{ + + if (aim_bstream_empty(bs) < 2) + return 0; /* XXX throw an exception */ + + bs->offset += 2; + + return aimutil_get16(bs->data + bs->offset - 2); +} - while (left) { - ret = recv(fd, ((unsigned char *)buf)+cur, left, 0); - if (ret == -1) - return -1; - if (ret == 0) - return cur; - - cur += ret; - left -= ret; - } +faim_internal fu32_t aimbs_get32(aim_bstream_t *bs) +{ + + if (aim_bstream_empty(bs) < 4) + return 0; /* XXX throw an exception */ + + bs->offset += 4; + + return aimutil_get32(bs->data + bs->offset - 4); +} + +faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v) +{ + + if (aim_bstream_empty(bs) < 1) + return 0; /* XXX throw an exception */ + + bs->offset += aimutil_put8(bs->data + bs->offset, v); + + return 1; +} + +faim_internal int aimbs_put16(aim_bstream_t *bs, fu16_t v) +{ + + if (aim_bstream_empty(bs) < 2) + return 0; /* XXX throw an exception */ + + bs->offset += aimutil_put16(bs->data + bs->offset, v); + + return 2; +} + +faim_internal int aimbs_put32(aim_bstream_t *bs, fu32_t v) +{ + + if (aim_bstream_empty(bs) < 4) + return 0; /* XXX throw an exception */ + + bs->offset += aimutil_put32(bs->data + bs->offset, v); + + return 1; +} + +faim_internal int aimbs_getrawbuf(aim_bstream_t *bs, fu8_t *buf, int len) +{ + + if (aim_bstream_empty(bs) < len) + return 0; + + memcpy(buf, bs->data + bs->offset, len); + bs->offset += len; + + return len; +} + +faim_internal fu8_t *aimbs_getraw(aim_bstream_t *bs, int len) +{ + fu8_t *ob; + + if (!(ob = malloc(len))) + return NULL; + + if (aimbs_getrawbuf(bs, ob, len) < len) { + free(ob); + return NULL; + } - return cur; -#endif + return ob; +} + +faim_internal char *aimbs_getstr(aim_bstream_t *bs, int len) +{ + char *ob; + + if (!(ob = malloc(len+1))) + return NULL; + + if (aimbs_getrawbuf(bs, ob, len) < len) { + free(ob); + return NULL; + } + + ob[len] = '\0'; + + return ob; +} + +faim_internal int aimbs_putraw(aim_bstream_t *bs, const fu8_t *v, int len) +{ + + if (aim_bstream_empty(bs) < len) + return 0; /* XXX throw an exception */ + + memcpy(bs->data + bs->offset, v, len); + bs->offset += len; + + return len; } +faim_internal int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len) +{ + + if (aim_bstream_empty(srcbs) < len) + return 0; /* XXX throw exception (underrun) */ + + if (aim_bstream_empty(bs) < len) + return 0; /* XXX throw exception (overflow) */ + + memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len); + bs->offset += len; + srcbs->offset += len; + + return len; +} + +/** + * aim_frame_destroy - free aim_frame_t + * @frame: the frame to free + * + * returns -1 on error; 0 on success. + * + */ +faim_internal void aim_frame_destroy(aim_frame_t *frame) +{ + + free(frame->data.data); /* XXX aim_bstream_free */ + + if (frame->hdrtype == AIM_FRAMETYPE_OFT) + free(frame->hdr.oft.hdr2); + free(frame); + + return; +} + + /* * Grab a single command sequence off the socket, and enqueue * it in the incoming event queue in a seperate struct. */ -faim_export int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn) { - unsigned char generic[6]; - struct command_rx_struct *newrx = NULL; + fu8_t flaphdr_raw[6]; + aim_bstream_t flaphdr; + aim_frame_t *newrx; + fu16_t payloadlen; + + if (!sess || !conn) + return 0; - if (!sess || !conn) - return 0; + if (conn->fd == -1) + return -1; /* its a aim_conn_close()'d connection */ - if (conn->fd == -1) - return -1; /* its a aim_conn_close()'d connection */ + if (conn->fd < 3) /* can happen when people abuse the interface */ + return 0; + + if (conn->status & AIM_CONN_STATUS_INPROGRESS) + return aim_conn_completeconnect(sess, conn); - if (conn->fd < 3) /* can happen when people abuse the interface */ - return 0; - - if (conn->status & AIM_CONN_STATUS_INPROGRESS) - return aim_conn_completeconnect(sess, conn); + /* + * Rendezvous (client-client) connections do not speak + * FLAP, so this function will break on them. + */ + if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) + return aim_get_command_rendezvous(sess, conn); + else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { + faimdprintf(sess, 0, "AIM_CONN_TYPE_RENDEZVOUS_OUT on fd %d\n", conn->fd); + return 0; + } - /* - * Rendezvous (client-client) connections do not speak - * FLAP, so this function will break on them. - */ - if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) - return aim_get_command_rendezvous(sess, conn); - if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { - faimdprintf(sess, 0, "out on fd %d\n", conn->fd); - return 0; - } + aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw)); - /* - * Read FLAP header. Six bytes: - * - * 0 char -- Always 0x2a - * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. - * 2 short -- Sequence number - * 4 short -- Number of data bytes that follow. - */ - faim_mutex_lock(&conn->active); - if (aim_recv(conn->fd, generic, 6) < 6){ - aim_conn_close(conn); - faim_mutex_unlock(&conn->active); - return -1; - } + /* + * Read FLAP header. Six bytes: + * + * 0 char -- Always 0x2a + * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. + * 2 short -- Sequence number + * 4 short -- Number of data bytes that follow. + */ + faim_mutex_lock(&conn->active); + if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) { + aim_conn_close(conn); + faim_mutex_unlock(&conn->active); + return -1; + } - /* - * This shouldn't happen unless the socket breaks, the server breaks, - * or we break. We must handle it just in case. - */ - if (generic[0] != 0x2a) { - faimdprintf(sess, 1, "Bad incoming data!"); - aim_conn_close(conn); - faim_mutex_unlock(&conn->active); - return -1; - } + aim_bstream_rewind(&flaphdr); + + /* + * This shouldn't happen unless the socket breaks, the server breaks, + * or we break. We must handle it just in case. + */ + if (aimbs_get8(&flaphdr) != 0x2a) { + faimdprintf(sess, 0, "FLAP framing disrupted"); + aim_conn_close(conn); + faim_mutex_unlock(&conn->active); + return -1; + } - /* allocate a new struct */ - if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) { - faim_mutex_unlock(&conn->active); - return -1; - } - memset(newrx, 0x00, sizeof(struct command_rx_struct)); - - newrx->lock = 1; /* lock the struct */ - - /* we're doing OSCAR if we're here */ - newrx->hdrtype = AIM_FRAMETYPE_OSCAR; - - /* store channel -- byte 2 */ - newrx->hdr.oscar.type = (char) generic[1]; + /* allocate a new struct */ + if (!(newrx = (aim_frame_t *)malloc(sizeof(aim_frame_t)))) { + faim_mutex_unlock(&conn->active); + return -1; + } + memset(newrx, 0, sizeof(aim_frame_t)); - /* store seqnum -- bytes 3 and 4 */ - newrx->hdr.oscar.seqnum = aimutil_get16(generic+2); + /* we're doing FLAP if we're here */ + newrx->hdrtype = AIM_FRAMETYPE_FLAP; + + newrx->hdr.flap.type = aimbs_get8(&flaphdr); + newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr); + payloadlen = aimbs_get16(&flaphdr); - /* store commandlen -- bytes 5 and 6 */ - newrx->commandlen = aimutil_get16(generic+4); + newrx->nofree = 0; /* free by default */ - newrx->nofree = 0; /* free by default */ + if (payloadlen) { + fu8_t *payload = NULL; - /* malloc for data portion */ - if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) { - free(newrx); - faim_mutex_unlock(&conn->active); - return -1; - } + if (!(payload = (fu8_t *) malloc(payloadlen))) { + aim_frame_destroy(newrx); + faim_mutex_unlock(&conn->active); + return -1; + } + + aim_bstream_init(&newrx->data, payload, payloadlen); - /* read the data portion of the packet */ - if (aim_recv(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){ - free(newrx->data); - free(newrx); - aim_conn_close(conn); - faim_mutex_unlock(&conn->active); - return -1; - } - faim_mutex_unlock(&conn->active); + /* read the payload */ + if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) { + free(payload); + aim_frame_destroy(newrx); + aim_conn_close(conn); + faim_mutex_unlock(&conn->active); + return -1; + } + } else + aim_bstream_init(&newrx->data, NULL, 0); - newrx->conn = conn; + faim_mutex_unlock(&conn->active); - newrx->next = NULL; /* this will always be at the bottom */ - newrx->lock = 0; /* unlock */ + aim_bstream_rewind(&newrx->data); - /* enqueue this packet */ - if (sess->queue_incoming == NULL) { - sess->queue_incoming = newrx; - } else { - struct command_rx_struct *cur; + newrx->conn = conn; + + newrx->next = NULL; /* this will always be at the bottom */ + + if (!sess->queue_incoming) + sess->queue_incoming = newrx; + else { + aim_frame_t *cur; - /* - * This append operation takes a while. It might be faster - * if we maintain a pointer to the last entry in the queue - * and just update that. Need to determine if the overhead - * to maintain that is lower than the overhead for this loop. - */ - for (cur = sess->queue_incoming; cur->next; cur = cur->next) - ; - cur->next = newrx; - } - - newrx->conn->lastactivity = time(NULL); + for (cur = sess->queue_incoming; cur->next; cur = cur->next) + ; + cur->next = newrx; + } - return 0; + newrx->conn->lastactivity = time(NULL); + + return 0; } /* @@ -182,55 +410,23 @@ * does not keep a pointer, it's lost forever. * */ -faim_export void aim_purge_rxqueue(struct aim_session_t *sess) +faim_export void aim_purge_rxqueue(aim_session_t *sess) { - struct command_rx_struct *cur = NULL; - struct command_rx_struct *tmp; + aim_frame_t *cur, **prev; - if (sess->queue_incoming == NULL) - return; - - if (sess->queue_incoming->next == NULL) { - if (sess->queue_incoming->handled) { - tmp = sess->queue_incoming; - sess->queue_incoming = NULL; - - if (!tmp->nofree) { - if (tmp->hdrtype == AIM_FRAMETYPE_OFT) - free(tmp->hdr.oft.hdr2); - free(tmp->data); - free(tmp); - } else - tmp->next = NULL; - } - return; - } + for (prev = &sess->queue_incoming; (cur = *prev); ) { + if (cur->handled) { - for(cur = sess->queue_incoming; cur->next != NULL; ) { - if (cur->next->handled) { - tmp = cur->next; - cur->next = tmp->next; - if (!tmp->nofree) { - if (tmp->hdrtype == AIM_FRAMETYPE_OFT) - free(tmp->hdr.oft.hdr2); - free(tmp->data); - free(tmp); - } else - tmp->next = NULL; - } - cur = cur->next; + *prev = cur->next; + + if (!cur->nofree) + aim_frame_destroy(cur); - /* - * Be careful here. Because of the way we just - * manipulated the pointer, cur may be NULL and - * the for() will segfault doing the check unless - * we find this case first. - */ - if (cur == NULL) - break; - } + } else + prev = &cur->next; + } - return; + return; } /* @@ -240,13 +436,14 @@ * XXX: this is something that was handled better in the old connection * handling method, but eh. */ -faim_internal void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn) { - struct command_rx_struct *currx; + aim_frame_t *currx; - for (currx = sess->queue_incoming; currx; currx = currx->next) { - if ((!currx->handled) && (currx->conn == conn)) - currx->handled = 1; - } - return; + for (currx = sess->queue_incoming; currx; currx = currx->next) { + if ((!currx->handled) && (currx->conn == conn)) + currx->handled = 1; + } + return; } + diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/search.c --- a/src/protocols/oscar/search.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/search.c Sun Sep 09 10:07:14 2001 +0000 @@ -9,124 +9,112 @@ #define FAIM_INTERNAL #include -faim_export unsigned long aim_usersearch_address(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *address) +faim_export int aim_usersearch_address(aim_session_t *sess, aim_conn_t *conn, const char *address) { - struct command_tx_struct *newpacket; - - if (!address) - return -1; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+strlen(address)))) - return -1; + if (!sess || !conn || !address) + return -EINVAL; - newpacket->lock = 1; - - aim_putsnac(newpacket->data, 0x000a, 0x0002, 0x0000, sess->snac_nextid); - - aimutil_putstr(newpacket->data+10, address, strlen(address)); + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+strlen(address)))) + return -ENOMEM; - aim_tx_enqueue(sess, newpacket); + snacid = aim_cachesnac(sess, 0x000a, 0x0002, 0x0000, strdup(address), strlen(address)+1); + aim_putsnac(&fr->data, 0x000a, 0x0002, 0x0000, snacid); + + aimbs_putraw(&fr->data, address, strlen(address)); - aim_cachesnac(sess, 0x000a, 0x0002, 0x0000, address, strlen(address)+1); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid; + return 0; } /* 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) +static int error(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - int ret = 0; - aim_rxcallback_t userfunc; - struct aim_snac_t *snac2; - - /* XXX the modules interface should have already retrieved this for us */ - if(!(snac2 = aim_remsnac(sess, snac->id))) { - faimdprintf(sess, 2, "couldn't get a snac for 0x%08lx\n", snac->id); - return 0; - } + int ret = 0; + aim_rxcallback_t userfunc; + aim_snac_t *snac2; - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, snac2->data /* address */); + /* XXX the modules interface should have already retrieved this for us */ + if (!(snac2 = aim_remsnac(sess, snac->id))) { + faimdprintf(sess, 2, "search error: couldn't get a snac for 0x%08lx\n", snac->id); + return 0; + } - /* XXX freesnac()? */ - if (snac2) { - if(snac2->data) - free(snac2->data); - free(snac2); - } + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, snac2->data /* address */); - return ret; + /* XXX freesnac()? */ + if (snac2) + free(snac2->data); + free(snac2); + + return ret; } -static int reply(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int reply(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - unsigned int j, m, ret = 0; - struct aim_tlvlist_t *tlvlist; - char *cur = NULL, *buf = NULL; - aim_rxcallback_t userfunc; - struct aim_snac_t *snac2; + int j = 0, m, ret = 0; + aim_tlvlist_t *tlvlist; + char *cur = NULL, *buf = NULL; + aim_rxcallback_t userfunc; + aim_snac_t *snac2; + char *searchaddr = NULL; - if (!(snac2 = aim_remsnac(sess, snac->id))) { - faimdprintf(sess, 2, "faim: couldn't get a snac for 0x%08lx\n", snac->id); - return 0; - } + if ((snac2 = aim_remsnac(sess, snac->id))) + searchaddr = (char *)snac2->data; - if (!(tlvlist = aim_readtlvchain(data, datalen))) - return 0; + tlvlist = aim_readtlvchain(bs); + m = aim_counttlvchain(&tlvlist); - j = 0; - - m = aim_counttlvchain(&tlvlist); + /* XXX uhm. */ + while ((cur = aim_gettlv_str(tlvlist, 0x0001, j+1)) && j < m) { + buf = realloc(buf, (j+1) * (MAXSNLEN+1)); - while((cur = aim_gettlv_str(tlvlist, 0x0001, j+1)) && j < m) { - if(!(buf = realloc(buf, (j+1) * (MAXSNLEN+1)))) - faimdprintf(sess, 2, "faim: couldn't realloc buf. oh well.\n"); + strncpy(&buf[j * (MAXSNLEN+1)], cur, MAXSNLEN); + free(cur); - strncpy(&buf[j * (MAXSNLEN+1)], cur, MAXSNLEN); - free(cur); + j++; + } - j++; - } - - aim_freetlvchain(&tlvlist); + aim_freetlvchain(&tlvlist); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, snac2->data /* address */, j, buf); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, searchaddr, j, buf); - /* XXX freesnac()? */ - if(snac2) { - if(snac2->data) - free(snac2->data); - free(snac2); - } + /* XXX freesnac()? */ + if (snac2) + free(snac2->data); + free(snac2); - if(buf) - free(buf); + free(buf); - return ret; + 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) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0001) - return error(sess, mod, rx, snac, data, datalen); - else if (snac->subtype == 0x0003) - return reply(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0001) + return error(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0003) + return reply(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int search_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int search_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x000a; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "search", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x000a; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "search", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } + + diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/snac.c --- a/src/protocols/oscar/snac.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/snac.c Sun Sep 09 10:07:14 2001 +0000 @@ -18,68 +18,62 @@ /* * Called from aim_session_init() to initialize the hash. */ -faim_internal void aim_initsnachash(struct aim_session_t *sess) +faim_internal void aim_initsnachash(aim_session_t *sess) { - int i; + int i; - for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) { - sess->snac_hash[i] = NULL; - faim_mutex_init(&sess->snac_hash_locks[i]); - } + for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) { + sess->snac_hash[i] = NULL; + faim_mutex_init(&sess->snac_hash_locks[i]); + } - return; + return; } -faim_internal unsigned long aim_cachesnac(struct aim_session_t *sess, - const unsigned short family, - const unsigned short type, - const unsigned short flags, - const void *data, const int datalen) +faim_internal aim_snacid_t aim_cachesnac(aim_session_t *sess, const fu16_t family, const fu16_t type, const fu16_t flags, const void *data, const int datalen) { - struct aim_snac_t snac; + aim_snac_t snac; + + snac.id = sess->snacid_next++; + snac.family = family; + snac.type = type; + snac.flags = flags; - snac.id = sess->snac_nextid++; - snac.family = family; - snac.type = type; - snac.flags = flags; + if (datalen) { + if (!(snac.data = malloc(datalen))) + return 0; /* er... */ + memcpy(snac.data, data, datalen); + } else + snac.data = NULL; - if (datalen) { - if (!(snac.data = malloc(datalen))) - return 0; /* er... */ - memcpy(snac.data, data, datalen); - } else - snac.data = NULL; - - return aim_newsnac(sess, &snac); + return aim_newsnac(sess, &snac); } /* * Clones the passed snac structure and caches it in the * list/hash. */ -faim_internal unsigned long aim_newsnac(struct aim_session_t *sess, - struct aim_snac_t *newsnac) +faim_internal aim_snacid_t aim_newsnac(aim_session_t *sess, aim_snac_t *newsnac) { - struct aim_snac_t *snac = NULL; - int index; + aim_snac_t *snac; + int index; - if (!newsnac) - return 0; + if (!newsnac) + return 0; - if (!(snac = calloc(1, sizeof(struct aim_snac_t)))) - return 0; - memcpy(snac, newsnac, sizeof(struct aim_snac_t)); - snac->issuetime = time(&snac->issuetime); - snac->next = NULL; + if (!(snac = malloc(sizeof(aim_snac_t)))) + return 0; + memcpy(snac, newsnac, sizeof(aim_snac_t)); + snac->issuetime = time(NULL); + + index = snac->id % FAIM_SNAC_HASH_SIZE; - index = snac->id % FAIM_SNAC_HASH_SIZE; + faim_mutex_lock(&sess->snac_hash_locks[index]); + snac->next = (aim_snac_t *)sess->snac_hash[index]; + sess->snac_hash[index] = (void *)snac; + faim_mutex_unlock(&sess->snac_hash_locks[index]); - faim_mutex_lock(&sess->snac_hash_locks[index]); - snac->next = sess->snac_hash[index]; - sess->snac_hash[index] = snac; - faim_mutex_unlock(&sess->snac_hash_locks[index]); - - return(snac->id); + return snac->id; } /* @@ -89,37 +83,24 @@ * The returned structure must be freed by the caller. * */ -faim_internal struct aim_snac_t *aim_remsnac(struct aim_session_t *sess, - u_long id) +faim_internal aim_snac_t *aim_remsnac(aim_session_t *sess, aim_snacid_t id) { - struct aim_snac_t *cur = NULL; - int index; + aim_snac_t *cur, **prev; + int index; - index = id % FAIM_SNAC_HASH_SIZE; + index = id % FAIM_SNAC_HASH_SIZE; - faim_mutex_lock(&sess->snac_hash_locks[index]); - if (!sess->snac_hash[index]) - ; - else if (sess->snac_hash[index]->id == id) { - cur = sess->snac_hash[index]; - sess->snac_hash[index] = cur->next; - } else { - cur = sess->snac_hash[index]; - while (cur->next) { - if (cur->next->id == id) { - struct aim_snac_t *tmp; - - tmp = cur->next; - cur->next = cur->next->next; - cur = tmp; - break; - } - cur = cur->next; - } - } - faim_mutex_unlock(&sess->snac_hash_locks[index]); + faim_mutex_lock(&sess->snac_hash_locks[index]); + for (prev = (aim_snac_t **)&sess->snac_hash[index]; (cur = *prev); ) { + if (cur->id == id) { + *prev = cur->next; + return cur; + } else + prev = &cur->next; + } + faim_mutex_unlock(&sess->snac_hash_locks[index]); - return cur; + return cur; } /* @@ -129,49 +110,47 @@ * maxage is the _minimum_ age in seconds to keep SNACs. * */ -faim_internal int aim_cleansnacs(struct aim_session_t *sess, - int maxage) +faim_internal void aim_cleansnacs(aim_session_t *sess, int maxage) { - int i; + int i; + + for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) { + aim_snac_t *cur, **prev; + time_t curtime; - for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) { - struct aim_snac_t *cur, **prev; - time_t curtime; + faim_mutex_lock(&sess->snac_hash_locks[i]); + if (!sess->snac_hash[i]) { + faim_mutex_unlock(&sess->snac_hash_locks[i]); + continue; + } - faim_mutex_lock(&sess->snac_hash_locks[i]); - if (!sess->snac_hash[i]) { - faim_mutex_unlock(&sess->snac_hash_locks[i]); - continue; - } - - curtime = time(NULL); /* done here in case we waited for the lock */ + curtime = time(NULL); /* done here in case we waited for the lock */ - for (prev = &sess->snac_hash[i]; (cur = *prev); ) { - if ((curtime - cur->issuetime) > maxage) { + for (prev = (aim_snac_t **)&sess->snac_hash[i]; (cur = *prev); ) { + if ((curtime - cur->issuetime) > maxage) { - *prev = cur->next; + *prev = cur->next; - /* XXX should we have destructors here? */ - if (cur->data) - free(cur->data); - free(cur); + /* XXX should we have destructors here? */ + free(cur->data); + free(cur); - } else - prev = &cur->next; - } + } else + prev = &cur->next; + } + faim_mutex_unlock(&sess->snac_hash_locks[i]); + } - faim_mutex_unlock(&sess->snac_hash_locks[i]); - } - - return 0; + return; } -faim_internal int aim_putsnac(u_char *buf, int family, int subtype, int flags, u_long snacid) +faim_internal int aim_putsnac(aim_bstream_t *bs, fu16_t family, fu16_t subtype, fu16_t flags, aim_snacid_t snacid) { - int curbyte = 0; - curbyte += aimutil_put16(buf+curbyte, (u_short)(family&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (u_short)(subtype&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (u_short)(flags&0xffff)); - curbyte += aimutil_put32(buf+curbyte, snacid); - return curbyte; + + aimbs_put16(bs, family); + aimbs_put16(bs, subtype); + aimbs_put16(bs, flags); + aimbs_put32(bs, snacid); + + return 10; } diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/stats.c --- a/src/protocols/oscar/stats.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/stats.c Sun Sep 09 10:07:14 2001 +0000 @@ -2,36 +2,36 @@ #define FAIM_INTERNAL #include -static int reportinterval(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int reportinterval(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - unsigned short interval; - aim_rxcallback_t userfunc; + fu16_t interval; + aim_rxcallback_t userfunc; - interval = aimutil_get16(data); + interval = aimbs_get16(bs); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - return userfunc(sess, rx, interval); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, interval); - return 0; + 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) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0002) - return reportinterval(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0002) + return reportinterval(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int stats_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int stats_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x000b; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "stats", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x000b; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "stats", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/tlv.c --- a/src/protocols/oscar/tlv.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/tlv.c Sun Sep 09 10:07:14 2001 +0000 @@ -2,6 +2,30 @@ #define FAIM_INTERNAL #include +static aim_tlv_t *createtlv(void) +{ + aim_tlv_t *newtlv; + + if (!(newtlv = (aim_tlv_t *)malloc(sizeof(aim_tlv_t)))) + return NULL; + memset(newtlv, 0, sizeof(aim_tlv_t)); + + return newtlv; +} + +static void freetlv(aim_tlv_t **oldtlv) +{ + + if (!oldtlv || !*oldtlv) + return; + + free((*oldtlv)->value); + free(*oldtlv); + *oldtlv = NULL; + + return; +} + /** * aim_readtlvchain - Read a TLV chain from a buffer. * @buf: Input buffer @@ -12,65 +36,54 @@ * routines. When done with a TLV chain, aim_freetlvchain() should * be called to free the dynamic substructures. * + * XXX There should be a flag setable here to have the tlvlist contain + * bstream references, so that at least the ->value portion of each + * element doesn't need to be malloc/memcpy'd. This could prove to be + * just as effecient as the in-place TLV parsing used in a couple places + * in libfaim. + * */ -faim_export struct aim_tlvlist_t *aim_readtlvchain(const unsigned char *buf, const int maxlen) +faim_export aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs) { - int pos; - struct aim_tlvlist_t *list; - struct aim_tlvlist_t *cur; - - unsigned short type, length; + aim_tlvlist_t *list = NULL, *cur; + fu16_t type, length; - if (!buf) - return NULL; + while (aim_bstream_empty(bs)) { - list = NULL; - - pos = 0; - - while (pos < maxlen) - { - type = aimutil_get16(buf+pos); - pos += 2; + type = aimbs_get16(bs); + length = aimbs_get16(bs); - if (pos < maxlen) - { - length = aimutil_get16(buf+pos); - pos += 2; - - if ((pos+length) <= maxlen) - { - /* - * Okay, so now AOL has decided that any TLV of - * type 0x0013 can only be two bytes, despite - * what the actual given length is. So here - * we dump any invalid TLVs of that sort. Hopefully - * theres no special cases to this special case. - * - mid (30jun2000) - */ - if ((type == 0x0013) && (length != 0x0002)) - length = 0x0002; - else { - cur = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(cur, 0x00, sizeof(struct aim_tlvlist_t)); +#if 0 /* temporarily disabled until I know if they're still doing it or not */ + /* + * Okay, so now AOL has decided that any TLV of + * type 0x0013 can only be two bytes, despite + * what the actual given length is. So here + * we dump any invalid TLVs of that sort. Hopefully + * theres no special cases to this special case. + * - mid (30jun2000) + */ + if ((type == 0x0013) && (length != 0x0002)) + length = 0x0002; +#else + if (0) + ; +#endif + else { - cur->tlv = aim_createtlv(); - cur->tlv->type = type; - cur->tlv->length = length; - if (length) { - cur->tlv->value = (unsigned char *)malloc(length); - memcpy(cur->tlv->value, buf+pos, length); - } + cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)); + memset(cur, 0, sizeof(aim_tlvlist_t)); - cur->next = list; - list = cur; - } - pos += length; - } + cur->tlv = createtlv(); + cur->tlv->type = type; + if ((cur->tlv->length = length)) + cur->tlv->value = aimbs_getraw(bs, length); + + cur->next = list; + list = cur; + } } - } - return list; + return list; } /** @@ -82,23 +95,26 @@ * should be removed before calling this. * */ -faim_export void aim_freetlvchain(struct aim_tlvlist_t **list) +faim_export void aim_freetlvchain(aim_tlvlist_t **list) { - struct aim_tlvlist_t *cur, *cur2; + aim_tlvlist_t *cur; - if (!list || !(*list)) - return; + if (!list || !*list) + return; - cur = *list; - while (cur) - { - aim_freetlv(&cur->tlv); - cur2 = cur->next; - free(cur); - cur = cur2; - } - list = NULL; - return; + for (cur = *list; cur; ) { + aim_tlvlist_t *tmp; + + freetlv(&cur->tlv); + + tmp = cur->next; + free(cur); + cur = tmp; + } + + list = NULL; + + return; } /** @@ -108,18 +124,18 @@ * Returns the number of TLVs stored in the passed chain. * */ -faim_export int aim_counttlvchain(struct aim_tlvlist_t **list) +faim_export int aim_counttlvchain(aim_tlvlist_t **list) { - struct aim_tlvlist_t *cur; - int count = 0; + aim_tlvlist_t *cur; + int count; - if (!list || !(*list)) - return 0; + if (!list || !*list) + return 0; - for (cur = *list; cur; cur = cur->next) - count++; - - return count; + for (cur = *list, count = 0; cur; cur = cur->next) + count++; + + return count; } /** @@ -130,18 +146,18 @@ * write the passed TLV chain to a data buffer. * */ -faim_export int aim_sizetlvchain(struct aim_tlvlist_t **list) +faim_export int aim_sizetlvchain(aim_tlvlist_t **list) { - struct aim_tlvlist_t *cur; - int size = 0; + aim_tlvlist_t *cur; + int size; - if (!list || !(*list)) - return 0; + if (!list || !*list) + return 0; - for (cur = *list; cur; cur = cur->next) - size += (4 + cur->tlv->length); - - return size; + for (cur = *list, size = 0; cur; cur = cur->next) + size += (4 + cur->tlv->length); + + return size; } /** @@ -155,35 +171,36 @@ * to the TLV chain. * */ -faim_export int aim_addtlvtochain_str(struct aim_tlvlist_t **list, const unsigned short type, const char *str, const int len) +faim_export int aim_addtlvtochain_raw(aim_tlvlist_t **list, const fu16_t t, const fu16_t l, const fu8_t *v) { - struct aim_tlvlist_t *newtlv; - struct aim_tlvlist_t *cur; + aim_tlvlist_t *newtlv, *cur; - if (!list) - return 0; + if (!list) + return 0; - newtlv = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(newtlv, 0x00, sizeof(struct aim_tlvlist_t)); + if (!(newtlv = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)))) + return 0; + memset(newtlv, 0x00, sizeof(aim_tlvlist_t)); - newtlv->tlv = aim_createtlv(); - newtlv->tlv->type = type; - newtlv->tlv->length = len; - newtlv->tlv->value = (unsigned char *)malloc(newtlv->tlv->length*sizeof(unsigned char)); - memcpy(newtlv->tlv->value, str, newtlv->tlv->length); - - newtlv->next = NULL; + if (!(newtlv->tlv = createtlv())) { + free(newtlv); + return 0; + } + newtlv->tlv->type = t; + if ((newtlv->tlv->length = l)) { + newtlv->tlv->value = (fu8_t *)malloc(newtlv->tlv->length); + memcpy(newtlv->tlv->value, v, newtlv->tlv->length); + } - if (*list == NULL) { - *list = newtlv; - } else if ((*list)->next == NULL) { - (*list)->next = newtlv; - } else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtlv; - } - return newtlv->tlv->length; + if (!*list) + *list = newtlv; + else { + for(cur = *list; cur->next; cur = cur->next) + ; + cur->next = newtlv; + } + + return newtlv->tlv->length; } /** @@ -195,35 +212,13 @@ * Adds a two-byte unsigned integer to a TLV chain. * */ -faim_export int aim_addtlvtochain16(struct aim_tlvlist_t **list, const unsigned short type, const unsigned short val) +faim_export int aim_addtlvtochain16(aim_tlvlist_t **list, const fu16_t t, const fu16_t v) { - struct aim_tlvlist_t *newtl; - struct aim_tlvlist_t *cur; - - if (!list) - return 0; - - newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(newtl, 0x00, sizeof(struct aim_tlvlist_t)); + fu8_t v16[2]; - newtl->tlv = aim_createtlv(); - newtl->tlv->type = type; - newtl->tlv->length = 2; - newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char)); - aimutil_put16(newtl->tlv->value, val); - - newtl->next = NULL; + aimutil_put16(v16, v); - if (*list == NULL) { - *list = newtl; - } else if ((*list)->next == NULL) { - (*list)->next = newtl; - } else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtl; - } - return 2; + return aim_addtlvtochain_raw(list, t, 2, v16); } /** @@ -235,35 +230,13 @@ * Adds a four-byte unsigned integer to a TLV chain. * */ -faim_export int aim_addtlvtochain32(struct aim_tlvlist_t **list, const unsigned short type, const unsigned long val) +faim_export int aim_addtlvtochain32(aim_tlvlist_t **list, const fu16_t t, const fu32_t v) { - struct aim_tlvlist_t *newtl; - struct aim_tlvlist_t *cur; - - if (!list) - return 0; - - newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(newtl, 0x00, sizeof(struct aim_tlvlist_t)); + fu8_t v32[4]; - newtl->tlv = aim_createtlv(); - newtl->tlv->type = type; - newtl->tlv->length = 4; - newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char)); - aimutil_put32(newtl->tlv->value, val); - - newtl->next = NULL; + aimutil_put32(v32, v); - if (*list == NULL) { - *list = newtl; - } else if ((*list)->next == NULL) { - (*list)->next = newtl; - } else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtl; - } - return 4; + return aim_addtlvtochain_raw(list, t, 4, v32); } /** @@ -288,37 +261,16 @@ * %AIM_CAPS_SENDFILE Supports Send File functions * */ -faim_export int aim_addtlvtochain_caps(struct aim_tlvlist_t **list, const unsigned short type, const unsigned short caps) +faim_export int aim_addtlvtochain_caps(aim_tlvlist_t **list, const fu16_t t, const fu16_t caps) { - unsigned char buf[128]; /* icky fixed length buffer */ - struct aim_tlvlist_t *newtl; - struct aim_tlvlist_t *cur; - - if(!list) - return 0; - - newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(newtl, 0x00, sizeof(struct aim_tlvlist_t)); - - newtl->tlv = aim_createtlv(); - newtl->tlv->type = type; + fu8_t buf[16*16]; /* icky fixed length buffer */ + aim_bstream_t bs; - newtl->tlv->length = aim_putcap(buf, sizeof(buf), caps); - newtl->tlv->value = (unsigned char *)calloc(1, newtl->tlv->length); - memcpy(newtl->tlv->value, buf, newtl->tlv->length); - - newtl->next = NULL; + aim_bstream_init(&bs, buf, sizeof(buf)); - if (*list == NULL) { - *list = newtl; - } else if ((*list)->next == NULL) { - (*list)->next = newtl; - } else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtl; - } - return newtl->tlv->length; + aim_putcap(&bs, caps); + + return aim_addtlvtochain_raw(list, t, aim_bstream_curpos(&bs), buf); } /** @@ -329,31 +281,44 @@ * Adds a TLV with a zero length to a TLV chain. * */ -faim_internal int aim_addtlvtochain_noval(struct aim_tlvlist_t **list, const unsigned short type) +faim_internal int aim_addtlvtochain_noval(aim_tlvlist_t **list, const fu16_t t) { - struct aim_tlvlist_t *newtlv; - struct aim_tlvlist_t *cur; - - newtlv = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(newtlv, 0x00, sizeof(struct aim_tlvlist_t)); - - newtlv->tlv = aim_createtlv(); - newtlv->tlv->type = type; - newtlv->tlv->length = 0; - newtlv->tlv->value = NULL; + return aim_addtlvtochain_raw(list, t, 0, NULL); +} - newtlv->next = NULL; +/* + * Note that the inner TLV chain will not be modifiable as a tlvchain once + * it is written using this. Or rather, it can be, but updates won't be + * made to this. + * + * XXX should probably support sublists for real. + * + * This is so neat. + * + */ +faim_internal int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl) +{ + fu8_t *buf; + int buflen; + aim_bstream_t bs; - if (*list == NULL) { - *list = newtlv; - } else if ((*list)->next == NULL) { - (*list)->next = newtlv; - } else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtlv; - } - return newtlv->tlv->length; + buflen = aim_sizetlvchain(tl); + + if (buflen <= 0) + return 0; + + if (!(buf = malloc(buflen))) + return 0; + + aim_bstream_init(&bs, buf, buflen); + + aim_writetlvchain(&bs, tl); + + aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); + + free(buf); + + return buflen; } /** @@ -367,34 +332,31 @@ * aim_freetlvchain() must still be called to free up the memory used * by the chain structures. * + * XXX clean this up, make better use of bstreams */ -faim_export int aim_writetlvchain(unsigned char *buf, int buflen, struct aim_tlvlist_t **list) +faim_export int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list) { - int goodbuflen = 0; - int i = 0; - struct aim_tlvlist_t *cur; + int goodbuflen; + aim_tlvlist_t *cur; - if (!list || !buf || !buflen) - return 0; + /* do an initial run to test total length */ + for (cur = *list, goodbuflen = 0; cur; cur = cur->next) { + goodbuflen += 2 + 2; /* type + len */ + goodbuflen += cur->tlv->length; + } - /* do an initial run to test total length */ - for (cur = *list; cur; cur = cur->next) { - goodbuflen += 2 + 2; /* type + len */ - goodbuflen += cur->tlv->length; - } - - if (goodbuflen > buflen) - return 0; /* not enough buffer */ + if (goodbuflen > aim_bstream_empty(bs)) + return 0; /* not enough buffer */ - /* do the real write-out */ - for (cur = *list; cur; cur = cur->next) { - i += aimutil_put16(buf+i, cur->tlv->type); - i += aimutil_put16(buf+i, cur->tlv->length); - memcpy(buf+i, cur->tlv->value, cur->tlv->length); - i += cur->tlv->length; - } + /* do the real write-out */ + for (cur = *list; cur; cur = cur->next) { + aimbs_put16(bs, cur->tlv->type); + aimbs_put16(bs, cur->tlv->length); + if (cur->tlv->length) + aimbs_putraw(bs, cur->tlv->value, cur->tlv->length); + } - return i; + return 1; /* XXX this is a nonsensical return */ } @@ -410,23 +372,21 @@ * in a chain. * */ -faim_export struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, const unsigned short type, const int nth) +faim_export aim_tlv_t *aim_gettlv(aim_tlvlist_t *list, const fu16_t t, const int n) { - int i; - struct aim_tlvlist_t *cur; - - i = 0; - for (cur = list; cur != NULL; cur = cur->next) - { - if (cur && cur->tlv) - { - if (cur->tlv->type == type) - i++; - if (i >= nth) - return cur->tlv; + aim_tlvlist_t *cur; + int i; + + for (cur = list, i = 0; cur; cur = cur->next) { + if (cur && cur->tlv) { + if (cur->tlv->type == t) + i++; + if (i >= n) + return cur->tlv; + } } - } - return NULL; + + return NULL; } /** @@ -440,19 +400,19 @@ * dynamic buffer and must be freed by the caller. * */ -faim_export char *aim_gettlv_str(struct aim_tlvlist_t *list, const unsigned short type, const int nth) +faim_export char *aim_gettlv_str(aim_tlvlist_t *list, const fu16_t t, const int n) { - struct aim_tlv_t *tlv; - char *newstr; + aim_tlv_t *tlv; + char *newstr; - if (!(tlv = aim_gettlv(list, type, nth))) - return NULL; - - newstr = (char *) malloc(tlv->length + 1); - memcpy(newstr, tlv->value, tlv->length); - *(newstr + tlv->length) = '\0'; + if (!(tlv = aim_gettlv(list, t, n))) + return NULL; - return newstr; + newstr = (char *) malloc(tlv->length + 1); + memcpy(newstr, tlv->value, tlv->length); + *(newstr + tlv->length) = '\0'; + + return newstr; } /** @@ -465,13 +425,13 @@ * 8bit integer instead of an aim_tlv_t. * */ -faim_internal unsigned char aim_gettlv8(struct aim_tlvlist_t *list, const unsigned short type, const int num) +faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t t, const int n) { - struct aim_tlv_t *tlv; + aim_tlv_t *tlv; - if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value) - return 0; /* erm */ - return aimutil_get8(tlv->value); + if (!(tlv = aim_gettlv(list, t, n))) + return 0; /* erm */ + return aimutil_get8(tlv->value); } /** @@ -484,13 +444,13 @@ * 16bit integer instead of an aim_tlv_t. * */ -faim_internal unsigned short aim_gettlv16(struct aim_tlvlist_t *list, const unsigned short type, const int num) +faim_internal fu16_t aim_gettlv16(aim_tlvlist_t *list, const fu16_t t, const int n) { - struct aim_tlv_t *tlv; + aim_tlv_t *tlv; - if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value) - return 0; /* erm */ - return aimutil_get16(tlv->value); + if (!(tlv = aim_gettlv(list, t, n))) + return 0; /* erm */ + return aimutil_get16(tlv->value); } /** @@ -503,144 +463,16 @@ * 32bit integer instead of an aim_tlv_t. * */ -faim_internal unsigned long aim_gettlv32(struct aim_tlvlist_t *list, const unsigned short type, const int num) +faim_internal fu32_t aim_gettlv32(aim_tlvlist_t *list, const fu16_t t, const int n) { - struct aim_tlv_t *tlv; - - if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value) - return 0; /* erm */ - return aimutil_get32(tlv->value); -} + aim_tlv_t *tlv; -/** - * aim_grabtlv - Grab a single TLV from a data buffer - * @src: Source data buffer (must be at least 4 bytes long) - * - * Creates a TLV structure aim_tlv_t and returns it - * filled with values from a buffer, possibly including a - * dynamically allocated buffer for the value portion. - * - * Both the aim_tlv_t and the tlv->value pointer - * must be freed by the caller if non-%NULL. - * - */ -faim_export struct aim_tlv_t *aim_grabtlv(const unsigned char *src) -{ - struct aim_tlv_t *dest = NULL; - - dest = aim_createtlv(); - - dest->type = src[0] << 8; - dest->type += src[1]; - - dest->length = src[2] << 8; - dest->length += src[3]; - - dest->value = (unsigned char *) malloc(dest->length); - memset(dest->value, 0, dest->length); - - memcpy(dest->value, &(src[4]), dest->length); - - return dest; + if (!(tlv = aim_gettlv(list, t, n))) + return 0; /* erm */ + return aimutil_get32(tlv->value); } -/** - * aim_grabtlvstr - Grab a single TLV from a data buffer as string - * @src: Source data buffer (must be at least 4 bytes long) - * - * Creates a TLV structure aim_tlv_t and returns it - * filled with values from a buffer, possibly including a - * dynamically allocated buffer for the value portion, which - * is %NULL-terminated as a string. - * - * Both the aim_tlv_t and the tlv->value pointer - * must be freed by the caller if non-%NULL. - * - */ -faim_export struct aim_tlv_t *aim_grabtlvstr(const unsigned char *src) -{ - struct aim_tlv_t *dest = NULL; - - dest = aim_createtlv(); - - dest->type = src[0] << 8; - dest->type += src[1]; - - dest->length = src[2] << 8; - dest->length += src[3]; - - dest->value = (unsigned char *) malloc(dest->length+1); - memset(dest->value, 0, dest->length+1); - - memcpy(dest->value, src+4, dest->length); - dest->value[dest->length] = '\0'; - - return dest; -} - -/** - * aim_puttlv - Write a aim_tlv_t into a data buffer - * @dest: Destination data buffer - * @newtlv: Source TLV structure - * - * Writes out the passed TLV structure into the buffer. No bounds - * checking is done on the output buffer. - * - * The passed aim_tlv_t is not freed. aim_freetlv() should - * still be called by the caller to free the structure. - * - */ -faim_export int aim_puttlv(unsigned char *dest, struct aim_tlv_t *newtlv) -{ - int i=0; - - dest[i++] = newtlv->type >> 8; - dest[i++] = newtlv->type & 0x00FF; - dest[i++] = newtlv->length >> 8; - dest[i++] = newtlv->length & 0x00FF; - memcpy(&(dest[i]), newtlv->value, newtlv->length); - i+=newtlv->length; - return i; -} - -/** - * aim_createtlv - Generate an aim_tlv_t structure. - * - * Allocates an empty TLV structure and returns a pointer - * to it; %NULL on error. - * - */ -faim_export struct aim_tlv_t *aim_createtlv(void) -{ - struct aim_tlv_t *newtlv; - - if (!(newtlv = (struct aim_tlv_t *)malloc(sizeof(struct aim_tlv_t)))) - return NULL; - memset(newtlv, 0, sizeof(struct aim_tlv_t)); - return newtlv; -} - -/** - * aim_freetlv - Free a aim_tlv_t structure - * @oldtlv: TLV to be destroyed - * - * Frees both the TLV structure and the value portion. - * - */ -faim_export int aim_freetlv(struct aim_tlv_t **oldtlv) -{ - if (!oldtlv) - return -1; - if (!*oldtlv) - return -1; - if ((*oldtlv)->value) - free((*oldtlv)->value); - free(*(oldtlv)); - (*oldtlv) = NULL; - - return 0; -} - +#if 0 /** * aim_puttlv_8 - Write a one-byte TLV. * @buf: Destination buffer @@ -650,15 +482,13 @@ * Writes a TLV with a one-byte integer value portion. * */ -faim_export int aim_puttlv_8(unsigned char *buf, const unsigned short t, const unsigned char v) +faim_export int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v) { - int curbyte=0; + fu8_t v8[1]; - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0001); - curbyte += aimutil_put8(buf+curbyte, (unsigned char)(v&0xff)); + aimutil_put8(v8, v); - return curbyte; + return aim_puttlv_raw(buf, t, 1, v8); } /** @@ -670,15 +500,16 @@ * Writes a TLV with a two-byte integer value portion. * */ -faim_export int aim_puttlv_16(unsigned char *buf, const unsigned short t, const unsigned short v) +faim_export int aim_puttlv_16(fu8_t *buf, const fu16_t t, const fu16_t v) { - int curbyte=0; - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0002); - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(v&0xffff)); - return curbyte; + fu8_t v16[2]; + + aimutil_put16(v16, v); + + return aim_puttlv_raw(buf, t, 2, v16); } + /** * aim_puttlv_32 - Write a four-byte TLV. * @buf: Destination buffer @@ -688,36 +519,38 @@ * Writes a TLV with a four-byte integer value portion. * */ -faim_export int aim_puttlv_32(unsigned char *buf, const unsigned short t, const unsigned long v) +faim_export int aim_puttlv_32(fu8_t *buf, const fu16_t t, const fu32_t v) { - int curbyte=0; - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0004); - curbyte += aimutil_put32(buf+curbyte, (unsigned long)(v&0xffffffff)); - return curbyte; + fu8_t v32[4]; + + aimutil_put32(v32, v); + + return aim_puttlv_raw(buf, t, 4, v32); } /** - * aim_puttlv_str - Write a string TLV. + * aim_puttlv_raw - Write a raw TLV. * @buf: Destination buffer * @t: TLV type * @l: Length of string * @v: String to write * - * Writes a TLV with a string value portion. (Only the first @l - * bytes of the passed string will be written, which should not - * include the terminating NULL.) + * Writes a TLV with a raw value portion. (Only the first @l + * bytes of the passed buffer will be written, which should not + * include a terminating NULL.) * */ -faim_export int aim_puttlv_str(unsigned char *buf, const unsigned short t, const int l, const char *v) +faim_export int aim_puttlv_raw(fu8_t *buf, const fu16_t t, const fu16_t l, const fu8_t *v) { - int curbyte; - - curbyte = 0; - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(l&0xffff)); - if (v) - memcpy(buf+curbyte, (unsigned char *)v, l); - curbyte += l; - return curbyte; + int i; + + i = aimutil_put16(buf, t); + i += aimutil_put16(buf+i, l); + if (l) + memcpy(buf+i, v, l); + i += l; + + return i; } +#endif + diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/txqueue.c --- a/src/protocols/oscar/txqueue.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/txqueue.c Sun Sep 09 10:07:14 2001 +0000 @@ -20,60 +20,65 @@ * Right now, that is. If/when we implement a pool of transmit * frames, this will become the request-an-unused-frame part. * - * framing = AIM_FRAMETYPE_OFT/OSCAR - * chan = channel for OSCAR, hdrtype for OFT + * framing = AIM_FRAMETYPE_OFT/FLAP + * chan = channel for FLAP, hdrtype for OFT * */ -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 aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen) { - struct command_tx_struct *newtx; + aim_frame_t *fr; + + if (!conn) { + faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n"); + return NULL; + } - if (!conn) { - faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n"); - return NULL; - } + /* For sanity... */ + if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) || + (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT)) { + if (framing != AIM_FRAMETYPE_OFT) { + faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n"); + return NULL; + } + } else { + if (framing != AIM_FRAMETYPE_FLAP) { + faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n"); + return NULL; + } + } + + if (!(fr = (aim_frame_t *)malloc(sizeof(aim_frame_t)))) + return NULL; + memset(fr, 0, sizeof(aim_frame_t)); - /* For sanity... */ - if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) || (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT)) { - if (framing != AIM_FRAMETYPE_OFT) { - faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n"); - return NULL; - } - } else { - if (framing != AIM_FRAMETYPE_OSCAR) { - faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n"); - return NULL; - } - } + fr->conn = conn; + + fr->hdrtype = framing; + + if (fr->hdrtype == AIM_FRAMETYPE_FLAP) { - newtx = (struct command_tx_struct *)malloc(sizeof(struct command_tx_struct)); - if (!newtx) - return NULL; - memset(newtx, 0, sizeof(struct command_tx_struct)); + fr->hdr.flap.type = chan; + + } else if (fr->hdrtype == AIM_FRAMETYPE_OFT) { + + fr->hdr.oft.type = chan; + fr->hdr.oft.hdr2len = 0; /* this will get setup by caller */ - newtx->conn = conn; + } else + faimdprintf(sess, 0, "tx_new: unknown framing\n"); - if(datalen) { - newtx->data = (unsigned char *)malloc(datalen); - newtx->commandlen = datalen; - } else - newtx->data = NULL; + if (datalen > 0) { + fu8_t *data; - newtx->hdrtype = framing; - if (newtx->hdrtype == AIM_FRAMETYPE_OSCAR) { - newtx->hdr.oscar.type = chan; - } else if (newtx->hdrtype == AIM_FRAMETYPE_OFT) { - newtx->hdr.oft.type = chan; - newtx->hdr.oft.hdr2len = 0; /* this will get setup by caller */ - } else { - faimdprintf(sess, 0, "tx_new: unknown framing\n"); - } + if (!(data = (unsigned char *)malloc(datalen))) { + aim_frame_destroy(fr); + return NULL; + } - return newtx; + aim_bstream_init(&fr->data, data, datalen); + } + + return fr; } /* @@ -82,48 +87,41 @@ * The overall purpose here is to enqueue the passed in command struct * into the outgoing (tx) queue. Basically... * 1) Make a scope-irrelevent copy of the struct - * 2) Lock the struct * 3) Mark as not-sent-yet * 4) Enqueue the struct into the list - * 5) Unlock the struct once it's linked in * 6) Return * * Note that this is only used when doing queue-based transmitting; * that is, when sess->tx_enqueue is set to &aim_tx_enqueue__queuebased. * */ -static int aim_tx_enqueue__queuebased(struct aim_session_t *sess, struct command_tx_struct *newpacket) +static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr) { - struct command_tx_struct *cur; + + if (!fr->conn) { + faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n"); + fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); + } + + if (fr->hdrtype == AIM_FRAMETYPE_FLAP) { + /* assign seqnum -- XXX should really not assign until hardxmit */ + fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn); + } - if (newpacket->conn == NULL) { - faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n"); - newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); - } - - if (newpacket->hdrtype == AIM_FRAMETYPE_OSCAR) { - /* assign seqnum */ - newpacket->hdr.oscar.seqnum = aim_get_next_txseqnum(newpacket->conn); - } - /* set some more fields */ - newpacket->lock = 1; /* lock */ - newpacket->sent = 0; /* not sent yet */ - newpacket->next = NULL; /* always last */ + fr->handled = 0; /* not sent yet */ - /* see overhead note in aim_rxqueue counterpart */ - if (sess->queue_outgoing == NULL) { - sess->queue_outgoing = newpacket; - } else { - for (cur = sess->queue_outgoing; - cur->next; - cur = cur->next) - ; - cur->next = newpacket; - } + /* see overhead note in aim_rxqueue counterpart */ + if (!sess->queue_outgoing) + sess->queue_outgoing = fr; + else { + aim_frame_t *cur; - newpacket->lock = 0; /* unlock so it can be sent */ + for (cur = sess->queue_outgoing; cur->next; cur = cur->next) + ; + cur->next = fr; + } - return 0; + return 0; } /* @@ -137,63 +135,58 @@ * right here. * */ -static int aim_tx_enqueue__immediate(struct aim_session_t *sess, struct command_tx_struct *newpacket) +static int aim_tx_enqueue__immediate(aim_session_t *sess, aim_frame_t *fr) { - if (newpacket->conn == NULL) { - faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n"); - if (newpacket->data) - free(newpacket->data); - free(newpacket); - return -1; - } + + if (!fr->conn) { + faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n"); + aim_frame_destroy(fr); + return 0; + } - if (newpacket->hdrtype == AIM_FRAMETYPE_OSCAR) - newpacket->hdr.oscar.seqnum = aim_get_next_txseqnum(newpacket->conn); + if (fr->hdrtype == AIM_FRAMETYPE_FLAP) + fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn); - newpacket->lock = 1; /* lock */ - newpacket->sent = 0; /* not sent yet */ + fr->handled = 0; /* not sent yet */ - aim_tx_sendframe(sess, newpacket); + aim_tx_sendframe(sess, fr); - if (newpacket->data) - free(newpacket->data); - free(newpacket); + aim_frame_destroy(fr); - return 0; + return 0; } -faim_export int aim_tx_setenqueue(struct aim_session_t *sess, - int what, - int (*func)(struct aim_session_t *, struct command_tx_struct *)) +faim_export int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *)) { - if (!sess) - return -1; + + if (what == AIM_TX_QUEUED) + sess->tx_enqueue = &aim_tx_enqueue__queuebased; + else if (what == AIM_TX_IMMEDIATE) + sess->tx_enqueue = &aim_tx_enqueue__immediate; + else if (what == AIM_TX_USER) { + if (!func) + return -EINVAL; + sess->tx_enqueue = func; + } else + return -EINVAL; /* unknown action */ - if (what == AIM_TX_QUEUED) - sess->tx_enqueue = &aim_tx_enqueue__queuebased; - else if (what == AIM_TX_IMMEDIATE) - sess->tx_enqueue = &aim_tx_enqueue__immediate; - else if (what == AIM_TX_USER) { - if (!func) - return -1; - sess->tx_enqueue = func; - } else - return -1; /* unknown action */ - - return 0; + return 0; } -faim_internal int aim_tx_enqueue(struct aim_session_t *sess, struct command_tx_struct *command) +faim_internal int aim_tx_enqueue(aim_session_t *sess, aim_frame_t *fr) { - /* - * If we want to send a connection thats inprogress, we have to force - * them to use the queue based version. Otherwise, use whatever they - * want. - */ - if (command && command->conn && (command->conn->status & AIM_CONN_STATUS_INPROGRESS)) { - return aim_tx_enqueue__queuebased(sess, command); - } - return (*sess->tx_enqueue)(sess, command); + + /* + * If we want to send a connection thats inprogress, we have to force + * them to use the queue based version. Otherwise, use whatever they + * want. + */ + if (fr && fr->conn && + (fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) { + return aim_tx_enqueue__queuebased(sess, fr); + } + + return (*sess->tx_enqueue)(sess, fr); } /* @@ -205,184 +198,194 @@ * before enqueuement (in aim_tx_enqueue()). * */ -faim_internal unsigned int aim_get_next_txseqnum(struct aim_conn_t *conn) +faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *conn) +{ + flap_seqnum_t ret; + + faim_mutex_lock(&conn->seqnum_lock); + ret = ++conn->seqnum; + faim_mutex_unlock(&conn->seqnum_lock); + + return ret; +} + +static int aim_send(int fd, const void *buf, size_t count) { - u_int ret; - - faim_mutex_lock(&conn->seqnum_lock); - ret = ++conn->seqnum; - faim_mutex_unlock(&conn->seqnum_lock); - return ret; + int left, cur; + + for (cur = 0, left = count; left; ) { + int ret; + + ret = send(fd, ((unsigned char *)buf)+cur, left, 0); + if (ret == -1) + return -1; + else if (ret == 0) + return cur; + + cur += ret; + left -= ret; + } + + return cur; +} + +static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count) +{ + int wrote = 0; + + if (!bs || !conn || (count < 0)) + return -EINVAL; + + if (count > aim_bstream_empty(bs)) + count = aim_bstream_empty(bs); /* truncate to remaining space */ + + if (count) + wrote = aim_send(conn->fd, bs->data + bs->offset, count); + + if (((aim_session_t *)conn->sessv)->debug >= 2) { + int i; + aim_session_t *sess = (aim_session_t *)conn->sessv; + + faimdprintf(sess, 2, "\nOutgoing data: (%d bytes)", wrote); + for (i = 0; i < wrote; i++) { + if (!(i % 8)) + faimdprintf(sess, 2, "\n\t"); + faimdprintf(sess, 2, "0x%02x ", *(bs->data + bs->offset + i)); + } + faimdprintf(sess, 2, "\n"); + } + + + bs->offset += wrote; + + return wrote; } -/* - * aim_tx_flushqueue() - * - * This the function is responsable for putting the queued commands - * onto the wire. This function is critical to the operation of - * the queue and therefore is the most prone to brokenness. It - * seems to be working quite well at this point. - * - * Procedure: - * 1) Traverse the list, only operate on commands that are unlocked - * and haven't been sent yet. - * 2) Lock the struct - * 3) Allocate a temporary buffer to store the finished, fully - * processed packet in. - * 4) Build the packet from the command_tx_struct data. - * 5) Write the packet to the socket. - * 6) If success, mark the packet sent, if fail report failure, do NOT - * mark the packet sent (so it will not get purged and therefore - * be attempted again on next call). - * 7) Unlock the struct. - * 8) Free the temp buffer - * 9) Step to next struct in list and go back to 1. - * - */ -faim_internal int aim_tx_sendframe(struct aim_session_t *sess, struct command_tx_struct *cur) +static int sendframe_flap(aim_session_t *sess, aim_frame_t *fr) { - int buflen = 0; - unsigned char *curPacket; - - if (!cur) - return -1; /* fatal */ + aim_bstream_t obs; + fu8_t *obs_raw; + int payloadlen, err = 0, obslen; - cur->lock = 1; /* lock the struct */ - - if (cur->hdrtype == AIM_FRAMETYPE_OSCAR) - buflen = cur->commandlen + 6; - else if (cur->hdrtype == AIM_FRAMETYPE_OFT) - buflen = cur->hdr.oft.hdr2len + 8; - else { - cur->lock = 0; - return -1; - } + payloadlen = aim_bstream_curpos(&fr->data); - /* allocate full-packet buffer */ - if (!(curPacket = (unsigned char *) malloc(buflen))) { - cur->lock = 0; - return -1; - } - - if (cur->hdrtype == AIM_FRAMETYPE_OSCAR) { - /* command byte */ - curPacket[0] = 0x2a; - - /* type/family byte */ - curPacket[1] = cur->hdr.oscar.type; - - /* bytes 3+4: word: FLAP sequence number */ - aimutil_put16(curPacket+2, cur->hdr.oscar.seqnum); + if (!(obs_raw = malloc(6 + payloadlen))) + return -ENOMEM; - /* bytes 5+6: word: SNAC len */ - aimutil_put16(curPacket+4, cur->commandlen); - - /* bytes 7 and on: raw: SNAC data */ /* XXX: ye gods! get rid of this! */ - memcpy(&(curPacket[6]), cur->data, cur->commandlen); + aim_bstream_init(&obs, obs_raw, 6 + payloadlen); - } else if (cur->hdrtype == AIM_FRAMETYPE_OFT) { - int z = 0; - - z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[0]); - z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[1]); - z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[2]); - z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[3]); - - z += aimutil_put16(curPacket+z, cur->hdr.oft.hdr2len + 8); - z += aimutil_put16(curPacket+z, cur->hdr.oft.type); - - memcpy(curPacket+z, cur->hdr.oft.hdr2, cur->hdr.oft.hdr2len); - } + /* FLAP header */ + aimbs_put8(&obs, 0x2a); + aimbs_put8(&obs, fr->hdr.flap.type); + aimbs_put16(&obs, fr->hdr.flap.seqnum); + aimbs_put16(&obs, payloadlen); - /* - * For OSCAR, a full image of the raw packet data now in curPacket. - * For OFT, an image of just the bloated header is in curPacket, - * since OFT allows us to do the data in a different write (yay!). - */ - faim_mutex_lock(&cur->conn->active); - if (send(cur->conn->fd, curPacket, buflen, 0) != buflen) { - faim_mutex_unlock(&cur->conn->active); - cur->sent = 1; - aim_conn_close(cur->conn); - return 0; /* bail out */ - } - - if ((cur->hdrtype == AIM_FRAMETYPE_OFT) && cur->commandlen) { - int curposi; - for(curposi = 0; curposi < cur->commandlen; curposi++) - faimdprintf(sess, 0, "%02x ", cur->data[curposi]); + /* payload */ + aim_bstream_rewind(&fr->data); + aimbs_putbs(&obs, &fr->data, payloadlen); - if (send(cur->conn->fd, cur->data, cur->commandlen, 0) != (int)cur->commandlen) { - /* - * Theres nothing we can do about this since we've already sent the - * header! The connection is unstable. - */ - faim_mutex_unlock(&cur->conn->active); - cur->sent = 1; - aim_conn_close(cur->conn); - return 0; /* bail out */ - } - - } - - cur->sent = 1; /* mark the struct as sent */ - cur->conn->lastactivity = time(NULL); - - faim_mutex_unlock(&cur->conn->active); + obslen = aim_bstream_curpos(&obs); + aim_bstream_rewind(&obs); - if (sess->debug >= 2) { - int i; + if (aim_bstream_send(&obs, fr->conn, obslen) != obslen) + err = -errno; + + free(obs_raw); /* XXX aim_bstream_free */ - faimdprintf(sess, 2, "\nOutgoing packet: (only valid for OSCAR)"); - for (i = 0; i < buflen; i++) { - if (!(i % 8)) - faimdprintf(sess, 2, "\n\t"); - faimdprintf(sess, 2, "0x%02x ", curPacket[i]); - } - faimdprintf(sess, 2, "\n"); - } + fr->handled = 1; + fr->conn->lastactivity = time(NULL); - cur->lock = 0; /* unlock the struct */ - - free(curPacket); /* free up full-packet buffer */ - - return 1; /* success */ + return err; } -faim_export int aim_tx_flushqueue(struct aim_session_t *sess) +static int sendframe_oft(aim_session_t *sess, aim_frame_t *fr) { - struct command_tx_struct *cur; - - if (sess->queue_outgoing == NULL) - return 0; + aim_bstream_t hbs; + fu8_t *hbs_raw; + int hbslen; + int err = 0; + + hbslen = 8 + fr->hdr.oft.hdr2len; + + if (!(hbs_raw = malloc(hbslen))) + return -1; + + aim_bstream_init(&hbs, hbs_raw, hbslen); + + aimbs_putraw(&hbs, fr->hdr.oft.magic, 4); + aimbs_put16(&hbs, fr->hdr.oft.hdr2len + 8); + aimbs_put16(&hbs, fr->hdr.oft.type); + aimbs_putraw(&hbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len); - faimdprintf(sess, 2, "beginning txflush...\n"); - for (cur = sess->queue_outgoing; cur; cur = cur->next) { - /* only process if its unlocked and unsent */ - if (!cur->lock && !cur->sent) { + aim_bstream_rewind(&hbs); + + if (aim_bstream_send(&hbs, fr->conn, hbslen) != hbslen) { + + err = -errno; + + } else if (aim_bstream_curpos(&fr->data)) { + int len; - if (cur->conn && (cur->conn->status & AIM_CONN_STATUS_INPROGRESS)) - continue; + len = aim_bstream_curpos(&fr->data); + aim_bstream_rewind(&fr->data); + + if (aim_bstream_send(&fr->data, fr->conn, len) != len) + err = -errno; + } + + free(hbs_raw); /* XXX aim_bstream_free */ + + fr->handled = 1; + fr->conn->lastactivity = time(NULL); + + + return err; +} - /* - * And now for the meager attempt to force transmit - * latency and avoid missed messages. - */ - if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) { - /* FIXME FIXME -- should be a break! we dont want to block the upper layers */ - sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL)); - } +faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *fr) +{ + if (fr->hdrtype == AIM_FRAMETYPE_FLAP) + return sendframe_flap(sess, fr); + else if (fr->hdrtype == AIM_FRAMETYPE_OFT) + return sendframe_oft(sess, fr); + return -1; +} + +faim_export int aim_tx_flushqueue(aim_session_t *sess) +{ + aim_frame_t *cur; + + for (cur = sess->queue_outgoing; cur; cur = cur->next) { + + if (cur->handled) + continue; /* already been sent */ + + if (cur->conn && (cur->conn->status & AIM_CONN_STATUS_INPROGRESS)) + continue; - /* XXX XXX XXX this should call the custom "queuing" function!! */ - if (aim_tx_sendframe(sess, cur) == -1) - break; - } - } + /* + * And now for the meager attempt to force transmit + * latency and avoid missed messages. + */ + if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) { + /* + * XXX should be a break! we dont want to block the + * upper layers + * + * XXX or better, just do this right. + * + */ + sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL)); + } - /* purge sent commands from queue */ - aim_tx_purgequeue(sess); + /* XXX this should call the custom "queuing" function!! */ + aim_tx_sendframe(sess, cur); + } - return 0; + /* purge sent commands from queue */ + aim_tx_purgequeue(sess); + + return 0; } /* @@ -393,47 +396,22 @@ * reduce memory footprint at run time! * */ -faim_export void aim_tx_purgequeue(struct aim_session_t *sess) +faim_export void aim_tx_purgequeue(aim_session_t *sess) { - struct command_tx_struct *cur = NULL; - struct command_tx_struct *tmp; + aim_frame_t *cur, **prev; - if (sess->queue_outgoing == NULL) - return; - - if (sess->queue_outgoing->next == NULL) { - if (!sess->queue_outgoing->lock && sess->queue_outgoing->sent) { - tmp = sess->queue_outgoing; - sess->queue_outgoing = NULL; - if (tmp->hdrtype == AIM_FRAMETYPE_OFT) - free(tmp->hdr.oft.hdr2); - free(tmp->data); - free(tmp); - } - return; - } + for (prev = &sess->queue_outgoing; (cur = *prev); ) { - for(cur = sess->queue_outgoing; cur->next != NULL; ) { - if (!cur->next->lock && cur->next->sent) { - tmp = cur->next; - cur->next = tmp->next; - if (tmp->hdrtype == AIM_FRAMETYPE_OFT) - free(tmp->hdr.oft.hdr2); - free(tmp->data); - free(tmp); - } - cur = cur->next; + if (cur->handled) { + *prev = cur->next; + + aim_frame_destroy(cur); - /* - * Be careful here. Because of the way we just - * manipulated the pointer, cur may be NULL and - * the for() will segfault doing the check unless - * we find this case first. - */ - if (cur == NULL) - break; - } - return; + } else + prev = &cur->next; + } + + return; } /** @@ -444,22 +422,17 @@ * for now this simply marks all packets as sent and lets them * disappear without warning. * - * doesn't respect command_tx_struct locks. */ - -faim_export int aim_tx_cleanqueue(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export void aim_tx_cleanqueue(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *cur = NULL; - - if(!sess || !conn) - return -1; + aim_frame_t *cur; - /* we don't respect locks here */ - for(cur = sess->queue_outgoing; cur; cur = cur->next) - if(cur->conn == conn) - cur->sent = 1; - - return 0; + for (cur = sess->queue_outgoing; cur; cur = cur->next) { + if (cur->conn == conn) + cur->handled = 1; + } + + return; } - - + + diff -r 31157c54fe6e -r 933346315b9b src/protocols/oscar/util.c --- a/src/protocols/oscar/util.c Sun Sep 09 06:33:54 2001 +0000 +++ b/src/protocols/oscar/util.c Sun Sep 09 10:07:14 2001 +0000 @@ -7,62 +7,10 @@ #include #include -#ifdef AIMUTIL_USEMACROS -/* macros in faim/aim.h */ -#else -faim_shortfunc int aimutil_put8(u_char *buf, u_char data) -{ - buf[0] = (u_char)data&0xff; - return 1; -} - -faim_shortfunc u_char aimutil_get8(u_char *buf) -{ - return buf[0]; -} - -/* - * Endian-ness issues here? - */ -faim_shortfunc int aimutil_put16(u_char *buf, u_short data) -{ - buf[0] = (u_char)(data>>8)&0xff; - buf[1] = (u_char)(data)&0xff; - return 2; -} - -faim_shortfunc u_short aimutil_get16(u_char *buf) -{ - u_short val; - val = (buf[0] << 8) & 0xff00; - val+= (buf[1]) & 0xff; - return val; -} - -faim_shortfunc int aimutil_put32(u_char *buf, u_long data) -{ - buf[0] = (u_char)(data>>24)&0xff; - buf[1] = (u_char)(data>>16)&0xff; - buf[2] = (u_char)(data>>8)&0xff; - buf[3] = (u_char)(data)&0xff; - return 4; -} - -faim_shortfunc u_long aimutil_get32(u_char *buf) -{ - u_long val; - val = (buf[0] << 24) & 0xff000000; - val+= (buf[1] << 16) & 0x00ff0000; - val+= (buf[2] << 8) & 0x0000ff00; - val+= (buf[3] ) & 0x000000ff; - return val; -} -#endif /* AIMUTIL_USEMACROS */ - faim_export faim_shortfunc int aimutil_putstr(u_char *dest, const char *src, int len) { - memcpy(dest, src, len); - return len; + memcpy(dest, src, len); + return len; } /* @@ -72,194 +20,184 @@ */ faim_export int aimutil_tokslen(char *toSearch, int index, char dl) { - int curCount = 1; - char *next; - char *last; - int toReturn; + int curCount = 1; + char *next; + char *last; + int toReturn; + + last = toSearch; + next = strchr(toSearch, dl); - last = toSearch; - next = strchr(toSearch, dl); - - while(curCount < index && next != NULL) - { - curCount++; - last = next + 1; - next = strchr(last, dl); - } - - if ((curCount < index) || (next == NULL)) - toReturn = strlen(toSearch) - (curCount - 1); - else - toReturn = next - toSearch - (curCount - 1); + while(curCount < index && next != NULL) { + curCount++; + last = next + 1; + next = strchr(last, dl); + } - return toReturn; + if ((curCount < index) || (next == NULL)) + toReturn = strlen(toSearch) - (curCount - 1); + else + toReturn = next - toSearch - (curCount - 1); + + return toReturn; } faim_export int aimutil_itemcnt(char *toSearch, char dl) { - int curCount; - char *next; - - curCount = 1; - - next = strchr(toSearch, dl); - - while(next != NULL) - { - curCount++; - next = strchr(next + 1, dl); - } - - return curCount; + int curCount; + char *next; + + curCount = 1; + + next = strchr(toSearch, dl); + + while(next != NULL) { + curCount++; + next = strchr(next + 1, dl); + } + + return curCount; } faim_export char *aimutil_itemidx(char *toSearch, int index, char dl) { - int curCount; - char *next; - char *last; - char *toReturn; - - curCount = 0; - - last = toSearch; - next = strchr(toSearch, dl); - - while(curCount < index && next != NULL) - { - curCount++; - last = next + 1; - next = strchr(last, dl); - } - - if (curCount < index) - { - toReturn = malloc(sizeof(char)); - *toReturn = '\0'; - } - next = strchr(last, dl); - - if (curCount < index) - { - toReturn = malloc(sizeof(char)); - *toReturn = '\0'; - } - else - { - if (next == NULL) - { - toReturn = malloc((strlen(last) + 1) * sizeof(char)); - strcpy(toReturn, last); + int curCount; + char *next; + char *last; + char *toReturn; + + curCount = 0; + + last = toSearch; + next = strchr(toSearch, dl); + + while (curCount < index && next != NULL) { + curCount++; + last = next + 1; + next = strchr(last, dl); } - else - { - toReturn = malloc((next - last + 1) * sizeof(char)); - memcpy(toReturn, last, (next - last)); - toReturn[next - last] = '\0'; + + if (curCount < index) { + toReturn = malloc(sizeof(char)); + *toReturn = '\0'; } - } - return toReturn; + next = strchr(last, dl); + + if (curCount < index) { + toReturn = malloc(sizeof(char)); + *toReturn = '\0'; + } else { + if (next == NULL) { + toReturn = malloc((strlen(last) + 1) * sizeof(char)); + strcpy(toReturn, last); + } else { + toReturn = malloc((next - last + 1) * sizeof(char)); + memcpy(toReturn, last, (next - last)); + toReturn[next - last] = '\0'; + } + } + return toReturn; } /* - * int snlen(const char *) - * - * This takes a screen name and returns its length without - * spaces. If there are no spaces in the SN, then the - * return is equal to that of strlen(). - * - */ +* int snlen(const char *) +* +* This takes a screen name and returns its length without +* spaces. If there are no spaces in the SN, then the +* return is equal to that of strlen(). +* +*/ faim_export int aim_snlen(const char *sn) { - int i = 0; - const char *curPtr = NULL; + int i = 0; + const char *curPtr = NULL; - if (!sn) - return 0; + if (!sn) + return 0; - curPtr = sn; - while ( (*curPtr) != (char) NULL) { - if ((*curPtr) != ' ') - i++; - curPtr++; - } + curPtr = sn; + while ( (*curPtr) != (char) NULL) { + if ((*curPtr) != ' ') + i++; + curPtr++; + } - return i; + return i; } /* - * int sncmp(const char *, const char *) - * - * This takes two screen names and compares them using the rules - * on screen names for AIM/AOL. Mainly, this means case and space - * insensitivity (all case differences and spacing differences are - * ignored). - * - * Return: 0 if equal - * non-0 if different - * - */ +* int sncmp(const char *, const char *) +* +* This takes two screen names and compares them using the rules +* on screen names for AIM/AOL. Mainly, this means case and space +* insensitivity (all case differences and spacing differences are +* ignored). +* +* Return: 0 if equal +* non-0 if different +* +*/ faim_export int aim_sncmp(const char *sn1, const char *sn2) { - const char *curPtr1 = NULL, *curPtr2 = NULL; + const char *curPtr1 = NULL, *curPtr2 = NULL; - if (aim_snlen(sn1) != aim_snlen(sn2)) - return 1; + if (aim_snlen(sn1) != aim_snlen(sn2)) + return 1; - curPtr1 = sn1; - curPtr2 = sn2; - while ( (*curPtr1 != (char) NULL) && (*curPtr2 != (char) NULL) ) { - if ( (*curPtr1 == ' ') || (*curPtr2 == ' ') ) { - if (*curPtr1 == ' ') - curPtr1++; - if (*curPtr2 == ' ') - curPtr2++; - } else { - if ( toupper(*curPtr1) != toupper(*curPtr2)) - return 1; - curPtr1++; - curPtr2++; - } - } + curPtr1 = sn1; + curPtr2 = sn2; + while ( (*curPtr1 != (char) NULL) && (*curPtr2 != (char) NULL) ) { + if ( (*curPtr1 == ' ') || (*curPtr2 == ' ') ) { + if (*curPtr1 == ' ') + curPtr1++; + if (*curPtr2 == ' ') + curPtr2++; + } else { + if ( toupper(*curPtr1) != toupper(*curPtr2)) + return 1; + curPtr1++; + curPtr2++; + } + } - return 0; + return 0; } /* strsep Copyright (C) 1992, 1993 Free Software Foundation, Inc. - strsep is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., 675 Mass Ave, - Cambridge, MA 02139, USA. */ +strsep is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ /* Minor changes by and1000 on 15/1/97 to make it go under Nemesis */ faim_export char *aim_strsep(char **pp, const char *delim) { - char *p, *q; - - if (!(p = *pp)) - return 0; - - if ((q = strpbrk (p, delim))) - { - *pp = q + 1; - *q = '\0'; - } - else - *pp = 0; - - return p; + char *p, *q; + + if (!(p = *pp)) + return 0; + + if ((q = strpbrk (p, delim))) { + *pp = q + 1; + *q = '\0'; + } else + *pp = 0; + + return p; } + + diff -r 31157c54fe6e -r 933346315b9b src/prpl.h --- a/src/prpl.h Sun Sep 09 06:33:54 2001 +0000 +++ b/src/prpl.h Sun Sep 09 10:07:14 2001 +0000 @@ -130,6 +130,8 @@ void (* keepalive) (struct gaim_connection *); void (* chat_set_topic) (struct gaim_connection *, int id, char *topic); + void (* convo_closed) (struct gaim_connection *, char *who); + char *(* normalize)(const char *); };