# HG changeset patch # User Eric Warmenhoven # Date 958782653 0 # Node ID 6ced2f1c8b247be43c1af07a59fa8fdae6f14357 # Parent 62d470738cc799024f2f2831fec4eef05733bdba [gaim-migrate @ 247] How cool is this, libfaim is making a comeback. I completely redid everything, as was necessary because of the updates to libfaim since gaim 0.9.7. You can sign on and send/recv IMs, but there's a bad lag between display updates that I haven't figured out how to fix yet. committer: Tailor Script diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/BUGS --- a/libfaim/BUGS Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/BUGS Sat May 20 00:30:53 2000 +0000 @@ -27,3 +27,11 @@ aim_snac.c ---------- - Should implement better SNAC handling + +aim_tlv.c +--------- + - Newer TLV bulk-read routines most likely have leakage somewhere. + +aim_rxhandlers.c +---------------- + - Need a better solution than sleep() diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/CHANGES --- a/libfaim/CHANGES Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/CHANGES Sat May 20 00:30:53 2000 +0000 @@ -1,6 +1,183 @@ No release numbers ------------------ + - Sun Apr 2 07:29:11 UTC 2000 + - Redid much of the tx path to remove the superfluous copy. But + it touches every function that transmits. Its been a long + time in coming. + - Added caps parameter to aim_bos_setprofile(). You can now + control what capabilties you show up as others to + - Added ->capabilities to userinfo. It should be nonzero when + its coming off buddy oncoming information, but NOT requested + user info. + + - Sun Apr 2 01:45:15 UTC 2000 + - Increased AIM_CONN_MAX from 5 to 7. Precausionary only + - Removed deprecated TIS_TELNET_PROXY from faim/faimconfig.h + - Added macros for the simple integer functions in aim_util.c + - Removed usage of aim_failsaferead() + - Still not sure why I had it to begin with. I think it + was a remament from when we used non-blocking sockets + (which I don't know why I did either) + - Removed some of the oddities in aim_get_command() + - gprof showed this taking 20kns on my k6-300. Should be faster now. + - Added conn parameter. This should prevent aim_select() from + getting called too many times in a row. + + - Thu Mar 23 08:45:40 UTC 2000 + - Removed aim_countconn() > 0 check in aim_select(), its logically redundent + - Added aim_putuserinfo() (inverse of aim_extractuserinfo()) + - Added aim_sendbuddyoncoming/offgoing() + - Rearranged loop in rxdispatch() + - Remove aim_conn_close() if connections dead in aim_get_command() + + - Thu Mar 23 00:44:32 UTC 2000 + - Added a check to purge_rxqueue to skip handled commands + + - Mon Mar 20 05:30:59 UTC 2000 + - Added some server-only functions for login + - Added aim_counttlvchain() + - Added aim_sncmp() and aim_snlen() + + - Sun Mar 19 06:07:52 UTC 2000 + - Added a parameter to aim_select to return event type + - REQUIRES CLIENT CHANGES. + - For the most part rewrote the tx and rx queuing code + - Should fix many, many outstanding problems in and related + to that code, including one that keeps memory from freeing + - Fixed several bugs in various places + - Reformated a lot of code, and did general cleanups + - Should have a generally more robust lib now. + + - Sun Mar 12 00:07:40 UTC 2000 + - Fixed a robustness problem in aim_handleredirect_middle() + - Added TLV chain creation routines (yes, aimd is progressing) + + - Mon Jan 3 04:07:55 UTC 2000 + - Fixed bug in aim_snac.c + - Fixed condition where commands read from connections that have + been closed were still left in the queue. Now cancelled. + - Added some printfs to aim_info to get more informative crahes + - Fixed a bug in aim_rxqueue::purge + + - Sun Jan 2 10:31:19 UTC 2000 + - Cleanups in aim_info.c + - Can compile with -Ddebug=100 again + - Implemented chat: Joining/Leaving, info parsing, IM parsing/sending + - Implemented some chatnav: rights req/parsing, room creation + + - Thu Dec 30 10:08:42 UTC 1999 + - Fixed bug in aim_im.c when (encoding == NULL) || (lang == NULL) + - Added detection of voice chat requests + - Added AIM_CLASS_* defines, including new Away flag + - Added awaymsg parameter to bos_setprofile. + - If awaymsg is nonnull, you will be advertised as being away (your + class will be ORed with AIM_CLASS_AWAY), otherwise you'll show + up normal. + + - Wed Dec 29 10:06:35 UTC 1999 + - Fixed small bug in IM parser + - Added stubs for the capability TLVs in userinfo. + + - Wed Dec 29 09:14:45 UTC 1999 + - Added a capability block to aim_bos_setprofile. Can now get chat + invites again. + - Extended ICBM parser to support channel 2 messages (chat invites) + - A channel parameter has been prepended to the varargs -- REQUIRES + CLIENT CHANGES. + - Extended faimtest to support chat invites. + - Changed faimtest to get sn/password from environment + + - Wed Dec 29 04:17:03 UTC 1999 + - Added -g to CFLAGS + - Added aim_sendconnack() to aim_login.c (needed for newer login) + - Added code for the new SNAC-based login/auth procedure. (see SNACLOGIN + in faim/faimconfig.h for why its not enabled) + - Reimplemented aim_authparse(), aim_handleredirect() using TLVlists + - The old auth_failed callback is now integrated into the + success one. If there was an error, logininfo->errorcode is nonzero + - Fiddled with version information. Added aim_setversions() + - Added table of SNAC names for showing unknown snacs (jbm) + - Added a middle handler for MOTD + - Added new authorization SNACs to faim/aim_cbtypes.h + + - Sun Dec 26 22:59:10 UTC 1999 + - Renamed login_phase1_struct to aim_login_struct + - Changed cookie and sn to be static arrays in aim_login_struct + - Integrated the Jabber-faim changes. (temas) [BIG CLIENT CHANGES] + - Added aim_session_t, removed all global variables + - Changed all functions to accept a session pointer + - Removed aim_global.c + - Updated faimtest to use an aim_session_t. + - Removed all cases where logininfo was passed as vararg to client + - Fixed small bug in aim_newconn's 'fixing' of host:port addresses + - Added an install rule to the makefile (installs headers+so only!) + - Enabled USE_SNAC_FOR_IMS by default, assuming it got fixed + by n's new aim_snac.c from ages ago + - Implemented a middle handler for 0004/0001 message errors, added + snacid lookup to get illfated destination SN and pass to client + - Implemented a short middle handler for offgoing buddy. + + - Fri Dec 24 21:30:06 UTC 1999 + - Added an error-counting Read() that has been sitting in my inbox + - Cleaned up header files, created aim_cbtypes.h. + - Added void * to aim_conn_t for private client use if they want. (Orb) + - Removed all stderr output. All output is important, and goes to stdout. + - Renamed isautoresponse in IM parser to icbmflags. + - Added Orb's fix for the new login code, deleted old (see Orb, I do read + your mail....eventually). + - Added mailing lists to README. + + - Fri Dec 24 11:12:34 UTC 1999 + - Cleaned up both outgoing and incoming ICBM handling. Anything + that crashes around there is no longer libfaims fault! + - The encoding flags are now passed up to the client. + - Added several TLV routines to parse large blocks of continuous + TLV triplets. Not terribly effecient, but quite elegent in usage. + - Added icbm_setparams() back in from way-back-long-ago. It hasn't + been implemented in a long time, but I think we should still send it. + + - Fri Dec 24 01:23:06 UTC 1999 + - Fixed a very minor bug in aim_newconn(). + - Added aimutil_get{16,32}() + - Added aim_extractuserinfo() for extracting user data + blocks and putting them into struct aim_userinfo_s's. + - Added a loop to print out info on extraneous TLVs. + - Put in lots of comments. + - Added parse_oncoming_middle() to parse the user data + block of that packet. Now passes struct aim_userinfo_s + to client. + - Rearranged parse_userinfo_middle(). Now passes an entire + userinfo struct to client instead of individual variables. + - Convered the version of parse_im_middle() thats actually getting + used to pass up a userinfo struct. + - Updated faimtest to accept new structs. + + - Tue Dec 21 06:18:50 UTC 1999 + - Fixed a Win32 header problem + - Tue Dec 21 03:44:13 UTC 1999 + - Latency timers now update on rx as well as tx. Gets rid of even more + of the rate problems that most clients are having. + - Renamed lasttx and settxlatency to lastactivity and setlatency, respec. + - Integrated fixes needed for Win32 -- should compile cleanly now (DMP) + - Cleaned up some places, use aim_putsnac everywhere now. + + - Sun Sep 26 20:04:20 MST 1999 + - Reduced the IM parsing to look for 3 zeros instead of 4 -- NEEDS WORK + - This was needed to work with MacAIM3 and some WinAIM3s. + - Added aim_conn_settxlatency() for throttling outgoing frames -- NEEDS WORK + - Added an int to the userinfo and incoming IM user callbacks for new + TLV that AOL put it in -- its the number of seconds elapsed since + the user logged in + - Worked more on the callbacks (more internal rearrangements) + - Fixed bug in aim_select() (returning negative fds) + - Clear out logininfo struct before putting more data into it + - Other bugfixes that I can't particularly remember. + + - Tue Aug 24 03:13:12 UTC 1999 --- TRANSITION RELEASE!! + - Added jbm's new aim_rxqueue.c, which should crash less + - Started the overhaul on the callback system. No where near complete yet. + - Sun Aug 1 03:02:17 UTC 1999 - Added aimutil_*()s in aim_util.c for raw byte placement - Cleaned up aim_im.c, aim_auth.c, and aim_login.c using aimutil_* @@ -11,6 +188,7 @@ changes left to do) - Some Chat stuff changed, still no where near functional - Finally remembered to switch the license to LGPL (from GPL) + - Permit/Deny (blocking) list support added - Released a snapshot - Sat Jul 31 05:28:38 UTC 1999 diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/CHANGES.gaim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfaim/CHANGES.gaim Sat May 20 00:30:53 2000 +0000 @@ -0,0 +1,10 @@ +Sat May 20 00:16:25 UTC 2000 EWarmenhoven + - First log entry! Yay! + - Updated the libfaim code to the latest in CVS + - Rewrote much of oscar.c (if not all). + - Current supported features: + Signing On + Receiving IMs + Sending IMs + - There is a 2 second delay between GTK updates. Please, someone + fix this before I go insane. diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/Makefile.am --- a/libfaim/Makefile.am Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/Makefile.am Sat May 20 00:30:53 2000 +0000 @@ -2,13 +2,17 @@ EXTRA_LIBRARIES = libfaim.a -EXTRA_DIST = aim.h faimconfig.h +EXTRA_DIST = aim.h aim_cbtypes.h faimconfig.h -libfaim_a_SOURCES = aim_chatnav.c aim_info.c aim_rxhandlers.c \ - aim_tlv.c aim_auth.c aim_conn.c aim_login.c \ - aim_rxqueue.c aim_txqueue.c aim_buddylist.c \ - aim_global.c aim_logoff.c aim_search.c aim_util.c \ - aim_chat.c aim_im.c aim_misc.c aim_snac.c +#libfaim_a_SOURCES = aim_chatnav.c aim_info.c aim_rxhandlers.c \ +# aim_tlv.c aim_auth.c aim_conn.c aim_login.c \ +# aim_rxqueue.c aim_txqueue.c aim_buddylist.c \ +# aim_global.c aim_logoff.c aim_search.c aim_util.c \ +# aim_chat.c aim_im.c aim_misc.c aim_snac.c +libfaim_a_SOURCES = aim_auth.c aim_buddylist.c aim_chat.c aim_chatnav.c \ + aim_conn.c aim_im.c aim_info.c aim_login.c \ + aim_logoff.c aim_misc.c aim_rxhandlers.c aim_rxqueue.c \ + aim_search.c aim_snac.c aim_tlv.c aim_txqueue.c aim_util.c CFLAGS += $(GAIM_CFLAGS) -I../src diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/README --- a/libfaim/README Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/README Sat May 20 00:30:53 2000 +0000 @@ -4,7 +4,7 @@ This is libfaim, the purpose of which is to implement as much as the AOL AIM/OSCAR protocol as possible (which should be all of it). After -nearly a year of development, its still nowhere close. +over a year of development, its still nowhere close. This is not a full client and never will be. libfaim only implements the routines to implement a client (ie, there's no user interface). @@ -14,7 +14,9 @@ I would not recommend using this version of libfaim in any form yet. It's beta-quality and I know it leaks memory quite badly. It seems fairly -stable, however. YMMV, YAYOR, etc. +stable, however. YMMV, YAYOR, etc. I suppose I should say regardless of +that warning, that several clients use it and people use those clients +on a daily basis (in particular, me). Building @@ -22,8 +24,8 @@ Everything in this libfaim dist should build cleanly on any UNIX(-like) operating system. Originally developed on Linux+glibc. Past versions -known to work on Linux+libc5, FreeBSD, HP/UX, Solaris, Mac OS X Server, -and others. +known to work on Linux+libc5, FreeBSD, HP/UX, Solaris, Mac OS X Server, +Win32 using VC++ 98/6 and others. libfaim builds as both libfaim.a and libfaim.so. If your platform for some reason does not support dynamic libraries (eg, you get errors when @@ -63,15 +65,21 @@ Use the source and utils/faimtest/faimtest.c as a reference when coding front-ends. +Mailing Lists +------------- + +Thanks to Sourceforge, we have our mailing lists back. See: +http://www.sourceforge.org/mail/?group_id=920 for instructions +on subscribing to the lists: + + libfaim-devel: Discussion of libfaim and its developement. + libfaim-aim-protocol: Discussion of the finer points of OSCAR hacking + Contact Info ------------ -The author (Adam Fritzler), can be reached at afritz@iname.com or mid@auk.cx. - -I did have mailing lists available for faim-related discussion, but they -have dwindled and eventually broke and to my knowledge have yet to fix -themselves. +The author (Adam Fritzler), can be reached at mid@auk.cx. Front-end information: http://www.auk.cx/faim/ diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/README.gaim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfaim/README.gaim Sat May 20 00:30:53 2000 +0000 @@ -0,0 +1,73 @@ +Hello, your good friend EW here with a nice little notice that I'm sure will +affect the ten of you who actually read this. + +I'm going to start trying to get gaim to use Oscar through libfaim. As far as I +can tell, the only thing it used to be able to do is sign on and receive IMs. I +updated libfaim to what's currently in the libfaim CVS on sourceforge. As of +right now, I haven't even gotten it to sign on, but theoretically it can receive +IMs. + +I'm going to try to make as few modifications as possible to the libfaim code. +The only two modifications I'll probably ever make to it are 1) to make my life +easier (like putting all the .h files in the same directory as the .c files) or +2) to fix a compilation error that I happen to be able to fix very easily (like +with a typo or something). That means that what you're getting when you enable +oscar is basically faimtest (the very instructional program included with the +libfaim source on sourceforge) with the Gaim GTK front-end. I'll put any changes +I make into a file, but so far, I haven't made any changes other than moving the +.h files down a directory. + +HOW TO HELP +=========== +So here's what you can do in order to help gaim use libfaim. There are basically +3 steps: + +1) In server.c, find an #ifndef USE_OSCAR tag that doesn't have a corresponding +#else. Find it in a good fun function that you want to implement. Basically +copy the code from the TOC side for the Oscar side. For example: + +void serv_send_im(char *name, char *message, int away) +{ + char buf[MSG_LEN - 7]; + +#ifndef USE_OSCAR + g_snprintf(buf, MSG_LEN - 8, "toc_send_im %s \"%s\"%s", normalize(name), message, ((away) ? " auto" : "")); + sflap_send(buf, strlen(buf), TYPE_DATA); +#endif + if (!away) + serv_touch_idle(); +} + +becomes: + +void serv_send_im(char *name, char *message, int away) +{ + char buf[MSG_LEN - 7]; + +#ifndef USE_OSCAR + g_snprintf(buf, MSG_LEN - 8, "toc_send_im %s \"%s\"%s", normalize(name), + message, ((away) ? " auto" : "")); + sflap_send(buf, strlen(buf), TYPE_DATA); +#else + oscar_send_im(name, message, away); +#endif + if (!away) + serv_touch_idle(); +} + +2) Edit gaim.h to add the new function (you'll see a list of them in there) + +3) Edit oscar.c to implement the new function + +Most of the functions you're going to need to call use a session and connection +structure. These are kept statically in oscar.c as gaim_sess and gaim_conn. For +example, from above: + +void oscar_send_im(char *name, char *msg, int away) { + if (away) + aim_send_im(gaim_sess, gaim_conn, name, AIM_IMFLAGS_AWAY, msg); + else + aim_send_im(gaim_sess, gaim_conn, name, 0, msg); +} + +That should be all that's needed. And that's that. Happy hacking. diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim.h --- a/libfaim/aim.h Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim.h Sat May 20 00:30:53 2000 +0000 @@ -1,46 +1,88 @@ +/* + * Main libfaim header. Must be included in client for prototypes/macros. + * + */ + #ifndef __AIM_H__ #define __AIM_H__ #include +#include -/* some global includes */ #include #include #include -#include #include -#include -#include -#include -#include #include #include #include -#define CONNECT_SIG_LEN 10 /* not used anymore, hopefully */ -#define LOGIN_RESP_LEN 512 /* should only be 334b but no segfault for us! */ +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif + +/* Portability stuff (DMP) */ +#ifdef _WIN32 +#define sleep Sleep +#define strlen(x) (int)strlen(x) /* win32 has a unsigned size_t */ +#endif + +#if defined(_WIN32) || (defined(mach) && defined(__APPLE__)) +#define gethostbyname2(x,y) gethostbyname(x) /* revert to IPv4 */ +#endif + +/* + * Current Maximum Length for Screen Names (not including NULL) + */ +#define MAXSNLEN 16 /* - * Error codes + * Standard size of an AIM authorization cookie */ -#define AIM_CONNECT_ERROR -0x1 -#define AIM_SIGNON_TOO_SOON -0x4 -#define AIM_SERVICE_FULL -0x6f +#define AIM_COOKIELEN 0x100 +#if debug > 0 +#define faimdprintf(l, x...) {if (l >= debug) printf(x); } +#else +#define faimdprintf(l, x...) +#endif -struct login_phase1_struct { - char *screen_name; +/* + * Login info. Passes information from the Authorization + * stage of login to the service (BOS, etc) connection + * phase. + * + */ +struct aim_login_struct { + char screen_name[MAXSNLEN+1]; char *BOSIP; - char *cookie; + char cookie[AIM_COOKIELEN]; char *email; - ushort regstatus; + u_short regstatus; + char *errorurl; + u_short errorcode; }; -extern struct login_phase1_struct aim_logininfo; - +/* + * Client info. Filled in by the client and passed + * in to aim_login(). The information ends up + * getting passed to OSCAR through the initial + * login command. + * + * XXX: Should this be per-session? -mid + * + */ struct client_info_s { - char clientstring[100]; /* arbitrary number */ + char clientstring[100]; /* arbitrary size */ int major; int minor; int build; @@ -48,55 +90,49 @@ char lang[3]; }; -struct connection_info_struct { - unsigned int local_seq_num_origin; /* our first seq num */ - int local_command_count; - - unsigned int remote_seq_num_origin; /* oscar's first seqnum */ - int remote_command_count; /* command_count + seq_num_origin = cur_seq_num */ - - char *sn; /* our screen name */ - - int fd; /* socket descriptor */ -}; - #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif -#define AIM_CONN_MAX 5 -/* these could be arbitrary, but its easier to use the actual AIM values */ -#define AIM_CONN_TYPE_AUTH 0x0007 -#define AIM_CONN_TYPE_ADS 0x0005 -#define AIM_CONN_TYPE_BOS 2 -#define AIM_CONN_TYPE_CHAT 0x000e -#define AIM_CONN_TYPE_CHATNAV 0x000d +/* + * These could be arbitrary, but its easier to use the actual AIM values + */ +#define AIM_CONN_TYPE_AUTH 0x0007 +#define AIM_CONN_TYPE_ADS 0x0005 +#define AIM_CONN_TYPE_BOS 0x0002 +#define AIM_CONN_TYPE_CHAT 0x000e +#define AIM_CONN_TYPE_CHATNAV 0x000d -#define AIM_CONN_STATUS_READY 0x0001 +/* + * Status values returned from aim_conn_new(). ORed together. + */ +#define AIM_CONN_STATUS_READY 0x0001 #define AIM_CONN_STATUS_INTERNALERR 0x0002 -#define AIM_CONN_STATUS_RESOLVERR 0x80 -#define AIM_CONN_STATUS_CONNERR 0x40 - +#define AIM_CONN_STATUS_RESOLVERR 0x0080 +#define AIM_CONN_STATUS_CONNERR 0x0040 struct aim_conn_t { int fd; int type; 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; }; -struct aim_conn_t aim_conns[AIM_CONN_MAX]; - /* struct for incoming commands */ struct command_rx_struct { /* byte 1 assumed to always be 0x2a */ char type; /* type code (byte 2) */ - unsigned int seqnum; /* sequence number (bytes 3 and 4) */ - unsigned int commandlen; /* total packet len - 6 (bytes 5 and 6) */ - char *data; /* packet data (from 7 byte on) */ - unsigned int lock; /* 1 = locked, 0 = open */ - unsigned int handled; /* 1 = been handled, 0 = new */ + u_int seqnum; /* sequence number (bytes 3 and 4) */ + u_int commandlen; /* total packet len - 6 (bytes 5 and 6) */ + u_char *data; /* packet data (from 7 byte on) */ + u_int lock; /* 0 = open, !0 = locked */ + u_int handled; /* 0 = new, !0 = been handled */ + u_int 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 */ }; @@ -105,103 +141,189 @@ struct command_tx_struct { /* byte 1 assumed to be 0x2a */ char type; /* type/family code */ - unsigned int seqnum; /* seqnum dynamically assigned on tx */ - unsigned int commandlen; /* SNAC length */ - char *data; /* packet data */ - unsigned int lock; /* 1 = locked, 0 = open */ - unsigned int sent; /* 1 = has been sent, 0 = new */ + u_int seqnum; /* seqnum dynamically assigned on tx */ + u_int commandlen; /* SNAC length */ + u_char *data; /* packet 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 */ }; -/* TLV-related tidbits */ + +/* + * AIM Session: The main client-data interface. + * + */ +struct aim_session_t { + + /* ---- Client Accessible ------------------------ */ + /* + * Login information. See definition above. + * + */ + struct aim_login_struct logininfo; + + /* + * Pointer to anything the client wants to + * explicitly associate with this session. + */ + void *aux_data; + + + /* ---- Internal Use Only ------------------------ */ + /* + * Connection information + */ + struct aim_conn_t conns[AIM_CONN_MAX]; + + /* + * TX/RX queues + */ + struct command_tx_struct *queue_outgoing; + struct command_rx_struct *queue_incoming; + + /* + * 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; + + /* + * Outstanding snac handling + * + * XXX: Should these be per-connection? -mid + **/ + struct aim_snac_t *outstanding_snacs; + u_long snac_nextid; +}; + + +/* + * AIM User Info, Standard Form. + */ +struct aim_userinfo_s { + char sn[MAXSNLEN+1]; + u_short warnlevel; + u_short idletime; + u_short class; + u_long membersince; + u_long onlinesince; + u_long sessionlen; + u_short capabilities; +}; + +#define AIM_CLASS_TRIAL 0x0001 +#define AIM_CLASS_UNKNOWN2 0x0002 +#define AIM_CLASS_AOL 0x0004 +#define AIM_CLASS_UNKNOWN4 0x0008 +#define AIM_CLASS_FREE 0x0010 +#define AIM_CLASS_AWAY 0x0020 +#define AIM_CLASS_UNKNOWN40 0x0040 +#define AIM_CLASS_UNKNOWN80 0x0080 + +/* + * TLV handling + */ + +/* Generic TLV structure. */ struct aim_tlv_t { u_short type; u_short length; u_char *value; }; +/* List of above. */ +struct aim_tlvlist_t { + struct aim_tlv_t *tlv; + struct aim_tlvlist_t *next; +}; + +/* TLV-handling functions */ +struct aim_tlvlist_t *aim_readtlvchain(u_char *buf, int maxlen); +void aim_freetlvchain(struct aim_tlvlist_t **list); struct aim_tlv_t *aim_grabtlv(u_char *src); struct aim_tlv_t *aim_grabtlvstr(u_char *src); +struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *, u_short, int); +char *aim_gettlv_str(struct aim_tlvlist_t *, u_short, int); int aim_puttlv (u_char *dest, struct aim_tlv_t *newtlv); struct aim_tlv_t *aim_createtlv(void); int aim_freetlv(struct aim_tlv_t **oldtlv); int aim_puttlv_16(u_char *, u_short, u_short); - -/* some prototypes... */ - -/* implicitly or explicitly called */ -int aim_get_command(void); -int aim_rxdispatch(void); -int aim_logoff(void); - -typedef int (*rxcallback_t)(struct command_rx_struct *, ...); -int aim_register_callbacks(rxcallback_t *); +int aim_puttlv_32(u_char *, u_short, u_long); +int aim_puttlv_str(u_char *buf, u_short t, u_short l, u_char *v); +int aim_writetlvchain(u_char *buf, int buflen, struct aim_tlvlist_t **list); +int aim_addtlvtochain16(struct aim_tlvlist_t **list, unsigned short type, unsigned short val); +int aim_addtlvtochain32(struct aim_tlvlist_t **list, unsigned short type, unsigned long val); +int aim_addtlvtochain_str(struct aim_tlvlist_t **list, unsigned short type, char *str, int len); +int aim_counttlvchain(struct aim_tlvlist_t **list); -u_long aim_genericreq_n(struct aim_conn_t *conn, u_short family, u_short subtype); -u_long aim_genericreq_l(struct aim_conn_t *conn, u_short family, u_short subtype, u_long *); -u_long aim_genericreq_s(struct aim_conn_t *conn, u_short family, u_short subtype, u_short *); +/* + * Get command from connections / Dispatch commands + * already in queue. + */ +int aim_get_command(struct aim_session_t *, struct aim_conn_t *); +int aim_rxdispatch(struct aim_session_t *); -/* aim_login.c */ -int aim_send_login (struct aim_conn_t *, char *, char *, struct client_info_s *); -int aim_encode_password(const char *, char *); - - -struct command_rx_struct *aim_purge_rxqueue(struct command_rx_struct *queue); +int aim_logoff(struct aim_session_t *); -int aim_parse_unknown(struct command_rx_struct *command, ...); -int aim_parse_missed_im(struct command_rx_struct *, ...); -int aim_parse_last_bad(struct command_rx_struct *, ...); +typedef int (*rxcallback_t)(struct aim_session_t *, struct command_rx_struct *, ...); +int aim_register_callbacks(rxcallback_t *); -int aim_tx_enqueue(struct command_tx_struct *); -unsigned int aim_get_next_txseqnum(struct aim_conn_t *); -int aim_tx_flushqueue(void); -int aim_tx_printqueue(void); -int aim_tx_purgequeue(void); +u_long aim_genericreq_n(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype); +u_long aim_genericreq_l(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype, u_long *); +u_long aim_genericreq_s(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype, u_short *); -/* queue (linked list) pointers */ -extern struct command_tx_struct *aim_queue_outgoing; /* incoming commands */ -extern struct command_rx_struct *aim_queue_incoming; /* outgoing commands */ +/* aim_login.c */ +int aim_sendconnack(struct aim_session_t *sess, struct aim_conn_t *conn); +int aim_request_login (struct aim_session_t *sess, struct aim_conn_t *conn, char *sn); +int aim_send_login (struct aim_session_t *, struct aim_conn_t *, char *, char *, struct client_info_s *); +int aim_encode_password(const char *, u_char *); +unsigned long aim_sendauthresp(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *sn, char *bosip, + char *cookie, char *email, + int regstatus); +int aim_gencookie(unsigned char *buf); +int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn); +unsigned long aim_sendredirect(struct aim_session_t *sess, + struct aim_conn_t *conn, + unsigned short servid, + char *ip, + char *cookie); +void aim_purge_rxqueue(struct aim_session_t *); -/* The default callback handler array */ -extern rxcallback_t aim_callbacks[]; - -extern struct aim_snac_t *aim_outstanding_snacs; -extern u_long aim_snac_nextid; -#define AIM_CB_INCOMING_IM 0 -#define AIM_CB_ONCOMING_BUDDY 1 -#define AIM_CB_OFFGOING_BUDDY 2 -#define AIM_CB_MISSED_IM 3 -#define AIM_CB_MISSED_CALL 4 -#define AIM_CB_LOGIN_P4_C1 5 -#define AIM_CB_LOGIN_P4_C2 6 -#define AIM_CB_LOGIN_P2_1 7 -#define AIM_CB_LOGIN_P2_2 8 -#define AIM_CB_LOGIN_P3_B 9 -#define AIM_CB_LOGIN_P3D_A 10 -#define AIM_CB_LOGIN_P3D_B 11 -#define AIM_CB_LOGIN_P3D_C 12 -#define AIM_CB_LOGIN_P3D_D 13 -#define AIM_CB_LOGIN_P3D_E 14 -#define AIM_CB_LOGIN_P3D_F 15 -#define AIM_CB_RATECHANGE 16 -#define AIM_CB_USERERROR 17 -#define AIM_CB_UNKNOWN 18 -#define AIM_CB_USERINFO 19 -#define AIM_CB_SEARCH_ADDRESS 20 -#define AIM_CB_SEARCH_NAME 21 -#define AIM_CB_SEARCH_FAIL 22 -#define AIM_CB_AUTH_ERROR 23 -#define AIM_CB_AUTH_SUCCESS 24 -#define AIM_CB_AUTH_SVRREADY 25 -#define AIM_CB_AUTH_OTHER 26 -#define AIM_CB_AUTH_INFOCHNG_REPLY 27 -#define AIM_CB_CHATNAV_SVRREADY 28 +int aim_parse_unknown(struct aim_session_t *, struct command_rx_struct *command, ...); +int aim_parse_missed_im(struct aim_session_t *, struct command_rx_struct *, ...); +int aim_parse_last_bad(struct aim_session_t *, struct command_rx_struct *, ...); + +struct command_tx_struct *aim_tx_new(int, struct aim_conn_t *, int); +int aim_tx_enqueue(struct aim_session_t *, struct command_tx_struct *); +u_int aim_get_next_txseqnum(struct aim_conn_t *); +int aim_tx_flushqueue(struct aim_session_t *); +int aim_tx_printqueue(struct aim_session_t *); +void aim_tx_purgequeue(struct aim_session_t *); -int Read(int, u_char *, int); +struct aim_rxcblist_t { + u_short family; + u_short type; + rxcallback_t handler; + u_short flags; + struct aim_rxcblist_t *next; +}; +int aim_conn_setlatency(struct aim_conn_t *conn, int newval); + +int aim_conn_addhandler(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short type, rxcallback_t newhandler, u_short flags); +rxcallback_t aim_callhandler(struct aim_conn_t *conn, u_short family, u_short type); +int aim_clearhandlers(struct aim_conn_t *conn); + +/* + * Generic SNAC structure. Rarely if ever used. + */ struct aim_snac_t { u_long id; u_short family; @@ -211,87 +333,170 @@ time_t issuetime; struct aim_snac_t *next; }; -u_long aim_newsnac(struct aim_snac_t *newsnac); -struct aim_snac_t *aim_remsnac(u_long id); -int aim_cleansnacs(int maxage); +u_long aim_newsnac(struct aim_session_t *, struct aim_snac_t *newsnac); +struct aim_snac_t *aim_remsnac(struct aim_session_t *, u_long id); +int aim_cleansnacs(struct aim_session_t *, int maxage); int aim_putsnac(u_char *, int, int, int, u_long); -void aim_connrst(void); -struct aim_conn_t *aim_conn_getnext(void); + +void aim_connrst(struct aim_session_t *); +struct aim_conn_t *aim_conn_getnext(struct aim_session_t *); void aim_conn_close(struct aim_conn_t *deadconn); -struct aim_conn_t *aim_getconn_type(int type); -struct aim_conn_t *aim_newconn(int type, char *dest); -int aim_conngetmaxfd(void); -struct aim_conn_t *aim_select(struct timeval *); +struct aim_conn_t *aim_getconn_type(struct aim_session_t *, int type); +struct aim_conn_t *aim_newconn(struct aim_session_t *, int type, char *dest); +int aim_conngetmaxfd(struct aim_session_t *); +struct aim_conn_t *aim_select(struct aim_session_t *, struct timeval *, int *); int aim_conn_isready(struct aim_conn_t *); int aim_conn_setstatus(struct aim_conn_t *, int); +void aim_session_init(struct aim_session_t *); /* aim_misc.c */ -#define AIM_VISIBILITYCHANGE_PERMITADD 0x05 +#define AIM_VISIBILITYCHANGE_PERMITADD 0x05 #define AIM_VISIBILITYCHANGE_PERMITREMOVE 0x06 -#define AIM_VISIBILITYCHANGE_DENYADD 0x07 -#define AIM_VISIBILITYCHANGE_DENYREMOVE 0x08 +#define AIM_VISIBILITYCHANGE_DENYADD 0x07 +#define AIM_VISIBILITYCHANGE_DENYREMOVE 0x08 -u_long aim_bos_setidle(struct aim_conn_t *, u_long); -u_long aim_bos_changevisibility(struct aim_conn_t *, int, char *); -u_long aim_bos_setbuddylist(struct aim_conn_t *, char *); -u_long aim_bos_setprofile(struct aim_conn_t *, char *); -u_long aim_bos_setgroupperm(struct aim_conn_t *, u_long); -u_long aim_bos_clientready(struct aim_conn_t *); -u_long aim_bos_reqrate(struct aim_conn_t *); -u_long aim_bos_ackrateresp(struct aim_conn_t *); -u_long aim_bos_setprivacyflags(struct aim_conn_t *, u_long); -u_long aim_bos_reqpersonalinfo(struct aim_conn_t *); -u_long aim_bos_reqservice(struct aim_conn_t *, u_short); -u_long aim_bos_reqrights(struct aim_conn_t *); -u_long aim_bos_reqbuddyrights(struct aim_conn_t *); -u_long aim_bos_reqlocaterights(struct aim_conn_t *); -u_long aim_bos_reqicbmparaminfo(struct aim_conn_t *); +u_long aim_bos_setidle(struct aim_session_t *, struct aim_conn_t *, u_long); +u_long aim_bos_changevisibility(struct aim_session_t *, struct aim_conn_t *, int, char *); +u_long aim_bos_setbuddylist(struct aim_session_t *, struct aim_conn_t *, char *); +u_long aim_bos_setprofile(struct aim_session_t *, struct aim_conn_t *, char *, char *, unsigned int); +u_long aim_bos_setgroupperm(struct aim_session_t *, struct aim_conn_t *, u_long); +u_long aim_bos_clientready(struct aim_session_t *, struct aim_conn_t *); +u_long aim_bos_reqrate(struct aim_session_t *, struct aim_conn_t *); +u_long aim_bos_ackrateresp(struct aim_session_t *, struct aim_conn_t *); +u_long aim_bos_setprivacyflags(struct aim_session_t *, struct aim_conn_t *, u_long); +u_long aim_bos_reqpersonalinfo(struct aim_session_t *, struct aim_conn_t *); +u_long aim_bos_reqservice(struct aim_session_t *, struct aim_conn_t *, u_short); +u_long aim_bos_reqrights(struct aim_session_t *, struct aim_conn_t *); +u_long aim_bos_reqbuddyrights(struct aim_session_t *, struct aim_conn_t *); +u_long aim_bos_reqlocaterights(struct aim_session_t *, struct aim_conn_t *); +u_long aim_bos_reqicbmparaminfo(struct aim_session_t *, struct aim_conn_t *); +u_long aim_setversions(struct aim_session_t *sess, struct aim_conn_t *conn); /* aim_rxhandlers.c */ -int aim_register_callbacks(rxcallback_t *); -int aim_rxdispatch(void); -int aim_authparse(struct command_rx_struct *); -int aim_handleredirect_middle(struct command_rx_struct *, ...); -int aim_parse_unknown(struct command_rx_struct *, ...); -int aim_parse_missed_im(struct command_rx_struct *, ...); -int aim_parse_last_bad(struct command_rx_struct *, ...); -int aim_parse_generalerrs(struct command_rx_struct *command, ...); +int aim_rxdispatch(struct aim_session_t *); +int aim_authparse(struct aim_session_t *, struct command_rx_struct *); +int aim_handleredirect_middle(struct aim_session_t *, struct command_rx_struct *, ...); +int aim_parse_unknown(struct aim_session_t *, struct command_rx_struct *, ...); +int aim_parse_last_bad(struct aim_session_t *, struct command_rx_struct *, ...); +int aim_parse_generalerrs(struct aim_session_t *, struct command_rx_struct *command, ...); +int aim_parsemotd_middle(struct aim_session_t *sess, struct command_rx_struct *command, ...); /* aim_im.c */ #define AIM_IMFLAGS_AWAY 0x01 /* mark as an autoreply */ -#define AIM_IMFLAGS_ACK 0x02 /* request a receipt notice */ -u_long aim_send_im(struct aim_conn_t *, char *, int, char *); -int aim_parse_incoming_im_middle(struct command_rx_struct *); +#define AIM_IMFLAGS_ACK 0x02 /* request a receipt notice */ + +u_long aim_send_im(struct aim_session_t *, struct aim_conn_t *, char *, u_int, char *); +int aim_parse_incoming_im_middle(struct aim_session_t *, struct command_rx_struct *); +u_long aim_seticbmparam(struct aim_session_t *, struct aim_conn_t *conn); +int aim_parse_msgerror_middle(struct aim_session_t *, struct command_rx_struct *); /* aim_info.c */ -u_long aim_getinfo(struct aim_conn_t *, const char *); -int aim_parse_userinfo_middle(struct command_rx_struct *); +#define AIM_CAPS_BUDDYICON 0x01 +#define AIM_CAPS_VOICE 0x02 +#define AIM_CAPS_IMIMAGE 0x04 +#define AIM_CAPS_CHAT 0x08 +#define AIM_CAPS_GETFILE 0x10 +#define AIM_CAPS_SENDFILE 0x20 +extern u_char aim_caps[6][16]; +u_long aim_getinfo(struct aim_session_t *, struct aim_conn_t *, const char *); +int aim_extractuserinfo(u_char *, struct aim_userinfo_s *); +int aim_parse_userinfo_middle(struct aim_session_t *, struct command_rx_struct *); +int aim_parse_oncoming_middle(struct aim_session_t *, struct command_rx_struct *); +int aim_parse_offgoing_middle(struct aim_session_t *, struct command_rx_struct *); +int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info); +int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info); +int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn); + /* aim_auth.c */ -int aim_auth_sendcookie(struct aim_conn_t *, char *); -u_long aim_auth_clientready(struct aim_conn_t *); -u_long aim_auth_changepasswd(struct aim_conn_t *, char *, char *); +int aim_auth_sendcookie(struct aim_session_t *, struct aim_conn_t *, u_char *); +u_long aim_auth_clientready(struct aim_session_t *, struct aim_conn_t *); +u_long aim_auth_changepasswd(struct aim_session_t *, struct aim_conn_t *, char *, char *); /* aim_buddylist.c */ -u_long aim_add_buddy(struct aim_conn_t *, char *); -u_long aim_remove_buddy(struct aim_conn_t *, char *); +u_long aim_add_buddy(struct aim_session_t *, struct aim_conn_t *, char *); +u_long aim_remove_buddy(struct aim_session_t *, struct aim_conn_t *, char *); /* aim_search.c */ -u_long aim_usersearch_address(struct aim_conn_t *, char *); -/* u_long aim_usersearch_name(struct aim_conn_t *, char *); */ +u_long aim_usersearch_address(struct aim_session_t *, struct aim_conn_t *, char *); +/* u_long aim_usersearch_name(struct aim_session_t *, struct aim_conn_t *, char *); */ + + +struct aim_chat_roominfo { + u_short exchange; + char *name; + u_short instance; +}; +int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo); +int aim_chat_parse_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command); +int aim_chat_parse_joined(struct aim_session_t *sess, struct command_rx_struct *command); +int aim_chat_parse_leave(struct aim_session_t *sess, struct command_rx_struct *command); +int aim_chat_parse_incoming(struct aim_session_t *sess, struct command_rx_struct *command); +u_long aim_chat_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, char *msg); +u_long aim_chat_join(struct aim_session_t *sess, struct aim_conn_t *conn, u_short exchange, const char *roomname); +u_long aim_chat_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); +int aim_chat_attachname(struct aim_conn_t *conn, char *roomname); +char *aim_chat_getname(struct aim_conn_t *conn); +struct aim_conn_t *aim_chat_getconn(struct aim_session_t *, char *name); + +u_long aim_chatnav_reqrights(struct aim_session_t *sess, struct aim_conn_t *conn); +u_long aim_chatnav_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); + +u_long aim_chat_invite(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, char *msg, u_short exchange, char *roomname, u_short instance); + +struct aim_chat_exchangeinfo { + u_short number; + char *name; + char *charset1; + char *lang1; + char *charset2; + char *lang2; +}; +int aim_chatnav_parse_info(struct aim_session_t *sess, struct command_rx_struct *command); +u_long aim_chatnav_createroom(struct aim_session_t *sess, struct aim_conn_t *conn, char *name, u_short exchange); +int aim_chat_leaveroom(struct aim_session_t *sess, char *name); /* aim_util.c */ -int aimutil_put8(u_char *, u_short); +#ifdef AIMUTIL_USEMACROS +/* + * These are really ugly. You'd think this was LISP. I wish it was. + */ +#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) +#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) +#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); -int aimutil_putstr(u_char *, u_char *, int); +u_long aimutil_get32(u_char *); +#endif -/* proxy support */ -#ifdef ENABLE_PROXY_SUPPORT -#include "proxy.h" -#endif +int aimutil_putstr(u_char *, const u_char *, int); +int aimutil_tokslen(char *toSearch, int index, char dl); +int aimutil_itemcnt(char *toSearch, char dl); +char *aimutil_itemidx(char *toSearch, int index, char dl); + +int aim_snlen(const char *sn); +int aim_sncmp(const char *sn1, const char *sn2); #endif /* __AIM_H__ */ diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_auth.c --- a/libfaim/aim_auth.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_auth.c Sat May 20 00:30:53 2000 +0000 @@ -5,145 +5,103 @@ */ -#include "aim.h" +#include /* this just pushes the passed cookie onto the passed connection -- NO SNAC! */ -int aim_auth_sendcookie(struct aim_conn_t *conn, char *chipsahoy) +int aim_auth_sendcookie(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_char *chipsahoy) { - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; int curbyte=0; - newpacket.lock = 1; + if (!(newpacket = aim_tx_new(0x0001, conn, 4+2+2+AIM_COOKIELEN))) + return -1; - if (conn==NULL) - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_AUTH); - else - newpacket.conn = conn; + newpacket->lock = 1; - newpacket.type = 0x0001; /* channel 1 (no SNACs, you know) */ - - newpacket.commandlen = 4 + 2 + 2 + 0x100; - newpacket.data = (char *) calloc(1, newpacket.commandlen); - - 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, 0x0100); - memcpy(&(newpacket.data[curbyte]), chipsahoy, 0x100); + 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(&newpacket); - - return 0; + return aim_tx_enqueue(sess, newpacket); } -u_long aim_auth_clientready(struct aim_conn_t *conn) +u_long aim_auth_clientready(struct aim_session_t *sess, + struct aim_conn_t *conn) { - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; int curbyte = 0; - newpacket.lock = 1; + if (!(newpacket = aim_tx_new(0x0002, conn, 26))) + return -1; - if (conn==NULL) - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_AUTH); - else - newpacket.conn = conn; + newpacket->lock = 1; - newpacket.type = 0x0002; - - newpacket.commandlen = 26; - newpacket.data = (char *) malloc(newpacket.commandlen); - - curbyte += aim_putsnac(newpacket.data+curbyte, 0x0001, 0x0002, 0x0000, aim_snac_nextid); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0002); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0013); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0007); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); + curbyte += aim_putsnac(newpacket->data+curbyte, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0013); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0007); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); - aim_tx_enqueue(&newpacket); + aim_tx_enqueue(sess, newpacket); { struct aim_snac_t snac; - snac.id = aim_snac_nextid; + snac.id = sess->snac_nextid; snac.family = 0x0001; snac.type = 0x0004; snac.flags = 0x0000; snac.data = NULL; - aim_newsnac(&snac); + aim_newsnac(sess, &snac); } - return (aim_snac_nextid++); + return (sess->snac_nextid++); } -u_long aim_auth_changepasswd(struct aim_conn_t *conn, char *new, char *current) +u_long aim_auth_changepasswd(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *new, char *current) { - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; int i; - newpacket.lock = 1; - - if (conn==NULL) - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_AUTH); - else - newpacket.conn = conn; - - newpacket.type = 0x0002; - - newpacket.commandlen = 10 + 4 + strlen(current) + 4 + strlen(new); - newpacket.data = (char *) malloc(newpacket.commandlen); + if (!(newpacket = aim_tx_new(0x0002, conn, 10+4+strlen(current)+4+strlen(new)))) + return -1; - newpacket.data[0] = 0x00; - newpacket.data[1] = 0x07; - - newpacket.data[2] = 0x00; - newpacket.data[3] = 0x04; + newpacket->lock = 1; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; - - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + i = aim_putsnac(newpacket->data, 0x0007, 0x0004, 0x0000, sess->snac_nextid); /* current password TLV t(0002) */ - i = 10; - newpacket.data[i++] = 0x00; - newpacket.data[i++] = 0x02; - newpacket.data[i++] = 0x00; - newpacket.data[i++] = strlen(current) & 0xff; - memcpy(&(newpacket.data[i]), current, strlen(current)); - i += strlen(current); + i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(current), current); /* new password TLV t(0012) */ - newpacket.data[i++] = 0x00; - newpacket.data[i++] = 0x12; - newpacket.data[i++] = 0x00; - newpacket.data[i++] = strlen(new) & 0xff; - memcpy(&(newpacket.data[i]), new, strlen(new)); - i+=strlen(new); + i += aim_puttlv_str(newpacket->data+i, 0x0012, strlen(new), new); - aim_tx_enqueue(&newpacket); + aim_tx_enqueue(sess, newpacket); { struct aim_snac_t snac; - snac.id = aim_snac_nextid; + snac.id = sess->snac_nextid; snac.family = 0x0001; snac.type = 0x0004; snac.flags = 0x0000; snac.data = NULL; - aim_newsnac(&snac); + aim_newsnac(sess, &snac); } - return (aim_snac_nextid++); + return (sess->snac_nextid++); } diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_buddylist.c --- a/libfaim/aim_buddylist.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_buddylist.c Sat May 20 00:30:53 2000 +0000 @@ -7,47 +7,31 @@ * Adds a single buddy to your buddy list after login. * */ -u_long aim_add_buddy(struct aim_conn_t *conn, char *sn ) +u_long aim_add_buddy(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *sn ) { - struct command_tx_struct newpacket; - - if( !sn ) - return -1; + struct command_tx_struct *newpacket; + int i; - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - - newpacket.lock = 1; - newpacket.type = 0x0002; - newpacket.commandlen = 11 + strlen( sn ); - newpacket.data = (char *)malloc( newpacket.commandlen ); + if(!sn) + return -1; - newpacket.data[0] = 0x00; - newpacket.data[1] = 0x03; - newpacket.data[2] = 0x00; - newpacket.data[3] = 0x04; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; + if (!(newpacket = aim_tx_new(0x0002, conn, 10+1+strlen(sn)))) + return -1; + + newpacket->lock = 1; - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + 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)); - /* length of screenname */ - newpacket.data[10] = strlen( sn ); - - memcpy( &(newpacket.data[11]), sn, strlen( sn ) ); - - aim_tx_enqueue( &newpacket ); + aim_tx_enqueue(sess, newpacket ); { struct aim_snac_t snac; - snac.id = aim_snac_nextid; + snac.id = sess->snac_nextid; snac.family = 0x0003; snac.type = 0x0004; snac.flags = 0x0000; @@ -55,53 +39,38 @@ snac.data = malloc( strlen( sn ) + 1 ); memcpy( snac.data, sn, strlen( sn ) + 1 ); - aim_newsnac( &snac ); + aim_newsnac(sess, &snac); } - return( aim_snac_nextid++ ); + return( sess->snac_nextid++ ); } -u_long aim_remove_buddy(struct aim_conn_t *conn, char *sn ) +u_long aim_remove_buddy(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *sn ) { - struct command_tx_struct newpacket; - - if( !sn ) - return -1; + struct command_tx_struct *newpacket; + int i; - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - - newpacket.lock = 1; - newpacket.type = 0x0002; - newpacket.commandlen = 11 + strlen(sn); - newpacket.data = (char *)malloc( newpacket.commandlen ); + if(!sn) + return -1; - newpacket.data[0] = 0x00; - newpacket.data[1] = 0x03; - newpacket.data[2] = 0x00; - newpacket.data[3] = 0x05; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; + if (!(newpacket = aim_tx_new(0x0002, conn, 10+1+strlen(sn)))) + return -1; + + newpacket->lock = 1; - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + i = aim_putsnac(newpacket->data, 0x0003, 0x0005, 0x0000, sess->snac_nextid); - /* length of screenname */ - newpacket.data[10] = strlen( sn ); + i += aimutil_put8(newpacket->data+i, strlen(sn)); + i += aimutil_putstr(newpacket->data+i, sn, strlen(sn)); - memcpy( &(newpacket.data[11]), sn, strlen( sn ) ); - - aim_tx_enqueue( &newpacket ); + aim_tx_enqueue(sess, newpacket); { struct aim_snac_t snac; - snac.id = aim_snac_nextid; + snac.id = sess->snac_nextid; snac.family = 0x0003; snac.type = 0x0005; snac.flags = 0x0000; @@ -109,9 +78,9 @@ snac.data = malloc( strlen( sn ) + 1 ); memcpy( snac.data, sn, strlen( sn ) + 1 ); - aim_newsnac( &snac ); + aim_newsnac(sess, &snac ); } - return( aim_snac_nextid++ ); + return( sess->snac_nextid++ ); } diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_cbtypes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfaim/aim_cbtypes.h Sat May 20 00:30:53 2000 +0000 @@ -0,0 +1,197 @@ +/* + * AIM Callback Types + * + */ +#ifndef __AIM_CBTYPES_H__ +#define __AIM_CBTYPES_H__ + +/* + * SNAC Families. + */ +#define AIM_CB_FAM_ACK 0x0000 +#define AIM_CB_FAM_GEN 0x0001 +#define AIM_CB_FAM_LOC 0x0002 +#define AIM_CB_FAM_BUD 0x0003 +#define AIM_CB_FAM_MSG 0x0004 +#define AIM_CB_FAM_ADS 0x0005 +#define AIM_CB_FAM_INV 0x0006 +#define AIM_CB_FAM_ADM 0x0007 +#define AIM_CB_FAM_POP 0x0008 +#define AIM_CB_FAM_BOS 0x0009 +#define AIM_CB_FAM_LOK 0x000a +#define AIM_CB_FAM_STS 0x000b +#define AIM_CB_FAM_TRN 0x000c +#define AIM_CB_FAM_CTN 0x000d /* ChatNav */ +#define AIM_CB_FAM_CHT 0x000e /* Chat */ +#define AIM_CB_FAM_ATH 0x0017 +#define AIM_CB_FAM_SPECIAL 0xffff /* Internal libfaim use */ + +/* + * SNAC Family: Ack. + * + * Not really a family, but treating it as one really + * helps it fit into the libfaim callback structure better. + * + */ +#define AIM_CB_ACK_ACK 0x0001 + +/* + * SNAC Family: General. + */ +#define AIM_CB_GEN_ERROR 0x0001 +#define AIM_CB_GEN_CLIENTREADY 0x0002 +#define AIM_CB_GEN_SERVERREADY 0x0003 +#define AIM_CB_GEN_SERVICEREQ 0x0004 +#define AIM_CB_GEN_REDIRECT 0x0005 +#define AIM_CB_GEN_RATEINFOREQ 0x0006 +#define AIM_CB_GEN_RATEINFO 0x0007 +#define AIM_CB_GEN_RATEINFOACK 0x0008 +#define AIM_CB_GEN_RATECHANGE 0x000a +#define AIM_CB_GEN_SERVERPAUSE 0x000b +#define AIM_CB_GEN_SERVERRESUME 0x000d +#define AIM_CB_GEN_REQSELFINFO 0x000e +#define AIM_CB_GEN_SELFINFO 0x000f +#define AIM_CB_GEN_EVIL 0x0010 +#define AIM_CB_GEN_SETIDLE 0x0011 +#define AIM_CB_GEN_MIGRATIONREQ 0x0012 +#define AIM_CB_GEN_MOTD 0x0013 +#define AIM_CB_GEN_SETPRIVFLAGS 0x0014 +#define AIM_CB_GEN_WELLKNOWNURL 0x0015 +#define AIM_CB_GEN_NOP 0x0016 +#define AIM_CB_GEN_DEFAULT 0xffff + +/* + * SNAC Family: Location Services. + */ +#define AIM_CB_LOC_ERROR 0x0001 +#define AIM_CB_LOC_REQRIGHTS 0x0002 +#define AIM_CB_LOC_RIGHTSINFO 0x0003 +#define AIM_CB_LOC_SETUSERINFO 0x0004 +#define AIM_CB_LOC_REQUSERINFO 0x0005 +#define AIM_CB_LOC_USERINFO 0x0006 +#define AIM_CB_LOC_WATCHERSUBREQ 0x0007 +#define AIM_CB_LOC_WATCHERNOT 0x0008 +#define AIM_CB_LOC_DEFAULT 0xffff + +/* + * SNAC Family: Buddy List Management Services. + */ +#define AIM_CB_BUD_ERROR 0x0001 +#define AIM_CB_BUD_REQRIGHTS 0x0002 +#define AIM_CB_BUD_RIGHTSINFO 0x0003 +#define AIM_CB_BUD_ADDBUDDY 0x0004 +#define AIM_CB_BUD_REMBUDDY 0x0005 +#define AIM_CB_BUD_REJECT 0x000a +#define AIM_CB_BUD_ONCOMING 0x000b +#define AIM_CB_BUD_OFFGOING 0x000c +#define AIM_CB_BUD_DEFAULT 0xffff + +/* + * SNAC Family: Messeging Services. + */ +#define AIM_CB_MSG_ERROR 0x0001 +#define AIM_CB_MSG_PARAMINFO 0x0005 +#define AIM_CB_MSG_INCOMING 0x0007 +#define AIM_CB_MSG_EVIL 0x0009 +#define AIM_CB_MSG_MISSEDCALL 0x000a +#define AIM_CB_MSG_CLIENTERROR 0x000b +#define AIM_CB_MSG_ACK 0x000c +#define AIM_CB_MSG_DEFAULT 0xffff + +/* + * SNAC Family: Advertisement Services + */ +#define AIM_CB_ADS_ERROR 0x0001 +#define AIM_CB_ADS_DEFAULT 0xffff + +/* + * SNAC Family: Invitation Services. + */ +#define AIM_CB_INV_ERROR 0x0001 +#define AIM_CB_INV_DEFAULT 0xffff + +/* + * SNAC Family: Administrative Services. + */ +#define AIM_CB_ADM_ERROR 0x0001 +#define AIM_CB_ADM_INFOCHANGE_REPLY 0x0005 +#define AIM_CB_ADM_DEFAULT 0xffff + +/* + * SNAC Family: Popup Messages + */ +#define AIM_CB_POP_ERROR 0x0001 +#define AIM_CB_POP_DEFAULT 0xffff + +/* + * SNAC Family: Misc BOS Services. + */ +#define AIM_CB_BOS_ERROR 0x0001 +#define AIM_CB_BOS_DEFAULT 0xffff + +/* + * SNAC Family: User Lookup Services + */ +#define AIM_CB_LOK_ERROR 0x0001 +#define AIM_CB_LOK_DEFAULT 0xffff + +/* + * SNAC Family: User Status Services + */ +#define AIM_CB_STS_ERROR 0x0001 +#define AIM_CB_STS_SETREPORTINTERVAL 0x0002 +#define AIM_CB_STS_REPORTACK 0x0004 +#define AIM_CB_STS_DEFAULT 0xffff + +/* + * SNAC Family: Translation Services + */ +#define AIM_CB_TRN_ERROR 0x0001 +#define AIM_CB_TRN_DEFAULT 0xffff + +/* + * SNAC Family: Chat Navigation Services + */ +#define AIM_CB_CTN_ERROR 0x0001 +#define AIM_CB_CTN_CREATE 0x0008 +#define AIM_CB_CTN_INFO 0x0009 +#define AIM_CB_CTN_DEFAULT 0xffff + +/* + * SNAC Family: Chat Services + */ +#define AIM_CB_CHT_ERROR 0x0001 +#define AIM_CB_CHT_ROOMINFOUPDATE 0x0002 +#define AIM_CB_CHT_USERJOIN 0x0003 +#define AIM_CB_CHT_USERLEAVE 0x0004 +#define AIM_CB_CHT_OUTGOINGMSG 0x0005 +#define AIM_CB_CHT_INCOMINGMSG 0x0006 +#define AIM_CB_CHT_DEFAULT 0xffff + +/* + * SNAC Family: Authorizer + * + * Used only in protocol versions three and above. + * + */ +#define AIM_CB_ATH_ERROR 0x0001 +#define AIM_CB_ATH_LOGINREQEST 0x0002 +#define AIM_CB_ATH_LOGINRESPONSE 0x0003 +#define AIM_CB_ATH_AUTHREQ 0x0006 +#define AIM_CB_ATH_AUTHRESPONSE 0x0007 + +/* + * SNAC Family: Internal Messages + * + * This isn't truely a SNAC family either, but using + * these, we can integrated non-SNAC services into + * the SNAC-centered libfaim callback structure. + * + */ +#define AIM_CB_SPECIAL_AUTHSUCCESS 0x0001 +#define AIM_CB_SPECIAL_AUTHOTHER 0x0002 +#define AIM_CB_SPECIAL_UNKNOWN 0xffff +#define AIM_CB_SPECIAL_DEFAULT AIM_CB_SPECIAL_UNKNOWN + + +#endif/*__AIM_CBTYPES_H__ */ diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_chat.c --- a/libfaim/aim_chat.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_chat.c Sat May 20 00:30:53 2000 +0000 @@ -5,76 +5,645 @@ * */ -#include "aim.h" +#include + +char *aim_chat_getname(struct aim_conn_t *conn) +{ + if (!conn) + return NULL; + if (conn->type != AIM_CONN_TYPE_CHAT) + return NULL; + + return (char *)conn->priv; /* yuck ! */ +} + +struct aim_conn_t *aim_chat_getconn(struct aim_session_t *sess, char *name) +{ + int i; + + for (i=0;iconns[i].type == AIM_CONN_TYPE_CHAT) + { + if (sess->conns[i].priv) + if (!strcmp((char *)sess->conns[i].priv, name)) + { + return &sess->conns[i]; + } + } + } + return NULL; +} + +int aim_chat_attachname(struct aim_conn_t *conn, char *roomname) +{ + if (!conn || !roomname) + return -1; + + conn->priv = malloc(strlen(roomname)+1); + strcpy(conn->priv, roomname); + + return 0; +} + +u_long aim_chat_send_im(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *msg) +{ + + int curbyte,i; + struct command_tx_struct *newpacket; + + if (!sess || !conn || !msg) + return 0; + + if (!(newpacket = aim_tx_new(0x0002, conn, 1152))) + return -1; + + newpacket->lock = 1; /* lock struct */ + + curbyte = 0; + curbyte += aim_putsnac(newpacket->data+curbyte, + 0x000e, 0x0005, 0x0000, sess->snac_nextid); + + /* + * Generate a random message cookie + */ + for (i=0;i<8;i++) + curbyte += aimutil_put8(newpacket->data+curbyte, (u_char) random()); + + /* + * metaTLV start. -- i assume this is a metaTLV. it could be the + * channel ID though. + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); + + /* + * Type 1: Unknown. Blank. + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + + /* + * Type 6: Unknown. Blank. + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0006); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + + /* + * 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); + + /* + * SubTLV: Type 1: Message + */ + curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(msg), msg); + + newpacket->commandlen = curbyte; + + newpacket->lock = 0; + aim_tx_enqueue(sess, newpacket); + + return (sess->snac_nextid++); +} /* - * FIXME: Doesn't work. + * 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. * */ -u_long aim_chat_join(struct aim_conn_t *conn, const char *roomname) +u_long aim_chat_join(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_short exchange, + const char *roomname) { - struct command_tx_struct newpacket; - - newpacket.lock = 1; - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - newpacket.type = 0x0002; + struct command_tx_struct *newpacket; + int i; + + if (!sess || !conn || !roomname) + return 0; - newpacket.commandlen = 12+7+strlen(roomname)+6; - newpacket.data = (char *) malloc(newpacket.commandlen); - memset(newpacket.data, 0x00, newpacket.commandlen); + if (!(newpacket = aim_tx_new(0x0002, conn, 10+9+strlen(roomname)+2))) + return -1; - newpacket.data[0] = 0x00; - newpacket.data[1] = 0x01; + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x0001, 0x0004, 0x0000, sess->snac_nextid); - newpacket.data[2] = 0x00; - newpacket.data[3] = 0x04; - - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; + i+= aimutil_put16(newpacket->data+i, 0x000e); - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + /* + * 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)); + memcpy(newpacket->data+i, roomname, strlen(roomname)); + i+= strlen(roomname); + //i+= aimutil_putstr(newpacket->data+i, roomname, strlen(roomname)); + i+= aimutil_put16(newpacket->data+i, 0x0000); - newpacket.data[10] = 0x00; - newpacket.data[11] = 0x0e; - newpacket.data[12] = 0x00; - newpacket.data[13] = 0x01; - newpacket.data[14] = 0x00; - newpacket.data[15] = 0x0c; - newpacket.data[16] = 0x00; - newpacket.data[17] = 0x04; - newpacket.data[18] = strlen(roomname) & 0x00ff; - memcpy(&(newpacket.data[19]), roomname, strlen(roomname)); - - { - int i = 0; - printf("\n\n\n"); - for (i = 0;i < newpacket.commandlen; i++) - printf("0x%02x ", newpacket.data[i]); - printf("\n\n\n"); - } + /* + * 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 = (char *)malloc(strlen(roomname)+1); + strcpy(sess->pendingjoin, roomname); - aim_tx_enqueue(&newpacket); + newpacket->lock = 0; + aim_tx_enqueue(sess, newpacket); +#if 0 { struct aim_snac_t snac; - snac.id = aim_snac_nextid; + snac.id = sess->snac_nextid; snac.family = 0x0001; snac.type = 0x0004; snac.flags = 0x0000; - snac.data = malloc(strlen(roomname)); - memcpy(snac.data, roomname, strlen(roomname)); + snac.data = malloc(strlen(roomname)+1); + strcpy(snac.data, roomname); - aim_newsnac(&snac); + aim_newsnac(sess, &snac); } - return (aim_snac_nextid++); +#endif + return (sess->snac_nextid++); +} + +int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo) +{ + int namelen = 0; + int i = 0; + + if (!buf || !outinfo) + return 0; + + outinfo->exchange = aimutil_get16(buf+i); + i += 2; + + namelen = aimutil_get8(buf+i); + i += 1; + + 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; +}; + + +/* + * General room information. Lots of stuff. + * + * Values I know are in here but I havent attached + * them to any of the 'Unknown's: + * - Language (English) + * + */ +int aim_chat_parse_infoupdate(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + struct aim_userinfo_s *userinfo = NULL; + rxcallback_t userfunc=NULL; + int ret = 1, i = 0; + int usercount = 0; + u_char detaillevel = 0; + char *roomname = NULL; + struct aim_chat_roominfo roominfo; + u_short tlvcount = 0; + struct aim_tlvlist_t *tlvlist; + char *roomdesc = NULL; + + i = 10; + i += aim_chat_readroominfo(command->data+i, &roominfo); + + detaillevel = aimutil_get8(command->data+i); + i++; + + tlvcount = aimutil_get16(command->data+i); + i += 2; + + /* + * Everything else are TLVs. + */ + tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); + + /* + * TLV type 0x006a is the room name in Human Readable Form. + */ + if (aim_gettlv(tlvlist, 0x006a, 1)) + roomname = aim_gettlv_str(tlvlist, 0x006a, 1); + + /* + * Type 0x006f: Number of occupants. + */ + if (aim_gettlv(tlvlist, 0x006f, 1)) + { + struct aim_tlv_t *tmptlv; + tmptlv = aim_gettlv(tlvlist, 0x006f, 1); + + usercount = aimutil_get16(tmptlv->value); + } + + /* + * Type 0x0073: Occupant list. + */ + if (aim_gettlv(tlvlist, 0x0073, 1)) + { + int curoccupant = 0; + struct aim_tlv_t *tmptlv; + + tmptlv = aim_gettlv(tlvlist, 0x0073, 1); + + /* Allocate enough userinfo structs for all occupants */ + userinfo = calloc(usercount, sizeof(struct aim_userinfo_s)); + + i = 0; + while (curoccupant < usercount) + i += aim_extractuserinfo(tmptlv->value+i, &userinfo[curoccupant++]); + } + + /* + * Type 0x00c9: Unknown. + */ + if (aim_gettlv(tlvlist, 0x00c9, 1)) + ; + + /* + * Type 0x00ca: Creation date + */ + if (aim_gettlv(tlvlist, 0x00ca, 1)) + ; + + /* + * Type 0x00d1: Maximum Message Length + */ + if (aim_gettlv(tlvlist, 0x00d1, 1)) + ; + + /* + * Type 0x00d2: Unknown. + */ + if (aim_gettlv(tlvlist, 0x00d2, 1)) + ; + + /* + * Type 0x00d3: Room Description + */ + if (aim_gettlv(tlvlist, 0x00d3, 1)) + roomdesc = aim_gettlv_str(tlvlist, 0x00d3, 1); + + /* + * Type 0x00d5: Unknown. + */ + if (aim_gettlv(tlvlist, 0x00d5, 1)) + ; + + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE); + if (userfunc) + { + ret = userfunc(sess, + command, + &roominfo, + roomname, + usercount, + userinfo, + roomdesc); + } + free(roominfo.name); + free(userinfo); + free(roomname); + free(roomdesc); + aim_freetlvchain(&tlvlist); + + return ret; } + +int aim_chat_parse_joined(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + struct aim_userinfo_s *userinfo = NULL; + rxcallback_t userfunc=NULL; + int i = 10, curcount = 0, ret = 1; + + while (i < command->commandlen) + { + curcount++; + userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); + i += aim_extractuserinfo(command->data+i, &userinfo[curcount-1]); + } + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN); + if (userfunc) + { + ret = userfunc(sess, + command, + curcount, + userinfo); + } + + free(userinfo); + + return ret; +} + +int aim_chat_parse_leave(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + + struct aim_userinfo_s *userinfo = NULL; + rxcallback_t userfunc=NULL; + int i = 10, curcount = 0, ret = 1; + + while (i < command->commandlen) + { + curcount++; + userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); + i += aim_extractuserinfo(command->data+i, &userinfo[curcount-1]); + } + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE); + if (userfunc) + { + ret = userfunc(sess, + command, + curcount, + userinfo); + } + + free(userinfo); + + return ret; +} + +/* + * We could probably include this in the normal ICBM parsing + * code as channel 0x0003, however, since only the start + * would be the same, we might as well do it here. + */ +int aim_chat_parse_incoming(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + struct aim_userinfo_s userinfo; + rxcallback_t userfunc=NULL; + int ret = 1, i = 0, z = 0; + u_char cookie[8]; + int channel; + struct aim_tlvlist_t *outerlist; + char *msg = NULL; + + memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); + + i = 10; /* skip snac */ + + /* + * ICBM Cookie. Ignore it. + */ + for (z=0; z<8; z++,i++) + cookie[z] = command->data[i]; + + /* + * Channel ID + * + * Channels 1 and 2 are implemented in the normal ICBM + * parser. + * + * We only do channel 3 here. + * + */ + channel = aimutil_get16(command->data+i); + i += 2; + + if (channel != 0x0003) + { + printf("faim: chat_incoming: unknown channel! (0x%04x)\n", channel); + return 1; + } + + /* + * Start parsing TLVs right away. + */ + outerlist = aim_readtlvchain(command->data+i, command->commandlen-i); + + /* + * Type 0x0003: Source User Information + */ + if (aim_gettlv(outerlist, 0x0003, 1)) + { + struct aim_tlv_t *userinfotlv; + + userinfotlv = aim_gettlv(outerlist, 0x0003, 1); + aim_extractuserinfo(userinfotlv->value, &userinfo); + } + + /* + * Type 0x0001: Unknown. + */ + if (aim_gettlv(outerlist, 0x0001, 1)) + ; + + /* + * Type 0x0005: Message Block. Conains more TLVs. + */ + if (aim_gettlv(outerlist, 0x0005, 1)) + { + struct aim_tlvlist_t *innerlist; + struct aim_tlv_t *msgblock; + + msgblock = aim_gettlv(outerlist, 0x0005, 1); + innerlist = aim_readtlvchain(msgblock->value, msgblock->length); + + /* + * Type 0x0001: Message. + */ + if (aim_gettlv(innerlist, 0x0001, 1)) + msg = aim_gettlv_str(innerlist, 0x0001, 1); + + aim_freetlvchain(&innerlist); + } + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG); + if (userfunc) + { + ret = userfunc(sess, + command, + &userinfo, + msg); + } + free(msg); + aim_freetlvchain(&outerlist); + + return ret; +} + +u_long aim_chat_clientready(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct command_tx_struct *newpacket; + int i; + + if (!(newpacket = aim_tx_new(0x0002, conn, 0x20))) + return -1; + + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + + i+= aimutil_put16(newpacket->data+i, 0x000e); + i+= aimutil_put16(newpacket->data+i, 0x0001); + + i+= aimutil_put16(newpacket->data+i, 0x0004); + i+= aimutil_put16(newpacket->data+i, 0x0001); + + i+= aimutil_put16(newpacket->data+i, 0x0001); + i+= aimutil_put16(newpacket->data+i, 0x0003); + + i+= aimutil_put16(newpacket->data+i, 0x0004); + i+= aimutil_put16(newpacket->data+i, 0x0686); + + newpacket->lock = 0; + aim_tx_enqueue(sess, newpacket); + + return (sess->snac_nextid++); +} + +int aim_chat_leaveroom(struct aim_session_t *sess, char *name) +{ + int i; + + for (i=0;iconns[i].type == AIM_CONN_TYPE_CHAT) + { + if (sess->conns[i].priv) + if (!strcmp((char *)sess->conns[i].priv, name)) + { + aim_conn_close(&sess->conns[i]); + return 0; + } + } + } + return -1; +} + +/* + * conn must be a BOS connection! + */ +u_long aim_chat_invite(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *sn, + char *msg, + u_short exchange, + char *roomname, + u_short instance) +{ + struct command_tx_struct *newpacket; + int i,curbyte=0; + + if (!sess || !conn || !sn || !msg || !roomname) + return 0; + + if (!(newpacket = aim_tx_new(0x0002, conn, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) + return -1; + + newpacket->lock = 1; + + curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid); + + /* + * Cookie + */ + for (i=0;i<8;i++) + curbyte += aimutil_put8(newpacket->data+curbyte, (u_char)rand()); + + /* + * Channel (2) + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); + + /* + * Dest sn + */ + curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sn)); + curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn)); + + /* + * TLV t(0005) + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x28+strlen(msg)+0x04+0x03+strlen(roomname)+0x02); + + /* + * Unknown info + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x3131); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x3538); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x3446); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x4100); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x748f); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x2420); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x6287); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x11d1); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x8222); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x4445); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x5354); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + + /* + * TLV t(000a) -- Unknown + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + + /* + * TLV t(000f) -- Unknown + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + + /* + * TLV t(000c) -- Invitation message + */ + curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000c, strlen(msg), msg); + + /* + * TLV t(2711) -- Container for room information + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711); + curbyte += aimutil_put16(newpacket->data+curbyte, 3+strlen(roomname)+2); + curbyte += aimutil_put16(newpacket->data+curbyte, exchange); + curbyte += aimutil_put8(newpacket->data+curbyte, strlen(roomname)); + curbyte += aimutil_putstr(newpacket->data+curbyte, roomname, strlen(roomname)); + curbyte += aimutil_put16(newpacket->data+curbyte, instance); + + newpacket->commandlen = curbyte; + newpacket->lock = 0; + aim_tx_enqueue(sess, newpacket); + + return (sess->snac_nextid++); +} diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_chatnav.c --- a/libfaim/aim_chatnav.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_chatnav.c Sat May 20 00:30:53 2000 +0000 @@ -5,5 +5,319 @@ * */ -#include "aim.h" +#include + + +/* + * conn must be a chatnav connection! + */ +u_long aim_chatnav_reqrights(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct aim_snac_t snac; + + snac.id = aim_genericreq_n(sess, conn, 0x000d, 0x0002); + + snac.family = 0x000d; + snac.type = 0x0002; + snac.flags = 0x0000; + snac.data = NULL; + + aim_newsnac(sess, &snac); + + return (sess->snac_nextid); /* already incremented */ +} + +u_long aim_chatnav_clientready(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct command_tx_struct *newpacket; + int i; + + if (!(newpacket = aim_tx_new(0x0002, conn, 0x20))) + return -1; + + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + + i+= aimutil_put16(newpacket->data+i, 0x000d); + i+= aimutil_put16(newpacket->data+i, 0x0001); + + i+= aimutil_put16(newpacket->data+i, 0x0004); + i+= aimutil_put16(newpacket->data+i, 0x0001); + + i+= aimutil_put16(newpacket->data+i, 0x0001); + i+= aimutil_put16(newpacket->data+i, 0x0003); + + i+= aimutil_put16(newpacket->data+i, 0x0004); + i+= aimutil_put16(newpacket->data+i, 0x0686); + + aim_tx_enqueue(sess, newpacket); + + return (sess->snac_nextid++); +} + +/* + * Since multiple things can trigger this callback, + * we must lookup the snacid to determine the original + * snac subtype that was called. + */ +int aim_chatnav_parse_info(struct aim_session_t *sess, struct command_rx_struct *command) +{ + struct aim_snac_t *snac; + u_long snacid; + rxcallback_t userfunc; + + snacid = aimutil_get32(command->data+6); + snac = aim_remsnac(sess, snacid); + + if (!snac) + { + printf("faim: chatnav_parse_info: received response to unknown request! (%08lx)\n", snacid); + return 1; + } + + if (snac->family != 0x000d) + { + printf("faim: chatnav_parse_info: recieved response that maps to corrupt request! (fam=%04x)\n", snac->family); + return 1; + } + + /* + * We now know what the original SNAC subtype was. + */ + switch(snac->type) + { + case 0x0002: /* request chat rights */ + { + struct aim_tlvlist_t *tlvlist; + struct aim_chat_exchangeinfo *exchanges = NULL; + int curexchange = 0; + struct aim_tlv_t *exchangetlv; + u_char maxrooms = 0; + int ret = 1; + struct aim_tlvlist_t *innerlist; + + tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10); + + /* + * Type 0x0002: Maximum concurrent rooms. + */ + if (aim_gettlv(tlvlist, 0x0002, 1)) + { + struct aim_tlv_t *maxroomstlv; + maxroomstlv = aim_gettlv(tlvlist, 0x0002, 1); + maxrooms = aimutil_get8(maxroomstlv->value); + } + + /* + * Type 0x0003: Exchange information + * + * There can be any number of these, each one + * representing another exchange. + * + */ + curexchange = 0; + while ((exchangetlv = aim_gettlv(tlvlist, 0x0003, curexchange+1))) + { + curexchange++; + exchanges = realloc(exchanges, curexchange * sizeof(struct aim_chat_exchangeinfo)); + + /* exchange number */ + exchanges[curexchange-1].number = aimutil_get16(exchangetlv->value); + innerlist = aim_readtlvchain(exchangetlv->value+2, exchangetlv->length-2); + + /* + * Type 0x000d: Unknown. + */ + if (aim_gettlv(innerlist, 0x000d, 1)) + ; + + /* + * Type 0x0004: Unknown + */ + if (aim_gettlv(innerlist, 0x0004, 1)) + ; + + /* + * Type 0x00c9: Unknown + */ + if (aim_gettlv(innerlist, 0x00c9, 1)) + ; + + /* + * Type 0x00ca: Creation Date + */ + if (aim_gettlv(innerlist, 0x00ca, 1)) + ; + + /* + * Type 0x00d0: Unknown + */ + if (aim_gettlv(innerlist, 0x00d0, 1)) + ; + /* + * Type 0x00d1: Maximum Message length + */ + if (aim_gettlv(innerlist, 0x00d1, 1)) + ; + + /* + * Type 0x00d2: Unknown + */ + if (aim_gettlv(innerlist, 0x00d2, 1)) + ; + + /* + * Type 0x00d3: Exchange Name + */ + if (aim_gettlv(innerlist, 0x00d3, 1)) + exchanges[curexchange-1].name = aim_gettlv_str(innerlist, 0x00d3, 1); + else + exchanges[curexchange-1].name = NULL; + + /* + * Type 0x00d5: Unknown + */ + if (aim_gettlv(innerlist, 0x00d5, 1)) + ; + + /* + * Type 0x00d6: Character Set (First Time) + */ + if (aim_gettlv(innerlist, 0x00d6, 1)) + exchanges[curexchange-1].charset1 = aim_gettlv_str(innerlist, 0x00d6, 1); + else + exchanges[curexchange-1].charset1 = NULL; + + /* + * Type 0x00d7: Language (First Time) + */ + if (aim_gettlv(innerlist, 0x00d7, 1)) + exchanges[curexchange-1].lang1 = aim_gettlv_str(innerlist, 0x00d7, 1); + else + exchanges[curexchange-1].lang1 = NULL; + + /* + * Type 0x00d8: Character Set (Second Time) + */ + if (aim_gettlv(innerlist, 0x00d8, 1)) + exchanges[curexchange-1].charset2 = aim_gettlv_str(innerlist, 0x00d8, 1); + else + exchanges[curexchange-1].charset2 = NULL; + + /* + * Type 0x00d9: Language (Second Time) + */ + if (aim_gettlv(innerlist, 0x00d9, 1)) + exchanges[curexchange-1].lang2 = aim_gettlv_str(innerlist, 0x00d9, 1); + else + exchanges[curexchange-1].lang2 = NULL; + + } + + /* + * Call client. + */ + userfunc = aim_callhandler(command->conn, 0x000d, 0x0009); + if (userfunc) + ret = userfunc(sess, + command, + snac->type, + maxrooms, + curexchange, + exchanges); + curexchange--; + while(curexchange) + { + if (exchanges[curexchange].name) + free(exchanges[curexchange].name); + if (exchanges[curexchange].charset1) + free(exchanges[curexchange].charset1); + if (exchanges[curexchange].lang1) + free(exchanges[curexchange].lang1); + if (exchanges[curexchange].charset2) + free(exchanges[curexchange].charset2); + if (exchanges[curexchange].lang2) + free(exchanges[curexchange].lang2); + curexchange--; + } + free(exchanges); + aim_freetlvchain(&innerlist); + aim_freetlvchain(&tlvlist); + return ret; + } + case 0x0003: /* request exchange info */ + printf("faim: chatnav_parse_info: resposne to exchange info\n"); + return 1; + case 0x0004: /* request room info */ + printf("faim: chatnav_parse_info: response to room info\n"); + return 1; + case 0x0005: /* request more room info */ + printf("faim: chatnav_parse_info: response to more room info\n"); + return 1; + case 0x0006: /* request occupant list */ + printf("faim: chatnav_parse_info: response to occupant info\n"); + return 1; + case 0x0007: /* search for a room */ + printf("faim: chatnav_parse_info: search results\n"); + return 1; + case 0x0008: /* create room */ + printf("faim: chatnav_parse_info: response to create room\n"); + return 1; + default: /* unknown */ + printf("faim: chatnav_parse_info: unknown request subtype (%04x)\n", snac->type); + } + + return 1; /* shouldn't get here */ +} + +u_long aim_chatnav_createroom(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *name, + u_short exchange) +{ + struct command_tx_struct *newpacket; + int i; + struct aim_snac_t snac; + + if (!(newpacket = aim_tx_new(0x0002, conn, 10+12+strlen("invite")+strlen(name)))) + return -1; + + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x000d, 0x0008, 0x0000, sess->snac_nextid); + + /* exchange */ + i+= aimutil_put16(newpacket->data+i, exchange); + + /* room cookie */ + i+= aimutil_put8(newpacket->data+i, strlen("invite")); + i+= aimutil_putstr(newpacket->data+i, "invite", strlen("invite")); + + /* 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 */ + i+= aim_puttlv_str(newpacket->data+i, 0x00d3, strlen(name), name); + + snac.id = sess->snac_nextid; + snac.family = 0x000d; + snac.type = 0x0008; + snac.flags = 0x0000; + snac.data = NULL; + + aim_newsnac(sess, &snac); + + aim_tx_enqueue(sess, newpacket); + + return (sess->snac_nextid++); +} diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_conn.c --- a/libfaim/aim_conn.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_conn.c Sat May 20 00:30:53 2000 +0000 @@ -6,26 +6,31 @@ * */ -#include "aim.h" +#include -void aim_connrst(void) +void aim_connrst(struct aim_session_t *sess) { int i; for (i = 0; i < AIM_CONN_MAX; i++) { - aim_conns[i].fd = -1; - aim_conns[i].type = -1; - aim_conns[i].status = 0; + sess->conns[i].fd = -1; + sess->conns[i].type = -1; + sess->conns[i].status = 0; + sess->conns[i].seqnum = 0; + sess->conns[i].lastactivity = 0; + sess->conns[i].forcedlatency = 0; + aim_clearhandlers(&(sess->conns[i])); + sess->conns[i].handlerlist = NULL; } } -struct aim_conn_t *aim_conn_getnext(void) +struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess) { int i; for (i=0;iconns[i].fd == -1) + return &(sess->conns[i]); return NULL; } @@ -35,14 +40,23 @@ close(deadconn->fd); deadconn->fd = -1; deadconn->type = -1; + deadconn->seqnum = 0; + deadconn->lastactivity = 0; + deadconn->forcedlatency = 0; + aim_clearhandlers(deadconn); + deadconn->handlerlist = NULL; + if (deadconn->priv) + free(deadconn->priv); + deadconn->priv = NULL; } -struct aim_conn_t *aim_getconn_type(int type) +struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess, + int type) { int i; for (i=0; iconns[i].type == type) + return &(sess->conns[i]); return NULL; } @@ -55,20 +69,28 @@ * FIXME: Return errors in a more sane way. * */ -struct aim_conn_t *aim_newconn(int type, char *dest) +struct aim_conn_t *aim_newconn(struct aim_session_t *sess, + int type, char *dest) { struct aim_conn_t *connstruct; int ret; struct sockaddr_in sa; struct hostent *hp; - int port = FAIM_LOGIN_PORT; + u_short port = FAIM_LOGIN_PORT; + char *host = NULL; int i=0; - if (!dest || ((connstruct=aim_conn_getnext())==NULL)) + if ((connstruct=aim_conn_getnext(sess))==NULL) return NULL; connstruct->type = type; + if (!dest) { /* just allocate a struct */ + connstruct->fd = -1; + connstruct->status = 0; + 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 @@ -77,15 +99,21 @@ * We put this here to catch every case. * */ - for(i=0;(istatus = (h_errno | AIM_CONN_STATUS_RESOLVERR); @@ -105,26 +133,26 @@ connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); return connstruct; } - + return connstruct; } -int aim_conngetmaxfd(void) +int aim_conngetmaxfd(struct aim_session_t *sess) { int i,j; j=0; for (i=0;i j) - j = aim_conns[i].fd; + if(sess->conns[i].fd > j) + j = sess->conns[i].fd; return j; } -int aim_countconn(void) +int aim_countconn(struct aim_session_t *sess) { int i,cnt; cnt = 0; for (i=0;i -1) + if (sess->conns[i].fd > -1) cnt++; return cnt; } @@ -135,46 +163,51 @@ * Waits for a socket with data or for timeout, whichever comes first. * See select(2). * + * Return codes in *status: + * -1 error in select() (NULL returned) + * 0 no events pending (NULL returned) + * 1 outgoing data pending (NULL returned) + * 2 incoming data pending (connection with pending data returned) + * */ -struct aim_conn_t *aim_select(struct timeval *timeout) +struct aim_conn_t *aim_select(struct aim_session_t *sess, + struct timeval *timeout, int *status) { fd_set fds; - fd_set errfds; int i; - if (aim_countconn() <= 0) + if (aim_countconn(sess) <= 0) return 0; - + + /* + * If we have data waiting to be sent, return immediatly + */ + if (sess->queue_outgoing != NULL) { + *status = 1; + return NULL; + } + FD_ZERO(&fds); - FD_ZERO(&errfds); for(i=0;i-1) - { - FD_SET(aim_conns[i].fd, &fds); - FD_SET(aim_conns[i].fd, &errfds); - } + if (sess->conns[i].fd>-1) + FD_SET(sess->conns[i].fd, &fds); - i = select(aim_conngetmaxfd()+1, &fds, NULL, &errfds, timeout); - if (i>=1) - { - int j; - for (j=0;j=1) { + int j; + for (j=0;jconns[j].fd > -1) { + if ((FD_ISSET(sess->conns[j].fd, &fds))) { + *status = 2; + return &(sess->conns[j]); /* return the first waiting struct */ } - else if ((FD_ISSET(aim_conns[j].fd, &fds))) - return &(aim_conns[j]); /* return the first waiting struct */ - } - /* should never get here */ - } - else - return (struct aim_conn_t *)i; /* no waiting or error, return -- FIXME: return type funnies */ - return NULL; /* NO REACH */ + } + } + /* should never get here */ + } + + *status = i; /* may be 0 or -1 */ + return NULL; /* no waiting or error, return */ } int aim_conn_isready(struct aim_conn_t *conn) @@ -193,3 +226,47 @@ return -1; } +int aim_conn_setlatency(struct aim_conn_t *conn, int newval) +{ + if (!conn) + return -1; + + conn->forcedlatency = newval; + conn->lastactivity = 0; /* reset this just to make sure */ + + return 0; +} + +void aim_session_init(struct aim_session_t *sess) +{ + int i; + + if (!sess) + return; + + memset(sess->logininfo.screen_name, 0x00, MAXSNLEN); + sess->logininfo.BOSIP = NULL; + memset(sess->logininfo.cookie, 0x00, AIM_COOKIELEN); + sess->logininfo.email = NULL; + sess->logininfo.regstatus = 0x00; + + for (i = 0; i < AIM_CONN_MAX; i++) + { + sess->conns[i].fd = -1; + sess->conns[i].type = -1; + sess->conns[i].status = 0; + sess->conns[i].seqnum = 0; + sess->conns[i].lastactivity = 0; + sess->conns[i].forcedlatency = 0; + sess->conns[i].handlerlist = NULL; + sess->conns[i].priv = NULL; + } + + sess->queue_outgoing = NULL; + sess->queue_incoming = NULL; + sess->pendingjoin = NULL; + sess->outstanding_snacs = NULL; + sess->snac_nextid = 0x00000001; + + return; +} diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_global.c --- a/libfaim/aim_global.c Thu May 18 18:20:18 2000 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -/* - aim_global.c - - These are things that are globally required, but don't fit the - naming of the rest of the functions. Namely, the queue ptrs and fds. - - */ - -#include "aim.h" - -/* the dreaded global variables... */ - -struct login_phase1_struct aim_logininfo; - -/* queue (linked list) pointers */ -struct command_tx_struct *aim_queue_outgoing = NULL; /* incoming commands */ -struct command_rx_struct *aim_queue_incoming = NULL; /* outgoing commands */ diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_im.c --- a/libfaim/aim_im.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_im.c Sat May 20 00:30:53 2000 +0000 @@ -5,7 +5,7 @@ * */ -#include "aim.h" +#include /* * Send an ICBM (instant message). @@ -16,75 +16,103 @@ * AIM_IMFLAGS_ACK -- Requests that the server send an ack * when the message is received (of type 0x0004/0x000c) * - * - * TODO: Update to new standard form - * - * */ - -u_long aim_send_im(struct aim_conn_t *conn, char *destsn, int flags, char *msg) +u_long aim_send_im(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *destsn, u_int flags, char *msg) { - int curbyte; - struct command_tx_struct newpacket; + int curbyte,i; + struct command_tx_struct *newpacket; - newpacket.lock = 1; /* lock struct */ - newpacket.type = 0x02; /* IMs are always family 0x02 */ - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); + if (!(newpacket = aim_tx_new(0x0002, conn, 1152))) + return -1; - newpacket.commandlen = 20+1+strlen(destsn)+1+1+2+7+2+4+strlen(msg)+2; - - if (flags & AIM_IMFLAGS_ACK) - newpacket.commandlen += 4; - if (flags & AIM_IMFLAGS_AWAY) - newpacket.commandlen += 4; - - newpacket.data = (char *) calloc(1, newpacket.commandlen); + newpacket->lock = 1; /* lock struct */ curbyte = 0; - curbyte += aim_putsnac(newpacket.data+curbyte, 0x0004, 0x0006, 0x0000, aim_snac_nextid); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0001); - curbyte += aimutil_put8(newpacket.data+curbyte,strlen(destsn)); - curbyte += aimutil_putstr(newpacket.data+curbyte, destsn, strlen(destsn)); + curbyte += aim_putsnac(newpacket->data+curbyte, + 0x0004, 0x0006, 0x0000, sess->snac_nextid); + + /* + * Generate a random message cookie + * + * We could cache these like we do SNAC IDs. (In fact, it + * might be a good idea.) In the message error functions, + * the 8byte message cookie is returned as well as the + * SNAC ID. + * + */ + for (i=0;i<8;i++) + curbyte += aimutil_put8(newpacket->data+curbyte, (u_char) random()); - if (flags & AIM_IMFLAGS_ACK) - { - curbyte += aimutil_put16(newpacket.data+curbyte,0x0003); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); - } + /* + * Channel ID + */ + curbyte += aimutil_put16(newpacket->data+curbyte,0x0001); + + /* + * Destination SN (prepended with byte length) + */ + curbyte += aimutil_put8(newpacket->data+curbyte,strlen(destsn)); + curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn)); + + /* + * metaTLV start. + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); + curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg) + 0x0d); - if (flags & AIM_IMFLAGS_AWAY) - { - curbyte += aimutil_put16(newpacket.data+curbyte,0x0004); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); - } + /* + * Flag data? + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0501); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0101); + curbyte += aimutil_put8 (newpacket->data+curbyte, 0x01); + + /* + * Message block length. + */ + curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg) + 0x04); + + /* + * Character set data? + */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0002); - curbyte += aimutil_put16(newpacket.data+curbyte,strlen(msg)+0xf); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0501); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0001); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0101); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0101); - curbyte += aimutil_put8(newpacket.data+curbyte,0x01); - curbyte += aimutil_put16(newpacket.data+curbyte,strlen(msg)+4); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); - curbyte += aimutil_put16(newpacket.data+curbyte,0x0000); - curbyte += aimutil_putstr(newpacket.data+curbyte, msg, strlen(msg)); + /* + * Message. Not terminated. + */ + curbyte += aimutil_putstr(newpacket->data+curbyte,msg, strlen(msg)); - aim_tx_enqueue(&newpacket); + /* + * Set the Request Acknowledge flag. + */ + if (flags & AIM_IMFLAGS_ACK) { + curbyte += aimutil_put16(newpacket->data+curbyte,0x0003); + curbyte += aimutil_put16(newpacket->data+curbyte,0x0000); + } + + /* + * Set the Autoresponse flag. + */ + if (flags & AIM_IMFLAGS_AWAY) { + curbyte += aimutil_put16(newpacket->data+curbyte,0x0004); + curbyte += aimutil_put16(newpacket->data+curbyte,0x0000); + } + + newpacket->commandlen = curbyte; + newpacket->lock = 0; + + aim_tx_enqueue(sess, newpacket); #ifdef USE_SNAC_FOR_IMS { struct aim_snac_t snac; - snac.id = aim_snac_nextid; + snac.id = sess->snac_nextid; snac.family = 0x0004; snac.type = 0x0006; snac.flags = 0x0000; @@ -92,162 +120,428 @@ snac.data = malloc(strlen(destsn)+1); memcpy(snac.data, destsn, strlen(destsn)+1); - aim_newsnac(&snac); + aim_newsnac(sess, &snac); } - aim_cleansnacs(60); /* clean out all SNACs over 60sec old */ + aim_cleansnacs(sess, 60); /* clean out all SNACs over 60sec old */ #endif - return (aim_snac_nextid++); + return (sess->snac_nextid++); } -int aim_parse_incoming_im_middle(struct command_rx_struct *command) +/* + * It can easily be said that parsing ICBMs is THE single + * most difficult thing to do in the in AIM protocol. In + * fact, I think I just did say that. + * + * Below is the best damned solution I've come up with + * over the past sixteen months of battling with it. This + * can parse both away and normal messages from every client + * I have access to. Its not fast, its not clean. But it works. + * + * We should also support at least minimal parsing of + * Channel 2, so that we can at least know the name of the + * room we're invited to, but obviously can't attend... + * + */ +int aim_parse_incoming_im_middle(struct aim_session_t *sess, + struct command_rx_struct *command) { - int i = 0; - char *srcsn = NULL; - char *msg = NULL; - unsigned int msglen = 0; - int warninglevel = 0; - int tlvcnt = 0; - int class = 0; - ulong membersince = 0; - ulong onsince = 0; - int idletime = 0; - int isautoreply = 0; + u_int i = 0,z; + rxcallback_t userfunc = NULL; + u_char cookie[8]; + int channel; + struct aim_tlvlist_t *tlvlist; + struct aim_userinfo_s userinfo; + u_short wastebits; + + memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); + + i = 10; /* Skip SNAC header */ - i = 20; + /* + * Read ICBM Cookie. And throw away. + */ + for (z=0; z<8; z++,i++) + cookie[z] = command->data[i]; - srcsn = malloc(command->data[i] + 1); - memcpy(srcsn, &(command->data[i+1]), command->data[i]); - srcsn[(int)command->data[i]] = '\0'; + /* + * Channel ID. + * + * Channel 0x0001 is the message channel. There are + * other channels for things called "rendevous" + * which represent chat and some of the other new + * features of AIM2/3/3.5. + * + * Channel 0x0002 is the Rendevous channel, which + * is where Chat Invitiations and various client-client + * connection negotiations come from. + * + */ + channel = aimutil_get16(command->data+i); + i += 2; - i += (int) command->data[i] + 1; /* add SN len */ - - /* warning level */ - warninglevel = (command->data[i] << 8); - warninglevel += (command->data[i+1]); + /* + * + */ + if ((channel != 0x01) && (channel != 0x02)) + { + printf("faim: icbm: ICBM received on an unsupported channel. Ignoring.\n (chan = %04x)", channel); + return 1; + } + + /* + * Source screen name. + */ + memcpy(userinfo.sn, command->data+i+1, (int)command->data[i]); + userinfo.sn[(int)command->data[i]] = '\0'; + i += 1 + (int)command->data[i]; + + /* + * Warning Level + */ + userinfo.warnlevel = aimutil_get16(command->data+i); /* guess */ + i += 2; + + /* + * Number of TLVs that follow. Not needed. + */ + wastebits = aimutil_get16(command->data+i); i += 2; - tlvcnt = ((command->data[i++]) << 8) & 0xFF00; - tlvcnt += (command->data[i++]) & 0x00FF; - - /* a mini TLV parser */ - { - int curtlv = 0; - int tlv1 = 0; - - while (curtlv < tlvcnt) - { - if ((command->data[i] == 0x00) && - (command->data[i+1] == 0x01) ) - { - if (tlv1) - break; - /* t(0001) = class */ - if (command->data[i+3] != 0x02) - printf("faim: userinfo: **warning: strange v(%x) for t(1)\n", command->data[i+3]); - class = ((command->data[i+4]) << 8) & 0xFF00; - class += (command->data[i+5]) & 0x00FF; - i += (2 + 2 + command->data[i+3]); - tlv1++; - } - else if ((command->data[i] == 0x00) && - (command->data[i+1] == 0x02)) - { - /* t(0002) = member since date */ - if (command->data[i+3] != 0x04) - printf("faim: userinfo: **warning: strange v(%x) for t(2)\n", command->data[i+3]); - - membersince = ((command->data[i+4]) << 24) & 0xFF000000; - membersince += ((command->data[i+5]) << 16) & 0x00FF0000; - membersince += ((command->data[i+6]) << 8) & 0x0000FF00; - membersince += ((command->data[i+7]) ) & 0x000000FF; - i += (2 + 2 + command->data[i+3]); - } - else if ((command->data[i] == 0x00) && - (command->data[i+1] == 0x03)) - { - /* t(0003) = on since date */ - if (command->data[i+3] != 0x04) - printf("faim: userinfo: **warning: strange v(%x) for t(3)\n", command->data[i+3]); + /* + * Read block of TLVs. All further data is derived + * from what is parsed here. + */ + tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); - onsince = ((command->data[i+4]) << 24) & 0xFF000000; - onsince += ((command->data[i+5]) << 16) & 0x00FF0000; - onsince += ((command->data[i+6]) << 8) & 0x0000FF00; - onsince += ((command->data[i+7]) ) & 0x000000FF; - i += (2 + 2 + command->data[i+3]); - } - else if ((command->data[i] == 0x00) && - (command->data[i+1] == 0x04) ) - { - /* t(0004) = idle time */ - if (command->data[i+3] != 0x02) - printf("faim: userinfo: **warning: strange v(%x) for t(4)\n", command->data[i+3]); - idletime = ((command->data[i+4]) << 8) & 0xFF00; - idletime += (command->data[i+5]) & 0x00FF; - i += (2 + 2 + command->data[i+3]); - } - else - { - printf("faim: userinfo: **warning: unexpected TLV t(%02x%02x) l(%02x%02x)\n", command->data[i], command->data[i+1], command->data[i+2], command->data[i+3]); - i += (2 + 2 + command->data[i+3]); - } - curtlv++; - } - } + /* + * From here on, its depends on what channel we're on. + */ + if (channel == 1) + { + u_int j = 0, y = 0, z = 0; + char *msg = NULL; + u_int icbmflags = 0; + struct aim_tlv_t *msgblocktlv, *tmptlv; + u_char *msgblock; + u_short flag1,flag2; + + /* + * Check Autoresponse status. If it is an autoresponse, + * it will contain a second type 0x0004 TLV, with zero length. + */ + if (aim_gettlv(tlvlist, 0x0004, 2)) + icbmflags |= AIM_IMFLAGS_AWAY; + + /* + * Check Ack Request status. + */ + if (aim_gettlv(tlvlist, 0x0003, 2)) + icbmflags |= AIM_IMFLAGS_ACK; + + /* + * Extract the various pieces of the userinfo struct. + */ + /* Class. */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0001, 1))) + userinfo.class = aimutil_get16(tmptlv->value); + /* Member-since date. */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0002, 1))) + { + /* If this is larger than 4, its probably the message block, skip */ + if (tmptlv->length <= 4) + userinfo.membersince = aimutil_get32(tmptlv->value); + } + /* On-since date */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0003, 1))) + userinfo.onlinesince = aimutil_get32(tmptlv->value); + /* Idle-time */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0004, 1))) + userinfo.idletime = aimutil_get16(tmptlv->value); + /* Session Length (AIM) */ + if ((tmptlv = aim_gettlv(tlvlist, 0x000f, 1))) + userinfo.sessionlen = aimutil_get16(tmptlv->value); + /* Session Length (AOL) */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0010, 1))) + userinfo.sessionlen = aimutil_get16(tmptlv->value); + + /* + * Message block. + * + * XXX: Will the msgblock always be the second 0x0002? + */ + msgblocktlv = aim_gettlv(tlvlist, 0x0002, 1); + if (!msgblocktlv) + { + printf("faim: icbm: major error! no message block TLV found!\n"); + aim_freetlvchain(&tlvlist); + return 1; + } + + /* + * Extracting the message from the unknown cruft. + * + * This is a bit messy, and I'm not really qualified, + * even as the author, to comment on it. At least + * its not as bad as a while loop shooting into infinity. + * + * "Do you believe in magic?" + * + */ + msgblock = msgblocktlv->value; + j = 0; + + wastebits = aimutil_get8(msgblock+j++); + wastebits = aimutil_get8(msgblock+j++); + + y = aimutil_get16(msgblock+j); + j += 2; + for (z = 0; z < y; z++) + wastebits = aimutil_get8(msgblock+j++); + wastebits = aimutil_get8(msgblock+j++); + wastebits = aimutil_get8(msgblock+j++); + + /* + * Message string length, including flag words. + */ + i = aimutil_get16(msgblock+j); + j += 2; + + /* + * Flag words. + * + * Its rumored that these can kick in some funky + * 16bit-wide char stuff that used to really kill + * libfaim. Hopefully the latter is no longer true. + * + * Though someone should investiagte the former. + * + */ + flag1 = aimutil_get16(msgblock+j); + j += 2; + flag2 = aimutil_get16(msgblock+j); + j += 2; + + if (flag1 || flag2) + printf("faim: icbm: **warning: encoding flags are being used! {%04x, %04x}\n", flag1, flag2); + + /* + * Message string. + */ + i -= 4; + msg = (char *)malloc(i+1); + memcpy(msg, msgblock+j, i); + msg[i] = '\0'; + + /* + * Call client. + */ + userfunc = aim_callhandler(command->conn, 0x0004, 0x0007); + if (userfunc) + i = userfunc(sess, command, channel, &userinfo, msg, icbmflags, flag1, flag2); + else + i = 0; + + free(msg); + } + else if (channel == 0x0002) + { + int rendtype; + struct aim_tlv_t *block1; + struct aim_tlvlist_t *list2; + struct aim_tlv_t *tmptlv; + int a; + + /* Class. */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0001, 1))) + userinfo.class = aimutil_get16(tmptlv->value); + /* On-since date */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0003, 1))) + userinfo.onlinesince = aimutil_get32(tmptlv->value); + /* Idle-time */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0004, 1))) + userinfo.idletime = aimutil_get16(tmptlv->value); + /* Session Length (AIM) */ + if ((tmptlv = aim_gettlv(tlvlist, 0x000f, 1))) + userinfo.sessionlen = aimutil_get16(tmptlv->value); + /* Session Length (AOL) */ + if ((tmptlv = aim_gettlv(tlvlist, 0x0010, 1))) + userinfo.sessionlen = aimutil_get16(tmptlv->value); - { - /* detect if this is an auto-response or not */ - /* auto-responses can be detected by the presence of a *second* TLV with - t(0004), but of zero length (and therefore no value portion) */ - struct aim_tlv_t *tsttlv = NULL; - tsttlv = aim_grabtlv((u_char *) &(command->data[i])); - if (tsttlv->type == 0x04) - isautoreply = 1; - aim_freetlv(&tsttlv); - } - - i += 2; - - i += 2; /* skip first msglen */ - i += 7; /* skip garbage */ - i -= 4; + /* + * There's another block of TLVs embedded in the type 5 here. + */ + block1 = aim_gettlv(tlvlist, 0x0005, 1); + if (!block1) + return 1; /* major problem */ + + a = 0x1a; /* skip -- not sure what this information is! */ + + /* + * XXX: Ignore if there's no data, only cookie information. + * + * Its probably just an accepted invitation or something. + * + */ + if (block1->length <= 0x1a) + { + aim_freetlvchain(&tlvlist); + return 1; + } + + list2 = aim_readtlvchain(block1->value+a, block1->length-a); + + if (aim_gettlv(list2, 0x0004, 1) /* start connection */ || + aim_gettlv(list2, 0x000b, 1) /* close conncetion */) + { + rendtype = 1; /* voice request */ - /* oh boy is this terrible... this comes from a specific of the spec */ - while(1) - { - if ( ( (command->data[i] == 0x00) && - (command->data[i+1] == 0x00) && - (command->data[i+2] == 0x00) && - (command->data[i+3] == 0x00) ) && - (i < command->commandlen) ) /* prevent infinity */ - break; + /* + * Call client. + */ + userfunc = aim_callhandler(command->conn, 0x0004, 0x0007); + if (userfunc) + i = userfunc(sess, + command, + channel, + rendtype, + &userinfo); + else + i = 0; + } else - i++; + { + struct aim_chat_roominfo roominfo; + char *msg=NULL,*encoding=NULL,*lang=NULL; + + rendtype = 0; /* chat invite */ + if (aim_gettlv(list2, 0x2711, 1)) + { + struct aim_tlv_t *nametlv; + + nametlv = aim_gettlv(list2, 0x2711, 1); + aim_chat_readroominfo(nametlv->value, &roominfo); + } + + if (aim_gettlv(list2, 0x000c, 1)) + msg = aim_gettlv_str(list2, 0x000c, 1); + + if (aim_gettlv(list2, 0x000d, 1)) + encoding = aim_gettlv_str(list2, 0x000d, 1); + + if (aim_gettlv(list2, 0x000e, 1)) + lang = aim_gettlv_str(list2, 0x000e, 1); + + /* + * Call client. + */ + userfunc = aim_callhandler(command->conn, 0x0004, 0x0007); + if (userfunc) + i = userfunc(sess, + command, + channel, + rendtype, + &userinfo, + &roominfo, + msg, + encoding?encoding+1:NULL, + lang?lang+1:NULL); + else + i = 0; + + free(roominfo.name); + free(msg); + free(encoding); + free(lang); + } + aim_freetlvchain(&list2); } - i -= 2; + /* + * Free up the TLV chain. + */ + aim_freetlvchain(&tlvlist); - if ( (command->data[i] == 0x00) && - (command->data[i+1] == 0x00) ) - i += 2; - - msglen = ( (( (unsigned int) command->data[i]) & 0xFF ) << 8); - msglen += ( (unsigned int) command->data[i+1]) & 0xFF; /* mask off garbage */ - i += 2; - - msglen -= 4; /* skip four 0x00s */ - i += 4; - - msg = malloc(msglen +1); - - memcpy(msg, &(command->data[i]), msglen); - msg[msglen] = '\0'; - - i = (aim_callbacks[AIM_CB_INCOMING_IM])(command, srcsn, msg, warninglevel, class, membersince, onsince, idletime, isautoreply); - - free(srcsn); - free(msg); return i; } + +/* + * Not real sure what this does, nor does anyone I've talk to. + * + * Didn't use to send it. But now I think it might be a good + * idea. + * + */ +u_long aim_seticbmparam(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct command_tx_struct *newpacket; + int curbyte; + + if(!(newpacket = aim_tx_new(0x0002, conn, 10+16))) + return -1; + + newpacket->lock = 1; + + curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0002, 0x0000, sess->snac_nextid); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + curbyte += aimutil_put32(newpacket->data+curbyte, 0x00000003); + curbyte += aimutil_put8(newpacket->data+curbyte, 0x1f); + curbyte += aimutil_put8(newpacket->data+curbyte, 0x40); + curbyte += aimutil_put8(newpacket->data+curbyte, 0x03); + curbyte += aimutil_put8(newpacket->data+curbyte, 0xe7); + curbyte += aimutil_put8(newpacket->data+curbyte, 0x03); + curbyte += aimutil_put8(newpacket->data+curbyte, 0xe7); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + + newpacket->lock = 0; + aim_tx_enqueue(sess, newpacket); + + return (sess->snac_nextid++); +} + +int aim_parse_msgerror_middle(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + u_long snacid = 0x000000000; + struct aim_snac_t *snac = NULL; + int ret = 0; + rxcallback_t userfunc = NULL; + + /* + * Get SNAC from packet and look it up + * the list of unrepliedto/outstanding + * SNACs. + * + * After its looked up, the SN that the + * message should've gone to will be + * in the ->data element of the snac struct. + * + */ + snacid = aimutil_get32(command->data+6); + snac = aim_remsnac(sess, snacid); + + if (!snac) + { + printf("faim: msgerr: got an ICBM-failed error on an unknown SNAC ID! (%08lx)\n", snacid); + } + + /* + * Call client. + */ + userfunc = aim_callhandler(command->conn, 0x0004, 0x0001); + if (userfunc) + ret = userfunc(sess, command, (snac)?snac->data:"(UNKNOWN)"); + else + ret = 0; + + free(snac->data); + free(snac); + + return ret; +} + + diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_info.c --- a/libfaim/aim_info.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_info.c Sat May 20 00:30:53 2000 +0000 @@ -1,68 +1,350 @@ /* - aim_info.c - - The functions here are responsible for requesting and parsing information- - gathering SNACs. - + * aim_info.c + * + * The functions here are responsible for requesting and parsing information- + * gathering SNACs. + * */ -#include "aim.h" /* for most everything */ - -u_long aim_getinfo(struct aim_conn_t *conn, const char *sn) -{ - struct command_tx_struct newpacket; +#include - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); +u_long aim_getinfo(struct aim_session_t *sess, + struct aim_conn_t *conn, + const char *sn) +{ + struct command_tx_struct *newpacket; + int i = 0; - newpacket.lock = 1; - newpacket.type = 0x0002; - - newpacket.commandlen = 12 + 1 + strlen(sn); - newpacket.data = (char *) malloc(newpacket.commandlen); + if (!sess || !conn || !sn) + return 0; - newpacket.data[0] = 0x00; - newpacket.data[1] = 0x02; - newpacket.data[2] = 0x00; - newpacket.data[3] = 0x05; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; + if (!(newpacket = aim_tx_new(0x0002, conn, 12+1+strlen(sn)))) + return -1; + + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x0002, 0x0005, 0x0000, sess->snac_nextid); - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + i += aimutil_put16(newpacket->data+i, 0x0001); + i += aimutil_put8(newpacket->data+i, strlen(sn)); + i += aimutil_putstr(newpacket->data+i, sn, strlen(sn)); - /* TLV: Screen Name */ - /* t(0x0001) */ - newpacket.data[10] = 0x00; - newpacket.data[11] = 0x01; - /* l() */ - newpacket.data[12] = strlen(sn); - /* v() */ - memcpy(&(newpacket.data[13]), sn, strlen(sn)); - - aim_tx_enqueue(&newpacket); + newpacket->lock = 0; + aim_tx_enqueue(sess, newpacket); { struct aim_snac_t snac; - snac.id = aim_snac_nextid; + snac.id = sess->snac_nextid; snac.family = 0x0002; snac.type = 0x0005; snac.flags = 0x0000; snac.data = malloc(strlen(sn)+1); - memcpy(snac.data, sn, strlen(sn)+1); + strcpy(snac.data, sn); - aim_newsnac(&snac); + aim_newsnac(sess, &snac); } - return (aim_snac_nextid++); + return (sess->snac_nextid++); +} + + +/* + * Capability blocks. + */ +u_char aim_caps[6][16] = { + + /* Buddy icon */ + {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}, + + /* Voice */ + {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}, + + /* IM image */ + {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}, + + /* Chat */ + {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}, + + /* Get file */ + {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}, + + /* Send file */ + {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +}; + +/* + * AIM is fairly regular about providing user info. This + * is a generic routine to extract it in its standard form. + */ +int aim_extractuserinfo(u_char *buf, struct aim_userinfo_s *outinfo) +{ + int i = 0; + int tlvcnt = 0; + int curtlv = 0; + int tlv1 = 0; + u_short curtype; + + + if (!buf || !outinfo) + return -1; + + /* Clear out old data first */ + memset(outinfo, 0x00, sizeof(struct aim_userinfo_s)); + + /* + * Screen name. Stored as an unterminated string prepended + * with an unsigned byte containing its length. + */ + memcpy(outinfo->sn, &(buf[i+1]), buf[i]); + outinfo->sn[(int)buf[i]] = '\0'; + i = 1 + (int)buf[i]; + + /* + * Warning Level. Stored as an unsigned short. + */ + outinfo->warnlevel = aimutil_get16(&buf[i]); + i += 2; + + /* + * TLV Count. Unsigned short representing the number of + * Type-Length-Value triples that follow. + */ + tlvcnt = aimutil_get16(&buf[i]); + i += 2; + + /* + * Parse out the Type-Length-Value triples as they're found. + */ + while (curtlv < tlvcnt) + { + curtype = aimutil_get16(&buf[i]); + switch (curtype) + { + /* + * Type = 0x0001: Member Class. + * + * 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->class = 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 = 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. + * + * Ignore. + * + */ + case 0x000d: + { + int z,y; + int len; + len = aimutil_get16(buf+i+2); + if (!len) + break; + + for (z = 0; z < len; z+=0x10) { + for(y=0; y < 6; y++) { + if (memcmp(&aim_caps[y], buf+i+4+z, 0x10) == 0) { + switch(y) { + case 0: outinfo->capabilities |= AIM_CAPS_BUDDYICON; break; + case 1: outinfo->capabilities |= AIM_CAPS_VOICE; break; + case 2: outinfo->capabilities |= AIM_CAPS_IMIMAGE; break; + case 3: outinfo->capabilities |= AIM_CAPS_CHAT; break; + case 4: outinfo->capabilities |= AIM_CAPS_GETFILE; break; + case 5: outinfo->capabilities |= AIM_CAPS_SENDFILE; break; + default: outinfo->capabilities |= 0xff00; break; + } + } + } + } + } + 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[80]; + printf("faim: userinfo: **warning: unexpected TLV:\n"); + printf("faim: userinfo: sn =%s\n", outinfo->sn); + printf("faim: userinfo: curtlv=0x%04x\n", curtlv); + printf("faim: userinfo: type =0x%04x\n",aimutil_get16(&buf[i])); + printf("faim: userinfo: length=0x%04x\n", len = aimutil_get16(&buf[i+2])); + printf("faim: userinfo: data: \n"); + while (zdata+i, &userinfo); + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING); + if (userfunc) + i = userfunc(sess, command, &userinfo); + + return 1; +} + +/* + * Offgoing Buddy notifications contain no useful + * information other than the name it applies to. + * + */ +int aim_parse_offgoing_middle(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + char sn[MAXSNLEN+1]; + u_int i = 0; + rxcallback_t userfunc=NULL; + + strncpy(sn, command->data+11, (int)command->data[10]); + sn[(int)command->data[10]] = '\0'; + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING); + if (userfunc) + i = userfunc(sess, command, sn); + + return 1; } /* @@ -70,151 +352,150 @@ * the higher-level callback (in the user app). * */ - -int aim_parse_userinfo_middle(struct command_rx_struct *command) +int aim_parse_userinfo_middle(struct aim_session_t *sess, + struct command_rx_struct *command) { - char *sn = NULL; + struct aim_userinfo_s userinfo; char *prof_encoding = NULL; char *prof = NULL; - u_short warnlevel = 0x0000; - u_short idletime = 0x0000; - u_short class = 0x0000; - u_long membersince = 0x00000000; - u_long onlinesince = 0x00000000; - int tlvcnt = 0; - int i = 0; + u_int i = 0; + rxcallback_t userfunc=NULL; + struct aim_tlvlist_t *tlvlist; { u_long snacid = 0x000000000; struct aim_snac_t *snac = NULL; - snacid = (command->data[6] << 24) & 0xFF000000; - snacid+= (command->data[7] << 16) & 0x00FF0000; - snacid+= (command->data[8] << 8) & 0x0000FF00; - snacid+= (command->data[9]) & 0x000000FF; + snacid = aimutil_get32(&command->data[6]); + snac = aim_remsnac(sess, snacid); - snac = aim_remsnac(snacid); - - free(snac->data); - free(snac); + if (snac) + { + if (snac->data) + free(snac->data); + else + printf("faim: parse_userinfo_middle: warning: no ->data in cached SNAC\n"); + free(snac); + } + else + printf("faim: parseuserinfo_middle: warning: no SNAC cached with for this response (%08lx)\n", snacid); } - - sn = (char *) malloc(command->data[10]+1); - memcpy(sn, &(command->data[11]), command->data[10]); - sn[(int)command->data[10]] = '\0'; - i = 11 + command->data[10]; - warnlevel = ((command->data[i++]) << 8) & 0xFF00; - warnlevel += (command->data[i++]) & 0x00FF; - - tlvcnt = ((command->data[i++]) << 8) & 0xFF00; - tlvcnt += (command->data[i++]) & 0x00FF; - - /* a mini TLV parser */ - { - int curtlv = 0; - int tlv1 = 0; - - while (curtlv < tlvcnt) - { - if ((command->data[i] == 0x00) && - (command->data[i+1] == 0x01) ) - { - if (tlv1) - break; - /* t(0001) = class */ - class = ((command->data[i+4]) << 8) & 0xFF00; - class += (command->data[i+5]) & 0x00FF; - i += (2 + 2 + command->data[i+3]); - tlv1++; - } - else if ((command->data[i] == 0x00) && - (command->data[i+1] == 0x02)) - { - /* t(0002) = member since date */ - if (command->data[i+3] != 0x04) - printf("faim: userinfo: **warning: strange v(%x) for t(2)\n", command->data[i+3]); - - membersince = ((command->data[i+4]) << 24) & 0xFF000000; - membersince += ((command->data[i+5]) << 16) & 0x00FF0000; - membersince += ((command->data[i+6]) << 8) & 0x0000FF00; - membersince += ((command->data[i+7]) ) & 0x000000FF; - i += (2 + 2 + command->data[i+3]); - } - else if ((command->data[i] == 0x00) && - (command->data[i+1] == 0x03)) - { - /* t(0003) = on since date */ - if (command->data[i+3] != 0x04) - printf("faim: userinfo: **warning: strange v(%x) for t(3)\n", command->data[i+3]); + i = 10; - onlinesince = ((command->data[i+4]) << 24) & 0xFF000000; - onlinesince += ((command->data[i+5]) << 16) & 0x00FF0000; - onlinesince += ((command->data[i+6]) << 8) & 0x0000FF00; - onlinesince += ((command->data[i+7]) ) & 0x000000FF; - i += (2 + 2 + command->data[i+3]); - } - else if ((command->data[i] == 0x00) && - (command->data[i+1] == 0x04) ) - { - /* t(0004) = idle time */ - if (command->data[i+3] != 0x02) - printf("faim: userinfo: **warning: strange v(%x) for t(4)\n", command->data[i+3]); - idletime = ((command->data[i+4]) << 8) & 0xFF00; - idletime += (command->data[i+5]) & 0x00FF; - i += (2 + 2 + command->data[i+3]); - } - else - { - printf("faim: userinfo: **warning: unexpected TLV t(%02x%02x) l(%02x%02x)\n", command->data[i], command->data[i+1], command->data[i+2], command->data[i+3]); - i += (2 + 2 + command->data[i+3]); - } - curtlv++; - } - } - if (i < command->commandlen) + /* + * extractuserinfo will give us the basic metaTLV information + */ + i += aim_extractuserinfo(command->data+i, &userinfo); + + /* + * However, in this command, there's usually more TLVs following... + */ + tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); + prof_encoding = aim_gettlv_str(tlvlist, 0x0001, 1); + prof = aim_gettlv_str(tlvlist, 0x0002, 1); + + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO); + if (userfunc) { - if ( (command->data[i] == 0x00) && - (command->data[i+1] == 0x01) ) - { - int len = 0; - - len = ((command->data[i+2] << 8) & 0xFF00); - len += (command->data[i+3]) & 0x00FF; - - prof_encoding = (char *) malloc(len+1); - memcpy(prof_encoding, &(command->data[i+4]), len); - prof_encoding[len] = '\0'; - - i += (2+2+len); - } - else - { - printf("faim: userinfo: **warning: unexpected TLV after TLVblock t(%02x%02x) l(%02x%02x)\n", command->data[i], command->data[i+1], command->data[i+2], command->data[i+3]); - i += 2 + 2 + command->data[i+3]; - } + i = userfunc(sess, + command, + &userinfo, + prof_encoding, + prof); } - - if (i < command->commandlen) - { - int len = 0; - - len = ((command->data[i+2]) << 8) & 0xFF00; - len += (command->data[i+3]) & 0x00FF; - - prof = (char *) malloc(len+1); - memcpy(prof, &(command->data[i+4]), len); - prof[len] = '\0'; - } - else - printf("faim: userinfo: **early parse abort...no profile?\n"); - - i = (aim_callbacks[AIM_CB_USERINFO])(command, sn, prof_encoding, prof, warnlevel, idletime, class, membersince, onlinesince); - - free(sn); + free(prof_encoding); free(prof); + aim_freetlvchain(&tlvlist); + return 1; +} + +/* + * Inverse of aim_extractuserinfo() + */ +int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info) +{ + int i = 0; + struct aim_tlvlist_t *tlvlist = NULL; + + if (!buf || !info) + return 0; + + i += aimutil_put8(buf+i, strlen(info->sn)); + i += aimutil_putstr(buf+i, info->sn, strlen(info->sn)); + + i += aimutil_put16(buf+i, info->warnlevel); + + /* XXX: we only put down five */ + i += aimutil_put16(buf+i, 5); + aim_addtlvtochain16(&tlvlist, 0x0001, info->class); + aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince); + aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince); + aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime); + /* XXX: should put caps here */ + aim_addtlvtochain32(&tlvlist, (info->class)&AIM_CLASS_AOL?0x0010:0x000f, info->sessionlen); + + i += aim_writetlvchain(buf+i, buflen-i, &tlvlist); + aim_freetlvchain(&tlvlist); + return i; } + +int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info) +{ + struct command_tx_struct *tx; + int i = 0; + + if (!sess || !conn || !info) + return 0; + + if (!(tx = aim_tx_new(0x0002, conn, 1152))) + return -1; + + tx->lock = 1; + + 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); + + i += aim_putuserinfo(tx->data+i, tx->commandlen-i, info); + + tx->commandlen = i; + tx->lock = 0; + aim_tx_enqueue(sess, tx); + + return 0; +} + +int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn) +{ + struct command_tx_struct *tx; + int i = 0; + + if (!sess || !conn || !sn) + return 0; + + if (!(tx = aim_tx_new(0x0002, conn, 10+1+strlen(sn)))) + return -1; + + tx->lock = 1; + + 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); + + 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); + + return 0; +} diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_login.c --- a/libfaim/aim_login.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_login.c Sat May 20 00:30:53 2000 +0000 @@ -5,7 +5,7 @@ * */ -#include "aim.h" +#include /* @@ -15,8 +15,57 @@ #include "tis_telnet_proxy.h" #endif +int aim_sendconnack(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + int curbyte=0; + + struct command_tx_struct *newpacket; + + if (!(newpacket = aim_tx_new(0x0001, conn, 4))) + return -1; + + newpacket->lock = 1; + + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + + newpacket->lock = 0; + return aim_tx_enqueue(sess, newpacket); +} + +#ifdef SNACLOGIN /* - * send_login(int socket, char *sn, char *password) + * 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). + */ +int aim_request_login(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *sn) +{ + int curbyte=0; + + struct command_tx_struct *newpacket; + + if (!(newpacket = aim_tx_new(0x0002, conn, 10+2+2+strlen(sn)))) + return -1; + + newpacket->lock = 1; + + curbyte += aim_putsnac(newpacket->data+curbyte, 0x0017, 0x0006, 0x0000, 0x00010000); + curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn); + + newpacket->lock = 0; + return aim_tx_enqueue(sess, newpacket); +} +#endif /* SNACLOGIN */ + +/* + * send_login(int socket, char *sn, char *password) * * This is the initial login request packet. * @@ -24,84 +73,109 @@ * encode_password(). See that function for their * stupid method of doing it. * - * - * */ -int aim_send_login (struct aim_conn_t *conn, char *sn, char *password, struct client_info_s *clientinfo) +int aim_send_login (struct aim_session_t *sess, + struct aim_conn_t *conn, + char *sn, char *password, struct client_info_s *clientinfo) { - char *password_encoded = NULL; /* to store encoded password */ + u_char *password_encoded = NULL; /* to store encoded password */ int curbyte=0; - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; + + if (!clientinfo || !sn || !password) + return -1; + + if (!(newpacket = aim_tx_new(0x0002, conn, 1152))) + return -1; - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_AUTH); - - newpacket.commandlen = 6+2+strlen(sn)+1+1+2+strlen(password)+6; +#ifdef SNACLOGIN + newpacket->commandlen = 10; + newpacket->commandlen += 2 + 2 + strlen(sn); + newpacket->commandlen += 2 + 2 + strlen(password); + newpacket->commandlen += 2 + 2 + strlen(clientinfo->clientstring); + newpacket->commandlen += 56; + + newpacket->lock = 1; - if (clientinfo) - { - if (strlen(clientinfo->clientstring)) - newpacket.commandlen += strlen(clientinfo->clientstring)+4; - newpacket.commandlen += 6+6+6; - if (strlen(clientinfo->country)) - newpacket.commandlen += strlen(clientinfo->country)+4; - if (strlen(clientinfo->lang)) - newpacket.commandlen += strlen(clientinfo->lang)+4; - } + curbyte = aim_putsnac(newpacket->data+curbyte, 0x0017, 0x0002, 0x0000, 0x00010000); + curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn); + password_encoded = (u_char *) malloc(strlen(password)); + aim_encode_password(password, password_encoded); + curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0002, strlen(password), password_encoded); + curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0003, + strlen(clientinfo->clientstring), + clientinfo->clientstring); + /* XXX: should use clientinfo provided version info */ + curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x0016, 0x0004); + curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x0017, 0x0003); + curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x0018, 0x0005); + curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x0019, 0x0000); + curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x001a, 0x0686); + curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0001, 0x0002, clientinfo->country); + curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0001, 0x0002, clientinfo->lang); + curbyte+= aim_puttlv_32(newpacket->data+curbyte, 0x0014, 0x0000002a); + curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015); +#else + + newpacket->commandlen = 4 + 4+strlen(sn) + 4+strlen(password) + 6; + + if (clientinfo) { + if (strlen(clientinfo->clientstring)) + newpacket->commandlen += 4+strlen(clientinfo->clientstring); + newpacket->commandlen += 6+6+6+6; + if (strlen(clientinfo->country)) + newpacket->commandlen += 4+strlen(clientinfo->country); + if (strlen(clientinfo->lang)) + newpacket->commandlen += 4+strlen(clientinfo->lang); + } + newpacket->commandlen += 6; - newpacket.data = (char *) calloc (1, newpacket.commandlen ); - newpacket.lock = 1; - newpacket.type = 0x01; + newpacket->lock = 1; + newpacket->type = 0x01; - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket.data+curbyte, strlen(sn)); - curbyte += aimutil_putstr(newpacket.data+curbyte, sn, strlen(sn)); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + curbyte += aimutil_put16(newpacket->data+curbyte, strlen(sn)); + curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn)); - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0002); - curbyte += aimutil_put16(newpacket.data+curbyte, strlen(password)); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); + curbyte += aimutil_put16(newpacket->data+curbyte, strlen(password)); password_encoded = (char *) malloc(strlen(password)); aim_encode_password(password, password_encoded); - curbyte += aimutil_putstr(newpacket.data+curbyte, password_encoded, strlen(password)); + curbyte += aimutil_putstr(newpacket->data+curbyte, password_encoded, strlen(password)); free(password_encoded); - curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0016, 0x0001); + curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, 0x0004); + + if (clientinfo) { + if (strlen(clientinfo->clientstring)) { + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); + curbyte += aimutil_put16(newpacket->data+curbyte, strlen(clientinfo->clientstring)); + curbyte += aimutil_putstr(newpacket->data+curbyte, clientinfo->clientstring, strlen(clientinfo->clientstring)); + } + curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, clientinfo->major /*0x0001*/); + curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, clientinfo->minor /*0x0001*/); + curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, 0x0000); + curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, clientinfo->build /*0x0013*/); + if (strlen(clientinfo->country)) { + curbyte += aimutil_put16(newpacket->data+curbyte, 0x000e); + curbyte += aimutil_put16(newpacket->data+curbyte, strlen(clientinfo->country)); + curbyte += aimutil_putstr(newpacket->data+curbyte, clientinfo->country, strlen(clientinfo->country)); + } + if (strlen(clientinfo->lang)) { + curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f); + curbyte += aimutil_put16(newpacket->data+curbyte, strlen(clientinfo->lang)); + curbyte += aimutil_putstr(newpacket->data+curbyte, clientinfo->lang, strlen(clientinfo->lang)); + } + } - if (clientinfo) - { - if (strlen(clientinfo->clientstring)) - { - curbyte += aimutil_put16(newpacket.data+curbyte, 0x0003); - curbyte += aimutil_put16(newpacket.data+curbyte, strlen(clientinfo->clientstring)); - curbyte += aimutil_putstr(newpacket.data+curbyte, clientinfo->clientstring, strlen(clientinfo->clientstring)); - } - curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0017, 0x0001); - curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0018, 0x0001); - curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x001a, 0x0013); - if (strlen(clientinfo->country)) - { - curbyte += aimutil_put16(newpacket.data+curbyte, 0x000e); - curbyte += aimutil_put16(newpacket.data+curbyte, strlen(clientinfo->country)); - curbyte += aimutil_putstr(newpacket.data+curbyte, clientinfo->country, strlen(clientinfo->country)); - } - if (strlen(clientinfo->lang)) - { - curbyte += aimutil_put16(newpacket.data+curbyte, 0x000f); - curbyte += aimutil_put16(newpacket.data+curbyte, strlen(clientinfo->lang)); - curbyte += aimutil_putstr(newpacket.data+curbyte, clientinfo->lang, strlen(clientinfo->lang)); - } - } + curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015); +#endif - curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0009, 0x0015); - - newpacket.lock = 0; - aim_tx_enqueue(&newpacket); - - return 0; + newpacket->lock = 0; + return aim_tx_enqueue(sess, newpacket); } /* @@ -120,9 +194,9 @@ * hope it doesn't change over time! * */ -int aim_encode_password(const char *password, char *encoded) +int aim_encode_password(const char *password, u_char *encoded) { - char encoding_table[] = { + u_char encoding_table[] = { 0xf3, 0xb3, 0x6c, 0x99, 0x95, 0x3f, 0xac, 0xb6, 0xc5, 0xfa, 0x6b, 0x63, @@ -137,6 +211,224 @@ return 0; } +/* + * This is sent back as a general response to the login command. + * It can be either an error or a success, depending on the + * precense of certain TLVs. + * + * The client should check the value of logininfo->errorcode. If + * its nonzero, there was an error. + * + */ +int aim_authparse(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + struct aim_tlvlist_t *tlvlist; + int ret = 1; + char *sn; + rxcallback_t userfunc = NULL; + + memset(&sess->logininfo, 0x00, sizeof(sess->logininfo)); + + /* + * Read block of TLVs. All further data is derived + * from what is parsed here. + */ +#ifdef SNACLOGIN + tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10); +#else + tlvlist = aim_readtlvchain(command->data, command->commandlen); +#endif + /* + * No matter what, we should have a screen name. + */ + sn = aim_gettlv_str(tlvlist, 0x0001, 1); + memcpy(sess->logininfo.screen_name, sn, strlen(sn)); + sn[(strlen(sn))] = '\0'; + + /* + * Check for an error code. If so, we should also + * have an error url. + */ + if (aim_gettlv(tlvlist, 0x0008, 1)) + { + struct aim_tlv_t *errtlv; + errtlv = aim_gettlv(tlvlist, 0x0008, 1); + sess->logininfo.errorcode = aimutil_get16(errtlv->value); + sess->logininfo.errorurl = aim_gettlv_str(tlvlist, 0x0004, 1); + } + /* + * If we have both an IP number (0x0005) and a cookie (0x0006), + * then the login was successful. + */ + else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1)) + { + struct aim_tlv_t *tmptlv; + + /* + * IP address of BOS server. + */ + sess->logininfo.BOSIP = aim_gettlv_str(tlvlist, 0x0005, 1); + + /* + * Authorization Cookie + */ + tmptlv = aim_gettlv(tlvlist, 0x0006, 1); + memcpy(sess->logininfo.cookie, tmptlv->value, AIM_COOKIELEN); + + /* + * The email address attached to this account + */ + sess->logininfo.email = aim_gettlv_str(tlvlist, 0x0011, 1); + + /* + * The registration status. (Not real sure what it means.) + */ + tmptlv = aim_gettlv(tlvlist, 0x0013, 1); + sess->logininfo.regstatus = aimutil_get16(tmptlv->value); + + } + +#ifdef SNACLOGIN + userfunc = aim_callhandler(command->conn, 0x0017, 0x0003); +#else + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS); +#endif + if (userfunc) + ret = userfunc(sess, command); + + aim_freetlvchain(&tlvlist); + + /* These have been clobbered by the freetlvchain */ + sess->logininfo.BOSIP = NULL; + sess->logininfo.email = NULL; + sess->logininfo.errorurl = NULL; + + return ret; +} + +/* + * Generate an authorization response. + * + * You probably don't want this unless you're writing an AIM server. + * + */ +unsigned long aim_sendauthresp(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *sn, char *bosip, + char *cookie, char *email, + int regstatus) +{ + struct command_tx_struct *tx; + struct aim_tlvlist_t *tlvlist = NULL; + + if (!(tx = aim_tx_new(0x0001 /*right??*/, conn, 1152))) + return -1; + + tx->lock = 1; + + if (sn) + aim_addtlvtochain_str(&tlvlist, 0x0001, sn, strlen(sn)); + else + aim_addtlvtochain_str(&tlvlist, 0x0001, sess->logininfo.screen_name, strlen(sess->logininfo.screen_name)); + + if (sess->logininfo.errorcode) { + aim_addtlvtochain16(&tlvlist, 0x0008, sess->logininfo.errorcode); + aim_addtlvtochain_str(&tlvlist, 0x0004, sess->logininfo.errorurl, strlen(sess->logininfo.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, regstatus); + } + + tx->commandlen = aim_writetlvchain(tx->data, tx->commandlen, &tlvlist); + tx->lock = 0; + return aim_tx_enqueue(sess, tx); +} + +/* + * Generate a random cookie. (Non-client use only) + */ +int aim_gencookie(unsigned char *buf) +{ + int i; + + srand(time(NULL)); + + for (i=0; i < AIM_COOKIELEN; i++) + buf[i] = 1+(int) (256.0*rand()/(RAND_MAX+0.0)); + + return i; +} + +/* + * Send Server Ready. (Non-client) + */ +int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn) +{ + struct command_tx_struct *tx; + int i = 0; + + if (!(tx = aim_tx_new(0x0002, conn, 10+0x20))) + return -1; + + tx->lock = 1; + + i += aimutil_put16(tx->data+i, 0x0001); + i += aimutil_put16(tx->data+i, 0x0003); + i += aimutil_put16(tx->data+i, 0x0000); + i += aimutil_put16(tx->data+i, 0x0000); + i += aimutil_put16(tx->data+i, 0x0000); + + 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); + + tx->lock = 0; + + return aim_tx_enqueue(sess, tx); +} +/* + * Send service redirect. (Non-Client) + */ +unsigned long aim_sendredirect(struct aim_session_t *sess, + struct aim_conn_t *conn, + unsigned short servid, + char *ip, + char *cookie) +{ + struct command_tx_struct *tx; + struct aim_tlvlist_t *tlvlist = NULL; + int i = 0; + if (!(tx = aim_tx_new(0x0002, conn, 1152))) + return -1; + + tx->lock = 1; + + i += aimutil_put16(tx->data+i, 0x0001); + i += aimutil_put16(tx->data+i, 0x0005); + i += aimutil_put16(tx->data+i, 0x0000); + i += aimutil_put16(tx->data+i, 0x0000); + i += aimutil_put16(tx->data+i, 0x0000); + + aim_addtlvtochain16(&tlvlist, 0x000d, servid); + aim_addtlvtochain_str(&tlvlist, 0x0005, ip, strlen(ip)); + aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN); + + tx->commandlen = aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist)+i; + aim_freetlvchain(&tlvlist); + + tx->lock = 0; + return aim_tx_enqueue(sess, tx); +} diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_logoff.c --- a/libfaim/aim_logoff.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_logoff.c Sat May 20 00:30:53 2000 +0000 @@ -4,7 +4,7 @@ * */ -#include "aim.h" +#include /* * aim_logoff() @@ -12,16 +12,16 @@ * Closes -ALL- open connections. * */ -int aim_logoff(void) +int aim_logoff(struct aim_session_t *sess) { int i = AIM_CONN_MAX-1; while (i > -1) { - if (aim_conns[i].fd>-1) - aim_conn_close(&(aim_conns[i])); + if (sess->conns[i].fd>-1) + aim_conn_close(&(sess->conns[i])); i--; } - aim_connrst(); /* in case we want to connect again */ + aim_connrst(sess); /* in case we want to connect again */ return 0; diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_misc.c --- a/libfaim/aim_misc.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_misc.c Sat May 20 00:30:53 2000 +0000 @@ -11,7 +11,7 @@ * */ -#include "aim.h" +#include /* * aim_bos_setidle() @@ -21,9 +21,11 @@ * time. * */ -u_long aim_bos_setidle(struct aim_conn_t *conn, u_long idletime) +u_long aim_bos_setidle(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_long idletime) { - return aim_genericreq_l(conn, 0x0001, 0x0011, &idletime); + return aim_genericreq_l(sess, conn, 0x0001, 0x0011, &idletime); } @@ -55,91 +57,66 @@ * * */ -u_long aim_bos_changevisibility(struct aim_conn_t *conn, int changetype, char *denylist) +u_long aim_bos_changevisibility(struct aim_session_t *sess, + struct aim_conn_t *conn, + int changetype, char *denylist) { - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; + int packlen = 0; + u_short subtype; char *localcpy = NULL; char *tmpptr = NULL; - char *tmpptr2 = NULL; int i,j; + int listcount; if (!denylist) return 0; - newpacket.lock = 1; - - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - - newpacket.type = 0x02; - newpacket.commandlen = 10; - localcpy = (char *) malloc(strlen(denylist)+1); memcpy(localcpy, denylist, strlen(denylist)+1); - tmpptr2 = localcpy; /* save this for the free() */ + + listcount = aimutil_itemcnt(localcpy, '&'); + packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9; - i = 0; - tmpptr = strsep(&localcpy, "&"); - while (strlen(tmpptr) && (i < 100)) - { - newpacket.commandlen += strlen(tmpptr)+1; - i++; - tmpptr = strsep(&localcpy, "&"); - } - free(tmpptr2); - tmpptr2 = NULL; + if (!(newpacket = aim_tx_new(0x0002, conn, packlen))) + return -1; - newpacket.data = (char *) malloc(newpacket.commandlen); - memset(newpacket.data, 0x00, newpacket.commandlen); + newpacket->lock = 1; - newpacket.data[0] = 0x00; - newpacket.data[1] = 0x09; - newpacket.data[2] = 0x00; switch(changetype) { - case AIM_VISIBILITYCHANGE_PERMITADD: - newpacket.data[3] = 0x05; break; - case AIM_VISIBILITYCHANGE_PERMITREMOVE: - newpacket.data[3] = 0x06; break; - case AIM_VISIBILITYCHANGE_DENYADD: - newpacket.data[3] = 0x07; break; - case AIM_VISIBILITYCHANGE_DENYREMOVE: - newpacket.data[4] = 0x08; break; + 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; } - /* SNAC reqid -- we actually DO NOT send a SNAC ID with this one! */ - newpacket.data[6] = 0; - newpacket.data[7] = 0; - newpacket.data[8] = 0; - newpacket.data[9] = 0; + + /* We actually DO NOT send a SNAC ID with this one! */ + aim_putsnac(newpacket->data, 0x0009, subtype, 0x00, 0); j = 10; /* the next byte */ - - localcpy = (char *) malloc(strlen(denylist)+1); - memcpy(localcpy, denylist, strlen(denylist)+1); - tmpptr2 = localcpy; /* save this for the free() */ - - i = 0; - tmpptr = strsep(&localcpy, "&"); - while (strlen(tmpptr) && (i < 100)) + + for (i=0; (i < (listcount - 1)) && (i < 99); i++) { - newpacket.data[j] = strlen(tmpptr); - memcpy(&(newpacket.data[j+1]), tmpptr, strlen(tmpptr)); + tmpptr = aimutil_itemidx(localcpy, i, '&'); + + newpacket->data[j] = strlen(tmpptr); + memcpy(&(newpacket->data[j+1]), tmpptr, strlen(tmpptr)); j += strlen(tmpptr)+1; - i++; - tmpptr = strsep(&localcpy, "&"); + free(tmpptr); } - free(tmpptr2); + free(localcpy); - newpacket.lock = 0; + newpacket->lock = 0; - aim_tx_enqueue(&newpacket); + aim_tx_enqueue(sess, newpacket); - return (aim_snac_nextid); /* dont increment */ + return (sess->snac_nextid); /* dont increment */ } @@ -152,14 +129,18 @@ * * buddy_list = "Screen Name One&ScreenNameTwo&"; * - * TODO: Clean this up. + * TODO: Clean this up. + * + * XXX: I can't stress the TODO enough. * */ -u_long aim_bos_setbuddylist(struct aim_conn_t *conn, char *buddy_list) +u_long aim_bos_setbuddylist(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *buddy_list) { int i, j; - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; int packet_login_phase3c_hi_b_len = 0; @@ -169,15 +150,9 @@ packet_login_phase3c_hi_b_len = 16; /* 16b for FLAP and SNAC headers */ /* bail out if we can't make the packet */ - if (buddy_list == NULL) - { - printf("\nNO BUDDIES! ARE YOU THAT LONELY???\n"); - return 0; - } -#if debug > 0 - printf("****buddy list: %s\n", buddy_list); - printf("****buddy list len: %d (%x)\n", strlen(buddy_list), strlen(buddy_list)); -#endif + if (!buddy_list) { + return -1; + } localcpy = (char *) malloc(strlen(buddy_list)+1); memcpy(localcpy, buddy_list, strlen(buddy_list)+1); @@ -198,27 +173,12 @@ #endif free(localcpy); - newpacket.type = 0x02; - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - newpacket.commandlen = packet_login_phase3c_hi_b_len - 6; - newpacket.lock = 1; - - newpacket.data = (char *) malloc(newpacket.commandlen); + if (!(newpacket = aim_tx_new(0x0002, conn, packet_login_phase3c_hi_b_len - 6))) + return -1; - newpacket.data[0] = 0x00; - newpacket.data[1] = 0x03; - newpacket.data[2] = 0x00; - newpacket.data[3] = 0x04; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + newpacket->lock = 1; + + aim_putsnac(newpacket->data, 0x0003, 0x0004, 0x0000, sess->snac_nextid); j = 10; /* the next byte */ @@ -229,18 +189,18 @@ #if debug > 0 printf("---adding %s (%d)\n", tmpptr, strlen(tmpptr)); #endif - newpacket.data[j] = strlen(tmpptr); - memcpy(&(newpacket.data[j+1]), tmpptr, strlen(tmpptr)); + newpacket->data[j] = strlen(tmpptr); + memcpy(&(newpacket->data[j+1]), tmpptr, strlen(tmpptr)); j += strlen(tmpptr)+1; i++; tmpptr = strtok(NULL, "&"); } - newpacket.lock = 0; + newpacket->lock = 0; - aim_tx_enqueue(&newpacket); + aim_tx_enqueue(sess, newpacket); - return (aim_snac_nextid++); + return (sess->snac_nextid++); } /* @@ -248,70 +208,70 @@ * * Gives BOS your profile. * + * + * The large data chunk given here is of unknown decoding. + * What I do know is that each 0x20 byte repetition + * represents a capability. People with only the + * first two reptitions can support normal messaging + * and chat (client version 2.0 or 3.0). People with + * the third as well can also support voice chat (client + * version 3.5 or higher). IOW, if we don't send this, + * we won't get chat invitations (get "software doesn't + * support chat" error). + * + * This data is broadcast along with your oncoming + * buddy command to everyone who has you on their + * buddy list, as a type 0x0002 TLV. + * */ -u_long aim_bos_setprofile(struct aim_conn_t *conn, char *profile) +u_long aim_bos_setprofile(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *profile, + char *awaymsg, + unsigned int caps) { - int packet_profile_len = 0; - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; int i = 0; - /* len: SNAC */ - packet_profile_len = 10; - /* len: T+L (where t(0001)) */ - packet_profile_len += 2 + 2; - /* len: V (where t(0001)) */ - packet_profile_len += strlen("text/x-aolrtf"); - /* len: T+L (where t(0002)) */ - packet_profile_len += 2 + 2; - /* len: V (where t(0002)) */ - packet_profile_len += strlen(profile); + if (!(newpacket = aim_tx_new(0x0002, conn, 1152+strlen(profile)+1+(awaymsg?strlen(awaymsg):0)))) + return -1; - newpacket.type = 0x02; - if (conn) - newpacket.conn = conn; + i += aim_putsnac(newpacket->data, 0x0002, 0x004, 0x0000, sess->snac_nextid); + i += aim_puttlv_str(newpacket->data+i, 0x0001, strlen("text/x-aolrtf; charset=\"us-ascii\""), "text/x-aolrtf; charset=\"us-ascii\""); + i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(profile), profile); + /* why do we send this twice? */ + i += aim_puttlv_str(newpacket->data+i, 0x0003, strlen("text/x-aolrtf; charset=\"us-ascii\""), "text/x-aolrtf; charset=\"us-ascii\""); + + /* Away message -- we send this no matter what, even if its blank */ + if (awaymsg) + i += aim_puttlv_str(newpacket->data+i, 0x0004, strlen(awaymsg), awaymsg); else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - newpacket.commandlen = packet_profile_len; - newpacket.data = (char *) malloc(packet_profile_len); + i += aim_puttlv_str(newpacket->data+i, 0x0004, 0x0000, NULL); - i = 0; - /* SNAC: family */ - newpacket.data[i++] = 0x00; - newpacket.data[i++] = 0x02; - /* SNAC: subtype */ - newpacket.data[i++] = 0x00; - newpacket.data[i++] = 0x04; - /* SNAC: flags */ - newpacket.data[i++] = 0x00; - newpacket.data[i++] = 0x00; - /* SNAC: id */ - /* SNAC reqid */ - newpacket.data[i++] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[i++] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[i++] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[i++] = (aim_snac_nextid) & 0xFF; - /* TLV t(0001) */ - newpacket.data[i++] = 0x00; - newpacket.data[i++] = 0x01; - /* TLV l(000d) */ - newpacket.data[i++] = 0x00; - newpacket.data[i++] = 0x0d; - /* TLV v(text/x-aolrtf) */ - memcpy(&(newpacket.data[i]), "text/x-aolrtf", 0x000d); - i += 0x000d; + /* Capability information. */ + { + int isave; + i += aimutil_put16(newpacket->data+i, 0x0005); + isave = i; + i += aimutil_put16(newpacket->data+i, 0); + if (caps & AIM_CAPS_BUDDYICON) + i += aimutil_putstr(newpacket->data+i, aim_caps[0], 0x10); + if (caps & AIM_CAPS_VOICE) + i += aimutil_putstr(newpacket->data+i, aim_caps[1], 0x10); + if (caps & AIM_CAPS_IMIMAGE) + i += aimutil_putstr(newpacket->data+i, aim_caps[2], 0x10); + if (caps & AIM_CAPS_CHAT) + i += aimutil_putstr(newpacket->data+i, aim_caps[3], 0x10); + if (caps & AIM_CAPS_GETFILE) + i += aimutil_putstr(newpacket->data+i, aim_caps[4], 0x10); + if (caps & AIM_CAPS_SENDFILE) + i += aimutil_putstr(newpacket->data+i, aim_caps[5], 0x10); + aimutil_put16(newpacket->data+isave, i-isave-2); + } + newpacket->commandlen = i; + aim_tx_enqueue(sess, newpacket); - /* TLV t(0002) */ - newpacket.data[i++] = 0x00; - newpacket.data[i++] = 0x02; - /* TLV l() */ - newpacket.data[i++] = (strlen(profile) >> 8) & 0xFF; - newpacket.data[i++] = (strlen(profile) & 0xFF); - /* TLV v(profile) */ - memcpy(&(newpacket.data[i]), profile, strlen(profile)); - - aim_tx_enqueue(&newpacket); - - return (aim_snac_nextid++); + return (sess->snac_nextid++); } /* @@ -320,9 +280,11 @@ * Set group permisson mask. Normally 0x1f. * */ -u_long aim_bos_setgroupperm(struct aim_conn_t *conn, u_long mask) +u_long aim_bos_setgroupperm(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_long mask) { - return aim_genericreq_l(conn, 0x0009, 0x0004, &mask); + return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask); } /* @@ -333,43 +295,71 @@ * TODO: Dynamisize. * */ -u_long aim_bos_clientready(struct aim_conn_t *conn) +u_long aim_bos_clientready(struct aim_session_t *sess, + struct aim_conn_t *conn) { - char command_2[] = { - 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x7a, 0x8c, - 0x11, 0xab, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, - 0x00, 0x13, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x01, + u_char command_2[] = { + /* placeholders for dynamic data */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, + /* real data */ + 0x00, 0x01, + 0x00, 0x03, + 0x00, 0x04, + 0x06, 0x86, + 0x00, 0x02, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + + 0x00, 0x03, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + + 0x00, 0x06, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + 0x00, 0x08, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + + 0x00, 0x09, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + 0x00, 0x0a, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + + 0x00, 0x0b, + 0x00, 0x01, + 0x00, 0x04, 0x00, 0x01 }; int command_2_len = 0x52; - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; - newpacket.lock = 1; - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - newpacket.type = 0x02; - newpacket.commandlen = command_2_len; - newpacket.data = (char *) malloc (newpacket.commandlen); - memcpy(newpacket.data, command_2, newpacket.commandlen); + if (!(newpacket = aim_tx_new(0x0002, conn, command_2_len))) + return -1; + + newpacket->lock = 1; + + memcpy(newpacket->data, command_2, command_2_len); - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + /* This write over the dynamic parts of the byte block */ + aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); - aim_tx_enqueue(&newpacket); + aim_tx_enqueue(sess, newpacket); - return (aim_snac_nextid++); + return (sess->snac_nextid++); } /* @@ -380,9 +370,10 @@ * TODO: Move to aim_conn. * TODO: Move to SNAC interface. */ -u_long aim_bos_reqrate(struct aim_conn_t *conn) +u_long aim_bos_reqrate(struct aim_session_t *sess, + struct aim_conn_t *conn) { - return aim_genericreq_n(conn, 0x0001, 0x0006); + return aim_genericreq_n(sess, conn, 0x0001, 0x0006); } /* @@ -391,43 +382,32 @@ * Rate Information Response Acknowledge. * */ -u_long aim_bos_ackrateresp(struct aim_conn_t *conn) +u_long aim_bos_ackrateresp(struct aim_session_t *sess, + struct aim_conn_t *conn) { - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; + int packlen = 18, i=0; - newpacket.lock = 1; - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - newpacket.type = 0x02; - newpacket.commandlen = 18; + if (conn->type != AIM_CONN_TYPE_BOS) + packlen += 2; + + if(!(newpacket = aim_tx_new(0x0002, conn, packlen))); + + newpacket->lock = 1; - newpacket.data = (char *) malloc(newpacket.commandlen); - newpacket.data[0] = 0x00; - newpacket.data[1] = 0x01; - newpacket.data[2] = 0x00; - newpacket.data[3] = 0x08; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + i = aim_putsnac(newpacket->data, 0x0001, 0x0008, 0x0000, sess->snac_nextid); + 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); + + if (conn->type != AIM_CONN_TYPE_BOS) { + i += aimutil_put16(newpacket->data+i, 0x0005); + } - newpacket.data[10] = 0x00; - newpacket.data[11] = 0x01; - newpacket.data[12] = 0x00; - newpacket.data[13] = 0x02; - newpacket.data[14] = 0x00; - newpacket.data[15] = 0x03; - newpacket.data[16] = 0x00; - newpacket.data[17] = 0x04; + aim_tx_enqueue(sess, newpacket); - aim_tx_enqueue(&newpacket); - - return (aim_snac_nextid++); + return (sess->snac_nextid++); } /* @@ -439,9 +419,11 @@ * * */ -u_long aim_bos_setprivacyflags(struct aim_conn_t *conn, u_long flags) +u_long aim_bos_setprivacyflags(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_long flags) { - return aim_genericreq_l(conn, 0x0001, 0x0014, &flags); + return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags); } /* @@ -451,50 +433,97 @@ * because aparently it uses SNAC flags. * */ -u_long aim_bos_reqpersonalinfo(struct aim_conn_t *conn) +u_long aim_bos_reqpersonalinfo(struct aim_session_t *sess, + struct aim_conn_t *conn) { - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; - newpacket.lock = 1; - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - newpacket.type = 0x02; - newpacket.commandlen = 12; + if (!(newpacket = aim_tx_new(0x0002, conn, 12))) + return -1; - newpacket.data = (char *) malloc(newpacket.commandlen); + newpacket->lock = 1; + + aim_putsnac(newpacket->data, 0x000a, 0x0001, 0x000e /* huh? */, sess->snac_nextid); - newpacket.data[0] = 0x00; - newpacket.data[1] = 0x0a; - newpacket.data[2] = 0x00; - newpacket.data[3] = 0x01; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x0e; /* huh? */ + newpacket->data[10] = 0x0d; + newpacket->data[11] = 0xda; + + newpacket->lock = 0; + aim_tx_enqueue(sess, newpacket); + + return (sess->snac_nextid++); +} + +u_long aim_setversions(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct command_tx_struct *newpacket; + int i; + + if (!(newpacket = aim_tx_new(0x0002, conn, 10 + (4*11)))) + return -1; + + newpacket->lock = 1; + + i = aim_putsnac(newpacket->data, 0x0001, 0x0017, 0x0000, sess->snac_nextid); + + 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); - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + 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); + + 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); - newpacket.data[10] = 0x0d; - newpacket.data[11] = 0xda; + i += aimutil_put16(newpacket->data+i, 0x000c); + i += aimutil_put16(newpacket->data+i, 0x0001); + + i += aimutil_put16(newpacket->data+i, 0x0015); + i += aimutil_put16(newpacket->data+i, 0x0001); - aim_tx_enqueue(&newpacket); +#if 0 + for (j = 0; j < 0x10; j++) { + i += aimutil_put16(newpacket->data+i, j); /* family */ + i += aimutil_put16(newpacket->data+i, 0x0003); /* version */ + } +#endif + newpacket->lock = 0; + aim_tx_enqueue(sess, newpacket); - return (aim_snac_nextid++); + return (sess->snac_nextid++); } + /* * aim_bos_reqservice(serviceid) * * Service request. * */ -u_long aim_bos_reqservice(struct aim_conn_t *conn, u_short serviceid) +u_long aim_bos_reqservice(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_short serviceid) { - return aim_genericreq_s(conn, 0x0001, 0x0004, &serviceid); + return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid); } /* @@ -503,9 +532,10 @@ * Request BOS rights. * */ -u_long aim_bos_reqrights(struct aim_conn_t *conn) +u_long aim_bos_reqrights(struct aim_session_t *sess, + struct aim_conn_t *conn) { - return aim_genericreq_n(conn, 0x0009, 0x0002); + return aim_genericreq_n(sess, conn, 0x0009, 0x0002); } /* @@ -514,9 +544,10 @@ * Request Buddy List rights. * */ -u_long aim_bos_reqbuddyrights(struct aim_conn_t *conn) +u_long aim_bos_reqbuddyrights(struct aim_session_t *sess, + struct aim_conn_t *conn) { - return aim_genericreq_n(conn, 0x0003, 0x0002); + return aim_genericreq_n(sess, conn, 0x0003, 0x0002); } /* @@ -531,124 +562,77 @@ * back to the single. I don't see any advantage to doing it either way. * */ -u_long aim_genericreq_n(struct aim_conn_t *conn, u_short family, u_short subtype) +u_long aim_genericreq_n(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_short family, u_short subtype) { - struct command_tx_struct newpacket; - - newpacket.lock = 1; - - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - newpacket.type = 0x02; - - newpacket.commandlen = 10; + struct command_tx_struct *newpacket; - newpacket.data = (char *) malloc(newpacket.commandlen); - memset(newpacket.data, 0x00, newpacket.commandlen); - newpacket.data[0] = (family & 0xff00)>>8; - newpacket.data[1] = family & 0xff; - newpacket.data[2] = (subtype & 0xff00)>>8; - newpacket.data[3] = subtype & 0xff; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + if (!(newpacket = aim_tx_new(0x0002, conn, 10))) + return 0; + + newpacket->lock = 1; - aim_tx_enqueue(&newpacket); - return (aim_snac_nextid++); + aim_putsnac(newpacket->data, family, subtype, 0x0000, sess->snac_nextid); + + aim_tx_enqueue(sess, newpacket); + return (sess->snac_nextid++); } /* * * */ -u_long aim_genericreq_l(struct aim_conn_t *conn, u_short family, u_short subtype, u_long *longdata) +u_long aim_genericreq_l(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_short family, u_short subtype, u_long *longdata) { - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; u_long newlong; /* If we don't have data, there's no reason to use this function */ if (!longdata) - return aim_genericreq_n(conn, family, subtype); - - newpacket.lock = 1; - - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - newpacket.type = 0x02; - - newpacket.commandlen = 10+sizeof(u_long); + return aim_genericreq_n(sess, conn, family, subtype); - newpacket.data = (char *) malloc(newpacket.commandlen); - memset(newpacket.data, 0x00, newpacket.commandlen); + if (!(newpacket = aim_tx_new(0x0002, conn, 10+sizeof(u_long)))) + return -1; - newpacket.data[0] = (family & 0xff00)>>8; - newpacket.data[1] = family & 0xff; - newpacket.data[2] = (subtype & 0xff00)>>8; - newpacket.data[3] = subtype & 0xff; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + newpacket->lock = 1; + + aim_putsnac(newpacket->data, family, subtype, 0x0000, sess->snac_nextid); /* copy in data */ newlong = htonl(*longdata); - memcpy(&(newpacket.data[10]), &newlong, sizeof(u_long)); + memcpy(&(newpacket->data[10]), &newlong, sizeof(u_long)); - aim_tx_enqueue(&newpacket); - return (aim_snac_nextid++); + aim_tx_enqueue(sess, newpacket); + return (sess->snac_nextid++); } -u_long aim_genericreq_s(struct aim_conn_t *conn, u_short family, u_short subtype, u_short *shortdata) +u_long aim_genericreq_s(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_short family, u_short subtype, u_short *shortdata) { - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; u_short newshort; /* If we don't have data, there's no reason to use this function */ if (!shortdata) - return aim_genericreq_n(conn, family, subtype); - - newpacket.lock = 1; - - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - newpacket.type = 0x02; - - newpacket.commandlen = 10+sizeof(u_short); + return aim_genericreq_n(sess, conn, family, subtype); - newpacket.data = (char *) malloc(newpacket.commandlen); - memset(newpacket.data, 0x00, newpacket.commandlen); + if (!(newpacket = aim_tx_new(0x0002, conn, 10+sizeof(u_short)))) + return -1; - newpacket.data[0] = (family & 0xff00)>>8; - newpacket.data[1] = family & 0xff; - newpacket.data[2] = (subtype & 0xff00)>>8; - newpacket.data[3] = subtype & 0xff; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + newpacket->lock = 1; + + aim_putsnac(newpacket->data, family, subtype, 0x0000, sess->snac_nextid); /* copy in data */ newshort = htons(*shortdata); - memcpy(&(newpacket.data[10]), &newshort, sizeof(u_short)); + memcpy(&(newpacket->data[10]), &newshort, sizeof(u_short)); - aim_tx_enqueue(&newpacket); - return (aim_snac_nextid++); + aim_tx_enqueue(sess, newpacket); + return (sess->snac_nextid++); } /* @@ -657,9 +641,10 @@ * Request Location services rights. * */ -u_long aim_bos_reqlocaterights(struct aim_conn_t *conn) +u_long aim_bos_reqlocaterights(struct aim_session_t *sess, + struct aim_conn_t *conn) { - return aim_genericreq_n(conn, 0x0002, 0x0002); + return aim_genericreq_n(sess, conn, 0x0002, 0x0002); } /* @@ -668,7 +653,8 @@ * Request ICBM parameter information. * */ -u_long aim_bos_reqicbmparaminfo(struct aim_conn_t *conn) +u_long aim_bos_reqicbmparaminfo(struct aim_session_t *sess, + struct aim_conn_t *conn) { - return aim_genericreq_n(conn, 0x0004, 0x0004); + return aim_genericreq_n(sess, conn, 0x0004, 0x0004); } diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_rxhandlers.c --- a/libfaim/aim_rxhandlers.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_rxhandlers.c Sat May 20 00:30:53 2000 +0000 @@ -1,80 +1,274 @@ +/* + * aim_rxhandlers.c + * + * This file contains most all of the incoming packet handlers, along + * with aim_rxdispatch(), the Rx dispatcher. Queue/list management is + * actually done in aim_rxqueue.c. + * + */ + +#include /* - aim_rxhandlers.c - - This file contains most all of the incoming packet handlers, along - with aim_rxdispatch(), the Rx dispatcher. Queue/list management is - actually done in aim_rxqueue.c. - + * Bleck functions get called when there's no non-bleck functions + * around to cleanup the mess... */ +int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...) +{ + u_short family; + u_short subtype; + u_short maxf; + u_short maxs; -#include "aim.h" /* for most everything */ + /* 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", + } + }; -int bleck(struct command_rx_struct *param, ...) -{ + 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((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL)) + printf("bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]); + else + printf("bleck: null handler for %04x/%04x (no literal)\n",family,subtype); + return 1; } -/* - * The callbacks. Used to pass data up from the wire into the client. - * - * TODO: MASSIVE OVERHAUL. This method of doing it (array of function - * pointers) is ugly. Overhaul may mean including chained callbacks - * for having client features such as run-time loadable modules. - * - */ -rxcallback_t aim_callbacks[] = { - bleck, /* incoming IM */ - bleck, /* oncoming buddy */ - bleck, /* offgoing buddy */ - bleck, /* messaging error */ - bleck, /* server missed call */ - bleck, /* login phase 4 packet C command 1*/ - bleck, /* login phase 4 packet C command 2 */ - bleck, /* login phase 2, first resp */ - bleck, /* login phase 2, second resp -- **REQUIRED** */ - bleck, /* login phase 3 packet B */ - bleck, /* login phase 3D packet A */ - bleck, /* login phase 3D packet B */ - bleck, /* login phase 3D packet C */ - bleck, /* login phase 3D packet D */ - bleck, /* login phase 3D packet E */ - bleck, /* redirect -- **REQUIRED** */ - bleck, /* server rate change */ - bleck, /* user location error */ - aim_parse_unknown, /* completely unknown command */ - bleck, /* User Info Response */ - bleck, /* User Search by Address response */ - bleck, /* User Search by Name response */ - bleck, /* user search fail */ - bleck, /* auth error */ - bleck, /* auth success */ - bleck, /* auth server ready */ - bleck, /* auth other */ - bleck, /* info change reply */ - bleck, /* ChatNAV: server ready */ - 0x00 -}; +int aim_conn_addhandler(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_short family, + u_short type, + rxcallback_t newhandler, + u_short flags) +{ + struct aim_rxcblist_t *new,*cur; + + if (!conn) + return -1; + + faimdprintf(1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type); + + new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t)); + new->family = family; + new->type = type; + new->flags = flags; + if (!newhandler) + new->handler = &bleck; + else + new->handler = newhandler; + new->next = NULL; + + cur = conn->handlerlist; + if (!cur) + conn->handlerlist = new; + else + { + while (cur->next) + cur = cur->next; + cur->next = new; + } + + return 0; +} + +int aim_clearhandlers(struct aim_conn_t *conn) +{ + struct aim_rxcblist_t *cur,*tmp; + if (!conn) + return -1; + cur = conn->handlerlist; + while(cur) + { + tmp = cur->next; + free(cur); + cur = tmp; + } + return 0; +} -int aim_register_callbacks(rxcallback_t *newcallbacks) +rxcallback_t aim_callhandler(struct aim_conn_t *conn, + u_short family, + u_short type) { - int i = 0; + struct aim_rxcblist_t *cur; + + if (!conn) + return NULL; + + faimdprintf(1, "aim_callhandler: calling for %04x/%04x\n", family, type); - for (i = 0; aim_callbacks[i] != 0x00; i++) + cur = conn->handlerlist; + while(cur) { - if ( (newcallbacks[i] != NULL) && - (newcallbacks[i] != 0x00) ) - { -#if debug > 3 - printf("aim_register_callbacks: changed handler %d\n", i); -#endif - aim_callbacks[i] = newcallbacks[i]; - } + if ( (cur->family == family) && (cur->type == type) ) + return cur->handler; + cur = cur->next; } - - return 0; + + if (type==0xffff) + return NULL; + return aim_callhandler(conn, family, 0xffff); +} + +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) +{ + rxcallback_t userfunc = NULL; + userfunc = aim_callhandler(conn, family, type); + if (userfunc) + return userfunc(sess, ptr); + return 1; /* XXX */ } /* @@ -100,349 +294,380 @@ TODO: Allow for NULL handlers. */ -int aim_rxdispatch(void) +int aim_rxdispatch(struct aim_session_t *sess) { int i = 0; struct command_rx_struct *workingPtr = NULL; - if (aim_queue_incoming == NULL) - /* this shouldn't really happen, unless the main loop's select is broke */ - printf("parse_generic: incoming packet queue empty.\n"); - else - { - workingPtr = aim_queue_incoming; - for (i = 0; workingPtr != NULL; i++) - { - switch(workingPtr->conn->type) - { - case AIM_CONN_TYPE_AUTH: - if ( (workingPtr->data[0] == 0x00) && - (workingPtr->data[1] == 0x00) && - (workingPtr->data[2] == 0x00) && - (workingPtr->data[3] == 0x01) ) - { -#if debug > 0 - fprintf(stderr, "got connection ack on auth line\n"); + if (sess->queue_incoming == NULL) { + faimdprintf(1, "parse_generic: incoming packet queue empty.\n"); + return 0; + } else { + workingPtr = sess->queue_incoming; + for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) { + /* + * XXX: This is still fairly ugly. + */ + if (workingPtr->handled) + continue; + + switch(workingPtr->conn->type) { + case -1: + /* + * This can happen if we have a queued command + * that was recieved after a connection has + * been terminated. In which case, the handler + * list has been cleared, and there's nothing we + * can do for it. We can only cancel it. + */ + workingPtr->handled = 1; + break; + case AIM_CONN_TYPE_AUTH: { + u_long head; + + head = aimutil_get32(workingPtr->data); + if (head == 0x00000001) { + faimdprintf(1, "got connection ack on auth line\n"); + workingPtr->handled = 1; + } else { + u_short family,subtype; + + family = aimutil_get16(workingPtr->data); + subtype = aimutil_get16(workingPtr->data+2); + + switch (family) { + /* New login protocol */ +#ifdef SNACLOGIN + case 0x0017: + if (subtype == 0x0001) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_authparse(sess, workingPtr); + else if (subtype == 0x0007) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr); + else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr); + break; +#else + /* XXX: this isnt foolproof */ + case 0x0001: + if (subtype == 0x0003) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr); + else + workingPtr->handled = aim_authparse(sess, workingPtr); + break; + case 0x0007: + if (subtype == 0x0005) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr); + break; + default: + /* Old login protocol */ + /* any user callbacks will be called from here */ + workingPtr->handled = aim_authparse(sess, workingPtr); #endif - workingPtr->handled = 1; - } - else - { - /* any user callbacks will be called from here */ - workingPtr->handled = aim_authparse(workingPtr); - } - break; - case AIM_CONN_TYPE_BOS: - { - u_short family; - u_short subtype; - family = (workingPtr->data[0] << 8) + workingPtr->data[1]; - subtype = (workingPtr->data[2] << 8) + workingPtr->data[3]; - switch (family) - { - case 0x0000: /* not really a family, but it works */ - if (subtype == 0x0001) - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P2_1])(workingPtr); - else - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - case 0x0001: /* Family: General */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = aim_parse_generalerrs(workingPtr); - break; - case 0x0003: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P2_2])(workingPtr); - break; - case 0x0005: - workingPtr->handled = aim_handleredirect_middle(workingPtr); - break; - case 0x0007: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3_B])(workingPtr); - break; - case 0x000a: - workingPtr->handled = (aim_callbacks[AIM_CB_RATECHANGE])(workingPtr); - break; - case 0x000f: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_A])(workingPtr); - break; - case 0x0013: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P4_C2])(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - } - break; - case 0x0002: /* Family: Location */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = (aim_callbacks[AIM_CB_MISSED_IM])(workingPtr); - break; - case 0x0003: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_D])(workingPtr); - break; - case 0x0006: - workingPtr->handled = aim_parse_userinfo_middle(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - } - break; - case 0x0003: /* Family: Buddy List */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = aim_parse_generalerrs(workingPtr); - break; - case 0x0003: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_C])(workingPtr); - break; - case 0x000b: - workingPtr->handled = (aim_callbacks[AIM_CB_ONCOMING_BUDDY])(workingPtr); - break; - case 0x000c: - workingPtr->handled = (aim_callbacks[AIM_CB_OFFGOING_BUDDY])(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - } - break; - case 0x0004: /* Family: Messeging */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = (aim_callbacks[AIM_CB_USERERROR])(workingPtr); - break; - case 0x0005: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_E])(workingPtr); - break; - case 0x0007: - workingPtr->handled = aim_parse_incoming_im_middle(workingPtr); - break; - case 0x000a: - workingPtr->handled = (aim_callbacks[AIM_CB_MISSED_CALL])(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - } - break; - case 0x0009: - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_B])(workingPtr); - else - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - case 0x000a: /* Family: User lookup */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = (aim_callbacks[AIM_CB_SEARCH_FAIL])(workingPtr); - break; - case 0x0003: - workingPtr->handled = (aim_callbacks[AIM_CB_SEARCH_ADDRESS])(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - } - break; - case 0x000b: - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(workingPtr); - else if (subtype == 0x0002) - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P4_C1])(workingPtr); - else - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - } - } - break; - case AIM_CONN_TYPE_CHATNAV: - if ( (workingPtr->data[0] == 0x00) && - (workingPtr->data[1] == 0x02) && - (workingPtr->data[2] == 0x00) && - (workingPtr->data[3] == 0x06) ) - { - workingPtr->handled = 1; - aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY); - } - else - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - case AIM_CONN_TYPE_CHAT: - fprintf(stderr, "\nAHH! Dont know what to do with CHAT stuff yet!\n"); - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - default: - fprintf(stderr, "\nAHHHHH! UNKNOWN CONNECTION TYPE!\n\n"); - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - } - /* move to next command */ - workingPtr = workingPtr->next; + } } + break; + } + case AIM_CONN_TYPE_BOS: { + u_short family; + u_short subtype; + + family = aimutil_get16(workingPtr->data); + subtype = aimutil_get16(workingPtr->data+2); + + switch (family) { + case 0x0000: /* not really a family, but it works */ + if (subtype == 0x0001) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr); + else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); + break; + case 0x0001: /* Family: General */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); + break; + case 0x0003: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr); + break; + case 0x0005: + workingPtr->handled = aim_handleredirect_middle(sess, workingPtr); + break; + case 0x0007: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr); + break; + case 0x000a: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr); + break; + case 0x000f: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr); + break; + case 0x0013: + workingPtr->handled = aim_parsemotd_middle(sess, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr); + break; + } + case 0x0002: /* Family: Location */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr); + break; + case 0x0003: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr); + break; + case 0x0006: + workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr); + break; + } + case 0x0003: /* Family: Buddy List */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); + break; + case 0x0003: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr); + break; + case 0x000b: /* oncoming buddy */ + workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr); + break; + case 0x000c: /* offgoing buddy */ + workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr); + } + break; + case 0x0004: /* Family: Messeging */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr); + break; + case 0x0005: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr); + break; + case 0x0007: + workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr); + break; + case 0x000a: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr); + } + break; + case 0x0009: + if (subtype == 0x0001) + workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr); + else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr); + break; + case 0x000a: /* Family: User lookup */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr); + break; + case 0x0003: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr); + } + break; + case 0x000b: + if (subtype == 0x0001) + workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); + else if (subtype == 0x0002) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr); + else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); + break; + } + break; + } + case AIM_CONN_TYPE_CHATNAV: { + u_short family; + u_short subtype; + family = aimutil_get16(workingPtr->data); + subtype= aimutil_get16(workingPtr->data+2); + + if ((family == 0x0002) && (subtype == 0x0006)) { + workingPtr->handled = 1; + aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY); + } else if ((family == 0x000d) && (subtype == 0x0009)) { + workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr); + } else { + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); + } + break; + } + case AIM_CONN_TYPE_CHAT: { + u_short family, subtype; + + family = aimutil_get16(workingPtr->data); + subtype= aimutil_get16(workingPtr->data+2); + + if ((family == 0x0000) && (subtype == 0x00001)) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr); + else if (family == 0x0001) { + if (subtype == 0x0001) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr); + else if (subtype == 0x0007) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr); + else + printf("Chat: unknown snac %04x/%04x\n", family, subtype); + } else if (family == 0x000e) { + if (subtype == 0x0002) + workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_chat_parse_joined(sess, workingPtr); + else if (subtype == 0x0004) + workingPtr->handled = aim_chat_parse_leave(sess, workingPtr); + else if (subtype == 0x0006) + workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr); + else + printf("Chat: unknown snac %04x/%04x\n", family, subtype); + } else { + printf("Chat: unknown snac %04x/%04x\n", family, subtype); + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr); + } + break; + } + default: + printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, channel = %02x, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->type, workingPtr->commandlen); + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); + break; + } } + } - aim_queue_incoming = aim_purge_rxqueue(aim_queue_incoming); + /* + * 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); return 0; } -/* - * TODO: check and cure memory leakage in this function. - */ -int aim_authparse(struct command_rx_struct *command) +int aim_parsemotd_middle(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { - int iserror = 0; - struct aim_tlv_t *tlv = NULL; - char *errorurl = NULL; - short errorcode; - int z = 0; + rxcallback_t userfunc = NULL; + char *msg; + int ret=1; + struct aim_tlvlist_t *tlvlist; + u_short id; + + /* + * Dunno. + */ + id = aimutil_get16(command->data+10); + + /* + * TLVs follow + */ + tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12); + + msg = aim_gettlv_str(tlvlist, 0x000b, 1); + + userfunc = aim_callhandler(command->conn, 0x0001, 0x0013); + if (userfunc) + ret = userfunc(sess, command, id, msg); + + aim_freetlvchain(&tlvlist); + + return ret; + +} - if ( (command->data[0] == 0x00) && - (command->data[1] == 0x01) && - (command->data[2] == 0x00) && - (command->data[3] == 0x03) ) +int aim_handleredirect_middle(struct aim_session_t *sess, + struct command_rx_struct *command, ...) +{ + struct aim_tlv_t *tmptlv = NULL; + int serviceid = 0x00; + char cookie[AIM_COOKIELEN]; + char *ip = NULL; + rxcallback_t userfunc = NULL; + struct aim_tlvlist_t *tlvlist; + int ret = 1; + + if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10))) { - /* "server ready" -- can be ignored */ - return (aim_callbacks[AIM_CB_AUTH_SVRREADY])(command); + printf("libfaim: major bug: unable to read tlvchain from redirect\n"); + return ret; + } + + if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1))) + { + printf("libfaim: major bug: no service ID in tlvchain from redirect\n"); + aim_freetlvchain(&tlvlist); + return ret; } - else if ( (command->data[0] == 0x00) && - (command->data[1] == 0x07) && - (command->data[2] == 0x00) && - (command->data[3] == 0x05) ) + serviceid = aimutil_get16(tmptlv->value); + + if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1))) + { + printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid); + aim_freetlvchain(&tlvlist); + return ret; + } + + if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1))) { - /* "information change reply" */ - return (aim_callbacks[AIM_CB_AUTH_INFOCHNG_REPLY])(command); + printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid); + aim_freetlvchain(&tlvlist); + return ret; + } + memcpy(cookie, tmptlv->value, AIM_COOKIELEN); + + if (serviceid == AIM_CONN_TYPE_CHAT) + { + /* + * Chat hack. + * + */ + userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); + if (userfunc) + ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin); + free(sess->pendingjoin); + sess->pendingjoin = NULL; } else { - /* anything else -- usually used for login; just parse as pure TLVs */ - + userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); + if (userfunc) + ret = userfunc(sess, command, serviceid, ip, cookie); + } - /* all this block does is figure out if it's an - error or a success, nothing more */ - while (z < command->commandlen) - { - tlv = aim_grabtlvstr(&(command->data[z])); - switch(tlv->type) - { - case 0x0001: /* screen name */ - aim_logininfo.screen_name = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0004: /* error URL */ - errorurl = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0005: /* BOS IP */ - aim_logininfo.BOSIP = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0006: /* auth cookie */ - aim_logininfo.cookie = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv=NULL; - break; - case 0x0011: /* email addy */ - aim_logininfo.email = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0013: /* registration status */ - aim_logininfo.regstatus = *(tlv->value); - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - break; - case 0x0008: /* error code */ - errorcode = *(tlv->value); - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - iserror = 1; - break; - default: - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - /* dunno */ - } - } + /* + * XXX: Is there a leak here? Where does IP get freed? + */ + aim_freetlvchain(&tlvlist); - if (iserror && - errorurl && - errorcode) - return (aim_callbacks[AIM_CB_AUTH_ERROR])(command, &aim_logininfo, errorurl, errorcode); - else if (aim_logininfo.screen_name && - aim_logininfo.cookie && aim_logininfo.BOSIP) - return (aim_callbacks[AIM_CB_AUTH_SUCCESS])(command, &aim_logininfo); - else - return (aim_callbacks[AIM_CB_AUTH_OTHER])(command); - } + return ret; } -/* - * TODO: check for and cure any memory leaks here. - */ -int aim_handleredirect_middle(struct command_rx_struct *command, ...) +int aim_parse_unknown(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { - struct aim_tlv_t *tlv = NULL; - int z = 10; - int serviceid; - char *cookie; - char *ip; + u_int i = 0; - while (z < command->commandlen) - { - tlv = aim_grabtlvstr(&(command->data[z])); - switch(tlv->type) - { - case 0x000d: /* service id */ - aim_freetlv(&tlv); - /* regrab as an int */ - tlv = aim_grabtlv(&(command->data[z])); - serviceid = (tlv->value[0] << 8) + tlv->value[1]; /* hehe */ - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - break; - case 0x0005: /* service server IP */ - ip = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0006: /* auth cookie */ - cookie = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - default: - /* dunno */ - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - } - } - return (aim_callbacks[AIM_CB_LOGIN_P3D_F])(command, serviceid, ip, cookie); -} - -int aim_parse_unknown(struct command_rx_struct *command, ...) -{ - int i = 0; - - printf("\nRecieved unknown packet:"); + faimdprintf(1, "\nRecieved unknown packet:"); for (i = 0; i < command->commandlen; i++) { @@ -464,18 +689,20 @@ * Middle handler for 0x0001 snac of each family. * */ -int aim_parse_generalerrs(struct command_rx_struct *command, ...) +int aim_parse_generalerrs(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { u_short family; u_short subtype; - family = (command->data[0] << 8) + command->data[1]; - subtype = (command->data[2] << 8) + command->data[3]; + + family = aimutil_get16(command->data+0); + subtype= aimutil_get16(command->data+2); switch(family) { default: /* Unknown family */ - return (aim_callbacks[AIM_CB_UNKNOWN])(command); + return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command); } return 1; diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_rxqueue.c --- a/libfaim/aim_rxqueue.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_rxqueue.c Sat May 20 00:30:53 2000 +0000 @@ -1,247 +1,165 @@ /* - aim_rxqueue.c - - This file contains the management routines for the receive - (incoming packet) queue. The actual packet handlers are in - aim_rxhandlers.c. - + * aim_rxqueue.c + * + * This file contains the management routines for the receive + * (incoming packet) queue. The actual packet handlers are in + * aim_rxhandlers.c. */ -#include "aim.h" - -/* - This is a modified read() to make SURE we get the number - of bytes we are told to, otherwise block. - */ -int Read(int fd, u_char *buf, int len) -{ - int i = 0; - int j = 0; - - while ((i < len) && (!(i < 0))) - { - j = read(fd, &(buf[i]), len-i); - if ( (j < 0) && (errno != EAGAIN)) - return -errno; /* fail */ - else - i += j; /* success, continue */ - } -#if 0 - printf("\nRead Block: (%d/%04x)\n", len, len); - printf("\t"); - for (j = 0; j < len; j++) - { - if (j % 8 == 0) - printf("\n\t"); - if (buf[j] >= ' ' && buf[j] < 127) - printf("%c=%02x ",buf[j], buf[j]); - else - printf("0x%02x ", buf[j]); - } - printf("\n\n"); -#endif - return i; -} +#include /* - struct command_struct * - get_generic( - struct connection_info struct *, - struct command_struct * - ) - - Grab as many command sequences as we can off the socket, and enqueue - each command in the incoming event queue in a seperate struct. - -*/ -int aim_get_command(void) + * Grab a single command sequence off the socket, and enqueue + * it in the incoming event queue in a seperate struct. + */ +int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn) { - int i, readgood, j, isav, err; - int s; - fd_set fds; - struct timeval tv; - char generic[6]; - struct command_rx_struct *workingStruct = NULL; - struct command_rx_struct *workingPtr = NULL; - struct aim_conn_t *conn = NULL; -#if debug > 0 - printf("Reading generic/unknown response..."); -#endif - - - /* dont wait at all (ie, never call this unless something is there) */ - tv.tv_sec = 0; - tv.tv_usec = 0; - conn = aim_select(&tv); + u_char generic[6]; + struct command_rx_struct *newrx = NULL; - if (conn==NULL) - return 0; /* nothing waiting */ - - s = conn->fd; + if (!sess || !conn) + return 0; - FD_ZERO(&fds); - FD_SET(s, &fds); - tv.tv_sec = 0; /* wait, but only for 10us */ - tv.tv_usec = 10; - - generic[0] = 0x00; + if (conn->fd < 3) /* can happen when people abuse the interface */ + return 0; - readgood = 0; - i = 0; - j = 0; - /* read first 6 bytes (the FLAP header only) off the socket */ - while ( (select(s+1, &fds, NULL, NULL, &tv) == 1) && (i < 6)) - { - if ((err = Read(s, &(generic[i]), 1)) < 0) - { - /* error is probably not recoverable...(must be a pessimistic day) */ - aim_conn_close(conn); - return err; - } + /* + * 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. + */ + if (read(conn->fd, generic, 6) < 6){ + aim_conn_close(conn); + return -1; + } - if (readgood == 0) - { - if (generic[i] == 0x2a) - { - readgood = 1; -#if debug > 1 - printf("%x ", generic[i]); - fflush(stdout); -#endif - i++; - } - else - { -#if debug > 1 - printf("skipping 0x%d ", generic[i]); - fflush(stdout); -#endif - j++; - } - } - else - { -#if debug > 1 - printf("%x ", generic[i]); -#endif - i++; - } - FD_ZERO(&fds); - FD_SET(s, &fds); - tv.tv_sec= 2; - tv.tv_usec= 2; - } - - if (generic[0] != 0x2a) - { - /* this really shouldn't happen, since the main loop - select() should protect us from entering this function - without data waiting */ - printf("Bad incoming data!"); - return -1; - } - - isav = i; + /* + * 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(1, "Bad incoming data!"); + return -1; + } /* allocate a new struct */ - workingStruct = (struct command_rx_struct *) malloc(sizeof(struct command_rx_struct)); - workingStruct->lock = 1; /* lock the struct */ + newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)); + if (!newrx) + return -1; + memset(newrx, 0x00, sizeof(struct command_rx_struct)); - /* store type -- byte 2 */ - workingStruct->type = (char) generic[1]; + newrx->lock = 1; /* lock the struct */ + + /* store channel -- byte 2 */ + newrx->type = (char) generic[1]; /* store seqnum -- bytes 3 and 4 */ - workingStruct->seqnum = ( (( (unsigned int) generic[2]) & 0xFF) << 8); - workingStruct->seqnum += ( (unsigned int) generic[3]) & 0xFF; + newrx->seqnum = aimutil_get16(generic+2); /* store commandlen -- bytes 5 and 6 */ - workingStruct->commandlen = ( (( (unsigned int) generic[4]) & 0xFF ) << 8); - workingStruct->commandlen += ( (unsigned int) generic[5]) & 0xFF; - - printf("%d\n", workingStruct->commandlen); + newrx->commandlen = aimutil_get16(generic+4); + + newrx->nofree = 0; /* free by default */ /* malloc for data portion */ - workingStruct->data = (char *) malloc(workingStruct->commandlen); + newrx->data = (u_char *) malloc(newrx->commandlen); + if (!newrx->data) { + free(newrx); + return -1; + } /* read the data portion of the packet */ - i = Read(s, workingStruct->data, workingStruct->commandlen); - if (i < 0) - { - aim_conn_close(conn); - return i; - } + if (read(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){ + free(newrx->data); + free(newrx); + aim_conn_close(conn); + return -1; + } -#if debug > 0 - printf(" done. (%db+%db read, %db skipped)\n", isav, i, j); -#endif + newrx->conn = conn; - workingStruct->conn = conn; - - workingStruct->next = NULL; /* this will always be at the bottom */ - workingStruct->lock = 0; /* unlock */ + newrx->next = NULL; /* this will always be at the bottom */ + newrx->lock = 0; /* unlock */ /* enqueue this packet */ - if (aim_queue_incoming == NULL) - aim_queue_incoming = workingStruct; - else - { - workingPtr = aim_queue_incoming; - while (workingPtr->next != NULL) - workingPtr = workingPtr->next; - workingPtr->next = workingStruct; - } + if (sess->queue_incoming == NULL) { + sess->queue_incoming = newrx; + } else { + struct command_rx_struct *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); return 0; } /* - purge_rxqueue() - - This is just what it sounds. It purges the receive (rx) queue of - all handled commands. This is normally called from inside - aim_rxdispatch() after it's processed all the commands in the queue. - + * Purge recieve queue of all handled commands (->handled==1). Also + * allows for selective freeing using ->nofree so that the client can + * keep the data for various purposes. + * + * If ->nofree is nonzero, the frame will be delinked from the global list, + * but will not be free'ed. The client _must_ keep a pointer to the + * data -- libfaim will not! If the client marks ->nofree but + * does not keep a pointer, it's lost forever. + * */ -struct command_rx_struct *aim_purge_rxqueue(struct command_rx_struct *queue) +void aim_purge_rxqueue(struct aim_session_t *sess) { - int i = 0; - struct command_rx_struct *workingPtr = NULL; - struct command_rx_struct *workingPtr2 = NULL; + struct command_rx_struct *cur = NULL; + struct command_rx_struct *tmp; - workingPtr = queue; - if (queue == NULL) - { - return queue; + 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) { + free(tmp->data); + free(tmp); + } else + tmp->next = NULL; } - else if (queue->next == NULL) - { - if (queue->handled == 1) - { - workingPtr2 = queue; - queue = NULL; - free(workingPtr2->data); - free(workingPtr2); - } - return queue; - } - else - { - for (i = 0; workingPtr != NULL; i++) - { - if (workingPtr->next->handled == 1) - { - /* save struct */ - workingPtr2 = workingPtr->next; - /* dequeue */ - workingPtr->next = workingPtr2->next; - /* free */ - free(workingPtr2->data); - free(workingPtr2); - } + return; + } - workingPtr = workingPtr->next; - } - } + for(cur = sess->queue_incoming; cur->next != NULL; ) { + if (cur->next->handled) { + tmp = cur->next; + cur->next = tmp->next; + if (!tmp->nofree) { + free(tmp->data); + free(tmp); + } else + tmp->next = NULL; + } + cur = cur->next; - return queue; + /* + * 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; } diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_search.c --- a/libfaim/aim_search.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_search.c Sat May 20 00:30:53 2000 +0000 @@ -8,46 +8,30 @@ #include -u_long aim_usersearch_address(struct aim_conn_t *conn, char *address) +u_long aim_usersearch_address(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *address) { - struct command_tx_struct newpacket; + struct command_tx_struct *newpacket; if (!address) return -1; - newpacket.lock = 1; + if (!(newpacket = aim_tx_new(0x0002, conn, 10+strlen(address)))) + return -1; - if (conn) - newpacket.conn = conn; - else - newpacket.conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - - newpacket.type = 0x0002; - - newpacket.commandlen = 10 + strlen(address); - newpacket.data = (char *) malloc(newpacket.commandlen); + newpacket->lock = 1; - newpacket.data[0] = 0x00; - newpacket.data[1] = 0x0a; - newpacket.data[2] = 0x00; - newpacket.data[3] = 0x02; - newpacket.data[4] = 0x00; - newpacket.data[5] = 0x00; + aim_putsnac(newpacket->data, 0x000a, 0x0002, 0x0000, sess->snac_nextid); - /* SNAC reqid */ - newpacket.data[6] = (aim_snac_nextid >> 24) & 0xFF; - newpacket.data[7] = (aim_snac_nextid >> 16) & 0xFF; - newpacket.data[8] = (aim_snac_nextid >> 8) & 0xFF; - newpacket.data[9] = (aim_snac_nextid) & 0xFF; + aimutil_putstr(newpacket->data+10, address, strlen(address)); - memcpy(&(newpacket.data[10]), address, strlen(address)); - - aim_tx_enqueue(&newpacket); + aim_tx_enqueue(sess, newpacket); { struct aim_snac_t snac; - snac.id = aim_snac_nextid; + snac.id = sess->snac_nextid; snac.family = 0x000a; snac.type = 0x0002; snac.flags = 0x0000; @@ -55,9 +39,9 @@ snac.data = malloc(strlen(address)+1); memcpy(snac.data, address, strlen(address)+1); - aim_newsnac(&snac); + aim_newsnac(sess, &snac); } - return (aim_snac_nextid++); + return (sess->snac_nextid++); } diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_snac.c --- a/libfaim/aim_snac.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_snac.c Sat May 20 00:30:53 2000 +0000 @@ -13,51 +13,60 @@ */ #include -#include -struct aim_snac_t *aim_outstanding_snacs = NULL; -u_long aim_snac_nextid = 0x00000001; - -u_long aim_newsnac(struct aim_snac_t *newsnac) { - struct aim_snac_t *snac = NULL, *cur = aim_outstanding_snacs; +u_long aim_newsnac(struct aim_session_t *sess, + struct aim_snac_t *newsnac) +{ + struct aim_snac_t *snac = NULL, *cur = NULL; - assert(newsnac != NULL); - snac = calloc(1, sizeof(struct aim_snac_t)); - assert(snac != NULL); - memcpy(snac, newsnac, sizeof(struct aim_snac_t)); - snac->issuetime = time(&snac->issuetime); - snac->next = NULL; + if (!newsnac) + return 0; + + cur = sess->outstanding_snacs; - if (cur == NULL) { - aim_outstanding_snacs = snac; - return(snac->id); - } - while (cur->next != NULL) - cur = cur->next; - cur->next = snac; - return(snac->id); + snac = calloc(1, sizeof(struct aim_snac_t)); + if (!snac) + return 0; + memcpy(snac, newsnac, sizeof(struct aim_snac_t)); + snac->issuetime = time(&snac->issuetime); + snac->next = NULL; + + if (cur == NULL) { + sess->outstanding_snacs = snac; + return(snac->id); + } + while (cur->next != NULL) + cur = cur->next; + cur->next = snac; + + return(snac->id); } -struct aim_snac_t *aim_remsnac(u_long id) { - struct aim_snac_t *cur = aim_outstanding_snacs; +struct aim_snac_t *aim_remsnac(struct aim_session_t *sess, + u_long id) +{ + struct aim_snac_t *cur; + + cur = sess->outstanding_snacs; + + if (cur == NULL) + return(NULL); - if (cur == NULL) - return(NULL); - if (cur->id == id) { - aim_outstanding_snacs = cur->next; - return(cur); - } - while (cur->next != NULL) { - if (cur->next->id == id) { - struct aim_snac_t *tmp = NULL; - - tmp = cur->next; - cur->next = cur->next->next; - return(tmp); - } - cur = cur->next; - } - return(NULL); + if (cur->id == id) { + sess->outstanding_snacs = cur->next; + return(cur); + } + while (cur->next != NULL) { + if (cur->next->id == id) { + struct aim_snac_t *tmp = NULL; + + tmp = cur->next; + cur->next = cur->next->next; + return(tmp); + } + cur = cur->next; + } + return(NULL); } /* @@ -68,22 +77,25 @@ * why its called _max_age). * */ -int aim_cleansnacs(int maxage) +int aim_cleansnacs(struct aim_session_t *sess, + int maxage) { - struct aim_snac_t *cur = aim_outstanding_snacs; + struct aim_snac_t *cur; struct aim_snac_t *remed = NULL; time_t curtime; + + cur = sess->outstanding_snacs; curtime = time(&curtime); - + while (cur) { if ( (cur) && (((cur->issuetime) + maxage) < curtime)) { #if DEBUG > 1 - printf("aimsnac: WARNING purged obsolete snac %ul\n", cur->id); + printf("aimsnac: WARNING purged obsolete snac %08lx\n", cur->id); #endif - remed = aim_remsnac(cur->id); + remed = aim_remsnac(sess, cur->id); if (remed) { if (remed->data) @@ -93,16 +105,16 @@ } cur = cur->next; } - + return 0; } int aim_putsnac(u_char *buf, int family, int subtype, int flags, u_long snacid) { int curbyte = 0; - curbyte += aimutil_put16(buf+curbyte,family&0xffff); - curbyte += aimutil_put16(buf+curbyte,subtype&0xffff); - curbyte += aimutil_put16(buf+curbyte,flags&0xffff); - curbyte += aimutil_put32(buf+curbyte,snacid); + 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; } diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_tlv.c --- a/libfaim/aim_tlv.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_tlv.c Sat May 20 00:30:53 2000 +0000 @@ -1,5 +1,246 @@ #include +struct aim_tlvlist_t *aim_readtlvchain(u_char *buf, int maxlen) +{ + int pos; + struct aim_tlvlist_t *list; + struct aim_tlvlist_t *cur; + + u_short type; + u_short length; + + if (!buf) + return NULL; + + list = NULL; + + pos = 0; + + while (pos < maxlen) + { + type = aimutil_get16(buf+pos); + pos += 2; + + if (pos < maxlen) + { + length = aimutil_get16(buf+pos); + pos += 2; + + if ((pos+length) <= maxlen) + { + cur = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); + memset(cur, 0x00, sizeof(struct aim_tlvlist_t)); + + cur->tlv = aim_createtlv(); + cur->tlv->type = type; + cur->tlv->length = length; + cur->tlv->value = (u_char *)malloc(length*sizeof(u_char)); + memcpy(cur->tlv->value, buf+pos, length); + + cur->next = list; + list = cur; + + pos += length; + } + } + } + + return list; +} + +void aim_freetlvchain(struct aim_tlvlist_t **list) +{ + struct aim_tlvlist_t *cur, *cur2; + + if (!list || !(*list)) + return; + + cur = *list; + while (cur) + { + aim_freetlv(&cur->tlv); + cur2 = cur->next; + free(cur); + cur = cur2; + } + list = NULL; + return; +} + +int aim_counttlvchain(struct aim_tlvlist_t **list) +{ + struct aim_tlvlist_t *cur; + int count = 0; + + if (!list || !(*list)) + return 0; + + for (cur = *list; cur; cur = cur->next) + count++; + + return count; +} + +int aim_addtlvtochain_str(struct aim_tlvlist_t **list, unsigned short type, char *str, int len) +{ + struct aim_tlvlist_t *new; + struct aim_tlvlist_t *cur; + + if (!list) + return 0; + + new = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); + memset(new, 0x00, sizeof(struct aim_tlvlist_t)); + + new->tlv = aim_createtlv(); + new->tlv->type = type; + new->tlv->length = len; + new->tlv->value = (u_char *)malloc(new->tlv->length*sizeof(u_char)); + memcpy(new->tlv->value, str, new->tlv->length); + + new->next = NULL; + + if (*list == NULL) { + *list = new; + } else if ((*list)->next == NULL) { + (*list)->next = new; + } else { + for(cur = *list; cur->next; cur = cur->next) + ; + cur->next = new; + } + return new->tlv->length; +} + +int aim_addtlvtochain16(struct aim_tlvlist_t **list, unsigned short type, unsigned short val) +{ + struct aim_tlvlist_t *new; + struct aim_tlvlist_t *cur; + + if (!list) + return 0; + + new = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); + memset(new, 0x00, sizeof(struct aim_tlvlist_t)); + + new->tlv = aim_createtlv(); + new->tlv->type = type; + new->tlv->length = 2; + new->tlv->value = (u_char *)malloc(new->tlv->length*sizeof(u_char)); + aimutil_put16(new->tlv->value, val); + + new->next = NULL; + + if (*list == NULL) { + *list = new; + } else if ((*list)->next == NULL) { + (*list)->next = new; + } else { + for(cur = *list; cur->next; cur = cur->next) + ; + cur->next = new; + } + return 2; +} + +int aim_addtlvtochain32(struct aim_tlvlist_t **list, unsigned short type, unsigned long val) +{ + struct aim_tlvlist_t *new; + struct aim_tlvlist_t *cur; + + if (!list) + return 0; + + new = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); + memset(new, 0x00, sizeof(struct aim_tlvlist_t)); + + new->tlv = aim_createtlv(); + new->tlv->type = type; + new->tlv->length = 4; + new->tlv->value = (u_char *)malloc(new->tlv->length*sizeof(u_char)); + aimutil_put32(new->tlv->value, val); + + new->next = NULL; + + if (*list == NULL) { + *list = new; + } else if ((*list)->next == NULL) { + (*list)->next = new; + } else { + for(cur = *list; cur->next; cur = cur->next) + ; + cur->next = new; + } + return 4; +} + +int aim_writetlvchain(u_char *buf, int buflen, struct aim_tlvlist_t **list) +{ + int goodbuflen = 0; + int i = 0; + struct aim_tlvlist_t *cur; + + if (!list || !buf || !buflen) + return 0; + + /* 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 */ + + /* 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; + } + + return i; +} + + +/* + * Grab the Nth TLV of type type in the TLV list list. + */ +struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, u_short type, int nth) +{ + 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; + } + } + return NULL; +} + +char *aim_gettlv_str(struct aim_tlvlist_t *list, u_short type, int nth) +{ + struct 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'; + + return newstr; +} + struct aim_tlv_t *aim_grabtlv(u_char *src) { struct aim_tlv_t *dest = NULL; @@ -79,8 +320,30 @@ int aim_puttlv_16(u_char *buf, u_short t, u_short v) { int curbyte=0; - curbyte += aimutil_put16(buf+curbyte, t&0xffff); - curbyte += aimutil_put16(buf+curbyte, 0x0002); - curbyte += aimutil_put16(buf+curbyte, v&0xffff); + curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff)); + curbyte += aimutil_put16(buf+curbyte, (u_short)0x0002); + curbyte += aimutil_put16(buf+curbyte, (u_short)(v&0xffff)); + return curbyte; +} + +int aim_puttlv_32(u_char *buf, u_short t, u_long v) +{ + int curbyte=0; + curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff)); + curbyte += aimutil_put16(buf+curbyte, (u_short)0x0004); + curbyte += aimutil_put32(buf+curbyte, (u_long)(v&0xffffffff)); return curbyte; } + +int aim_puttlv_str(u_char *buf, u_short t, u_short l, u_char *v) +{ + int curbyte; + + curbyte = 0; + curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff)); + curbyte += aimutil_put16(buf+curbyte, (u_short)(l&0xffff)); + if (v) + memcpy(buf+curbyte, v, l); + curbyte += l; + return curbyte; +} diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_txqueue.c --- a/libfaim/aim_txqueue.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_txqueue.c Sat May 20 00:30:53 2000 +0000 @@ -1,307 +1,290 @@ /* - aim_txqueue.c - - Herein lies all the mangement routines for the transmit (Tx) queue. - - */ - -#include "aim.h" - -/* - aim_tx_enqeue() - - 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 - + * aim_txqueue.c + * + * Herein lies all the mangement routines for the transmit (Tx) queue. + * */ -int aim_tx_enqueue(struct command_tx_struct *newpacket) +#include + +/* + * Allocate a new tx frame. + * + * This is more for looks than anything else. + * + * Right now, that is. If/when we implement a pool of transmit + * frames, this will become the request-an-unused-frame part. + */ +struct command_tx_struct *aim_tx_new(int chan, struct aim_conn_t *conn, int datalen) { - struct command_tx_struct *workingPtr = NULL; - struct command_tx_struct *newpacket_copy = NULL; + struct command_tx_struct *new; - if (newpacket->conn == NULL) - { - printf("aim_tx_enqueue: WARNING: enqueueing packet with no connecetion, defaulting to BOS\n"); - newpacket->conn = aim_getconn_type(AIM_CONN_TYPE_BOS); - } - - newpacket_copy = (struct command_tx_struct *) malloc (sizeof(struct command_tx_struct)); - memcpy(newpacket_copy, newpacket, sizeof(struct command_tx_struct)); + if (!conn) + return NULL; + + new = (struct command_tx_struct *)malloc(sizeof(struct command_tx_struct)); + if (!new) + return NULL; + memset(new, 0, sizeof(struct command_tx_struct)); - /* assign seqnum */ - newpacket_copy->seqnum = aim_get_next_txseqnum(newpacket_copy->conn); - /* set some more fields */ - newpacket_copy->lock = 1; /* lock */ - newpacket_copy->sent = 0; /* not sent yet */ - newpacket_copy->next = NULL; /* always last */ + new->conn = conn; + new->type = chan; + + if(datalen) { + new->data = (u_char *)malloc(datalen); + new->commandlen = datalen; + } + + return new; +} - if (aim_queue_outgoing == NULL) - { - aim_queue_outgoing = newpacket_copy; - } - else - { - workingPtr = aim_queue_outgoing; - while (workingPtr->next != NULL) - workingPtr = workingPtr->next; - workingPtr->next = newpacket_copy; - } - - newpacket_copy->lock = 0; /* unlock so it can be sent */ +/* + * aim_tx_enqeue() + * + * 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 + * + */ +int aim_tx_enqueue(struct aim_session_t *sess, + struct command_tx_struct *newpacket) +{ + struct command_tx_struct *cur; -#if debug > 2 - printf("calling aim_tx_printqueue()\n"); - aim_tx_printqueue(); - printf("back from aim_tx_printqueue()\n"); -#endif + if (newpacket->conn == NULL) { + faimdprintf(1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n"); + newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); + } + + /* assign seqnum */ + newpacket->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 */ - /* we'll force a flush for now -- this behavior probably will change */ -#if debug > 1 - printf("calling aim_tx_flushqueue()\n"); -#endif - aim_tx_flushqueue(); -#if debug > 1 - printf("back from aim_tx_flushqueue()\n"); + /* 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; + } + + newpacket->lock = 0; /* unlock so it can be sent */ + +#if debug == 2 + faimdprintf(2, "calling aim_tx_printqueue()\n"); + aim_tx_printqueue(sess); + faimdprintf(2, "back from aim_tx_printqueue()\n"); #endif return 0; } /* - aim_get_next_txseqnum() - - This increments the tx command count, and returns the seqnum - that should be stamped on the next FLAP packet sent. This is - normally called during the final step of packet preparation - before enqueuement (in aim_tx_enqueue()). - + * aim_get_next_txseqnum() + * + * This increments the tx command count, and returns the seqnum + * that should be stamped on the next FLAP packet sent. This is + * normally called during the final step of packet preparation + * before enqueuement (in aim_tx_enqueue()). + * */ -unsigned int aim_get_next_txseqnum(struct aim_conn_t *conn) +u_int aim_get_next_txseqnum(struct aim_conn_t *conn) { return ( ++conn->seqnum ); } /* - aim_tx_printqueue() - - This is basically for debuging purposes only. It dumps all the - records in the tx queue and their current status. Very helpful - if the queue isn't working quite right. - + * aim_tx_printqueue() + * + * This is basically for debuging purposes only. It dumps all the + * records in the tx queue and their current status. Very helpful + * if the queue isn't working quite right. + * */ -#if debug > 2 -int aim_tx_printqueue(void) +#if debug == 2 +int aim_tx_printqueue(struct aim_session_t *sess) { - struct command_tx_struct *workingPtr = NULL; + struct command_tx_struct *cur; - workingPtr = aim_queue_outgoing; -#if debug > 2 - printf("\ncurrent aim_queue_outgoing...\n"); - printf("\ttype seqnum len lock sent\n"); -#endif - if (workingPtr == NULL) - printf("aim_tx_flushqueue(): queue empty"); - else - { - while (workingPtr != NULL) - { - printf("\t %2x %4x %4x %1d %1d\n", workingPtr->type, workingPtr->seqnum, workingPtr->commandlen, workingPtr->lock, workingPtr->sent); - - workingPtr = workingPtr->next; - } - } + faimdprintf(2, "\ncurrent aim_queue_outgoing...\n"); + faimdprintf(2, "\ttype seqnum len lock sent\n"); - printf("\n(done printing queue)\n"); + if (sess->queue_outgoing == NULL) + faimdprintf(2, "aim_tx_flushqueue(): queue empty"); + else { + for (cur = sess->queue_outgoing; cur; cur = cur->next) { + faimdprintf(2, "\t %2x %4x %4x %1d %1d\n", + cur->type, cur->seqnum, + cur->commandlen, cur->lock, + cur->sent); + } + } + + faimdprintf(2, "\n(done printing queue)\n"); return 0; } #endif /* - 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. - + * 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. + * */ -int aim_tx_flushqueue(void) +int aim_tx_flushqueue(struct aim_session_t *sess) { - struct command_tx_struct *workingPtr = NULL; - unsigned char *curPacket = NULL; + struct command_tx_struct *cur; + u_char *curPacket = NULL; #if debug > 1 int i = 0; #endif - workingPtr = aim_queue_outgoing; -#if debug > 1 - printf("beginning txflush...\n"); -#endif - while (workingPtr != NULL) - { - /* only process if its unlocked and unsent */ - if ( (workingPtr->lock == 0) && - (workingPtr->sent == 0) ) - { - workingPtr->lock = 1; /* lock the struct */ - - /* allocate full-packet buffer */ - curPacket = (char *) malloc(workingPtr->commandlen + 6); - - /* command byte */ - curPacket[0] = 0x2a; - /* type/family byte */ - curPacket[1] = workingPtr->type; - /* bytes 3+4: word: FLAP sequence number */ - curPacket[2] = (char) ( (workingPtr->seqnum) >> 8); - curPacket[3] = (char) ( (workingPtr->seqnum) & 0xFF); - /* bytes 5+6: word: SNAC len */ - curPacket[4] = (char) ( (workingPtr->commandlen) >> 8); - curPacket[5] = (char) ( (workingPtr->commandlen) & 0xFF); - /* bytes 7 and on: raw: SNAC data */ - memcpy(&(curPacket[6]), workingPtr->data, workingPtr->commandlen); - - /* full image of raw packet data now in curPacket */ + if (sess->queue_outgoing == NULL) + return 0; + + faimdprintf(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) { + + /* + * 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)); + } + + cur->lock = 1; /* lock the struct */ + + /* allocate full-packet buffer */ + curPacket = (char *) malloc(cur->commandlen + 6); + + /* command byte */ + curPacket[0] = 0x2a; + + /* type/family byte */ + curPacket[1] = cur->type; + + /* bytes 3+4: word: FLAP sequence number */ + aimutil_put16(curPacket+2, cur->seqnum); - if ( write(workingPtr->conn->fd, curPacket, (workingPtr->commandlen + 6)) != (workingPtr->commandlen + 6)) - { - perror("write"); - printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", workingPtr->seqnum); - workingPtr->sent = 0; /* mark it unsent */ - return -1; /* bail out */ - } - else - { -#if debug > 2 - printf("\nSENT 0x%4x\n\n", workingPtr->seqnum); -#endif - workingPtr->sent = 1; /* mark the struct as sent */ - } + /* bytes 5+6: word: SNAC len */ + aimutil_put16(curPacket+4, cur->commandlen); + + /* bytes 7 and on: raw: SNAC data */ + memcpy(&(curPacket[6]), cur->data, cur->commandlen); + + /* full image of raw packet data now in curPacket */ + if ( (u_int)write(cur->conn->fd, curPacket, (cur->commandlen + 6)) != (cur->commandlen + 6)) { + printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", cur->seqnum); + cur->sent = 0; /* mark it unsent */ + continue; /* bail out */ + } else { + faimdprintf(2, "\nSENT 0x%4x\n\n", cur->seqnum); + + cur->sent = 1; /* mark the struct as sent */ + cur->conn->lastactivity = time(NULL); + } #if debug > 2 - printf("\nPacket:"); - for (i = 0; i < (workingPtr->commandlen + 6); i++) - { - if ((i % 8) == 0) - printf("\n\t"); - if (curPacket[i] >= ' ' && curPacket[i]<127) - printf("%c=%02x ",curPacket[i], curPacket[i]); - else - printf("0x%2x ", curPacket[i]); - } - printf("\n"); + faimdprintf(2, "\nPacket:"); + for (i = 0; i < (cur->commandlen + 6); i++) { + if ((i % 8) == 0) { + faimdprintf(2, "\n\t"); + } + if (curPacket[i] >= ' ' && curPacket[i]<127) { + faimdprintf(2, "%c=%02x ", curPacket[i], curPacket[i]); + } else { + faimdprintf(2, "0x%2x ", curPacket[i]); + } + } + faimdprintf(2, "\n"); #endif - workingPtr->lock = 0; /* unlock the struct */ - free(curPacket); /* free up full-packet buffer */ - } - workingPtr = workingPtr->next; + cur->lock = 0; /* unlock the struct */ + free(curPacket); /* free up full-packet buffer */ } + } /* purge sent commands from queue */ - /* this may not always occur explicitly--i may put this on a timer later */ -#if debug > 1 - printf("calling aim_tx_purgequeue()\n"); -#endif - aim_tx_purgequeue(); -#if debug > 1 - printf("back from aim_tx_purgequeu() [you must be a lucky one]\n"); -#endif + aim_tx_purgequeue(sess); return 0; } /* - aim_tx_purgequeue() - - This is responsable for removing sent commands from the transmit - queue. This is not a required operation, but it of course helps - reduce memory footprint at run time! - + * aim_tx_purgequeue() + * + * This is responsable for removing sent commands from the transmit + * queue. This is not a required operation, but it of course helps + * reduce memory footprint at run time! + * */ -int aim_tx_purgequeue(void) +void aim_tx_purgequeue(struct aim_session_t *sess) { - struct command_tx_struct *workingPtr = NULL; - struct command_tx_struct *workingPtr2 = NULL; -#if debug > 1 - printf("purgequeue(): starting purge\n"); -#endif - /* Empty queue: nothing to do */ - if (aim_queue_outgoing == NULL) - { -#if debug > 1 - printf("purgequeue(): purge done (len=0)\n"); -#endif - return 0; + struct command_tx_struct *cur = NULL; + struct command_tx_struct *tmp; + + 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; + free(tmp->data); + free(tmp); } - /* One Node queue: free node and return */ - else if (aim_queue_outgoing->next == NULL) - { -#if debug > 1 - printf("purgequeue(): entered case len=1\n"); -#endif - /* only free if sent AND unlocked -- dont assume sent structs are done */ - if ( (aim_queue_outgoing->lock == 0) && - (aim_queue_outgoing->sent == 1) ) - { -#if debug > 1 - printf("purgequeue(): purging seqnum 0x%04x\n", aim_queue_outgoing->seqnum); -#endif - workingPtr2 = aim_queue_outgoing; - aim_queue_outgoing = NULL; - free(workingPtr2->data); - free(workingPtr2); - } -#if debug > 1 - printf("purgequeue(): purge done (len=1)\n"); -#endif - return 0; - } - else - { -#if debug > 1 - printf("purgequeue(): entering case len>1\n"); -#endif - while(workingPtr->next != NULL) - { - if ( (workingPtr->next->lock == 0) && - (workingPtr->next->sent == 1) ) - { -#if debug > 1 - printf("purgequeue(): purging seqnum 0x%04x\n", workingPtr->next->seqnum); -#endif - workingPtr2 = workingPtr->next; - workingPtr->next = workingPtr2->next; - free(workingPtr2->data); - free(workingPtr2); - } - } -#if debug > 1 - printf("purgequeue(): purge done (len>1)\n"); -#endif - return 0; - } + return; + } + + for(cur = sess->queue_outgoing; cur->next != NULL; ) { + if (!cur->next->lock && cur->next->sent) { + tmp = cur->next; + cur->next = tmp->next; + free(tmp->data); + free(tmp); + } + cur = cur->next; - /* no reach */ + /* + * 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; } diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/aim_util.c --- a/libfaim/aim_util.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_util.c Sat May 20 00:30:53 2000 +0000 @@ -4,35 +4,226 @@ * */ -#include "aim.h" +#include +#include + +#define AIMUTIL_USEMACROS -int aimutil_put8(u_char *buf, u_short data) +#ifdef AIMUTIL_USEMACROS +/* macros in aim.h */ +#else +inline int aimutil_put8(u_char *buf, u_char data) { - buf[0] = data&0xff; + buf[0] = (u_char)data&0xff; return 1; } +inline u_char aimutil_get8(u_char *buf) +{ + return buf[0]; +} + /* * Endian-ness issues here? */ -int aimutil_put16(u_char *buf, u_short data) +inline int aimutil_put16(u_char *buf, u_short data) { - buf[0] = (data>>8)&0xff; - buf[1] = (data)&0xff; + buf[0] = (u_char)(data>>8)&0xff; + buf[1] = (u_char)(data)&0xff; return 2; } -int aimutil_put32(u_char *buf, u_long data) +inline u_short aimutil_get16(u_char *buf) { - buf[0] = (data>>24)&0xff; - buf[1] = (data>>16)&0xff; - buf[2] = (data>>8)&0xff; - buf[3] = (data)&0xff; + u_short val; + val = (buf[0] << 8) & 0xff00; + val+= (buf[1]) & 0xff; + return val; +} + +inline 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; } -int aimutil_putstr(u_char *dest, u_char *src, int len) +inline 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 */ + +inline int aimutil_putstr(u_char *dest, const u_char *src, int len) { memcpy(dest, src, len); return len; } + +/* + * Tokenizing functions. Used to portably replace strtok/sep. + * -- DMP. + * + */ +int aimutil_tokslen(char *toSearch, int index, char dl) +{ + int curCount = 1; + char *next; + char *last; + int toReturn; + + 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); + + return toReturn; +} + +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; +} + +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); + } + 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 aim_snlen(const char *sn) +{ + int i = 0; + const char *curPtr = NULL; + + if (!sn) + return 0; + + curPtr = sn; + while ( (*curPtr) != (char) NULL) { + if ((*curPtr) != ' ') + i++; + curPtr++; + } + + 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 aim_sncmp(const char *sn1, const char *sn2) +{ + const char *curPtr1 = NULL, *curPtr2 = NULL; + + 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++; + } + } + + return 0; +} diff -r 62d470738cc7 -r 6ced2f1c8b24 libfaim/faimconfig.h --- a/libfaim/faimconfig.h Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/faimconfig.h Sat May 20 00:30:53 2000 +0000 @@ -1,42 +1,106 @@ +/* + * faimconfig.h + * + * Contains various compile-time options that apply _only_ to libfaim. + * Note that setting any of these options in a frontend header does not imply + * that they'll get set here. Notably, the 'debug' of this file is _not_ + * the same as the frontend 'debug'. They can be different values. + * + */ + #ifndef __FAIMCONFIG_H__ #define __FAIMCONFIG_H__ -/* - faimconfig.h +/* + * set debug to be > 0 if you want debugging information spewing + * on the attached tty. set to 0 for daily use. this value + * is _not_ inherited by the frontend, only this backend. + * + * Default: 0 +*/ +#define debug 0 - Contains various compile-time options that apply _only to the faim backend_. - Note that setting any of these options in a frontend header does not imply - that they'll get set here. Notably, the 'debug' of this file is _not_ - the same as the frontend 'debug'. They can be different values. - +/* + * Maximum number of connections the library can simultaneously + * handle per session structure. Five is fairly arbitrary. + * + * Normally, only one connection gets used at a time. However, if + * chat is used, its easily possible for several connections to be + * open simultaneously. + * + * Normal connection list looks like this: + * 1 -- used for authentication at login (closed after login) + * 1 -- used for BOS (general messaging) (stays open for entire session) + * 1 -- used for chatnav (room creation, etc) (opened at random) + * 1n -- used for n connected chat rooms (AOL limits to three) + * + * Default: 7 + * */ +#define AIM_CONN_MAX 7 -/* - set debug to be > 0 if you want debugging information spewing - on the attached tty. set to 0 for daily use. this value - is _not_ inherited by the frontend, only this backend. - - Default: 0 -*/ -#define debug 10 +/* + * USE_SNAC_FOR_IMS is an old feature that allowed better + * tracking of error messages by caching SNAC IDs of outgoing + * ICBMs and comparing them to incoming errors. However, + * its a helluvalot of overhead for something that should + * rarely happen. + * + * Default: defined. This is now defined by default + * because it should be stable and its not too bad. + * And Josh wanted it. + * + */ +#define USE_SNAC_FOR_IMS /* - define TIS_TELNET_PROXY if you have a TIS firewall (Gauntlet) and - you want to use FAIM through the firewall - - Default: undefined + * As of AIM 3.5 or so, AOL as added a better way of + * logging in. Define this to use it instead of the + * old Version 1.0 way. + * + * The largest caveat here is that I have no idea + * how to encode passwords using the new 3.5 way. + * Until someone figures that out the... + * + * Default: Undefined. + * */ -/* #define TIS_TELNET_PROXY "proxy.mydomain.com" */ - +#undef SNACLOGIN -/* #define USE_SNAC_FOR_IMS */ - -/* ---- these shouldn't need any changes ---- */ - -/* authentication server of OSCAR */ +/* + * Default Authorizer server name and TCP port for the OSCAR farm. + * + * You shouldn't need to change this unless you're writing + * your own server. + * + * Note that only one server is needed to start the whole + * AIM process. The later server addresses come from + * the authorizer service. + * + * This is only here for convenience. Its still up to + * the client to connect to it. + * + */ #define FAIM_LOGIN_SERVER "login.oscar.aol.com" -/* port on OSCAR authenticator to connect to */ #define FAIM_LOGIN_PORT 5190 +/* + * MAX_READ_ERROR can be decreased if you find dead connections + * lingering around, and not getting detected, for too long. + * + * Default: 100 + * + */ +#define MAX_READ_ERROR 100 + +/* + * 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 #endif /* __FAIMCONFIG_H__ */ diff -r 62d470738cc7 -r 6ced2f1c8b24 src/dialogs.c --- a/src/dialogs.c Thu May 18 18:20:18 2000 +0000 +++ b/src/dialogs.c Sat May 20 00:30:53 2000 +0000 @@ -1085,10 +1085,7 @@ return; } - buf = g_malloc(BUF_LONG); - g_snprintf(buf, BUF_LONG, "toc_change_passwd %s %s", orig, new1); - sflap_send(buf, strlen(buf), TYPE_DATA); - g_free(buf); + serv_change_passwd(orig, new1); destroy_dialog(NULL, b->window); g_free(b); @@ -2098,7 +2095,7 @@ return; } if ((f = fopen(path,"w"))) { - toc_build_config(buf, 8192 - 1); + serv_build_config(buf, 8192 - 1); fprintf(f, "%s\n", buf); fclose(f); chmod(buf, S_IRUSR | S_IWUSR); diff -r 62d470738cc7 -r 6ced2f1c8b24 src/gaim.h --- a/src/gaim.h Thu May 18 18:20:18 2000 +0000 +++ b/src/gaim.h Sat May 20 00:30:53 2000 +0000 @@ -337,7 +337,7 @@ #define TYPE_SIGNOFF 4 #define TYPE_KEEPALIVE 5 -#define REVISION "gaim:$Revision: 244 $" +#define REVISION "gaim:$Revision: 247 $" #define FLAPON "FLAPON\r\n\r\n" #define ROAST "Tic/Toc" @@ -357,7 +357,10 @@ #endif /* USE_APPLET */ /* Globals in oscar.c */ -extern struct aim_conn_t *gaim_conn; +#ifdef USE_OSCAR +extern struct aim_session_t *gaim_sess; +extern struct aim_conn_t *gaim_conn; +#endif /* Globals in server.c */ extern int correction_time; @@ -505,12 +508,14 @@ extern void serv_set_idle(int); extern void serv_set_info(char *); extern void serv_set_away(char *); +extern void serv_change_passwd(char *, char *); extern void serv_add_buddy(char *); extern void serv_add_buddies(GList *); extern void serv_remove_buddy(char *); extern void serv_add_permit(char *); extern void serv_add_deny(char *); extern void serv_set_permit_deny(); +extern void serv_build_config(char *, int); extern void serv_save_config(); extern void serv_warn(char *, int); extern void serv_set_dir(char *, char *, char *, char *, char *, char *, char *, int); @@ -553,8 +558,8 @@ extern int connect_address(unsigned int, unsigned short); /* Functions in oscar.c */ -extern void oscar_close(); extern int oscar_login(char *, char *); +extern int oscar_send_im(char *, char *, int); /* Functions in toc.c */ extern void toc_close(); diff -r 62d470738cc7 -r 6ced2f1c8b24 src/oscar.c --- a/src/oscar.c Thu May 18 18:20:18 2000 +0000 +++ b/src/oscar.c Sat May 20 00:30:53 2000 +0000 @@ -35,367 +35,382 @@ #include #include #include "gaim.h" -#include +#include "aim.h" #include "gnome_applet_mgr.h" -struct aim_conn_t *gaim_conn = NULL; static int inpa = -1; +static struct aim_session_t *gaim_sess; +static struct aim_conn_t *gaim_conn; -int gaim_auth_failure(struct command_rx_struct *command, ...); -int gaim_auth_success(struct command_rx_struct *command, ...); -int gaim_serverready_handle(struct command_rx_struct *command, ...); -int gaim_redirect_handle(struct command_rx_struct *command, ...); -int gaim_im_handle(struct command_rx_struct *command, ...); +static int gaim_parse_auth_resp (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_auth_server_ready(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_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_unknown (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_motd (struct aim_session_t *, struct command_rx_struct *, ...); + +static void oscar_callback(gpointer data, gint source, + GdkInputCondition condition) { + struct aim_session_t *sess = (struct aim_session_t *)data; + struct aim_conn_t *conn = NULL; + struct timeval tv; + int selstat; -rxcallback_t gaim_callbacks[] = { - gaim_im_handle, /* incoming IM */ - NULL,/*gaim_buddy_coming, oncoming buddy */ - NULL,/*gaim_buddy_going, offgoing buddy */ - NULL, /* last IM was missed 1 */ - NULL, /* last IM was missed 2 */ - NULL, /* UNUSED */ - NULL, /* UNUSED */ - NULL, /* UNUSED */ - gaim_serverready_handle, /* server ready */ - NULL, /* UNUSED */ - NULL, /* UNUSED */ - NULL, /* UNUSED */ - NULL, /* UNUSED */ - NULL, /* UNUSED */ - NULL, /* UNUSED */ - gaim_redirect_handle, /* redirect */ - NULL, /* last command bad */ - NULL, /* missed some messages */ - NULL, /* completely unknown command */ - NULL, /*gaim_userinfo_handler, User Info Response */ - NULL, /* Address search response */ - NULL, /* Name search response */ - NULL, /* User Search fail */ - gaim_auth_failure, /* auth error */ - gaim_auth_success, /* auth success */ - NULL, /* auth server ready */ - NULL, /* ? */ - NULL, /* password change done */ - gaim_serverready_handle, /* server ready */ - 0x00 -}; + /* FIXME : There's gotta be a better way of getting this to not + * either hang until a message is received or only update every + * 2 seconds. If someone can tell me what it is, let me know. */ + tv.tv_sec = 2; + tv.tv_usec = 0; + conn = aim_select(sess, &tv, &selstat); -struct client_info_s cinfo; - - -void oscar_close() -{ -#ifdef USE_APPLET - setUserState(offline); -#endif /* USE_APPLET */ - set_state(STATE_OFFLINE); - aim_conn_close(gaim_conn); - if (inpa > 0) - gdk_input_remove(inpa); - inpa=-1; + switch(selstat) { + case -1: /* error */ + signoff(); + hide_login_progress("Disconnected."); + aim_logoff(sess); + gdk_input_remove(inpa); + break; + case 0: /* this should never happen because of the gdk_input */ + gdk_input_remove(inpa); + while (gtk_events_pending()) + gtk_main_iteration(); + inpa = gdk_input_add(gaim_conn->fd, + GDK_INPUT_READ | GDK_INPUT_WRITE | + GDK_INPUT_EXCEPTION, + oscar_callback, sess); + break; + case 1: /* outgoing data pending */ + aim_tx_flushqueue(sess); + break; + case 2: /* incoming data pending */ + if (aim_get_command(sess, conn) < 0) + debug_print("connection error!\n"); + else + aim_rxdispatch(sess); + break; + } } +int oscar_login(char *username, char *password) { + struct aim_session_t *sess; + struct aim_conn_t *conn; + struct client_info_s info = {"Gaim/Faim", 3, 5, 1670, "us", "en"}; + char buf[256]; -void oscar_callback(gpointer data, gint source, GdkInputCondition condition) -{ - if (aim_get_command() < 0) { - signoff(); - hide_login_progress("Connection Closed"); - return; - } else - aim_rxdispatch(); + sess = g_new0(struct aim_session_t, 1); + aim_session_init(sess); + + sprintf(buf, "Looking up %s", FAIM_LOGIN_SERVER); + set_login_progress(1, buf); + conn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, FAIM_LOGIN_SERVER); + if (conn == NULL) { + debug_print("internal connection error\n"); +#ifdef USE_APPLET + setUserState(offline); +#endif + set_state(STATE_OFFLINE); + hide_login_progress("Unable to login to AIM"); + return -1; + } else if (conn->fd == -1) { +#ifdef USE_APPLET + setUserState(offline); +#endif + set_state(STATE_OFFLINE); + if (conn->status & AIM_CONN_STATUS_RESOLVERR) { + sprintf(debug_buff, "couldn't resolve host\n"); + debug_print(debug_buff); + hide_login_progress(debug_buff); + } else if (conn->status & AIM_CONN_STATUS_CONNERR) { + sprintf(debug_buff, "couldn't connect to host\n"); + debug_print(debug_buff); + hide_login_progress(debug_buff); + } + return -1; + } + g_snprintf(buf, sizeof(buf), "Signon: %s", username); + set_login_progress(2, buf); + + aim_conn_addhandler(sess, conn, AIM_CB_FAM_SPECIAL, + AIM_CB_SPECIAL_AUTHSUCCESS, + gaim_parse_auth_resp, 0); + aim_conn_addhandler(sess, conn, AIM_CB_FAM_GEN, + AIM_CB_GEN_SERVERREADY, + gaim_auth_server_ready, 0); + aim_send_login(sess, conn, username, password, &info); + + inpa = gdk_input_add(conn->fd, + GDK_INPUT_READ | GDK_INPUT_EXCEPTION, + oscar_callback, sess); + + if (!current_user) { + current_user = g_new0(struct aim_user, 1); + g_snprintf(current_user->username, sizeof(current_user->username), + DEFAULT_INFO); + aim_users = g_list_append(aim_users, current_user); + } + g_snprintf(current_user->username, sizeof(current_user->username), + "%s", username); + g_snprintf(current_user->password, sizeof(current_user->password), + "%s", password); + save_prefs(); + + return 0; } -int oscar_login(char *username, char *password) -{ - char buf[256]; - struct timeval timeout; - time_t lastcycle=0; - - aim_connrst(); - aim_register_callbacks(gaim_callbacks); - - aim_conn_getnext()->fd = STDIN_FILENO; - - spintf(buf, "Looking up %s", login_host); - set_login_progress(1, buf); - - gaim_conn = aim_newconn(AIM_CONN_TYPE_AUTH, login_host); - - if (!gaim_conn) { -#ifdef USE_APPLET - setUserState(offline); -#endif /* USE_APPLET */ - set_state(STATE_OFFLINE); - hide_login_progress("Unable to login to AIM"); - return -1; - } else if (gaim_conn->fd == -1) { -#ifdef USE_APPLET - setUserState(offline); -#endif /* USE_APPLET */ - set_state(STATE_OFFLINE); - - if (gaim_conn->status & AIM_CONN_STATUS_RESOLVERR) { - sprintf(buf, "Unable to lookup %s", login_host); - hide_login_progress(buf); - } else if (gaim_conn->status & AIM_CONN_STATUS_CONNERR) { - sprintf(buf, "Unable to connect to %s", login_host); - hide_login_progress(buf); - } - return -1; - } - - g_snprintf(buf, sizeof(buf), "Signon: %s",username); - - set_login_progress(2, buf); - - strcpy(cinfo.clientstring, "libfaim/GAIM, jimduchek@ou.edu, see at http://www.marko.net/gaim"); - cinfo.major = 0; - cinfo.minor = 9; - cinfo.build = 7; - strcpy(cinfo.country, "us"); - strcpy(cinfo.lang, "en"); - - aim_send_login(gaim_conn, username, password, &cinfo); - - if (!current_user) { - current_user = g_new0(struct aim_user, 1); - g_snprintf(current_user->username, sizeof(current_user->username), DEFAULT_INFO); - aim_users = g_list_append(aim_users, current_user); - } - - g_snprintf(current_user->username, sizeof(current_user->username), "%s", username); - g_snprintf(current_user->password, sizeof(current_user->password), "%s", password); - - save_prefs(); - - inpa = gdk_input_add(gaim_conn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, oscar_callback, NULL); - - return 0; +int oscar_send_im(char *name, char *msg, int away) { + if (away) + aim_send_im(gaim_sess, gaim_conn, name, AIM_IMFLAGS_AWAY, msg); + else + aim_send_im(gaim_sess, gaim_conn, name, 0, msg); } -int gaim_auth_success(struct command_rx_struct *command, ...) -{ - va_list ap; - struct login_phase1_struct *logininfo; - struct aim_conn_t *bosconn = NULL; - char buf[128]; - - va_start(ap, command); - logininfo = va_arg(ap, struct login_phase1_struct *); - va_end(ap); +int gaim_parse_auth_resp(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + struct aim_conn_t *bosconn = NULL; + sprintf(debug_buff, "inside auth_resp (Screen name: %s)\n", + sess->logininfo.screen_name); + debug_print(debug_buff); - g_snprintf(buf, sizeof(buf), "Auth successful, logging in to %s:", logininfo->BOSIP); - set_login_progress(3, buf); - - printf(" Screen name: %s\n", logininfo->screen_name); - printf(" Email addresss: %s\n", logininfo->email); - printf(" Registration status: %02i\n", logininfo->regstatus); - printf("Connecting to %s, closing auth connection.\n", - logininfo->BOSIP); + if (sess->logininfo.errorcode) { + sprintf(debug_buff, "Login Error Code 0x%04x\n", + sess->logininfo.errorcode); + debug_print(debug_buff); + sprintf(debug_buff, "Error URL: %s\n", + sess->logininfo.errorurl); + debug_print(debug_buff); +#ifdef USE_APPLET + setUserState(offline); +#endif + set_state(STATE_OFFLINE); + hide_login_progress("Authentication Failed"); + gdk_input_remove(inpa); + aim_conn_close(command->conn); + return 0; + } - aim_conn_close(command->conn); - gdk_input_remove(inpa); + sprintf(debug_buff, "Email: %s\n", sess->logininfo.email); + debug_print(debug_buff); + sprintf(debug_buff, "Closing auth connection...\n"); + debug_print(debug_buff); + gdk_input_remove(inpa); + aim_conn_close(command->conn); - if ((bosconn = aim_newconn(AIM_CONN_TYPE_BOS, logininfo->BOSIP)) - == NULL) { + bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, sess->logininfo.BOSIP); + if (bosconn == NULL) { #ifdef USE_APPLET - setUserState(offline); -#endif /* USE_APPLET */ - set_state(STATE_OFFLINE); - - hide_login_progress("Could not connect to BOS: internal error"); - return(-1); - } else if (bosconn->status != 0) { + setUserState(offline); +#endif + set_state(STATE_OFFLINE); + hide_login_progress("Internal Error"); + return -1; + } else if (bosconn->status != 0) { #ifdef USE_APPLET - setUserState(offline); -#endif /* USE_APPLET */ - set_state(STATE_OFFLINE); + setUserState(offline); +#endif + set_state(STATE_OFFLINE); + hide_login_progress("Could Not Connect"); + return -1; + } - hide_login_progress("Could not connect to BOS"); - return(-1); - } else { - aim_auth_sendcookie(bosconn, logininfo->cookie); - inpa = gdk_input_add(bosconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, oscar_callback, NULL); - set_login_progress(4, "BOS connection established, cookie sent."); - return(1); - } + 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_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, NULL, 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); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, gaim_parse_incoming_im, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, gaim_parse_misses, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, gaim_parse_misses, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, gaim_parse_misses, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, gaim_parse_misses, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parse_user_info, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_CTN, AIM_CB_CTN_DEFAULT, gaim_parse_unknown, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEFAULT, gaim_parse_unknown, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, gaim_parse_motd, 0); + + aim_auth_sendcookie(sess, bosconn, sess->logininfo.cookie); + inpa = gdk_input_add(bosconn->fd, + GDK_INPUT_READ | GDK_INPUT_WRITE | GDK_INPUT_EXCEPTION, + oscar_callback, sess); + set_login_progress(4, "Connection established, cookie sent"); + return 1; } -int gaim_auth_failure(struct command_rx_struct *command, ...) -{ - va_list ap; - struct login_phase1_struct *logininfo; - char *errorurl; - short errorcode; - - va_start(ap, command); - logininfo = va_arg(ap, struct login_phase1_struct *); - printf("Screen name: %s\n", logininfo->screen_name); - errorurl = va_arg(ap, char *); - printf("Error URL: %s\n", errorurl); - errorcode = va_arg(ap, short); - printf("Error code: 0x%02x\n", errorcode); - va_end(ap); -#ifdef USE_APPLET - setUserState(offline); -#endif /* USE_APPLET */ - set_state(STATE_OFFLINE); - hide_login_progress("Authentication Failed"); - - aim_conn_close(aim_getconn_type(AIM_CONN_TYPE_AUTH)); - - return 1; +int gaim_auth_server_ready(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + aim_auth_clientready(sess, command->conn); + return 1; } -int gaim_serverready_handle(struct command_rx_struct *command, ...) -{ - switch (command->conn->type) { - case AIM_CONN_TYPE_BOS: - aim_bos_reqrate(command->conn); - aim_bos_ackrateresp(command->conn); - aim_bos_setprivacyflags(command->conn, 0x00000003); - aim_bos_reqservice(command->conn, AIM_CONN_TYPE_ADS); - aim_bos_setgroupperm(NULL, 0x1f); - break; - case AIM_CONN_TYPE_CHATNAV: +int gaim_server_ready(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + switch (command->conn->type) { + case AIM_CONN_TYPE_BOS: + aim_bos_reqrate(sess, command->conn); + aim_bos_ackrateresp(sess, command->conn); + aim_bos_setprivacyflags(sess, command->conn, 0x00000003); + aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_ADS); + aim_setversions(sess, command->conn); + aim_bos_setgroupperm(sess, command->conn, 0x1f); + debug_print("done with BOS ServerReady\n"); break; - default: - printf("Unknown connection type on serverready\n"); + case AIM_CONN_TYPE_CHATNAV: + break; + case AIM_CONN_TYPE_CHAT: break; - } - return(1); - + default: /* huh? */ + break; + } + return 1; } -int gaim_redirect_handle(struct command_rx_struct *command, ...) -{ - va_list ap; - int serviceid; - char *ip, *cookie; +int gaim_handle_redirect(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + va_list ap; + int serviceid; + char *ip; + char *cookie; - va_start(ap, command); - serviceid = va_arg(ap, int); - ip = va_arg(ap, char *); - cookie = va_arg(ap, char *); - va_end(ap); + /* FIXME */ + char buddies[] = "EWarmenhoven&RobFlynn&Zilding&FlynOrange&"; + char profile[] = "Hello"; - switch(serviceid) { - case 0x0005: { - char *buf; - char *buf2; - char file[1024]; - FILE *f; + va_start(ap, command); + serviceid = va_arg(ap, int); + ip = va_arg(ap, char *); + cookie = va_arg(ap, char *); - g_snprintf(file, sizeof(file), "%s/.gaimbuddy", getenv("HOME")); - - if (!(f = fopen(file,"r"))) { - } else { - buf = g_malloc(BUF_LONG); - fread(buf, BUF_LONG, 1, f); + switch(serviceid) { + case 0x0005: /* Ads */ + aim_bos_setbuddylist(sess, command->conn, buddies); + aim_bos_setprofile(sess, command->conn, profile, NULL, AIM_CAPS_CHAT); - parse_toc_buddy_list(buf); + aim_bos_clientready(sess, command->conn); - build_edit_tree(); - build_permit_tree(); - + gaim_sess = sess; + gaim_conn = command->conn; - g_free(buf); - } - - - - aim_bos_clientready(command->conn); - - set_login_progress(5, "Logged in.\n"); + debug_print("Roger that, all systems go\n"); #ifdef USE_APPLET + make_buddy(); if (general_options & OPT_GEN_APP_BUDDY_SHOW) { - show_buddy_list(); - refresh_buddy_window(); + gnome_buddy_show(); + createOnlinePopup(); + set_applet_draw_open(); } else { + gnome_buddy_hide(); + set_applet_draw_closed(); } - - set_applet_draw_closed(); setUserState(online); + gtk_widget_hide(mainwindow); #else gtk_widget_hide(mainwindow); show_buddy_list(); refresh_buddy_window(); #endif - serv_finish_login(); - gaim_conn = command->conn; - - break; - } - case 0x0007: { - struct aim_conn_t *tstconn; - - tstconn = aim_newconn(AIM_CONN_TYPE_AUTH, ip); - if ((tstconn == NULL) || - (tstconn->status >= AIM_CONN_STATUS_RESOLVERR)) { -#ifdef USE_APPLET - setUserState(offline); -#endif /* USE_APPLET */ - set_state(STATE_OFFLINE); - hide_login_progress("Unable to reconnect to authorizer"); - } else - aim_auth_sendcookie(tstconn, cookie); break; - } - case 0x000d: { - struct aim_conn_t *tstconn; - - tstconn = aim_newconn(AIM_CONN_TYPE_CHATNAV, ip); - if ((tstconn == NULL) || - (tstconn->status >= AIM_CONN_STATUS_RESOLVERR)) - printf("Unable to connect to chatnav server\n"); + case 0x7: /* Authorizer */ + { + struct aim_conn_t *tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, ip); + if (tstconn == NULL || tstconn->status >= AIM_CONN_STATUS_RESOLVERR) + debug_print("unable to reconnect with authorizer\n"); else - aim_auth_sendcookie( - aim_getconn_type(AIM_CONN_TYPE_CHATNAV), - cookie); + aim_auth_sendcookie(sess, tstconn, cookie); + } + break; + case 0xd: /* ChatNav */ + break; + case 0xe: /* Chat */ + break; + default: /* huh? */ + sprintf(debug_buff, "got redirect for unknown service 0x%04x\n", + serviceid); + debug_print(debug_buff); break; } - case 0x000e: - printf("CHAT is not yet supported :(\n"); - break; - default: - printf("Unknown redirect %#04X\n", serviceid); - break; - } - return(1); - + + va_end(ap); + + return 1; +} + +int gaim_parse_oncoming(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + return 1; +} + +int gaim_parse_offgoing(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + return 1; } - +int gaim_parse_incoming_im(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + int channel; + va_list ap; -int gaim_im_handle(struct command_rx_struct *command, ...) -{ - time_t t = 0; - char *screenname, *msg; - int warninglevel, class, idletime, isautoreply; - ulong membersince, onsince; - va_list ap; + va_start(ap, command); + channel = va_arg(ap, int); - va_start(ap, command); - screenname = va_arg(ap, char *); - msg = va_arg(ap, char *); - warninglevel = va_arg(ap, int); - class = va_arg(ap, int); - membersince = va_arg(ap, ulong); - onsince = va_arg(ap, ulong); - idletime = va_arg(ap, int); - isautoreply = va_arg(ap, int); - va_end(ap); + /* channel 1: standard message */ + if (channel == 1) { + struct aim_userinfo_s *userinfo; + char *msg = NULL; + u_int icbmflags = 0; + char *tmpstr = NULL; + u_short flag1, flag2; - printf("'%s'\n", msg); - - serv_got_im(screenname, msg, isautoreply); + userinfo = va_arg(ap, struct aim_userinfo_s *); + msg = va_arg(ap, char *); + icbmflags = va_arg(ap, u_int); + flag1 = va_arg(ap, u_short); + flag2 = va_arg(ap, u_short); + va_end(ap); - return(1); + serv_got_im(userinfo->sn, msg, icbmflags & AIM_IMFLAGS_AWAY); + } - + return 1; } -#endif +int gaim_parse_misses(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + return 1; +} + +int gaim_parse_user_info(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + return 1; +} + +int gaim_parse_unknown(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + return 1; +} + +int gaim_parse_motd(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + char *msg; + u_short id; + va_list ap; + + va_start(ap, command); + id = va_arg(ap, u_short); + msg = va_arg(ap, char *); + va_end(ap); + + sprintf(debug_buff, "MOTD: %s\n", msg); + debug_print(debug_buff); + + return 1; +} + +#endif /* USE_OSCAR */ diff -r 62d470738cc7 -r 6ced2f1c8b24 src/rvous.c --- a/src/rvous.c Thu May 18 18:20:18 2000 +0000 +++ b/src/rvous.c Sat May 20 00:30:53 2000 +0000 @@ -19,6 +19,8 @@ * */ +#ifndef USE_OSCAR + #include #include #include @@ -699,3 +701,5 @@ */ } } + +#endif /* USE_OSCAR */ diff -r 62d470738cc7 -r 6ced2f1c8b24 src/server.c --- a/src/server.c Thu May 18 18:20:18 2000 +0000 +++ b/src/server.c Sat May 20 00:30:53 2000 +0000 @@ -53,8 +53,6 @@ { #ifndef USE_OSCAR toc_close(); -#else - oscar_close(); #endif gtk_timeout_remove(idle_timer); idle_timer = -1; @@ -159,7 +157,7 @@ message, ((away) ? " auto" : "")); sflap_send(buf, strlen(buf), TYPE_DATA); #else - aim_send_im(NULL, normalize(name), ((away) ? 0 : AIM_IMFLAGS_AWAY), message); + oscar_send_im(name, message, away); #endif if (!away) serv_touch_idle(); @@ -167,8 +165,8 @@ void serv_get_info(char *name) { + char buf[MSG_LEN]; #ifndef USE_OSCAR - char buf[MSG_LEN]; g_snprintf(buf, MSG_LEN, "toc_get_info %s", normalize(name)); sflap_send(buf, -1, TYPE_DATA); #endif @@ -176,8 +174,8 @@ void serv_get_dir(char *name) { + char buf[MSG_LEN]; #ifndef USE_OSCAR - char buf[MSG_LEN]; g_snprintf(buf, MSG_LEN, "toc_get_dir %s", normalize(name)); sflap_send(buf, -1, TYPE_DATA); #endif @@ -186,8 +184,8 @@ void serv_set_dir(char *first, char *middle, char *last, char *maiden, char *city, char *state, char *country, int web) { + char buf2[BUF_LEN*4], buf[BUF_LEN]; #ifndef USE_OSCAR - char buf2[BUF_LEN*4], buf[BUF_LEN]; g_snprintf(buf2, sizeof(buf2), "%s:%s:%s:%s:%s:%s:%s:%s", first, middle, last, maiden, city, state, country, (web == 1) ? "Y" : ""); @@ -200,8 +198,8 @@ void serv_dir_search(char *first, char *middle, char *last, char *maiden, char *city, char *state, char *country, char *email) { + char buf[BUF_LONG]; #ifndef USE_OSCAR - char buf[BUF_LONG]; g_snprintf(buf, sizeof(buf)/2, "toc_dir_search %s:%s:%s:%s:%s:%s:%s:%s", first, middle, last, maiden, city, state, country, email); sprintf(debug_buff,"Searching for: %s,%s,%s,%s,%s,%s,%s\n", first, middle, last, maiden, city, state, country); debug_print(debug_buff); @@ -212,8 +210,8 @@ void serv_set_away(char *message) { + char buf[MSG_LEN]; #ifndef USE_OSCAR - char buf[MSG_LEN]; if (message) g_snprintf(buf, MSG_LEN, "toc_set_away \"%s\"", message); else @@ -228,16 +226,22 @@ #ifndef USE_OSCAR g_snprintf(buf, sizeof(buf), "toc_set_info \"%s\n\"", info); sflap_send(buf, -1, TYPE_DATA); -#else - g_snprintf(buf, sizeof(buf), "%s\n", info); - aim_bos_setprofile(gaim_conn, buf); +#endif +} + +void serv_change_passwd(char *orig, char *new) { +#ifndef USE_OSCAR + char *buf = g_malloc(BUF_LONG); + g_snprintf(buf, BUF_LONG, "toc_change_passwd %s %s", orig, new); + sflap_send(buf, strlen(buf), TYPE_DATA); + g_free(buf); #endif } void serv_add_buddy(char *name) { + char buf[1024]; #ifndef USE_OSCAR - char buf[1024]; g_snprintf(buf, sizeof(buf), "toc_add_buddy %s", normalize(name)); sflap_send(buf, -1, TYPE_DATA); #endif @@ -247,8 +251,8 @@ { char buf[MSG_LEN]; int n, num = 0; + #ifndef USE_OSCAR - n = g_snprintf(buf, sizeof(buf), "toc_add_buddy"); while(buddies) { if (num == 20) { @@ -261,25 +265,14 @@ buddies = buddies->next; } sflap_send(buf, -1, TYPE_DATA); -#else - while(buddies) { - if (num == 20) { - aim_bos_setbuddylist(gaim_conn, buf); - num = 0; - } - ++num; - n += g_snprintf(buf + n, sizeof(buf) - n, "%s&", normalize(buddies->data)); - buddies = buddies->next; - } - aim_bos_setbuddylist(gaim_conn, buf); #endif } void serv_remove_buddy(char *name) { + char buf[1024]; #ifndef USE_OSCAR - char buf[1024]; g_snprintf(buf, sizeof(buf), "toc_remove_buddy %s", normalize(name)); sflap_send(buf, -1, TYPE_DATA); #endif @@ -287,8 +280,8 @@ void serv_add_permit(char *name) { + char buf[1024]; #ifndef USE_OSCAR - char buf[1024]; g_snprintf(buf, sizeof(buf), "toc_add_permit %s", normalize(name)); sflap_send(buf, -1, TYPE_DATA); #endif @@ -298,8 +291,8 @@ void serv_add_deny(char *name) { + char buf[1024]; #ifndef USE_OSCAR - char buf[1024]; g_snprintf(buf, sizeof(buf), "toc_add_deny %s", normalize(name)); sflap_send(buf, -1, TYPE_DATA); #endif @@ -309,10 +302,11 @@ void serv_set_permit_deny() { -#ifndef USE_OSCAR char buf[MSG_LEN]; int at; GList *list; + +#ifndef USE_OSCAR /* FIXME! We flash here. */ if (permdeny == 1 || permdeny == 3) { g_snprintf(buf, sizeof(buf), "toc_add_permit"); @@ -340,16 +334,13 @@ } buf[at] = 0; sflap_send(buf, -1, TYPE_DATA); - - - #endif } void serv_set_idle(int time) { + char buf[256]; #ifndef USE_OSCAR - char buf[256]; g_snprintf(buf, sizeof(buf), "toc_set_idle %d", time); sflap_send(buf, -1, TYPE_DATA); #endif @@ -367,38 +358,24 @@ #endif } +void serv_build_config(char *buf, int len) { +#ifndef USE_OSCAR + toc_build_config(buf, len); +#endif +} + void serv_save_config() { #ifndef USE_OSCAR char *buf = g_malloc(BUF_LONG); char *buf2 = g_malloc(MSG_LEN); - toc_build_config(buf, BUF_LONG / 2); + serv_build_config(buf, BUF_LONG / 2); g_snprintf(buf2, MSG_LEN, "toc_set_config {%s}", buf); sflap_send(buf2, -1, TYPE_DATA); g_free(buf2); g_free(buf); -#else - FILE *f; - char *buf = g_malloc(BUF_LONG); - char file[1024]; - - g_snprintf(file, sizeof(file), "%s/.gaimbuddy", getenv("HOME")); - - if ((f = fopen(file,"w"))) { - build_config(buf, BUF_LONG - 1); - fprintf(f, "%s\n", buf); - fclose(f); - chmod(buf, S_IRUSR | S_IWUSR); - } else { - g_snprintf(buf, BUF_LONG / 2, "Error writing file %s", file); - do_error_dialog(buf, "Error"); - } - - g_free(buf); - #endif - } @@ -414,8 +391,8 @@ void serv_join_chat(int exchange, char *name) { + char buf[BUF_LONG]; #ifndef USE_OSCAR - char buf[BUF_LONG]; g_snprintf(buf, sizeof(buf)/2, "toc_chat_join %d \"%s\"", exchange, name); sflap_send(buf, -1, TYPE_DATA); #endif @@ -423,8 +400,8 @@ void serv_chat_invite(int id, char *message, char *name) { + char buf[BUF_LONG]; #ifndef USE_OSCAR - char buf[BUF_LONG]; g_snprintf(buf, sizeof(buf)/2, "toc_chat_invite %d \"%s\" %s", id, message, normalize(name)); sflap_send(buf, -1, TYPE_DATA); #endif @@ -442,8 +419,8 @@ void serv_chat_whisper(int id, char *who, char *message) { + char buf2[MSG_LEN]; #ifndef USE_OSCAR - char buf2[MSG_LEN]; g_snprintf(buf2, sizeof(buf2), "toc_chat_whisper %d %s \"%s\"", id, who, message); sflap_send(buf2, -1, TYPE_DATA); #endif @@ -451,8 +428,8 @@ void serv_chat_send(int id, char *message) { + char buf[MSG_LEN]; #ifndef USE_OSCAR - char buf[MSG_LEN]; g_snprintf(buf, sizeof(buf), "toc_chat_send %d \"%s\"",id, message); sflap_send(buf, -1, TYPE_DATA); #endif diff -r 62d470738cc7 -r 6ced2f1c8b24 src/toc.c --- a/src/toc.c Thu May 18 18:20:18 2000 +0000 +++ b/src/toc.c Sat May 20 00:30:53 2000 +0000 @@ -35,6 +35,7 @@ #include "gaim.h" #include "gnome_applet_mgr.h" +#ifndef USE_OSCAR /* descriptor for talking to TOC */ @@ -843,6 +844,8 @@ } } +#endif /* USE_OSCAR */ + void parse_toc_buddy_list(char *config) { char *c;