From d410cf58c1b99101922ced3773b50c72e1dbfe5d Mon Sep 17 00:00:00 2001 From: mid Date: Sat, 8 Sep 2001 02:10:29 +0000 Subject: [PATCH] - Mon Sep 3 18:48:26 PDT 2001 - Reformat everything to use real tabs (and to my latest coding style) - Abstract out the numerical data types to fu8/16/32_t for portability. - AIM_FRAMETYPE_OSCAR -> AIM_FRAMETYPE_FLAP. This makes more sense. - aim_conn_t's FLAP sequence number was a signed int. Oops. - Get rid of the 'struct' on all types suffixed with _t. That's been annoying me for a while. They're all real typedefs now. - Yes, client people are going to be rather annoyed by this. But it doesn't stop there. Keep reading. - Make the 'struct aim_rxcblist_t' type local to rxhandlers.c. - Combine the command_tx_struct and command_rx_struct into aim_frame_t. - Mostly aim_frame_t is command_rx_struct. For command_tx_struct, the same structure is used, except where ->sent was, ->handled is now used. - This makes things a lot easier, everywhere. - Get rid of ->lock. Pointless. If libfaim is ever preemptible, it has much more important problems than that. - Welcome to aim_bstream_t. No more direct buffer accesses. Anywhere. - In fact I plan on getting rid of the aimutil macros completly. - This isn't complete yet. It will be better later. Believe me. Maybe even make more sense. - More advanced and configurable boundschecking is coming, too. - Clean up lots of stuff, everywhere. - Rearrange the implementation of the TLV functions, saving lots of code. - I'm rather pleased with the way some things got implemented with this, particularly in places where TLVs contain TLVs. - Get rid of aim_puttlv_() functions. Those were gross. Use tlvchains. - XOR login is temporarily broken. I'll fix it someday. ("Someone" needs it.) - Fix the return values of most everything -- OSCAR functions should all return 0 on sucess, negative errno on failure. - There are several things braced with #ifdef MID_REWROTE_ALL_THE_CRAP. Consider that code broken and nonfunctional for now. - I think I may have broken buddy icons. Remind me to fix that. - Renovate faimtest substantially. Reformat, split up, update to new types. --- CHANGES | 35 + include/aim.h | 810 +++++----- include/aim_internal.h | 186 ++- src/admin.c | 324 ++-- src/adverts.c | 44 +- src/auth.c | 343 ++--- src/bos.c | 90 +- src/buddylist.c | 168 +- src/chat.c | 909 ++++++----- src/chatnav.c | 688 +++++---- src/conn.c | 1248 ++++++++------- src/ft.c | 156 +- src/im.c | 693 ++++----- src/info.c | 943 +++++------- src/login.c | 513 +++---- src/md5.c | 1 - src/meta.c | 43 +- src/misc.c | 960 +++++------- src/msgcookie.c | 192 ++- src/rxhandlers.c | 939 ++++++------ src/rxqueue.c | 599 +++++--- src/search.c | 161 +- src/snac.c | 187 +-- src/stats.c | 36 +- src/tlv.c | 741 ++++----- src/txqueue.c | 678 ++++----- src/util.c | 362 ++--- utils/faimtest/Makefile.am | 2 +- utils/faimtest/chat.c | 260 ++++ utils/faimtest/commands.c | 310 ++-- utils/faimtest/faimtest.c | 2943 ++++++++++++------------------------ utils/faimtest/faimtest.h | 69 +- utils/faimtest/ft.c | 530 +++++++ utils/faimtest/login.c | 192 +++ 34 files changed, 8023 insertions(+), 8332 deletions(-) create mode 100644 utils/faimtest/chat.c create mode 100644 utils/faimtest/ft.c create mode 100644 utils/faimtest/login.c diff --git a/CHANGES b/CHANGES index 864512c..7506427 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,41 @@ No release numbers ------------------ + - Mon Sep 3 18:48:26 PDT 2001 + - Reformat everything to use real tabs (and to my latest coding style) + - Abstract out the numerical data types to fu8/16/32_t for portability. + - AIM_FRAMETYPE_OSCAR -> AIM_FRAMETYPE_FLAP. This makes more sense. + - aim_conn_t's FLAP sequence number was a signed int. Oops. + - Get rid of the 'struct' on all types suffixed with _t. That's been + annoying me for a while. They're all real typedefs now. + - Yes, client people are going to be rather annoyed by this. But it + doesn't stop there. Keep reading. + - Make the 'struct aim_rxcblist_t' type local to rxhandlers.c. + - Combine the command_tx_struct and command_rx_struct into aim_frame_t. + - Mostly aim_frame_t is command_rx_struct. For command_tx_struct, the + same structure is used, except where ->sent was, ->handled is now + used. + - This makes things a lot easier, everywhere. + - Get rid of ->lock. Pointless. If libfaim is ever preemptible, it + has much more important problems than that. + - Welcome to aim_bstream_t. No more direct buffer accesses. Anywhere. + - In fact I plan on getting rid of the aimutil macros completly. + - This isn't complete yet. It will be better later. Believe me. Maybe + even make more sense. + - More advanced and configurable boundschecking is coming, too. + - Clean up lots of stuff, everywhere. + - Rearrange the implementation of the TLV functions, saving lots of code. + - I'm rather pleased with the way some things got implemented with this, + particularly in places where TLVs contain TLVs. + - Get rid of aim_puttlv_() functions. Those were gross. Use tlvchains. + - XOR login is temporarily broken. I'll fix it someday. ("Someone" needs it.) + - Fix the return values of most everything -- OSCAR functions should all + return 0 on sucess, negative errno on failure. + - There are several things braced with #ifdef MID_REWROTE_ALL_THE_CRAP. + Consider that code broken and nonfunctional for now. + - I think I may have broken buddy icons. Remind me to fix that. + - Renovate faimtest substantially. Reformat, split up, update to new types. + - Wed Aug 29 16:59:24 PDT 2001 - Pass up entire icon triplet (checksum/length/timestamp) in all cases that it is recieved. diff --git a/include/aim.h b/include/aim.h index 3148acf..a12b95c 100644 --- a/include/aim.h +++ b/include/aim.h @@ -39,6 +39,13 @@ #include #endif +/* XXX adjust these based on autoconf-detected platform */ +typedef unsigned char fu8_t; +typedef unsigned short fu16_t; +typedef unsigned long fu32_t; +typedef fu32_t aim_snacid_t; +typedef fu16_t flap_seqnum_t; + #ifdef FAIM_USEPTHREADS #include #define faim_mutex_t pthread_mutex_t @@ -53,14 +60,20 @@ * means we don't have to do real locking. The * macros below do nothing really. They're a joke. * But they get it to compile. + * + * XXX NOTE that locking hasn't really been tested in a long time, + * and most code written after dec2000 --is not thread safe--. You'll + * want to audit locking use before you use less-than-library level + * concurrency. + * */ -#define faim_mutex_t char +#define faim_mutex_t fu8_t #define faim_mutex_init(x) *x = 0 #define faim_mutex_lock(x) while(*x != 0) {/* spin */}; *x = 1; #define faim_mutex_unlock(x) while(*x != 0) {/* spin spin spin */}; *x = 0; #define faim_mutex_destroy(x) while(*x != 0) {/* spiiiinnn */}; *x = 0; #elif defined(FAIM_USENOPLOCKS) -#define faim_mutex_t char +#define faim_mutex_t fu8_t #define faim_mutex_init(x) #define faim_mutex_lock(x) #define faim_mutex_unlock(x) @@ -164,39 +177,39 @@ * */ struct client_info_s { - char clientstring[100]; /* arbitrary size */ - int major; - int minor; - int build; - char country[3]; - char lang[3]; - int major2; - int minor2; - long unknown; + char clientstring[100]; /* arbitrary size */ + int major; + int minor; + int build; + char country[3]; + char lang[3]; + int major2; + int minor2; + long unknown; }; #define AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 { \ - "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \ - 0x0003, \ - 0x0005, \ - 0x0686, \ - "us", \ - "en", \ - 0x0004, \ - 0x0000, \ - 0x0000002a, \ + "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \ + 0x0003, \ + 0x0005, \ + 0x0686, \ + "us", \ + "en", \ + 0x0004, \ + 0x0000, \ + 0x0000002a, \ } #define AIM_CLIENTINFO_KNOWNGOOD_4_1_2010 { \ - "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \ - 0x0004, \ - 0x0001, \ - 0x07da, \ - "us", \ - "en", \ - 0x0004, \ - 0x0000, \ - 0x0000004b, \ + "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \ + 0x0004, \ + 0x0001, \ + 0x07da, \ + "us", \ + "en", \ + 0x0004, \ + 0x0000, \ + 0x0000004b, \ } /* @@ -224,7 +237,7 @@ struct client_info_s { #define AIM_CONN_TYPE_CHATNAV 0x000d /* they start getting arbitrary in rendezvous stuff =) */ -#define AIM_CONN_TYPE_RENDEZVOUS 0x0101 /* these do not speak OSCAR! */ +#define AIM_CONN_TYPE_RENDEZVOUS 0x0101 /* these do not speak FLAP! */ #define AIM_CONN_TYPE_RENDEZVOUS_OUT 0x0102 /* socket waiting for accept() */ /* @@ -245,145 +258,154 @@ struct client_info_s { #define AIM_CONN_STATUS_CONNERR 0x0080 #define AIM_CONN_STATUS_INPROGRESS 0x0100 -#define AIM_FRAMETYPE_OSCAR 0x0000 -#define AIM_FRAMETYPE_OFT 0x0001 - -struct aim_conn_t { - int fd; - unsigned short type; - unsigned short subtype; - int seqnum; - int status; - void *priv; /* misc data the client may want to store */ - time_t lastactivity; /* time of last transmit */ - int forcedlatency; - struct aim_rxcblist_t *handlerlist; - faim_mutex_t active; /* lock around read/writes */ - faim_mutex_t seqnum_lock; /* lock around ->seqnum changes */ - void *sessv; - struct aim_conn_t *next; -}; - -/* struct for incoming commands */ -struct command_rx_struct { - unsigned char hdrtype; /* defines which piece of the union to use */ - union { - struct { - char type; - unsigned short seqnum; - } oscar; - struct { - unsigned short type; - unsigned char magic[4]; /* ODC2 OFT2 */ - unsigned short hdr2len; - unsigned char *hdr2; /* rest of bloated header */ - } oft; - } hdr; - unsigned short commandlen; /* total payload length */ - unsigned char *data; /* packet data (from 7 byte on) */ - unsigned char lock; /* 0 = open, !0 = locked */ - unsigned char handled; /* 0 = new, !0 = been handled */ - unsigned char nofree; /* 0 = free data on purge, 1 = only unlink */ - struct aim_conn_t *conn; /* the connection it came in on... */ - struct command_rx_struct *next; /* ptr to next struct in list */ -}; +#define AIM_FRAMETYPE_FLAP 0x0000 +#define AIM_FRAMETYPE_OFT 0x0001 + +typedef struct aim_conn_s { + int fd; + fu16_t type; + fu16_t subtype; + flap_seqnum_t seqnum; + fu32_t status; + void *priv; /* misc data the client may want to store */ + time_t lastactivity; /* time of last transmit */ + int forcedlatency; + void *handlerlist; + faim_mutex_t active; /* lock around read/writes */ + faim_mutex_t seqnum_lock; /* lock around ->seqnum changes */ + void *sessv; /* pointer to parent session */ + struct aim_conn_s *next; +} aim_conn_t; -/* struct for outgoing commands */ -struct command_tx_struct { - unsigned char hdrtype; /* defines which piece of the union to use */ - union { - struct { - unsigned char type; - unsigned short seqnum; - } oscar; - struct { - unsigned short type; - unsigned char magic[4]; /* ODC2 OFT2 */ - unsigned short hdr2len; - unsigned char *hdr2; - } oft; - } hdr; - u_int commandlen; - u_char *data; - u_int lock; /* 0 = open, !0 = locked */ - u_int sent; /* 0 = pending, !0 = has been sent */ - struct aim_conn_t *conn; - struct command_tx_struct *next; /* ptr to next struct in list */ -}; +/* + * Byte Stream type. Sort of. + * + * Use of this type serves a couple purposes: + * - Buffer/buflen pairs are passed all around everywhere. This turns + * that into one value, as well as abstracting it slightly. + * - Through the abstraction, it is possible to enable bounds checking + * for robustness at the cost of performance. But a clean failure on + * weird packets is much better than a segfault. + * - I like having variables named "bs". + * + * Don't touch the insides of this struct. Or I'll have to kill you. + * + */ +typedef struct aim_bstream_s { + fu8_t *data; + fu16_t len; + fu16_t offset; +} aim_bstream_t; + +typedef struct aim_frame_s { + fu8_t hdrtype; /* defines which piece of the union to use */ + union { + struct { + fu8_t type; + flap_seqnum_t seqnum; + } flap; + struct { + fu16_t type; + fu8_t magic[4]; /* ODC2 OFT2 */ + fu16_t hdr2len; + fu8_t *hdr2; /* rest of bloated header */ + } oft; + } hdr; + aim_bstream_t data; /* payload stream */ + fu8_t handled; /* 0 = new, !0 = been handled */ + fu8_t nofree; /* 0 = free data on purge, 1 = only unlink */ + aim_conn_t *conn; /* the connection it came in on... */ + struct aim_frame_s *next; +} aim_frame_t; + +typedef struct aim_msgcookie_s { + unsigned char cookie[8]; + int type; + void *data; + time_t addtime; + struct aim_msgcookie_s *next; +} aim_msgcookie_t; /* * AIM Session: The main client-data interface. * */ -struct aim_session_t { - - /* ---- Client Accessible ------------------------ */ - /* - * Our screen name. - * - */ - char sn[MAXSNLEN+1]; - - /* - * Pointer to anything the client wants to - * explicitly associate with this session. - * - * This is for use in the callbacks mainly. In any - * callback, you can access this with sess->aux_data. - * - */ - void *aux_data; - - /* ---- Internal Use Only ------------------------ */ - /* - * Connection information - */ - struct aim_conn_t *connlist; - faim_mutex_t connlistlock; - - /* - * TX/RX queues - */ - struct command_tx_struct *queue_outgoing; - struct command_rx_struct *queue_incoming; - - /* - * Tx Enqueuing function - */ - int (*tx_enqueue)(struct aim_session_t *, struct command_tx_struct *); - - /* - * This is a dreadful solution to the what-room-are-we-joining - * problem. (There's no connection between the service - * request and the resulting redirect.) - */ - char *pendingjoin; - unsigned short pendingjoinexchange; - - /* - * Outstanding snac handling - * - * XXX: Should these be per-connection? -mid - */ - struct aim_snac_t *snac_hash[FAIM_SNAC_HASH_SIZE]; - faim_mutex_t snac_hash_locks[FAIM_SNAC_HASH_SIZE]; - unsigned long snac_nextid; - - struct { - char server[128]; - char username[128]; - char password[128]; - } socksproxy; - - unsigned long flags; - - int debug; - void (*debugcb)(struct aim_session_t *sess, int level, const char *format, va_list va); /* same as faim_debugging_callback_t */ - - struct aim_msgcookie_t *msgcookies; - - void *modlistv; -}; +typedef struct aim_session_s { + + /* ---- Client Accessible ------------------------ */ + + /* Our screen name. */ + char sn[MAXSNLEN+1]; + + /* + * Pointer to anything the client wants to + * explicitly associate with this session. + * + * This is for use in the callbacks mainly. In any + * callback, you can access this with sess->aux_data. + * + */ + void *aux_data; + + /* ---- Internal Use Only ------------------------ */ + + /* Connection information */ + aim_conn_t *connlist; + faim_mutex_t connlistlock; + + /* + * Transmit/receive queues. + * + * These are only used when you don't use your own lowlevel + * I/O. I don't suggest that you use libfaim's internal I/O. + * Its really bad and the API/event model is quirky at best. + * + */ + aim_frame_t *queue_outgoing; + aim_frame_t *queue_incoming; + + /* + * Tx Enqueuing function. + * + * This is how you override the transmit direction of libfaim's + * internal I/O. This function will be called whenever it needs + * to send something. + * + */ + int (*tx_enqueue)(struct aim_session_s *, aim_frame_t *); + + /* + * This is a dreadful solution to the what-room-are-we-joining + * problem. (There's no connection between the service + * request and the resulting redirect.) + */ + char *pendingjoin; + fu16_t pendingjoinexchange; + + /* + * Outstanding snac handling + * + * XXX: Should these be per-connection? -mid + */ + void *snac_hash[FAIM_SNAC_HASH_SIZE]; + faim_mutex_t snac_hash_locks[FAIM_SNAC_HASH_SIZE]; + aim_snacid_t snacid_next; + + struct { + char server[128]; + char username[128]; + char password[128]; + } socksproxy; + + fu32_t flags; /* AIM_SESS_FLAGS_ */ + + int debug; + void (*debugcb)(struct aim_session_s *sess, int level, const char *format, va_list va); /* same as faim_debugging_callback_t */ + + aim_msgcookie_t *msgcookies; + + void *modlistv; +} aim_session_t; /* Values for sess->flags */ #define AIM_SESS_FLAGS_SNACLOGIN 0x00000001 @@ -394,19 +416,19 @@ struct aim_session_t { * AIM User Info, Standard Form. */ struct aim_userinfo_s { - char sn[MAXSNLEN+1]; - u_short warnlevel; - u_short idletime; - u_short flags; - u_long membersince; - u_long onlinesince; - u_long sessionlen; - u_short capabilities; - struct { - unsigned short status; - unsigned int ipaddr; - char crap[0x25]; /* until we figure it out... */ - } icqinfo; + char sn[MAXSNLEN+1]; + fu16_t warnlevel; + fu16_t idletime; + fu16_t flags; + fu32_t membersince; + fu32_t onlinesince; + fu32_t sessionlen; + fu16_t capabilities; + struct { + fu16_t status; + fu32_t ipaddr; + fu8_t crap[0x25]; /* until we figure it out... */ + } icqinfo; }; #define AIM_FLAG_UNCONFIRMED 0x0001 /* "damned transients" */ @@ -427,112 +449,114 @@ struct aim_userinfo_s { */ /* Generic TLV structure. */ -struct aim_tlv_t { - u_short type; - u_short length; - u_char *value; -}; +typedef struct aim_tlv_s { + fu16_t type; + fu16_t length; + fu8_t *value; +} aim_tlv_t; /* List of above. */ -struct aim_tlvlist_t { - struct aim_tlv_t *tlv; - struct aim_tlvlist_t *next; -}; +typedef struct aim_tlvlist_s { + aim_tlv_t *tlv; + struct aim_tlvlist_s *next; +} aim_tlvlist_t; /* TLV-handling functions */ -faim_internal struct aim_tlvlist_t *aim_readtlvchain(const unsigned char *buf, const int maxlen); -faim_internal void aim_freetlvchain(struct aim_tlvlist_t **list); -faim_internal struct aim_tlv_t *aim_grabtlv(const unsigned char *src); -faim_internal struct aim_tlv_t *aim_grabtlvstr(const unsigned char *src); -faim_internal struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *, const unsigned short, const int); -faim_internal char *aim_gettlv_str(struct aim_tlvlist_t *, const unsigned short, const int); -faim_internal unsigned char aim_gettlv8(struct aim_tlvlist_t *list, const unsigned short type, const int num); -faim_internal unsigned short aim_gettlv16(struct aim_tlvlist_t *list, const unsigned short type, const int num); -faim_internal unsigned long aim_gettlv32(struct aim_tlvlist_t *list, const unsigned short type, const int num); -faim_internal int aim_puttlv (unsigned char *dest, struct aim_tlv_t *newtlv); -faim_internal struct aim_tlv_t *aim_createtlv(void); -faim_internal int aim_freetlv(struct aim_tlv_t **oldtlv); -faim_internal int aim_puttlv_8(unsigned char *buf, const unsigned short t, const unsigned char v); -faim_internal int aim_puttlv_16(unsigned char *, const unsigned short, const unsigned short); -faim_internal int aim_puttlv_32(unsigned char *, const unsigned short, const unsigned long); -faim_internal int aim_puttlv_str(u_char *buf, const unsigned short t, const int l, const char *v); -faim_internal int aim_writetlvchain(unsigned char *buf, const int buflen, struct aim_tlvlist_t **list); -faim_internal int aim_addtlvtochain16(struct aim_tlvlist_t **list, const unsigned short type, const unsigned short val); -faim_internal int aim_addtlvtochain32(struct aim_tlvlist_t **list, const unsigned short type, const unsigned long val); -faim_internal int aim_addtlvtochain_str(struct aim_tlvlist_t **list, const unsigned short type, const char *str, const int len); -faim_internal int aim_addtlvtochain_caps(struct aim_tlvlist_t **list, const unsigned short type, const unsigned short caps); -faim_internal int aim_addtlvtochain_noval(struct aim_tlvlist_t **list, const unsigned short type); -faim_internal int aim_counttlvchain(struct aim_tlvlist_t **list); + +#if 0 +/* Very, very raw TLV handling. */ +faim_internal int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v); +faim_internal int aim_puttlv_16(fu8_t *buf, const fu16_t t, const fu16_t v); +faim_internal int aim_puttlv_32(fu8_t *buf, const fu16_t t, const fu32_t v); +faim_internal int aim_puttlv_raw(fu8_t *buf, const fu16_t t, const fu16_t l, const fu8_t *v); +#endif + +/* TLV list handling. */ +faim_internal aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs); +faim_internal void aim_freetlvchain(aim_tlvlist_t **list); +faim_internal aim_tlv_t *aim_gettlv(aim_tlvlist_t *, fu16_t t, const int n); +faim_internal char *aim_gettlv_str(aim_tlvlist_t *, const fu16_t t, const int n); +faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t type, const int num); +faim_internal fu16_t aim_gettlv16(aim_tlvlist_t *list, const fu16_t t, const int n); +faim_internal fu32_t aim_gettlv32(aim_tlvlist_t *list, const fu16_t t, const int n); +faim_internal int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list); +faim_internal int aim_addtlvtochain16(aim_tlvlist_t **list, const fu16_t t, const fu16_t v); +faim_internal int aim_addtlvtochain32(aim_tlvlist_t **list, const fu16_t type, const fu32_t v); +faim_internal int aim_addtlvtochain_raw(aim_tlvlist_t **list, const fu16_t t, const fu16_t l, const fu8_t *v); +faim_internal int aim_addtlvtochain_caps(aim_tlvlist_t **list, const fu16_t t, const fu16_t caps); +faim_internal int aim_addtlvtochain_noval(aim_tlvlist_t **list, const fu16_t type); +faim_internal int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl); +faim_internal int aim_counttlvchain(aim_tlvlist_t **list); +faim_export int aim_sizetlvchain(aim_tlvlist_t **list); #endif /* FAIM_INTERNAL */ /* - * Get command from connections / Dispatch commands - * already in queue. + * Get command from connections + * + * aim_get_commmand() is the libfaim lowlevel I/O in the receive direction. + * XXX Make this easily overridable. + * + */ +faim_export int aim_get_command(aim_session_t *, aim_conn_t *); + +/* + * Dispatch commands that are in the rx queue. */ -faim_export int aim_get_command(struct aim_session_t *, struct aim_conn_t *); -int aim_rxdispatch(struct aim_session_t *); +faim_export void aim_rxdispatch(aim_session_t *); -faim_export unsigned long aim_debugconn_sendconnect(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_export int aim_debugconn_sendconnect(aim_session_t *sess, aim_conn_t *conn); -faim_export int aim_logoff(struct aim_session_t *); +faim_export int aim_logoff(aim_session_t *); #if !defined(FAIM_INTERNAL) || defined(FAIM_INTERNAL_INSANE) /* the library should never call aim_conn_kill */ -faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn); +faim_export void aim_conn_kill(aim_session_t *sess, aim_conn_t **deadconn); #endif -typedef int (*aim_rxcallback_t)(struct aim_session_t *, struct command_rx_struct *, ...); +typedef int (*aim_rxcallback_t)(aim_session_t *, aim_frame_t *, ...); /* aim_login.c */ -faim_export int aim_sendflapver(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export int aim_request_login (struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn); -faim_export int aim_send_login (struct aim_session_t *, struct aim_conn_t *, char *, char *, struct client_info_s *, char *key); +faim_export int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn); +faim_export int aim_send_login(aim_session_t *, aim_conn_t *, const char *, const char *, struct client_info_s *, const char *key); faim_export int aim_encode_password_md5(const char *password, const char *key, unsigned char *digest); -faim_export unsigned long aim_sendauthresp(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, int errorcode, char *errorurl, char *bosip, char *cookie, char *email, int regstatus); +faim_export int aim_sendauthresp(aim_session_t *sess, aim_conn_t *conn, const char *sn, int errorcode, const char *errorurl, const char *bosip, const char *cookie, const char *email, int regstatus); faim_export int aim_gencookie(unsigned char *buf); -faim_export int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_sendredirect(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short servid, char *ip, char *cookie); -faim_export void aim_purge_rxqueue(struct aim_session_t *); +faim_export int aim_sendserverready(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_sendredirect(aim_session_t *sess, aim_conn_t *conn, fu16_t servid, const char *ip, const char *cookie); +faim_export void aim_purge_rxqueue(aim_session_t *); #define AIM_TX_QUEUED 0 /* default */ #define AIM_TX_IMMEDIATE 1 #define AIM_TX_USER 2 -faim_export int aim_tx_setenqueue(struct aim_session_t *sess, int what, int (*func)(struct aim_session_t *, struct command_tx_struct *)); - -faim_export int aim_tx_flushqueue(struct aim_session_t *); -faim_export void aim_tx_purgequeue(struct aim_session_t *); - -struct aim_rxcblist_t { - u_short family; - u_short type; - aim_rxcallback_t handler; - u_short flags; - struct aim_rxcblist_t *next; -}; - -faim_export int aim_conn_setlatency(struct aim_conn_t *conn, int newval); - -faim_export int aim_conn_addhandler(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short type, aim_rxcallback_t newhandler, u_short flags); -faim_export int aim_clearhandlers(struct aim_conn_t *conn); - -faim_export struct aim_session_t *aim_conn_getsess(struct aim_conn_t *conn); -faim_export void aim_conn_close(struct aim_conn_t *deadconn); -faim_export struct aim_conn_t *aim_newconn(struct aim_session_t *, int type, char *dest); -faim_export int aim_conngetmaxfd(struct aim_session_t *); -faim_export struct aim_conn_t *aim_select(struct aim_session_t *, struct timeval *, int *); -faim_export int aim_conn_isready(struct aim_conn_t *); -faim_export int aim_conn_setstatus(struct aim_conn_t *, int); -faim_export int aim_conn_completeconnect(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export int aim_conn_isconnecting(struct aim_conn_t *conn); - -typedef void (*faim_debugging_callback_t)(struct aim_session_t *sess, int level, const char *format, va_list va); -faim_export int aim_setdebuggingcb(struct aim_session_t *sess, faim_debugging_callback_t); -faim_export void aim_session_init(struct aim_session_t *, unsigned long flags, int debuglevel); -faim_export void aim_session_kill(struct aim_session_t *); -faim_export void aim_setupproxy(struct aim_session_t *sess, char *server, char *username, char *password); -faim_export struct aim_conn_t *aim_getconn_type(struct aim_session_t *, int type); -faim_export struct aim_conn_t *aim_getconn_type_all(struct aim_session_t *, int type); -faim_export struct aim_conn_t *aim_getconn_fd(struct aim_session_t *, int fd); +faim_export int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *)); + +faim_export int aim_tx_flushqueue(aim_session_t *); +faim_export void aim_tx_purgequeue(aim_session_t *); + +faim_export int aim_conn_setlatency(aim_conn_t *conn, int newval); + +faim_export int aim_conn_addhandler(aim_session_t *, aim_conn_t *conn, u_short family, u_short type, aim_rxcallback_t newhandler, u_short flags); +faim_export int aim_clearhandlers(aim_conn_t *conn); + +faim_export aim_session_t *aim_conn_getsess(aim_conn_t *conn); +faim_export void aim_conn_close(aim_conn_t *deadconn); +faim_export aim_conn_t *aim_newconn(aim_session_t *, int type, const char *dest); +faim_export int aim_conngetmaxfd(aim_session_t *); +faim_export aim_conn_t *aim_select(aim_session_t *, struct timeval *, int *); +faim_export int aim_conn_isready(aim_conn_t *); +faim_export int aim_conn_setstatus(aim_conn_t *, int); +faim_export int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_conn_isconnecting(aim_conn_t *conn); + +typedef void (*faim_debugging_callback_t)(aim_session_t *sess, int level, const char *format, va_list va); +faim_export int aim_setdebuggingcb(aim_session_t *sess, faim_debugging_callback_t); +faim_export void aim_session_init(aim_session_t *, unsigned long flags, int debuglevel); +faim_export void aim_session_kill(aim_session_t *); +faim_export void aim_setupproxy(aim_session_t *sess, const char *server, const char *username, const char *password); +faim_export aim_conn_t *aim_getconn_type(aim_session_t *, int type); +faim_export aim_conn_t *aim_getconn_type_all(aim_session_t *, int type); +faim_export aim_conn_t *aim_getconn_fd(aim_session_t *, int fd); /* aim_misc.c */ @@ -546,36 +570,29 @@ faim_export struct aim_conn_t *aim_getconn_fd(struct aim_session_t *, int fd); #define AIM_WARN_ANON 0x01 -faim_export int aim_send_warning(struct aim_session_t *sess, struct aim_conn_t *conn, const char *destsn, unsigned long flags); -faim_export unsigned long aim_bos_nop(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_flap_nop(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_bos_setidle(struct aim_session_t *, struct aim_conn_t *, u_long); -faim_export unsigned long aim_bos_changevisibility(struct aim_session_t *, struct aim_conn_t *, int, char *); -faim_export unsigned long aim_bos_setbuddylist(struct aim_session_t *, struct aim_conn_t *, char *); -faim_export unsigned long aim_bos_setprofile(struct aim_session_t *sess, struct aim_conn_t *conn, const char *profile, const char *awaymsg, unsigned short caps); -faim_export unsigned long aim_bos_setgroupperm(struct aim_session_t *, struct aim_conn_t *, u_long); -faim_export unsigned long aim_bos_clientready(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_reqrate(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_ackrateresp(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_setprivacyflags(struct aim_session_t *, struct aim_conn_t *, u_long); -faim_export unsigned long aim_bos_reqpersonalinfo(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_reqservice(struct aim_session_t *, struct aim_conn_t *, u_short); -faim_export unsigned long aim_bos_reqrights(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_reqbuddyrights(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_bos_reqlocaterights(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_setversions(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_auth_setversions(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_auth_reqconfirm(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_auth_getinfo(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short info); -faim_export unsigned long aim_auth_setemail(struct aim_session_t *sess, struct aim_conn_t *conn, char *newemail); -faim_export unsigned long aim_setdirectoryinfo(struct aim_session_t *sess, struct aim_conn_t *conn, char *first, char *middle, char *last, char *maiden, char *nickname, char *street, char *city, char *state, char *zip, int country, unsigned short privacy); -faim_export unsigned long aim_setuserinterests(struct aim_session_t *sess, struct aim_conn_t *conn, char *interest1, char *interest2, char *interest3, char *interest4, char *interest5, unsigned short privacy); -faim_export unsigned long aim_icq_setstatus(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long status); - -faim_export struct aim_fileheader_t *aim_getlisting(struct aim_session_t *sess, FILE *); - -/* aim_rxhandlers.c */ -faim_export int aim_rxdispatch(struct aim_session_t *); +faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags); +faim_export int aim_bos_nop(aim_session_t *, aim_conn_t *); +faim_export int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_bos_setidle(aim_session_t *, aim_conn_t *, fu32_t); +faim_export int aim_bos_changevisibility(aim_session_t *, aim_conn_t *, int, const char *); +faim_export int aim_bos_setbuddylist(aim_session_t *, aim_conn_t *, const char *); +faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu16_t caps); +faim_export int aim_bos_setgroupperm(aim_session_t *, aim_conn_t *, fu32_t mask); +faim_export int aim_bos_clientready(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_reqrate(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_ackrateresp(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_setprivacyflags(aim_session_t *, aim_conn_t *, fu32_t); +faim_export int aim_bos_reqpersonalinfo(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_reqservice(aim_session_t *, aim_conn_t *, fu16_t); +faim_export int aim_bos_reqrights(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_reqbuddyrights(aim_session_t *, aim_conn_t *); +faim_export int aim_bos_reqlocaterights(aim_session_t *, aim_conn_t *); +faim_export int aim_setversions(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_setdirectoryinfo(aim_session_t *sess, aim_conn_t *conn, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, fu16_t privacy); +faim_export int aim_setuserinterests(aim_session_t *sess, aim_conn_t *conn, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, fu16_t privacy); +faim_export int aim_icq_setstatus(aim_session_t *sess, aim_conn_t *conn, fu32_t status); + +faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *); #define AIM_CLIENTTYPE_UNKNOWN 0x0000 #define AIM_CLIENTTYPE_MC 0x0001 @@ -588,49 +605,49 @@ faim_export unsigned short aim_fingerprintclient(unsigned char *msghdr, int len) #define AIM_RATE_CODE_WARNING 0x0002 #define AIM_RATE_CODE_LIMIT 0x0003 #define AIM_RATE_CODE_CLEARLIMIT 0x0004 -faim_export unsigned long aim_ads_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_ads_requestads(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_export int aim_ads_clientready(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_ads_requestads(aim_session_t *sess, aim_conn_t *conn); /* aim_im.c */ struct aim_directim_priv { - unsigned char cookie[8]; - char sn[MAXSNLEN+1]; - char ip[30]; + fu8_t cookie[8]; + char sn[MAXSNLEN+1]; + fu8_t ip[30]; }; struct aim_fileheader_t { #if 0 - char magic[4]; /* 0 */ - short hdrlen; /* 4 */ - short hdrtype; /* 6 */ + char magic[4]; /* 0 */ + short hdrlen; /* 4 */ + short hdrtype; /* 6 */ #endif - char bcookie[8]; /* 8 */ - short encrypt; /* 16 */ - short compress; /* 18 */ - short totfiles; /* 20 */ - short filesleft; /* 22 */ - short totparts; /* 24 */ - short partsleft; /* 26 */ - long totsize; /* 28 */ - long size; /* 32 */ - long modtime; /* 36 */ - long checksum; /* 40 */ - long rfrcsum; /* 44 */ - long rfsize; /* 48 */ - long cretime; /* 52 */ - long rfcsum; /* 56 */ - long nrecvd; /* 60 */ - long recvcsum; /* 64 */ - char idstring[32]; /* 68 */ - char flags; /* 100 */ - char lnameoffset; /* 101 */ - char lsizeoffset; /* 102 */ - char dummy[69]; /* 103 */ - char macfileinfo[16]; /* 172 */ - short nencode; /* 188 */ - short nlanguage; /* 190 */ - char name[64]; /* 192 */ - /* 256 */ + char bcookie[8]; /* 8 */ + short encrypt; /* 16 */ + short compress; /* 18 */ + short totfiles; /* 20 */ + short filesleft; /* 22 */ + short totparts; /* 24 */ + short partsleft; /* 26 */ + long totsize; /* 28 */ + long size; /* 32 */ + long modtime; /* 36 */ + long checksum; /* 40 */ + long rfrcsum; /* 44 */ + long rfsize; /* 48 */ + long cretime; /* 52 */ + long rfcsum; /* 56 */ + long nrecvd; /* 60 */ + long recvcsum; /* 64 */ + char idstring[32]; /* 68 */ + char flags; /* 100 */ + char lnameoffset; /* 101 */ + char lsizeoffset; /* 102 */ + char dummy[69]; /* 103 */ + char macfileinfo[16]; /* 172 */ + short nencode; /* 188 */ + short nlanguage; /* 190 */ + char name[64]; /* 192 */ + /* 256 */ }; struct aim_filetransfer_priv { @@ -708,18 +725,18 @@ struct aim_incomingim_ch2_args { } info; }; -faim_export int aim_send_im_ext(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_sendimext_args *args); -faim_export int aim_send_im(struct aim_session_t *, struct aim_conn_t *, const char *destsn, unsigned short flags, const char *msg); -faim_export int aim_send_icon(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn, const unsigned char *icon, int iconlen, time_t stamp, unsigned short iconsum); +faim_export int aim_send_im_ext(aim_session_t *sess, aim_conn_t *conn, struct aim_sendimext_args *args); +faim_export int aim_send_im(aim_session_t *, aim_conn_t *, const char *destsn, unsigned short flags, const char *msg); +faim_export int aim_send_icon(aim_session_t *sess, aim_conn_t *conn, const char *sn, const unsigned char *icon, int iconlen, time_t stamp, unsigned short iconsum); faim_export unsigned short aim_iconsum(const unsigned char *buf, int buflen); -faim_export int aim_send_im_direct(struct aim_session_t *, struct aim_conn_t *, char *); -faim_export struct aim_conn_t * aim_directim_initiate(struct aim_session_t *, struct aim_conn_t *, struct aim_directim_priv *, char *destsn); -faim_export struct aim_conn_t *aim_directim_connect(struct aim_session_t *, struct aim_conn_t *, struct aim_directim_priv *); +faim_export int aim_send_im_direct(aim_session_t *, aim_conn_t *, const char *msg); +faim_export aim_conn_t *aim_directim_initiate(aim_session_t *, aim_conn_t *, struct aim_directim_priv *, const char *destsn); +faim_export aim_conn_t *aim_directim_connect(aim_session_t *, aim_conn_t *, struct aim_directim_priv *); -faim_export struct aim_conn_t *aim_getfile_initiate(struct aim_session_t *sess, struct aim_conn_t *conn, char *destsn); -faim_export int aim_oft_getfile_request(struct aim_session_t *sess, struct aim_conn_t *conn, const unsigned char *name, const int size); -faim_export int aim_oft_getfile_ack(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export int aim_oft_getfile_end(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn); +faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size); +faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_oft_getfile_end(aim_session_t *sess, aim_conn_t *conn); /* aim_info.c */ #define AIM_CAPS_BUDDYICON 0x0001 @@ -734,29 +751,21 @@ faim_export int aim_oft_getfile_end(struct aim_session_t *sess, struct aim_conn_ #define AIM_CAPS_GAMES2 0x0200 #define AIM_CAPS_LAST 0x8000 -faim_export int aim_0002_000b(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn); +faim_export int aim_0002_000b(aim_session_t *sess, aim_conn_t *conn, const char *sn); #define AIM_SENDMEMBLOCK_FLAG_ISREQUEST 0 #define AIM_SENDMEMBLOCK_FLAG_ISHASH 1 -faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag); +faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag); #define AIM_GETINFO_GENERALINFO 0x00001 #define AIM_GETINFO_AWAYMESSAGE 0x00003 -struct aim_msgcookie_t { - unsigned char cookie[8]; - int type; - void *data; - time_t addtime; - struct aim_msgcookie_t *next; -}; - struct aim_invite_priv { - char *sn; - char *roomname; - int exchange; - int instance; + char *sn; + char *roomname; + fu16_t exchange; + fu16_t instance; }; #define AIM_COOKIETYPE_UNKNOWN 0x00 @@ -776,17 +785,17 @@ struct aim_invite_priv { #define AIM_COOKIETYPE_OFTIMAGE 0x14 #define AIM_COOKIETYPE_OFTICON 0x15 -faim_export int aim_handlerendconnect(struct aim_session_t *sess, struct aim_conn_t *cur); +faim_export int aim_handlerendconnect(aim_session_t *sess, aim_conn_t *cur); #define AIM_TRANSFER_DENY_NOTSUPPORTED 0x0000 #define AIM_TRANSFER_DENY_DECLINE 0x0001 #define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002 -faim_export int aim_denytransfer(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sender, const char *cookie, unsigned short code); -faim_export struct aim_conn_t *aim_accepttransfer(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, char *cookie, char *ip, unsigned short listingfiles, unsigned short listingtotsize, unsigned short listingsize, unsigned int listingchecksum, unsigned short rendid); +faim_export int aim_denytransfer(aim_session_t *sess, aim_conn_t *conn, const char *sender, const char *cookie, unsigned short code); +faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *cookie, const fu8_t *ip, fu16_t listingfiles, fu16_t listingtotsize, fu16_t listingsize, fu32_t listingchecksum, fu16_t rendid); -faim_export int aim_getinfo(struct aim_session_t *, struct aim_conn_t *, const char *, unsigned short); -faim_export int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info); -faim_export int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn); +faim_export int aim_getinfo(aim_session_t *, aim_conn_t *, const char *, unsigned short); +faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *info); +faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn); #define AIM_IMPARAM_FLAG_CHANMSGS_ALLOWED 0x00000001 #define AIM_IMPARAM_FLAG_MISSEDCALLS_ENABLED 0x00000002 @@ -819,79 +828,78 @@ struct aim_icbmparameters { unsigned long minmsginterval; /* in milliseconds? */ }; -faim_export unsigned long aim_reqicbmparams(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_seticbmparam(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_icbmparameters *params); +faim_export int aim_reqicbmparams(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_seticbmparam(aim_session_t *sess, aim_conn_t *conn, struct aim_icbmparameters *params); -/* aim_auth.c */ -faim_export int aim_auth_sendcookie(struct aim_session_t *, struct aim_conn_t *, u_char *); -faim_export u_long aim_auth_clientready(struct aim_session_t *, struct aim_conn_t *); -faim_export unsigned long aim_auth_changepasswd(struct aim_session_t *, struct aim_conn_t *, char *, char *); +/* auth.c */ +faim_export int aim_auth_sendcookie(aim_session_t *, aim_conn_t *, const fu8_t *); + +faim_export int aim_auth_clientready(aim_session_t *, aim_conn_t *); +faim_export int aim_auth_changepasswd(aim_session_t *, aim_conn_t *, const char *newpw, const char *curpw); +faim_export int aim_auth_setversions(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_auth_reqconfirm(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_auth_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info); +faim_export int aim_auth_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail); /* aim_buddylist.c */ -faim_export unsigned long aim_add_buddy(struct aim_session_t *, struct aim_conn_t *, char *); -faim_export unsigned long aim_remove_buddy(struct aim_session_t *, struct aim_conn_t *, char *); +faim_export int aim_add_buddy(aim_session_t *, aim_conn_t *, const char *); +faim_export int aim_remove_buddy(aim_session_t *, aim_conn_t *, const char *); /* aim_search.c */ -faim_export u_long aim_usersearch_address(struct aim_session_t *, struct aim_conn_t *, char *); +faim_export int aim_usersearch_address(aim_session_t *, aim_conn_t *, const char *); struct aim_chat_exchangeinfo { - u_short number; - char *name; - char *charset1; - char *lang1; - char *charset2; - char *lang2; + fu16_t number; + char *name; + char *charset1; + char *lang1; + char *charset2; + char *lang2; }; #define AIM_CHATFLAGS_NOREFLECT 0x0001 #define AIM_CHATFLAGS_AWAY 0x0002 -faim_export unsigned long aim_chat_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short flags, const char *msg, int msglen); -faim_export unsigned long aim_chat_join(struct aim_session_t *sess, struct aim_conn_t *conn, u_short exchange, const char *roomname); -faim_export unsigned long aim_chat_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export int aim_chat_attachname(struct aim_conn_t *conn, char *roomname); -faim_export char *aim_chat_getname(struct aim_conn_t *conn); -faim_export struct aim_conn_t *aim_chat_getconn(struct aim_session_t *, char *name); +faim_export int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, fu16_t flags, const char *msg, int msglen); +faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance); +faim_export int aim_chat_clientready(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_chat_attachname(aim_conn_t *conn, const char *roomname); +faim_export char *aim_chat_getname(aim_conn_t *conn); +faim_export aim_conn_t *aim_chat_getconn(aim_session_t *, const char *name); -faim_export unsigned long aim_chatnav_reqrights(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_export unsigned long aim_chatnav_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn); +faim_export int aim_chatnav_clientready(aim_session_t *sess, aim_conn_t *conn); -faim_export unsigned long aim_chat_invite(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, char *msg, u_short exchange, char *roomname, u_short instance); +faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance); -faim_export u_long aim_chatnav_createroom(struct aim_session_t *sess, struct aim_conn_t *conn, char *name, u_short exchange); -faim_export int aim_chat_leaveroom(struct aim_session_t *sess, char *name); +faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange); +faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name); /* aim_util.c */ -#ifdef AIMUTIL_USEMACROS /* * These are really ugly. You'd think this was LISP. I wish it was. + * + * XXX With the advent of bstream's, these should be removed to enforce + * their use. + * */ #define aimutil_put8(buf, data) ((*(buf) = (u_char)(data)&0xff),1) #define aimutil_get8(buf) ((*(buf))&0xff) #define aimutil_put16(buf, data) ( \ - (*(buf) = (u_char)((data)>>8)&0xff), \ - (*((buf)+1) = (u_char)(data)&0xff), \ - 2) + (*(buf) = (u_char)((data)>>8)&0xff), \ + (*((buf)+1) = (u_char)(data)&0xff), \ + 2) #define aimutil_get16(buf) ((((*(buf))<<8)&0xff00) + ((*((buf)+1)) & 0xff)) #define aimutil_put32(buf, data) ( \ - (*((buf)) = (u_char)((data)>>24)&0xff), \ - (*((buf)+1) = (u_char)((data)>>16)&0xff), \ - (*((buf)+2) = (u_char)((data)>>8)&0xff), \ - (*((buf)+3) = (u_char)(data)&0xff), \ - 4) + (*((buf)) = (u_char)((data)>>24)&0xff), \ + (*((buf)+1) = (u_char)((data)>>16)&0xff), \ + (*((buf)+2) = (u_char)((data)>>8)&0xff), \ + (*((buf)+3) = (u_char)(data)&0xff), \ + 4) #define aimutil_get32(buf) ((((*(buf))<<24)&0xff000000) + \ - (((*((buf)+1))<<16)&0x00ff0000) + \ - (((*((buf)+2))<< 8)&0x0000ff00) + \ - (((*((buf)+3) )&0x000000ff))) -#else -#warning Not using aimutil macros. May have performance problems. -int aimutil_put8(u_char *, u_char); -u_char aimutil_get8(u_char *buf); -int aimutil_put16(u_char *, u_short); -u_short aimutil_get16(u_char *); -int aimutil_put32(u_char *, u_long); -u_long aimutil_get32(u_char *); -#endif + (((*((buf)+1))<<16)&0x00ff0000) + \ + (((*((buf)+2))<< 8)&0x0000ff00) + \ + (((*((buf)+3) )&0x000000ff))) faim_export int aimutil_putstr(u_char *, const char *, int); faim_export int aimutil_tokslen(char *toSearch, int index, char dl); diff --git a/include/aim_internal.h b/include/aim_internal.h index fff1e52..1c79bd5 100644 --- a/include/aim_internal.h +++ b/include/aim_internal.h @@ -8,88 +8,110 @@ #define __AIM_INTERNAL_H__ 1 typedef struct { - unsigned short family; - unsigned short subtype; - unsigned short flags; - unsigned long id; + fu16_t family; + fu16_t subtype; + fu16_t flags; + fu32_t id; } aim_modsnac_t; #define AIM_MODULENAME_MAXLEN 16 #define AIM_MODFLAG_MULTIFAMILY 0x0001 typedef struct aim_module_s { - unsigned short family; - unsigned short flags; - unsigned short version; - char name[AIM_MODULENAME_MAXLEN+1]; - int (*snachandler)(struct aim_session_t *sess, struct aim_module_s *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen); - void (*shutdown)(struct aim_session_t *sess, struct aim_module_s *mod); - void *priv; - struct aim_module_s *next; + unsigned short family; + unsigned short flags; + unsigned short version; + char name[AIM_MODULENAME_MAXLEN+1]; + int (*snachandler)(aim_session_t *sess, struct aim_module_s *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs); + void (*shutdown)(aim_session_t *sess, struct aim_module_s *mod); + void *priv; + struct aim_module_s *next; } aim_module_t; -faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst)(struct aim_session_t *, aim_module_t *)); -faim_internal void aim__shutdownmodules(struct aim_session_t *sess); - - -faim_internal int buddylist_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int admin_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int bos_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int search_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int stats_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int auth_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int msg_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int misc_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int chatnav_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int chat_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int locate_modfirst(struct aim_session_t *sess, aim_module_t *mod); -faim_internal int general_modfirst(struct aim_session_t *sess, aim_module_t *mod); - -faim_internal unsigned long aim_genericreq_n(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype); -faim_internal unsigned long aim_genericreq_n_snacid(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype); -faim_internal unsigned long aim_genericreq_l(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype, u_long *); -faim_internal unsigned long aim_genericreq_s(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype, u_short *); - -faim_internal void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn); -faim_internal int aim_recv(int fd, void *buf, size_t count); +faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *)); +faim_internal void aim__shutdownmodules(aim_session_t *sess); + -faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn); +faim_internal int buddylist_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int bos_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int search_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int stats_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int auth_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int misc_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int chatnav_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int chat_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int locate_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod); -faim_internal int aim_tx_sendframe(struct aim_session_t *sess, struct command_tx_struct *cur); -faim_internal unsigned int aim_get_next_txseqnum(struct aim_conn_t *); -faim_internal struct command_tx_struct *aim_tx_new(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned char framing, int chan, int datalen); -faim_internal int aim_tx_enqueue(struct aim_session_t *, struct command_tx_struct *); -faim_internal int aim_tx_printqueue(struct aim_session_t *); -faim_internal int aim_tx_cleanqueue(struct aim_session_t *, struct aim_conn_t *); +faim_internal int aim_genericreq_n(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype); +faim_internal int aim_genericreq_n_snacid(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype); +faim_internal int aim_genericreq_l(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype, fu32_t *); +faim_internal int aim_genericreq_s(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype, fu16_t *); -faim_internal aim_rxcallback_t aim_callhandler(struct aim_session_t *sess, struct aim_conn_t *conn, u_short family, u_short type); -faim_internal int aim_callhandler_noparam(struct aim_session_t *sess, struct aim_conn_t *conn, u_short family, u_short type, struct command_rx_struct *ptr); +#define AIMBS_CURPOSPAIR(x) ((x)->data + (x)->offset), ((x)->len - (x)->offset) + +faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn); +faim_internal int aim_recv(int fd, void *buf, size_t count); +faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count); +faim_internal int aim_bstream_init(aim_bstream_t *bs, fu8_t *data, int len); +faim_internal int aim_bstream_empty(aim_bstream_t *bs); +faim_internal int aim_bstream_curpos(aim_bstream_t *bs); +faim_internal int aim_bstream_setpos(aim_bstream_t *bs, int off); +faim_internal void aim_bstream_rewind(aim_bstream_t *bs); +faim_internal int aim_bstream_advance(aim_bstream_t *bs, int n); +faim_internal fu8_t aimbs_get8(aim_bstream_t *bs); +faim_internal fu16_t aimbs_get16(aim_bstream_t *bs); +faim_internal fu32_t aimbs_get32(aim_bstream_t *bs); +faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v); +faim_internal int aimbs_put16(aim_bstream_t *bs, fu16_t v); +faim_internal int aimbs_put32(aim_bstream_t *bs, fu32_t v); +faim_internal int aimbs_getrawbuf(aim_bstream_t *bs, fu8_t *buf, int len); +faim_internal fu8_t *aimbs_getraw(aim_bstream_t *bs, int len); +faim_internal char *aimbs_getstr(aim_bstream_t *bs, int len); +faim_internal int aimbs_putraw(aim_bstream_t *bs, const fu8_t *v, int len); +faim_internal int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len); + +faim_internal int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn); + +faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *cur); +faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *); +faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen); +faim_internal void aim_frame_destroy(aim_frame_t *); +faim_internal int aim_tx_enqueue(aim_session_t *, aim_frame_t *); +faim_internal int aim_tx_printqueue(aim_session_t *); +faim_internal void aim_tx_cleanqueue(aim_session_t *, aim_conn_t *); + +faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, u_short family, u_short type); +faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_frame_t *ptr); /* * Generic SNAC structure. Rarely if ever used. */ -struct aim_snac_t { - u_long id; - u_short family; - u_short type; - u_short flags; - void *data; - time_t issuetime; - struct aim_snac_t *next; -}; -faim_internal void aim_initsnachash(struct aim_session_t *sess); -faim_internal unsigned long aim_newsnac(struct aim_session_t *, struct aim_snac_t *newsnac); -faim_internal unsigned long aim_cachesnac(struct aim_session_t *sess, const unsigned short family, const unsigned short type, const unsigned short flags, const void *data, const int datalen); -faim_internal struct aim_snac_t *aim_remsnac(struct aim_session_t *, u_long id); -faim_internal int aim_cleansnacs(struct aim_session_t *, int maxage); -faim_internal int aim_putsnac(u_char *, int, int, int, u_long); - -faim_internal struct aim_conn_t *aim_cloneconn(struct aim_session_t *sess, struct aim_conn_t *src); +typedef struct aim_snac_s { + aim_snacid_t id; + fu16_t family; + fu16_t type; + fu16_t flags; + void *data; + time_t issuetime; + struct aim_snac_s *next; +} aim_snac_t; + +faim_internal void aim_initsnachash(aim_session_t *sess); +faim_internal aim_snacid_t aim_newsnac(aim_session_t *, aim_snac_t *newsnac); +faim_internal aim_snacid_t aim_cachesnac(aim_session_t *sess, const fu16_t family, const fu16_t type, const fu16_t flags, const void *data, const int datalen); +faim_internal aim_snac_t *aim_remsnac(aim_session_t *, aim_snacid_t id); +faim_internal void aim_cleansnacs(aim_session_t *, int maxage); +faim_internal int aim_putsnac(aim_bstream_t *, fu16_t family, fu16_t type, fu16_t flags, aim_snacid_t id); + +faim_internal aim_conn_t *aim_cloneconn(aim_session_t *sess, aim_conn_t *src); +faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src); faim_internal int aim_oft_buildheader(unsigned char *,struct aim_fileheader_t *); faim_internal int aim_listenestablish(u_short); -faim_internal int aim_tx_destroy(struct command_tx_struct *); -faim_internal int aim_parse_unknown(struct aim_session_t *, struct command_rx_struct *, ...); +faim_internal int aim_parse_unknown(aim_session_t *, aim_frame_t *, ...); /* these are used by aim_*_clientready */ #define AIM_TOOL_JAVA 0x0001 @@ -100,35 +122,31 @@ faim_internal int aim_parse_unknown(struct aim_session_t *, struct command_rx_st #define AIM_TOOL_MACPPC 0x0006 #define AIM_TOOL_NEWWIN 0x0010 struct aim_tool_version { - unsigned short group; - unsigned short version; - unsigned short tool; - unsigned short toolversion; + fu16_t group; + fu16_t version; + fu16_t tool; + fu16_t toolversion; }; -faim_internal int aim_negchan_middle(struct aim_session_t *sess, struct command_rx_struct *command); - -faim_internal unsigned short aim_getcap(struct aim_session_t *sess, unsigned char *capblock, int buflen); -faim_internal int aim_putcap(unsigned char *capblock, int buflen, unsigned short caps); +faim_internal fu16_t aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len); +faim_internal int aim_putcap(aim_bstream_t *bs, fu16_t caps); -faim_internal int aim_cachecookie(struct aim_session_t *sess, struct aim_msgcookie_t *cookie); -faim_internal struct aim_msgcookie_t *aim_uncachecookie(struct aim_session_t *sess, unsigned char *cookie, int type); -faim_internal struct aim_msgcookie_t *aim_mkcookie(unsigned char *, int, void *); -faim_internal struct aim_msgcookie_t *aim_checkcookie(struct aim_session_t *, const unsigned char *, const int); -faim_internal int aim_freecookie(struct aim_session_t *sess, struct aim_msgcookie_t *cookie); +faim_internal int aim_cachecookie(aim_session_t *sess, aim_msgcookie_t *cookie); +faim_internal aim_msgcookie_t *aim_uncachecookie(aim_session_t *sess, fu8_t *cookie, int type); +faim_internal aim_msgcookie_t *aim_mkcookie(fu8_t *, int, void *); +faim_internal aim_msgcookie_t *aim_checkcookie(aim_session_t *, const unsigned char *, const int); +faim_internal int aim_freecookie(aim_session_t *sess, aim_msgcookie_t *cookie); faim_internal int aim_msgcookie_gettype(int reqclass); -faim_internal int aim_cookie_free(struct aim_session_t *sess, struct aim_msgcookie_t *cookie); +faim_internal int aim_cookie_free(aim_session_t *sess, aim_msgcookie_t *cookie); -faim_internal int aim_extractuserinfo(struct aim_session_t *sess, unsigned char *, struct aim_userinfo_s *); -faim_internal int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info); +faim_internal int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, struct aim_userinfo_s *); +faim_internal int aim_putuserinfo(aim_bstream_t *bs, struct aim_userinfo_s *info); -faim_internal int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo); +faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo); -faim_internal void faimdprintf(struct aim_session_t *sess, int dlevel, const char *format, ...); +faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...); #ifndef FAIM_INTERNAL_INSANE -/* why the hell wont cpp let you use #error inside #define's? */ -/* isn't it single-pass? so the #error would get passed to the compiler --jbm */ #define printf() printf called inside libfaim #define sprintf() unbounded sprintf used inside libfaim #endif diff --git a/src/admin.c b/src/admin.c index 4a461b6..260c8fe 100644 --- a/src/admin.c +++ b/src/admin.c @@ -3,180 +3,171 @@ #include /* called for both reply and change-reply */ -static int infochange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int infochange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - int i; - - /* - * struct { - * unsigned short perms; - * unsigned short tlvcount; - * aim_tlv_t tlvs[tlvcount]; - * } admin_info[n]; - */ - for (i = 0; i < datalen; ) { - int perms, tlvcount; - - perms = aimutil_get16(data+i); - i += 2; - - tlvcount = aimutil_get16(data+i); - i += 2; - - while (tlvcount) { - aim_rxcallback_t userfunc; - struct aim_tlv_t *tlv; - int str = 0; - - if ((aimutil_get16(data+i) == 0x0011) || - (aimutil_get16(data+i) == 0x0004)) - str = 1; - - if (str) - tlv = aim_grabtlvstr(data+i); - else - tlv = aim_grabtlv(data+i); - - /* XXX fix so its only called once for the entire packet */ - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - userfunc(sess, rx, perms, tlv->type, tlv->length, tlv->value, str); - - if (tlv) - i += 2+2+tlv->length; - - if (tlv && tlv->value) - free(tlv->value); - if (tlv) - free(tlv); - - tlvcount--; - } - } - - return 1; +#ifdef MID_FINALLY_REWROTE_ALL_THE_CRAP + int i; + + /* + * struct { + * unsigned short perms; + * unsigned short tlvcount; + * aim_tlv_t tlvs[tlvcount]; + * } admin_info[n]; + */ + for (i = 0; i < datalen; ) { + int perms, tlvcount; + + perms = aimutil_get16(data+i); + i += 2; + + tlvcount = aimutil_get16(data+i); + i += 2; + + while (tlvcount) { + aim_rxcallback_t userfunc; + aim_tlv_t *tlv; + int str = 0; + + if ((aimutil_get16(data+i) == 0x0011) || + (aimutil_get16(data+i) == 0x0004)) + str = 1; + + if (str) + tlv = aim_grabtlvstr(data+i); + else + tlv = aim_grabtlv(data+i); + + /* XXX fix so its only called once for the entire packet */ + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + userfunc(sess, rx, perms, tlv->type, tlv->length, tlv->value, str); + + if (tlv) + i += 2+2+tlv->length; + + if (tlv && tlv->value) + free(tlv->value); + if (tlv) + free(tlv); + + tlvcount--; + } + } +#endif /* MID_FINALLY_REWROTE_ALL_THE_CRAP */ + return 1; } -static int accountconfirm(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int accountconfirm(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - aim_rxcallback_t userfunc; - int status; + aim_rxcallback_t userfunc; + fu16_t status; - status = aimutil_get16(data); + status = aimbs_get16(bs); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - return userfunc(sess, rx, status); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, status); - return 0; + return 0; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if ((snac->subtype == 0x0003) || (snac->subtype == 0x0005)) - return infochange(sess, mod, rx, snac, data, datalen); - else if (snac->subtype == 0x0007) - return accountconfirm(sess, mod, rx, snac, data, datalen); + if ((snac->subtype == 0x0003) || (snac->subtype == 0x0005)) + return infochange(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0007) + return accountconfirm(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int admin_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x0007; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "admin", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x0007; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "admin", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } -faim_export unsigned long aim_auth_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_auth_clientready(aim_session_t *sess, aim_conn_t *conn) { - struct aim_tool_version tools[] = { - {0x0001, 0x0003, AIM_TOOL_NEWWIN, 0x0361}, - {0x0007, 0x0001, AIM_TOOL_NEWWIN, 0x0361}, - }; - int i,j; - struct command_tx_struct *newpacket; - int toolcount = sizeof(tools)/sizeof(struct aim_tool_version); - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); - - for (j = 0; j < toolcount; j++) { - i += aimutil_put16(newpacket->data+i, tools[j].group); - i += aimutil_put16(newpacket->data+i, tools[j].version); - i += aimutil_put16(newpacket->data+i, tools[j].tool); - i += aimutil_put16(newpacket->data+i, tools[j].toolversion); - } - - newpacket->commandlen = i; - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + static const struct aim_tool_version tools[] = { + {0x0001, 0x0003, AIM_TOOL_NEWWIN, 0x0361}, + {0x0007, 0x0001, AIM_TOOL_NEWWIN, 0x0361}, + }; + int j; + aim_frame_t *tx; + int toolcount = sizeof(tools) / sizeof(struct aim_tool_version); + aim_snacid_t snacid; + + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 1152))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&tx->data, 0x0001, 0x0002, 0x0000, snacid); + + for (j = 0; j < toolcount; j++) { + aimbs_put16(&tx->data, tools[j].group); + aimbs_put16(&tx->data, tools[j].version); + aimbs_put16(&tx->data, tools[j].tool); + aimbs_put16(&tx->data, tools[j].toolversion); + } + + aim_tx_enqueue(sess, tx); + + return 0; } -faim_export unsigned long aim_auth_changepasswd(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *new, char *current) +faim_export int aim_auth_changepasswd(aim_session_t *sess, aim_conn_t *conn, const char *newpw, const char *curpw) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *tx; + aim_tlvlist_t *tl = NULL; + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+4+strlen(current)+4+strlen(new)))) - return -1; + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+strlen(curpw)+4+strlen(newpw)))) + return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid); - i = aim_putsnac(newpacket->data, 0x0007, 0x0004, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + /* new password TLV t(0002) */ + aim_addtlvtochain_raw(&tl, 0x0002, strlen(newpw), newpw); - /* new password TLV t(0002) */ - i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(new), new); + /* current password TLV t(0012) */ + aim_addtlvtochain_raw(&tl, 0x0012, strlen(curpw), curpw); - /* current password TLV t(0012) */ - i += aim_puttlv_str(newpacket->data+i, 0x0012, strlen(current), current); + aim_writetlvchain(&tx->data, &tl); + aim_freetlvchain(&tl); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, tx); - return sess->snac_nextid; + return 0; } -faim_export unsigned long aim_auth_setversions(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_auth_setversions(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + (4*2)))) - return -1; + aim_frame_t *tx; + aim_snacid_t snacid; - newpacket->lock = 1; + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 18))) + return -ENOMEM; - i = aim_putsnac(newpacket->data, 0x0001, 0x0017, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); + snacid = aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); + aim_putsnac(&tx->data, 0x0001, 0x0017, 0x0000, snacid); - i += aimutil_put16(newpacket->data+i, 0x0001); - i += aimutil_put16(newpacket->data+i, 0x0003); + aimbs_put16(&tx->data, 0x0001); + aimbs_put16(&tx->data, 0x0003); - i += aimutil_put16(newpacket->data+i, 0x0007); - i += aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&tx->data, 0x0007); + aimbs_put16(&tx->data, 0x0001); - newpacket->commandlen = i; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, tx); - return sess->snac_nextid; + return 0; } /* @@ -187,10 +178,9 @@ faim_export unsigned long aim_auth_setversions(struct aim_session_t *sess, * get the TRIAL flag removed from your account. * */ -faim_export unsigned long aim_auth_reqconfirm(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_auth_reqconfirm(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0007, 0x0006); + return aim_genericreq_n(sess, conn, 0x0007, 0x0006); } /* @@ -199,49 +189,43 @@ faim_export unsigned long aim_auth_reqconfirm(struct aim_session_t *sess, * The only known valid tag is 0x0011 (email address). * */ -faim_export unsigned long aim_auth_getinfo(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned short info) +faim_export int aim_auth_getinfo(aim_session_t *sess, aim_conn_t *conn, fu16_t info) { - struct command_tx_struct *newpacket; - int i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + 4))) - return -1; + aim_frame_t *tx; + aim_snacid_t snacid; - newpacket->lock = 1; + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 14))) + return -ENOMEM; - i = aim_putsnac(newpacket->data, 0x0007, 0x0002, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0002, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(sess, 0x0002, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&tx->data, 0x0007, 0x0002, 0x0000, snacid); - i += aimutil_put16(newpacket->data+i, info); - i += aimutil_put16(newpacket->data+i, 0x0000); + aimbs_put16(&tx->data, info); + aimbs_put16(&tx->data, 0x0000); - newpacket->commandlen = i; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, tx); - return sess->snac_nextid; + return 0; } -faim_export unsigned long aim_auth_setemail(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *newemail) +faim_export int aim_auth_setemail(aim_session_t *sess, aim_conn_t *conn, const char *newemail) { - struct command_tx_struct *newpacket; - int i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+2+strlen(newemail)))) - return -1; - - newpacket->lock = 1; + aim_frame_t *tx; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; - i = aim_putsnac(newpacket->data, 0x0007, 0x0004, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(newemail)))) + return -ENOMEM; - i += aim_puttlv_str(newpacket->data+i, 0x0011, strlen(newemail), newemail); + snacid = aim_cachesnac(sess, 0x0007, 0x0004, 0x0000, NULL, 0); + aim_putsnac(&tx->data, 0x0007, 0x0004, 0x0000, snacid); - aim_tx_enqueue(sess, newpacket); + aim_addtlvtochain_raw(&tl, 0x0011, strlen(newemail), newemail); + + aim_writetlvchain(&tx->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, tx); - return sess->snac_nextid; + return 0; } diff --git a/src/adverts.c b/src/adverts.c index 3f717c6..0c40e73 100644 --- a/src/adverts.c +++ b/src/adverts.c @@ -6,38 +6,34 @@ #define FAIM_INTERNAL #include -faim_export unsigned long aim_ads_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_ads_clientready(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 0x1a))) + return -ENOMEM; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 0x1a))) - return -1; + snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid); - newpacket->lock = 1; + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0002); - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0013); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0002); + aimbs_put16(&fr->data, 0x0005); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0013); + aim_tx_enqueue(sess, fr); - i+= aimutil_put16(newpacket->data+i, 0x0005); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0001); - - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); - - return (sess->snac_nextid++); + return 0; } -faim_export unsigned long aim_ads_requestads(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_ads_requestads(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0005, 0x0002); + return aim_genericreq_n(sess, conn, 0x0005, 0x0002); } diff --git a/src/auth.c b/src/auth.c index 6db41c4..ff1ad08 100644 --- a/src/auth.c +++ b/src/auth.c @@ -1,33 +1,30 @@ /* - aim_auth.c - - Deals with the authorizer. - + * aim_auth.c + * + * Deals with the authorizer. + * */ #define FAIM_INTERNAL #include /* this just pushes the passed cookie onto the passed connection -- NO SNAC! */ -faim_export int aim_auth_sendcookie(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned char *chipsahoy) +faim_export int aim_auth_sendcookie(aim_session_t *sess, aim_conn_t *conn, const fu8_t *chipsahoy) { - struct command_tx_struct *newpacket; - int curbyte=0; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0001, 4+2+2+AIM_COOKIELEN))) - return -1; + aim_frame_t *fr; + aim_tlvlist_t *tl = NULL; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0001, 4+2+2+AIM_COOKIELEN))) + return -ENOMEM; - newpacket->lock = 1; + aimbs_put32(&fr->data, 0x00000001); + aim_addtlvtochain_raw(&tl, 0x0006, AIM_COOKIELEN, chipsahoy); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0006); - curbyte += aimutil_put16(newpacket->data+curbyte, AIM_COOKIELEN); - memcpy(newpacket->data+curbyte, chipsahoy, AIM_COOKIELEN); + aim_tx_enqueue(sess, fr); - return aim_tx_enqueue(sess, newpacket); + return 0; } /* @@ -39,137 +36,126 @@ faim_export int aim_auth_sendcookie(struct aim_session_t *sess, * its nonzero, there was an error. * */ -static int parse(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int parse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_tlvlist_t *tlvlist; - int ret = 0; - aim_rxcallback_t userfunc; - char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL; - unsigned char *cookie = NULL; - int errorcode = 0, regstatus = 0; - int latestbuild = 0, latestbetabuild = 0; - char *latestrelease = NULL, *latestbeta = NULL; - char *latestreleaseurl = NULL, *latestbetaurl = NULL; - char *latestreleaseinfo = NULL, *latestbetainfo = NULL; - - /* - * Read block of TLVs. All further data is derived - * from what is parsed here. - * - */ - tlvlist = aim_readtlvchain(data, datalen); - - /* - * No matter what, we should have a screen name. - */ - memset(sess->sn, 0, sizeof(sess->sn)); - if (aim_gettlv(tlvlist, 0x0001, 1)) { - sn = aim_gettlv_str(tlvlist, 0x0001, 1); - strncpy(sess->sn, sn, sizeof(sess->sn)); - } - - /* - * Check for an error code. If so, we should also - * have an error url. - */ - if (aim_gettlv(tlvlist, 0x0008, 1)) - errorcode = aim_gettlv16(tlvlist, 0x0008, 1); - if (aim_gettlv(tlvlist, 0x0004, 1)) - errurl = aim_gettlv_str(tlvlist, 0x0004, 1); - - /* - * BOS server address. - */ - if (aim_gettlv(tlvlist, 0x0005, 1)) - bosip = aim_gettlv_str(tlvlist, 0x0005, 1); - - /* - * Authorization cookie. - */ - if (aim_gettlv(tlvlist, 0x0006, 1)) { - struct aim_tlv_t *tmptlv; - - tmptlv = aim_gettlv(tlvlist, 0x0006, 1); - - if ((cookie = malloc(tmptlv->length))) - memcpy(cookie, tmptlv->value, tmptlv->length); - } - - /* - * The email address attached to this account - * Not available for ICQ logins. - */ - if (aim_gettlv(tlvlist, 0x0011, 1)) - email = aim_gettlv_str(tlvlist, 0x0011, 1); - - /* - * The registration status. (Not real sure what it means.) - * Not available for ICQ logins. - * - * 1 = No disclosure - * 2 = Limited disclosure - * 3 = Full disclosure - * - * This has to do with whether your email address is available - * to other users or not. AFAIK, this feature is no longer used. - * - */ - if (aim_gettlv(tlvlist, 0x0013, 1)) - regstatus = aim_gettlv16(tlvlist, 0x0013, 1); - - if (aim_gettlv(tlvlist, 0x0040, 1)) - latestbetabuild = aim_gettlv32(tlvlist, 0x0040, 1); - if (aim_gettlv(tlvlist, 0x0041, 1)) - latestbetaurl = aim_gettlv_str(tlvlist, 0x0041, 1); - if (aim_gettlv(tlvlist, 0x0042, 1)) - latestbetainfo = aim_gettlv_str(tlvlist, 0x0042, 1); - if (aim_gettlv(tlvlist, 0x0043, 1)) - latestbeta = aim_gettlv_str(tlvlist, 0x0043, 1); - if (aim_gettlv(tlvlist, 0x0048, 1)) - ; /* no idea what this is */ - - if (aim_gettlv(tlvlist, 0x0044, 1)) - latestbuild = aim_gettlv32(tlvlist, 0x0044, 1); - if (aim_gettlv(tlvlist, 0x0045, 1)) - latestreleaseurl = aim_gettlv_str(tlvlist, 0x0045, 1); - if (aim_gettlv(tlvlist, 0x0046, 1)) - latestreleaseinfo = aim_gettlv_str(tlvlist, 0x0046, 1); - if (aim_gettlv(tlvlist, 0x0047, 1)) - latestrelease = aim_gettlv_str(tlvlist, 0x0047, 1); - if (aim_gettlv(tlvlist, 0x0049, 1)) - ; /* no idea what this is */ - - - if ((userfunc = aim_callhandler(sess, rx->conn, snac?snac->family:0x0017, snac?snac->subtype:0x0003))) - ret = userfunc(sess, rx, sn, errorcode, errurl, regstatus, email, bosip, cookie, latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo, latestbeta, latestbetabuild, latestbetaurl, latestbetainfo); - - - if (sn) - free(sn); - if (bosip) - free(bosip); - if (errurl) - free(errurl); - if (email) - free(email); - if (cookie) - free(cookie); - if (latestrelease) - free(latestrelease); - if (latestreleaseurl) - free(latestreleaseurl); - if (latestbeta) - free(latestbeta); - if (latestbetaurl) - free(latestbetaurl); - if (latestreleaseinfo) - free(latestreleaseinfo); - if (latestbetainfo) - free(latestbetainfo); - - aim_freetlvchain(&tlvlist); - - return ret; + aim_tlvlist_t *tlvlist; + int ret = 0; + aim_rxcallback_t userfunc; + char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL; + unsigned char *cookie = NULL; + int errorcode = 0, regstatus = 0; + int latestbuild = 0, latestbetabuild = 0; + char *latestrelease = NULL, *latestbeta = NULL; + char *latestreleaseurl = NULL, *latestbetaurl = NULL; + char *latestreleaseinfo = NULL, *latestbetainfo = NULL; + + /* + * Read block of TLVs. All further data is derived + * from what is parsed here. + */ + tlvlist = aim_readtlvchain(bs); + + /* + * No matter what, we should have a screen name. + */ + memset(sess->sn, 0, sizeof(sess->sn)); + if (aim_gettlv(tlvlist, 0x0001, 1)) { + sn = aim_gettlv_str(tlvlist, 0x0001, 1); + strncpy(sess->sn, sn, sizeof(sess->sn)); + } + + /* + * Check for an error code. If so, we should also + * have an error url. + */ + if (aim_gettlv(tlvlist, 0x0008, 1)) + errorcode = aim_gettlv16(tlvlist, 0x0008, 1); + if (aim_gettlv(tlvlist, 0x0004, 1)) + errurl = aim_gettlv_str(tlvlist, 0x0004, 1); + + /* + * BOS server address. + */ + if (aim_gettlv(tlvlist, 0x0005, 1)) + bosip = aim_gettlv_str(tlvlist, 0x0005, 1); + + /* + * Authorization cookie. + */ + if (aim_gettlv(tlvlist, 0x0006, 1)) { + aim_tlv_t *tmptlv; + + tmptlv = aim_gettlv(tlvlist, 0x0006, 1); + + if ((cookie = malloc(tmptlv->length))) + memcpy(cookie, tmptlv->value, tmptlv->length); + } + + /* + * The email address attached to this account + * Not available for ICQ logins. + */ + if (aim_gettlv(tlvlist, 0x0011, 1)) + email = aim_gettlv_str(tlvlist, 0x0011, 1); + + /* + * The registration status. (Not real sure what it means.) + * Not available for ICQ logins. + * + * 1 = No disclosure + * 2 = Limited disclosure + * 3 = Full disclosure + * + * This has to do with whether your email address is available + * to other users or not. AFAIK, this feature is no longer used. + * + */ + if (aim_gettlv(tlvlist, 0x0013, 1)) + regstatus = aim_gettlv16(tlvlist, 0x0013, 1); + + if (aim_gettlv(tlvlist, 0x0040, 1)) + latestbetabuild = aim_gettlv32(tlvlist, 0x0040, 1); + if (aim_gettlv(tlvlist, 0x0041, 1)) + latestbetaurl = aim_gettlv_str(tlvlist, 0x0041, 1); + if (aim_gettlv(tlvlist, 0x0042, 1)) + latestbetainfo = aim_gettlv_str(tlvlist, 0x0042, 1); + if (aim_gettlv(tlvlist, 0x0043, 1)) + latestbeta = aim_gettlv_str(tlvlist, 0x0043, 1); + if (aim_gettlv(tlvlist, 0x0048, 1)) + ; /* no idea what this is */ + + if (aim_gettlv(tlvlist, 0x0044, 1)) + latestbuild = aim_gettlv32(tlvlist, 0x0044, 1); + if (aim_gettlv(tlvlist, 0x0045, 1)) + latestreleaseurl = aim_gettlv_str(tlvlist, 0x0045, 1); + if (aim_gettlv(tlvlist, 0x0046, 1)) + latestreleaseinfo = aim_gettlv_str(tlvlist, 0x0046, 1); + if (aim_gettlv(tlvlist, 0x0047, 1)) + latestrelease = aim_gettlv_str(tlvlist, 0x0047, 1); + if (aim_gettlv(tlvlist, 0x0049, 1)) + ; /* no idea what this is */ + + + if ((userfunc = aim_callhandler(sess, rx->conn, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003))) { + /* XXX return as a struct? */ + ret = userfunc(sess, rx, sn, errorcode, errurl, regstatus, email, bosip, cookie, latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo, latestbeta, latestbetabuild, latestbetaurl, latestbetainfo); + } + + free(sn); + free(bosip); + free(errurl); + free(email); + free(cookie); + free(latestrelease); + free(latestreleaseurl); + free(latestbeta); + free(latestbetaurl); + free(latestreleaseinfo); + free(latestbetainfo); + + aim_freetlvchain(&tlvlist); + + return ret; } /* @@ -179,46 +165,43 @@ static int parse(struct aim_session_t *sess, aim_module_t *mod, struct command_r * Calls the client, which should then use the value to call aim_send_login. * */ -static int keyparse(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int keyparse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - unsigned char *key; - int keylen; - int ret = 1; - aim_rxcallback_t userfunc; - - keylen = aimutil_get16(data); - if (!(key = malloc(keylen+1))) - return ret; - memcpy(key, data+2, keylen); - key[keylen] = '\0'; - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, (char *)key); - - free(key); - - return ret; + int keylen, ret = 1; + aim_rxcallback_t userfunc; + char *keystr; + + keylen = aimbs_get16(bs); + keystr = aimbs_getstr(bs, keylen); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, keystr); + + free(keystr); + + return ret; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0003) - return parse(sess, mod, rx, snac, data, datalen); - else if (snac->subtype == 0x0007) - return keyparse(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0003) + return parse(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0007) + return keyparse(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int auth_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int auth_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x0017; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "auth", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x0017; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "auth", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } + diff --git a/src/bos.c b/src/bos.c index 8d6810b..3149111 100644 --- a/src/bos.c +++ b/src/bos.c @@ -12,64 +12,62 @@ * a bitwise OR of all the user classes you want to see you. * */ -faim_export unsigned long aim_bos_setgroupperm(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_long mask) +faim_export int aim_bos_setgroupperm(aim_session_t *sess, aim_conn_t *conn, fu32_t mask) { - return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask); + return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask); } -static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - aim_rxcallback_t userfunc; - int ret = 0; - struct aim_tlvlist_t *tlvlist; - unsigned short maxpermits = 0, maxdenies = 0; - - /* - * TLVs follow - */ - if (!(tlvlist = aim_readtlvchain(data, datalen))) - return 0; - - /* - * TLV type 0x0001: Maximum number of buddies on permit list. - */ - if (aim_gettlv(tlvlist, 0x0001, 1)) - maxpermits = aim_gettlv16(tlvlist, 0x0001, 1); - - /* - * TLV type 0x0002: Maximum number of buddies on deny list. - * - */ - if (aim_gettlv(tlvlist, 0x0002, 1)) - maxdenies = aim_gettlv16(tlvlist, 0x0002, 1); - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, maxpermits, maxdenies); - - aim_freetlvchain(&tlvlist); - - return ret; + aim_rxcallback_t userfunc; + aim_tlvlist_t *tlvlist; + fu16_t maxpermits = 0, maxdenies = 0; + int ret = 0; + + /* + * TLVs follow + */ + tlvlist = aim_readtlvchain(bs); + + /* + * TLV type 0x0001: Maximum number of buddies on permit list. + */ + if (aim_gettlv(tlvlist, 0x0001, 1)) + maxpermits = aim_gettlv16(tlvlist, 0x0001, 1); + + /* + * TLV type 0x0002: Maximum number of buddies on deny list. + */ + if (aim_gettlv(tlvlist, 0x0002, 1)) + maxdenies = aim_gettlv16(tlvlist, 0x0002, 1); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, maxpermits, maxdenies); + + aim_freetlvchain(&tlvlist); + + return ret; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0003) - return rights(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0003) + return rights(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int bos_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int bos_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x0009; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "bos", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x0009; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "bos", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } + + diff --git a/src/buddylist.c b/src/buddylist.c index cebcb6f..975fccf 100644 --- a/src/buddylist.c +++ b/src/buddylist.c @@ -11,76 +11,77 @@ * it is still in a format parsable by extractuserinfo. * */ -static int buddychange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int buddychange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_userinfo_s userinfo; - aim_rxcallback_t userfunc; + struct aim_userinfo_s userinfo; + aim_rxcallback_t userfunc; - aim_extractuserinfo(sess, data, &userinfo); + aim_extractuserinfo(sess, bs, &userinfo); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - return userfunc(sess, rx, &userinfo); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, &userinfo); - return 0; + return 0; } -static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - aim_rxcallback_t userfunc; - struct aim_tlvlist_t *tlvlist; - unsigned short maxbuddies = 0, maxwatchers = 0; - int ret = 0; - - /* - * TLVs follow - */ - if (!(tlvlist = aim_readtlvchain(data, datalen))) - return 0; - - /* - * TLV type 0x0001: Maximum number of buddies. - */ - if (aim_gettlv(tlvlist, 0x0001, 1)) - maxbuddies = aim_gettlv16(tlvlist, 0x0001, 1); - - /* - * TLV type 0x0002: Maximum number of watchers. - * - * XXX: what the hell is a watcher? - * - */ - if (aim_gettlv(tlvlist, 0x0002, 1)) - maxwatchers = aim_gettlv16(tlvlist, 0x0002, 1); - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, maxbuddies, maxwatchers); - - aim_freetlvchain(&tlvlist); - - return ret; + aim_rxcallback_t userfunc; + aim_tlvlist_t *tlvlist; + fu16_t maxbuddies = 0, maxwatchers = 0; + int ret = 0; + + /* + * TLVs follow + */ + tlvlist = aim_readtlvchain(bs); + + /* + * TLV type 0x0001: Maximum number of buddies. + */ + if (aim_gettlv(tlvlist, 0x0001, 1)) + maxbuddies = aim_gettlv16(tlvlist, 0x0001, 1); + + /* + * TLV type 0x0002: Maximum number of watchers. + * + * Watchers are other users who have you on their buddy + * list. (This is called the "reverse list" by a certain + * other IM protocol.) + * + */ + if (aim_gettlv(tlvlist, 0x0002, 1)) + maxwatchers = aim_gettlv16(tlvlist, 0x0002, 1); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, maxbuddies, maxwatchers); + + aim_freetlvchain(&tlvlist); + + return ret; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0003) - return rights(sess, mod, rx, snac, data, datalen); - else if ((snac->subtype == 0x000b) || (snac->subtype == 0x000c)) - return buddychange(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0003) + return rights(sess, mod, rx, snac, bs); + else if ((snac->subtype == 0x000b) || (snac->subtype == 0x000c)) + return buddychange(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int buddylist_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int buddylist_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x0003; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "buddylist", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x0003; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "buddylist", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } /* @@ -91,30 +92,26 @@ faim_internal int buddylist_modfirst(struct aim_session_t *sess, aim_module_t *m * XXX this should just be an extension of setbuddylist() * */ -faim_export unsigned long aim_add_buddy(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *sn ) +faim_export int aim_add_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; - if(!sn) - return -1; + if (!sn || !strlen(sn)) + return -EINVAL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+1+strlen(sn)))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)))) + return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1); + aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid); - i = aim_putsnac(newpacket->data, 0x0003, 0x0004, 0x0000, sess->snac_nextid); - i += aimutil_put8(newpacket->data+i, strlen(sn)); - i += aimutil_putstr(newpacket->data+i, sn, strlen(sn)); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - aim_tx_enqueue(sess, newpacket ); + aim_tx_enqueue(sess, fr); - aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1); - - return sess->snac_nextid; + return 0; } /* @@ -122,30 +119,25 @@ faim_export unsigned long aim_add_buddy(struct aim_session_t *sess, * the same as setbuddylist() but with a different snac subtype). * */ -faim_export unsigned long aim_remove_buddy(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *sn ) +faim_export int aim_remove_buddy(aim_session_t *sess, aim_conn_t *conn, const char *sn) { - struct command_tx_struct *newpacket; - int i; - - if(!sn) - return -1; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+1+strlen(sn)))) - return -1; + aim_frame_t *fr; + aim_snacid_t snacid; - newpacket->lock = 1; + if (!sn || !strlen(sn)) + return -EINVAL; - i = aim_putsnac(newpacket->data, 0x0003, 0x0005, 0x0000, sess->snac_nextid); + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+1+strlen(sn)))) + return -ENOMEM; - i += aimutil_put8(newpacket->data+i, strlen(sn)); - i += aimutil_putstr(newpacket->data+i, sn, strlen(sn)); + snacid = aim_cachesnac(sess, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1); + aim_putsnac(&fr->data, 0x0003, 0x0005, 0x0000, snacid); - aim_tx_enqueue(sess, newpacket); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - aim_cachesnac(sess, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid; + return 0; } diff --git a/src/chat.c b/src/chat.c index 0a48205..7a09c0b 100644 --- a/src/chat.c +++ b/src/chat.c @@ -8,47 +8,50 @@ #define FAIM_INTERNAL #include -faim_export char *aim_chat_getname(struct aim_conn_t *conn) +faim_export char *aim_chat_getname(aim_conn_t *conn) { - if (!conn) - return NULL; - if (conn->type != AIM_CONN_TYPE_CHAT) - return NULL; + + if (!conn) + return NULL; + + if (conn->type != AIM_CONN_TYPE_CHAT) + return NULL; - return (char *)conn->priv; /* yuck ! */ + return (char *)conn->priv; /* yuck ! */ } -faim_export struct aim_conn_t *aim_chat_getconn(struct aim_session_t *sess, char *name) +faim_export aim_conn_t *aim_chat_getconn(aim_session_t *sess, const char *name) { - struct aim_conn_t *cur; - - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->type != AIM_CONN_TYPE_CHAT) - continue; - if (!cur->priv) { - faimdprintf(sess, 0, "faim: chat: chat connection with no name! (fd = %d)\n", cur->fd); - continue; - } - if (strcmp((char *)cur->priv, name) == 0) - break; - } - faim_mutex_unlock(&sess->connlistlock); - - return cur; + aim_conn_t *cur; + + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (cur->type != AIM_CONN_TYPE_CHAT) + continue; + if (!cur->priv) { + faimdprintf(sess, 0, "faim: chat: chat connection with no name! (fd = %d)\n", cur->fd); + continue; + } + if (strcmp((char *)cur->priv, name) == 0) + break; + } + faim_mutex_unlock(&sess->connlistlock); + + return cur; } -faim_export int aim_chat_attachname(struct aim_conn_t *conn, char *roomname) +faim_export int aim_chat_attachname(aim_conn_t *conn, const char *roomname) { - if (!conn || !roomname) - return -1; - if (conn->priv) - free(conn->priv); + if (!conn || !roomname) + return -EINVAL; + + if (conn->priv) + free(conn->priv); - conn->priv = strdup(roomname); + conn->priv = strdup(roomname); - return 0; + return 0; } /* @@ -63,331 +66,317 @@ faim_export int aim_chat_attachname(struct aim_conn_t *conn, char *roomname) * * XXX convert this to use tlvchains */ -faim_export unsigned long aim_chat_send_im(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned short flags, - const char *msg, - int msglen) +faim_export int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, fu16_t flags, const char *msg, int msglen) { + int i; + aim_frame_t *fr; + aim_msgcookie_t *cookie; + aim_snacid_t snacid; + fu8_t ckstr[8]; + aim_tlvlist_t *otl = NULL, *itl = NULL; + + if (!sess || !conn || !msg || (msglen <= 0)) + return 0; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x000e, 0x0005, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x000e, 0x0005, 0x0000, snacid); + - int curbyte,i; - struct command_tx_struct *newpacket; - struct aim_msgcookie_t *cookie; - - if (!sess || !conn || !msg || (msglen <= 0)) - return 0; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 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) rand()); - - cookie = aim_mkcookie(newpacket->data+curbyte-8, AIM_COOKIETYPE_CHAT, NULL); - cookie->data = strdup(conn->priv); /* chat hack dependent */ - - aim_cachecookie(sess, cookie); - - /* - * Channel ID. - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); - - /* - * Type 1: Flag meaning this message is destined to the room. - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - - /* - * Type 6: Reflect - */ - if (!(flags & AIM_CHATFLAGS_NOREFLECT)) { - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0006); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - } - - /* - * Type 7: Autoresponse - */ - if (flags & AIM_CHATFLAGS_AWAY) { - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0007); - 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++); + /* + * Generate a random message cookie. + * + * XXX mkcookie should generate the cookie and cache it in one + * operation to preserve uniqueness. + * + */ + for (i = 0; i < sizeof(ckstr); i++) + aimutil_put8(ckstr+i, (fu8_t) rand()); + + cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL); + cookie->data = strdup(conn->priv); /* chat hack dependent */ + + aim_cachecookie(sess, cookie); + + for (i = 0; i < sizeof(ckstr); i++) + aimbs_put8(&fr->data, ckstr[i]); + + + /* + * Channel ID. + */ + aimbs_put16(&fr->data, 0x0003); + + + /* + * Type 1: Flag meaning this message is destined to the room. + */ + aim_addtlvtochain_noval(&otl, 0x0001); + + /* + * Type 6: Reflect + */ + if (!(flags & AIM_CHATFLAGS_NOREFLECT)) + aim_addtlvtochain_noval(&otl, 0x0006); + + /* + * Type 7: Autoresponse + */ + if (flags & AIM_CHATFLAGS_AWAY) + aim_addtlvtochain_noval(&otl, 0x0007); + + /* + * SubTLV: Type 1: Message + */ + aim_addtlvtochain_raw(&itl, 0x0001, strlen(msg), msg); + + /* + * Type 5: Message block. Contains more TLVs. + * + * This could include other information... We just + * put in a message TLV however. + * + */ + aim_addtlvtochain_frozentlvlist(&otl, 0x0005, &itl); + + aim_writetlvchain(&fr->data, &otl); + + aim_freetlvchain(&itl); + aim_freetlvchain(&otl); + + aim_tx_enqueue(sess, fr); + + return 0; } -/* - * Join a room of name roomname. This is the first - * step to joining an already created room. It's - * basically a Service Request for family 0x000e, - * with a little added on to specify the exchange - * and room name. - * - */ -faim_export unsigned long aim_chat_join(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short exchange, - const char *roomname) +static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance) { - struct command_tx_struct *newpacket; - int i; - - if (!sess || !conn || !roomname) - return 0; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+9+strlen(roomname)+2))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0004, 0x0000, sess->snac_nextid); - - i+= aimutil_put16(newpacket->data+i, 0x000e); - - /* - * this is techinally a TLV, but we can't use normal functions - * because we need the extraneous nulls and other weird things. - */ - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 2+1+strlen(roomname)+2); - i+= aimutil_put16(newpacket->data+i, exchange); - i+= aimutil_put8(newpacket->data+i, strlen(roomname)); - i+= aimutil_putstr(newpacket->data+i, roomname, strlen(roomname)); - i+= aimutil_put16(newpacket->data+i, 0x0000); /* instance? */ - - /* - * Chat hack. - * - * XXX: A problem occurs here if we request a channel - * join but it fails....pendingjoin will be nonnull - * even though the channel is never going to get a - * redirect! - * - */ - sess->pendingjoin = strdup(roomname); - sess->pendingjoinexchange = exchange; - - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); - - aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, roomname, strlen(roomname)+1); - - return sess->snac_nextid; + fu8_t *buf; + int buflen; + aim_bstream_t bs; + + buflen = 2 + 1 + strlen(roomname) + 2; + + if (!(buf = malloc(buflen))) + return 0; + + aim_bstream_init(&bs, buf, buflen); + + aimbs_put16(&bs, exchange); + aimbs_put8(&bs, strlen(roomname)); + aimbs_putraw(&bs, roomname, strlen(roomname)); + aimbs_put16(&bs, instance); + + aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); + + free(buf); + + return 0; } -faim_internal int aim_chat_readroominfo(u_char *buf, struct aim_chat_roominfo *outinfo) +/* + * Join a room of name roomname. This is the first step to joining an + * already created room. It's basically a Service Request for + * family 0x000e, with a little added on to specify the exchange and room + * name. + */ +faim_export int aim_chat_join(aim_session_t *sess, aim_conn_t *conn, fu16_t exchange, const char *roomname, fu16_t instance) { - int namelen = 0; - int i = 0; + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + + if (!sess || !conn || !roomname || !strlen(roomname)) + return -EINVAL; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+9+strlen(roomname)+2))) + return -ENOMEM; + - if (!buf || !outinfo) - return 0; + snacid = aim_cachesnac(sess, 0x0001, 0x0004, 0x0000, roomname, strlen(roomname)+1); + aim_putsnac(&fr->data, 0x0001, 0x0004, 0x0000, snacid); - outinfo->exchange = aimutil_get16(buf+i); - i += 2; + /* + * Requesting service chat (0x000e) + */ + aimbs_put16(&fr->data, 0x000e); - namelen = aimutil_get8(buf+i); - i += 1; + aim_addtlvtochain_chatroom(&tl, 0x0001, exchange, roomname, instance); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + /* + * Chat hack. + * + * XXX: A problem occurs here if we request a channel + * join but it fails....pendingjoin will be nonnull + * even though the channel is never going to get a + * redirect! + * + */ + sess->pendingjoin = strdup(roomname); + sess->pendingjoinexchange = exchange; - outinfo->name = (char *)malloc(namelen+1); - memcpy(outinfo->name, buf+i, namelen); - outinfo->name[namelen] = '\0'; - i += namelen; + aim_tx_enqueue(sess, fr); - outinfo->instance = aimutil_get16(buf+i); - i += 2; - - return i; + return 0; } -faim_export unsigned long aim_chat_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_internal int aim_chat_readroominfo(aim_bstream_t *bs, struct aim_chat_roominfo *outinfo) { - struct command_tx_struct *newpacket; - int i; + int namelen; + + if (!bs || !outinfo) + return 0; + + outinfo->exchange = aimbs_get16(bs); + namelen = aimbs_get8(bs); + outinfo->name = aimbs_getstr(bs, namelen); + outinfo->instance = aimbs_get16(bs); + + return 0; +} - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 0x20))) - return -1; +faim_export int aim_chat_clientready(aim_session_t *sess, aim_conn_t *conn) +{ + aim_frame_t *fr; + aim_snacid_t snacid; - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 0x20))) + return -ENOMEM; - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid); - i+= aimutil_put16(newpacket->data+i, 0x000e); - i+= aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&fr->data, 0x000e); + aimbs_put16(&fr->data, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0004); - i+= aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0003); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0003); - i+= aimutil_put16(newpacket->data+i, 0x0004); - i+= aimutil_put16(newpacket->data+i, 0x0686); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0686); - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return (sess->snac_nextid++); + return 0; } -faim_export int aim_chat_leaveroom(struct aim_session_t *sess, char *name) +faim_export int aim_chat_leaveroom(aim_session_t *sess, const char *name) { - struct aim_conn_t *conn; + aim_conn_t *conn; - if ((conn = aim_chat_getconn(sess, name))) - aim_conn_close(conn); + if (!(conn = aim_chat_getconn(sess, name))) + return -ENOENT; - if (!conn) - return -1; - return 0; + aim_conn_close(conn); + + return 0; } /* * conn must be a BOS connection! */ -faim_export unsigned long aim_chat_invite(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *sn, - char *msg, - u_short exchange, - char *roomname, - u_short instance) +faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance) { - struct command_tx_struct *newpacket; - int i,curbyte=0; - struct aim_msgcookie_t *cookie; - struct aim_invite_priv *priv; - - if (!sess || !conn || !sn || !msg || !roomname) - return -1; - - if (conn->type != AIM_CONN_TYPE_BOS) - return -1; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) - return -1; - - newpacket->lock = 1; - - curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid); - - /* - * Cookie - */ - for (i=0;i<8;i++) - curbyte += aimutil_put8(newpacket->data+curbyte, (u_char)rand()); - - /* XXX this should get uncached by the unwritten 'invite accept' handler */ - if(!(priv = calloc(sizeof(struct aim_invite_priv), 1))) - return -1; - priv->sn = strdup(sn); - priv->roomname = strdup(roomname); - priv->exchange = exchange; - priv->instance = instance; - - if(!(cookie = aim_mkcookie(newpacket->data+curbyte-8, AIM_COOKIETYPE_INVITE, priv))) - return -1; - aim_cachecookie(sess, cookie); - - /* - * Channel (2) - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); - - /* - * Dest sn - */ - curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sn)); - curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn)); - - /* - * TLV t(0005) - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x28+strlen(msg)+0x04+0x03+strlen(roomname)+0x02); - - /* - * Unknown info - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x3131); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x3538); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x3446); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x4100); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x748f); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x2420); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x6287); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x11d1); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x8222); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x4445); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x5354); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - - /* - * TLV t(000a) -- Unknown - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x000a); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); - - /* - * TLV t(000f) -- Unknown - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - - /* - * TLV t(000c) -- Invitation message - */ - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000c, strlen(msg), msg); - - /* - * TLV t(2711) -- Container for room information - */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x2711); - curbyte += aimutil_put16(newpacket->data+curbyte, 3+strlen(roomname)+2); - curbyte += aimutil_put16(newpacket->data+curbyte, exchange); - curbyte += aimutil_put8(newpacket->data+curbyte, strlen(roomname)); - curbyte += aimutil_putstr(newpacket->data+curbyte, roomname, strlen(roomname)); - curbyte += aimutil_put16(newpacket->data+curbyte, instance); - - newpacket->commandlen = curbyte; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); - - return (sess->snac_nextid++); + int i; + aim_frame_t *fr; + aim_msgcookie_t *cookie; + struct aim_invite_priv *priv; + fu8_t ckstr[8]; + aim_snacid_t snacid; + aim_tlvlist_t *otl = NULL, *itl = NULL; + fu8_t *hdr; + int hdrlen; + aim_bstream_t hdrbs; + + if (!sess || !conn || !sn || !msg || !roomname) + return -EINVAL; + + if (conn->type != AIM_CONN_TYPE_BOS) + return -EINVAL; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1); + aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); + + + /* + * Cookie + */ + for (i = 0; i < sizeof(ckstr); i++) + aimutil_put8(ckstr, (fu8_t) rand()); + + /* XXX should be uncached by an unwritten 'invite accept' handler */ + if ((priv = malloc(sizeof(struct aim_invite_priv)))) { + priv->sn = strdup(sn); + priv->roomname = strdup(roomname); + priv->exchange = exchange; + priv->instance = instance; + } + + if ((cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_INVITE, priv))) + aim_cachecookie(sess, cookie); + else + free(priv); + + for (i = 0; i < sizeof(ckstr); i++) + aimbs_put8(&fr->data, ckstr[i]); + + + /* + * Channel (2) + */ + aimbs_put16(&fr->data, 0x0002); + + /* + * Dest sn + */ + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); + + /* + * TLV t(0005) + * + * Everything else is inside this TLV. + * + * Sigh. AOL was rather inconsistent right here. So we have + * to play some minor tricks. Right inside the type 5 is some + * raw data, followed by a series of TLVs. + * + */ + hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2; + hdr = malloc(hdrlen); + aim_bstream_init(&hdrbs, hdr, hdrlen); + + aimbs_put16(&hdrbs, 0x0000); /* Unknown! */ + aimbs_putraw(&hdrbs, ckstr, sizeof(ckstr)); /* I think... */ + aim_putcap(&hdrbs, AIM_CAPS_CHAT); + + aim_addtlvtochain16(&itl, 0x000a, 0x0001); + aim_addtlvtochain_noval(&itl, 0x000f); + aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg); + aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance); + aim_writetlvchain(&hdrbs, &itl); + + aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); + + aim_writetlvchain(&fr->data, &otl); + + free(hdr); + aim_freetlvchain(&itl); + aim_freetlvchain(&otl); + + aim_tx_enqueue(sess, fr); + + return 0; } /* @@ -399,43 +388,38 @@ faim_export unsigned long aim_chat_invite(struct aim_session_t *sess, * * SNAC 000e/0002 */ -static int infoupdate(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int infoupdate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { struct aim_userinfo_s *userinfo = NULL; - aim_rxcallback_t userfunc=NULL; - int ret = 0, i = 0; + aim_rxcallback_t userfunc; + int ret = 0; int usercount = 0; - unsigned char detaillevel = 0; + fu8_t detaillevel = 0; char *roomname = NULL; struct aim_chat_roominfo roominfo; - unsigned short tlvcount = 0; - struct aim_tlvlist_t *tlvlist; + fu16_t tlvcount = 0; + aim_tlvlist_t *tlvlist; char *roomdesc = NULL; - unsigned short unknown_c9 = 0; - unsigned long creationtime = 0; - unsigned short maxmsglen = 0, maxvisiblemsglen = 0; - unsigned short unknown_d2 = 0, unknown_d5 = 0; + fu16_t unknown_c9 = 0; + fu32_t creationtime = 0; + fu16_t maxmsglen = 0, maxvisiblemsglen = 0; + fu16_t unknown_d2 = 0, unknown_d5 = 0; - i += aim_chat_readroominfo(data+i, &roominfo); + aim_chat_readroominfo(bs, &roominfo); - detaillevel = aimutil_get8(data+i); - i++; + detaillevel = aimbs_get8(bs); if (detaillevel != 0x02) { - if (detaillevel == 0x01) - faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level 1 not supported\n"); - else - faimdprintf(sess, 0, "faim: chat_roomupdateinfo: unknown detail level %d\n", detaillevel); + faimdprintf(sess, 0, "faim: chat_roomupdateinfo: detail level %d not supported\n", detaillevel); return 1; } - tlvcount = aimutil_get16(data+i); - i += 2; + tlvcount = aimbs_get16(bs); /* * Everything else are TLVs. */ - tlvlist = aim_readtlvchain(data+i, datalen-i); + tlvlist = aim_readtlvchain(bs); /* * TLV type 0x006a is the room name in Human Readable Form. @@ -454,15 +438,18 @@ static int infoupdate(struct aim_session_t *sess, aim_module_t *mod, struct comm */ if (aim_gettlv(tlvlist, 0x0073, 1)) { int curoccupant = 0; - struct aim_tlv_t *tmptlv; + aim_tlv_t *tmptlv; + aim_bstream_t occbs; tmptlv = aim_gettlv(tlvlist, 0x0073, 1); /* Allocate enough userinfo structs for all occupants */ userinfo = calloc(usercount, sizeof(struct aim_userinfo_s)); - for (i = 0; curoccupant < usercount; ) - i += aim_extractuserinfo(sess, tmptlv->value+i, &userinfo[curoccupant++]); + aim_bstream_init(&occbs, tmptlv->value, tmptlv->length); + + while (curoccupant < usercount) + aim_extractuserinfo(sess, &occbs, &userinfo[curoccupant++]); } /* @@ -563,24 +550,24 @@ static int infoupdate(struct aim_session_t *sess, aim_module_t *mod, struct comm return ret; } -static int userlistchange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int userlistchange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_userinfo_s *userinfo = NULL; - aim_rxcallback_t userfunc; - int i = 0, curcount = 0, ret = 0; + struct aim_userinfo_s *userinfo = NULL; + aim_rxcallback_t userfunc; + int curcount = 0, ret = 0; - while (i < datalen) { - curcount++; - userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); - i += aim_extractuserinfo(sess, data+i, &userinfo[curcount-1]); - } + while (aim_bstream_empty(bs)) { + curcount++; + userinfo = realloc(userinfo, curcount * sizeof(struct aim_userinfo_s)); + aim_extractuserinfo(sess, bs, &userinfo[curcount-1]); + } - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, curcount, userinfo); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, curcount, userinfo); - free(userinfo); + free(userinfo); - return ret; + return ret; } /* @@ -606,118 +593,124 @@ static int userlistchange(struct aim_session_t *sess, aim_module_t *mod, struct * possibly others * */ -static int incomingmsg(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int incomingmsg(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_userinfo_s userinfo; - aim_rxcallback_t userfunc=NULL; - int ret = 0, i = 0; - unsigned char cookie[8]; - int channel; - struct aim_tlvlist_t *outerlist; - char *msg = NULL; - struct aim_msgcookie_t *ck; - - memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); - - /* - * ICBM Cookie. Cache it. - */ - memcpy(cookie, data, 8); - i += 8; - - if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) { - if (ck->data) - free(ck->data); - free(ck); - } - - /* - * Channel ID - * - * Channels 1 and 2 are implemented in the normal ICBM - * parser. - * - * We only do channel 3 here. - * - */ - channel = aimutil_get16(data+i); - i += 2; - - if (channel != 0x0003) { - faimdprintf(sess, 0, "faim: chat_incoming: unknown channel! (0x%04x)\n", channel); - return 0; - } - - /* - * Start parsing TLVs right away. - */ - outerlist = aim_readtlvchain(data+8+2, datalen-8-2); - - /* - * Type 0x0003: Source User Information - */ - if (aim_gettlv(outerlist, 0x0003, 1)) { - struct aim_tlv_t *userinfotlv; - - userinfotlv = aim_gettlv(outerlist, 0x0003, 1); - aim_extractuserinfo(sess, userinfotlv->value, &userinfo); - } - - /* - * Type 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); - } - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, &userinfo, msg); - - free(msg); - aim_freetlvchain(&outerlist); - - return ret; + struct aim_userinfo_s userinfo; + aim_rxcallback_t userfunc; + int ret = 0; + fu8_t *cookie; + fu16_t channel; + aim_tlvlist_t *otl; + char *msg = NULL; + aim_msgcookie_t *ck; + + memset(&userinfo, 0, sizeof(struct aim_userinfo_s)); + + /* + * ICBM Cookie. Uncache it. + */ + cookie = aimbs_getraw(bs, 8); + + if ((ck = aim_uncachecookie(sess, cookie, AIM_COOKIETYPE_CHAT))) { + free(ck->data); + free(ck); + } + + /* + * Channel ID + * + * Channels 1 and 2 are implemented in the normal ICBM + * parser. + * + * We only do channel 3 here. + * + */ + channel = aimbs_get16(bs); + + if (channel != 0x0003) { + faimdprintf(sess, 0, "faim: chat_incoming: unknown channel! (0x%04x)\n", channel); + return 0; + } + + /* + * Start parsing TLVs right away. + */ + otl = aim_readtlvchain(bs); + + /* + * Type 0x0003: Source User Information + */ + if (aim_gettlv(otl, 0x0003, 1)) { + aim_tlv_t *userinfotlv; + aim_bstream_t tbs; + + userinfotlv = aim_gettlv(otl, 0x0003, 1); + + aim_bstream_init(&tbs, userinfotlv->value, userinfotlv->length); + aim_extractuserinfo(sess, &tbs, &userinfo); + } + + /* + * Type 0x0001: If present, it means it was a message to the + * room (as opposed to a whisper). + */ + if (aim_gettlv(otl, 0x0001, 1)) + ; + + /* + * Type 0x0005: Message Block. Conains more TLVs. + */ + if (aim_gettlv(otl, 0x0005, 1)) { + aim_tlvlist_t *itl; + aim_tlv_t *msgblock; + aim_bstream_t tbs; + + msgblock = aim_gettlv(otl, 0x0005, 1); + aim_bstream_init(&tbs, msgblock->value, msgblock->length); + itl = aim_readtlvchain(&tbs); + + /* + * Type 0x0001: Message. + */ + if (aim_gettlv(itl, 0x0001, 1)) + msg = aim_gettlv_str(itl, 0x0001, 1); + + aim_freetlvchain(&itl); + } + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, &userinfo, msg); + + free(cookie); + free(msg); + aim_freetlvchain(&otl); + + return ret; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0002) - return infoupdate(sess, mod, rx, snac, data, datalen); - else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004)) - return userlistchange(sess, mod, rx, snac, data, datalen); - else if (snac->subtype == 0x0006) - return incomingmsg(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0002) + return infoupdate(sess, mod, rx, snac, bs); + else if ((snac->subtype == 0x0003) || (snac->subtype == 0x0004)) + return userlistchange(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0006) + return incomingmsg(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int chat_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int chat_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x000e; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "chat", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x000e; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "chat", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } + + diff --git a/src/chatnav.c b/src/chatnav.c index 1c0196c..3551ab2 100644 --- a/src/chatnav.c +++ b/src/chatnav.c @@ -13,400 +13,388 @@ /* * conn must be a chatnav connection! */ -faim_export unsigned long aim_chatnav_reqrights(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_chatnav_reqrights(aim_session_t *sess, aim_conn_t *conn) { - - return aim_genericreq_n_snacid(sess, conn, 0x000d, 0x0002); + return aim_genericreq_n_snacid(sess, conn, 0x000d, 0x0002); } -faim_export unsigned long aim_chatnav_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_chatnav_clientready(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 0x20))) - return -1; + aim_frame_t *fr; + aim_snacid_t snacid; - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 0x20))) + return -ENOMEM; - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); + snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid); - i+= aimutil_put16(newpacket->data+i, 0x000d); - i+= aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&fr->data, 0x000d); + aimbs_put16(&fr->data, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0004); - i+= aimutil_put16(newpacket->data+i, 0x0001); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0001); - i+= aimutil_put16(newpacket->data+i, 0x0003); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0003); - i+= aimutil_put16(newpacket->data+i, 0x0004); - i+= aimutil_put16(newpacket->data+i, 0x0686); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0686); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return (sess->snac_nextid++); + return 0; } -faim_export unsigned long aim_chatnav_createroom(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *name, - u_short exchange) +faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange) { - struct command_tx_struct *newpacket; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+12+strlen("invite")+strlen(name)))) + return -ENOMEM; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+12+strlen("invite")+strlen(name)))) - return -1; + snacid = aim_cachesnac(sess, 0x000d, 0x0008, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x000d, 0x0008, 0x0000, snacid); - newpacket->lock = 1; + /* exchange */ + aimbs_put16(&fr->data, exchange); - i = aim_putsnac(newpacket->data, 0x000d, 0x0008, 0x0000, sess->snac_nextid); + /* room cookie */ + aimbs_put8(&fr->data, strlen("invite")); + aimbs_putraw(&fr->data, "invite", strlen("invite")); - /* exchange */ - i+= aimutil_put16(newpacket->data+i, exchange); + /* + * instance + * + * Setting this to 0xffff apparently assigns the last instance. + * + */ + aimbs_put16(&fr->data, 0xffff); - /* room cookie */ - i+= aimutil_put8(newpacket->data+i, strlen("invite")); - i+= aimutil_putstr(newpacket->data+i, "invite", strlen("invite")); + /* detail level */ + aimbs_put8(&fr->data, 0x01); - /* instance */ - i+= aimutil_put16(newpacket->data+i, 0xffff); - - /* detail level */ - i+= aimutil_put8(newpacket->data+i, 0x01); - - /* tlvcount */ - i+= aimutil_put16(newpacket->data+i, 0x0001); + /* room name */ + aim_addtlvtochain_raw(&tl, 0x00d3, strlen(name), name); - /* room name */ - i+= aim_puttlv_str(newpacket->data+i, 0x00d3, strlen(name), name); + /* tlvcount */ + aimbs_put16(&fr->data, aim_counttlvchain(&tl)); + aim_writetlvchain(&fr->data, &tl); - aim_cachesnac(sess, 0x000d, 0x0008, 0x0000, NULL, 0); + aim_freetlvchain(&tl); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid; + return 0; } -static int parseinfo_perms(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen, struct aim_snac_t *snac2) +static int parseinfo_perms(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs, aim_snac_t *snac2) { - aim_rxcallback_t userfunc; - int ret = 0; - struct aim_tlvlist_t *tlvlist; - struct aim_chat_exchangeinfo *exchanges = NULL; - int curexchange = 0; - struct aim_tlv_t *exchangetlv; - unsigned char maxrooms = 0; - struct aim_tlvlist_t *innerlist; - - tlvlist = aim_readtlvchain(data, datalen); - - /* - * Type 0x0002: Maximum concurrent rooms. - */ - if (aim_gettlv(tlvlist, 0x0002, 1)) - maxrooms = aim_gettlv8(tlvlist, 0x0002, 1); - - /* - * Type 0x0003: Exchange information - * - * There can be any number of these, each one - * representing another exchange. - * - */ - curexchange = 0; - while ((exchangetlv = aim_gettlv(tlvlist, 0x0003, curexchange+1))) { - curexchange++; - exchanges = realloc(exchanges, curexchange * sizeof(struct aim_chat_exchangeinfo)); - /* exchange number */ - exchanges[curexchange-1].number = aimutil_get16(exchangetlv->value); - innerlist = aim_readtlvchain(exchangetlv->value+2, exchangetlv->length-2); - - /* - * Type 0x000d: Unknown. - */ - if (aim_gettlv(innerlist, 0x000d, 1)) - ; - - /* - * Type 0x0004: Unknown - */ - if (aim_gettlv(innerlist, 0x0004, 1)) - ; - - /* - * Type 0x0002: Unknown - */ - if (aim_gettlv(innerlist, 0x0002, 1)) { - unsigned short classperms; - - classperms = aim_gettlv16(innerlist, 0x0002, 1); - - faimdprintf(sess, 1, "faim: class permissions %x\n", classperms); - } - - /* - * Type 0x00c9: Unknown - */ - if (aim_gettlv(innerlist, 0x00c9, 1)) - ; - - /* - * Type 0x00ca: Creation Date - */ - if (aim_gettlv(innerlist, 0x00ca, 1)) - ; - - /* - * Type 0x00d0: Mandatory Channels? - */ - if (aim_gettlv(innerlist, 0x00d0, 1)) - ; - - /* - * Type 0x00d1: Maximum Message length - */ - if (aim_gettlv(innerlist, 0x00d1, 1)) - ; - - /* - * Type 0x00d2: Maximum Occupancy? - */ - if (aim_gettlv(innerlist, 0x00d2, 1)) - ; - - /* - * Type 0x00d3: Exchange Name - */ - if (aim_gettlv(innerlist, 0x00d3, 1)) - exchanges[curexchange-1].name = aim_gettlv_str(innerlist, 0x00d3, 1); - else - exchanges[curexchange-1].name = NULL; - - /* - * Type 0x00d5: Creation Permissions - * - * 0 Creation not allowed - * 1 Room creation allowed - * 2 Exchange creation allowed - * - */ - if (aim_gettlv(innerlist, 0x00d5, 1)) { - unsigned char createperms; - - createperms = aim_gettlv8(innerlist, 0x00d5, 1); - } - - /* - * Type 0x00d6: Character Set (First Time) - */ - if (aim_gettlv(innerlist, 0x00d6, 1)) - exchanges[curexchange-1].charset1 = aim_gettlv_str(innerlist, 0x00d6, 1); - else - exchanges[curexchange-1].charset1 = NULL; - - /* - * Type 0x00d7: Language (First Time) - */ - if (aim_gettlv(innerlist, 0x00d7, 1)) - exchanges[curexchange-1].lang1 = aim_gettlv_str(innerlist, 0x00d7, 1); - else - exchanges[curexchange-1].lang1 = NULL; - - /* - * Type 0x00d8: Character Set (Second Time) - */ - if (aim_gettlv(innerlist, 0x00d8, 1)) - exchanges[curexchange-1].charset2 = aim_gettlv_str(innerlist, 0x00d8, 1); - else - exchanges[curexchange-1].charset2 = NULL; - - /* - * Type 0x00d9: Language (Second Time) - */ - if (aim_gettlv(innerlist, 0x00d9, 1)) - exchanges[curexchange-1].lang2 = aim_gettlv_str(innerlist, 0x00d9, 1); - else - exchanges[curexchange-1].lang2 = NULL; - - aim_freetlvchain(&innerlist); - } - - /* - * Call client. - */ - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, snac2->type, maxrooms, curexchange, exchanges); - curexchange--; - while(curexchange >= 0) { - free(exchanges[curexchange].name); - free(exchanges[curexchange].charset1); - free(exchanges[curexchange].lang1); - free(exchanges[curexchange].charset2); - free(exchanges[curexchange].lang2); - curexchange--; - } - free(exchanges); - aim_freetlvchain(&tlvlist); - - return ret; + aim_rxcallback_t userfunc; + int ret = 0; + struct aim_chat_exchangeinfo *exchanges = NULL; + int curexchange; + aim_tlv_t *exchangetlv; + fu8_t maxrooms = 0; + aim_tlvlist_t *tlvlist, *innerlist; + + tlvlist = aim_readtlvchain(bs); + + /* + * Type 0x0002: Maximum concurrent rooms. + */ + if (aim_gettlv(tlvlist, 0x0002, 1)) + maxrooms = aim_gettlv8(tlvlist, 0x0002, 1); + + /* + * Type 0x0003: Exchange information + * + * There can be any number of these, each one + * representing another exchange. + * + */ + for (curexchange = 0; ((exchangetlv = aim_gettlv(tlvlist, 0x0003, curexchange+1))); ) { + aim_bstream_t tbs; + + aim_bstream_init(&tbs, exchangetlv->value, exchangetlv->length); + + curexchange++; + + exchanges = realloc(exchanges, curexchange * sizeof(struct aim_chat_exchangeinfo)); + + /* exchange number */ + exchanges[curexchange-1].number = aimbs_get16(&tbs); + innerlist = aim_readtlvchain(&tbs); + + /* + * Type 0x000d: Unknown. + */ + if (aim_gettlv(innerlist, 0x000d, 1)) + ; + + /* + * Type 0x0004: Unknown + */ + if (aim_gettlv(innerlist, 0x0004, 1)) + ; + + /* + * Type 0x0002: Unknown + */ + if (aim_gettlv(innerlist, 0x0002, 1)) { + fu16_t classperms; + + classperms = aim_gettlv16(innerlist, 0x0002, 1); + + faimdprintf(sess, 1, "faim: class permissions %x\n", classperms); + } + + /* + * Type 0x00c9: Unknown + */ + if (aim_gettlv(innerlist, 0x00c9, 1)) + ; + + /* + * Type 0x00ca: Creation Date + */ + if (aim_gettlv(innerlist, 0x00ca, 1)) + ; + + /* + * Type 0x00d0: Mandatory Channels? + */ + if (aim_gettlv(innerlist, 0x00d0, 1)) + ; + + /* + * Type 0x00d1: Maximum Message length + */ + if (aim_gettlv(innerlist, 0x00d1, 1)) + ; + + /* + * Type 0x00d2: Maximum Occupancy? + */ + if (aim_gettlv(innerlist, 0x00d2, 1)) + ; + + /* + * Type 0x00d3: Exchange Name + */ + if (aim_gettlv(innerlist, 0x00d3, 1)) + exchanges[curexchange-1].name = aim_gettlv_str(innerlist, 0x00d3, 1); + else + exchanges[curexchange-1].name = NULL; + + /* + * Type 0x00d5: Creation Permissions + * + * 0 Creation not allowed + * 1 Room creation allowed + * 2 Exchange creation allowed + * + */ + if (aim_gettlv(innerlist, 0x00d5, 1)) { + fu8_t createperms; + + createperms = aim_gettlv8(innerlist, 0x00d5, 1); + } + + /* + * Type 0x00d6: Character Set (First Time) + */ + if (aim_gettlv(innerlist, 0x00d6, 1)) + exchanges[curexchange-1].charset1 = aim_gettlv_str(innerlist, 0x00d6, 1); + else + exchanges[curexchange-1].charset1 = NULL; + + /* + * Type 0x00d7: Language (First Time) + */ + if (aim_gettlv(innerlist, 0x00d7, 1)) + exchanges[curexchange-1].lang1 = aim_gettlv_str(innerlist, 0x00d7, 1); + else + exchanges[curexchange-1].lang1 = NULL; + + /* + * Type 0x00d8: Character Set (Second Time) + */ + if (aim_gettlv(innerlist, 0x00d8, 1)) + exchanges[curexchange-1].charset2 = aim_gettlv_str(innerlist, 0x00d8, 1); + else + exchanges[curexchange-1].charset2 = NULL; + + /* + * Type 0x00d9: Language (Second Time) + */ + if (aim_gettlv(innerlist, 0x00d9, 1)) + exchanges[curexchange-1].lang2 = aim_gettlv_str(innerlist, 0x00d9, 1); + else + exchanges[curexchange-1].lang2 = NULL; + + aim_freetlvchain(&innerlist); + } + + /* + * Call client. + */ + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, snac2->type, maxrooms, curexchange, exchanges); + + for (curexchange--; curexchange >= 0; curexchange++) { + free(exchanges[curexchange].name); + free(exchanges[curexchange].charset1); + free(exchanges[curexchange].lang1); + free(exchanges[curexchange].charset2); + free(exchanges[curexchange].lang2); + curexchange--; + } + free(exchanges); + aim_freetlvchain(&tlvlist); + + return ret; } -static int parseinfo_create(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen, struct aim_snac_t *snac2) +static int parseinfo_create(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs, aim_snac_t *snac2) { - aim_rxcallback_t userfunc; - struct aim_tlvlist_t *tlvlist, *innerlist; - char *ck = NULL, *fqcn = NULL, *name = NULL; - unsigned short exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0; - unsigned long createtime = 0; - unsigned char createperms = 0; - int i = 0, cklen; - struct aim_tlv_t *bigblock; - int ret = 0; - - if (!(tlvlist = aim_readtlvchain(data, datalen))) { - faimdprintf(sess, 0, "unable to read top tlv in create room response\n"); - return 0; - } - - if (!(bigblock = aim_gettlv(tlvlist, 0x0004, 1))) { - faimdprintf(sess, 0, "no bigblock in top tlv in create room response\n"); - aim_freetlvchain(&tlvlist); - return 0; - } - - exchange = aimutil_get16(bigblock->value+i); - i += 2; - - cklen = aimutil_get8(bigblock->value+i); - i++; - - ck = malloc(cklen+1); - memcpy(ck, bigblock->value+i, cklen); - ck[cklen] = '\0'; - i += cklen; - - instance = aimutil_get16(bigblock->value+i); - i += 2; - - if (aimutil_get8(bigblock->value+i) != 0x02) { - faimdprintf(sess, 0, "unknown detaillevel in create room response (0x%02x)\n", aimutil_get8(bigblock->value+i)); - aim_freetlvchain(&tlvlist); - free(ck); - return 0; - } - i += 1; - - unknown = aimutil_get16(bigblock->value+i); - i += 2; - - if (!(innerlist = aim_readtlvchain(bigblock->value+i, bigblock->length-i))) { - faimdprintf(sess, 0, "unable to read inner tlv chain in create room response\n"); - aim_freetlvchain(&tlvlist); - free(ck); - return 0; - } - - if (aim_gettlv(innerlist, 0x006a, 1)) - fqcn = aim_gettlv_str(innerlist, 0x006a, 1); - - if (aim_gettlv(innerlist, 0x00c9, 1)) - flags = aim_gettlv16(innerlist, 0x00c9, 1); - - if (aim_gettlv(innerlist, 0x00ca, 1)) - createtime = aim_gettlv32(innerlist, 0x00ca, 1); - - if (aim_gettlv(innerlist, 0x00d1, 1)) - maxmsglen = aim_gettlv16(innerlist, 0x00d1, 1); - - if (aim_gettlv(innerlist, 0x00d2, 1)) - maxoccupancy = aim_gettlv16(innerlist, 0x00d2, 1); - - if (aim_gettlv(innerlist, 0x00d3, 1)) - name = aim_gettlv_str(innerlist, 0x00d3, 1); - - if (aim_gettlv(innerlist, 0x00d5, 1)) - createperms = aim_gettlv8(innerlist, 0x00d5, 1); - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck); - - free(ck); - free(name); - free(fqcn); - aim_freetlvchain(&innerlist); - aim_freetlvchain(&tlvlist); - - return ret; + aim_rxcallback_t userfunc; + aim_tlvlist_t *tlvlist, *innerlist; + char *ck = NULL, *fqcn = NULL, *name = NULL; + fu16_t exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0; + fu32_t createtime = 0; + fu8_t createperms = 0, detaillevel; + int cklen; + aim_tlv_t *bigblock; + int ret = 0; + aim_bstream_t bbbs; + + tlvlist = aim_readtlvchain(bs); + + if (!(bigblock = aim_gettlv(tlvlist, 0x0004, 1))) { + faimdprintf(sess, 0, "no bigblock in top tlv in create room response\n"); + aim_freetlvchain(&tlvlist); + return 0; + } + + aim_bstream_init(&bbbs, bigblock->value, bigblock->length); + + exchange = aimbs_get16(&bbbs); + cklen = aimbs_get8(&bbbs); + ck = aimbs_getstr(&bbbs, cklen); + instance = aimbs_get16(&bbbs); + detaillevel = aimbs_get8(&bbbs); + + if (detaillevel != 0x02) { + faimdprintf(sess, 0, "unknown detaillevel in create room response (0x%02x)\n", detaillevel); + aim_freetlvchain(&tlvlist); + free(ck); + return 0; + } + + unknown = aimbs_get16(&bbbs); + + innerlist = aim_readtlvchain(&bbbs); + + if (aim_gettlv(innerlist, 0x006a, 1)) + fqcn = aim_gettlv_str(innerlist, 0x006a, 1); + + if (aim_gettlv(innerlist, 0x00c9, 1)) + flags = aim_gettlv16(innerlist, 0x00c9, 1); + + if (aim_gettlv(innerlist, 0x00ca, 1)) + createtime = aim_gettlv32(innerlist, 0x00ca, 1); + + if (aim_gettlv(innerlist, 0x00d1, 1)) + maxmsglen = aim_gettlv16(innerlist, 0x00d1, 1); + + if (aim_gettlv(innerlist, 0x00d2, 1)) + maxoccupancy = aim_gettlv16(innerlist, 0x00d2, 1); + + if (aim_gettlv(innerlist, 0x00d3, 1)) + name = aim_gettlv_str(innerlist, 0x00d3, 1); + + if (aim_gettlv(innerlist, 0x00d5, 1)) + createperms = aim_gettlv8(innerlist, 0x00d5, 1); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { + ret = userfunc(sess, rx, snac2->type, fqcn, instance, exchange, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck); + } + + free(ck); + free(name); + free(fqcn); + aim_freetlvchain(&innerlist); + aim_freetlvchain(&tlvlist); + + return ret; } /* - * Since multiple things can trigger this callback, - * we must lookup the snacid to determine the original - * snac subtype that was called. + * Since multiple things can trigger this callback, we must lookup the + * snacid to determine the original snac subtype that was called. */ -static int parseinfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int parseinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_snac_t *snac2; - int ret = 0; - - if (!(snac2 = aim_remsnac(sess, snac->id))) { - faimdprintf(sess, 0, "faim: chatnav_parse_info: received response to unknown request! (%08lx)\n", snac->id); - return 0; - } - - if (snac2->family != 0x000d) { - faimdprintf(sess, 0, "faim: chatnav_parse_info: recieved response that maps to corrupt request! (fam=%04x)\n", snac2->family); - return 0; - } - - /* - * We now know what the original SNAC subtype was. - */ - if (snac2->type == 0x0002) /* request chat rights */ - ret = parseinfo_perms(sess, mod, rx, snac, data, datalen, snac2); - else if (snac2->type == 0x0003) /* request exchange info */ - faimdprintf(sess, 0, "chatnav_parse_info: resposne to exchange info\n"); - else if (snac2->type == 0x0004) /* request room info */ - faimdprintf(sess, 0, "chatnav_parse_info: response to room info\n"); - else if (snac2->type == 0x0005) /* request more room info */ - faimdprintf(sess, 0, "chatnav_parse_info: response to more room info\n"); - else if (snac2->type == 0x0006) /* request occupant list */ - faimdprintf(sess, 0, "chatnav_parse_info: response to occupant info\n"); - else if (snac2->type == 0x0007) /* search for a room */ - faimdprintf(sess, 0, "chatnav_parse_info: search results\n"); - else if (snac2->type == 0x0008) /* create room */ - ret = parseinfo_create(sess, mod, rx, snac, data, datalen, snac2); - else - faimdprintf(sess, 0, "chatnav_parse_info: unknown request subtype (%04x)\n", snac2->type); - - if (snac2) - free(snac2->data); - free(snac2); - - return ret; + aim_snac_t *snac2; + int ret = 0; + + if (!(snac2 = aim_remsnac(sess, snac->id))) { + faimdprintf(sess, 0, "faim: chatnav_parse_info: received response to unknown request! (%08lx)\n", snac->id); + return 0; + } + + if (snac2->family != 0x000d) { + faimdprintf(sess, 0, "faim: chatnav_parse_info: recieved response that maps to corrupt request! (fam=%04x)\n", snac2->family); + return 0; + } + + /* + * We now know what the original SNAC subtype was. + */ + if (snac2->type == 0x0002) /* request chat rights */ + ret = parseinfo_perms(sess, mod, rx, snac, bs, snac2); + else if (snac2->type == 0x0003) /* request exchange info */ + faimdprintf(sess, 0, "chatnav_parse_info: resposne to exchange info\n"); + else if (snac2->type == 0x0004) /* request room info */ + faimdprintf(sess, 0, "chatnav_parse_info: response to room info\n"); + else if (snac2->type == 0x0005) /* request more room info */ + faimdprintf(sess, 0, "chatnav_parse_info: response to more room info\n"); + else if (snac2->type == 0x0006) /* request occupant list */ + faimdprintf(sess, 0, "chatnav_parse_info: response to occupant info\n"); + else if (snac2->type == 0x0007) /* search for a room */ + faimdprintf(sess, 0, "chatnav_parse_info: search results\n"); + else if (snac2->type == 0x0008) /* create room */ + ret = parseinfo_create(sess, mod, rx, snac, bs, snac2); + else + faimdprintf(sess, 0, "chatnav_parse_info: unknown request subtype (%04x)\n", snac2->type); + + if (snac2) + free(snac2->data); + free(snac2); + + return ret; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0009) - return parseinfo(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0009) + return parseinfo(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int chatnav_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int chatnav_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x000d; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "chatnav", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x000d; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "chatnav", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } diff --git a/src/conn.c b/src/conn.c index 517cb0c..0c61686 100644 --- a/src/conn.c +++ b/src/conn.c @@ -22,21 +22,25 @@ * Clears out the connection list and kills any connections left. * */ -static void aim_connrst(struct aim_session_t *sess) +static void aim_connrst(aim_session_t *sess) { - faim_mutex_init(&sess->connlistlock); - if (sess->connlist) { - struct aim_conn_t *cur = sess->connlist, *tmp; - - while(cur) { - tmp = cur->next; - aim_conn_close(cur); - free(cur); - cur = tmp; - } - } - sess->connlist = NULL; - return; + + faim_mutex_init(&sess->connlistlock); + + if (sess->connlist) { + aim_conn_t *cur = sess->connlist, *tmp; + + while (cur) { + tmp = cur->next; + aim_conn_close(cur); + free(cur); + cur = tmp; + } + } + + sess->connlist = NULL; + + return; } /** @@ -46,23 +50,24 @@ static void aim_connrst(struct aim_session_t *sess) * Initializes and/or resets a connection structure. * */ -static void aim_conn_init(struct aim_conn_t *deadconn) +static void aim_conn_init(aim_conn_t *deadconn) { - if (!deadconn) - return; - - deadconn->fd = -1; - deadconn->subtype = -1; - deadconn->type = -1; - deadconn->seqnum = 0; - deadconn->lastactivity = 0; - deadconn->forcedlatency = 0; - deadconn->handlerlist = NULL; - deadconn->priv = NULL; - faim_mutex_init(&deadconn->active); - faim_mutex_init(&deadconn->seqnum_lock); - - return; + + if (!deadconn) + return; + + deadconn->fd = -1; + deadconn->subtype = -1; + deadconn->type = -1; + deadconn->seqnum = 0; + deadconn->lastactivity = 0; + deadconn->forcedlatency = 0; + deadconn->handlerlist = NULL; + deadconn->priv = NULL; + faim_mutex_init(&deadconn->active); + faim_mutex_init(&deadconn->seqnum_lock); + + return; } /** @@ -72,28 +77,28 @@ static void aim_conn_init(struct aim_conn_t *deadconn) * Allocate a new empty connection structure. * */ -static struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess) +static aim_conn_t *aim_conn_getnext(aim_session_t *sess) { - struct aim_conn_t *newconn, *cur; - - if (!(newconn = malloc(sizeof(struct aim_conn_t)))) - return NULL; - - memset(newconn, 0, sizeof(struct aim_conn_t)); - aim_conn_init(newconn); - newconn->next = NULL; - - faim_mutex_lock(&sess->connlistlock); - if (sess->connlist == NULL) - sess->connlist = newconn; - else { - for (cur = sess->connlist; cur->next; cur = cur->next) - ; - cur->next = newconn; - } - faim_mutex_unlock(&sess->connlistlock); - - return newconn; + aim_conn_t *newconn, *cur; + + if (!(newconn = malloc(sizeof(aim_conn_t)))) + return NULL; + memset(newconn, 0, sizeof(aim_conn_t)); + + aim_conn_init(newconn); + newconn->next = NULL; + + faim_mutex_lock(&sess->connlistlock); + if (!sess->connlist) + sess->connlist = newconn; + else { + for (cur = sess->connlist; cur->next; cur = cur->next) + ; + cur->next = newconn; + } + faim_mutex_unlock(&sess->connlistlock); + + return newconn; } /** @@ -105,44 +110,44 @@ static struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess) * called from within libfaim. * */ -faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn) +faim_export void aim_conn_kill(aim_session_t *sess, aim_conn_t **deadconn) { - struct aim_conn_t *cur; - - if (!deadconn || !*deadconn) - return; - - aim_tx_cleanqueue(sess, *deadconn); - - faim_mutex_lock(&sess->connlistlock); - if (sess->connlist == NULL) - ; - else if (sess->connlist->next == NULL) { - if (sess->connlist == *deadconn) - sess->connlist = NULL; - } else { - cur = sess->connlist; - while (cur->next) { - if (cur->next == *deadconn) { - cur->next = cur->next->next; - break; - } - cur = cur->next; - } - } - faim_mutex_unlock(&sess->connlistlock); - - /* XXX: do we need this for txqueue too? */ - aim_rxqueue_cleanbyconn(sess, *deadconn); - - if ((*deadconn)->fd != -1) - aim_conn_close(*deadconn); - if ((*deadconn)->priv) - free((*deadconn)->priv); - free(*deadconn); - deadconn = NULL; - - return; + aim_conn_t *cur; + + if (!deadconn || !*deadconn) + return; + + aim_tx_cleanqueue(sess, *deadconn); + + faim_mutex_lock(&sess->connlistlock); + if (sess->connlist == NULL) + ; + else if (sess->connlist->next == NULL) { + if (sess->connlist == *deadconn) + sess->connlist = NULL; + } else { + cur = sess->connlist; + while (cur->next) { + if (cur->next == *deadconn) { + cur->next = cur->next->next; + break; + } + cur = cur->next; + } + } + faim_mutex_unlock(&sess->connlistlock); + + /* XXX: do we need this for txqueue too? */ + aim_rxqueue_cleanbyconn(sess, *deadconn); + + if ((*deadconn)->fd != -1) + aim_conn_close(*deadconn); + if ((*deadconn)->priv) + free((*deadconn)->priv); + free(*deadconn); + deadconn = NULL; + + return; } /** @@ -156,18 +161,18 @@ faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **d * dead connections). * */ -faim_export void aim_conn_close(struct aim_conn_t *deadconn) +faim_export void aim_conn_close(aim_conn_t *deadconn) { - faim_mutex_destroy(&deadconn->active); - faim_mutex_destroy(&deadconn->seqnum_lock); - if (deadconn->fd >= 3) - close(deadconn->fd); - deadconn->fd = -1; - if (deadconn->handlerlist) - aim_clearhandlers(deadconn); + faim_mutex_destroy(&deadconn->active); + faim_mutex_destroy(&deadconn->seqnum_lock); + if (deadconn->fd >= 3) + close(deadconn->fd); + deadconn->fd = -1; + if (deadconn->handlerlist) + aim_clearhandlers(deadconn); - return; + return; } /** @@ -180,50 +185,48 @@ faim_export void aim_conn_close(struct aim_conn_t *deadconn) * type found. * */ -faim_export struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess, - int type) +faim_export aim_conn_t *aim_getconn_type(aim_session_t *sess, int type) { - struct aim_conn_t *cur; + aim_conn_t *cur; - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if ((cur->type == type) && !(cur->status & AIM_CONN_STATUS_INPROGRESS)) - break; - } - faim_mutex_unlock(&sess->connlistlock); + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if ((cur->type == type) && + !(cur->status & AIM_CONN_STATUS_INPROGRESS)) + break; + } + faim_mutex_unlock(&sess->connlistlock); - return cur; + return cur; } -faim_export struct aim_conn_t *aim_getconn_type_all(struct aim_session_t *sess, - int type) +faim_export aim_conn_t *aim_getconn_type_all(aim_session_t *sess, int type) { - struct aim_conn_t *cur; + aim_conn_t *cur; - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->type == type) - break; - } - faim_mutex_unlock(&sess->connlistlock); + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (cur->type == type) + break; + } + faim_mutex_unlock(&sess->connlistlock); - return cur; + return cur; } /* If you pass -1 for the fd, you'll get what you ask for. Gibberish. */ -faim_export struct aim_conn_t *aim_getconn_fd(struct aim_session_t *sess, - int fd) +faim_export aim_conn_t *aim_getconn_fd(aim_session_t *sess, int fd) { - struct aim_conn_t *cur; + aim_conn_t *cur; - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->fd == fd) - break; - } - faim_mutex_unlock(&sess->connlistlock); + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (cur->fd == fd) + break; + } + faim_mutex_unlock(&sess->connlistlock); - return cur; + return cur; } /** @@ -237,161 +240,162 @@ faim_export struct aim_conn_t *aim_getconn_fd(struct aim_session_t *sess, * proxy settings, if present. If no proxy is configured for * this session, the connection is done directly. * + * XXX this is really awful. + * */ -static int aim_proxyconnect(struct aim_session_t *sess, - char *host, unsigned short port, - int *statusret) +static int aim_proxyconnect(aim_session_t *sess, const char *host, fu16_t port, fu32_t *statusret) { - int fd = -1; - - if (strlen(sess->socksproxy.server)) { /* connecting via proxy */ - int i; - unsigned char buf[512]; - struct sockaddr_in sa; - struct hostent *hp; - char *proxy; - unsigned short proxyport = 1080; - - for(i=0;i<(int)strlen(sess->socksproxy.server);i++) { - if (sess->socksproxy.server[i] == ':') { - proxyport = atoi(&(sess->socksproxy.server[i+1])); - break; - } - } - proxy = (char *)malloc(i+1); - strncpy(proxy, sess->socksproxy.server, i); - proxy[i] = '\0'; - - if (!(hp = gethostbyname(proxy))) { - faimdprintf(sess, 0, "proxyconnect: unable to resolve proxy name\n"); - *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); - return -1; - } - free(proxy); - - memset(&sa.sin_zero, 0, 8); - sa.sin_port = htons(proxyport); - memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); - sa.sin_family = hp->h_addrtype; - - fd = socket(hp->h_addrtype, SOCK_STREAM, 0); - if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { - faimdprintf(sess, 0, "proxyconnect: unable to connect to proxy\n"); - close(fd); - return -1; - } - - i = 0; - buf[0] = 0x05; /* SOCKS version 5 */ - if (strlen(sess->socksproxy.username)) { - buf[1] = 0x02; /* two methods */ - buf[2] = 0x00; /* no authentication */ - buf[3] = 0x02; /* username/password authentication */ - i = 4; - } else { - buf[1] = 0x01; - buf[2] = 0x00; - i = 3; - } - - if (write(fd, buf, i) < i) { - *statusret = errno; - close(fd); - return -1; - } - - if (read(fd, buf, 2) < 2) { - *statusret = errno; - close(fd); - return -1; - } - - if ((buf[0] != 0x05) || (buf[1] == 0xff)) { - *statusret = EINVAL; - close(fd); - return -1; - } - - /* check if we're doing username authentication */ - if (buf[1] == 0x02) { - i = aimutil_put8(buf, 0x01); /* version 1 */ - i += aimutil_put8(buf+i, strlen(sess->socksproxy.username)); - i += aimutil_putstr(buf+i, sess->socksproxy.username, strlen(sess->socksproxy.username)); - i += aimutil_put8(buf+i, strlen(sess->socksproxy.password)); - i += aimutil_putstr(buf+i, sess->socksproxy.password, strlen(sess->socksproxy.password)); - if (write(fd, buf, i) < i) { - *statusret = errno; - close(fd); - return -1; - } - if (read(fd, buf, 2) < 2) { - *statusret = errno; - close(fd); - return -1; - } - if ((buf[0] != 0x01) || (buf[1] != 0x00)) { - *statusret = EINVAL; - close(fd); - return -1; - } - } - - i = aimutil_put8(buf, 0x05); - i += aimutil_put8(buf+i, 0x01); /* CONNECT */ - i += aimutil_put8(buf+i, 0x00); /* reserved */ - i += aimutil_put8(buf+i, 0x03); /* address type: host name */ - i += aimutil_put8(buf+i, strlen(host)); - i += aimutil_putstr(buf+i, host, strlen(host)); - i += aimutil_put16(buf+i, port); - - if (write(fd, buf, i) < i) { - *statusret = errno; - close(fd); - return -1; - } - if (read(fd, buf, 10) < 10) { - *statusret = errno; - close(fd); - return -1; - } - if ((buf[0] != 0x05) || (buf[1] != 0x00)) { - *statusret = EINVAL; - close(fd); - return -1; - } - - } else { /* connecting directly */ - struct sockaddr_in sa; - struct hostent *hp; - - if (!(hp = gethostbyname(host))) { - *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); - return -1; - } - - memset(&sa, 0, sizeof(struct sockaddr_in)); - sa.sin_port = htons(port); - memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); - sa.sin_family = hp->h_addrtype; - - fd = socket(hp->h_addrtype, SOCK_STREAM, 0); - - if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) - fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */ - - if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { - if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) { - if ((errno == EINPROGRESS) || (errno == EINTR)) { - if (statusret) - *statusret |= AIM_CONN_STATUS_INPROGRESS; - return fd; + int fd = -1; + + if (strlen(sess->socksproxy.server)) { /* connecting via proxy */ + int i; + unsigned char buf[512]; + struct sockaddr_in sa; + struct hostent *hp; + char *proxy; + unsigned short proxyport = 1080; + + for(i=0;i<(int)strlen(sess->socksproxy.server);i++) { + if (sess->socksproxy.server[i] == ':') { + proxyport = atoi(&(sess->socksproxy.server[i+1])); + break; + } + } + + proxy = (char *)malloc(i+1); + strncpy(proxy, sess->socksproxy.server, i); + proxy[i] = '\0'; + + if (!(hp = gethostbyname(proxy))) { + faimdprintf(sess, 0, "proxyconnect: unable to resolve proxy name\n"); + *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); + return -1; + } + free(proxy); + + memset(&sa.sin_zero, 0, 8); + sa.sin_port = htons(proxyport); + memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); + sa.sin_family = hp->h_addrtype; + + fd = socket(hp->h_addrtype, SOCK_STREAM, 0); + if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { + faimdprintf(sess, 0, "proxyconnect: unable to connect to proxy\n"); + close(fd); + return -1; + } + + i = 0; + buf[0] = 0x05; /* SOCKS version 5 */ + if (strlen(sess->socksproxy.username)) { + buf[1] = 0x02; /* two methods */ + buf[2] = 0x00; /* no authentication */ + buf[3] = 0x02; /* username/password authentication */ + i = 4; + } else { + buf[1] = 0x01; + buf[2] = 0x00; + i = 3; + } + + if (write(fd, buf, i) < i) { + *statusret = errno; + close(fd); + return -1; + } + + if (read(fd, buf, 2) < 2) { + *statusret = errno; + close(fd); + return -1; + } + + if ((buf[0] != 0x05) || (buf[1] == 0xff)) { + *statusret = EINVAL; + close(fd); + return -1; + } + + /* check if we're doing username authentication */ + if (buf[1] == 0x02) { + i = aimutil_put8(buf, 0x01); /* version 1 */ + i += aimutil_put8(buf+i, strlen(sess->socksproxy.username)); + i += aimutil_putstr(buf+i, sess->socksproxy.username, strlen(sess->socksproxy.username)); + i += aimutil_put8(buf+i, strlen(sess->socksproxy.password)); + i += aimutil_putstr(buf+i, sess->socksproxy.password, strlen(sess->socksproxy.password)); + if (write(fd, buf, i) < i) { + *statusret = errno; + close(fd); + return -1; + } + if (read(fd, buf, 2) < 2) { + *statusret = errno; + close(fd); + return -1; + } + if ((buf[0] != 0x01) || (buf[1] != 0x00)) { + *statusret = EINVAL; + close(fd); + return -1; + } + } + + i = aimutil_put8(buf, 0x05); + i += aimutil_put8(buf+i, 0x01); /* CONNECT */ + i += aimutil_put8(buf+i, 0x00); /* reserved */ + i += aimutil_put8(buf+i, 0x03); /* address type: host name */ + i += aimutil_put8(buf+i, strlen(host)); + i += aimutil_putstr(buf+i, host, strlen(host)); + i += aimutil_put16(buf+i, port); + + if (write(fd, buf, i) < i) { + *statusret = errno; + close(fd); + return -1; + } + if (read(fd, buf, 10) < 10) { + *statusret = errno; + close(fd); + return -1; + } + if ((buf[0] != 0x05) || (buf[1] != 0x00)) { + *statusret = EINVAL; + close(fd); + return -1; + } + + } else { /* connecting directly */ + struct sockaddr_in sa; + struct hostent *hp; + + if (!(hp = gethostbyname(host))) { + *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); + return -1; + } + + memset(&sa, 0, sizeof(struct sockaddr_in)); + sa.sin_port = htons(port); + memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); + sa.sin_family = hp->h_addrtype; + + fd = socket(hp->h_addrtype, SOCK_STREAM, 0); + + if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) + fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */ + + if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { + if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) { + if ((errno == EINPROGRESS) || (errno == EINTR)) { + if (statusret) + *statusret |= AIM_CONN_STATUS_INPROGRESS; + return fd; + } + } + close(fd); + fd = -1; + } } - } - close(fd); - fd = -1; - } - } - return fd; + return fd; } /** @@ -407,35 +411,28 @@ static int aim_proxyconnect(struct aim_session_t *sess, * This function returns a pointer to the new aim_conn_t, or %NULL on * error */ -faim_internal struct aim_conn_t *aim_cloneconn(struct aim_session_t *sess, - struct aim_conn_t *src) +faim_internal aim_conn_t *aim_cloneconn(aim_session_t *sess, aim_conn_t *src) { - struct aim_conn_t *conn; - struct aim_rxcblist_t *cur; - - if (!(conn = aim_conn_getnext(sess))) - return NULL; + aim_conn_t *conn; - faim_mutex_lock(&conn->active); + if (!(conn = aim_conn_getnext(sess))) + return NULL; - conn->fd = src->fd; - conn->type = src->type; - conn->subtype = src->subtype; - conn->seqnum = src->seqnum; - conn->priv = src->priv; - conn->lastactivity = src->lastactivity; - conn->forcedlatency = src->forcedlatency; - conn->sessv = src->sessv; + faim_mutex_lock(&conn->active); - /* clone handler list */ - for (cur = src->handlerlist; cur; cur = cur->next) { - aim_conn_addhandler(sess, conn, cur->family, cur->type, - cur->handler, cur->flags); - } + conn->fd = src->fd; + conn->type = src->type; + conn->subtype = src->subtype; + conn->seqnum = src->seqnum; + conn->priv = src->priv; + conn->lastactivity = src->lastactivity; + conn->forcedlatency = src->forcedlatency; + conn->sessv = src->sessv; + aim_clonehandlers(sess, conn, src); - faim_mutex_unlock(&conn->active); + faim_mutex_unlock(&conn->active); - return conn; + return conn; } /** @@ -452,63 +449,62 @@ faim_internal struct aim_conn_t *aim_cloneconn(struct aim_session_t *sess, * FIXME: Return errors in a more sane way. * */ -faim_export struct aim_conn_t *aim_newconn(struct aim_session_t *sess, - int type, char *dest) +faim_export aim_conn_t *aim_newconn(aim_session_t *sess, int type, const char *dest) { - struct aim_conn_t *connstruct; - int ret; - u_short port = FAIM_LOGIN_PORT; - char *host = NULL; - int i=0; - - if ((connstruct=aim_conn_getnext(sess))==NULL) - return NULL; - - faim_mutex_lock(&connstruct->active); - - connstruct->sessv = (void *)sess; - connstruct->type = type; - - if (!dest) { /* just allocate a struct */ - connstruct->fd = -1; - connstruct->status = 0; - faim_mutex_unlock(&connstruct->active); - return connstruct; - } - - /* - * As of 23 Jul 1999, AOL now sends the port number, preceded by a - * colon, in the BOS redirect. This fatally breaks all previous - * libfaims. Bad, bad AOL. - * - * We put this here to catch every case. - * - */ - - for(i=0;i<(int)strlen(dest);i++) { - if (dest[i] == ':') { - port = atoi(&(dest[i+1])); - break; - } - } - host = (char *)malloc(i+1); - strncpy(host, dest, i); - host[i] = '\0'; - - if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) { - connstruct->fd = -1; - connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); - free(host); - faim_mutex_unlock(&connstruct->active); - return connstruct; - } else - connstruct->fd = ret; - - faim_mutex_unlock(&connstruct->active); - - free(host); - - return connstruct; + aim_conn_t *connstruct; + fu16_t port = FAIM_LOGIN_PORT; + char *host; + int i, ret; + + if (!(connstruct = aim_conn_getnext(sess))) + return NULL; + + faim_mutex_lock(&connstruct->active); + + connstruct->sessv = (void *)sess; + connstruct->type = type; + + if (!dest) { /* just allocate a struct */ + connstruct->fd = -1; + connstruct->status = 0; + faim_mutex_unlock(&connstruct->active); + return connstruct; + } + + /* + * As of 23 Jul 1999, AOL now sends the port number, preceded by a + * colon, in the BOS redirect. This fatally breaks all previous + * libfaims. Bad, bad AOL. + * + * We put this here to catch every case. + * + */ + + for(i = 0; i < (int)strlen(dest); i++) { + if (dest[i] == ':') { + port = atoi(&(dest[i+1])); + break; + } + } + + host = (char *)malloc(i+1); + strncpy(host, dest, i); + host[i] = '\0'; + + if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) { + connstruct->fd = -1; + connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); + free(host); + faim_mutex_unlock(&connstruct->active); + return connstruct; + } else + connstruct->fd = ret; + + faim_mutex_unlock(&connstruct->active); + + free(host); + + return connstruct; } /** @@ -519,19 +515,19 @@ faim_export struct aim_conn_t *aim_newconn(struct aim_session_t *sess, * connections in @sess. * */ -faim_export int aim_conngetmaxfd(struct aim_session_t *sess) +faim_export int aim_conngetmaxfd(aim_session_t *sess) { - int j = 0; - struct aim_conn_t *cur; + int j; + aim_conn_t *cur; - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->fd > j) - j = cur->fd; - } - faim_mutex_unlock(&sess->connlistlock); + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist, j = 0; cur; cur = cur->next) { + if (cur->fd > j) + j = cur->fd; + } + faim_mutex_unlock(&sess->connlistlock); - return j; + return j; } /** @@ -543,18 +539,20 @@ faim_export int aim_conngetmaxfd(struct aim_session_t *sess) * zero otherwise. * */ -faim_export int aim_conn_in_sess(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_conn_in_sess(aim_session_t *sess, aim_conn_t *conn) { - struct aim_conn_t *cur; - - faim_mutex_lock(&sess->connlistlock); - for(cur = sess->connlist; cur; cur = cur->next) - if(cur == conn) { - faim_mutex_unlock(&sess->connlistlock); - return 1; - } - faim_mutex_unlock(&sess->connlistlock); - return 0; + aim_conn_t *cur; + + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (cur == conn) { + faim_mutex_unlock(&sess->connlistlock); + return 1; + } + } + faim_mutex_unlock(&sess->connlistlock); + + return 0; } /** @@ -575,126 +573,80 @@ faim_export int aim_conn_in_sess(struct aim_session_t *sess, struct aim_conn_t * * XXX: we could probably stand to do a little courser locking here. * */ -faim_export struct aim_conn_t *aim_select(struct aim_session_t *sess, - struct timeval *timeout, - int *status) +faim_export aim_conn_t *aim_select(aim_session_t *sess, struct timeval *timeout, int *status) { - struct aim_conn_t *cur; - fd_set fds, wfds; - int maxfd = 0; - int i, haveconnecting = 0; - - faim_mutex_lock(&sess->connlistlock); - if (sess->connlist == NULL) { - faim_mutex_unlock(&sess->connlistlock); - *status = -1; - return NULL; - } - faim_mutex_unlock(&sess->connlistlock); - - FD_ZERO(&fds); - FD_ZERO(&wfds); - maxfd = 0; - - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if (cur->fd == -1) { - /* don't let invalid/dead connections sit around */ - *status = 2; - faim_mutex_unlock(&sess->connlistlock); - return cur; - } else if (cur->status & AIM_CONN_STATUS_INPROGRESS) { - FD_SET(cur->fd, &wfds); - - haveconnecting++; - } - FD_SET(cur->fd, &fds); - if (cur->fd > maxfd) - maxfd = cur->fd; - } - faim_mutex_unlock(&sess->connlistlock); - - /* - * If we have data waiting to be sent, return - * - * We have to not do this if theres at least one - * connection thats still connecting, since that connection - * may have queued data and this return would prevent - * the connection from ever completing! This is a major - * inadequacy of the libfaim way of doing things. It means - * that nothing can transmit as long as there's connecting - * sockets. Evil. - * - * But its still better than having blocking connects. - * - */ - if (!haveconnecting && (sess->queue_outgoing != NULL)) { - *status = 1; - return NULL; - } - - if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) { - faim_mutex_lock(&sess->connlistlock); - for (cur = sess->connlist; cur; cur = cur->next) { - if ((FD_ISSET(cur->fd, &fds)) || - ((cur->status & AIM_CONN_STATUS_INPROGRESS) && - FD_ISSET(cur->fd, &wfds))) { - *status = 2; + aim_conn_t *cur; + fd_set fds, wfds; + int maxfd, i, haveconnecting = 0; + + faim_mutex_lock(&sess->connlistlock); + if (!sess->connlist) { + faim_mutex_unlock(&sess->connlistlock); + *status = -1; + return NULL; + } faim_mutex_unlock(&sess->connlistlock); - return cur; /* XXX race condition here -- shouldnt unlock connlist */ - } - } - *status = 0; /* shouldn't happen */ - } else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */ - *status = 0; - else - *status = i; /* can be 0 or -1 */ - - faim_mutex_unlock(&sess->connlistlock); - - return NULL; /* no waiting or error, return */ -} -/** - * aim_conn_isready - Test if a connection is marked ready - * @conn: Connection to test - * - * Returns true if the connection is ready, false otherwise. - * Returns -1 if the connection is invalid. - * - * XXX: This is deprecated. - * - */ -faim_export int aim_conn_isready(struct aim_conn_t *conn) -{ - if (conn) - return (conn->status & 0x0001); - return -1; -} + FD_ZERO(&fds); + FD_ZERO(&wfds); + + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist, maxfd = 0; cur; cur = cur->next) { + if (cur->fd == -1) { + /* don't let invalid/dead connections sit around */ + *status = 2; + faim_mutex_unlock(&sess->connlistlock); + return cur; + } else if (cur->status & AIM_CONN_STATUS_INPROGRESS) { + FD_SET(cur->fd, &wfds); + + haveconnecting++; + } + FD_SET(cur->fd, &fds); + if (cur->fd > maxfd) + maxfd = cur->fd; + } + faim_mutex_unlock(&sess->connlistlock); -/** - * aim_conn_setstatus - Set the status of a connection - * @conn: Connection - * @status: New status - * - * @newstatus is %XOR'd with the previous value of the connection - * status and returned. Returns -1 if the connection is invalid. - * - * This isn't real useful. - * - */ -faim_export int aim_conn_setstatus(struct aim_conn_t *conn, int status) -{ - int val; + /* + * If we have data waiting to be sent, return + * + * We have to not do this if theres at least one + * connection thats still connecting, since that connection + * may have queued data and this return would prevent + * the connection from ever completing! This is a major + * inadequacy of the libfaim way of doing things. It means + * that nothing can transmit as long as there's connecting + * sockets. Evil. + * + * But its still better than having blocking connects. + * + */ + if (!haveconnecting && sess->queue_outgoing) { + *status = 1; + return NULL; + } + + if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) { + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if ((FD_ISSET(cur->fd, &fds)) || + ((cur->status & AIM_CONN_STATUS_INPROGRESS) && + FD_ISSET(cur->fd, &wfds))) { + *status = 2; + faim_mutex_unlock(&sess->connlistlock); + return cur; /* XXX race condition here -- shouldnt unlock connlist */ + } + } + *status = 0; /* shouldn't happen */ + } else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */ + *status = 0; + else + *status = i; /* can be 0 or -1 */ - if (!conn) - return -1; - - faim_mutex_lock(&conn->active); - val = conn->status ^= status; - faim_mutex_unlock(&conn->active); + faim_mutex_unlock(&sess->connlistlock); - return val; + return NULL; /* no waiting or error, return */ } /** @@ -711,17 +663,18 @@ faim_export int aim_conn_setstatus(struct aim_conn_t *conn, int status) * backs off like the real rate limiting does. * */ -faim_export int aim_conn_setlatency(struct aim_conn_t *conn, int newval) +faim_export int aim_conn_setlatency(aim_conn_t *conn, int newval) { - if (!conn) - return -1; - faim_mutex_lock(&conn->active); - conn->forcedlatency = newval; - conn->lastactivity = 0; /* reset this just to make sure */ - faim_mutex_unlock(&conn->active); + if (!conn) + return -1; + + faim_mutex_lock(&conn->active); + conn->forcedlatency = newval; + conn->lastactivity = 0; /* reset this just to make sure */ + faim_mutex_unlock(&conn->active); - return 0; + return 0; } /** @@ -738,27 +691,31 @@ faim_export int aim_conn_setlatency(struct aim_conn_t *conn, int newval) * Set username and password to %NULL if not applicable. * */ -faim_export void aim_setupproxy(struct aim_session_t *sess, char *server, char *username, char *password) +faim_export void aim_setupproxy(aim_session_t *sess, const char *server, const char *username, const char *password) { - /* clear out the proxy info */ - if (!server || !strlen(server)) { - memset(sess->socksproxy.server, 0, sizeof(sess->socksproxy.server)); - memset(sess->socksproxy.username, 0, sizeof(sess->socksproxy.username)); - memset(sess->socksproxy.password, 0, sizeof(sess->socksproxy.password)); - return; - } - - strncpy(sess->socksproxy.server, server, sizeof(sess->socksproxy.server)); - if (username && strlen(username)) - strncpy(sess->socksproxy.username, username, sizeof(sess->socksproxy.username)); - if (password && strlen(password)) - strncpy(sess->socksproxy.password, password, sizeof(sess->socksproxy.password)); - return; + /* clear out the proxy info */ + if (!server || !strlen(server)) { + memset(sess->socksproxy.server, 0, sizeof(sess->socksproxy.server)); + memset(sess->socksproxy.username, 0, sizeof(sess->socksproxy.username)); + memset(sess->socksproxy.password, 0, sizeof(sess->socksproxy.password)); + return; + } + + strncpy(sess->socksproxy.server, server, sizeof(sess->socksproxy.server)); + if (username && strlen(username)) + strncpy(sess->socksproxy.username, username, sizeof(sess->socksproxy.username)); + if (password && strlen(password)) + strncpy(sess->socksproxy.password, password, sizeof(sess->socksproxy.password)); + + return; } -static void defaultdebugcb(struct aim_session_t *sess, int level, const char *format, va_list va) +static void defaultdebugcb(aim_session_t *sess, int level, const char *format, va_list va) { - vfprintf(stderr, format, va); + + vfprintf(stderr, format, va); + + return; } /** @@ -770,74 +727,74 @@ static void defaultdebugcb(struct aim_session_t *sess, int level, const char *fo * Sets up the initial values for a session. * */ -faim_export void aim_session_init(struct aim_session_t *sess, unsigned long flags, int debuglevel) +faim_export void aim_session_init(aim_session_t *sess, fu32_t flags, int debuglevel) { - if (!sess) - return; - - memset(sess, 0, sizeof(struct aim_session_t)); - aim_connrst(sess); - sess->queue_outgoing = NULL; - sess->queue_incoming = NULL; - sess->pendingjoin = NULL; - sess->pendingjoinexchange = 0; - aim_initsnachash(sess); - sess->msgcookies = NULL; - sess->snac_nextid = 0x00000001; - - sess->flags = 0; - sess->debug = debuglevel; - sess->debugcb = defaultdebugcb; - - sess->modlistv = NULL; - - /* - * Default to SNAC login unless XORLOGIN is explicitly set. - */ - if (!(flags & AIM_SESS_FLAGS_XORLOGIN)) - sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; - sess->flags |= flags; - - /* - * This must always be set. Default to the queue-based - * version for back-compatibility. - */ - aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL); - - - /* - * Register all the modules for this session... - */ - aim__registermodule(sess, misc_modfirst); /* load the catch-all first */ - aim__registermodule(sess, buddylist_modfirst); - aim__registermodule(sess, admin_modfirst); - aim__registermodule(sess, bos_modfirst); - aim__registermodule(sess, search_modfirst); - aim__registermodule(sess, stats_modfirst); - aim__registermodule(sess, auth_modfirst); - aim__registermodule(sess, msg_modfirst); - aim__registermodule(sess, chatnav_modfirst); - aim__registermodule(sess, chat_modfirst); - aim__registermodule(sess, locate_modfirst); - aim__registermodule(sess, general_modfirst); - - return; + + if (!sess) + return; + + memset(sess, 0, sizeof(aim_session_t)); + aim_connrst(sess); + sess->queue_outgoing = NULL; + sess->queue_incoming = NULL; + sess->pendingjoin = NULL; + sess->pendingjoinexchange = 0; + aim_initsnachash(sess); + sess->msgcookies = NULL; + sess->snacid_next = 0x00000001; + + sess->flags = 0; + sess->debug = debuglevel; + sess->debugcb = defaultdebugcb; + + sess->modlistv = NULL; + + /* + * Default to SNAC login unless XORLOGIN is explicitly set. + */ + if (!(flags & AIM_SESS_FLAGS_XORLOGIN)) + sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; + sess->flags |= flags; + + /* + * This must always be set. Default to the queue-based + * version for back-compatibility. + */ + aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL); + + + /* + * Register all the modules for this session... + */ + aim__registermodule(sess, misc_modfirst); /* load the catch-all first */ + aim__registermodule(sess, buddylist_modfirst); + aim__registermodule(sess, admin_modfirst); + aim__registermodule(sess, bos_modfirst); + aim__registermodule(sess, search_modfirst); + aim__registermodule(sess, stats_modfirst); + aim__registermodule(sess, auth_modfirst); + aim__registermodule(sess, msg_modfirst); + aim__registermodule(sess, chatnav_modfirst); + aim__registermodule(sess, chat_modfirst); + aim__registermodule(sess, locate_modfirst); + aim__registermodule(sess, general_modfirst); + + return; } /** * aim_session_kill - Deallocate a session * @sess: Session to kill * - * */ -faim_export void aim_session_kill(struct aim_session_t *sess) +faim_export void aim_session_kill(aim_session_t *sess) { - aim_logoff(sess); + aim_logoff(sess); - aim__shutdownmodules(sess); + aim__shutdownmodules(sess); - return; + return; } /** @@ -850,15 +807,15 @@ faim_export void aim_session_kill(struct aim_session_t *sess) * the value faimdprintf was called with. * */ -faim_export int aim_setdebuggingcb(struct aim_session_t *sess, faim_debugging_callback_t cb) +faim_export int aim_setdebuggingcb(aim_session_t *sess, faim_debugging_callback_t cb) { - if (!sess) - return -1; + if (!sess) + return -1; - sess->debugcb = cb; + sess->debugcb = cb; - return 0; + return 0; } /** @@ -870,76 +827,81 @@ faim_export int aim_setdebuggingcb(struct aim_session_t *sess, faim_debugging_ca * has yet to be called on it). * */ -faim_export int aim_conn_isconnecting(struct aim_conn_t *conn) +faim_export int aim_conn_isconnecting(aim_conn_t *conn) { - if (!conn) - return 0; - return (conn->status & AIM_CONN_STATUS_INPROGRESS)?1:0; + + if (!conn) + return 0; + + return !!(conn->status & AIM_CONN_STATUS_INPROGRESS); } -faim_export int aim_conn_completeconnect(struct aim_session_t *sess, struct aim_conn_t *conn) +/* + * XXX this is nearly as ugly as proxyconnect(). + */ +faim_export int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn) { - fd_set fds, wfds; - struct timeval tv; - int res, error = ETIMEDOUT; - aim_rxcallback_t userfunc; - - if (!conn || (conn->fd == -1)) - return -1; - - if (!(conn->status & AIM_CONN_STATUS_INPROGRESS)) - return -1; - - FD_ZERO(&fds); - FD_SET(conn->fd, &fds); - FD_ZERO(&wfds); - FD_SET(conn->fd, &wfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - - if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) { - error = errno; - aim_conn_close(conn); - errno = error; - return -1; - } else if (res == 0) { - faimdprintf(sess, 0, "aim_conn_completeconnect: false alarm on %d\n", conn->fd); - return 0; /* hasn't really completed yet... */ - } - - if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) { - int len = sizeof(error); - - if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) - error = errno; - } - - if (error) { - aim_conn_close(conn); - errno = error; - return -1; - } - - fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */ - - conn->status &= ~AIM_CONN_STATUS_INPROGRESS; - - if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE))) - userfunc(sess, NULL, conn); - - /* Flush out the queues if there was something waiting for this conn */ - aim_tx_flushqueue(sess); - - return 0; + fd_set fds, wfds; + struct timeval tv; + int res, error = ETIMEDOUT; + aim_rxcallback_t userfunc; + + if (!conn || (conn->fd == -1)) + return -1; + + if (!(conn->status & AIM_CONN_STATUS_INPROGRESS)) + return -1; + + FD_ZERO(&fds); + FD_SET(conn->fd, &fds); + FD_ZERO(&wfds); + FD_SET(conn->fd, &wfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) { + error = errno; + aim_conn_close(conn); + errno = error; + return -1; + } else if (res == 0) { + faimdprintf(sess, 0, "aim_conn_completeconnect: false alarm on %d\n", conn->fd); + return 0; /* hasn't really completed yet... */ + } + + if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) { + int len = sizeof(error); + + if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) + error = errno; + } + + if (error) { + aim_conn_close(conn); + errno = error; + return -1; + } + + fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */ + + conn->status &= ~AIM_CONN_STATUS_INPROGRESS; + + if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE))) + userfunc(sess, NULL, conn); + + /* Flush out the queues if there was something waiting for this conn */ + aim_tx_flushqueue(sess); + + return 0; } -faim_export struct aim_session_t *aim_conn_getsess(struct aim_conn_t *conn) +faim_export aim_session_t *aim_conn_getsess(aim_conn_t *conn) { - if (!conn) - return NULL; + if (!conn) + return NULL; - return (struct aim_session_t *)conn->sessv; + return (aim_session_t *)conn->sessv; } /* @@ -948,12 +910,12 @@ faim_export struct aim_session_t *aim_conn_getsess(struct aim_conn_t *conn) * Closes -ALL- open connections. * */ -faim_export int aim_logoff(struct aim_session_t *sess) +faim_export int aim_logoff(aim_session_t *sess) { - aim_connrst(sess); /* in case we want to connect again */ + aim_connrst(sess); /* in case we want to connect again */ - return 0; + return 0; } diff --git a/src/ft.c b/src/ft.c index c9f4a9b..fabd309 100644 --- a/src/ft.c +++ b/src/ft.c @@ -17,6 +17,8 @@ #endif +#if 0 + /* TODO: o look for memory leaks.. there's going to be shitloads, i'm sure. */ @@ -109,7 +111,8 @@ faim_export int aim_handlerendconnect(struct aim_session_t *sess, struct aim_con return ret; } - +#endif + /** * aim_send_im_direct - send IM client-to-client over established connection * @sess: session to conn @@ -119,8 +122,10 @@ faim_export int aim_handlerendconnect(struct aim_session_t *sess, struct aim_con * Call this just like you would aim_send_im, to send a directim. You * _must_ have previously established the directim connection. */ -faim_export int aim_send_im_direct(struct aim_session_t *sess, struct aim_conn_t *conn, char *msg) +faim_export int aim_send_im_direct(aim_session_t *sess, aim_conn_t *conn, const char *msg) { + return -EINVAL; +#if 0 struct command_tx_struct *newpacket; struct aim_directim_priv *priv = NULL; int i; @@ -146,14 +151,14 @@ faim_export int aim_send_im_direct(struct aim_session_t *sess, struct aim_conn_t newpacket->hdr.oft.hdr2len = 0x54; if (!(newpacket->hdr.oft.hdr2 = calloc(1,newpacket->hdr.oft.hdr2len))) { newpacket->lock = 0; - aim_tx_destroy(newpacket); + aim_frame_destroy(newpacket); return -1; } } else { newpacket->hdr.oft.hdr2len = 0x44; if (!(newpacket->hdr.oft.hdr2 = calloc(1,newpacket->hdr.oft.hdr2len))) { newpacket->lock = 0; - aim_tx_destroy(newpacket); + aim_frame_destroy(newpacket); return -1; } } @@ -211,7 +216,9 @@ faim_export int aim_send_im_direct(struct aim_session_t *sess, struct aim_conn_t } newpacket->lock = 0; aim_tx_enqueue(sess, newpacket); + return 0; +#endif } /* XXX: give the client author the responsibility of setting up a @@ -226,12 +233,10 @@ faim_export int aim_send_im_direct(struct aim_session_t *sess, struct aim_conn_t * @destsn: the SN to connect to. * */ -faim_export struct aim_conn_t *aim_directim_initiate(struct aim_session_t *sess, - struct aim_conn_t *conn, - struct aim_directim_priv *priv, - char *destsn) +faim_export aim_conn_t *aim_directim_initiate(aim_session_t *sess, aim_conn_t *conn, struct aim_directim_priv *priv, const char *destsn) { - + return NULL; +#if 0 struct command_tx_struct *newpacket; struct aim_conn_t *newconn; struct aim_msgcookie_t *cookie; @@ -349,8 +354,10 @@ faim_export struct aim_conn_t *aim_directim_initiate(struct aim_session_t *sess, faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); return newconn; +#endif } +#if 0 /** * unsigned int aim_oft_listener_clean - close up old listeners * @sess: session to clean up in @@ -381,6 +388,7 @@ faim_export unsigned int aim_oft_listener_clean(struct aim_session_t *sess, time faim_mutex_unlock(&sess->connlistlock); return hit; } +#endif /** * aim_directim_connect - connect to buddy for directim @@ -390,8 +398,10 @@ faim_export unsigned int aim_oft_listener_clean(struct aim_session_t *sess, time * * returns conn if connected, %NULL on error */ -faim_export struct aim_conn_t *aim_directim_connect(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_directim_priv *priv) +faim_export aim_conn_t *aim_directim_connect(aim_session_t *sess, aim_conn_t *conn, struct aim_directim_priv *priv) { + return NULL; +#if 0 struct aim_conn_t *newconn = NULL; if (!sess || !conn || !priv) @@ -410,8 +420,10 @@ faim_export struct aim_conn_t *aim_directim_connect(struct aim_session_t *sess, faimdprintf(sess, 2, "faim: connected to peer (fd = %d)\n", newconn->fd); return newconn; +#endif } +#if 0 /** * aim_directim_getconn - find a directim conn for buddy name * @sess: your session, @@ -439,6 +451,7 @@ faim_export struct aim_conn_t *aim_directim_getconn(struct aim_session_t *sess, } faim_mutex_unlock(&sess->connlistlock); return cur; } +#endif /** * aim_accepttransfer - accept a file transfer request @@ -454,17 +467,21 @@ faim_export struct aim_conn_t *aim_directim_getconn(struct aim_session_t *sess, * @rendid: capability type (%AIM_CAPS_GETFILE or %AIM_CAPS_SENDFILE) * * Returns new connection or %NULL on error. + * + * XXX this should take a struct. */ -faim_export struct aim_conn_t *aim_accepttransfer(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *sn, char *cookie, - char *ip, - unsigned short listingfiles, - unsigned short listingtotsize, - unsigned short listingsize, - unsigned int listingchecksum, - unsigned short rendid) -{ +faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, + aim_conn_t *conn, + const char *sn, const fu8_t *cookie, + const fu8_t *ip, + fu16_t listingfiles, + fu16_t listingtotsize, + fu16_t listingsize, + fu32_t listingchecksum, + fu16_t rendid) +{ + return NULL; +#if 0 struct command_tx_struct *newpacket, *newoft; struct aim_conn_t *newconn; struct aim_fileheader_t *fh; @@ -547,7 +564,7 @@ faim_export struct aim_conn_t *aim_accepttransfer(struct aim_session_t *sess, if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); /* XXX: conn leak */ perror("calloc (1)"); return NULL; @@ -609,6 +626,7 @@ faim_export struct aim_conn_t *aim_accepttransfer(struct aim_session_t *sess, aim_tx_enqueue(sess, newpacket); return newconn; +#endif } /** @@ -621,9 +639,10 @@ faim_export struct aim_conn_t *aim_accepttransfer(struct aim_session_t *sess, * guess. * */ - -faim_export struct aim_fileheader_t *aim_getlisting(struct aim_session_t *sess, FILE *file) +faim_export struct aim_fileheader_t *aim_getlisting(aim_session_t *sess, FILE *file) { + return NULL; +#if 0 struct aim_fileheader_t *fh; u_long totsize = 0, size = 0, checksum = 0xffff0000; short totfiles = 0; @@ -727,6 +746,7 @@ faim_export struct aim_fileheader_t *aim_getlisting(struct aim_session_t *sess, faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name)))); return fh; +#endif } /** @@ -736,8 +756,10 @@ faim_export struct aim_fileheader_t *aim_getlisting(struct aim_session_t *sess, * you need to call accept() when it's connected. returns your fd * */ -faim_export int aim_listenestablish(u_short portnum) +faim_export int aim_listenestablish(fu16_t portnum) { + return -EINVAL; +#if 0 #if defined(__linux__) /* XXX what other OS's support getaddrinfo? */ int listenfd; @@ -808,6 +830,7 @@ faim_export int aim_listenestablish(u_short portnum) } return listenfd; #endif +#endif } /** @@ -818,8 +841,9 @@ faim_export int aim_listenestablish(u_short portnum) * this reads and handles data from conn->fd. currently a little rough * around the edges */ -faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_internal int aim_get_command_rendezvous(aim_session_t *sess, aim_conn_t *conn) { +#if 0 unsigned char hdrbuf1[6]; unsigned char *hdr = NULL; int hdrlen, hdrtype; @@ -873,7 +897,7 @@ faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); free(listing); faim_mutex_unlock(&conn->active); return -1; @@ -1108,13 +1132,13 @@ faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1235,7 +1259,7 @@ faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1298,7 +1322,7 @@ faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1386,8 +1410,12 @@ faim_internal int aim_get_command_rendezvous(struct aim_session_t *sess, struct hdr = NULL; } return 0; +#else + return -1; +#endif } - + +#if 0 /** * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr. * @hdr: buffer to extract header from @@ -1458,6 +1486,7 @@ static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr) i += 64; return fh; } +#endif /** * aim_oft_checksum - calculate oft checksum of buffer @@ -1477,10 +1506,13 @@ static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr) * Also, it's been said that this is incorrect as currently * written. You were warned. */ -faim_export int aim_oft_checksum(struct aim_session_t *sess, char *buffer, int bufsize, int *checksum) +faim_export fu32_t aim_oft_checksum(aim_session_t *sess, const char *buffer, int bufsize, fu32_t *checksum) { - short check0, check1; + return 0xdeadbeef; +#if 0 + fu16_t check0, check1; int i; + check0 = ((*checksum & 0xFF000000) >> 16); check1 = ((*checksum & 0x00ff0000) >> 16); for(i = 0; i < bufsize; i++) { @@ -1524,8 +1556,10 @@ faim_export int aim_oft_checksum(struct aim_session_t *sess, char *buffer, int b *checksum = ((check0 * 0x1000000) + (check1 * 0x10000)); return *checksum; +#endif } +#if 0 /** * aim_oft_buildheader - fills a buffer with network-order fh data * @dest: buffer to fill -- pre-alloced @@ -1535,7 +1569,7 @@ faim_export int aim_oft_checksum(struct aim_session_t *sess, char *buffer, int b * DOES NOT DO BOUNDS CHECKING! * */ -faim_internal int aim_oft_buildheader(unsigned char *dest,struct aim_fileheader_t *fh) +static int oft_buildheader(unsigned char *dest, struct aim_fileheader_t *fh) { int i, curbyte; if (!dest || !fh) @@ -1577,26 +1611,7 @@ faim_internal int aim_oft_buildheader(unsigned char *dest,struct aim_fileheader_ curbyte += 64; return curbyte; } - - -/** - * aim_tx_destroy - free's tx_command_t's - * @command: the command to free - * - * if command is locked, doesn't free. - * returns -1 on error (locked struct); 0 on success. - * - */ -faim_internal int aim_tx_destroy(struct command_tx_struct *command){ - if (command->lock) - return -1; - if (command->data) - free(command->data); - if (command->hdrtype == AIM_FRAMETYPE_OFT && command->hdr.oft.hdr2) - free(command->hdr.oft.hdr2); - free(command); - return 0; -} +#endif /** * aim_getfile_intitiate - Request an OFT getfile session @@ -1606,8 +1621,10 @@ faim_internal int aim_tx_destroy(struct command_tx_struct *command){ * * returns a new &aim_conn_t on success, %NULL on error */ -faim_export struct aim_conn_t *aim_getfile_initiate(struct aim_session_t *sess, struct aim_conn_t *conn, char *destsn) +faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn) { + return NULL; +#if 0 struct command_tx_struct *newpacket; struct aim_conn_t *newconn; struct aim_filetransfer_priv *priv; @@ -1745,6 +1762,7 @@ faim_export struct aim_conn_t *aim_getfile_initiate(struct aim_session_t *sess, faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd); return newconn; +#endif } /** @@ -1757,8 +1775,10 @@ faim_export struct aim_conn_t *aim_getfile_initiate(struct aim_session_t *sess, * * returns -1 on error, 0 on successful enqueuing */ -faim_export int aim_oft_getfile_request(struct aim_session_t *sess, struct aim_conn_t *conn, const unsigned char *name, const int size) +faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size) { + return -EINVAL; +#if 0 struct command_tx_struct *newoft; struct aim_filetransfer_priv *ft; if (!sess || !conn || !conn->priv || !name) @@ -1787,13 +1807,13 @@ faim_export int aim_oft_getfile_request(struct aim_session_t *sess, struct aim_c if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1801,6 +1821,7 @@ faim_export int aim_oft_getfile_request(struct aim_session_t *sess, struct aim_c aim_tx_enqueue(sess, newoft); return 0; +#endif } /** @@ -1812,8 +1833,10 @@ faim_export int aim_oft_getfile_request(struct aim_session_t *sess, struct aim_c * filetransfer. Returns -1 on error, 0 on apparent success * */ -faim_export int aim_oft_getfile_ack(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_oft_getfile_ack(aim_session_t *sess, aim_conn_t *conn) { + return -EINVAL; +#if 0 struct command_tx_struct *newoft; struct aim_filetransfer_priv *ft; @@ -1832,7 +1855,7 @@ faim_export int aim_oft_getfile_ack(struct aim_session_t *sess, struct aim_conn_ if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1840,13 +1863,14 @@ faim_export int aim_oft_getfile_ack(struct aim_session_t *sess, struct aim_conn_ if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } newoft->lock = 0; aim_tx_enqueue(sess, newoft); return 0; +#endif } /** @@ -1857,8 +1881,10 @@ faim_export int aim_oft_getfile_ack(struct aim_session_t *sess, struct aim_conn_ * call this before you close the getfile connection if you're on the * receiving/requesting end. */ -faim_export int aim_oft_getfile_end(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_oft_getfile_end(aim_session_t *sess, aim_conn_t *conn) { + return -EINVAL; +#if 0 struct command_tx_struct *newoft; struct aim_filetransfer_priv *ft; @@ -1877,7 +1903,7 @@ faim_export int aim_oft_getfile_end(struct aim_session_t *sess, struct aim_conn_ if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1889,7 +1915,7 @@ faim_export int aim_oft_getfile_end(struct aim_session_t *sess, struct aim_conn_ if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { newoft->lock = 0; - aim_tx_destroy(newoft); + aim_frame_destroy(newoft); return -1; } @@ -1897,4 +1923,6 @@ faim_export int aim_oft_getfile_end(struct aim_session_t *sess, struct aim_conn_ aim_tx_enqueue(sess, newoft); return 0; +#endif /* 0 */ } + diff --git a/src/im.c b/src/im.c index 143f4d7..6494b6d 100644 --- a/src/im.c +++ b/src/im.c @@ -38,29 +38,33 @@ * 0501 0004 0101 0102 0101 WinAIM 4.1.2010, libfaim (right here) * 0501 0001 0101 01 AOL v6.0, CompuServe 2000 v6.0, any * TOC client + * + * Note that in this function, only the feature bytes are tested, since + * the rest will always be the same. + * */ -faim_export unsigned short aim_fingerprintclient(unsigned char *msghdr, int len) +faim_export fu16_t aim_fingerprintclient(fu8_t *msghdr, int len) { static const struct { - unsigned short clientid; + fu16_t clientid; int len; - unsigned char data[10]; + fu8_t data[10]; } fingerprints[] = { /* AOL Mobile Communicator, WinAIM 1.0.414 */ { AIM_CLIENTTYPE_MC, - 9, {0x05, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01}}, + 3, {0x01, 0x01, 0x01}}, /* WinAIM 2.0.847, 2.1.1187, 3.0.1464, 4.3.2229, 4.4.2286 */ { AIM_CLIENTTYPE_WINAIM, - 9, {0x05, 0x01, 0x00, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01}}, + 3, {0x01, 0x01, 0x02}}, /* WinAIM 4.1.2010, libfaim */ { AIM_CLIENTTYPE_WINAIM41, - 10, {0x05, 0x01, 0x00, 0x04, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01}}, + 4, {0x01, 0x01, 0x01, 0x02}}, /* AOL v6.0, CompuServe 2000 v6.0, any TOC client */ { AIM_CLIENTTYPE_AOL_TOC, - 7, {0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01}}, + 1, {0x01}}, { 0, 0} }; @@ -80,9 +84,9 @@ faim_export unsigned short aim_fingerprintclient(unsigned char *msghdr, int len) } /* This should be endian-safe now... but who knows... */ -faim_export unsigned short aim_iconsum(const unsigned char *buf, int buflen) +faim_export fu16_t aim_iconsum(const fu8_t *buf, int buflen) { - unsigned long sum; + fu32_t sum; int i; for (i = 0, sum = 0; i < buflen; i += 2) @@ -128,14 +132,23 @@ faim_export unsigned short aim_iconsum(const unsigned char *buf, int buflen) * representation of the UNICODE index (in this case, UNICODE * "Horizontal Ellipsis", or 133 in in ASCII8). * + * Implementation note: Since this is one of the most-used functions + * in all of libfaim, it is written with performance in mind. As such, + * it is not as clear as it could be in respect to how this message is + * supposed to be layed out. Most obviously, tlvlists should be used + * instead of writing out the bytes manually. + * + * XXX support multipart + * */ -faim_export int aim_send_im_ext(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_sendimext_args *args) +faim_export int aim_send_im_ext(aim_session_t *sess, aim_conn_t *conn, struct aim_sendimext_args *args) { - int curbyte,i; - struct command_tx_struct *newpacket; + int i; + aim_frame_t *fr; + aim_snacid_t snacid; if (!sess || !conn || !args) - return -EINVAL; + return -EINVAL; if (!args->msg || (args->msglen <= 0)) return -EINVAL; @@ -143,14 +156,12 @@ faim_export int aim_send_im_ext(struct aim_session_t *sess, struct aim_conn_t *c if (args->msglen >= MAXMSGLEN) return -E2BIG; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, args->msglen+512))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, args->msglen+512))) return -ENOMEM; - newpacket->lock = 1; /* lock struct */ - - curbyte = 0; - curbyte += aim_putsnac(newpacket->data+curbyte, - 0x0004, 0x0006, 0x0000, sess->snac_nextid); + /* XXX should be optional */ + snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); + aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); /* * Generate a random message cookie @@ -161,28 +172,25 @@ faim_export int aim_send_im_ext(struct aim_session_t *sess, struct aim_conn_t *c * SNAC ID. * */ - for (i = 0; i < 8; i++) { - curbyte += aimutil_put8(newpacket->data+curbyte, - (unsigned char) rand()); - } + for (i = 0; i < 8; i++) + aimbs_put8(&fr->data, (fu8_t) rand()); /* * Channel ID */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + aimbs_put16(&fr->data, 0x0001); /* * Destination SN (prepended with byte length) */ - curbyte += aimutil_put8(newpacket->data+curbyte, strlen(args->destsn)); - curbyte += aimutil_putstr(newpacket->data+curbyte, - args->destsn, strlen(args->destsn)); + aimbs_put8(&fr->data, strlen(args->destsn)); + aimbs_putraw(&fr->data, args->destsn, strlen(args->destsn)); /* * metaTLV start. */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); - curbyte += aimutil_put16(newpacket->data+curbyte, args->msglen + 0x10); + aimbs_put16(&fr->data, 0x0002); + aimbs_put16(&fr->data, args->msglen + 0x10); /* * Flag data / ICBM Parameters? @@ -190,84 +198,79 @@ faim_export int aim_send_im_ext(struct aim_session_t *sess, struct aim_conn_t *c * I don't know what these are... * */ - curbyte += aimutil_put8(newpacket->data+curbyte, 0x05); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); + aimbs_put8(&fr->data, 0x05); + aimbs_put8(&fr->data, 0x01); /* number of bytes to follow */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); - curbyte += aimutil_put8(newpacket->data+curbyte, 0x02); + aimbs_put16(&fr->data, 0x0004); + aimbs_put8(&fr->data, 0x01); + aimbs_put8(&fr->data, 0x01); + aimbs_put8(&fr->data, 0x01); + aimbs_put8(&fr->data, 0x02); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0101); + aimbs_put16(&fr->data, 0x0101); /* * Message block length. */ - curbyte += aimutil_put16(newpacket->data+curbyte, args->msglen + 0x04); + aimbs_put16(&fr->data, args->msglen + 0x04); /* * Character set. */ if (args->flags & AIM_IMFLAGS_UNICODE) - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); + aimbs_put16(&fr->data, 0x0002); else if (args->flags & AIM_IMFLAGS_ISO_8859_1) - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); + aimbs_put16(&fr->data, 0x0003); else - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + aimbs_put16(&fr->data, 0x0000); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + aimbs_put16(&fr->data, 0x0000); /* * Message. Not terminated. */ - curbyte += aimutil_putstr(newpacket->data+curbyte, - args->msg, args->msglen); + aimbs_putraw(&fr->data, args->msg, args->msglen); /* * Set the Request Acknowledge flag. */ if (args->flags & AIM_IMFLAGS_ACK) { - curbyte += aimutil_put16(newpacket->data+curbyte,0x0003); - curbyte += aimutil_put16(newpacket->data+curbyte,0x0000); + aimbs_put16(&fr->data, 0x0003); + aimbs_put16(&fr->data, 0x0000); } - + /* * Set the Autoresponse flag. */ if (args->flags & AIM_IMFLAGS_AWAY) { - curbyte += aimutil_put16(newpacket->data+curbyte,0x0004); - curbyte += aimutil_put16(newpacket->data+curbyte,0x0000); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0000); } /* * Set the Buddy Icon Requested flag. */ if (args->flags & AIM_IMFLAGS_BUDDYREQ) { - curbyte += aimutil_put16(newpacket->data+curbyte,0x0009); - curbyte += aimutil_put16(newpacket->data+curbyte,0x0000); + aimbs_put16(&fr->data, 0x0009); + aimbs_put16(&fr->data, 0x0000); } /* - * Set the I HAVE A REALLY PURTY ICON flag (with timestamp). + * Set the I HAVE A REALLY PURTY ICON flag. */ if (args->flags & AIM_IMFLAGS_HASICON) { - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0008); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x000c); - curbyte += aimutil_put32(newpacket->data+curbyte, args->iconlen); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); - curbyte += aimutil_put16(newpacket->data+curbyte, args->iconsum); - curbyte += aimutil_put32(newpacket->data+curbyte, args->iconstamp); + aimbs_put16(&fr->data, 0x0009); + aimbs_put16(&fr->data, 0x000c); + aimbs_put32(&fr->data, args->iconlen); + aimbs_put16(&fr->data, 0x0001); /* XXX is this right?! */ + aimbs_put16(&fr->data, args->iconsum); + aimbs_put32(&fr->data, args->iconstamp); } - newpacket->commandlen = curbyte; - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); #if 1 /* XXX do this with autoconf or something... */ - aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); aim_cleansnacs(sess, 60); /* clean out all SNACs over 60sec old */ #endif @@ -284,7 +287,7 @@ faim_export int aim_send_im_ext(struct aim_session_t *sess, struct aim_conn_t *c * that requires an explicit message length. Use aim_send_im_ext(). * */ -faim_export int aim_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, const char *destsn, unsigned short flags, const char *msg) +faim_export int aim_send_im(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu16_t flags, const char *msg) { struct aim_sendimext_args args; @@ -296,155 +299,159 @@ faim_export int aim_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, return aim_send_im_ext(sess, conn, &args); } -faim_export int aim_send_icon(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn, const unsigned char *icon, int iconlen, time_t stamp, unsigned short iconsum) +/* + * This is also performance sensative. (If you can believe it...) + * + */ +faim_export int aim_send_icon(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *icon, int iconlen, time_t stamp, fu16_t iconsum) { - struct command_tx_struct *np; - int i, curbyte = 0; - unsigned char ck[8]; + int i; + fu8_t ck[8]; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!sess || !conn || !sn || !icon || - (iconlen <= 0) || (iconlen >= MAXICONLEN)) - return -EINVAL; + if (!sess || !conn || !sn || !icon || (iconlen <= 0) || (iconlen >= MAXICONLEN)) + return -EINVAL; if (conn->type != AIM_CONN_TYPE_BOS) return -EINVAL; - for (i = 0, curbyte = 0; i < 8; i++) - curbyte += aimutil_put8(ck+curbyte, (u_char)rand()); + for (i = 0; i < 8; i++) + aimutil_put8(ck+i, (fu8_t) rand()); - if (!(np = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2))) return -ENOMEM; - np->lock = 1; - - curbyte = aim_putsnac(np->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid); + snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); /* * Cookie */ - memcpy(np->data+curbyte, ck, 8); - curbyte += 8; + aimbs_putraw(&fr->data, ck, 8); /* * Channel (2) */ - curbyte += aimutil_put16(np->data+curbyte, 0x0002); + aimbs_put16(&fr->data, 0x0002); /* * Dest sn */ - curbyte += aimutil_put8(np->data+curbyte, strlen(sn)); - curbyte += aimutil_putstr(np->data+curbyte, sn, strlen(sn)); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); /* * TLV t(0005) + * + * Encompasses everything below. */ - curbyte += aimutil_put16(np->data+curbyte, 0x0005); - curbyte += aimutil_put16(np->data+curbyte, 2+8+16+6+4+4+iconlen+4+4+4+strlen(AIM_ICONIDENT)); - - curbyte += aimutil_put16(np->data+curbyte, 0x0000); + aimbs_put16(&fr->data, 0x0005); + aimbs_put16(&fr->data, 2+8+16+6+4+4+iconlen+4+4+4+strlen(AIM_ICONIDENT)); - memcpy(np->data+curbyte, ck, 8); - curbyte += 8; - - curbyte += aim_putcap(np->data+curbyte, 16, AIM_CAPS_BUDDYICON); + aimbs_put16(&fr->data, 0x0000); + aimbs_putraw(&fr->data, ck, 8); + aim_putcap(&fr->data, AIM_CAPS_BUDDYICON); /* TLV t(000a) */ - curbyte += aimutil_put16(np->data+curbyte, 0x000a); - curbyte += aimutil_put16(np->data+curbyte, 0x0002); - curbyte += aimutil_put16(np->data+curbyte, 0x0001); + aimbs_put16(&fr->data, 0x000a); + aimbs_put16(&fr->data, 0x0002); + aimbs_put16(&fr->data, 0x0001); /* TLV t(000f) */ - curbyte += aimutil_put16(np->data+curbyte, 0x000f); - curbyte += aimutil_put16(np->data+curbyte, 0x0000); + aimbs_put16(&fr->data, 0x000f); + aimbs_put16(&fr->data, 0x0000); /* TLV t(2711) */ - curbyte += aimutil_put16(np->data+curbyte, 0x2711); - curbyte += aimutil_put16(np->data+curbyte, 4+4+4+iconlen+strlen(AIM_ICONIDENT)); - curbyte += aimutil_put16(np->data+curbyte, 0x0000); - curbyte += aimutil_put16(np->data+curbyte, iconsum); - curbyte += aimutil_put32(np->data+curbyte, iconlen); - curbyte += aimutil_put32(np->data+curbyte, stamp); - memcpy(np->data+curbyte, icon, iconlen); - curbyte += iconlen; - memcpy(np->data+curbyte, AIM_ICONIDENT, strlen(AIM_ICONIDENT)); - curbyte += strlen(AIM_ICONIDENT); + aimbs_put16(&fr->data, 0x2711); + aimbs_put16(&fr->data, 4+4+4+iconlen+strlen(AIM_ICONIDENT)); + aimbs_put16(&fr->data, 0x0000); /* XXX is this right?! */ + aimbs_put16(&fr->data, iconsum); + aimbs_put32(&fr->data, iconlen); + aimbs_put32(&fr->data, stamp); + aimbs_putraw(&fr->data, icon, iconlen); + aimbs_putraw(&fr->data, AIM_ICONIDENT, strlen(AIM_ICONIDENT)); /* TLV t(0003) */ - curbyte += aimutil_put16(np->data+curbyte, 0x0003); - curbyte += aimutil_put16(np->data+curbyte, 0x0000); + aimbs_put16(&fr->data, 0x0003); + aimbs_put16(&fr->data, 0x0000); - np->commandlen = curbyte; - np->lock = 0; - aim_tx_enqueue(sess, np); + aim_tx_enqueue(sess, fr); return 0; } -static int outgoingim(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - unsigned int i, ret = 0; + int i, ret = 0; aim_rxcallback_t userfunc; - unsigned char cookie[8]; - int channel; - struct aim_tlvlist_t *tlvlist; - char sn[MAXSNLEN]; - unsigned short icbmflags = 0; - unsigned char flag1 = 0, flag2 = 0; - unsigned char *msgblock = NULL, *msg = NULL; + fu8_t cookie[8]; + fu16_t channel; + aim_tlvlist_t *tlvlist; + char *sn; + int snlen; + fu16_t icbmflags = 0; + fu8_t flag1 = 0, flag2 = 0; + fu8_t *msg = NULL; + aim_tlv_t *msgblock; /* ICBM Cookie. */ for (i = 0; i < 8; i++) - cookie[i] = aimutil_get8(data+i); + cookie[i] = aimbs_get8(bs); /* Channel ID */ - channel = aimutil_get16(data+i); - i += 2; + channel = aimbs_get16(bs); if (channel != 0x01) { faimdprintf(sess, 0, "icbm: ICBM recieved on unsupported channel. Ignoring. (chan = %04x)\n", channel); - return 1; + return 0; } - strncpy(sn, (char *) data+i+1, (int) *(data+i)); - i += 1 + (int) *(data+i); + snlen = aimbs_get8(bs); + sn = aimbs_getstr(bs, snlen); - tlvlist = aim_readtlvchain(data+i, datalen-i); + tlvlist = aim_readtlvchain(bs); if (aim_gettlv(tlvlist, 0x0003, 1)) icbmflags |= AIM_IMFLAGS_ACK; if (aim_gettlv(tlvlist, 0x0004, 1)) icbmflags |= AIM_IMFLAGS_AWAY; - if ((msgblock = (unsigned char *)aim_gettlv_str(tlvlist, 0x0002, 1))) { - int j = 0; + if ((msgblock = aim_gettlv(tlvlist, 0x0002, 1))) { + aim_bstream_t mbs; + int featurelen, msglen; + + aim_bstream_init(&mbs, msgblock->value, msgblock->length); - /* no, this really is correct. I'm not high or anything either. */ - j += 2; - j += 2 + aimutil_get16(msgblock+j); - j += 2; + aimbs_get8(&mbs); + aimbs_get8(&mbs); + for (featurelen = aimbs_get16(&mbs); featurelen; featurelen--) + aimbs_get8(&mbs); + aimbs_get8(&mbs); + aimbs_get8(&mbs); - j += 2; /* final block length */ + msglen = aimbs_get16(&mbs) - 4; /* final block length */ - flag1 = aimutil_get16(msgblock); - j += 2; - flag2 = aimutil_get16(msgblock); - j += 2; + flag1 = aimbs_get16(&mbs); + flag2 = aimbs_get16(&mbs); - msg = msgblock+j; + msg = aimbs_getstr(&mbs, msglen); } if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, channel, sn, msg, icbmflags, flag1, flag2); - free(msgblock); + free(sn); aim_freetlvchain(&tlvlist); return ret; } /* - * A multipart IM: + * + * This should use tlvlists, but doesn't for performance reasons. + * + * XXX support multipart IMs: * * 0004 0007 0000 8f08 d295 * 0031 6520 3b7b f9fd @@ -464,12 +471,13 @@ static int outgoingim(struct aim_session_t *sess, aim_module_t *mod, struct comm * 0101 000b 0000 0000 3c2f 4854 4d4c 3e another ASCII part * */ -static int incomingim_ch1(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned short channel, struct aim_userinfo_s *userinfo, unsigned char *data, int datalen, unsigned char *cookie) +static int incomingim_ch1(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, fu16_t channel, struct aim_userinfo_s *userinfo, aim_bstream_t *bs, fu8_t *cookie) { - unsigned short type, length; + fu16_t type, length; aim_rxcallback_t userfunc; - int i, ret = 0; + int ret = 0; struct aim_incomingim_ch1_args args; + int endpos; memset(&args, 0, sizeof(args)); @@ -478,54 +486,46 @@ static int incomingim_ch1(struct aim_session_t *sess, aim_module_t *mod, struct * I've changed it to process the TLVs in-place. This avoids lots * of per-IM memory allocations. */ - for (i = 0; i < datalen; ) { + while (aim_bstream_empty(bs)) { + + type = aimbs_get16(bs); + length = aimbs_get16(bs); - type = aimutil_get16(data+i); - i += 2; - - length = aimutil_get16(data+i); - i += 2; + endpos = aim_bstream_curpos(bs) + length; if (type == 0x0002) { /* Message Block */ - unsigned short wastebits; - unsigned char *msgblock; - int j = 0, y = 0, z = 0; + fu16_t featureslen; + int z; - msgblock = data+i; - /* - * Extracting the message from the unknown cruft. - * - * This is a bit messy, and I'm not really qualified, - * even as the author, to comment on it. At least - * its not as bad as a while loop shooting into - * infinity. - * - * "Do you believe in magic?" + * This TLV consists of the following: + * - 0501 -- Unknown + * - Features: Don't know how to interpret these + * - 0101 -- Unknown + * - Message * */ - wastebits = aimutil_get8(msgblock+j++); - wastebits = aimutil_get8(msgblock+j++); - - y = aimutil_get16(msgblock+j); - j += 2; - for (z = 0; z < y; z++) - wastebits = aimutil_get8(msgblock+j++); - wastebits = aimutil_get8(msgblock+j++); - wastebits = aimutil_get8(msgblock+j++); - - args.finlen = j; - if (args.finlen > sizeof(args.fingerprint)) - args.finlen = sizeof(args.fingerprint); - memcpy(args.fingerprint, msgblock, args.finlen); + aimbs_get8(bs); /* 05 */ + aimbs_get8(bs); /* 01 */ + featureslen = aimbs_get16(bs); + for (z = 0, args.finlen = 0; z < featureslen; z++) { + fu8_t tmp; + + tmp = aimbs_get8(bs); + if (z < sizeof(args.fingerprint)) { + args.fingerprint[z] = tmp; + args.finlen++; + } + } + aimbs_get8(bs); /* 01 */ + aimbs_get8(bs); /* 01 */ /* Message string length, including flag words. */ - args.msglen = aimutil_get16(msgblock+j); - j += 2; + args.msglen = aimbs_get16(bs); /* Flag words. */ - args.flag1 = aimutil_get16(msgblock+j); + args.flag1 = aimbs_get16(bs); if (args.flag1 == 0x0000) ; /* ASCII */ else if (args.flag1 == 0x0002) @@ -534,17 +534,16 @@ static int incomingim_ch1(struct aim_session_t *sess, aim_module_t *mod, struct args.icbmflags |= AIM_IMFLAGS_ISO_8859_1; else if (args.flag1 == 0xffff) ; /* no encoding (yeep!) */ - j += 2; - args.flag2 = aimutil_get16(msgblock+j); + args.flag2 = aimbs_get16(bs); if (args.flag2 == 0x0000) ; /* standard subencoding? */ else if (args.flag2 == 0x000b) args.icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH; else if (args.flag2 == 0xffff) ; /* no subencoding */ - j += 2; - + + /* XXX this isn't really necesary... */ if ( ((args.flag1 != 0x0000) && (args.flag1 != 0x0002) && (args.flag1 != 0x0003) && @@ -555,18 +554,22 @@ static int incomingim_ch1(struct aim_session_t *sess, aim_module_t *mod, struct faimdprintf(sess, 0, "icbm: **warning: encoding flags are being used! {%04x, %04x}\n", args.flag1, args.flag2); } - /* Message string. */ + /* Message. */ args.msglen -= 4; if (args.icbmflags & AIM_IMFLAGS_UNICODE) { + fu8_t *umsg; + + /* Can't use getstr because of wide null */ + umsg = aimbs_getraw(bs, args.msglen); args.msg = malloc(args.msglen+2); - memcpy(args.msg, msgblock+j, args.msglen); + memcpy(args.msg, umsg, args.msglen); args.msg[args.msglen] = '\0'; /* wide NULL */ args.msg[args.msglen+1] = '\0'; - } else { - args.msg = malloc(args.msglen+1); - memcpy(args.msg, msgblock+j, args.msglen); - args.msg[args.msglen] = '\0'; - } + + free(umsg); + + } else + args.msg = aimbs_getstr(bs, args.msglen); } else if (type == 0x0003) { /* Server Ack Requested */ @@ -576,11 +579,11 @@ static int incomingim_ch1(struct aim_session_t *sess, aim_module_t *mod, struct args.icbmflags |= AIM_IMFLAGS_AWAY; - } else if ((type == 0x0008) && (length == 0x000c)) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */ + } else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */ - args.iconchecksum = aimutil_get32(data+i); - args.iconlength = aimutil_get32(data+i+4); - args.iconstamp = aimutil_get32(data+i+8); + args.iconchecksum = aimbs_get32(bs); + args.iconlength = aimbs_get32(bs); + args.iconstamp = aimbs_get32(bs); args.icbmflags |= AIM_IMFLAGS_HASICON; } else if (type == 0x0009) { @@ -590,31 +593,43 @@ static int incomingim_ch1(struct aim_session_t *sess, aim_module_t *mod, struct } else if (type == 0x0017) { args.extdatalen = length; - args.extdata = data+i; + args.extdata = aimbs_getraw(bs, args.extdatalen); } else { faimdprintf(sess, 0, "incomingim_ch1: unknown TLV 0x%04x (len %d)\n", type, length); } - i += length; + /* + * This is here to protect ourselves from ourselves. That + * is, if something above doesn't completly parse its value + * section, or, worse, overparses it, this will set the + * stream where it needs to be in order to land on the next + * TLV when the loop continues. + * + */ + aim_bstream_setpos(bs, endpos); } if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, channel, userinfo, &args); + free(args.extdata); free(args.msg); return ret; } -static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned short channel, struct aim_userinfo_s *userinfo, struct aim_tlvlist_t *tlvlist, unsigned char *cookie) +/* XXX Ugh. I think its obvious. */ +static int incomingim_ch2(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, fu16_t channel, struct aim_userinfo_s *userinfo, aim_tlvlist_t *tlvlist, fu8_t *cookie) { aim_rxcallback_t userfunc; - struct aim_tlv_t *block1; - struct aim_tlvlist_t *list2; + aim_tlv_t *block1; + aim_tlvlist_t *list2; int ret = 0; struct aim_incomingim_ch2_args args; + aim_bstream_t bbs; + fu8_t *cookie2; memset(&args, 0, sizeof(args)); @@ -626,18 +641,22 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct return 0; } + aim_bstream_init(&bbs, block1->value, block1->length); + /* * First two bytes represent the status of the connection. * * 0 is a request, 2 is an accept */ - args.status = aimutil_get16(block1->value+0); + args.status = aimbs_get16(&bbs); /* * Next comes the cookie. Should match the ICBM cookie. */ - if (memcmp(block1->value+2, cookie, 8) != 0) + cookie2 = aimbs_getraw(&bbs, 8); + if (memcmp(cookie, cookie2, 8) != 0) faimdprintf(sess, 0, "rend: warning cookies don't match!\n"); + free(cookie2); /* * The next 16bytes are a capability block so we can @@ -651,7 +670,7 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct * Read off one capability string and we should have it ID'd. * */ - if ((args.reqclass = aim_getcap(sess, block1->value+2+8, 0x10)) == 0x0000) { + if ((args.reqclass = aim_getcap(sess, &bbs, 0x10)) == 0x0000) { faimdprintf(sess, 0, "rend: no ID block\n"); return 0; } @@ -662,18 +681,18 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct * * Ack packets for instance have nothing more to them. */ - list2 = aim_readtlvchain(block1->value+2+8+16, block1->length-2-8-16); + list2 = aim_readtlvchain(&bbs); if (!list2 || ((args.reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) { - struct aim_msgcookie_t *cook; + aim_msgcookie_t *cook; int type; type = aim_msgcookie_gettype(args.reqclass); /* XXX: fix this shitty code */ if ((cook = aim_checkcookie(sess, cookie, type)) == NULL) { faimdprintf(sess, 0, "non-data rendezvous thats not in cache (type %d)\n", type); - aim_freetlvchain(&list2); - return 1; + aim_freetlvchain(&list2); + return 1; } if (cook->type == AIM_COOKIETYPE_OFTGET) { @@ -686,14 +705,14 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct if (args.status != 0x0002) { - if (aim_gettlv(list2, 0x000b, 1)) - errorcode = aim_gettlv16(list2, 0x000b, 1); + if (aim_gettlv(list2, 0x000b, 1)) + errorcode = aim_gettlv16(list2, 0x000b, 1); - /* XXX this should make it up to the client, you know.. */ - if (errorcode) - faimdprintf(sess, 0, "transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sn, ft->ip, ft->fh.name, errorcode); + /* XXX this should make it up to the client, you know.. */ + if (errorcode) + faimdprintf(sess, 0, "transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sn, ft->ip, ft->fh.name, errorcode); } /* args.status != 0x0002 */ - + } else { faimdprintf(sess, 0, "no data attached to file transfer\n"); } /* !cook->data */ @@ -716,19 +735,16 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct * The rest of the handling depends on what type it is. */ if (args.reqclass & AIM_CAPS_BUDDYICON) { - struct aim_tlv_t *miscinfo; - int curpos = 0; + aim_tlv_t *miscinfo; + aim_bstream_t tbs; miscinfo = aim_gettlv(list2, 0x2711, 1); + aim_bstream_init(&tbs, miscinfo->value, miscinfo->length); - args.info.icon.checksum = aimutil_get32(miscinfo->value+curpos); - curpos += 4; - args.info.icon.length = aimutil_get32(miscinfo->value+curpos); - curpos += 4; - args.info.icon.timestamp = aimutil_get32(miscinfo->value+curpos); - curpos += 4; - args.info.icon.icon = malloc(args.info.icon.length); - memcpy(args.info.icon.icon, miscinfo->value+curpos, args.info.icon.length); + args.info.icon.checksum = aimbs_get32(&tbs); + args.info.icon.length = aimbs_get32(&tbs); + args.info.icon.timestamp = aimbs_get32(&tbs); + args.info.icon.icon = aimbs_getraw(&tbs, args.info.icon.length); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, channel, userinfo, &args); @@ -736,11 +752,11 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct free(args.info.icon.icon); } else if (args.reqclass & AIM_CAPS_VOICE) { - struct aim_msgcookie_t *cachedcook; + aim_msgcookie_t *cachedcook; faimdprintf(sess, 1, "rend: voice!\n"); - if(!(cachedcook = (struct aim_msgcookie_t*)calloc(1, sizeof(struct aim_msgcookie_t)))) { + if(!(cachedcook = (aim_msgcookie_t*)calloc(1, sizeof(aim_msgcookie_t)))) { aim_freetlvchain(&list2); return 0; } @@ -764,7 +780,7 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct memset(ip, 0, sizeof(ip)); if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0005, 1)) { - struct aim_tlv_t *iptlv, *porttlv; + aim_tlv_t *iptlv, *porttlv; iptlv = aim_gettlv(list2, 0x0003, 1); porttlv = aim_gettlv(list2, 0x0005, 1); @@ -794,10 +810,14 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct ret = userfunc(sess, rx, channel, userinfo, &args); } else if (args.reqclass & AIM_CAPS_CHAT) { - struct aim_tlv_t *miscinfo; + aim_tlv_t *miscinfo; + aim_bstream_t tbs; miscinfo = aim_gettlv(list2, 0x2711, 1); - aim_chat_readroominfo(miscinfo->value, &args.info.chat.roominfo); + + aim_bstream_init(&tbs, miscinfo->value, miscinfo->length); + + aim_chat_readroominfo(&tbs, &args.info.chat.roominfo); if (aim_gettlv(list2, 0x000c, 1)) args.info.chat.msg = aim_gettlv_str(list2, 0x000c, 1); @@ -818,13 +838,13 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct } else if (args.reqclass & AIM_CAPS_GETFILE) { char ip[30]; - struct aim_msgcookie_t *cachedcook; - struct aim_tlv_t *miscinfo; - struct aim_tlv_t *iptlv, *porttlv; + aim_msgcookie_t *cachedcook; + aim_tlv_t *miscinfo; + aim_tlv_t *iptlv, *porttlv; memset(ip, 0, 30); - if (!(cachedcook = calloc(1, sizeof(struct aim_msgcookie_t)))) { + if (!(cachedcook = calloc(1, sizeof(aim_msgcookie_t)))) { aim_freetlvchain(&list2); return 0; } @@ -858,13 +878,13 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct } else if (args.reqclass & AIM_CAPS_SENDFILE) { #if 0 char ip[30]; - struct aim_msgcookie_t *cachedcook; - struct aim_tlv_t *miscinfo; - struct aim_tlv_t *iptlv, *porttlv; + aim_msgcookie_t *cachedcook; + aim_tlv_t *miscinfo; + aim_tlv_t *iptlv, *porttlv; memset(ip, 0, 30); - if (!(cachedcook = calloc(1, sizeof(struct aim_msgcookie_t)))) { + if (!(cachedcook = calloc(1, sizeof(aim_msgcookie_t)))) { aim_freetlvchain(&list2); return 0; } @@ -933,11 +953,11 @@ static int incomingim_ch2(struct aim_session_t *sess, aim_module_t *mod, struct * I have access to. Its not fast, its not clean. But it works. * */ -static int incomingim(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int incomingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int i, ret = 0; - unsigned char cookie[8]; - int channel; + fu8_t cookie[8]; + fu16_t channel; struct aim_userinfo_s userinfo; memset(&userinfo, 0x00, sizeof(struct aim_userinfo_s)); @@ -946,7 +966,7 @@ static int incomingim(struct aim_session_t *sess, aim_module_t *mod, struct comm * Read ICBM Cookie. And throw away. */ for (i = 0; i < 8; i++) - cookie[i] = aimutil_get8(data+i); + cookie[i] = aimbs_get8(bs); /* * Channel ID. @@ -961,15 +981,14 @@ static int incomingim(struct aim_session_t *sess, aim_module_t *mod, struct comm * connection negotiations come from. * */ - channel = aimutil_get16(data+i); - i += 2; + channel = aimbs_get16(bs); /* * Technically Channel 3 in chat could be done here too. */ if ((channel != 0x01) && (channel != 0x02)) { faimdprintf(sess, 0, "icbm: ICBM received on an unsupported channel. Ignoring.\n (chan = %04x)", channel); - return 1; + return 0; } /* @@ -988,7 +1007,7 @@ static int incomingim(struct aim_session_t *sess, aim_module_t *mod, struct comm * never be two TLVs of the same type in one block. * */ - i += aim_extractuserinfo(sess, data+i, &userinfo); + aim_extractuserinfo(sess, bs, &userinfo); /* * From here on, its depends on what channel we're on. @@ -999,16 +1018,16 @@ static int incomingim(struct aim_session_t *sess, aim_module_t *mod, struct comm */ if (channel == 1) { - ret = incomingim_ch1(sess, mod, rx, snac, channel, &userinfo, data+i, datalen-i, cookie); + ret = incomingim_ch1(sess, mod, rx, snac, channel, &userinfo, bs, cookie); } else if (channel == 0x0002) { - struct aim_tlvlist_t *tlvlist; + aim_tlvlist_t *tlvlist; /* * Read block of TLVs (not including the userinfo data). All * further data is derived from what is parsed here. */ - tlvlist = aim_readtlvchain(data+i, datalen-i); + tlvlist = aim_readtlvchain(bs); ret = incomingim_ch2(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie); @@ -1028,30 +1047,29 @@ static int incomingim(struct aim_session_t *sess, aim_module_t *mod, struct comm * AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers" * */ -faim_export int aim_denytransfer(struct aim_session_t *sess, - struct aim_conn_t *conn, - const char *sender, - const char *cookie, - unsigned short code) +faim_export int aim_denytransfer(aim_session_t *sess, aim_conn_t *conn, const char *sender, const char *cookie, fu16_t code) { - struct command_tx_struct *newpacket; - int curbyte, i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(sender)+6))) + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sender)+6))) return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0004, 0x000b, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0004, 0x000b, 0x0000, snacid); + + aimbs_putraw(&fr->data, cookie, 8); - curbyte = aim_putsnac(newpacket->data, 0x0004, 0x000b, 0x0000, sess->snac_nextid++); - for (i = 0; i < 8; i++) - curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); - curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sender)); - curbyte += aimutil_putstr(newpacket->data+curbyte, sender, strlen(sender)); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0003, code); + aimbs_put16(&fr->data, 0x0002); /* channel */ + aimbs_put8(&fr->data, strlen(sender)); + aimbs_putraw(&fr->data, sender, strlen(sender)); - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_addtlvtochain16(&tl, 0x0003, code); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); return 0; } @@ -1062,96 +1080,77 @@ faim_export int aim_denytransfer(struct aim_session_t *sess, * Request ICBM parameter information. * */ -faim_export unsigned long aim_reqicbmparams(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_reqicbmparams(aim_session_t *sess, aim_conn_t *conn) { return aim_genericreq_n(sess, conn, 0x0004, 0x0004); } /* * + * I definitly recommend sending this. If you don't, you'll be stuck + * with the rather unreasonable defaults. You don't want those. Send this. + * */ -faim_export unsigned long aim_seticbmparam(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_icbmparameters *params) +faim_export int aim_seticbmparam(aim_session_t *sess, aim_conn_t *conn, struct aim_icbmparameters *params) { - struct command_tx_struct *newpacket; - int curbyte; + aim_frame_t *fr; + aim_snacid_t snacid; if (!sess || !conn || !params) return -EINVAL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+16))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+16))) return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0004, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0004, 0x0002, 0x0000, snacid); - curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0002, 0x0000, sess->snac_nextid++); - - /* This is read-only (in Parameter Reply). Must be set to zero here. */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + /* This is read-only (see Parameter Reply). Must be set to zero here. */ + aimbs_put16(&fr->data, 0x0000); /* These are all read-write */ - curbyte += aimutil_put32(newpacket->data+curbyte, params->flags); - curbyte += aimutil_put16(newpacket->data+curbyte, params->maxmsglen); - curbyte += aimutil_put16(newpacket->data+curbyte, params->maxsenderwarn); - curbyte += aimutil_put16(newpacket->data+curbyte, params->maxrecverwarn); - curbyte += aimutil_put32(newpacket->data+curbyte, params->minmsginterval); + aimbs_put32(&fr->data, params->flags); + aimbs_put16(&fr->data, params->maxmsglen); + aimbs_put16(&fr->data, params->maxsenderwarn); + aimbs_put16(&fr->data, params->maxrecverwarn); + aimbs_put32(&fr->data, params->minmsginterval); - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); return 0; } -static int paraminfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { struct aim_icbmparameters params; aim_rxcallback_t userfunc; - int i = 0; - - params.maxchan = aimutil_get16(data+i); - i += 2; - - params.flags = aimutil_get32(data+i); - i += 4; - - params.maxmsglen = aimutil_get16(data+i); - i += 2; - - params.maxsenderwarn = aimutil_get16(data+i); - i += 2; - - params.maxrecverwarn = aimutil_get16(data+i); - i += 2; - - params.minmsginterval = aimutil_get32(data+i); - i += 4; + params.maxchan = aimbs_get16(bs); + params.flags = aimbs_get32(bs); + params.maxmsglen = aimbs_get16(bs); + params.maxsenderwarn = aimbs_get16(bs); + params.maxrecverwarn = aimbs_get16(bs); + params.minmsginterval = aimbs_get32(bs); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) return userfunc(sess, rx, ¶ms); return 0; } -static int missedcall(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int missedcall(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - int i, ret = 0; + int ret = 0; aim_rxcallback_t userfunc; - unsigned short channel, nummissed, reason; + fu16_t channel, nummissed, reason; struct aim_userinfo_s userinfo; - - for (i = 0; i < datalen; ) { - - /* Channel ID. */ - channel = aimutil_get16(data+i); - i += 2; - /* Extract the standard user info block. */ - i += aim_extractuserinfo(sess, data+i, &userinfo); + while (aim_bstream_empty(bs)) { - nummissed = aimutil_get16(data+i); - i += 2; - - reason = aimutil_get16(data+i); - i += 2; + channel = aimbs_get16(bs); + aim_extractuserinfo(sess, bs, &userinfo); + nummissed = aimbs_get16(bs); + reason = aimbs_get16(bs); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason); @@ -1160,51 +1159,67 @@ static int missedcall(struct aim_session_t *sess, aim_module_t *mod, struct comm return ret; } -static int msgack(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int clienterr(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { + int ret = 0; aim_rxcallback_t userfunc; - char sn[MAXSNLEN]; - unsigned char ck[8]; - unsigned short type; - int i = 0; - unsigned char snlen; + fu16_t channel, reason; + char *sn; + fu8_t *ck, snlen; - memcpy(ck, data, 8); - i += 8; + ck = aimbs_getraw(bs, 8); + channel = aimbs_get16(bs); + snlen = aimbs_get8(bs); + sn = aimbs_getstr(bs, snlen); + reason = aimbs_get16(bs); - type = aimutil_get16(data+i); - i += 2; + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, channel, sn, reason); - snlen = aimutil_get8(data+i); - i++; + return ret; +} - memset(sn, 0, sizeof(sn)); - strncpy(sn, (char *)data+i, snlen); +static int msgack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) +{ + aim_rxcallback_t userfunc; + fu16_t type; + fu8_t snlen, *ck; + char *sn; + + ck = aimbs_getraw(bs, 8); + type = aimbs_get16(bs); + snlen = aimbs_get8(bs); + sn = aimbs_getstr(bs, snlen); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) return userfunc(sess, rx, type, sn); + free(sn); + free(ck); + return 0; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { if (snac->subtype == 0x0005) - return paraminfo(sess, mod, rx, snac, data, datalen); + return paraminfo(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0006) - return outgoingim(sess, mod, rx, snac, data, datalen); + return outgoingim(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0007) - return incomingim(sess, mod, rx, snac, data, datalen); + return incomingim(sess, mod, rx, snac, bs); else if (snac->subtype == 0x000a) - return missedcall(sess, mod, rx, snac, data, datalen); + return missedcall(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x000b) + return clienterr(sess, mod, rx, snac, bs); else if (snac->subtype == 0x000c) - return msgack(sess, mod, rx, snac, data, datalen); + return msgack(sess, mod, rx, snac, bs); return 0; } -faim_internal int msg_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int msg_modfirst(aim_session_t *sess, aim_module_t *mod) { mod->family = 0x0004; diff --git a/src/info.c b/src/info.c index a36a7f5..5ae956d 100644 --- a/src/info.c +++ b/src/info.c @@ -2,7 +2,7 @@ * aim_info.c * * The functions here are responsible for requesting and parsing information- - * gathering SNACs. + * gathering SNACs. Or something like that. * */ @@ -10,533 +10,434 @@ #include struct aim_priv_inforeq { - char sn[MAXSNLEN+1]; - unsigned short infotype; + char sn[MAXSNLEN+1]; + fu16_t infotype; }; -faim_export int aim_getinfo(struct aim_session_t *sess, - struct aim_conn_t *conn, - const char *sn, - unsigned short infotype) +faim_export int aim_getinfo(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu16_t infotype) { - struct command_tx_struct *newpacket; - struct aim_priv_inforeq privdata; - int i = 0; + struct aim_priv_inforeq privdata; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!sess || !conn || !sn) - return -1; + if (!sess || !conn || !sn) + return -EINVAL; - if ((infotype != AIM_GETINFO_GENERALINFO) && - (infotype != AIM_GETINFO_AWAYMESSAGE)) - return -1; + if ((infotype != AIM_GETINFO_GENERALINFO) && (infotype != AIM_GETINFO_AWAYMESSAGE)) + return -EINVAL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 12+1+strlen(sn)))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 12+1+strlen(sn)))) + return -ENOMEM; - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0002, 0x0005, 0x0000, sess->snac_nextid); - - i += aimutil_put16(newpacket->data+i, infotype); - i += aimutil_put8(newpacket->data+i, strlen(sn)); - i += aimutil_putstr(newpacket->data+i, sn, strlen(sn)); - - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); + strncpy(privdata.sn, sn, sizeof(privdata.sn)); + privdata.infotype = infotype; + snacid = aim_cachesnac(sess, 0x0002, 0x0005, 0x0000, &privdata, sizeof(struct aim_priv_inforeq)); + + aim_putsnac(&fr->data, 0x0002, 0x0005, 0x0000, snacid); + aimbs_put16(&fr->data, infotype); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - strncpy(privdata.sn, sn, sizeof(privdata.sn)); - privdata.infotype = infotype; - aim_cachesnac(sess, 0x0002, 0x0005, 0x0000, &privdata, sizeof(struct aim_priv_inforeq)); + aim_tx_enqueue(sess, fr); - return 0; + return 0; } /* * Capability blocks. */ static const struct { - unsigned short flag; - unsigned char data[16]; + unsigned short flag; + unsigned char data[16]; } aim_caps[] = { - - {AIM_CAPS_BUDDYICON, - {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_VOICE, - {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_IMIMAGE, - {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_CHAT, - {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_GETFILE, - {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_SENDFILE, - {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_SAVESTOCKS, - {0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - /* - * Indeed, there are two of these. The former appears - * to be correct, but in some versions of winaim, the - * second one is set. Either they forgot to fix endianness, - * or they made a typo. It really doesn't matter which. - */ - {AIM_CAPS_GAMES, - {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - {AIM_CAPS_GAMES2, - {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, - 0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_SENDBUDDYLIST, - {0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1, - 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, - - {AIM_CAPS_LAST} + + {AIM_CAPS_BUDDYICON, + {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_VOICE, + {0x09, 0x46, 0x13, 0x41, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_IMIMAGE, + {0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_CHAT, + {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_GETFILE, + {0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_SENDFILE, + {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_SAVESTOCKS, + {0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + /* + * Indeed, there are two of these. The former appears to be correct, + * but in some versions of winaim, the second one is set. Either they + * forgot to fix endianness, or they made a typo. It really doesn't + * matter which. + */ + {AIM_CAPS_GAMES, + {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + {AIM_CAPS_GAMES2, + {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, + 0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_SENDBUDDYLIST, + {0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + {AIM_CAPS_LAST} }; -faim_internal unsigned short aim_getcap(struct aim_session_t *sess, unsigned char *capblock, int buflen) +/* + * This still takes a length parameter even with a bstream because capabilities + * are not naturally bounded. + * + */ +faim_internal fu16_t aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len) { - unsigned short flags; - int i; - int offset = 0; - int identified; + fu16_t flags = 0; + int offset; + + for (offset = 0; aim_bstream_empty(bs) && (offset < len); offset += 0x10) { + fu8_t *cap; + int i, identified; - for (offset = 0, flags = 0; offset < buflen; offset += 0x0010) { + cap = aimbs_getraw(bs, 0x10); - for (i = 0, identified = 0; !(aim_caps[i].flag & AIM_CAPS_LAST); i++) { + for (i = 0, identified = 0; !(aim_caps[i].flag & AIM_CAPS_LAST); i++) { - if (memcmp(&aim_caps[i].data, capblock+offset, 0x10) == 0) { - flags |= aim_caps[i].flag; - identified++; - break; /* should only match once... */ - } + if (memcmp(&aim_caps[i].data, cap, 0x10) == 0) { + flags |= aim_caps[i].flag; + identified++; + break; /* should only match once... */ - } + } + } - if (!identified) - faimdprintf(sess, 0, "unknown capability!\n"); + if (!identified) + faimdprintf(sess, 0, "unknown capability!\n"); - } + free(cap); + } - return flags; + return flags; } -faim_internal int aim_putcap(unsigned char *capblock, int buflen, unsigned short caps) +faim_internal int aim_putcap(aim_bstream_t *bs, fu16_t caps) { - int offset, i; + int i; - if (!capblock) - return 0; + if (!bs) + return -EINVAL; - for (i = 0, offset = 0; - !(aim_caps[i].flag & AIM_CAPS_LAST) && (offset < buflen); i++) { + for (i = 0; aim_bstream_empty(bs); i++) { - if (caps & aim_caps[i].flag) { - memcpy(capblock+offset, aim_caps[i].data, 16); - offset += 16; - } + if (aim_caps[i].flag == AIM_CAPS_LAST) + break; - } + if (caps & aim_caps[i].flag) + aimbs_putraw(bs, aim_caps[i].data, 0x10); - return offset; + } + + return 0; } /* - * AIM is fairly regular about providing user info. This - * is a generic routine to extract it in its standard form. + * AIM is fairly regular about providing user info. This is a generic + * routine to extract it in its standard form. */ -faim_internal int aim_extractuserinfo(struct aim_session_t *sess, unsigned char *buf, struct aim_userinfo_s *outinfo) +faim_internal int aim_extractuserinfo(aim_session_t *sess, aim_bstream_t *bs, struct aim_userinfo_s *outinfo) { - int i = 0; - int tlvcnt = 0; - int curtlv = 0; - int tlv1 = 0; - u_short curtype; - int lastvalid; - - - 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. - */ - if (buf[i] < MAXSNLEN) { - memcpy(outinfo->sn, &(buf[i+1]), buf[i]); - outinfo->sn[(int)buf[i]] = '\0'; - } else { - memcpy(outinfo->sn, &(buf[i+1]), MAXSNLEN-1); - outinfo->sn[MAXSNLEN] = '\0'; - } - i = 1 + (int)buf[i]; - - /* - * Warning Level. Stored as an unsigned short. - */ - outinfo->warnlevel = 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) { - lastvalid = 1; - curtype = aimutil_get16(&buf[i]); - switch (curtype) { - /* - * Type = 0x0000: Invalid - * - * AOL has been trying to throw these in just to break us. - * They're real nice guys over there at AOL. - * - * Just skip the two zero bytes and continue on. (This doesn't - * count towards tlvcnt!) - */ - case 0x0000: - lastvalid = 0; - i += 2; - break; - - /* - * Type = 0x0001: User flags - * - * Specified as any of the following bitwise ORed together: - * 0x0001 Trial (user less than 60days) - * 0x0002 Unknown bit 2 - * 0x0004 AOL Main Service user - * 0x0008 Unknown bit 4 - * 0x0010 Free (AIM) user - * 0x0020 Away - * - * In some odd cases, we can end up with more - * than one of these. We only want the first, - * as the others may not be something we want. - * - */ - case 0x0001: - if (tlv1) /* use only the first */ - break; - outinfo->flags = aimutil_get16(&buf[i+4]); - tlv1++; - break; - - /* - * Type = 0x0002: Member-Since date. - * - * The time/date that the user originally - * registered for the service, stored in - * time_t format - */ - case 0x0002: - outinfo->membersince = aimutil_get32(&buf[i+4]); - break; - - /* - * Type = 0x0003: On-Since date. - * - * The time/date that the user started - * their current session, stored in time_t - * format. - */ - case 0x0003: - outinfo->onlinesince = aimutil_get32(&buf[i+4]); - break; - - /* - * Type = 0x0004: Idle time. - * - * Number of seconds since the user - * actively used the service. - */ - case 0x0004: - outinfo->idletime = aimutil_get16(&buf[i+4]); - break; - - /* - * Type = 0x0006: ICQ Online Status - * - * ICQ's Away/DND/etc "enriched" status - * Some decoding of values done by Scott - */ - case 0x0006: - outinfo->icqinfo.status = aimutil_get16(buf+i+2+2+2); - break; - - - /* - * Type = 0x000a - * - * ICQ User IP Address. - * Ahh, the joy of ICQ security. - */ - case 0x000a: - outinfo->icqinfo.ipaddr = aimutil_get32(&buf[i+4]); - break; - - /* Type = 0x000c - * - * random crap containing the IP address, - * apparently a port number, and some Other Stuff. - * - */ - case 0x000c: - memcpy(outinfo->icqinfo.crap, &buf[i+4], 0x25); - break; - - /* - * Type = 0x000d - * - * Capability information. Not real sure of - * actual decoding. See comment on aim_bos_setprofile() - * in aim_misc.c about the capability block, its the same. - * - */ - case 0x000d: - { - int len; - len = aimutil_get16(buf+i+2); - if (!len) - break; - - outinfo->capabilities = aim_getcap(sess, buf+i+4, len); - } - break; - - /* - * Type = 0x000e - * - * Unknown. Always of zero length, and always only - * on AOL users. - * - * Ignore. - * - */ - case 0x000e: - break; - - /* - * Type = 0x000f: Session Length. (AIM) - * Type = 0x0010: Session Length. (AOL) - * - * The duration, in seconds, of the user's - * current session. - * - * Which TLV type this comes in depends - * on the service the user is using (AIM or AOL). - * - */ - case 0x000f: - case 0x0010: - outinfo->sessionlen = aimutil_get32(&buf[i+4]); - break; - - /* - * Reaching here indicates that either AOL has - * added yet another TLV for us to deal with, - * or the parsing has gone Terribly Wrong. - * - * Either way, inform the owner and attempt - * recovery. - * - */ - default: - { - int len,z = 0, y = 0, x = 0; - char tmpstr[160]; - - faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV:\n"); - faimdprintf(sess, 0, "userinfo: sn =%s\n", outinfo->sn); - faimdprintf(sess, 0, "userinfo: curtlv=0x%04x\n", curtlv); - faimdprintf(sess, 0, "userinfo: type =0x%04x\n",aimutil_get16(&buf[i])); - faimdprintf(sess, 0, "userinfo: length=0x%04x\n", len = aimutil_get16(&buf[i+2])); - faimdprintf(sess, 0, "userinfo: data: \n"); - while (zsn, snlen); + + /* + * Warning Level. Stored as an unsigned short. + */ + outinfo->warnlevel = aimbs_get16(bs); + + /* + * TLV Count. Unsigned short representing the number of + * Type-Length-Value triples that follow. + */ + tlvcnt = aimbs_get16(bs); + + /* + * Parse out the Type-Length-Value triples as they're found. + */ + for (curtlv = 0; curtlv < tlvcnt; curtlv++) { + int endpos; + fu16_t type, length; + + type = aimbs_get16(bs); + length = aimbs_get16(bs); + + endpos = aim_bstream_curpos(bs) + length; + + if (type == 0x0001) { + /* + * Type = 0x0001: User flags + * + * Specified as any of the following ORed together: + * 0x0001 Trial (user less than 60days) + * 0x0002 Unknown bit 2 + * 0x0004 AOL Main Service user + * 0x0008 Unknown bit 4 + * 0x0010 Free (AIM) user + * 0x0020 Away + * + */ + outinfo->flags = aimbs_get16(bs); + + } else if (type == 0x0002) { + /* + * Type = 0x0002: Member-Since date. + * + * The time/date that the user originally registered for + * the service, stored in time_t format. + */ + outinfo->membersince = aimbs_get32(bs); + + } else if (type == 0x0003) { + /* + * Type = 0x0003: On-Since date. + * + * The time/date that the user started their current + * session, stored in time_t format. + */ + outinfo->onlinesince = aimbs_get32(bs); + + } else if (type == 0x0004) { + /* + * Type = 0x0004: Idle time. + * + * Number of seconds since the user actively used the + * service. + * + * Note that the client tells the server when to start + * counting idle times, so this may or may not be + * related to reality. + */ + outinfo->idletime = aimbs_get16(bs); + + } else if (type == 0x0006) { + /* + * Type = 0x0006: ICQ Online Status + * + * ICQ's Away/DND/etc "enriched" status. Some decoding + * of values done by Scott + */ + aimbs_get16(bs); + outinfo->icqinfo.status = aimbs_get16(bs); + + } else if (type == 0x000a) { + /* + * Type = 0x000a + * + * ICQ User IP Address. + * Ahh, the joy of ICQ security. + */ + outinfo->icqinfo.ipaddr = aimbs_get32(bs); + + } else if (type == 0x000c) { + /* + * Type = 0x000c + * + * random crap containing the IP address, + * apparently a port number, and some Other Stuff. + * + */ + aimbs_getrawbuf(bs, outinfo->icqinfo.crap, 0x25); + + } else if (type == 0x000d) { + /* + * Type = 0x000d + * + * Capability information. + * + */ + outinfo->capabilities = aim_getcap(sess, bs, length); + + } else if (type == 0x000e) { + /* + * Type = 0x000e + * + * Unknown. Always of zero length, and always only + * on AOL users. + * + * Ignore. + * + */ + + } else if ((type == 0x000f) || (type == 0x0010)) { + /* + * 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). + * + */ + outinfo->sessionlen = aimbs_get32(bs); + + } else { + + /* + * Reaching here indicates that either AOL has + * added yet another TLV for us to deal with, + * or the parsing has gone Terribly Wrong. + * + * Either way, inform the owner and attempt + * recovery. + * + */ + faimdprintf(sess, 0, "userinfo: **warning: unexpected TLV:\n"); + faimdprintf(sess, 0, "userinfo: sn =%s\n", outinfo->sn); + faimdprintf(sess, 0, "userinfo: type =0x%04x\n",type); + faimdprintf(sess, 0, "userinfo: length=0x%04x\n", length); + + } + + /* Save ourselves. */ + aim_bstream_setpos(bs, endpos); + } + + return 0; } /* * Inverse of aim_extractuserinfo() */ -faim_internal int aim_putuserinfo(u_char *buf, int buflen, struct aim_userinfo_s *info) +faim_internal int aim_putuserinfo(aim_bstream_t *bs, struct aim_userinfo_s *info) { - int i = 0, numtlv = 0; - struct aim_tlvlist_t *tlvlist = NULL; + aim_tlvlist_t *tlvlist = NULL; - if (!buf || !info) - return 0; + if (!bs || !info) + return -EINVAL; - i += aimutil_put8(buf+i, strlen(info->sn)); - i += aimutil_putstr(buf+i, info->sn, strlen(info->sn)); + aimbs_put8(bs, strlen(info->sn)); + aimbs_putraw(bs, info->sn, strlen(info->sn)); - i += aimutil_put16(buf+i, info->warnlevel); + aimbs_put16(bs, info->warnlevel); - aim_addtlvtochain16(&tlvlist, 0x0001, info->flags); - numtlv++; - - aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince); - numtlv++; - - aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince); - numtlv++; - - aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime); - numtlv++; + aim_addtlvtochain16(&tlvlist, 0x0001, info->flags); + aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince); + aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince); + aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime); #if ICQ_OSCAR_SUPPORT - if(atoi(info->sn) != 0) { - aim_addtlvtochain16(&tlvlist, 0x0006, info->icqinfo.status); - aim_addtlvtochain32(&tlvlist, 0x000a, info->icqinfo.ipaddr); - } + if (atoi(info->sn) != 0) { + aim_addtlvtochain16(&tlvlist, 0x0006, info->icqinfo.status); + aim_addtlvtochain32(&tlvlist, 0x000a, info->icqinfo.ipaddr); + } #endif - aim_addtlvtochain_caps(&tlvlist, 0x000d, info->capabilities); - numtlv++; + aim_addtlvtochain_caps(&tlvlist, 0x000d, info->capabilities); - aim_addtlvtochain32(&tlvlist, (unsigned short)((info->flags)&AIM_FLAG_AOL?0x0010:0x000f), info->sessionlen); - numtlv++; + aim_addtlvtochain32(&tlvlist, (fu16_t)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen); - i += aimutil_put16(buf+i, numtlv); /* tlvcount */ - i += aim_writetlvchain(buf+i, buflen-i, &tlvlist); /* tlvs */ - aim_freetlvchain(&tlvlist); + aimbs_put16(bs, aim_counttlvchain(&tlvlist)); + aim_writetlvchain(bs, &tlvlist); + aim_freetlvchain(&tlvlist); - return i; + return 0; } -faim_export int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_userinfo_s *info) +faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *info) { - struct command_tx_struct *tx; - int i = 0; - - if (!sess || !conn || !info) - return 0; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) - return -1; + if (!sess || !conn || !info) + return -EINVAL; - tx->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) + return -ENOMEM; - 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); + snacid = aim_cachesnac(sess, 0x0003, 0x000b, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0003, 0x000b, 0x0000, snacid); + aim_putuserinfo(&fr->data, info); - tx->commandlen = i; - tx->lock = 0; - aim_tx_enqueue(sess, tx); + aim_tx_enqueue(sess, fr); - return 0; + return 0; } -faim_export int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn) +faim_export int aim_sendbuddyoffgoing(aim_session_t *sess, aim_conn_t *conn, const char *sn) { - struct command_tx_struct *tx; - int i = 0; - - if (!sess || !conn || !sn) - return 0; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+1+strlen(sn)))) - return -1; + if (!sess || !conn || !sn) + return -EINVAL; - tx->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)))) + return -ENOMEM; - i += 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); + snacid = aim_cachesnac(sess, 0x0003, 0x000c, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0003, 0x000c, 0x0000, snacid); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - 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); + aim_tx_enqueue(sess, fr); - return 0; + return 0; } -faim_export int aim_0002_000b(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn) +/* + * Huh? What is this? + */ +faim_export int aim_0002_000b(aim_session_t *sess, aim_conn_t *conn, const char *sn) { - struct command_tx_struct *tx; - int i = 0; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!sess || !conn || !sn) - return 0; + if (!sess || !conn || !sn) + return -EINVAL; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+1+strlen(sn)))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)))) + return -ENOMEM; - tx->lock = 1; + snacid = aim_cachesnac(sess, 0x0002, 0x000b, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0002, 0x000b, 0x0000, snacid); + aimbs_put8(&fr->data, strlen(sn)); + aimbs_putraw(&fr->data, sn, strlen(sn)); - i = aim_putsnac(tx->data, 0x0002, 0x000b, 0x0000, sess->snac_nextid); - i += aimutil_put8(tx->data+i, strlen(sn)); - i += aimutil_putstr(tx->data+i, sn, strlen(sn)); - - tx->commandlen = i; - tx->lock = 0; - aim_tx_enqueue(sess, tx); + aim_tx_enqueue(sess, fr); - return 0; + return 0; } /* @@ -545,14 +446,14 @@ faim_export int aim_0002_000b(struct aim_session_t *sess, struct aim_conn_t *con * t(0002) - short - unknown (value = 16) [max MIME type length?] * t(0003) - short - unknown (value = 7) */ -static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int rights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_tlvlist_t *tlvlist; + aim_tlvlist_t *tlvlist; aim_rxcallback_t userfunc; int ret = 0; - unsigned short maxsiglen = 0; + fu16_t maxsiglen = 0; - tlvlist = aim_readtlvchain(data, datalen); + tlvlist = aim_readtlvchain(bs); if (aim_gettlv(tlvlist, 0x0001, 1)) maxsiglen = aim_gettlv16(tlvlist, 0x0001, 1); @@ -565,87 +466,83 @@ static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_ return ret; } -static int userinfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int userinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - struct aim_userinfo_s userinfo; - char *text_encoding = NULL; - char *text = NULL; - int i = 0; - aim_rxcallback_t userfunc; - struct aim_tlvlist_t *tlvlist; - struct aim_snac_t *origsnac = NULL; - struct aim_priv_inforeq *inforeq; - int ret = 0; - - origsnac = aim_remsnac(sess, snac->id); - - if (!origsnac || !origsnac->data) { - faimdprintf(sess, 0, "parse_userinfo_middle: major problem: no snac stored!\n"); - return 0; - } - - inforeq = (struct aim_priv_inforeq *)origsnac->data; - - if ((inforeq->infotype != AIM_GETINFO_GENERALINFO) && - (inforeq->infotype != AIM_GETINFO_AWAYMESSAGE)) { - faimdprintf(sess, 0, "parse_userinfo_middle: unknown infotype in request! (0x%04x)\n", inforeq->infotype); - return 0; - } - - i = aim_extractuserinfo(sess, data, &userinfo); - - tlvlist = aim_readtlvchain(data+i, datalen-i); - - /* - * Depending on what informational text was requested, different - * TLVs will appear here. - * - * Profile will be 1 and 2, away message will be 3 and 4. - */ - if (aim_gettlv(tlvlist, 0x0001, 1)) { - text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1); - text = aim_gettlv_str(tlvlist, 0x0002, 1); - } else if (aim_gettlv(tlvlist, 0x0003, 1)) { - text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1); - text = aim_gettlv_str(tlvlist, 0x0004, 1); - } - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, &userinfo, text_encoding, text, inforeq->infotype); - - free(text_encoding); - free(text); - - aim_freetlvchain(&tlvlist); - - if (origsnac) { - if (origsnac->data) - free(origsnac->data); - free(origsnac); - } - - return ret; + struct aim_userinfo_s userinfo; + char *text_encoding = NULL, *text = NULL; + aim_rxcallback_t userfunc; + aim_tlvlist_t *tlvlist; + aim_snac_t *origsnac = NULL; + struct aim_priv_inforeq *inforeq; + int ret = 0; + + origsnac = aim_remsnac(sess, snac->id); + + if (!origsnac || !origsnac->data) { + faimdprintf(sess, 0, "parse_userinfo_middle: major problem: no snac stored!\n"); + return 0; + } + + inforeq = (struct aim_priv_inforeq *)origsnac->data; + + if ((inforeq->infotype != AIM_GETINFO_GENERALINFO) && + (inforeq->infotype != AIM_GETINFO_AWAYMESSAGE)) { + faimdprintf(sess, 0, "parse_userinfo_middle: unknown infotype in request! (0x%04x)\n", inforeq->infotype); + return 0; + } + + aim_extractuserinfo(sess, bs, &userinfo); + + tlvlist = aim_readtlvchain(bs); + + /* + * Depending on what informational text was requested, different + * TLVs will appear here. + * + * Profile will be 1 and 2, away message will be 3 and 4. + */ + if (aim_gettlv(tlvlist, 0x0001, 1)) { + text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1); + text = aim_gettlv_str(tlvlist, 0x0002, 1); + } else if (aim_gettlv(tlvlist, 0x0003, 1)) { + text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1); + text = aim_gettlv_str(tlvlist, 0x0004, 1); + } + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, &userinfo, text_encoding, text, inforeq->infotype); + + free(text_encoding); + free(text); + + aim_freetlvchain(&tlvlist); + + if (origsnac) + free(origsnac->data); + free(origsnac); + + return ret; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0003) - return rights(sess, mod, rx, snac, data, datalen); - else if (snac->subtype == 0x0006) - return userinfo(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0003) + return rights(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0006) + return userinfo(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int locate_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int locate_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x0002; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "locate", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x0002; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "locate", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } diff --git a/src/login.c b/src/login.c index 041f823..784ac1b 100644 --- a/src/login.c +++ b/src/login.c @@ -12,109 +12,55 @@ static int aim_encode_password(const char *password, unsigned char *encoded); -faim_export int aim_sendflapver(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn) { - int curbyte=0; + aim_frame_t *fr; - struct command_tx_struct *newpacket; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0001, 4))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 4))) return -ENOMEM; - newpacket->lock = 1; - - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + aimbs_put32(&fr->data, 0x00000001); - newpacket->lock = 0; + aim_tx_enqueue(sess, fr); - return aim_tx_enqueue(sess, newpacket); + return 0; } /* - * In AIM 3.5 protocol, the first stage of login is to request - * login from the Authorizer, passing it the screen name - * for verification. If the name is invalid, a 0017/0003 - * is spit back, with the standard error contents. If valid, - * a 0017/0007 comes back, which is the signal to send - * it the main login command (0017/0002). + * In AIM 3.5 protocol, the first stage of login is to request login from the + * Authorizer, passing it the screen name for verification. If the name is + * invalid, a 0017/0003 is spit back, with the standard error contents. If + * valid, a 0017/0007 comes back, which is the signal to send it the main + * login command (0017/0002). + * + * XXX make ICQ logins work again. */ -faim_export int aim_request_login(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn) +faim_export int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn) { - int curbyte; - struct command_tx_struct *newpacket; - + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + if (!sess || !conn || !sn) return -EINVAL; - /* - * For ICQ, we enable the ancient horrible login and stuff - * a key packet into the queue to make it look like we got - * a reply back. This is so the client doesn't know we're - * really not doing MD5 login. - * - * This may sound stupid, but I'm not in the best of moods and - * I don't plan to keep support for this crap around much longer. - * Its all AOL's fault anyway, really. I hate AOL. Really. They - * always seem to be able to piss me off by doing the dumbest little - * things. Like disabling MD5 logins for ICQ UINs, or adding - * purposefully wrong TLV lengths, or adding superfluous information - * to host strings, or... I'll stop. - * - */ - if ((sn[0] >= '0') && (sn[0] <= '9')) { - struct command_rx_struct *newrx; - int i; - - /* XXX Uhm why doesn't this use aim_tx_new? */ - if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) - return -ENOMEM; - - memset(newrx, 0x00, sizeof(struct command_rx_struct)); - newrx->lock = 1; - newrx->hdrtype = AIM_FRAMETYPE_OSCAR; - newrx->hdr.oscar.type = 0x02; - newrx->hdr.oscar.seqnum = 0; - newrx->commandlen = 10+2+1; - newrx->nofree = 0; - - if (!(newrx->data = malloc(newrx->commandlen))) { - free(newrx); - return -ENOMEM; - } - - i = aim_putsnac(newrx->data, 0x0017, 0x0007, 0x0000, 0x0000); - i += aimutil_put16(newrx->data+i, 0x01); - i += aimutil_putstr(newrx->data+i, "0", 1); - - newrx->conn = conn; - - newrx->next = sess->queue_incoming; - sess->queue_incoming = newrx; - - newrx->lock = 0; - - sess->flags &= ~AIM_SESS_FLAGS_SNACLOGIN; - - return 0; - } - sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; aim_sendflapver(sess, conn); - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+2+strlen(sn)))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(sn)))) return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0017, 0x0006, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0017, 0x0006, 0x0000, snacid); - curbyte = aim_putsnac(newpacket->data, 0x0017, 0x0006, 0x0000, 0x00010000); - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn); + aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); - newpacket->commandlen = curbyte; - newpacket->lock = 0; + aim_tx_enqueue(sess, fr); - return aim_tx_enqueue(sess, newpacket); + return 0; } /* @@ -176,79 +122,74 @@ faim_export int aim_request_login(struct aim_session_t *sess, struct aim_conn_t * serverstore = 0x01 * */ -faim_export int aim_send_login (struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, char *password, struct client_info_s *clientinfo, char *key) +faim_export int aim_send_login(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password, struct client_info_s *clientinfo, const char *key) { - int curbyte=0; - struct command_tx_struct *newpacket; + aim_frame_t *fr; + aim_tlvlist_t *tl = NULL; if (!clientinfo || !sn || !password) return -EINVAL; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) return -ENOMEM; - newpacket->lock = 1; + if (sess->flags & AIM_SESS_FLAGS_XORLOGIN) { + fr->hdr.flap.type = 0x01; - newpacket->hdr.oscar.type = (sess->flags & AIM_SESS_FLAGS_SNACLOGIN)?0x02:0x01; + /* Use very specific version numbers to further indicate hack */ + clientinfo->major2 = 0x010a; + clientinfo->major = 0x0004; + clientinfo->minor = 0x003c; + clientinfo->minor2 = 0x0001; + clientinfo->build = 0x0cce; + clientinfo->unknown = 0x00000055; + } if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) - curbyte = aim_putsnac(newpacket->data, 0x0017, 0x0002, 0x0000, 0x00010000); - else { - curbyte = aimutil_put16(newpacket->data, 0x0000); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); - } + aim_putsnac(&fr->data, 0x0017, 0x0002, 0x0000, 0x00010000); + else + aimbs_put32(&fr->data, 0x00000001); - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn); + aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn); if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { - unsigned char digest[16]; + fu8_t digest[16]; aim_encode_password_md5(password, key, digest); - curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0025, 16, (char *)digest); + aim_addtlvtochain_raw(&tl, 0x0025, 16, digest); } else { char *password_encoded; password_encoded = (char *) malloc(strlen(password)); aim_encode_password(password, password_encoded); - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0002, strlen(password), password_encoded); + aim_addtlvtochain_raw(&tl, 0x0002, strlen(password), password_encoded); free(password_encoded); } - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring); - - if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { + aim_addtlvtochain_raw(&tl, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, (unsigned short)clientinfo->major2); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, (unsigned short)clientinfo->major); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, (unsigned short)clientinfo->minor); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, (unsigned short)clientinfo->minor2); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, (unsigned short)clientinfo->build); + aim_addtlvtochain16(&tl, 0x0016, (fu16_t)clientinfo->major2); + aim_addtlvtochain16(&tl, 0x0017, (fu16_t)clientinfo->major); + aim_addtlvtochain16(&tl, 0x0018, (fu16_t)clientinfo->minor); + aim_addtlvtochain16(&tl, 0x0019, (fu16_t)clientinfo->minor2); + aim_addtlvtochain16(&tl, 0x001a, (fu16_t)clientinfo->build); - } else { - /* Use very specific version numbers, to further indicate the hack. */ - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, 0x010a); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, 0x0004); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, 0x003c); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, 0x0001); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, 0x0cce); - curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, 0x00000055); - } + aim_addtlvtochain_raw(&tl, 0x000e, strlen(clientinfo->country), clientinfo->country); + aim_addtlvtochain_raw(&tl, 0x000f, strlen(clientinfo->lang), clientinfo->lang); - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000e, strlen(clientinfo->country), clientinfo->country); - curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000f, strlen(clientinfo->lang), clientinfo->lang); + if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) + aim_addtlvtochain16(&tl, 0x0009, 0x0015); - if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) { - curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, clientinfo->unknown); - curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015); - } + aim_writetlvchain(&fr->data, &tl); - newpacket->commandlen = curbyte; - newpacket->lock = 0; + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); - return aim_tx_enqueue(sess, newpacket); + return 0; } -faim_export int aim_encode_password_md5(const char *password, const char *key, unsigned char *digest) +faim_export int aim_encode_password_md5(const char *password, const char *key, fu8_t *digest) { md5_state_t state; @@ -278,9 +219,9 @@ faim_export int aim_encode_password_md5(const char *password, const char *key, u * This is only used for the XOR method, not the better MD5 method. * */ -static int aim_encode_password(const char *password, unsigned char *encoded) +static int aim_encode_password(const char *password, fu8_t *encoded) { - unsigned char encoding_table[] = { + fu8_t encoding_table[] = { #if 0 /* old v1 table */ 0xf3, 0xb3, 0x6c, 0x99, 0x95, 0x3f, 0xac, 0xb6, @@ -304,55 +245,51 @@ static int aim_encode_password(const char *password, unsigned char *encoded) /* * Generate an authorization response. * - * You probably don't want this unless you're writing an AIM server. + * You probably don't want this unless you're writing an AIM server. Which + * I hope you're not doing. Because it's far more difficult than it looks. * */ -faim_export unsigned long aim_sendauthresp(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *sn, int errorcode, - char *errorurl, char *bosip, - char *cookie, char *email, - int regstatus) +faim_export int aim_sendauthresp(aim_session_t *sess, aim_conn_t *conn, const char *sn, int errorcode, const char *errorurl, const char *bosip, const char *cookie, const char *email, int regstatus) { - struct command_tx_struct *tx; - struct aim_tlvlist_t *tlvlist = NULL; + aim_tlvlist_t *tlvlist = NULL; + aim_frame_t *fr; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0004, 1152))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x04, 1152))) return -ENOMEM; - tx->lock = 1; - if (sn) - aim_addtlvtochain_str(&tlvlist, 0x0001, sn, strlen(sn)); + aim_addtlvtochain_raw(&tlvlist, 0x0001, strlen(sn), sn); else - aim_addtlvtochain_str(&tlvlist, 0x0001, sess->sn, strlen(sess->sn)); + aim_addtlvtochain_raw(&tlvlist, 0x0001, strlen(sess->sn), sess->sn); if (errorcode) { aim_addtlvtochain16(&tlvlist, 0x0008, errorcode); - aim_addtlvtochain_str(&tlvlist, 0x0004, errorurl, strlen(errorurl)); + aim_addtlvtochain_raw(&tlvlist, 0x0004, strlen(errorurl), errorurl); } else { - aim_addtlvtochain_str(&tlvlist, 0x0005, bosip, strlen(bosip)); - aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN); - aim_addtlvtochain_str(&tlvlist, 0x0011, email, strlen(email)); - aim_addtlvtochain16(&tlvlist, 0x0013, (unsigned short)regstatus); + aim_addtlvtochain_raw(&tlvlist, 0x0005, strlen(bosip), bosip); + aim_addtlvtochain_raw(&tlvlist, 0x0006, AIM_COOKIELEN, cookie); + aim_addtlvtochain_raw(&tlvlist, 0x0011, strlen(email), email); + aim_addtlvtochain16(&tlvlist, 0x0013, (fu16_t)regstatus); } - tx->commandlen = aim_writetlvchain(tx->data, tx->commandlen, &tlvlist); - tx->lock = 0; + aim_writetlvchain(&fr->data, &tlvlist); + aim_freetlvchain(&tlvlist); + + aim_tx_enqueue(sess, fr); - return aim_tx_enqueue(sess, tx); + return 0; } /* * Generate a random cookie. (Non-client use only) */ -faim_export int aim_gencookie(unsigned char *buf) +faim_export int aim_gencookie(fu8_t *buf) { int i; srand(time(NULL)); - for (i=0; i < AIM_COOKIELEN; i++) + for (i = 0; i < AIM_COOKIELEN; i++) buf[i] = 1+(int) (256.0*rand()/(RAND_MAX+0.0)); return i; @@ -361,102 +298,97 @@ faim_export int aim_gencookie(unsigned char *buf) /* * Send Server Ready. (Non-client) */ -faim_export int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export int aim_sendserverready(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *tx; - int i; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+0x22))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+0x22))) return -ENOMEM; - tx->lock = 1; - - i = aim_putsnac(tx->data, 0x0001, 0x0003, 0x0000, sess->snac_nextid++); + snacid = aim_cachesnac(sess, 0x0001, 0x0003, 0x0000, NULL, 0); - i += aimutil_put16(tx->data+i, 0x0001); - i += aimutil_put16(tx->data+i, 0x0002); - i += aimutil_put16(tx->data+i, 0x0003); - i += aimutil_put16(tx->data+i, 0x0004); - i += aimutil_put16(tx->data+i, 0x0006); - i += aimutil_put16(tx->data+i, 0x0008); - i += aimutil_put16(tx->data+i, 0x0009); - i += aimutil_put16(tx->data+i, 0x000a); - i += aimutil_put16(tx->data+i, 0x000b); - i += aimutil_put16(tx->data+i, 0x000c); - i += aimutil_put16(tx->data+i, 0x0013); - i += aimutil_put16(tx->data+i, 0x0015); + aim_putsnac(&fr->data, 0x0001, 0x0003, 0x0000, snacid); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0002); + aimbs_put16(&fr->data, 0x0003); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0006); + aimbs_put16(&fr->data, 0x0008); + aimbs_put16(&fr->data, 0x0009); + aimbs_put16(&fr->data, 0x000a); + aimbs_put16(&fr->data, 0x000b); + aimbs_put16(&fr->data, 0x000c); + aimbs_put16(&fr->data, 0x0013); + aimbs_put16(&fr->data, 0x0015); - tx->commandlen = i; - tx->lock = 0; + aim_tx_enqueue(sess, fr); - return aim_tx_enqueue(sess, tx); + return 0; } /* * Send service redirect. (Non-Client) */ -faim_export unsigned long aim_sendredirect(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short servid, char *ip, char *cookie) +faim_export int aim_sendredirect(aim_session_t *sess, aim_conn_t *conn, fu16_t servid, const char *ip, const char *cookie) { - struct command_tx_struct *tx; - struct aim_tlvlist_t *tlvlist = NULL; - int i; + aim_tlvlist_t *tlvlist = NULL; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) return -ENOMEM; - tx->lock = 1; - - i = aim_putsnac(tx->data, 0x0001, 0x0005, 0x0000, 0x00000000); + snacid = aim_cachesnac(sess, 0x0001, 0x0005, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x0005, 0x0000, snacid); aim_addtlvtochain16(&tlvlist, 0x000d, servid); - aim_addtlvtochain_str(&tlvlist, 0x0005, ip, strlen(ip)); - aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN); + aim_addtlvtochain_raw(&tlvlist, 0x0005, strlen(ip), ip); + aim_addtlvtochain_raw(&tlvlist, 0x0006, AIM_COOKIELEN, cookie); - tx->commandlen = aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist)+i; + aim_writetlvchain(&fr->data, &tlvlist); aim_freetlvchain(&tlvlist); - tx->lock = 0; + aim_tx_enqueue(sess, fr); - return aim_tx_enqueue(sess, tx); + return 0; } -static int hostonline(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int hostonline(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; int ret = 0; - unsigned short *families; - int famcount, i; - - famcount = datalen/2; + fu16_t *families; + int famcount; - if (!(families = malloc(datalen))) + if (!(families = malloc(aim_bstream_empty(bs)))) return 0; - for (i = 0; i < famcount; i++) - families[i] = aimutil_get16(data+(i*2)); + for (famcount = 0; aim_bstream_empty(bs); famcount++) + families[famcount] = aimbs_get16(bs); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, famcount, families); free(families); - return ret; + return ret; } -static int redirect(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int redirect(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int serviceid; - unsigned char *cookie; + fu8_t *cookie; char *ip; aim_rxcallback_t userfunc; - struct aim_tlvlist_t *tlvlist; + aim_tlvlist_t *tlvlist; char *chathack = NULL; int chathackex = 0; int ret = 0; - tlvlist = aim_readtlvchain(data, datalen); + tlvlist = aim_readtlvchain(bs); if (!aim_gettlv(tlvlist, 0x000d, 1) || !aim_gettlv(tlvlist, 0x0005, 1) || @@ -542,7 +474,7 @@ static int redirect(struct aim_session_t *sess, aim_module_t *mod, struct comman */ /* XXX parse this */ -static int rateresp(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int rateresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; @@ -552,33 +484,22 @@ static int rateresp(struct aim_session_t *sess, aim_module_t *mod, struct comman return 0; } -static int ratechange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; - int i = 0, code; - unsigned long currentavg, maxavg; - unsigned long rateclass, windowsize, clear, alert, limit, disconnect; - - code = aimutil_get16(data+i); - i += 2; - - rateclass = aimutil_get16(data+i); - i += 2; - - windowsize = aimutil_get32(data+i); - i += 4; - clear = aimutil_get32(data+i); - i += 4; - alert = aimutil_get32(data+i); - i += 4; - limit = aimutil_get32(data+i); - i += 4; - disconnect = aimutil_get32(data+i); - i += 4; - currentavg = aimutil_get32(data+i); - i += 4; - maxavg = aimutil_get32(data+i); - i += 4; + fu16_t code, rateclass; + fu32_t currentavg, maxavg, windowsize, clear, alert, limit, disconnect; + + code = aimbs_get16(bs); + rateclass = aimbs_get16(bs); + + windowsize = aimbs_get32(bs); + clear = aimbs_get32(bs); + alert = aimbs_get32(bs); + limit = aimbs_get32(bs); + disconnect = aimbs_get32(bs); + currentavg = aimbs_get32(bs); + maxavg = aimbs_get32(bs); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) return userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg); @@ -587,7 +508,7 @@ static int ratechange(struct aim_session_t *sess, aim_module_t *mod, struct comm } /* XXX parse this */ -static int selfinfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; @@ -597,20 +518,18 @@ static int selfinfo(struct aim_session_t *sess, aim_module_t *mod, struct comman return 0; } -static int evilnotify(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - aim_rxcallback_t userfunc = NULL; - int i = 0; - unsigned short newevil; + aim_rxcallback_t userfunc; + fu16_t newevil; struct aim_userinfo_s userinfo; - newevil = aimutil_get16(data); - i += 2; - memset(&userinfo, 0, sizeof(struct aim_userinfo_s)); + + newevil = aimbs_get16(bs); - if (datalen-i) - i += aim_extractuserinfo(sess, data+i, &userinfo); + if (aim_bstream_empty(bs)) + aim_extractuserinfo(sess, bs, &userinfo); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) return userfunc(sess, rx, newevil, &userinfo); @@ -618,13 +537,13 @@ static int evilnotify(struct aim_session_t *sess, aim_module_t *mod, struct comm return 0; } -static int motd(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; char *msg = NULL; int ret = 0; - struct aim_tlvlist_t *tlvlist; - unsigned short id; + aim_tlvlist_t *tlvlist; + fu16_t id; /* * Code. @@ -636,13 +555,14 @@ static int motd(struct aim_session_t *sess, aim_module_t *mod, struct command_rx * 4 Nothing's wrong ("top o the world" -- normal) * */ - id = aimutil_get16(data); + id = aimbs_get16(bs); /* * TLVs follow */ - if ((tlvlist = aim_readtlvchain(data+2, datalen-2))) - msg = aim_gettlv_str(tlvlist, 0x000b, 1); + tlvlist = aim_readtlvchain(bs); + + msg = aim_gettlv_str(tlvlist, 0x000b, 1); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, id, msg); @@ -654,15 +574,19 @@ static int motd(struct aim_session_t *sess, aim_module_t *mod, struct command_rx return ret; } -static int hostversions(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int hostversions(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; int vercount; + fu8_t *versions; - vercount = datalen/4; + vercount = aim_bstream_empty(bs)/4; + versions = aimbs_getraw(bs, aim_bstream_empty(bs)); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - return userfunc(sess, rx, vercount, data); + return userfunc(sess, rx, vercount, versions); + + free(versions); return 0; } @@ -704,24 +628,18 @@ static int hostversions(struct aim_session_t *sess, aim_module_t *mod, struct co * Anyway, neener. We win again. * */ -static int memrequest(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { aim_rxcallback_t userfunc; - unsigned long offset, len; - int i = 0; - struct aim_tlvlist_t *list; - char *modname = NULL; - - offset = aimutil_get32(data); - i += 4; - - len = aimutil_get32(data+4); - i += 4; + fu32_t offset, len; + aim_tlvlist_t *list; + char *modname; - list = aim_readtlvchain(data+i, datalen-i); + offset = aimbs_get32(bs); + len = aimbs_get32(bs); + list = aim_readtlvchain(bs); - if (aim_gettlv(list, 0x0001, 1)) - modname = aim_gettlv_str(list, 0x0001, 1); + modname = aim_gettlv_str(list, 0x0001, 1); faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) of requested\n", offset, len, modname ? modname : "aim.exe"); @@ -734,7 +652,8 @@ static int memrequest(struct aim_session_t *sess, aim_module_t *mod, struct comm return 0; } -static void dumpbox(struct aim_session_t *sess, unsigned char *buf, int len) +#if 0 +static void dumpbox(aim_session_t *sess, unsigned char *buf, int len) { int i; @@ -754,39 +673,42 @@ static void dumpbox(struct aim_session_t *sess, unsigned char *buf, int len) return; } +#endif -faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag) +faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, fu32_t offset, fu32_t len, const fu8_t *buf, fu8_t flag) { - struct command_tx_struct *tx; - int i = 0; + aim_frame_t *fr; + aim_snacid_t snacid; if (!sess || !conn) return -EINVAL; - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+16))) + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+16))) return -ENOMEM; - tx->lock = 1; + snacid = aim_cachesnac(sess, 0x0001, 0x0020, 0x0000, NULL, 0); - i = aim_putsnac(tx->data, 0x0001, 0x0020, 0x0000, sess->snac_nextid++); - i += aimutil_put16(tx->data+i, 0x0010); /* md5 is always 16 bytes */ + aim_putsnac(&fr->data, 0x0001, 0x0020, 0x0000, snacid); + aimbs_put16(&fr->data, 0x0010); /* md5 is always 16 bytes */ if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && buf && (len == 0x10)) { /* we're getting a hash */ - memcpy(tx->data+i, buf, 0x10); - i += 0x10; + aimbs_putraw(&fr->data, buf, 0x10); } else if (buf && (len > 0)) { /* use input buffer */ md5_state_t state; + md5_byte_t digest[0x10]; md5_init(&state); md5_append(&state, (const md5_byte_t *)buf, len); - md5_finish(&state, (md5_byte_t *)(tx->data+i)); - i += 0x10; + md5_finish(&state, digest); + + aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10); } else if (len == 0) { /* no length, just hash NULL (buf is optional) */ md5_state_t state; - unsigned char nil = '\0'; + fu8_t nil = '\0'; + md5_byte_t digest[0x10]; /* * These MD5 routines are stupid in that you have to have @@ -795,8 +717,9 @@ faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t * */ md5_init(&state); md5_append(&state, (const md5_byte_t *)&nil, 0); - md5_finish(&state, (md5_byte_t *)(tx->data+i)); - i += 0x10; + md5_finish(&state, digest); + + aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10); } else { @@ -810,62 +733,60 @@ faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t * if ((offset == 0x03ffffff) && (len == 0x03ffffff)) { #if 1 /* with "AnrbnrAqhfzcd" */ - i += aimutil_put32(tx->data+i, 0x44a95d26); - i += aimutil_put32(tx->data+i, 0xd2490423); - i += aimutil_put32(tx->data+i, 0x93b8821f); - i += aimutil_put32(tx->data+i, 0x51c54b01); + aimbs_put32(&fr->data, 0x44a95d26); + aimbs_put32(&fr->data, 0xd2490423); + aimbs_put32(&fr->data, 0x93b8821f); + aimbs_put32(&fr->data, 0x51c54b01); #else /* no filename */ - i += aimutil_put32(tx->data+i, 0x1df8cbae); - i += aimutil_put32(tx->data+i, 0x5523b839); - i += aimutil_put32(tx->data+i, 0xa0e10db3); - i += aimutil_put32(tx->data+i, 0xa46d3b39); + aimbs_put32(&fr->data, 0x1df8cbae); + aimbs_put32(&fr->data, 0x5523b839); + aimbs_put32(&fr->data, 0xa0e10db3); + aimbs_put32(&fr->data, 0xa46d3b39); #endif } else if ((offset == 0x00001000) && (len == 0x00000000)) { - i += aimutil_put32(tx->data+i, 0xd41d8cd9); - i += aimutil_put32(tx->data+i, 0x8f00b204); - i += aimutil_put32(tx->data+i, 0xe9800998); - i += aimutil_put32(tx->data+i, 0xecf8427e); + aimbs_put32(&fr->data, 0xd41d8cd9); + aimbs_put32(&fr->data, 0x8f00b204); + aimbs_put32(&fr->data, 0xe9800998); + aimbs_put32(&fr->data, 0xecf8427e); } else faimdprintf(sess, 0, "sendmemblock: WARNING: unknown hash request\n"); } - tx->commandlen = i; - tx->lock = 0; - aim_tx_enqueue(sess, tx); + aim_tx_enqueue(sess, fr); return 0; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { if (snac->subtype == 0x0003) - return hostonline(sess, mod, rx, snac, data, datalen); + return hostonline(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0005) - return redirect(sess, mod, rx, snac, data, datalen); + return redirect(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0007) - return rateresp(sess, mod, rx, snac, data, datalen); + return rateresp(sess, mod, rx, snac, bs); else if (snac->subtype == 0x000a) - return ratechange(sess, mod, rx, snac, data, datalen); + return ratechange(sess, mod, rx, snac, bs); else if (snac->subtype == 0x000f) - return selfinfo(sess, mod, rx, snac, data, datalen); + return selfinfo(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0010) - return evilnotify(sess, mod, rx, snac, data, datalen); + return evilnotify(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0013) - return motd(sess, mod, rx, snac, data, datalen); + return motd(sess, mod, rx, snac, bs); else if (snac->subtype == 0x0018) - return hostversions(sess, mod, rx, snac, data, datalen); + return hostversions(sess, mod, rx, snac, bs); else if (snac->subtype == 0x001f) - return memrequest(sess, mod, rx, snac, data, datalen); + return memrequest(sess, mod, rx, snac, bs); return 0; } -faim_internal int general_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod) { mod->family = 0x0001; diff --git a/src/md5.c b/src/md5.c index 9b1ce6f..e627358 100644 --- a/src/md5.c +++ b/src/md5.c @@ -21,7 +21,6 @@ ghost@aladdin.com */ -/*$Id$ */ /* Independent implementation of MD5 (RFC 1321). diff --git a/src/meta.c b/src/meta.c index 55fff2a..5f40129 100644 --- a/src/meta.c +++ b/src/meta.c @@ -8,41 +8,42 @@ faim_export char *aim_getbuilddate(void) { - return AIM_BUILDDATE; + return AIM_BUILDDATE; } faim_export char *aim_getbuildtime(void) { - return AIM_BUILDTIME; + return AIM_BUILDTIME; } faim_export int aim_getbuildstring(char *buf, int buflen) { - snprintf(buf, buflen, "%d.%d.%d-%s%s", - FAIM_VERSION_MAJOR, - FAIM_VERSION_MINOR, - FAIM_VERSION_MINORMINOR, - aim_getbuilddate(), - aim_getbuildtime()); + snprintf(buf, buflen, "%d.%d.%d-%s%s", + FAIM_VERSION_MAJOR, + FAIM_VERSION_MINOR, + FAIM_VERSION_MINORMINOR, + aim_getbuilddate(), + aim_getbuildtime()); - return 0; + return 0; } -faim_internal void faimdprintf(struct aim_session_t *sess, int dlevel, const char *format, ...) +faim_internal void faimdprintf(aim_session_t *sess, int dlevel, const char *format, ...) { - if (!sess) { - fprintf(stderr, "faimdprintf: no session! boo! (%d, %s)\n", dlevel, format); - return; - } + if (!sess) { + fprintf(stderr, "faimdprintf: no session! boo! (%d, %s)\n", dlevel, format); + return; + } - if ((dlevel <= sess->debug) && sess->debugcb) { - va_list ap; + if ((dlevel <= sess->debug) && sess->debugcb) { + va_list ap; - va_start(ap, format); - sess->debugcb(sess, dlevel, format, ap); - va_end(ap); - } + va_start(ap, format); + sess->debugcb(sess, dlevel, format, ap); + va_end(ap); + } - return; + return; } + diff --git a/src/misc.c b/src/misc.c index 4f1a229..acc65be 100644 --- a/src/misc.c +++ b/src/misc.c @@ -22,11 +22,9 @@ * time. * */ -faim_export unsigned long aim_bos_setidle(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_long idletime) +faim_export int aim_bos_setidle(aim_session_t *sess, aim_conn_t *conn, fu32_t idletime) { - return aim_genericreq_l(sess, conn, 0x0001, 0x0011, &idletime); + return aim_genericreq_l(sess, conn, 0x0001, 0x0011, &idletime); } @@ -56,70 +54,58 @@ faim_export unsigned long aim_bos_setidle(struct aim_session_t *sess, * - Block the users below: Send an AIM_VISIBILITYCHANGE_DENYADD with * the list of users to be blocked * - * + * XXX ye gods. */ -faim_export unsigned long aim_bos_changevisibility(struct aim_session_t *sess, - struct aim_conn_t *conn, - int changetype, - char *denylist) +faim_export int aim_bos_changevisibility(aim_session_t *sess, aim_conn_t *conn, int changetype, const char *denylist) { - struct command_tx_struct *newpacket; - int packlen = 0; - u_short subtype; - - char *localcpy = NULL; - char *tmpptr = NULL; - int i,j; - int listcount; - - if (!denylist) - return 0; - - localcpy = (char *) malloc(strlen(denylist)+1); - memcpy(localcpy, denylist, strlen(denylist)+1); - - listcount = aimutil_itemcnt(localcpy, '&'); - packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, packlen))) - return -1; - - newpacket->lock = 1; - - switch(changetype) - { - case AIM_VISIBILITYCHANGE_PERMITADD: subtype = 0x05; break; - case AIM_VISIBILITYCHANGE_PERMITREMOVE: subtype = 0x06; break; - case AIM_VISIBILITYCHANGE_DENYADD: subtype = 0x07; break; - case AIM_VISIBILITYCHANGE_DENYREMOVE: subtype = 0x08; break; - default: - free(newpacket->data); - free(newpacket); - return 0; - } - - /* We actually DO NOT send a SNAC ID with this one! */ - aim_putsnac(newpacket->data, 0x0009, subtype, 0x00, 0); - - j = 10; /* the next byte */ - - for (i=0; (i < (listcount - 1)) && (i < 99); i++) - { - tmpptr = aimutil_itemidx(localcpy, i, '&'); - - newpacket->data[j] = strlen(tmpptr); - memcpy(&(newpacket->data[j+1]), tmpptr, strlen(tmpptr)); - j += strlen(tmpptr)+1; - free(tmpptr); - } - free(localcpy); - - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); - - return (sess->snac_nextid); /* dont increment */ + aim_frame_t *fr; + int packlen = 0; + fu16_t subtype; + char *localcpy = NULL, *tmpptr = NULL; + int i; + int listcount; + aim_snacid_t snacid; + + if (!denylist) + return -EINVAL; + + if (changetype == AIM_VISIBILITYCHANGE_PERMITADD) + subtype = 0x05; + else if (changetype == AIM_VISIBILITYCHANGE_PERMITREMOVE) + subtype = 0x06; + else if (changetype == AIM_VISIBILITYCHANGE_DENYADD) + subtype = 0x07; + else if (changetype == AIM_VISIBILITYCHANGE_DENYREMOVE) + subtype = 0x08; + else + return -EINVAL; + + localcpy = strdup(denylist); + + listcount = aimutil_itemcnt(localcpy, '&'); + packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, packlen))) { + free(localcpy); + return -ENOMEM; + } + + snacid = aim_cachesnac(sess, 0x0009, subtype, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0009, subtype, 0x00, snacid); + + for (i = 0; (i < (listcount - 1)) && (i < 99); i++) { + tmpptr = aimutil_itemidx(localcpy, i, '&'); + + aimbs_put8(&fr->data, strlen(tmpptr)); + aimbs_putraw(&fr->data, tmpptr, strlen(tmpptr)); + + free(tmpptr); + } + free(localcpy); + + aim_tx_enqueue(sess, fr); + return 0; } @@ -136,63 +122,50 @@ faim_export unsigned long aim_bos_changevisibility(struct aim_session_t *sess, * XXX: I can't stress the TODO enough. * */ -faim_export unsigned long aim_bos_setbuddylist(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *buddy_list) +faim_export int aim_bos_setbuddylist(aim_session_t *sess, aim_conn_t *conn, const char *buddy_list) { - int i, j; - - struct command_tx_struct *newpacket; - - int len = 0; - - char *localcpy = NULL; - char *tmpptr = NULL; - - len = 10; /* 10B SNAC headers */ - - if (!buddy_list || !(localcpy = (char *) malloc(strlen(buddy_list)+1))) - return -1; - strncpy(localcpy, buddy_list, strlen(buddy_list)+1); - - i = 0; - tmpptr = strtok(localcpy, "&"); - while ((tmpptr != NULL) && (i < 150)) { - faimdprintf(sess, 2, "---adding %d: %s (%d)\n", i, tmpptr, strlen(tmpptr)); - len += 1+strlen(tmpptr); - i++; - tmpptr = strtok(NULL, "&"); - } - faimdprintf(sess, 2, "*** send buddy list len: %d (%x)\n", len, len); - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, len))) - return -1; - - newpacket->lock = 1; - - aim_putsnac(newpacket->data, 0x0003, 0x0004, 0x0000, 0); - - j = 10; /* the next byte */ - - strncpy(localcpy, buddy_list, strlen(buddy_list)+1); - i = 0; - tmpptr = strtok(localcpy, "&"); - while ((tmpptr != NULL) & (i < 150)) { - faimdprintf(sess, 2, "---adding %d: %s (%d)\n", i, tmpptr, strlen(tmpptr)); - newpacket->data[j] = strlen(tmpptr); - memcpy(&(newpacket->data[j+1]), tmpptr, strlen(tmpptr)); - j += 1+strlen(tmpptr); - i++; - tmpptr = strtok(NULL, "&"); - } + aim_frame_t *fr; + aim_snacid_t snacid; + int i, len = 0; + char *localcpy = NULL; + char *tmpptr = NULL; + + if (!buddy_list || !(localcpy = strdup(buddy_list))) + return -EINVAL; + + i = 0; + tmpptr = strtok(localcpy, "&"); + while ((tmpptr != NULL) && (i < 150)) { + faimdprintf(sess, 2, "---adding %d: %s (%d)\n", i, tmpptr, strlen(tmpptr)); + len += 1+strlen(tmpptr); + i++; + tmpptr = strtok(NULL, "&"); + } + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+len))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid); + + strncpy(localcpy, buddy_list, strlen(buddy_list)+1); + i = 0; + tmpptr = strtok(localcpy, "&"); + while ((tmpptr != NULL) & (i < 150)) { + faimdprintf(sess, 2, "---adding %d: %s (%d)\n", i, tmpptr, strlen(tmpptr)); + + aimbs_put8(&fr->data, strlen(tmpptr)); + aimbs_putraw(&fr->data, tmpptr, strlen(tmpptr)); + i++; + tmpptr = strtok(NULL, "&"); + } + + aim_tx_enqueue(sess, fr); + + free(localcpy); - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); - - free(localcpy); - - return (sess->snac_nextid); + return 0; } /* @@ -202,49 +175,38 @@ faim_export unsigned long aim_bos_setbuddylist(struct aim_session_t *sess, * * */ -faim_export unsigned long aim_bos_setprofile(struct aim_session_t *sess, - struct aim_conn_t *conn, - const char *profile, - const char *awaymsg, - unsigned short caps) +faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu16_t caps) { - struct command_tx_struct *newpacket; - int i = 0, tmp, caplen; - static const char defencoding[] = {"text/aolrtf; charset=\"us-ascii\""}; - - i = 10; - if (profile) - i += 4+strlen(defencoding)+4+strlen(profile); - if (awaymsg) - i += 4+strlen(defencoding)+4+strlen(awaymsg); - i += 4+512; /* for capabilities */ - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, i))) - return -1; - - i = aim_putsnac(newpacket->data, 0x0002, 0x004, 0x0000, sess->snac_nextid); - - if (profile) { - i += aim_puttlv_str(newpacket->data+i, 0x0001, strlen(defencoding), defencoding); - i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(profile), profile); - } - - if (awaymsg) { - i += aim_puttlv_str(newpacket->data+i, 0x0003, strlen(defencoding), defencoding); - i += aim_puttlv_str(newpacket->data+i, 0x0004, strlen(awaymsg), awaymsg); - } - - /* Capability information. */ - - tmp = (i += aimutil_put16(newpacket->data+i, 0x0005)); - i += aimutil_put16(newpacket->data+i, 0x0000); /* rewritten later */ - i += (caplen = aim_putcap(newpacket->data+i, 512, caps)); - aimutil_put16(newpacket->data+tmp, caplen); /* rewrite TLV size */ - - newpacket->commandlen = i; - aim_tx_enqueue(sess, newpacket); - - return (sess->snac_nextid++); + static const char defencoding[] = {"text/aolrtf; charset=\"us-ascii\""}; + aim_frame_t *fr; + aim_tlvlist_t *tl = NULL; + aim_snacid_t snacid; + + /* Build to packet first to get real length */ + if (profile) { + aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), defencoding); + aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), profile); + } + + if (awaymsg) { + aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), defencoding); + aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), awaymsg); + } + + aim_addtlvtochain_caps(&tl, 0x0005, caps); + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_sizetlvchain(&tl)))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0002, 0x004, 0x0000, snacid); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); + + return 0; } /* @@ -253,85 +215,75 @@ faim_export unsigned long aim_bos_setprofile(struct aim_session_t *sess, * Send Client Ready. * */ -faim_export unsigned long aim_bos_clientready(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_clientready(aim_session_t *sess, aim_conn_t *conn) { - struct aim_tool_version tools[] = { - {0x0001, 0x0003, AIM_TOOL_WIN32, 0x0686}, - {0x0002, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x0003, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x0004, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x0006, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x0008, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x0009, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x000a, 0x0001, AIM_TOOL_WIN32, 0x0001}, - {0x000b, 0x0001, AIM_TOOL_WIN32, 0x0001} - }; - int i,j; - struct command_tx_struct *newpacket; - int toolcount = sizeof(tools)/sizeof(struct aim_tool_version); - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); - - for (j = 0; j < toolcount; j++) { - i += aimutil_put16(newpacket->data+i, tools[j].group); - i += aimutil_put16(newpacket->data+i, tools[j].version); - i += aimutil_put16(newpacket->data+i, tools[j].tool); - i += aimutil_put16(newpacket->data+i, tools[j].toolversion); - } - - newpacket->commandlen = i; - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + struct aim_tool_version tools[] = { + {0x0001, 0x0003, AIM_TOOL_WIN32, 0x0686}, + {0x0002, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x0003, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x0004, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x0006, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x0008, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x0009, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x000a, 0x0001, AIM_TOOL_WIN32, 0x0001}, + {0x000b, 0x0001, AIM_TOOL_WIN32, 0x0001} + }; + int j; + aim_frame_t *fr; + aim_snacid_t snacid; + int toolcount = sizeof(tools)/sizeof(struct aim_tool_version); + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid); + + for (j = 0; j < toolcount; j++) { + aimbs_put16(&fr->data, tools[j].group); + aimbs_put16(&fr->data, tools[j].version); + aimbs_put16(&fr->data, tools[j].tool); + aimbs_put16(&fr->data, tools[j].toolversion); + } + + aim_tx_enqueue(sess, fr); + + return 0; } /* * Request Rate Information. * */ -faim_export unsigned long aim_bos_reqrate(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_reqrate(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0001, 0x0006); + return aim_genericreq_n(sess, conn, 0x0001, 0x0006); } /* * Rate Information Response Acknowledge. * */ -faim_export unsigned long aim_bos_ackrateresp(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_ackrateresp(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int packlen = 20, i=0; - - if(!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, packlen))) - return (sess->snac_nextid); - - newpacket->lock = 1; + aim_frame_t *fr; + aim_snacid_t snacid; - i = aim_putsnac(newpacket->data, 0x0001, 0x0008, 0x0000, 0); - i += aimutil_put16(newpacket->data+i, 0x0001); - i += aimutil_put16(newpacket->data+i, 0x0002); - i += aimutil_put16(newpacket->data+i, 0x0003); - i += aimutil_put16(newpacket->data+i, 0x0004); - i += aimutil_put16(newpacket->data+i, 0x0005); + if(!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+10))) + return -ENOMEM; - newpacket->commandlen = i; - newpacket->lock = 0; + snacid = aim_cachesnac(sess, 0x0001, 0x0008, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0001, 0x0008, 0x0000, snacid); + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, 0x0002); + aimbs_put16(&fr->data, 0x0003); + aimbs_put16(&fr->data, 0x0004); + aimbs_put16(&fr->data, 0x0005); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return (sess->snac_nextid); + return 0; } /* @@ -343,81 +295,58 @@ faim_export unsigned long aim_bos_ackrateresp(struct aim_session_t *sess, * Bit 2: Allows other AIM users to see how long you've been a member. * */ -faim_export unsigned long aim_bos_setprivacyflags(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_long flags) +faim_export int aim_bos_setprivacyflags(aim_session_t *sess, aim_conn_t *conn, fu32_t flags) { - return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags); + return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags); } /* * aim_bos_reqpersonalinfo() * - * Requests the current user's information. Can't go generic on this one - * because aparently it uses SNAC flags. - * */ -faim_export unsigned long aim_bos_reqpersonalinfo(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_reqpersonalinfo(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0001, 0x000e); + return aim_genericreq_n(sess, conn, 0x0001, 0x000e); } -faim_export unsigned long aim_setversions(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_setversions(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; - int i; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + (4*16)))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0001, 0x0017, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); - - i += aimutil_put16(newpacket->data+i, 0x0001); - i += aimutil_put16(newpacket->data+i, 0x0003); - - i += aimutil_put16(newpacket->data+i, 0x0002); - i += aimutil_put16(newpacket->data+i, 0x0001); - - i += aimutil_put16(newpacket->data+i, 0x0003); - i += aimutil_put16(newpacket->data+i, 0x0001); - - i += aimutil_put16(newpacket->data+i, 0x0004); - i += aimutil_put16(newpacket->data+i, 0x0001); - - 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); + aim_frame_t *fr; + aim_snacid_t snacid; + static const struct version { + fu16_t group; + fu16_t version; + } versions[] = { + {0x0001, 0x0003}, + {0x0002, 0x0001}, + {0x0003, 0x0001}, + {0x0004, 0x0001}, + {0x0006, 0x0001}, + {0x0008, 0x0001}, + {0x0009, 0x0001}, + {0x000a, 0x0001}, + {0x000b, 0x0002}, + {0x000c, 0x0001}, + {0x0013, 0x0001}, + {0x0015, 0x0001}, + }; + int numversions = sizeof(versions) / sizeof(struct version); + int i; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + (4*numversions)))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0001, 0x0017, 0x0000, snacid); + for (i = 0; i < numversions; i++) { + aimbs_put16(&fr->data, versions[i].group); + aimbs_put16(&fr->data, versions[i].version); + } + + aim_tx_enqueue(sess, fr); - i += aimutil_put16(newpacket->data+i, 0x000b); - i += aimutil_put16(newpacket->data+i, 0x0002); - - i += aimutil_put16(newpacket->data+i, 0x000c); - i += aimutil_put16(newpacket->data+i, 0x0001); - - i += aimutil_put16(newpacket->data+i, 0x0013); - i += aimutil_put16(newpacket->data+i, 0x0001); - - i += aimutil_put16(newpacket->data+i, 0x0015); - i += aimutil_put16(newpacket->data+i, 0x0001); - - newpacket->commandlen = i; - newpacket->lock = 0; - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + return 0; } @@ -427,11 +356,9 @@ faim_export unsigned long aim_setversions(struct aim_session_t *sess, * Service request. * */ -faim_export unsigned long aim_bos_reqservice(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short serviceid) +faim_export int aim_bos_reqservice(aim_session_t *sess, aim_conn_t *conn, fu16_t serviceid) { - return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid); + return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid); } /* @@ -441,10 +368,9 @@ faim_export unsigned long aim_bos_reqservice(struct aim_session_t *sess, * the connection alive. Its not real necessary. * */ -faim_export unsigned long aim_bos_nop(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_nop(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0001, 0x0016); + return aim_genericreq_n(sess, conn, 0x0001, 0x0016); } /* @@ -453,21 +379,16 @@ faim_export unsigned long aim_bos_nop(struct aim_session_t *sess, * No-op. WinAIM 4.x sends these _every minute_ to keep * the connection alive. */ -faim_export unsigned long aim_flap_nop(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_flap_nop(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *newpacket; + aim_frame_t *fr; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0005, 0))) - return sess->snac_nextid; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x05, 0))) + return -ENOMEM; - newpacket->lock = 1; - newpacket->commandlen = 0; - newpacket->lock = 0; + aim_tx_enqueue(sess, fr); - aim_tx_enqueue(sess, newpacket); - - return (sess->snac_nextid); + return 0; } /* @@ -476,10 +397,9 @@ faim_export unsigned long aim_flap_nop(struct aim_session_t *sess, * Request BOS rights. * */ -faim_export unsigned long aim_bos_reqrights(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_reqrights(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0009, 0x0002); + return aim_genericreq_n(sess, conn, 0x0009, 0x0002); } /* @@ -488,10 +408,9 @@ faim_export unsigned long aim_bos_reqrights(struct aim_session_t *sess, * Request Buddy List rights. * */ -faim_export unsigned long aim_bos_reqbuddyrights(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_reqbuddyrights(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0003, 0x0002); + return aim_genericreq_n(sess, conn, 0x0003, 0x0002); } /* @@ -503,35 +422,27 @@ faim_export unsigned long aim_bos_reqbuddyrights(struct aim_session_t *sess, * returns -1 on error (couldn't alloc packet), 0 on success. * */ -faim_export int aim_send_warning(struct aim_session_t *sess, struct aim_conn_t *conn, const char *destsn, unsigned long flags) +faim_export int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, fu32_t flags) { - struct command_tx_struct *newpacket; - int curbyte; - unsigned short outflags = 0x0000; + aim_frame_t *fr; + aim_snacid_t snacid; + fu16_t outflags = 0x0000; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, - strlen(destsn)+13))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(destsn)+13))) + return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1); - curbyte = 0; - curbyte += aim_putsnac(newpacket->data+curbyte, - 0x0004, 0x0008, 0x0000, sess->snac_nextid); + aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid); if (flags & AIM_WARN_ANON) outflags |= 0x0001; - curbyte += aimutil_put16(newpacket->data+curbyte, outflags); - curbyte += aimutil_put8(newpacket->data+curbyte, strlen(destsn)); - curbyte += aimutil_putstr(newpacket->data+curbyte, destsn, strlen(destsn)); - - newpacket->commandlen = curbyte; - newpacket->lock = 0; + aimbs_put16(&fr->data, outflags); + aimbs_put8(&fr->data, strlen(destsn)); + aimbs_putraw(&fr->data, destsn, strlen(destsn)); - aim_tx_enqueue(sess, newpacket); - - aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1); + aim_tx_enqueue(sess, fr); return 0; } @@ -541,10 +452,9 @@ faim_export int aim_send_warning(struct aim_session_t *sess, struct aim_conn_t * * * For aimdebugd. If you don't know what it is, you don't want to. */ -faim_export unsigned long aim_debugconn_sendconnect(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_debugconn_sendconnect(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT); + return aim_genericreq_n(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT); } /* @@ -559,102 +469,81 @@ faim_export unsigned long aim_debugconn_sendconnect(struct aim_session_t *sess, * back to the single. I don't see any advantage to doing it either way. * */ -faim_internal unsigned long aim_genericreq_n(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short family, u_short subtype) +faim_internal int aim_genericreq_n(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t subtype) { - struct command_tx_struct *newpacket; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10))) - return 0; + aim_frame_t *fr; + aim_snacid_t snacid = 0x00000000; - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10))) + return -ENOMEM; - aim_putsnac(newpacket->data, family, subtype, 0x0000, 0x00000000); + aim_putsnac(&fr->data, family, subtype, 0x0000, snacid); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid; + return 0; } -faim_internal unsigned long aim_genericreq_n_snacid(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned short family, - unsigned short subtype) +faim_internal int aim_genericreq_n_snacid(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t subtype) { - struct command_tx_struct *newpacket; - - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10))) - return 0; + aim_frame_t *fr; + aim_snacid_t snacid; - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10))) + return -ENOMEM; - aim_putsnac(newpacket->data, family, subtype, 0x0000, sess->snac_nextid); - aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0); + snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0); + aim_putsnac(&fr->data, family, subtype, 0x0000, snacid); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid++; + return 0; } /* * * */ -faim_internal unsigned long aim_genericreq_l(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short family, u_short subtype, - u_long *longdata) +faim_internal int aim_genericreq_l(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t subtype, fu32_t *longdata) { - struct command_tx_struct *newpacket; - u_long newlong; + aim_frame_t *fr; + aim_snacid_t snacid; - /* If we don't have data, there's no reason to use this function */ - if (!longdata) - return aim_genericreq_n(sess, conn, family, subtype); + if (!longdata) + return aim_genericreq_n(sess, conn, family, subtype); - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+sizeof(u_long)))) - return -1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4))) + return -ENOMEM; - newpacket->lock = 1; + snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0); - aim_putsnac(newpacket->data, family, subtype, 0x0000, 0x00000000); + aim_putsnac(&fr->data, family, subtype, 0x0000, snacid); + aimbs_put32(&fr->data, *longdata); - /* copy in data */ - newlong = htonl(*longdata); - memcpy(&(newpacket->data[10]), &newlong, sizeof(u_long)); + aim_tx_enqueue(sess, fr); - aim_tx_enqueue(sess, newpacket); - - return sess->snac_nextid; + return 0; } -faim_internal unsigned long aim_genericreq_s(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short family, u_short subtype, - u_short *shortdata) +faim_internal int aim_genericreq_s(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t subtype, fu16_t *shortdata) { - struct command_tx_struct *newpacket; - u_short newshort; - - /* If we don't have data, there's no reason to use this function */ - if (!shortdata) - return aim_genericreq_n(sess, conn, family, subtype); + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+sizeof(u_short)))) - return -1; + if (!shortdata) + return aim_genericreq_n(sess, conn, family, subtype); - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2))) + return -ENOMEM; - aim_putsnac(newpacket->data, family, subtype, 0x0000, 0x00000000); + snacid = aim_cachesnac(sess, family, subtype, 0x0000, NULL, 0); - /* copy in data */ - newshort = htons(*shortdata); - memcpy(&(newpacket->data[10]), &newshort, sizeof(u_short)); + aim_putsnac(&fr->data, family, subtype, 0x0000, snacid); + aimbs_put16(&fr->data, *shortdata); - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - return sess->snac_nextid; + return 0; } /* @@ -663,202 +552,169 @@ faim_internal unsigned long aim_genericreq_s(struct aim_session_t *sess, * Request Location services rights. * */ -faim_export unsigned long aim_bos_reqlocaterights(struct aim_session_t *sess, - struct aim_conn_t *conn) +faim_export int aim_bos_reqlocaterights(aim_session_t *sess, aim_conn_t *conn) { - return aim_genericreq_n(sess, conn, 0x0002, 0x0002); + return aim_genericreq_n(sess, conn, 0x0002, 0x0002); } /* * Set directory profile data (not the same as aim_bos_setprofile!) + * + * privacy: 1 to allow searching, 0 to disallow. */ -faim_export unsigned long aim_setdirectoryinfo(struct aim_session_t *sess, struct aim_conn_t *conn, char *first, char *middle, char *last, char *maiden, char *nickname, char *street, char *city, char *state, char *zip, int country, unsigned short privacy) +faim_export int aim_setdirectoryinfo(aim_session_t *sess, aim_conn_t *conn, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, fu16_t privacy) { - struct command_tx_struct *newpacket; - int packlen = 0, i = 0; - - packlen += 2+2+2; - - if(first) /* TLV 0001 */ - packlen += (strlen(first) + 4); - if(middle) - packlen += (strlen(middle) + 4); - if(last) - packlen += (strlen(last) + 4); - if(maiden) - packlen += (strlen(maiden) + 4); - if(nickname) - packlen += (strlen(nickname) + 4); - if(street) - packlen += (strlen(street) + 4); - if(state) - packlen += (strlen(state) + 4); - if(city) - packlen += (strlen(city) + 4); - if(zip) - packlen += (strlen(zip) + 4); - - if(!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, packlen+10))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0002, 0x0009, 0x0000, 0); - - /* 000a/0002: privacy: 1 to allow search/disp, 0 to disallow */ - i += aim_puttlv_16(newpacket->data+i, 0x000a, privacy); - - - if (first) - i += aim_puttlv_str(newpacket->data+i, 0x0001, strlen(first), first); - if (middle) - i += aim_puttlv_str(newpacket->data+i, 0x0003, strlen(middle), middle); - if (last) - i += aim_puttlv_str(newpacket->data+i, 0x0002, strlen(last), last); - if (maiden) - i += aim_puttlv_str(newpacket->data+i, 0x0004, strlen(maiden), maiden); - if (nickname) - i += aim_puttlv_str(newpacket->data+i, 0x000c, strlen(nickname), nickname); - if (street) - i += aim_puttlv_str(newpacket->data+i, 0x0021, strlen(street), street); - if (city) - i += aim_puttlv_str(newpacket->data+i, 0x0008, strlen(city), city); - if (state) - i += aim_puttlv_str(newpacket->data+i, 0x0007, strlen(state), state); - if (zip) - i += aim_puttlv_str(newpacket->data+i, 0x000d, strlen(zip), zip); - - newpacket->commandlen = i; - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); - - return(sess->snac_nextid); -} + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; -faim_export unsigned long aim_setuserinterests(struct aim_session_t *sess, struct aim_conn_t *conn, char *interest1, char *interest2, char *interest3, char *interest4, char *interest5, unsigned short privacy) -{ - struct command_tx_struct *newpacket; - int packlen = 0, i = 0; - - packlen += 2+2+2; - - if(interest1) - packlen += (strlen(interest1) + 4); - if(interest2) - packlen += (strlen(interest2) + 4); - if(interest3) - packlen += (strlen(interest3) + 4); - if(interest4) - packlen += (strlen(interest4) + 4); - if(interest5) - packlen += (strlen(interest5) + 4) ; - - - if(!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, packlen+10))) - return -1; - - newpacket->lock = 1; - - i = aim_putsnac(newpacket->data, 0x0002, 0x000f, 0x0000, 0); - - /* 000a/0002: 0000 ?? ?privacy? */ - i += aim_puttlv_16(newpacket->data+i, 0x000a, privacy); - - if(interest1) - i += aim_puttlv_str(newpacket->data+i, 0x000b, strlen(interest1), interest1); - if(interest2) - i += aim_puttlv_str(newpacket->data+i, 0x000b, strlen(interest2), interest2); - if(interest3) - i += aim_puttlv_str(newpacket->data+i, 0x000b, strlen(interest3), interest3); - if(interest4) - i += aim_puttlv_str(newpacket->data+i, 0x000b, strlen(interest4), interest4); - if(interest5) - i += aim_puttlv_str(newpacket->data+i, 0x000b, strlen(interest1), interest5); - - newpacket->commandlen = i; - newpacket->lock = 0; - - aim_tx_enqueue(sess, newpacket); - - return(sess->snac_nextid); + + aim_addtlvtochain16(&tl, 0x000a, privacy); + + if (first) + aim_addtlvtochain_raw(&tl, 0x0001, strlen(first), first); + if (last) + aim_addtlvtochain_raw(&tl, 0x0002, strlen(last), last); + if (middle) + aim_addtlvtochain_raw(&tl, 0x0003, strlen(middle), middle); + if (maiden) + aim_addtlvtochain_raw(&tl, 0x0004, strlen(maiden), maiden); + + if (state) + aim_addtlvtochain_raw(&tl, 0x0007, strlen(state), state); + if (city) + aim_addtlvtochain_raw(&tl, 0x0008, strlen(city), city); + + if (nickname) + aim_addtlvtochain_raw(&tl, 0x000c, strlen(nickname), nickname); + if (zip) + aim_addtlvtochain_raw(&tl, 0x000d, strlen(zip), zip); + + if (street) + aim_addtlvtochain_raw(&tl, 0x0021, strlen(street), street); + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl)))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0002, 0x0009, 0x0000, NULL, 0); + + aim_putsnac(&fr->data, 0x0002, 0x0009, 0x0000, snacid); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); + + return 0; } -faim_export unsigned long aim_icq_setstatus(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned long status) +/* XXX pass these in better */ +faim_export int aim_setuserinterests(aim_session_t *sess, aim_conn_t *conn, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, fu16_t privacy) { - struct command_tx_struct *newpacket; - int i; - unsigned long data; - - data = 0x00030000 | status; /* yay for error checking ;^) */ + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; - if(!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10 + 4))) - return -1; + /* ?? privacy ?? */ + aim_addtlvtochain16(&tl, 0x000a, privacy); - newpacket->lock = 1; + if (interest1) + aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest1), interest1); + if (interest2) + aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest2), interest2); + if (interest3) + aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest3), interest3); + if (interest4) + aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest4), interest4); + if (interest5) + aim_addtlvtochain_raw(&tl, 0x0000b, strlen(interest5), interest5); - i = aim_putsnac(newpacket->data, 0x0001, 0x001e, 0x0000, 0x0000001e); - i += aim_puttlv_32(newpacket->data+i, 0x0006, data); + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+aim_sizetlvchain(&tl)))) + return -ENOMEM; - newpacket->commandlen = i; - newpacket->lock = 0; + snacid = aim_cachesnac(sess, 0x0002, 0x000f, 0x0000, NULL, 0); - aim_tx_enqueue(sess, newpacket); + aim_putsnac(&fr->data, 0x0002, 0x000f, 0x0000, 0); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); - return(sess->snac_nextid); + aim_tx_enqueue(sess, fr); + + return 0; +} + +faim_export int aim_icq_setstatus(aim_session_t *sess, aim_conn_t *conn, fu32_t status) +{ + aim_frame_t *fr; + aim_snacid_t snacid; + aim_tlvlist_t *tl = NULL; + fu32_t data; + + data = 0x00030000 | status; /* yay for error checking ;^) */ + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid); + + aim_addtlvtochain32(&tl, 0x0006, data); + aim_writetlvchain(&fr->data, &tl); + aim_freetlvchain(&tl); + + aim_tx_enqueue(sess, fr); + + return 0; } /* * Should be generic enough to handle the errors for all families... * */ -static int generror(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int generror(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - int ret = 0; - int error = 0; - aim_rxcallback_t userfunc; - struct aim_snac_t *snac2; + int ret = 0; + int error = 0; + aim_rxcallback_t userfunc; + aim_snac_t *snac2; - snac2 = aim_remsnac(sess, snac->id); + snac2 = aim_remsnac(sess, snac->id); - if (datalen) - error = aimutil_get16(data); + if (aim_bstream_empty(bs)) + error = aimbs_get16(bs); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, error, snac2?snac2->data:NULL); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, error, snac2 ? snac2->data : NULL); - if (snac2) - free(snac2->data); - free(snac2); + if (snac2) + free(snac2->data); + free(snac2); - return ret; + return ret; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0001) - return generror(sess, mod, rx, snac, data, datalen); - else if ((snac->family == 0xffff) && (snac->subtype == 0xffff)) { - aim_rxcallback_t userfunc; + if (snac->subtype == 0x0001) + return generror(sess, mod, rx, snac, bs); + else if ((snac->family == 0xffff) && (snac->subtype == 0xffff)) { + aim_rxcallback_t userfunc; - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - return userfunc(sess, rx); - } + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx); + } - return 0; + return 0; } -faim_internal int misc_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int misc_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0xffff; - mod->version = 0x0000; - mod->flags = AIM_MODFLAG_MULTIFAMILY; - strncpy(mod->name, "misc", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0xffff; + mod->version = 0x0000; + mod->flags = AIM_MODFLAG_MULTIFAMILY; + strncpy(mod->name, "misc", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } diff --git a/src/msgcookie.c b/src/msgcookie.c index 5ffa590..50f186f 100644 --- a/src/msgcookie.c +++ b/src/msgcookie.c @@ -27,29 +27,27 @@ * in may be free'd, so don't count on its value after calling this! * */ -faim_internal int aim_cachecookie(struct aim_session_t *sess, - struct aim_msgcookie_t *cookie) +faim_internal int aim_cachecookie(aim_session_t *sess, aim_msgcookie_t *cookie) { - struct aim_msgcookie_t *newcook; + aim_msgcookie_t *newcook; - if (!sess || !cookie) - return -1; + if (!sess || !cookie) + return -EINVAL; - if( (newcook = aim_checkcookie(sess, cookie->cookie, cookie->type)) ) { - if(newcook != cookie) { - aim_cookie_free(sess, newcook); - } else { - newcook->addtime = time(NULL); - return 1; - } - } + newcook = aim_checkcookie(sess, cookie->cookie, cookie->type); + + if (newcook == cookie) { + newcook->addtime = time(NULL); + return 1; + } else if (newcook) + aim_cookie_free(sess, newcook); - cookie->addtime = time(NULL); + cookie->addtime = time(NULL); - cookie->next = sess->msgcookies; - sess->msgcookies = cookie; + cookie->next = sess->msgcookies; + sess->msgcookies = cookie; - return 0; + return 0; } /** @@ -62,23 +60,23 @@ faim_internal int aim_cachecookie(struct aim_session_t *sess, * * if found, returns the struct; if none found (or on error), returns NULL: */ -faim_internal struct aim_msgcookie_t *aim_uncachecookie(struct aim_session_t *sess, unsigned char *cookie, int type) +faim_internal aim_msgcookie_t *aim_uncachecookie(aim_session_t *sess, fu8_t *cookie, int type) { - struct aim_msgcookie_t *cur, **prev; + aim_msgcookie_t *cur, **prev; - if (!cookie || !sess->msgcookies) - return NULL; + if (!cookie || !sess->msgcookies) + return NULL; - for (prev = &sess->msgcookies; (cur = *prev); ) { - if ((cur->type == type) && - (memcmp(cur->cookie, cookie, 8) == 0)) { - *prev = cur->next; - return cur; - } - prev = &cur->next; - } + for (prev = &sess->msgcookies; (cur = *prev); ) { + if ((cur->type == type) && + (memcmp(cur->cookie, cookie, 8) == 0)) { + *prev = cur->next; + return cur; + } + prev = &cur->next; + } - return NULL; + return NULL; } /** @@ -91,21 +89,21 @@ faim_internal struct aim_msgcookie_t *aim_uncachecookie(struct aim_session_t *se * success. * */ -faim_internal struct aim_msgcookie_t *aim_mkcookie(unsigned char *c, int type, void *data) +faim_internal aim_msgcookie_t *aim_mkcookie(fu8_t *c, int type, void *data) { - struct aim_msgcookie_t *cookie; - - if (!c) - return NULL; - - if (!(cookie = calloc(1, sizeof(struct aim_msgcookie_t)))) - return NULL; - - cookie->data = data; - cookie->type = type; - memcpy(cookie->cookie, c, 8); - - return cookie; + aim_msgcookie_t *cookie; + + if (!c) + return NULL; + + if (!(cookie = calloc(1, sizeof(aim_msgcookie_t)))) + return NULL; + + cookie->data = data; + cookie->type = type; + memcpy(cookie->cookie, c, 8); + + return cookie; } /** @@ -119,28 +117,31 @@ faim_internal struct aim_msgcookie_t *aim_mkcookie(unsigned char *c, int type, v * */ -faim_internal struct aim_msgcookie_t *aim_checkcookie(struct aim_session_t *sess, - const unsigned char *cookie, - const int type) +faim_internal aim_msgcookie_t *aim_checkcookie(aim_session_t *sess, const fu8_t *cookie, int type) { - struct aim_msgcookie_t *cur; + aim_msgcookie_t *cur; - for (cur = sess->msgcookies; cur; cur = cur->next) { - if ((cur->type == type) && - (memcmp(cur->cookie, cookie, 8) == 0)) - return cur; - } + for (cur = sess->msgcookies; cur; cur = cur->next) { + if ((cur->type == type) && + (memcmp(cur->cookie, cookie, 8) == 0)) + return cur; + } - return NULL; + return NULL; } #if 0 /* debugging feature */ -faim_internal int aim_dumpcookie(struct aim_msgcookie_t *cookie) +faim_internal int aim_dumpcookie(aim_msgcookie_t *cookie) { - if(!cookie) - return -1; - printf("\tCookie at %p: %d/%s with %p, next %p\n", cookie, cookie->type, cookie->cookie, cookie->data, cookie->next); - return 0; + + if (!cookie) + return -EINVAL; + + printf("\tCookie at %p: %d/%s with %p, next %p\n", + cookie, cookie->type, cookie->cookie, + cookie->data, cookie->next); + + return 0; } #endif @@ -157,56 +158,39 @@ faim_internal int aim_dumpcookie(struct aim_msgcookie_t *cookie) * returns -1 on error, 0 on success. * */ - -faim_internal int aim_cookie_free(struct aim_session_t *sess, - struct aim_msgcookie_t *cookie) +faim_internal int aim_cookie_free(aim_session_t *sess, aim_msgcookie_t *cookie) { - struct aim_msgcookie_t *cur, **prev; - - if (!sess || !cookie) - return -1; - - if(!cookie) - return 0; + aim_msgcookie_t *cur, **prev; - for (prev = &sess->msgcookies; (cur = *prev); ) { - if (cur == cookie) { - *prev = cur->next; - } else - prev = &cur->next; - } + if (!sess || !cookie) + return -EINVAL; - if(cookie->data) - free(cookie->data); + for (prev = &sess->msgcookies; (cur = *prev); ) { + if (cur == cookie) + *prev = cur->next; + else + prev = &cur->next; + } - free(cookie); + free(cookie->data); + free(cookie); - return 0; + return 0; } -faim_internal int aim_msgcookie_gettype(int reqclass) { - /* XXX: hokey-assed. needs fixed. */ - switch(reqclass) { - case AIM_CAPS_BUDDYICON: - return AIM_COOKIETYPE_OFTICON; - break; - case AIM_CAPS_VOICE: - return AIM_COOKIETYPE_OFTVOICE; - break; - case AIM_CAPS_IMIMAGE: - return AIM_COOKIETYPE_OFTIMAGE; - break; - case AIM_CAPS_CHAT: - return AIM_COOKIETYPE_CHAT; - break; - case AIM_CAPS_GETFILE: - return AIM_COOKIETYPE_OFTGET; - break; - case AIM_CAPS_SENDFILE: - return AIM_COOKIETYPE_OFTSEND; - break; - default: - return AIM_COOKIETYPE_UNKNOWN; - break; - } +/* XXX I hate switch */ +faim_internal int aim_msgcookie_gettype(int reqclass) +{ + /* XXX: hokey-assed. needs fixed. */ + switch(reqclass) { + case AIM_CAPS_BUDDYICON: return AIM_COOKIETYPE_OFTICON; + case AIM_CAPS_VOICE: return AIM_COOKIETYPE_OFTVOICE; + case AIM_CAPS_IMIMAGE: return AIM_COOKIETYPE_OFTIMAGE; + case AIM_CAPS_CHAT: return AIM_COOKIETYPE_CHAT; + case AIM_CAPS_GETFILE: return AIM_COOKIETYPE_OFTGET; + case AIM_CAPS_SENDFILE: return AIM_COOKIETYPE_OFTSEND; + default: return AIM_COOKIETYPE_UNKNOWN; + } } + + diff --git a/src/rxhandlers.c b/src/rxhandlers.c index 19baded..33b51f0 100644 --- a/src/rxhandlers.c +++ b/src/rxhandlers.c @@ -10,561 +10,564 @@ #define FAIM_INTERNAL #include -static aim_module_t *findmodule(struct aim_session_t *sess, const char *name) +struct aim_rxcblist_s { + fu16_t family; + fu16_t type; + aim_rxcallback_t handler; + u_short flags; + struct aim_rxcblist_s *next; +}; + +static aim_module_t *findmodule(aim_session_t *sess, const char *name) { - aim_module_t *cur; + aim_module_t *cur; - for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { - if (strcmp(name, cur->name) == 0) - return cur; - } + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + if (strcmp(name, cur->name) == 0) + return cur; + } - return NULL; + return NULL; } -faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst)(struct aim_session_t *, aim_module_t *)) +faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *)) { - aim_module_t *mod; + aim_module_t *mod; - if (!sess || !modfirst) - return -1; + if (!sess || !modfirst) + return -1; - if (!(mod = malloc(sizeof(aim_module_t)))) - return -1; - memset(mod, 0, sizeof(aim_module_t)); + if (!(mod = malloc(sizeof(aim_module_t)))) + return -1; + memset(mod, 0, sizeof(aim_module_t)); - if (modfirst(sess, mod) == -1) { - free(mod); - return -1; - } + if (modfirst(sess, mod) == -1) { + free(mod); + return -1; + } - if (findmodule(sess, mod->name)) { - if (mod->shutdown) - mod->shutdown(sess, mod); - free(mod); - return -1; - } + if (findmodule(sess, mod->name)) { + if (mod->shutdown) + mod->shutdown(sess, mod); + free(mod); + return -1; + } - mod->next = (aim_module_t *)sess->modlistv; - (aim_module_t *)sess->modlistv = mod; + mod->next = (aim_module_t *)sess->modlistv; + (aim_module_t *)sess->modlistv = mod; - faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family); + faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family); - return 0; + return 0; } -faim_internal void aim__shutdownmodules(struct aim_session_t *sess) +faim_internal void aim__shutdownmodules(aim_session_t *sess) { - aim_module_t *cur; + aim_module_t *cur; - for (cur = (aim_module_t *)sess->modlistv; cur; ) { - aim_module_t *tmp; + for (cur = (aim_module_t *)sess->modlistv; cur; ) { + aim_module_t *tmp; - tmp = cur->next; + tmp = cur->next; - if (cur->shutdown) - cur->shutdown(sess, cur); + if (cur->shutdown) + cur->shutdown(sess, cur); - free(cur); + free(cur); - cur = tmp; - } + cur = tmp; + } - sess->modlistv = NULL; + sess->modlistv = NULL; - return; + return; } -static int consumesnac(struct aim_session_t *sess, struct command_rx_struct *rx) +static int consumesnac(aim_session_t *sess, aim_frame_t *rx) { - aim_module_t *cur; - aim_modsnac_t snac; + aim_module_t *cur; + aim_modsnac_t snac; - snac.family = aimutil_get16(rx->data+0); - snac.subtype = aimutil_get16(rx->data+2); - snac.flags = aimutil_get16(rx->data+4); - snac.id = aimutil_get32(rx->data+6); + if (aim_bstream_empty(&rx->data) < 10) + return 0; - for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + snac.family = aimbs_get16(&rx->data); + snac.subtype = aimbs_get16(&rx->data); + snac.flags = aimbs_get16(&rx->data); + snac.id = aimbs_get32(&rx->data); - if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && - (cur->family != snac.family)) - continue; + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { - if (cur->snachandler(sess, cur, rx, &snac, rx->data+10, rx->commandlen-10)) - return 1; + if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && + (cur->family != snac.family)) + continue; - } + if (cur->snachandler(sess, cur, rx, &snac, &rx->data)) + return 1; - return 0; + } + + return 0; } -static int consumenonsnac(struct aim_session_t *sess, struct command_rx_struct *rx, unsigned short family, unsigned short subtype) +static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, fu16_t family, fu16_t subtype) { - aim_module_t *cur; - aim_modsnac_t snac; + aim_module_t *cur; + aim_modsnac_t snac; - snac.family = family; - snac.subtype = subtype; - snac.flags = snac.id = 0; + snac.family = family; + snac.subtype = subtype; + snac.flags = snac.id = 0; - for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { - if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && - (cur->family != snac.family)) - continue; + if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && + (cur->family != snac.family)) + continue; - if (cur->snachandler(sess, cur, rx, &snac, rx->data, rx->commandlen)) - return 1; + if (cur->snachandler(sess, cur, rx, &snac, &rx->data)) + return 1; - } + } - return 0; + return 0; +} + +static int negchan_middle(aim_session_t *sess, aim_frame_t *fr) +{ + aim_tlvlist_t *tlvlist; + char *msg = NULL; + fu16_t code = 0; + aim_rxcallback_t userfunc; + int ret = 1; + + if (aim_bstream_empty(&fr->data) == 0) { + /* XXX should do something with this */ + return 1; + } + + /* Used only by the older login protocol */ + /* XXX remove this special case? */ + if (fr->conn->type == AIM_CONN_TYPE_AUTH) + return consumenonsnac(sess, fr, 0x0017, 0x0003); + + tlvlist = aim_readtlvchain(&fr->data); + + if (aim_gettlv(tlvlist, 0x0009, 1)) + code = aim_gettlv16(tlvlist, 0x0009, 1); + + if (aim_gettlv(tlvlist, 0x000b, 1)) + msg = aim_gettlv_str(tlvlist, 0x000b, 1); + + if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) + ret = userfunc(sess, fr, code, msg); + + aim_freetlvchain(&tlvlist); + + free(msg); + + return ret; } /* * Bleck functions get called when there's no non-bleck functions * around to cleanup the mess... */ -faim_internal int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...) +faim_internal int bleck(aim_session_t *sess, aim_frame_t *frame, ...) { - u_short family; - u_short subtype; - - u_short maxf; - u_short maxs; - - /* 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", - } - }; - - 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)) - faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]); - else - faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (no literal)\n",family,subtype); - - return 1; + fu16_t family, subtype; + fu16_t maxf, maxs; + + static const char *channels[6] = { + "Invalid (0)", + "FLAP Version", + "SNAC", + "Invalid (3)", + "Negotiation", + "FLAP NOP" + }; + static const int maxchannels = 5; + + /* XXX: this is ugly. and big just for debugging. */ + static const char *literals[14][25] = { + {"Invalid", + NULL + }, + {"General", + "Invalid", + "Error", + "Client Ready", + "Server Ready", + "Service Request", + "Redirect", + "Rate Information Request", + "Rate Information", + "Rate Information Ack", + NULL, + "Rate Information Change", + "Server Pause", + NULL, + "Server Resume", + "Request Personal User Information", + "Personal User Information", + "Evil Notification", + NULL, + "Migration notice", + "Message of the Day", + "Set Privacy Flags", + "Well Known URL", + "NOP" + }, + {"Location", + "Invalid", + "Error", + "Request Rights", + "Rights Information", + "Set user information", + "Request User Information", + "User Information", + "Watcher Sub Request", + "Watcher Notification" + }, + {"Buddy List Management", + "Invalid", + "Error", + "Request Rights", + "Rights Information", + "Add Buddy", + "Remove Buddy", + "Watcher List Query", + "Watcher List Response", + "Watcher SubRequest", + "Watcher Notification", + "Reject Notification", + "Oncoming Buddy", + "Offgoing Buddy" + }, + {"Messeging", + "Invalid", + "Error", + "Add ICBM Parameter", + "Remove ICBM Parameter", + "Request Parameter Information", + "Parameter Information", + "Outgoing Message", + "Incoming Message", + "Evil Request", + "Evil Reply", + "Missed Calls", + "Message Error", + "Host Ack" + }, + {"Advertisements", + "Invalid", + "Error", + "Request Ad", + "Ad Data (GIFs)" + }, + {"Invitation / Client-to-Client", + "Invalid", + "Error", + "Invite a Friend", + "Invitation Ack" + }, + {"Administrative", + "Invalid", + "Error", + "Information Request", + "Information Reply", + "Information Change Request", + "Information Chat Reply", + "Account Confirm Request", + "Account Confirm Reply", + "Account Delete Request", + "Account Delete Reply" + }, + {"Popups", + "Invalid", + "Error", + "Display Popup" + }, + {"BOS", + "Invalid", + "Error", + "Request Rights", + "Rights Response", + "Set group permission mask", + "Add permission list entries", + "Delete permission list entries", + "Add deny list entries", + "Delete deny list entries", + "Server Error" + }, + {"User Lookup", + "Invalid", + "Error", + "Search Request", + "Search Response" + }, + {"Stats", + "Invalid", + "Error", + "Set minimum report interval", + "Report Events" + }, + {"Translate", + "Invalid", + "Error", + "Translate Request", + "Translate Reply", + }, + {"Chat Navigation", + "Invalid", + "Error", + "Request rights", + "Request Exchange Information", + "Request Room Information", + "Request Occupant List", + "Search for Room", + "Outgoing Message", + "Incoming Message", + "Evil Request", + "Evil Reply", + "Chat Error", + } + }; + + maxf = sizeof(literals) / sizeof(literals[0]); + maxs = sizeof(literals[0]) / sizeof(literals[0][0]); + + if (frame->hdr.flap.type == 0x02) { + + family = aimbs_get16(&frame->data); + subtype = aimbs_get16(&frame->data); + + if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL)) + faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->hdr.flap.type], family, subtype, literals[family][subtype+1]); + else + faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->hdr.flap.type], family, subtype); + } else { + + if (frame->hdr.flap.type <= maxchannels) + faimdprintf(sess, 0, "bleck: channel %s (0x%02x)\n", channels[frame->hdr.flap.type], frame->hdr.flap.type); + else + faimdprintf(sess, 0, "bleck: unknown channel 0x%02x\n", frame->hdr.flap.type); + + } + + return 1; } -faim_export int aim_conn_addhandler(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short family, - u_short type, - aim_rxcallback_t newhandler, - u_short flags) +faim_export int aim_conn_addhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_rxcallback_t newhandler, fu16_t flags) { - struct aim_rxcblist_t *newcb; - - if (!conn) - return -1; - - faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type); - - if (!(newcb = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t)))) - return -1; - newcb->family = family; - newcb->type = type; - newcb->flags = flags; - if (!newhandler) - newcb->handler = &bleck; - else - newcb->handler = newhandler; - newcb->next = NULL; - - if (!conn->handlerlist) - conn->handlerlist = newcb; - else { - struct aim_rxcblist_t *cur; - - cur = conn->handlerlist; - - while (cur->next) - cur = cur->next; - cur->next = newcb; - } - - return 0; + struct aim_rxcblist_s *newcb; + + if (!conn) + return -1; + + faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type); + + if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s)))) + return -1; + + newcb->family = family; + newcb->type = type; + newcb->flags = flags; + newcb->handler = newhandler ? newhandler : bleck; + newcb->next = NULL; + + if (!conn->handlerlist) + conn->handlerlist = (void *)newcb; + else { + struct aim_rxcblist_s *cur; + + for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next) + ; + cur->next = newcb; + } + + return 0; } -faim_export int aim_clearhandlers(struct aim_conn_t *conn) +faim_export int aim_clearhandlers(aim_conn_t *conn) { - struct aim_rxcblist_t *cur; + struct aim_rxcblist_s *cur; - if (!conn) - return -1; + if (!conn) + return -1; - for (cur = conn->handlerlist; cur; ) { - struct aim_rxcblist_t *tmp; + for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) { + struct aim_rxcblist_s *tmp; - tmp = cur->next; - free(cur); - cur = tmp; - } - conn->handlerlist = NULL; + tmp = cur->next; + free(cur); + cur = tmp; + } + conn->handlerlist = NULL; - return 0; + return 0; } -faim_internal aim_rxcallback_t aim_callhandler(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned short family, - unsigned short type) +faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type) { - struct aim_rxcblist_t *cur; + struct aim_rxcblist_s *cur; + + if (!conn) + return NULL; - if (!conn) - return NULL; + faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type); - faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type); - - for (cur = conn->handlerlist; cur; cur = cur->next) { - if ((cur->family == family) && (cur->type == type)) - return cur->handler; - } + for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) { + if ((cur->family == family) && (cur->type == type)) + return cur->handler; + } - if (type == AIM_CB_SPECIAL_DEFAULT) { - faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family); - return NULL; /* prevent infinite recursion */ - } + if (type == AIM_CB_SPECIAL_DEFAULT) { + faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family); + return NULL; /* prevent infinite recursion */ + } - faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type); + faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type); - return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT); + return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT); } -faim_internal int aim_callhandler_noparam(struct aim_session_t *sess, - struct aim_conn_t *conn, - u_short family, - u_short type, - struct command_rx_struct *ptr) +faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src) { - aim_rxcallback_t userfunc = NULL; - userfunc = aim_callhandler(sess, conn, family, type); - if (userfunc) - return userfunc(sess, ptr); - return 1; /* XXX */ -} + struct aim_rxcblist_s *cur; -/* - aim_rxdispatch() - - Basically, heres what this should do: - 1) Determine correct packet handler for this packet - 2) Mark the packet handled (so it can be dequeued in purge_queue()) - 3) Send the packet to the packet handler - 4) Go to next packet in the queue and start over - 5) When done, run purge_queue() to purge handled commands - - Note that any unhandlable packets should probably be left in the - queue. This is the best way to prevent data loss. This means - that a single packet may get looked at by this function multiple - times. This is more good than bad! This behavior may change. - - Aren't queue's fun? - - TODO: Get rid of all the ugly if's. - TODO: Clean up. - TODO: More support for mid-level handlers. - TODO: Allow for NULL handlers. - - */ -faim_export int aim_rxdispatch(struct aim_session_t *sess) -{ - int i = 0; - struct command_rx_struct *workingPtr = NULL; - static int critical = 0; - - if (critical) - return 0; /* don't call recursively! */ - - critical = 1; - - if (sess->queue_incoming == NULL) { - faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n"); - } else { - workingPtr = sess->queue_incoming; - for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) { - unsigned short family,subtype; - - /* - * XXX: This is still fairly ugly. - */ - if (workingPtr->handled) - continue; - - /* - * This is a debugging/sanity check only and probably could/should be removed - * for stable code. - */ - if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) && - (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || - ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) && - (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) { - faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type); - workingPtr->handled = 1; - continue; - } - - if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS) { - /* make sure that we only get OFT frames on these connections */ - if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) { - faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n"); - workingPtr->handled = 1; /* get rid of it */ - } else { - /* XXX: implement this */ - faimdprintf(sess, 0, "faim: OFT frame!\n"); - workingPtr->handled = 1; /* get rid of it */ + for (cur = (struct aim_rxcblist_s *)src->handlerlist; cur; cur = cur->next) { + aim_conn_addhandler(sess, dest, cur->family, cur->type, + cur->handler, cur->flags); } - continue; - } - - if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { - /* not possible */ - faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n"); - workingPtr->handled = 1; - continue; - } - - if ((workingPtr->commandlen == 4) && - (aimutil_get32(workingPtr->data) == 0x00000001)) { - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr); - continue; - } - - if (workingPtr->hdr.oscar.type == 0x04) { - workingPtr->handled = aim_negchan_middle(sess, workingPtr); - continue; - } - - if ((workingPtr->handled = consumesnac(sess, workingPtr))) - continue; - - if (!workingPtr->handled) { - family = aimutil_get16(workingPtr->data); - subtype = aimutil_get16(workingPtr->data+2); - - faimdprintf(sess, 1, "warning: unhandled packet %04x/%04x\n", family, subtype); - consumenonsnac(sess, workingPtr, 0xffff, 0xffff); /* last chance! */ - workingPtr->handled = 1; - } - } - } - - /* - * This doesn't have to be called here. It could easily be done - * by a seperate thread or something. It's an administrative operation, - * and can take a while. Though the less you call it the less memory - * you'll have :) - */ - aim_purge_rxqueue(sess); - - critical = 0; - - return 0; + + return; } -faim_internal int aim_parse_unknown(struct aim_session_t *sess, - struct command_rx_struct *command, ...) +faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn,fu16_t family, fu16_t type, aim_frame_t *ptr) { - u_int i = 0; + aim_rxcallback_t userfunc; - if (!sess || !command) - return 1; + if ((userfunc = aim_callhandler(sess, conn, family, type))) + return userfunc(sess, ptr); - faimdprintf(sess, 1, "\nRecieved unknown packet:"); + return 1; /* XXX */ +} - for (i = 0; i < command->commandlen; i++) - { - if ((i % 8) == 0) - faimdprintf(sess, 1, "\n\t"); +/* + * aim_rxdispatch() + * + * Basically, heres what this should do: + * 1) Determine correct packet handler for this packet + * 2) Mark the packet handled (so it can be dequeued in purge_queue()) + * 3) Send the packet to the packet handler + * 4) Go to next packet in the queue and start over + * 5) When done, run purge_queue() to purge handled commands + * + * TODO: Clean up. + * TODO: More support for mid-level handlers. + * TODO: Allow for NULL handlers. + * + */ +faim_export void aim_rxdispatch(aim_session_t *sess) +{ + int i; + aim_frame_t *cur; + + for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) { + + /* + * XXX: This is still fairly ugly. + */ + + if (cur->handled) + continue; + + /* + * This is a debugging/sanity check only and probably + * could/should be removed for stable code. + */ + if (((cur->hdrtype == AIM_FRAMETYPE_OFT) && + (cur->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || + ((cur->hdrtype == AIM_FRAMETYPE_FLAP) && + (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) { + faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", cur->hdrtype, cur->conn->type); + cur->handled = 1; + continue; + } + + if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) { + if (cur->hdrtype != AIM_FRAMETYPE_OFT) { + faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n"); + cur->handled = 1; /* get rid of it */ + } else { + /* XXX: implement this */ + faimdprintf(sess, 0, "faim: OFT frame!\n"); + cur->handled = 1; /* get rid of it */ + } + continue; + } + + if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { + /* not possible */ + faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n"); + cur->handled = 1; + continue; + } + + if (cur->hdr.flap.type == 0x01) { + + cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */ + + continue; + + } else if (cur->hdr.flap.type == 0x02) { + + if ((cur->handled = consumesnac(sess, cur))) + continue; + + } else if (cur->hdr.flap.type == 0x04) { + + cur->handled = negchan_middle(sess, cur); + continue; + + } else if (cur->hdr.flap.type == 0x05) + ; + + if (!cur->handled) { + consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */ + cur->handled = 1; + } + } - faimdprintf(sess, 1, "0x%2x ", command->data[i]); - } - - faimdprintf(sess, 1, "\n\n"); + /* + * 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 1; + return; } - -faim_internal int aim_negchan_middle(struct aim_session_t *sess, - struct command_rx_struct *command) +faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...) { - struct aim_tlvlist_t *tlvlist; - char *msg = NULL; - unsigned short code = 0; - aim_rxcallback_t userfunc = NULL; - int ret = 1; - - /* Used only by the older login protocol */ - /* XXX remove this special case? */ - if (command->conn->type == AIM_CONN_TYPE_AUTH) - return consumenonsnac(sess, command, 0x0017, 0x0003); + int i; - tlvlist = aim_readtlvchain(command->data, command->commandlen); + faimdprintf(sess, 1, "\nRecieved unknown packet:"); - if (aim_gettlv(tlvlist, 0x0009, 1)) - code = aim_gettlv16(tlvlist, 0x0009, 1); + for (i = 0; aim_bstream_empty(&frame->data); i++) { + if ((i % 8) == 0) + faimdprintf(sess, 1, "\n\t"); - if (aim_gettlv(tlvlist, 0x000b, 1)) - msg = aim_gettlv_str(tlvlist, 0x000b, 1); + faimdprintf(sess, 1, "0x%2x ", aimbs_get8(&frame->data)); + } - if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) - ret = userfunc(sess, command, code, msg); + faimdprintf(sess, 1, "\n\n"); - aim_freetlvchain(&tlvlist); + return 1; +} - if (msg) - free(msg); - return ret; -} diff --git a/src/rxqueue.c b/src/rxqueue.c index d177c82..be2a85e 100644 --- a/src/rxqueue.c +++ b/src/rxqueue.c @@ -14,161 +14,389 @@ #endif /* - * Since not all implementations support MSG_WAITALL, define - * an alternate guarenteed read function... - * - * We keep recv() for systems that can do it because it means - * a single system call for the entire packet, where read may - * take more for a badly fragmented packet. * */ faim_internal int aim_recv(int fd, void *buf, size_t count) { -#ifdef MSG_WAITALL - return recv(fd, buf, count, MSG_WAITALL); -#else - int left, ret, cur = 0; - - left = count; - - while (left) { - ret = recv(fd, ((unsigned char *)buf)+cur, left, 0); - if (ret == -1) - return -1; - if (ret == 0) - return cur; - - cur += ret; - left -= ret; - } - - return cur; -#endif + int left, cur; + + for (cur = 0, left = count; left; ) { + int ret; + + ret = recv(fd, ((unsigned char *)buf)+cur, left, 0); + if (ret == -1) + return -1; + else if (ret == 0) + return cur; + + cur += ret; + left -= ret; + } + + return cur; +} + +/* + * Read into a byte stream. Will not read more than count, but may read + * less if there is not enough room in the stream buffer. + */ +faim_internal int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count) +{ + int red = 0; + + if (!bs || (fd < 0) || (count < 0)) + return -1; + + if (count > (bs->len - bs->offset)) + count = bs->len - bs->offset; /* truncate to remaining space */ + + if (count) { + + red = aim_recv(fd, bs->data + bs->offset, count); + + if (red <= 0) + return -1; + } + + bs->offset += red; + + return red; +} + +faim_internal int aim_bstream_init(aim_bstream_t *bs, fu8_t *data, int len) +{ + + if (!bs) + return -1; + + bs->data = data; + bs->len = len; + bs->offset = 0; + + return 0; +} + +faim_internal int aim_bstream_empty(aim_bstream_t *bs) +{ + return bs->len - bs->offset; +} + +faim_internal int aim_bstream_curpos(aim_bstream_t *bs) +{ + return bs->offset; +} + +faim_internal int aim_bstream_setpos(aim_bstream_t *bs, int off) +{ + + if (off > bs->len) + return -1; + + bs->offset = off; + + return off; +} + +faim_internal void aim_bstream_rewind(aim_bstream_t *bs) +{ + + aim_bstream_setpos(bs, 0); + + return; +} + +faim_internal int aim_bstream_advance(aim_bstream_t *bs, int n) +{ + + if (aim_bstream_empty(bs) < n) + return 0; /* XXX throw an exception */ + + bs->offset += n; + + return n; +} + +faim_internal fu8_t aimbs_get8(aim_bstream_t *bs) +{ + + if (aim_bstream_empty(bs) < 1) + return 0; /* XXX throw an exception */ + + bs->offset++; + + return aimutil_get8(bs->data + bs->offset - 1); +} + +faim_internal fu16_t aimbs_get16(aim_bstream_t *bs) +{ + + if (aim_bstream_empty(bs) < 2) + return 0; /* XXX throw an exception */ + + bs->offset += 2; + + return aimutil_get16(bs->data + bs->offset - 2); +} + +faim_internal fu32_t aimbs_get32(aim_bstream_t *bs) +{ + + if (aim_bstream_empty(bs) < 4) + return 0; /* XXX throw an exception */ + + bs->offset += 4; + + return aimutil_get32(bs->data + bs->offset - 4); +} + +faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v) +{ + + if (aim_bstream_empty(bs) < 1) + return 0; /* XXX throw an exception */ + + bs->offset += aimutil_put8(bs->data + bs->offset, v); + + return 1; +} + +faim_internal int aimbs_put16(aim_bstream_t *bs, fu16_t v) +{ + + if (aim_bstream_empty(bs) < 2) + return 0; /* XXX throw an exception */ + + bs->offset += aimutil_put16(bs->data + bs->offset, v); + + return 2; +} + +faim_internal int aimbs_put32(aim_bstream_t *bs, fu32_t v) +{ + + if (aim_bstream_empty(bs) < 4) + return 0; /* XXX throw an exception */ + + bs->offset += aimutil_put32(bs->data + bs->offset, v); + + return 1; +} + +faim_internal int aimbs_getrawbuf(aim_bstream_t *bs, fu8_t *buf, int len) +{ + + if (aim_bstream_empty(bs) < len) + return 0; + + memcpy(buf, bs->data + bs->offset, len); + bs->offset += len; + + return len; +} + +faim_internal fu8_t *aimbs_getraw(aim_bstream_t *bs, int len) +{ + fu8_t *ob; + + if (!(ob = malloc(len))) + return NULL; + + if (aimbs_getrawbuf(bs, ob, len) < len) { + free(ob); + return NULL; + } + + return ob; +} + +faim_internal char *aimbs_getstr(aim_bstream_t *bs, int len) +{ + char *ob; + + if (!(ob = malloc(len+1))) + return NULL; + + if (aimbs_getrawbuf(bs, ob, len) < len) { + free(ob); + return NULL; + } + + ob[len] = '\0'; + + return ob; } +faim_internal int aimbs_putraw(aim_bstream_t *bs, const fu8_t *v, int len) +{ + + if (aim_bstream_empty(bs) < len) + return 0; /* XXX throw an exception */ + + memcpy(bs->data + bs->offset, v, len); + bs->offset += len; + + return len; +} + +faim_internal int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len) +{ + + if (aim_bstream_empty(srcbs) < len) + return 0; /* XXX throw exception (underrun) */ + + if (aim_bstream_empty(bs) < len) + return 0; /* XXX throw exception (overflow) */ + + memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len); + bs->offset += len; + srcbs->offset += len; + + return len; +} + +/** + * aim_frame_destroy - free aim_frame_t + * @frame: the frame to free + * + * returns -1 on error; 0 on success. + * + */ +faim_internal void aim_frame_destroy(aim_frame_t *frame) +{ + + free(frame->data.data); /* XXX aim_bstream_free */ + + if (frame->hdrtype == AIM_FRAMETYPE_OFT) + free(frame->hdr.oft.hdr2); + free(frame); + + return; +} + + /* * Grab a single command sequence off the socket, and enqueue * it in the incoming event queue in a seperate struct. */ -faim_export int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn) -{ - unsigned char generic[6]; - struct command_rx_struct *newrx = NULL; - - if (!sess || !conn) - return 0; - - if (conn->fd == -1) - return -1; /* its a aim_conn_close()'d connection */ - - if (conn->fd < 3) /* can happen when people abuse the interface */ - return 0; - - if (conn->status & AIM_CONN_STATUS_INPROGRESS) - return aim_conn_completeconnect(sess, conn); - - /* - * Rendezvous (client-client) connections do not speak - * FLAP, so this function will break on them. - */ - if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) - return aim_get_command_rendezvous(sess, conn); - if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { - faimdprintf(sess, 0, "out on fd %d\n", conn->fd); - return 0; - } - - /* - * Read FLAP header. Six bytes: - * - * 0 char -- Always 0x2a - * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. - * 2 short -- Sequence number - * 4 short -- Number of data bytes that follow. - */ - faim_mutex_lock(&conn->active); - if (aim_recv(conn->fd, generic, 6) < 6){ - aim_conn_close(conn); - faim_mutex_unlock(&conn->active); - return -1; - } - - /* - * This shouldn't happen unless the socket breaks, the server breaks, - * or we break. We must handle it just in case. - */ - if (generic[0] != 0x2a) { - faimdprintf(sess, 1, "Bad incoming data!"); - aim_conn_close(conn); - faim_mutex_unlock(&conn->active); - return -1; - } - - /* allocate a new struct */ - if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) { - faim_mutex_unlock(&conn->active); - return -1; - } - memset(newrx, 0x00, sizeof(struct command_rx_struct)); - - newrx->lock = 1; /* lock the struct */ - - /* we're doing OSCAR if we're here */ - newrx->hdrtype = AIM_FRAMETYPE_OSCAR; - - /* store channel -- byte 2 */ - newrx->hdr.oscar.type = (char) generic[1]; - - /* store seqnum -- bytes 3 and 4 */ - newrx->hdr.oscar.seqnum = aimutil_get16(generic+2); - - /* store commandlen -- bytes 5 and 6 */ - newrx->commandlen = aimutil_get16(generic+4); - - newrx->nofree = 0; /* free by default */ - - /* malloc for data portion */ - if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) { - free(newrx); - faim_mutex_unlock(&conn->active); - return -1; - } - - /* read the data portion of the packet */ - if (aim_recv(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){ - free(newrx->data); - free(newrx); - aim_conn_close(conn); - faim_mutex_unlock(&conn->active); - return -1; - } - faim_mutex_unlock(&conn->active); - - newrx->conn = conn; - - newrx->next = NULL; /* this will always be at the bottom */ - newrx->lock = 0; /* unlock */ - - /* enqueue this packet */ - 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; +faim_export int aim_get_command(aim_session_t *sess, aim_conn_t *conn) +{ + fu8_t flaphdr_raw[6]; + aim_bstream_t flaphdr; + aim_frame_t *newrx; + fu16_t payloadlen; + + if (!sess || !conn) + return 0; + + if (conn->fd == -1) + return -1; /* its a aim_conn_close()'d connection */ + + if (conn->fd < 3) /* can happen when people abuse the interface */ + return 0; + + if (conn->status & AIM_CONN_STATUS_INPROGRESS) + return aim_conn_completeconnect(sess, conn); + + /* + * Rendezvous (client-client) connections do not speak + * FLAP, so this function will break on them. + */ + if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) + return aim_get_command_rendezvous(sess, conn); + else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { + faimdprintf(sess, 0, "AIM_CONN_TYPE_RENDEZVOUS_OUT on fd %d\n", conn->fd); + return 0; + } + + aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw)); + + /* + * Read FLAP header. Six bytes: + * + * 0 char -- Always 0x2a + * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. + * 2 short -- Sequence number + * 4 short -- Number of data bytes that follow. + */ + faim_mutex_lock(&conn->active); + if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) { + aim_conn_close(conn); + faim_mutex_unlock(&conn->active); + return -1; + } + + aim_bstream_rewind(&flaphdr); + + /* + * This shouldn't happen unless the socket breaks, the server breaks, + * or we break. We must handle it just in case. + */ + if (aimbs_get8(&flaphdr) != 0x2a) { + faimdprintf(sess, 0, "FLAP framing disrupted"); + aim_conn_close(conn); + faim_mutex_unlock(&conn->active); + return -1; + } + + /* allocate a new struct */ + if (!(newrx = (aim_frame_t *)malloc(sizeof(aim_frame_t)))) { + faim_mutex_unlock(&conn->active); + return -1; + } + memset(newrx, 0, sizeof(aim_frame_t)); + + /* we're doing FLAP if we're here */ + newrx->hdrtype = AIM_FRAMETYPE_FLAP; + + newrx->hdr.flap.type = aimbs_get8(&flaphdr); + newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr); + payloadlen = aimbs_get16(&flaphdr); + + newrx->nofree = 0; /* free by default */ + + if (payloadlen) { + fu8_t *payload = NULL; + + if (!(payload = (fu8_t *) malloc(payloadlen))) { + aim_frame_destroy(newrx); + faim_mutex_unlock(&conn->active); + return -1; + } + + aim_bstream_init(&newrx->data, payload, payloadlen); + + /* read the payload */ + if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) { + free(payload); + aim_frame_destroy(newrx); + aim_conn_close(conn); + faim_mutex_unlock(&conn->active); + return -1; + } + } else + aim_bstream_init(&newrx->data, NULL, 0); + + faim_mutex_unlock(&conn->active); + + aim_bstream_rewind(&newrx->data); + + newrx->conn = conn; + + newrx->next = NULL; /* this will always be at the bottom */ + + if (!sess->queue_incoming) + sess->queue_incoming = newrx; + else { + aim_frame_t *cur; + + for (cur = sess->queue_incoming; cur->next; cur = cur->next) + ; + cur->next = newrx; + } + + newrx->conn->lastactivity = time(NULL); + + return 0; } /* @@ -182,55 +410,23 @@ faim_export int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *c * does not keep a pointer, it's lost forever. * */ -faim_export void aim_purge_rxqueue(struct aim_session_t *sess) -{ - struct command_rx_struct *cur = NULL; - struct command_rx_struct *tmp; - - if (sess->queue_incoming == NULL) - return; - - if (sess->queue_incoming->next == NULL) { - if (sess->queue_incoming->handled) { - tmp = sess->queue_incoming; - sess->queue_incoming = NULL; - - if (!tmp->nofree) { - if (tmp->hdrtype == AIM_FRAMETYPE_OFT) - free(tmp->hdr.oft.hdr2); - free(tmp->data); - free(tmp); - } else - tmp->next = NULL; - } - return; - } - - for(cur = sess->queue_incoming; cur->next != NULL; ) { - if (cur->next->handled) { - tmp = cur->next; - cur->next = tmp->next; - if (!tmp->nofree) { - if (tmp->hdrtype == AIM_FRAMETYPE_OFT) - free(tmp->hdr.oft.hdr2); - free(tmp->data); - free(tmp); - } else - tmp->next = NULL; - } - cur = cur->next; - - /* - * 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; +faim_export void aim_purge_rxqueue(aim_session_t *sess) +{ + aim_frame_t *cur, **prev; + + for (prev = &sess->queue_incoming; (cur = *prev); ) { + if (cur->handled) { + + *prev = cur->next; + + if (!cur->nofree) + aim_frame_destroy(cur); + + } else + prev = &cur->next; + } + + return; } /* @@ -240,13 +436,14 @@ faim_export void aim_purge_rxqueue(struct aim_session_t *sess) * XXX: this is something that was handled better in the old connection * handling method, but eh. */ -faim_internal void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_internal void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn) { - struct command_rx_struct *currx; + aim_frame_t *currx; - for (currx = sess->queue_incoming; currx; currx = currx->next) { - if ((!currx->handled) && (currx->conn == conn)) - currx->handled = 1; - } - return; + for (currx = sess->queue_incoming; currx; currx = currx->next) { + if ((!currx->handled) && (currx->conn == conn)) + currx->handled = 1; + } + return; } + diff --git a/src/search.c b/src/search.c index 0a59662..3279309 100644 --- a/src/search.c +++ b/src/search.c @@ -9,124 +9,117 @@ #define FAIM_INTERNAL #include -faim_export unsigned long aim_usersearch_address(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *address) +faim_export int aim_usersearch_address(aim_session_t *sess, aim_conn_t *conn, const char *address) { - struct command_tx_struct *newpacket; - - if (!address) - return -1; + aim_frame_t *fr; + aim_snacid_t snacid; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+strlen(address)))) - return -1; + if (!sess || !conn || !address) + return -EINVAL; - newpacket->lock = 1; + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+strlen(address)))) + return -ENOMEM; - aim_putsnac(newpacket->data, 0x000a, 0x0002, 0x0000, sess->snac_nextid); + snacid = aim_cachesnac(sess, 0x000a, 0x0002, 0x0000, address, strlen(address)+1); - aimutil_putstr(newpacket->data+10, address, strlen(address)); + aim_putsnac(&fr->data, 0x000a, 0x0002, 0x0000, snacid); + aimbs_putraw(&fr->data, address, strlen(address)); /* XXX this doesn't seem right at all... */ - aim_tx_enqueue(sess, newpacket); + aim_tx_enqueue(sess, fr); - aim_cachesnac(sess, 0x000a, 0x0002, 0x0000, address, strlen(address)+1); - - return sess->snac_nextid; + return 0; } /* XXX can this be integrated with the rest of the error handling? */ -static int error(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int error(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - int ret = 0; - aim_rxcallback_t userfunc; - struct aim_snac_t *snac2; - - /* XXX the modules interface should have already retrieved this for us */ - if(!(snac2 = aim_remsnac(sess, snac->id))) { - faimdprintf(sess, 2, "couldn't get a snac for 0x%08lx\n", snac->id); - return 0; - } - - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, snac2->data /* address */); - - /* XXX freesnac()? */ - if (snac2) { - if(snac2->data) - free(snac2->data); - free(snac2); - } - - return ret; + int ret = 0; + aim_rxcallback_t userfunc; + aim_snac_t *snac2; + + /* XXX the modules interface should have already retrieved this for us */ + if (!(snac2 = aim_remsnac(sess, snac->id))) { + faimdprintf(sess, 2, "search error: couldn't get a snac for 0x%08lx\n", snac->id); + return 0; + } + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, snac2->data /* address */); + + /* XXX freesnac()? */ + if (snac2) + free(snac2->data); + free(snac2); + + return ret; } -static int reply(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int reply(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - unsigned int j, m, ret = 0; - struct aim_tlvlist_t *tlvlist; - char *cur = NULL, *buf = NULL; - aim_rxcallback_t userfunc; - struct aim_snac_t *snac2; + int j, m, ret = 0; + aim_tlvlist_t *tlvlist; + char *cur = NULL, *buf = NULL; + aim_rxcallback_t userfunc; + aim_snac_t *snac2; - if (!(snac2 = aim_remsnac(sess, snac->id))) { - faimdprintf(sess, 2, "faim: couldn't get a snac for 0x%08lx\n", snac->id); - return 0; - } + if (!(snac2 = aim_remsnac(sess, snac->id))) { + faimdprintf(sess, 2, "search reply: couldn't get a snac for 0x%08lx\n", snac->id); + return 0; + } - if (!(tlvlist = aim_readtlvchain(data, datalen))) - return 0; + tlvlist = aim_readtlvchain(bs); + return 0; - j = 0; + j = 0; - m = aim_counttlvchain(&tlvlist); + m = aim_counttlvchain(&tlvlist); - while((cur = aim_gettlv_str(tlvlist, 0x0001, j+1)) && j < m) { - if(!(buf = realloc(buf, (j+1) * (MAXSNLEN+1)))) - faimdprintf(sess, 2, "faim: couldn't realloc buf. oh well.\n"); + /* XXX uhm. */ + while ((cur = aim_gettlv_str(tlvlist, 0x0001, j+1)) && j < m) { + buf = realloc(buf, (j+1) * (MAXSNLEN+1)); - strncpy(&buf[j * (MAXSNLEN+1)], cur, MAXSNLEN); - free(cur); + strncpy(&buf[j * (MAXSNLEN+1)], cur, MAXSNLEN); + free(cur); - j++; - } + j++; + } - aim_freetlvchain(&tlvlist); + aim_freetlvchain(&tlvlist); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, snac2->data /* address */, j, buf); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + ret = userfunc(sess, rx, snac2->data /* address */, j, buf); - /* XXX freesnac()? */ - if(snac2) { - if(snac2->data) - free(snac2->data); - free(snac2); - } + /* XXX freesnac()? */ + if (snac2) + free(snac2->data); + free(snac2); - if(buf) - free(buf); + free(buf); - return ret; + return ret; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0001) - return error(sess, mod, rx, snac, data, datalen); - else if (snac->subtype == 0x0003) - return reply(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0001) + return error(sess, mod, rx, snac, bs); + else if (snac->subtype == 0x0003) + return reply(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int search_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int search_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x000a; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "search", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x000a; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "search", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } + + diff --git a/src/snac.c b/src/snac.c index 96f288f..4ab1bbb 100644 --- a/src/snac.c +++ b/src/snac.c @@ -18,68 +18,62 @@ /* * Called from aim_session_init() to initialize the hash. */ -faim_internal void aim_initsnachash(struct aim_session_t *sess) +faim_internal void aim_initsnachash(aim_session_t *sess) { - int i; + int i; - for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) { - sess->snac_hash[i] = NULL; - faim_mutex_init(&sess->snac_hash_locks[i]); - } + for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) { + sess->snac_hash[i] = NULL; + faim_mutex_init(&sess->snac_hash_locks[i]); + } - return; + return; } -faim_internal unsigned long aim_cachesnac(struct aim_session_t *sess, - const unsigned short family, - const unsigned short type, - const unsigned short flags, - const void *data, const int datalen) +faim_internal aim_snacid_t aim_cachesnac(aim_session_t *sess, const fu16_t family, const fu16_t type, const fu16_t flags, const void *data, const int datalen) { - struct aim_snac_t snac; + aim_snac_t snac; - snac.id = sess->snac_nextid++; - snac.family = family; - snac.type = type; - snac.flags = flags; + snac.id = sess->snacid_next++; + snac.family = family; + snac.type = type; + snac.flags = flags; - if (datalen) { - if (!(snac.data = malloc(datalen))) - return 0; /* er... */ - memcpy(snac.data, data, datalen); - } else - snac.data = NULL; + if (datalen) { + if (!(snac.data = malloc(datalen))) + return 0; /* er... */ + memcpy(snac.data, data, datalen); + } else + snac.data = NULL; - return aim_newsnac(sess, &snac); + return aim_newsnac(sess, &snac); } /* * Clones the passed snac structure and caches it in the * list/hash. */ -faim_internal unsigned long aim_newsnac(struct aim_session_t *sess, - struct aim_snac_t *newsnac) +faim_internal aim_snacid_t aim_newsnac(aim_session_t *sess, aim_snac_t *newsnac) { - struct aim_snac_t *snac = NULL; - int index; + aim_snac_t *snac; + int index; - if (!newsnac) - return 0; + if (!newsnac) + return 0; - if (!(snac = calloc(1, sizeof(struct aim_snac_t)))) - return 0; - memcpy(snac, newsnac, sizeof(struct aim_snac_t)); - snac->issuetime = time(&snac->issuetime); - snac->next = NULL; + if (!(snac = malloc(sizeof(aim_snac_t)))) + return 0; + memcpy(snac, newsnac, sizeof(aim_snac_t)); + snac->issuetime = time(NULL); - index = snac->id % FAIM_SNAC_HASH_SIZE; + index = snac->id % FAIM_SNAC_HASH_SIZE; - faim_mutex_lock(&sess->snac_hash_locks[index]); - snac->next = sess->snac_hash[index]; - sess->snac_hash[index] = snac; - faim_mutex_unlock(&sess->snac_hash_locks[index]); + faim_mutex_lock(&sess->snac_hash_locks[index]); + snac->next = (aim_snac_t *)sess->snac_hash[index]; + sess->snac_hash[index] = (void *)snac; + faim_mutex_unlock(&sess->snac_hash_locks[index]); - return(snac->id); + return snac->id; } /* @@ -89,37 +83,24 @@ faim_internal unsigned long aim_newsnac(struct aim_session_t *sess, * The returned structure must be freed by the caller. * */ -faim_internal struct aim_snac_t *aim_remsnac(struct aim_session_t *sess, - u_long id) +faim_internal aim_snac_t *aim_remsnac(aim_session_t *sess, aim_snacid_t id) { - struct aim_snac_t *cur = NULL; - int index; - - index = id % FAIM_SNAC_HASH_SIZE; - - faim_mutex_lock(&sess->snac_hash_locks[index]); - if (!sess->snac_hash[index]) - ; - else if (sess->snac_hash[index]->id == id) { - cur = sess->snac_hash[index]; - sess->snac_hash[index] = cur->next; - } else { - cur = sess->snac_hash[index]; - while (cur->next) { - if (cur->next->id == id) { - struct aim_snac_t *tmp; - - tmp = cur->next; - cur->next = cur->next->next; - cur = tmp; - break; - } - cur = cur->next; - } - } - faim_mutex_unlock(&sess->snac_hash_locks[index]); - - return cur; + aim_snac_t *cur, **prev; + int index; + + index = id % FAIM_SNAC_HASH_SIZE; + + faim_mutex_lock(&sess->snac_hash_locks[index]); + for (prev = (aim_snac_t **)&sess->snac_hash[index]; (cur = *prev); ) { + if (cur->id == id) { + *prev = cur->next; + return cur; + } else + prev = &cur->next; + } + faim_mutex_unlock(&sess->snac_hash_locks[index]); + + return cur; } /* @@ -129,49 +110,47 @@ faim_internal struct aim_snac_t *aim_remsnac(struct aim_session_t *sess, * maxage is the _minimum_ age in seconds to keep SNACs. * */ -faim_internal int aim_cleansnacs(struct aim_session_t *sess, - int maxage) +faim_internal void aim_cleansnacs(aim_session_t *sess, int maxage) { - int i; + int i; - for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) { - struct aim_snac_t *cur, **prev; - time_t curtime; + for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) { + aim_snac_t *cur, **prev; + time_t curtime; - faim_mutex_lock(&sess->snac_hash_locks[i]); - if (!sess->snac_hash[i]) { - faim_mutex_unlock(&sess->snac_hash_locks[i]); - continue; - } + faim_mutex_lock(&sess->snac_hash_locks[i]); + if (!sess->snac_hash[i]) { + faim_mutex_unlock(&sess->snac_hash_locks[i]); + continue; + } - curtime = time(NULL); /* done here in case we waited for the lock */ + curtime = time(NULL); /* done here in case we waited for the lock */ - for (prev = &sess->snac_hash[i]; (cur = *prev); ) { - if ((curtime - cur->issuetime) > maxage) { + for (prev = (aim_snac_t **)&sess->snac_hash[i]; (cur = *prev); ) { + if ((curtime - cur->issuetime) > maxage) { - *prev = cur->next; + *prev = cur->next; - /* XXX should we have destructors here? */ - if (cur->data) - free(cur->data); - free(cur); + /* XXX should we have destructors here? */ + free(cur->data); + free(cur); - } else - prev = &cur->next; - } + } else + prev = &cur->next; + } + faim_mutex_unlock(&sess->snac_hash_locks[i]); + } - faim_mutex_unlock(&sess->snac_hash_locks[i]); - } - - return 0; + return; } -faim_internal int aim_putsnac(u_char *buf, int family, int subtype, int flags, u_long snacid) +faim_internal int aim_putsnac(aim_bstream_t *bs, fu16_t family, fu16_t subtype, fu16_t flags, aim_snacid_t snacid) { - int curbyte = 0; - curbyte += aimutil_put16(buf+curbyte, (u_short)(family&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (u_short)(subtype&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (u_short)(flags&0xffff)); - curbyte += aimutil_put32(buf+curbyte, snacid); - return curbyte; + + aimbs_put16(bs, family); + aimbs_put16(bs, subtype); + aimbs_put16(bs, flags); + aimbs_put32(bs, snacid); + + return 10; } diff --git a/src/stats.c b/src/stats.c index 523305c..ae3101e 100644 --- a/src/stats.c +++ b/src/stats.c @@ -2,36 +2,36 @@ #define FAIM_INTERNAL #include -static int reportinterval(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int reportinterval(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - unsigned short interval; - aim_rxcallback_t userfunc; + fu16_t interval; + aim_rxcallback_t userfunc; - interval = aimutil_get16(data); + interval = aimbs_get16(bs); - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - return userfunc(sess, rx, interval); + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, interval); - return 0; + return 0; } -static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { - if (snac->subtype == 0x0002) - return reportinterval(sess, mod, rx, snac, data, datalen); + if (snac->subtype == 0x0002) + return reportinterval(sess, mod, rx, snac, bs); - return 0; + return 0; } -faim_internal int stats_modfirst(struct aim_session_t *sess, aim_module_t *mod) +faim_internal int stats_modfirst(aim_session_t *sess, aim_module_t *mod) { - mod->family = 0x000b; - mod->version = 0x0000; - mod->flags = 0; - strncpy(mod->name, "stats", sizeof(mod->name)); - mod->snachandler = snachandler; + mod->family = 0x000b; + mod->version = 0x0000; + mod->flags = 0; + strncpy(mod->name, "stats", sizeof(mod->name)); + mod->snachandler = snachandler; - return 0; + return 0; } diff --git a/src/tlv.c b/src/tlv.c index 5d7deee..e7d27ab 100644 --- a/src/tlv.c +++ b/src/tlv.c @@ -2,6 +2,30 @@ #define FAIM_INTERNAL #include +static aim_tlv_t *createtlv(void) +{ + aim_tlv_t *newtlv; + + if (!(newtlv = (aim_tlv_t *)malloc(sizeof(aim_tlv_t)))) + return NULL; + memset(newtlv, 0, sizeof(aim_tlv_t)); + + return newtlv; +} + +static void freetlv(aim_tlv_t **oldtlv) +{ + + if (!oldtlv || !*oldtlv) + return; + + free((*oldtlv)->value); + free(*oldtlv); + *oldtlv = NULL; + + return; +} + /** * aim_readtlvchain - Read a TLV chain from a buffer. * @buf: Input buffer @@ -12,65 +36,54 @@ * routines. When done with a TLV chain, aim_freetlvchain() should * be called to free the dynamic substructures. * + * XXX There should be a flag setable here to have the tlvlist contain + * bstream references, so that at least the ->value portion of each + * element doesn't need to be malloc/memcpy'd. This could prove to be + * just as effecient as the in-place TLV parsing used in a couple places + * in libfaim. + * */ -faim_export struct aim_tlvlist_t *aim_readtlvchain(const unsigned char *buf, const int maxlen) +faim_export aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs) { - int pos; - struct aim_tlvlist_t *list; - struct aim_tlvlist_t *cur; - - unsigned short type, length; - - 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) - { - /* - * Okay, so now AOL has decided that any TLV of - * type 0x0013 can only be two bytes, despite - * what the actual given length is. So here - * we dump any invalid TLVs of that sort. Hopefully - * theres no special cases to this special case. - * - mid (30jun2000) - */ - if ((type == 0x0013) && (length != 0x0002)) - length = 0x0002; - else { - cur = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(cur, 0x00, sizeof(struct aim_tlvlist_t)); - - cur->tlv = aim_createtlv(); - cur->tlv->type = type; - cur->tlv->length = length; - if (length) { - cur->tlv->value = (unsigned char *)malloc(length); - memcpy(cur->tlv->value, buf+pos, length); - } - - cur->next = list; - list = cur; - } - pos += length; - } + aim_tlvlist_t *list = NULL, *cur; + fu16_t type, length; + + while (aim_bstream_empty(bs)) { + + type = aimbs_get16(bs); + length = aimbs_get16(bs); + +#if 0 /* temporarily disabled until I know if they're still doing it or not */ + /* + * Okay, so now AOL has decided that any TLV of + * type 0x0013 can only be two bytes, despite + * what the actual given length is. So here + * we dump any invalid TLVs of that sort. Hopefully + * theres no special cases to this special case. + * - mid (30jun2000) + */ + if ((type == 0x0013) && (length != 0x0002)) + length = 0x0002; +#else + if (0) + ; +#endif + else { + + cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)); + memset(cur, 0, sizeof(aim_tlvlist_t)); + + cur->tlv = createtlv(); + cur->tlv->type = type; + if ((cur->tlv->length = length)) + cur->tlv->value = aimbs_getraw(bs, length); + + cur->next = list; + list = cur; + } } - } - return list; + return list; } /** @@ -82,23 +95,26 @@ faim_export struct aim_tlvlist_t *aim_readtlvchain(const unsigned char *buf, con * should be removed before calling this. * */ -faim_export void aim_freetlvchain(struct aim_tlvlist_t **list) +faim_export void aim_freetlvchain(aim_tlvlist_t **list) { - struct aim_tlvlist_t *cur, *cur2; - - if (!list || !(*list)) - return; - - cur = *list; - while (cur) - { - aim_freetlv(&cur->tlv); - cur2 = cur->next; - free(cur); - cur = cur2; - } - list = NULL; - return; + aim_tlvlist_t *cur; + + if (!list || !*list) + return; + + for (cur = *list; cur; ) { + aim_tlvlist_t *tmp; + + freetlv(&cur->tlv); + + tmp = cur->next; + free(cur); + cur = tmp; + } + + list = NULL; + + return; } /** @@ -108,18 +124,18 @@ faim_export void aim_freetlvchain(struct aim_tlvlist_t **list) * Returns the number of TLVs stored in the passed chain. * */ -faim_export int aim_counttlvchain(struct aim_tlvlist_t **list) +faim_export int aim_counttlvchain(aim_tlvlist_t **list) { - struct aim_tlvlist_t *cur; - int count = 0; + aim_tlvlist_t *cur; + int count; - if (!list || !(*list)) - return 0; + if (!list || !*list) + return 0; - for (cur = *list; cur; cur = cur->next) - count++; - - return count; + for (cur = *list, count = 0; cur; cur = cur->next) + count++; + + return count; } /** @@ -130,18 +146,18 @@ faim_export int aim_counttlvchain(struct aim_tlvlist_t **list) * write the passed TLV chain to a data buffer. * */ -faim_export int aim_sizetlvchain(struct aim_tlvlist_t **list) +faim_export int aim_sizetlvchain(aim_tlvlist_t **list) { - struct aim_tlvlist_t *cur; - int size = 0; + aim_tlvlist_t *cur; + int size; + + if (!list || !*list) + return 0; - if (!list || !(*list)) - return 0; + for (cur = *list, size = 0; cur; cur = cur->next) + size += (4 + cur->tlv->length); - for (cur = *list; cur; cur = cur->next) - size += (4 + cur->tlv->length); - - return size; + return size; } /** @@ -155,35 +171,36 @@ faim_export int aim_sizetlvchain(struct aim_tlvlist_t **list) * to the TLV chain. * */ -faim_export int aim_addtlvtochain_str(struct aim_tlvlist_t **list, const unsigned short type, const char *str, const int len) +faim_export int aim_addtlvtochain_raw(aim_tlvlist_t **list, const fu16_t t, const fu16_t l, const fu8_t *v) { - struct aim_tlvlist_t *newtlv; - struct aim_tlvlist_t *cur; - - if (!list) - return 0; - - newtlv = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(newtlv, 0x00, sizeof(struct aim_tlvlist_t)); - - newtlv->tlv = aim_createtlv(); - newtlv->tlv->type = type; - newtlv->tlv->length = len; - newtlv->tlv->value = (unsigned char *)malloc(newtlv->tlv->length*sizeof(unsigned char)); - memcpy(newtlv->tlv->value, str, newtlv->tlv->length); - - newtlv->next = NULL; - - if (*list == NULL) { - *list = newtlv; - } else if ((*list)->next == NULL) { - (*list)->next = newtlv; - } else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtlv; - } - return newtlv->tlv->length; + aim_tlvlist_t *newtlv, *cur; + + if (!list) + return 0; + + if (!(newtlv = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)))) + return 0; + memset(newtlv, 0x00, sizeof(aim_tlvlist_t)); + + if (!(newtlv->tlv = createtlv())) { + free(newtlv); + return 0; + } + newtlv->tlv->type = t; + if ((newtlv->tlv->length = l)) { + newtlv->tlv->value = (fu8_t *)malloc(newtlv->tlv->length); + memcpy(newtlv->tlv->value, v, newtlv->tlv->length); + } + + if (!*list) + *list = newtlv; + else { + for(cur = *list; cur->next; cur = cur->next) + ; + cur->next = newtlv; + } + + return newtlv->tlv->length; } /** @@ -195,35 +212,13 @@ faim_export int aim_addtlvtochain_str(struct aim_tlvlist_t **list, const unsigne * Adds a two-byte unsigned integer to a TLV chain. * */ -faim_export int aim_addtlvtochain16(struct aim_tlvlist_t **list, const unsigned short type, const unsigned short val) +faim_export int aim_addtlvtochain16(aim_tlvlist_t **list, const fu16_t t, const fu16_t v) { - struct aim_tlvlist_t *newtl; - struct aim_tlvlist_t *cur; - - if (!list) - return 0; - - newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(newtl, 0x00, sizeof(struct aim_tlvlist_t)); - - newtl->tlv = aim_createtlv(); - newtl->tlv->type = type; - newtl->tlv->length = 2; - newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char)); - aimutil_put16(newtl->tlv->value, val); - - newtl->next = NULL; - - if (*list == NULL) { - *list = newtl; - } else if ((*list)->next == NULL) { - (*list)->next = newtl; - } else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtl; - } - return 2; + fu8_t v16[2]; + + aimutil_put16(v16, v); + + return aim_addtlvtochain_raw(list, t, 2, v16); } /** @@ -235,35 +230,13 @@ faim_export int aim_addtlvtochain16(struct aim_tlvlist_t **list, const unsigned * Adds a four-byte unsigned integer to a TLV chain. * */ -faim_export int aim_addtlvtochain32(struct aim_tlvlist_t **list, const unsigned short type, const unsigned long val) +faim_export int aim_addtlvtochain32(aim_tlvlist_t **list, const fu16_t t, const fu32_t v) { - struct aim_tlvlist_t *newtl; - struct aim_tlvlist_t *cur; - - if (!list) - return 0; - - newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(newtl, 0x00, sizeof(struct aim_tlvlist_t)); - - newtl->tlv = aim_createtlv(); - newtl->tlv->type = type; - newtl->tlv->length = 4; - newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char)); - aimutil_put32(newtl->tlv->value, val); - - newtl->next = NULL; - - if (*list == NULL) { - *list = newtl; - } else if ((*list)->next == NULL) { - (*list)->next = newtl; - } else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtl; - } - return 4; + fu8_t v32[4]; + + aimutil_put32(v32, v); + + return aim_addtlvtochain_raw(list, t, 4, v32); } /** @@ -288,37 +261,16 @@ faim_export int aim_addtlvtochain32(struct aim_tlvlist_t **list, const unsigned * %AIM_CAPS_SENDFILE Supports Send File functions * */ -faim_export int aim_addtlvtochain_caps(struct aim_tlvlist_t **list, const unsigned short type, const unsigned short caps) +faim_export int aim_addtlvtochain_caps(aim_tlvlist_t **list, const fu16_t t, const fu16_t caps) { - unsigned char buf[128]; /* icky fixed length buffer */ - struct aim_tlvlist_t *newtl; - struct aim_tlvlist_t *cur; - - if(!list) - return 0; - - newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(newtl, 0x00, sizeof(struct aim_tlvlist_t)); - - newtl->tlv = aim_createtlv(); - newtl->tlv->type = type; - - newtl->tlv->length = aim_putcap(buf, sizeof(buf), caps); - newtl->tlv->value = (unsigned char *)calloc(1, newtl->tlv->length); - memcpy(newtl->tlv->value, buf, newtl->tlv->length); - - newtl->next = NULL; - - if (*list == NULL) { - *list = newtl; - } else if ((*list)->next == NULL) { - (*list)->next = newtl; - } else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtl; - } - return newtl->tlv->length; + fu8_t buf[16*16]; /* icky fixed length buffer */ + aim_bstream_t bs; + + aim_bstream_init(&bs, buf, sizeof(buf)); + + aim_putcap(&bs, caps); + + return aim_addtlvtochain_raw(list, t, aim_bstream_curpos(&bs), buf); } /** @@ -329,31 +281,44 @@ faim_export int aim_addtlvtochain_caps(struct aim_tlvlist_t **list, const unsign * Adds a TLV with a zero length to a TLV chain. * */ -faim_internal int aim_addtlvtochain_noval(struct aim_tlvlist_t **list, const unsigned short type) +faim_internal int aim_addtlvtochain_noval(aim_tlvlist_t **list, const fu16_t t) { - struct aim_tlvlist_t *newtlv; - struct aim_tlvlist_t *cur; - - newtlv = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t)); - memset(newtlv, 0x00, sizeof(struct aim_tlvlist_t)); - - newtlv->tlv = aim_createtlv(); - newtlv->tlv->type = type; - newtlv->tlv->length = 0; - newtlv->tlv->value = NULL; - - newtlv->next = NULL; - - if (*list == NULL) { - *list = newtlv; - } else if ((*list)->next == NULL) { - (*list)->next = newtlv; - } else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtlv; - } - return newtlv->tlv->length; + return aim_addtlvtochain_raw(list, t, 0, NULL); +} + +/* + * Note that the inner TLV chain will not be modifiable as a tlvchain once + * it is written using this. Or rather, it can be, but updates won't be + * made to this. + * + * XXX should probably support sublists for real. + * + * This is so neat. + * + */ +faim_internal int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl) +{ + fu8_t *buf; + int buflen; + aim_bstream_t bs; + + buflen = aim_sizetlvchain(tl); + + if (buflen <= 0) + return 0; + + if (!(buf = malloc(buflen))) + return 0; + + aim_bstream_init(&bs, buf, buflen); + + aim_writetlvchain(&bs, tl); + + aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); + + free(buf); + + return buflen; } /** @@ -367,34 +332,31 @@ faim_internal int aim_addtlvtochain_noval(struct aim_tlvlist_t **list, const uns * aim_freetlvchain() must still be called to free up the memory used * by the chain structures. * + * XXX clean this up, make better use of bstreams */ -faim_export int aim_writetlvchain(unsigned char *buf, int buflen, struct aim_tlvlist_t **list) +faim_export int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list) { - int goodbuflen = 0; - int i = 0; - struct aim_tlvlist_t *cur; - - 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; + int goodbuflen; + aim_tlvlist_t *cur; + + /* do an initial run to test total length */ + for (cur = *list, goodbuflen = 0; cur; cur = cur->next) { + goodbuflen += 2 + 2; /* type + len */ + goodbuflen += cur->tlv->length; + } + + if (goodbuflen > aim_bstream_empty(bs)) + return 0; /* not enough buffer */ + + /* do the real write-out */ + for (cur = *list; cur; cur = cur->next) { + aimbs_put16(bs, cur->tlv->type); + aimbs_put16(bs, cur->tlv->length); + if (cur->tlv->length) + aimbs_putraw(bs, cur->tlv->value, cur->tlv->length); + } + + return 1; /* XXX this is a nonsensical return */ } @@ -410,23 +372,21 @@ faim_export int aim_writetlvchain(unsigned char *buf, int buflen, struct aim_tlv * in a chain. * */ -faim_export struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, const unsigned short type, const int nth) +faim_export aim_tlv_t *aim_gettlv(aim_tlvlist_t *list, const fu16_t t, const int n) { - int i; - struct aim_tlvlist_t *cur; - - i = 0; - for (cur = list; cur != NULL; cur = cur->next) - { - if (cur && cur->tlv) - { - if (cur->tlv->type == type) - i++; - if (i >= nth) - return cur->tlv; + aim_tlvlist_t *cur; + int i; + + for (cur = list, i = 0; cur; cur = cur->next) { + if (cur && cur->tlv) { + if (cur->tlv->type == t) + i++; + if (i >= n) + return cur->tlv; + } } - } - return NULL; + + return NULL; } /** @@ -440,19 +400,19 @@ faim_export struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, const unsig * dynamic buffer and must be freed by the caller. * */ -faim_export char *aim_gettlv_str(struct aim_tlvlist_t *list, const unsigned short type, const int nth) +faim_export char *aim_gettlv_str(aim_tlvlist_t *list, const fu16_t t, const int n) { - struct aim_tlv_t *tlv; - char *newstr; + aim_tlv_t *tlv; + char *newstr; + + if (!(tlv = aim_gettlv(list, t, n))) + return NULL; - 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'; + newstr = (char *) malloc(tlv->length + 1); + memcpy(newstr, tlv->value, tlv->length); + *(newstr + tlv->length) = '\0'; - return newstr; + return newstr; } /** @@ -465,13 +425,13 @@ faim_export char *aim_gettlv_str(struct aim_tlvlist_t *list, const unsigned shor * 8bit integer instead of an aim_tlv_t. * */ -faim_internal unsigned char aim_gettlv8(struct aim_tlvlist_t *list, const unsigned short type, const int num) +faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t t, const int n) { - struct aim_tlv_t *tlv; + aim_tlv_t *tlv; - if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value) - return 0; /* erm */ - return aimutil_get8(tlv->value); + if (!(tlv = aim_gettlv(list, t, n))) + return 0; /* erm */ + return aimutil_get8(tlv->value); } /** @@ -484,13 +444,13 @@ faim_internal unsigned char aim_gettlv8(struct aim_tlvlist_t *list, const unsign * 16bit integer instead of an aim_tlv_t. * */ -faim_internal unsigned short aim_gettlv16(struct aim_tlvlist_t *list, const unsigned short type, const int num) +faim_internal fu16_t aim_gettlv16(aim_tlvlist_t *list, const fu16_t t, const int n) { - struct aim_tlv_t *tlv; + aim_tlv_t *tlv; - if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value) - return 0; /* erm */ - return aimutil_get16(tlv->value); + if (!(tlv = aim_gettlv(list, t, n))) + return 0; /* erm */ + return aimutil_get16(tlv->value); } /** @@ -503,144 +463,16 @@ faim_internal unsigned short aim_gettlv16(struct aim_tlvlist_t *list, const unsi * 32bit integer instead of an aim_tlv_t. * */ -faim_internal unsigned long aim_gettlv32(struct aim_tlvlist_t *list, const unsigned short type, const int num) +faim_internal fu32_t aim_gettlv32(aim_tlvlist_t *list, const fu16_t t, const int n) { - struct aim_tlv_t *tlv; + aim_tlv_t *tlv; - if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value) - return 0; /* erm */ - return aimutil_get32(tlv->value); -} - -/** - * aim_grabtlv - Grab a single TLV from a data buffer - * @src: Source data buffer (must be at least 4 bytes long) - * - * Creates a TLV structure aim_tlv_t and returns it - * filled with values from a buffer, possibly including a - * dynamically allocated buffer for the value portion. - * - * Both the aim_tlv_t and the tlv->value pointer - * must be freed by the caller if non-%NULL. - * - */ -faim_export struct aim_tlv_t *aim_grabtlv(const unsigned char *src) -{ - struct aim_tlv_t *dest = NULL; - - dest = aim_createtlv(); - - dest->type = src[0] << 8; - dest->type += src[1]; - - dest->length = src[2] << 8; - dest->length += src[3]; - - dest->value = (unsigned char *) malloc(dest->length); - memset(dest->value, 0, dest->length); - - memcpy(dest->value, &(src[4]), dest->length); - - return dest; -} - -/** - * aim_grabtlvstr - Grab a single TLV from a data buffer as string - * @src: Source data buffer (must be at least 4 bytes long) - * - * Creates a TLV structure aim_tlv_t and returns it - * filled with values from a buffer, possibly including a - * dynamically allocated buffer for the value portion, which - * is %NULL-terminated as a string. - * - * Both the aim_tlv_t and the tlv->value pointer - * must be freed by the caller if non-%NULL. - * - */ -faim_export struct aim_tlv_t *aim_grabtlvstr(const unsigned char *src) -{ - struct aim_tlv_t *dest = NULL; - - dest = aim_createtlv(); - - dest->type = src[0] << 8; - dest->type += src[1]; - - dest->length = src[2] << 8; - dest->length += src[3]; - - dest->value = (unsigned char *) malloc(dest->length+1); - memset(dest->value, 0, dest->length+1); - - memcpy(dest->value, src+4, dest->length); - dest->value[dest->length] = '\0'; - - return dest; -} - -/** - * aim_puttlv - Write a aim_tlv_t into a data buffer - * @dest: Destination data buffer - * @newtlv: Source TLV structure - * - * Writes out the passed TLV structure into the buffer. No bounds - * checking is done on the output buffer. - * - * The passed aim_tlv_t is not freed. aim_freetlv() should - * still be called by the caller to free the structure. - * - */ -faim_export int aim_puttlv(unsigned char *dest, struct aim_tlv_t *newtlv) -{ - int i=0; - - dest[i++] = newtlv->type >> 8; - dest[i++] = newtlv->type & 0x00FF; - dest[i++] = newtlv->length >> 8; - dest[i++] = newtlv->length & 0x00FF; - memcpy(&(dest[i]), newtlv->value, newtlv->length); - i+=newtlv->length; - return i; -} - -/** - * aim_createtlv - Generate an aim_tlv_t structure. - * - * Allocates an empty TLV structure and returns a pointer - * to it; %NULL on error. - * - */ -faim_export struct aim_tlv_t *aim_createtlv(void) -{ - struct aim_tlv_t *newtlv; - - if (!(newtlv = (struct aim_tlv_t *)malloc(sizeof(struct aim_tlv_t)))) - return NULL; - memset(newtlv, 0, sizeof(struct aim_tlv_t)); - return newtlv; -} - -/** - * aim_freetlv - Free a aim_tlv_t structure - * @oldtlv: TLV to be destroyed - * - * Frees both the TLV structure and the value portion. - * - */ -faim_export int aim_freetlv(struct aim_tlv_t **oldtlv) -{ - if (!oldtlv) - return -1; - if (!*oldtlv) - return -1; - if ((*oldtlv)->value) - free((*oldtlv)->value); - free(*(oldtlv)); - (*oldtlv) = NULL; - - return 0; + if (!(tlv = aim_gettlv(list, t, n))) + return 0; /* erm */ + return aimutil_get32(tlv->value); } +#if 0 /** * aim_puttlv_8 - Write a one-byte TLV. * @buf: Destination buffer @@ -650,15 +482,13 @@ faim_export int aim_freetlv(struct aim_tlv_t **oldtlv) * Writes a TLV with a one-byte integer value portion. * */ -faim_export int aim_puttlv_8(unsigned char *buf, const unsigned short t, const unsigned char v) +faim_export int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v) { - int curbyte=0; + fu8_t v8[1]; - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0001); - curbyte += aimutil_put8(buf+curbyte, (unsigned char)(v&0xff)); + aimutil_put8(v8, v); - return curbyte; + return aim_puttlv_raw(buf, t, 1, v8); } /** @@ -670,15 +500,16 @@ faim_export int aim_puttlv_8(unsigned char *buf, const unsigned short t, const u * Writes a TLV with a two-byte integer value portion. * */ -faim_export int aim_puttlv_16(unsigned char *buf, const unsigned short t, const unsigned short v) +faim_export int aim_puttlv_16(fu8_t *buf, const fu16_t t, const fu16_t v) { - int curbyte=0; - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0002); - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(v&0xffff)); - return curbyte; + fu8_t v16[2]; + + aimutil_put16(v16, v); + + return aim_puttlv_raw(buf, t, 2, v16); } + /** * aim_puttlv_32 - Write a four-byte TLV. * @buf: Destination buffer @@ -688,36 +519,38 @@ faim_export int aim_puttlv_16(unsigned char *buf, const unsigned short t, const * Writes a TLV with a four-byte integer value portion. * */ -faim_export int aim_puttlv_32(unsigned char *buf, const unsigned short t, const unsigned long v) +faim_export int aim_puttlv_32(fu8_t *buf, const fu16_t t, const fu32_t v) { - int curbyte=0; - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0004); - curbyte += aimutil_put32(buf+curbyte, (unsigned long)(v&0xffffffff)); - return curbyte; + fu8_t v32[4]; + + aimutil_put32(v32, v); + + return aim_puttlv_raw(buf, t, 4, v32); } /** - * aim_puttlv_str - Write a string TLV. + * aim_puttlv_raw - Write a raw TLV. * @buf: Destination buffer * @t: TLV type * @l: Length of string * @v: String to write * - * Writes a TLV with a string value portion. (Only the first @l - * bytes of the passed string will be written, which should not - * include the terminating NULL.) + * Writes a TLV with a raw value portion. (Only the first @l + * bytes of the passed buffer will be written, which should not + * include a terminating NULL.) * */ -faim_export int aim_puttlv_str(unsigned char *buf, const unsigned short t, const int l, const char *v) +faim_export int aim_puttlv_raw(fu8_t *buf, const fu16_t t, const fu16_t l, const fu8_t *v) { - int curbyte; - - curbyte = 0; - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff)); - curbyte += aimutil_put16(buf+curbyte, (unsigned short)(l&0xffff)); - if (v) - memcpy(buf+curbyte, (unsigned char *)v, l); - curbyte += l; - return curbyte; + int i; + + i = aimutil_put16(buf, t); + i += aimutil_put16(buf+i, l); + if (l) + memcpy(buf+i, v, l); + i += l; + + return i; } +#endif + diff --git a/src/txqueue.c b/src/txqueue.c index 49a669f..0d28b0e 100644 --- a/src/txqueue.c +++ b/src/txqueue.c @@ -20,60 +20,65 @@ * Right now, that is. If/when we implement a pool of transmit * frames, this will become the request-an-unused-frame part. * - * framing = AIM_FRAMETYPE_OFT/OSCAR - * chan = channel for OSCAR, hdrtype for OFT + * framing = AIM_FRAMETYPE_OFT/FLAP + * chan = channel for FLAP, hdrtype for OFT * */ -faim_internal struct command_tx_struct *aim_tx_new(struct aim_session_t *sess, - struct aim_conn_t *conn, - unsigned char framing, - int chan, - int datalen) +faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen) { - struct command_tx_struct *newtx; - - if (!conn) { - faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n"); - return NULL; - } - - /* For sanity... */ - if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) || (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT)) { - if (framing != AIM_FRAMETYPE_OFT) { - faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n"); - return NULL; - } - } else { - if (framing != AIM_FRAMETYPE_OSCAR) { - faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n"); - return NULL; - } - } - - newtx = (struct command_tx_struct *)malloc(sizeof(struct command_tx_struct)); - if (!newtx) - return NULL; - memset(newtx, 0, sizeof(struct command_tx_struct)); - - newtx->conn = conn; - - if(datalen) { - newtx->data = (unsigned char *)malloc(datalen); - newtx->commandlen = datalen; - } else - newtx->data = NULL; - - newtx->hdrtype = framing; - if (newtx->hdrtype == AIM_FRAMETYPE_OSCAR) { - newtx->hdr.oscar.type = chan; - } else if (newtx->hdrtype == AIM_FRAMETYPE_OFT) { - newtx->hdr.oft.type = chan; - newtx->hdr.oft.hdr2len = 0; /* this will get setup by caller */ - } else { - faimdprintf(sess, 0, "tx_new: unknown framing\n"); - } - - return newtx; + aim_frame_t *fr; + + if (!conn) { + faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n"); + return NULL; + } + + /* For sanity... */ + if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) || + (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT)) { + if (framing != AIM_FRAMETYPE_OFT) { + faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n"); + return NULL; + } + } else { + if (framing != AIM_FRAMETYPE_FLAP) { + faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n"); + return NULL; + } + } + + if (!(fr = (aim_frame_t *)malloc(sizeof(aim_frame_t)))) + return NULL; + memset(fr, 0, sizeof(aim_frame_t)); + + fr->conn = conn; + + fr->hdrtype = framing; + + if (fr->hdrtype == AIM_FRAMETYPE_FLAP) { + + fr->hdr.flap.type = chan; + + } else if (fr->hdrtype == AIM_FRAMETYPE_OFT) { + + fr->hdr.oft.type = chan; + fr->hdr.oft.hdr2len = 0; /* this will get setup by caller */ + + } else + faimdprintf(sess, 0, "tx_new: unknown framing\n"); + + if (datalen > 0) { + fu8_t *data; + + if (!(data = (unsigned char *)malloc(datalen))) { + aim_frame_destroy(fr); + return NULL; + } + + aim_bstream_init(&fr->data, data, datalen); + } + + return fr; } /* @@ -82,48 +87,41 @@ faim_internal struct command_tx_struct *aim_tx_new(struct aim_session_t *sess, * The overall purpose here is to enqueue the passed in command struct * into the outgoing (tx) queue. Basically... * 1) Make a scope-irrelevent copy of the struct - * 2) Lock the struct * 3) Mark as not-sent-yet * 4) Enqueue the struct into the list - * 5) Unlock the struct once it's linked in * 6) Return * * Note that this is only used when doing queue-based transmitting; * that is, when sess->tx_enqueue is set to &aim_tx_enqueue__queuebased. * */ -static int aim_tx_enqueue__queuebased(struct aim_session_t *sess, struct command_tx_struct *newpacket) +static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr) { - struct command_tx_struct *cur; - - if (newpacket->conn == NULL) { - faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n"); - newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); - } - - if (newpacket->hdrtype == AIM_FRAMETYPE_OSCAR) { - /* assign seqnum */ - newpacket->hdr.oscar.seqnum = aim_get_next_txseqnum(newpacket->conn); - } - /* set some more fields */ - newpacket->lock = 1; /* lock */ - newpacket->sent = 0; /* not sent yet */ - newpacket->next = NULL; /* always last */ - - /* 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 */ - - return 0; + + if (!fr->conn) { + faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n"); + fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); + } + + if (fr->hdrtype == AIM_FRAMETYPE_FLAP) { + /* assign seqnum -- XXX should really not assign until hardxmit */ + fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn); + } + + fr->handled = 0; /* not sent yet */ + + /* see overhead note in aim_rxqueue counterpart */ + if (!sess->queue_outgoing) + sess->queue_outgoing = fr; + else { + aim_frame_t *cur; + + for (cur = sess->queue_outgoing; cur->next; cur = cur->next) + ; + cur->next = fr; + } + + return 0; } /* @@ -137,63 +135,58 @@ static int aim_tx_enqueue__queuebased(struct aim_session_t *sess, struct command * right here. * */ -static int aim_tx_enqueue__immediate(struct aim_session_t *sess, struct command_tx_struct *newpacket) +static int aim_tx_enqueue__immediate(aim_session_t *sess, aim_frame_t *fr) { - if (newpacket->conn == NULL) { - faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n"); - if (newpacket->data) - free(newpacket->data); - free(newpacket); - return -1; - } - if (newpacket->hdrtype == AIM_FRAMETYPE_OSCAR) - newpacket->hdr.oscar.seqnum = aim_get_next_txseqnum(newpacket->conn); + if (!fr->conn) { + faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n"); + aim_frame_destroy(fr); + return 0; + } - newpacket->lock = 1; /* lock */ - newpacket->sent = 0; /* not sent yet */ + if (fr->hdrtype == AIM_FRAMETYPE_FLAP) + fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn); - aim_tx_sendframe(sess, newpacket); + fr->handled = 0; /* not sent yet */ - if (newpacket->data) - free(newpacket->data); - free(newpacket); + aim_tx_sendframe(sess, fr); - return 0; + aim_frame_destroy(fr); + + return 0; } -faim_export int aim_tx_setenqueue(struct aim_session_t *sess, - int what, - int (*func)(struct aim_session_t *, struct command_tx_struct *)) +faim_export int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *)) { - if (!sess) - return -1; - - if (what == AIM_TX_QUEUED) - sess->tx_enqueue = &aim_tx_enqueue__queuebased; - else if (what == AIM_TX_IMMEDIATE) - sess->tx_enqueue = &aim_tx_enqueue__immediate; - else if (what == AIM_TX_USER) { - if (!func) - return -1; - sess->tx_enqueue = func; - } else - return -1; /* unknown action */ - - return 0; + + if (what == AIM_TX_QUEUED) + sess->tx_enqueue = &aim_tx_enqueue__queuebased; + else if (what == AIM_TX_IMMEDIATE) + sess->tx_enqueue = &aim_tx_enqueue__immediate; + else if (what == AIM_TX_USER) { + if (!func) + return -EINVAL; + sess->tx_enqueue = func; + } else + return -EINVAL; /* unknown action */ + + return 0; } -faim_internal int aim_tx_enqueue(struct aim_session_t *sess, struct command_tx_struct *command) +faim_internal int aim_tx_enqueue(aim_session_t *sess, aim_frame_t *fr) { - /* - * If we want to send a connection thats inprogress, we have to force - * them to use the queue based version. Otherwise, use whatever they - * want. - */ - if (command && command->conn && (command->conn->status & AIM_CONN_STATUS_INPROGRESS)) { - return aim_tx_enqueue__queuebased(sess, command); - } - return (*sess->tx_enqueue)(sess, command); + + /* + * If we want to send a connection thats inprogress, we have to force + * them to use the queue based version. Otherwise, use whatever they + * want. + */ + if (fr && fr->conn && + (fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) { + return aim_tx_enqueue__queuebased(sess, fr); + } + + return (*sess->tx_enqueue)(sess, fr); } /* @@ -205,184 +198,191 @@ faim_internal int aim_tx_enqueue(struct aim_session_t *sess, struct command_tx_s * before enqueuement (in aim_tx_enqueue()). * */ -faim_internal unsigned int aim_get_next_txseqnum(struct aim_conn_t *conn) +faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *conn) { - u_int ret; - - faim_mutex_lock(&conn->seqnum_lock); - ret = ++conn->seqnum; - faim_mutex_unlock(&conn->seqnum_lock); - return ret; + flap_seqnum_t ret; + + faim_mutex_lock(&conn->seqnum_lock); + ret = ++conn->seqnum; + faim_mutex_unlock(&conn->seqnum_lock); + + return ret; } -/* - * aim_tx_flushqueue() - * - * This the function is responsable for putting the queued commands - * onto the wire. This function is critical to the operation of - * the queue and therefore is the most prone to brokenness. It - * seems to be working quite well at this point. - * - * Procedure: - * 1) Traverse the list, only operate on commands that are unlocked - * and haven't been sent yet. - * 2) Lock the struct - * 3) Allocate a temporary buffer to store the finished, fully - * processed packet in. - * 4) Build the packet from the command_tx_struct data. - * 5) Write the packet to the socket. - * 6) If success, mark the packet sent, if fail report failure, do NOT - * mark the packet sent (so it will not get purged and therefore - * be attempted again on next call). - * 7) Unlock the struct. - * 8) Free the temp buffer - * 9) Step to next struct in list and go back to 1. - * - */ -faim_internal int aim_tx_sendframe(struct aim_session_t *sess, struct command_tx_struct *cur) +static int aim_send(int fd, const void *buf, size_t count) { - int buflen = 0; - unsigned char *curPacket; - - if (!cur) - return -1; /* fatal */ - - cur->lock = 1; /* lock the struct */ - - if (cur->hdrtype == AIM_FRAMETYPE_OSCAR) - buflen = cur->commandlen + 6; - else if (cur->hdrtype == AIM_FRAMETYPE_OFT) - buflen = cur->hdr.oft.hdr2len + 8; - else { - cur->lock = 0; - return -1; - } - - /* allocate full-packet buffer */ - if (!(curPacket = (unsigned char *) malloc(buflen))) { - cur->lock = 0; - return -1; - } - - if (cur->hdrtype == AIM_FRAMETYPE_OSCAR) { - /* command byte */ - curPacket[0] = 0x2a; - - /* type/family byte */ - curPacket[1] = cur->hdr.oscar.type; - - /* bytes 3+4: word: FLAP sequence number */ - aimutil_put16(curPacket+2, cur->hdr.oscar.seqnum); - - /* bytes 5+6: word: SNAC len */ - aimutil_put16(curPacket+4, cur->commandlen); - - /* bytes 7 and on: raw: SNAC data */ /* XXX: ye gods! get rid of this! */ - memcpy(&(curPacket[6]), cur->data, cur->commandlen); - - } else if (cur->hdrtype == AIM_FRAMETYPE_OFT) { - int z = 0; - - z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[0]); - z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[1]); - z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[2]); - z += aimutil_put8(curPacket+z, cur->hdr.oft.magic[3]); - - z += aimutil_put16(curPacket+z, cur->hdr.oft.hdr2len + 8); - z += aimutil_put16(curPacket+z, cur->hdr.oft.type); - - memcpy(curPacket+z, cur->hdr.oft.hdr2, cur->hdr.oft.hdr2len); - } - - /* - * For OSCAR, a full image of the raw packet data now in curPacket. - * For OFT, an image of just the bloated header is in curPacket, - * since OFT allows us to do the data in a different write (yay!). - */ - faim_mutex_lock(&cur->conn->active); - if (send(cur->conn->fd, curPacket, buflen, 0) != buflen) { - faim_mutex_unlock(&cur->conn->active); - cur->sent = 1; - aim_conn_close(cur->conn); - return 0; /* bail out */ - } - - if ((cur->hdrtype == AIM_FRAMETYPE_OFT) && cur->commandlen) { - int curposi; - for(curposi = 0; curposi < cur->commandlen; curposi++) - faimdprintf(sess, 0, "%02x ", cur->data[curposi]); - - if (send(cur->conn->fd, cur->data, cur->commandlen, 0) != (int)cur->commandlen) { - /* - * Theres nothing we can do about this since we've already sent the - * header! The connection is unstable. - */ - faim_mutex_unlock(&cur->conn->active); - cur->sent = 1; - aim_conn_close(cur->conn); - return 0; /* bail out */ - } - - } - - cur->sent = 1; /* mark the struct as sent */ - cur->conn->lastactivity = time(NULL); - - faim_mutex_unlock(&cur->conn->active); - - if (sess->debug >= 2) { - int i; - - faimdprintf(sess, 2, "\nOutgoing packet: (only valid for OSCAR)"); - for (i = 0; i < buflen; i++) { - if (!(i % 8)) - faimdprintf(sess, 2, "\n\t"); - faimdprintf(sess, 2, "0x%02x ", curPacket[i]); - } - faimdprintf(sess, 2, "\n"); - } - - cur->lock = 0; /* unlock the struct */ - - free(curPacket); /* free up full-packet buffer */ - - return 1; /* success */ + int left, cur; + + for (cur = 0, left = count; left; ) { + int ret; + + ret = send(fd, ((unsigned char *)buf)+cur, left, 0); + if (ret == -1) + return -1; + else if (ret == 0) + return cur; + + cur += ret; + left -= ret; + } + + return cur; } -faim_export int aim_tx_flushqueue(struct aim_session_t *sess) +static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count) { - struct command_tx_struct *cur; - - if (sess->queue_outgoing == NULL) - return 0; - - faimdprintf(sess, 2, "beginning txflush...\n"); - for (cur = sess->queue_outgoing; cur; cur = cur->next) { - /* only process if its unlocked and unsent */ - if (!cur->lock && !cur->sent) { - - if (cur->conn && (cur->conn->status & AIM_CONN_STATUS_INPROGRESS)) - continue; - - /* - * 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)); - } - - /* XXX XXX XXX this should call the custom "queuing" function!! */ - if (aim_tx_sendframe(sess, cur) == -1) - break; - } - } - - /* purge sent commands from queue */ - aim_tx_purgequeue(sess); - - return 0; + int wrote = 0; + + if (!bs || !conn || (count < 0)) + return -EINVAL; + + if (count > aim_bstream_empty(bs)) + count = aim_bstream_empty(bs); /* truncate to remaining space */ + + if (count) + wrote = aim_send(conn->fd, bs->data + bs->offset, count); + + if (((aim_session_t *)conn->sessv)->debug >= 2) { + int i; + aim_session_t *sess = (aim_session_t *)conn->sessv; + + faimdprintf(sess, 2, "\nOutgoing data: (%d bytes)", wrote); + for (i = 0; i < wrote; i++) { + if (!(i % 8)) + faimdprintf(sess, 2, "\n\t"); + faimdprintf(sess, 2, "0x%02x ", *(bs->data + bs->offset + i)); + } + faimdprintf(sess, 2, "\n"); + } + + + bs->offset += wrote; + + return wrote; +} + +static int sendframe_flap(aim_session_t *sess, aim_frame_t *fr) +{ + aim_bstream_t obs; + fu8_t *obs_raw; + int payloadlen, err = 0, obslen; + + payloadlen = aim_bstream_curpos(&fr->data); + + if (!(obs_raw = malloc(6 + payloadlen))) + return -ENOMEM; + + aim_bstream_init(&obs, obs_raw, 6 + payloadlen); + + /* FLAP header */ + aimbs_put8(&obs, 0x2a); + aimbs_put8(&obs, fr->hdr.flap.type); + aimbs_put16(&obs, fr->hdr.flap.seqnum); + aimbs_put16(&obs, payloadlen); + + /* payload */ + aim_bstream_rewind(&fr->data); + aimbs_putbs(&obs, &fr->data, payloadlen); + + obslen = aim_bstream_curpos(&obs); + aim_bstream_rewind(&obs); + + if (aim_bstream_send(&obs, fr->conn, obslen) != obslen) + err = -errno; + + free(obs_raw); /* XXX aim_bstream_free */ + + fr->handled = 1; + fr->conn->lastactivity = time(NULL); + + return err; +} + +static int sendframe_oft(aim_session_t *sess, aim_frame_t *fr) +{ + aim_bstream_t hbs; + fu8_t *hbs_raw; + int hbslen; + int err = 0; + + hbslen = 8 + fr->hdr.oft.hdr2len; + + if (!(hbs_raw = malloc(hbslen))) + return -1; + + aim_bstream_init(&hbs, hbs_raw, hbslen); + + aimbs_putraw(&hbs, fr->hdr.oft.magic, 4); + aimbs_put16(&hbs, fr->hdr.oft.hdr2len + 8); + aimbs_put16(&hbs, fr->hdr.oft.type); + aimbs_putraw(&hbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len); + + if (aim_bstream_send(&hbs, fr->conn, hbslen) != hbslen) { + + err = -errno; + + } else if (aim_bstream_curpos(&fr->data)) { + int len; + + len = aim_bstream_curpos(&fr->data); + aim_bstream_rewind(&fr->data); + + if (aim_bstream_send(&fr->data, fr->conn, len) != len) + err = -errno; + } + + free(hbs_raw); /* XXX aim_bstream_free */ + + fr->handled = 1; + fr->conn->lastactivity = time(NULL); + + return err; +} + +faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *fr) +{ + if (fr->hdrtype == AIM_FRAMETYPE_FLAP) + return sendframe_flap(sess, fr); + else if (fr->hdrtype == AIM_FRAMETYPE_OFT) + return sendframe_oft(sess, fr); + return -1; +} + +faim_export int aim_tx_flushqueue(aim_session_t *sess) +{ + aim_frame_t *cur; + + for (cur = sess->queue_outgoing; cur; cur = cur->next) { + + if (cur->handled) + continue; /* already been sent */ + + if (cur->conn && (cur->conn->status & AIM_CONN_STATUS_INPROGRESS)) + continue; + + /* + * And now for the meager attempt to force transmit + * latency and avoid missed messages. + */ + if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) { + /* + * XXX should be a break! we dont want to block the + * upper layers + * + * XXX or better, just do this right. + * + */ + sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL)); + } + + /* XXX this should call the custom "queuing" function!! */ + aim_tx_sendframe(sess, cur); + } + + /* purge sent commands from queue */ + aim_tx_purgequeue(sess); + + return 0; } /* @@ -393,47 +393,22 @@ faim_export int aim_tx_flushqueue(struct aim_session_t *sess) * reduce memory footprint at run time! * */ -faim_export void aim_tx_purgequeue(struct aim_session_t *sess) +faim_export void aim_tx_purgequeue(aim_session_t *sess) { - struct command_tx_struct *cur = NULL; - struct command_tx_struct *tmp; - - if (sess->queue_outgoing == NULL) - return; - - if (sess->queue_outgoing->next == NULL) { - if (!sess->queue_outgoing->lock && sess->queue_outgoing->sent) { - tmp = sess->queue_outgoing; - sess->queue_outgoing = NULL; - if (tmp->hdrtype == AIM_FRAMETYPE_OFT) - free(tmp->hdr.oft.hdr2); - free(tmp->data); - free(tmp); - } - return; - } - - for(cur = sess->queue_outgoing; cur->next != NULL; ) { - if (!cur->next->lock && cur->next->sent) { - tmp = cur->next; - cur->next = tmp->next; - if (tmp->hdrtype == AIM_FRAMETYPE_OFT) - free(tmp->hdr.oft.hdr2); - free(tmp->data); - free(tmp); - } - cur = cur->next; - - /* - * 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; + aim_frame_t *cur, **prev; + + for (prev = &sess->queue_outgoing; (cur = *prev); ) { + + if (cur->handled) { + *prev = cur->next; + + aim_frame_destroy(cur); + + } else + prev = &cur->next; + } + + return; } /** @@ -444,22 +419,17 @@ faim_export void aim_tx_purgequeue(struct aim_session_t *sess) * for now this simply marks all packets as sent and lets them * disappear without warning. * - * doesn't respect command_tx_struct locks. */ - -faim_export int aim_tx_cleanqueue(struct aim_session_t *sess, struct aim_conn_t *conn) +faim_export void aim_tx_cleanqueue(aim_session_t *sess, aim_conn_t *conn) { - struct command_tx_struct *cur = NULL; + aim_frame_t *cur; - if(!sess || !conn) - return -1; + for (cur = sess->queue_outgoing; cur; cur = cur->next) { + if (cur->conn == conn) + cur->handled = 1; + } - /* we don't respect locks here */ - for(cur = sess->queue_outgoing; cur; cur = cur->next) - if(cur->conn == conn) - cur->sent = 1; - - return 0; + return; } - - + + diff --git a/src/util.c b/src/util.c index e859400..b608091 100644 --- a/src/util.c +++ b/src/util.c @@ -7,62 +7,10 @@ #include #include -#ifdef AIMUTIL_USEMACROS -/* macros in faim/aim.h */ -#else -faim_shortfunc int aimutil_put8(u_char *buf, u_char data) -{ - buf[0] = (u_char)data&0xff; - return 1; -} - -faim_shortfunc u_char aimutil_get8(u_char *buf) -{ - return buf[0]; -} - -/* - * Endian-ness issues here? - */ -faim_shortfunc int aimutil_put16(u_char *buf, u_short data) -{ - buf[0] = (u_char)(data>>8)&0xff; - buf[1] = (u_char)(data)&0xff; - return 2; -} - -faim_shortfunc u_short aimutil_get16(u_char *buf) -{ - u_short val; - val = (buf[0] << 8) & 0xff00; - val+= (buf[1]) & 0xff; - return val; -} - -faim_shortfunc int aimutil_put32(u_char *buf, u_long data) -{ - buf[0] = (u_char)(data>>24)&0xff; - buf[1] = (u_char)(data>>16)&0xff; - buf[2] = (u_char)(data>>8)&0xff; - buf[3] = (u_char)(data)&0xff; - return 4; -} - -faim_shortfunc u_long aimutil_get32(u_char *buf) -{ - u_long val; - val = (buf[0] << 24) & 0xff000000; - val+= (buf[1] << 16) & 0x00ff0000; - val+= (buf[2] << 8) & 0x0000ff00; - val+= (buf[3] ) & 0x000000ff; - return val; -} -#endif /* AIMUTIL_USEMACROS */ - faim_export faim_shortfunc int aimutil_putstr(u_char *dest, const char *src, int len) { - memcpy(dest, src, len); - return len; + memcpy(dest, src, len); + return len; } /* @@ -72,194 +20,184 @@ faim_export faim_shortfunc int aimutil_putstr(u_char *dest, const char *src, int */ faim_export 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 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; } faim_export int aimutil_itemcnt(char *toSearch, char dl) { - int curCount; - char *next; - - curCount = 1; - - next = strchr(toSearch, dl); - - while(next != NULL) - { - curCount++; - next = strchr(next + 1, dl); - } - - return curCount; + int curCount; + char *next; + + curCount = 1; + + next = strchr(toSearch, dl); + + while(next != NULL) { + curCount++; + next = strchr(next + 1, dl); + } + + return curCount; } faim_export char *aimutil_itemidx(char *toSearch, int index, char dl) { - int curCount; - char *next; - char *last; - char *toReturn; - - curCount = 0; - - last = toSearch; - next = strchr(toSearch, dl); - - while(curCount < index && next != NULL) - { - curCount++; - last = next + 1; - next = strchr(last, dl); - } - - if (curCount < index) - { - toReturn = malloc(sizeof(char)); - *toReturn = '\0'; - } - next = strchr(last, dl); - - if (curCount < index) - { - toReturn = malloc(sizeof(char)); - *toReturn = '\0'; - } - else - { - if (next == NULL) - { - toReturn = malloc((strlen(last) + 1) * sizeof(char)); - strcpy(toReturn, last); + int curCount; + char *next; + char *last; + char *toReturn; + + curCount = 0; + + last = toSearch; + next = strchr(toSearch, dl); + + while (curCount < index && next != NULL) { + curCount++; + last = next + 1; + next = strchr(last, dl); } - else - { - toReturn = malloc((next - last + 1) * sizeof(char)); - memcpy(toReturn, last, (next - last)); - toReturn[next - last] = '\0'; + + if (curCount < index) { + toReturn = malloc(sizeof(char)); + *toReturn = '\0'; } - } - return toReturn; + next = strchr(last, dl); + + if (curCount < index) { + toReturn = malloc(sizeof(char)); + *toReturn = '\0'; + } else { + if (next == NULL) { + toReturn = malloc((strlen(last) + 1) * sizeof(char)); + strcpy(toReturn, last); + } else { + toReturn = malloc((next - last + 1) * sizeof(char)); + memcpy(toReturn, last, (next - last)); + toReturn[next - last] = '\0'; + } + } + return toReturn; } /* - * int snlen(const char *) - * - * This takes a screen name and returns its length without - * spaces. If there are no spaces in the SN, then the - * return is equal to that of strlen(). - * - */ +* int snlen(const char *) +* +* This takes a screen name and returns its length without +* spaces. If there are no spaces in the SN, then the +* return is equal to that of strlen(). +* +*/ faim_export int aim_snlen(const char *sn) { - int i = 0; - const char *curPtr = NULL; + int i = 0; + const char *curPtr = NULL; - if (!sn) - return 0; + if (!sn) + return 0; - curPtr = sn; - while ( (*curPtr) != (char) NULL) { - if ((*curPtr) != ' ') - i++; - curPtr++; - } + curPtr = sn; + while ( (*curPtr) != (char) NULL) { + if ((*curPtr) != ' ') + i++; + curPtr++; + } - return i; + return i; } /* - * int sncmp(const char *, const char *) - * - * This takes two screen names and compares them using the rules - * on screen names for AIM/AOL. Mainly, this means case and space - * insensitivity (all case differences and spacing differences are - * ignored). - * - * Return: 0 if equal - * non-0 if different - * - */ +* int sncmp(const char *, const char *) +* +* This takes two screen names and compares them using the rules +* on screen names for AIM/AOL. Mainly, this means case and space +* insensitivity (all case differences and spacing differences are +* ignored). +* +* Return: 0 if equal +* non-0 if different +* +*/ faim_export int aim_sncmp(const char *sn1, const char *sn2) { - const char *curPtr1 = NULL, *curPtr2 = NULL; - - 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; + 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; } /* strsep Copyright (C) 1992, 1993 Free Software Foundation, Inc. - strsep is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., 675 Mass Ave, - Cambridge, MA 02139, USA. */ +strsep is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ /* Minor changes by and1000 on 15/1/97 to make it go under Nemesis */ faim_export char *aim_strsep(char **pp, const char *delim) { - char *p, *q; - - if (!(p = *pp)) - return 0; - - if ((q = strpbrk (p, delim))) - { - *pp = q + 1; - *q = '\0'; - } - else - *pp = 0; - - return p; + char *p, *q; + + if (!(p = *pp)) + return 0; + + if ((q = strpbrk (p, delim))) { + *pp = q + 1; + *q = '\0'; + } else + *pp = 0; + + return p; } + + diff --git a/utils/faimtest/Makefile.am b/utils/faimtest/Makefile.am index c07f0f4..b2107ec 100644 --- a/utils/faimtest/Makefile.am +++ b/utils/faimtest/Makefile.am @@ -1,6 +1,6 @@ bin_PROGRAMS = faimtest -faimtest_SOURCES = faimtest.h faimtest.c commands.c +faimtest_SOURCES = faimtest.h faimtest.c commands.c login.c ft.c chat.c INCLUDES = -I$(top_srcdir)/include faimtest_LDADD = -L$(top_srcdir)/src/ -lfaim @READLINELIB@ faimtest_DEPENDENCIES = $(top_srcdir)/src/.libs/libfaim.a diff --git a/utils/faimtest/chat.c b/utils/faimtest/chat.c new file mode 100644 index 0000000..31ce24b --- /dev/null +++ b/utils/faimtest/chat.c @@ -0,0 +1,260 @@ + +#include "faimtest.h" + +static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + struct aim_userinfo_s *userinfo; + int count, i; + + va_start(ap, fr); + count = va_arg(ap, int); + userinfo = va_arg(ap, struct aim_userinfo_s *); + va_end(ap); + + dvprintf("faimtest: chat: %s: New occupants have joined:\n", (char *)fr->conn->priv); + for (i = 0; i < count; i++) + dvprintf("faimtest: chat: %s: \t%s\n", (char *)fr->conn->priv, userinfo[i].sn); + + return 1; +} + +static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + struct aim_userinfo_s *userinfo; + int count , i; + + va_start(ap, fr); + count = va_arg(ap, int); + userinfo = va_arg(ap, struct aim_userinfo_s *); + va_end(ap); + + dvprintf("faimtest: chat: %s: Some occupants have left:\n", (char *)fr->conn->priv); + + for (i = 0; i < count; i++) + dvprintf("faimtest: chat: %s: \t%s\n", (char *)fr->conn->priv, userinfo[i].sn); + + return 1; +} + +static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + struct aim_userinfo_s *userinfo; + struct aim_chat_roominfo *roominfo; + char *roomname; + int usercount, i; + char *roomdesc; + fu16_t unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen; + fu32_t creationtime; + const char *croomname = (const char *)fr->conn->priv; + + va_start(ap, fr); + roominfo = va_arg(ap, struct aim_chat_roominfo *); + roomname = va_arg(ap, char *); + usercount = va_arg(ap, int); + userinfo = va_arg(ap, struct aim_userinfo_s *); + roomdesc = va_arg(ap, char *); + unknown_c9 = va_arg(ap, fu16_t); + creationtime = va_arg(ap, fu32_t); + maxmsglen = va_arg(ap, fu16_t); + unknown_d2 = va_arg(ap, fu16_t); + unknown_d5 = va_arg(ap, fu16_t); + maxvisiblemsglen = va_arg(ap, fu16_t); + va_end(ap); + + dvprintf("faimtest: chat: %s: info update:\n", croomname); + dvprintf("faimtest: chat: %s: \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance); + dvprintf("faimtest: chat: %s: \tRoomname: %s\n", croomname, roomname); + dvprintf("faimtest: chat: %s: \tRoomdesc: %s\n", croomname, roomdesc); + dvprintf("faimtest: chat: %s: \tOccupants: (%d)\n", croomname, usercount); + + for (i = 0; i < usercount; i++) + dvprintf("faimtest: chat: %s: \t\t%s\n", croomname, userinfo[i].sn); + + dvprintf("faimtest: chat: %s: \tUnknown_c9: 0x%04x\n", croomname, unknown_c9); + dvprintf("faimtest: chat: %s: \tCreation time: %lu (time_t)\n", croomname, creationtime); + dvprintf("faimtest: chat: %s: \tUnknown_d2: 0x%04x\n", croomname, unknown_d2); + dvprintf("faimtest: chat: %s: \tUnknown_d5: 0x%02x\n", croomname, unknown_d5); + dvprintf("faimtest: chat: %s: \tMax message length: %d bytes\n", croomname, maxmsglen); + dvprintf("faimtest: chat: %s: \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen); + + return 1; +} + +static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + struct aim_userinfo_s *userinfo; + char *msg; + char tmpbuf[1152]; + + va_start(ap, fr); + userinfo = va_arg(ap, struct aim_userinfo_s *); + msg = va_arg(ap, char *); + va_end(ap); + + dvprintf("faimtest: chat: %s: incoming msg from %s: %s\n", (char *)fr->conn->priv, userinfo->sn, msg); + + /* + * Do an echo for testing purposes. But not for ourselves ("oops!") + */ + if (strcmp(userinfo->sn, sess->sn) != 0) { + sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); + aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf)); + } + + return 1; +} + +static int faimtest_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...) +{ + fu16_t type; + va_list ap; + + va_start(ap, fr); + type = va_arg(ap, fu16_t); + + if (type == 0x0002) { + int maxrooms; + struct aim_chat_exchangeinfo *exchanges; + int exchangecount, i; + + maxrooms = va_arg(ap, int); + exchangecount = va_arg(ap, int); + exchanges = va_arg(ap, struct aim_chat_exchangeinfo *); + va_end(ap); + + dprintf("faimtest: chat info: Chat Rights:\n"); + dvprintf("faimtest: chat info: \tMax Concurrent Rooms: %d\n", maxrooms); + + dvprintf("faimtest: chat info: \tExchange List: (%d total)\n", exchangecount); + for (i = 0; i < exchangecount; i++) { + dvprintf("faimtest: chat info: \t\t%x: %s (%s/%s)\n", + exchanges[i].number, + exchanges[i].name, + exchanges[i].charset1, + exchanges[i].lang1); + } + + } else if (type == 0x0008) { + char *fqcn, *name, *ck; + fu16_t instance, flags, maxmsglen, maxoccupancy, unknown, exchange; + fu8_t createperms; + fu32_t createtime; + + fqcn = va_arg(ap, char *); + instance = va_arg(ap, fu16_t); + exchange = va_arg(ap, fu16_t); + flags = va_arg(ap, fu16_t); + createtime = va_arg(ap, fu32_t); + maxmsglen = va_arg(ap, fu16_t); + maxoccupancy = va_arg(ap, fu16_t); + createperms = va_arg(ap, fu8_t); + unknown = va_arg(ap, fu16_t); + name = va_arg(ap, char *); + ck = va_arg(ap, char *); + va_end(ap); + + dvprintf("faimtest: received room create reply for %s/0x%04x\n", fqcn, exchange); + + } else { + va_end(ap); + dvprintf("faimtest: chatnav info: unknown type (%04x)\n", type); + } + + return 1; +} + +static int chat_serverready(aim_session_t *sess, aim_frame_t *fr, ...) +{ + int famcount, i; + fu16_t *families; + va_list ap; + + va_start(ap, fr); + famcount = va_arg(ap, int); + families = va_arg(ap, fu16_t *); + va_end(ap); + + dvprintf("chat: SNAC families supported by this host (type %d): ", fr->conn->type); + for (i = 0; i < famcount; i++) + dvinlineprintf("0x%04x ", families[i]); + dinlineprintf("\n"); + + if (fr->conn->type == AIM_CONN_TYPE_CHATNAV) { + + dprintf("chatnav got server ready\n"); + + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0); + aim_bos_reqrate(sess, fr->conn); + aim_bos_ackrateresp(sess, fr->conn); + aim_chatnav_clientready(sess, fr->conn); + aim_chatnav_reqrights(sess, fr->conn); + + } else if (fr->conn->type == AIM_CONN_TYPE_CHAT) { + + dprintf("chat got server ready\n"); + + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0); + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0); + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0); + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0); + aim_bos_reqrate(sess, fr->conn); + aim_bos_ackrateresp(sess, fr->conn); + aim_chat_clientready(sess, fr->conn); + } + + return 1; +} + +void chatnav_redirect(aim_session_t *sess, const char *ip, const fu8_t *cookie) +{ + aim_conn_t *tstconn; + + tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, ip); + if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) { + dprintf("faimtest: unable to connect to chat(nav) server\n"); + if (tstconn) + aim_conn_kill(sess, &tstconn); + return; + } + + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, chat_serverready, 0); + aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); + aim_auth_sendcookie(sess, tstconn, cookie); + + dprintf("chatnav: connected\n"); + + return; +} + +/* XXX this needs instance too */ +void chat_redirect(aim_session_t *sess, const char *ip, const fu8_t *cookie, const char *roomname, fu16_t exchange) +{ + aim_conn_t *tstconn; + + tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, ip); + if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) { + dprintf("faimtest: unable to connect to chat server\n"); + if (tstconn) + aim_conn_kill(sess, &tstconn); + return; + } + dvprintf("faimtest: chat: connected to %s on exchange %d\n", roomname, exchange); + + /* + * We must do this to attach the stored name to the connection! + */ + aim_chat_attachname(tstconn, roomname); + + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, chat_serverready, 0); + aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); + aim_auth_sendcookie(sess, tstconn, cookie); + + return; +} + + + diff --git a/utils/faimtest/commands.c b/utils/faimtest/commands.c index ec57c82..2cad4de 100644 --- a/utils/faimtest/commands.c +++ b/utils/faimtest/commands.c @@ -14,269 +14,271 @@ static int cmd_anonwarn(char *arg); static int cmd_sendmsg(char *arg); struct { - char *name; - Function *func; - char *doc; + char *name; + Function *func; + char *doc; } cmdlist[] = { - { "help", cmd_help, "Help"}, - { "quit", cmd_quit, "Quit"}, - { "login", cmd_login, "Log into AIM"}, - { "logout", cmd_logout, "Log out of AIM"}, - { "connlist", cmd_connlist, "List open connections"}, - { "goodday", cmd_goodday, "Say goodday to arg"}, - { "warn", cmd_warn, "Warn arg"}, - { "anonwarn", cmd_anonwarn, "Anonymously warn arg"}, - { "sendmsg", cmd_sendmsg, "Send arg[0] bytes to arg[1]"}, - { (char *)NULL, (Function *)NULL, (char *)NULL } + { "help", cmd_help, "Help"}, + { "quit", cmd_quit, "Quit"}, + { "login", cmd_login, "Log into AIM"}, + { "logout", cmd_logout, "Log out of AIM"}, + { "connlist", cmd_connlist, "List open connections"}, + { "goodday", cmd_goodday, "Say goodday to arg"}, + { "warn", cmd_warn, "Warn arg"}, + { "anonwarn", cmd_anonwarn, "Anonymously warn arg"}, + { "sendmsg", cmd_sendmsg, "Send arg[0] bytes to arg[1]"}, + { (char *)NULL, (Function *)NULL, (char *)NULL } }; -static char *stripwhite (char *string) +static char *stripwhite(char *string) { - char *s, *t; + char *s, *t; - for (s = string; whitespace(*s); s++) - ; + for (s = string; whitespace(*s); s++) + ; - if (*s == 0) - return (s); + if (*s == 0) + return (s); - t = s + strlen (s) - 1; - while (t > s && whitespace (*t)) - t--; - *++t = '\0'; + t = s + strlen (s) - 1; + while (t > s && whitespace (*t)) + t--; + *++t = '\0'; - return s; + return s; } static char *cmdgenerator(const char *text, int state) { - static int list_index, len; - char *name; - - if (!state) { - list_index = 0; - len = strlen (text); - } - - while ((name = cmdlist[list_index].name)) { - list_index++; - if (strncmp (name, text, len) == 0) - return (strdup(name)); - } - - /* If no names matched, then return NULL. */ - return (char *)NULL; + static int list_index, len; + char *name; + + if (!state) { + list_index = 0; + len = strlen (text); + } + + while ((name = cmdlist[list_index].name)) { + list_index++; + if (strncmp (name, text, len) == 0) + return (strdup(name)); + } + + /* If no names matched, then return NULL. */ + return (char *)NULL; } static char **cmdcomplete(const char *text, int start, int end) { - char **matches; + char **matches; - matches = (char **)NULL; + matches = (char **)NULL; - /* - * If this word is at the start of the line, then it is a command - * to complete. Otherwise it is the name of a file in the current - * directory. - */ - if (start == 0) - matches = completion_matches(text, cmdgenerator); + /* + * If this word is at the start of the line, then it is a command + * to complete. Otherwise it is the name of a file in the current + * directory. + */ + if (start == 0) + matches = completion_matches(text, cmdgenerator); - return matches; + return matches; } static Function *cmdfind(char *name) { - int i; + int i; - for (i = 0; cmdlist[i].name; i++) - if (strcmp (name, cmdlist[i].name) == 0) - return cmdlist[i].func; + for (i = 0; cmdlist[i].name; i++) { + if (strcmp (name, cmdlist[i].name) == 0) + return cmdlist[i].func; + } - return NULL; + return NULL; } static int cmdexec(char *line) { - int i; - Function *cmd; - char *word; - - /* Isolate the command word. */ - i = 0; - while (line[i] && whitespace (line[i])) - i++; - word = line + i; - - while (line[i] && !whitespace (line[i])) - i++; - - if (line[i]) - line[i++] = '\0'; - - if (!(cmd = cmdfind(word))) { - fprintf(stderr, "%s: invalid command\n", word); - return -1; - } - /* Get argument to command, if any. */ - while (whitespace (line[i])) - i++; - - word = line + i; - - /* Call the function. */ - return cmd(word); + int i; + Function *cmd; + char *word; + + /* Isolate the command word. */ + i = 0; + while (line[i] && whitespace (line[i])) + i++; + word = line + i; + + while (line[i] && !whitespace (line[i])) + i++; + + if (line[i]) + line[i++] = '\0'; + + if (!(cmd = cmdfind(word))) { + fprintf(stderr, "%s: invalid command\n", word); + return -1; + } + /* Get argument to command, if any. */ + while (whitespace (line[i])) + i++; + + word = line + i; + + /* Call the function. */ + return cmd(word); } static void fullline(char *x) { - char *stripped; + char *stripped; - stripped = stripwhite(rl_line_buffer); + stripped = stripwhite(rl_line_buffer); - if (*stripped) { - add_history(stripped); - cmdexec(stripped); - } + if (*stripped) { + add_history(stripped); + cmdexec(stripped); + } - return; + return; } void cmd_init(void) { - rl_attempted_completion_function = cmdcomplete; + rl_attempted_completion_function = cmdcomplete; - printf("Welcome to faimtest.\n"); + printf("Welcome to faimtest.\n"); - rl_callback_handler_install("faimtest> ", fullline); + rl_callback_handler_install("faimtest> ", fullline); - return; + return; } void cmd_gotkey(void) { - rl_callback_read_char(); + rl_callback_read_char(); - return; + return; } static int cmd_help(char *arg) { - int i; + int i; - for (i = 0; cmdlist[i].name; i++) - printf("%16s\t\t%s\n", cmdlist[i].name, cmdlist[i].doc); + for (i = 0; cmdlist[i].name; i++) + printf("%16s\t\t%s\n", cmdlist[i].name, cmdlist[i].doc); - return 0; + return 0; } static int cmd_quit(char *arg) { - keepgoing = 0; + keepgoing = 0; - return 0; + return 0; } static int cmd_login(char *arg) { - char *sn = NULL, *passwd = NULL; + char *sn = NULL, *passwd = NULL; - if (arg) { - sn = arg; - if ((passwd = index(sn, ' '))) { - *(passwd) = '\0'; - passwd++; - } - } + if (arg) { + sn = arg; + if ((passwd = index(sn, ' '))) { + *(passwd) = '\0'; + passwd++; + } + } - if (login(sn, passwd) != 0) - printf("login failed\n"); + if (login(&aimsess, sn, passwd) != 0) + printf("login failed\n"); - return 0; + return 0; } static int cmd_logout(char *arg) { - logout(); + logout(&aimsess); - return 0; + return 0; } static int cmd_connlist(char *arg) { - struct aim_conn_t *cur; + aim_conn_t *cur; - printf("Open connections:\n"); - for (cur = aimsess.connlist; cur; cur = cur->next) { - printf(" fd=%d type=0x%02x\n", cur->fd, cur->type); - } + printf("Open connections:\n"); + for (cur = aimsess.connlist; cur; cur = cur->next) + printf(" fd=%d type=0x%02x\n", cur->fd, cur->type); - return 0; + return 0; } static int cmd_goodday(char *arg) { - if (arg && strlen(arg) && (strlen(arg) < MAXSNLEN)) - aim_send_im(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), arg, AIM_IMFLAGS_ACK, "Good day to you too."); - else - printf("no one to say hello to!\n"); + if (arg && strlen(arg) && (strlen(arg) < MAXSNLEN)) + aim_send_im(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), arg, AIM_IMFLAGS_ACK, "Good day to you too."); + else + printf("no one to say hello to!\n"); - return 0; + return 0; } static int cmd_warn(char *arg) { - if (arg && strlen(arg) && (strlen(arg) < MAXSNLEN)) - aim_send_warning(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), arg, 0); - else - printf("no one to warn!\n"); + if (arg && strlen(arg) && (strlen(arg) < MAXSNLEN)) + aim_send_warning(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), arg, 0); + else + printf("no one to warn!\n"); - return 0; + return 0; } static int cmd_anonwarn(char *arg) { - if (arg && strlen(arg) && (strlen(arg) < MAXSNLEN)) - aim_send_warning(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), arg, AIM_WARN_ANON); - else - printf("no one to anonwarn!\n"); + if (arg && strlen(arg) && (strlen(arg) < MAXSNLEN)) + aim_send_warning(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), arg, AIM_WARN_ANON); + else + printf("no one to anonwarn!\n"); - return 0; + return 0; } static int cmd_sendmsg(char *arg) { - int len = 0, z; - char sn[MAXSNLEN+1], *newbuf = NULL; + int len = 0, z; + char sn[MAXSNLEN+1], *newbuf = NULL; - if ((sscanf(arg, "%d %32s", &len, sn) != 2) || - (len >= 10000) || (strlen(sn) > MAXSNLEN)) { - printf("invalid args\n"); - return 0; - } + if ((sscanf(arg, "%d %32s", &len, sn) != 2) || + (len >= 10000) || (strlen(sn) > MAXSNLEN)) { + printf("invalid args\n"); + return 0; + } - printf("sending %d bytes to %s\n", len, sn); + printf("sending %d bytes to %s\n", len, sn); - if (!(newbuf = malloc(len+1))) - return 0; + if (!(newbuf = malloc(len+1))) + return 0; - for (z = 0; z < len; z++) - newbuf[z] = (z % 10)+0x30; - newbuf[len] = '\0'; + for (z = 0; z < len; z++) + newbuf[z] = (z % 10)+0x30; + newbuf[len] = '\0'; - aim_send_im(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), sn, AIM_IMFLAGS_ACK, newbuf); + aim_send_im(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), sn, AIM_IMFLAGS_ACK, newbuf); - free(newbuf); + free(newbuf); - return 0; + return 0; } void cmd_uninit(void) { - rl_callback_handler_remove(); + rl_callback_handler_remove(); - return; + return; } + + diff --git a/utils/faimtest/faimtest.c b/utils/faimtest/faimtest.c index 0c8264a..2ad710b 100644 --- a/utils/faimtest/faimtest.c +++ b/utils/faimtest/faimtest.c @@ -1,172 +1,83 @@ /* - * ----------------------------------------------------------- - * ProtoFAIM: v1.xx.xxplxx - * ----------------------------------------------------------- + * faimtest. * - * This is ProtoFAIM v1.xx.xxplxx!!! Its nearly completely - * different than that ugly thing called v0. This app is - * compatible with the latest version of the libfaim library. - * Work is continuing. + * The point of faimtest is twofold: + * - Test the functionality of libfaim. + * - Demonstrate the functionality of libfaim and how to use it. * - * ProtoFAIM should only be used for two things... - * 1) Testing the libfaim backend. - * 2) For reference on the libfaim API when developing clients. - * - * Its very ugly. Probably always will be. Nothing is more - * ugly than the backend itself, however. + * It does the latter rather badly, and the first as best it can without a + * more realistic UI. libfaim has a slightly different event model than + * many C programmers are used to, which is why I provide faimtest as + * documentation instead of attempting to explain how it works in English. + * If you're still in need of more guidance, see the source for the OSCAR + * "plugin" in gaim. It does it nicely, and in a realistic situation. (Did + * I mention faimtest is a bit idealized?) * - * ----------------------------------------------------------- + * The faimtest code is very ugly. Probably always will be. * - * I'm releasing this code and all it's associated linkage - * under the GNU General Public License. For more information, - * please refer to http://www.fsf.org. For any questions, - * please contact me at the address below. - * - * Most everything: - * (c) 1998 Adam Fritzler, PST, mid@zigamoprh.net - * - * The password algorithms - * (c) 1998 Brock Wilcox, awwaiid@zigamorph.net - * - * THERE IS NO CODE FROM AOL'S AIM IN THIS CODE, NOR - * WAS THERE ANY DISASSEMBLAGE TO DEFINE PROTOCOL. All - * information was gained through painstakingly comparing - * TCP dumps while the AIM Java client was running. Nothing - * more than that, except for a lot of experimenting. - * - * ----------------------------------------------------------- + * Note that faimtest does not do a lot of error checking, except perhaps + * on some libfaim funtions. This is done for clarity, in hopes of + * making this crap ever so slighly more readable. * */ #include "faimtest.h" #include -static char *dprintf_ctime(void) +char *dprintf_ctime(void) { - static char retbuf[64]; - struct tm *lt; - struct timeval tv; - struct timezone tz; - - gettimeofday(&tv, &tz); - lt = localtime((time_t *)&tv.tv_sec); - strftime(retbuf, 64, "%a %b %e %H:%M:%S %Z %Y", lt); - return retbuf; -} + static char retbuf[64]; + struct tm *lt; + struct timeval tv; + struct timezone tz; -#define DPRINTF_OUTSTREAM stdout -#define dprintf(x) { \ - fprintf(DPRINTF_OUTSTREAM, "%s %s: " x, dprintf_ctime(), "faimtest"); \ - fflush(DPRINTF_OUTSTREAM); \ -} -#define dvprintf(x, y...) { \ - fprintf(DPRINTF_OUTSTREAM, "%s %s: " x, dprintf_ctime(), "faimtest", y); \ - fflush(DPRINTF_OUTSTREAM); \ -} -#define dinlineprintf(x) { \ - fprintf(DPRINTF_OUTSTREAM, x); \ - fflush(DPRINTF_OUTSTREAM); \ -} -#define dvinlineprintf(x, y...) { \ - fprintf(DPRINTF_OUTSTREAM, x, y); \ - fflush(DPRINTF_OUTSTREAM); \ + gettimeofday(&tv, &tz); + lt = localtime((time_t *)&tv.tv_sec); + strftime(retbuf, 64, "%a %b %e %H:%M:%S %Z %Y", lt); + + return retbuf; } -#define dperror(x) dvprintf("%s: %s\n", x, strerror(errno)); - -int faimtest_parse_oncoming(struct aim_session_t *, struct command_rx_struct *, ...); -int faimtest_parse_offgoing(struct aim_session_t *, struct command_rx_struct *, ...); -int faimtest_parse_login_phase3d_f(struct aim_session_t *, struct command_rx_struct *, ...); -static int faimtest_parse_authresp(struct aim_session_t *, struct command_rx_struct *, ...); -int faimtest_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *command, ...); -int faimtest_parse_userinfo(struct aim_session_t *, struct command_rx_struct *command, ...); -int faimtest_handleredirect(struct aim_session_t *, struct command_rx_struct *command, ...); -int faimtest_infochange(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_serverready(struct aim_session_t *, struct command_rx_struct *command, ...); -int faimtest_hostversions(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_parse_misses(struct aim_session_t *, struct command_rx_struct *command, ...); -int faimtest_parse_msgack(struct aim_session_t *, struct command_rx_struct *command, ...); -int faimtest_parse_motd(struct aim_session_t *, struct command_rx_struct *command, ...); -int faimtest_parse_login(struct aim_session_t *, struct command_rx_struct *command, ...); -int faimtest_chatnav_info(struct aim_session_t *, struct command_rx_struct *command, ...); -int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...); - -int faimtest_directim_request(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_directim_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...); - -int faimtest_getfile_filereq(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_getfile_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_getfile_listing(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_getfile_listingreq(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_getfile_receive(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_getfile_state4(struct aim_session_t *sess, struct command_rx_struct *command, ...); - -int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...); -int faimtest_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...); static char *msgerrreasons[] = { - "Invalid error", - "Invalid SNAC", - "Rate to host", - "Rate to client", - "Not logged on", - "Service unavailable", - "Service not defined", - "Obsolete SNAC", - "Not supported by host", - "Not supported by client", - "Refused by client", - "Reply too big", - "Responses lost", - "Request denied", - "Busted SNAC payload", - "Insufficient rights", - "In local permit/deny", - "Too evil (sender)", - "Too evil (receiver)", - "User temporarily unavailable", - "No match", - "List overflow", - "Request ambiguous", - "Queue full", - "Not while on AOL"}; + "Invalid error", + "Invalid SNAC", + "Rate to host", + "Rate to client", + "Not logged on", + "Service unavailable", + "Service not defined", + "Obsolete SNAC", + "Not supported by host", + "Not supported by client", + "Refused by client", + "Reply too big", + "Responses lost", + "Request denied", + "Busted SNAC payload", + "Insufficient rights", + "In local permit/deny", + "Too evil (sender)", + "Too evil (receiver)", + "User temporarily unavailable", + "No match", + "List overflow", + "Request ambiguous", + "Queue full", + "Not while on AOL", +}; static int msgerrreasonslen = 25; -static char *aimbinarypath = NULL; -static char *screenname,*password,*server=NULL; -static char *proxy = NULL, *proxyusername = NULL, *proxypass = NULL; -static char *ohcaptainmycaptain = NULL; -static int connected = 0; - -struct aim_session_t aimsess; +aim_session_t aimsess; int keepgoing = 1; -static FILE *listingfile; -static char *listingpath; - -static unsigned char *buddyicon = NULL; -static int buddyiconlen = 0; -static time_t buddyiconstamp = 0; -static unsigned short buddyiconsum = 0; - -static void faimtest_debugcb(struct aim_session_t *sess, int level, const char *format, va_list va) +/* + * This is used to intercept debugging/diagnostic messages from libfaim. + * + * Note that you should have one of these even if you use a debuglevel of + * zero, as libfaim will send serious errors to stderr by default. + * + */ +static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va) { vfprintf(stderr, format, va); @@ -174,47 +85,20 @@ static void faimtest_debugcb(struct aim_session_t *sess, int level, const char * return; } -int faimtest_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - unsigned short interval = 0; - - va_start(ap, command); - interval = va_arg(ap, int); - va_end(ap); - - dvprintf("aim: minimum report interval: %d (seconds?)\n", interval); - - if (!connected) - connected++; - -#if 0 - aim_bos_reqservice(sess, command->conn, 0x0005); /* adverts */ - aim_bos_reqservice(sess, command->conn, 0x000f); /* user directory */ - - /* Don't know what this does... */ - /* XXX sess->sn should be normalized by the 0001/000f handler */ - aim_0002_000b(sess, command->conn, sess->sn); -#endif - - aim_reqicbmparams(sess, command->conn); - - return 1; -} - -int faimtest_flapversion(struct aim_session_t *sess, struct command_rx_struct *command, ...) +int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...) { - dvprintf("faimtest: using FLAP version %u\n", aimutil_get32(command->data)); + /* XXX fix libfaim to support this */ + dvprintf("using FLAP version 0x%08x\n", /* aimutil_get32(fr->data)*/ 0xffffffff); #if 0 /* * This is an alternate location for starting the login process. */ /* XXX should do more checking to make sure its really the right AUTH conn */ - if (command->conn->type == AIM_CONN_TYPE_AUTH) { + if (fr->conn->type == AIM_CONN_TYPE_AUTH) { /* do NOT send a flapversion, request_login will send it if needed */ - aim_request_login(sess, command->conn, screenname); + aim_request_login(sess, fr->conn, priv->screenname); dprintf("faimtest: login request sent\n"); } #endif @@ -230,13 +114,13 @@ int faimtest_flapversion(struct aim_session_t *sess, struct command_rx_struct *c * will be queued and then transmitted when the connection completes. * */ -int faimtest_conncomplete(struct aim_session_t *sess, struct command_rx_struct *command, ...) +int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - struct aim_conn_t *conn; + aim_conn_t *conn; - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); + va_start(ap, fr); + conn = va_arg(ap, aim_conn_t *); va_end(ap); if (conn) @@ -250,9 +134,9 @@ int faimtest_conncomplete(struct aim_session_t *sess, struct command_rx_struct * * This is really all thats needed to link against libfaim on win32. * * Note that this particular version of faimtest has never been tested - * on win32, but I'm fairly sure it should. + * on win32, but I'm fairly sure it should work. */ -int initwsa(void) +static int initwsa(void) { WORD wVersionRequested; WSADATA wsaData; @@ -262,9 +146,12 @@ int initwsa(void) } #endif /* _WIN32 */ +/* + * This is unrealistic. Most clients will not be able to do this. + */ int faimtest_init(void) { - struct aim_conn_t *stdinconn = NULL; + aim_conn_t *stdinconn = NULL; if (!(stdinconn = aim_newconn(&aimsess, 0, NULL))) { dprintf("unable to create connection for stdin!\n"); @@ -276,96 +163,45 @@ int faimtest_init(void) return 0; } -int logout(void) -{ - - if (ohcaptainmycaptain) - aim_send_im(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), ohcaptainmycaptain, 0, "ta ta..."); - - aim_session_kill(&aimsess); - - if (faimtest_init() == -1) - dprintf("faimtest_init failed\n"); - - return 0; -} - -int login(const char *sn, const char *passwd) -{ - struct aim_conn_t *authconn; - - if (sn) - screenname = strdup(sn); - if (passwd) - password = strdup(passwd); - - if (proxy) - aim_setupproxy(&aimsess, proxy, proxyusername, proxypass); - - if (!screenname || !password) { - dprintf("need SN and password\n"); - return -1; - } - - if (!(authconn = aim_newconn(&aimsess, AIM_CONN_TYPE_AUTH, server?server:FAIM_LOGIN_SERVER))) { - dprintf("faimtest: internal connection error while in aim_login. bailing out.\n"); - return -1; - } else if (authconn->fd == -1) { - if (authconn->status & AIM_CONN_STATUS_RESOLVERR) { - dprintf("faimtest: could not resolve authorizer name\n"); - } else if (authconn->status & AIM_CONN_STATUS_CONNERR) { - dprintf("faimtest: could not connect to authorizer\n"); - } - aim_conn_kill(&aimsess, &authconn); - return -1; - } - - aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0); - aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); - aim_conn_addhandler(&aimsess, authconn, 0x0017, 0x0007, faimtest_parse_login, 0); - aim_conn_addhandler(&aimsess, authconn, 0x0017, 0x0003, faimtest_parse_authresp, 0); - - aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT, faimtest_debugconn_connect, 0); - - /* If the connection is in progress, this will just be queued */ - aim_request_login(&aimsess, authconn, screenname); - dprintf("faimtest: login request sent\n"); - - return 0; -} - int main(int argc, char **argv) { - struct aim_conn_t *waitingconn = NULL; + aim_conn_t *waitingconn = NULL; int i; int selstat = 0; static int faimtest_mode = 0; struct timeval tv; time_t lastnop = 0; const char *buddyiconpath = NULL; + struct faimtest_priv priv = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + 0, + NULL, NULL, + NULL, 0, 0, 0 + }; - screenname = getenv("SCREENNAME"); - password = getenv("PASSWORD"); - server = getenv("AUTHSERVER"); - proxy = getenv("SOCKSPROXY"); - proxyusername = getenv("SOCKSNAME"); - proxypass = getenv("SOCKSPASS"); + priv.screenname = getenv("SCREENNAME"); + priv.password = getenv("PASSWORD"); + priv.server = getenv("AUTHSERVER"); + priv.proxy = getenv("SOCKSPROXY"); + priv.proxyusername = getenv("SOCKSNAME"); + priv.proxypass = getenv("SOCKSPASS"); - listingpath = getenv("LISTINGPATH"); + priv.listingpath = getenv("LISTINGPATH"); while ((i = getopt(argc, argv, "u:p:a:U:P:A:l:c:hoOb:i:")) != EOF) { switch (i) { - case 'u': screenname = optarg; break; - case 'p': password = optarg; break; - case 'a': server = optarg; break; - case 'U': proxyusername = optarg; break; - case 'P': proxypass = optarg; break; - case 'A': proxy = optarg; break; - case 'l': listingpath = optarg; break; - case 'c': ohcaptainmycaptain = optarg; break; + case 'u': priv.screenname = optarg; break; + case 'p': priv.password = optarg; break; + case 'a': priv.server = optarg; break; + case 'U': priv.proxyusername = optarg; break; + case 'P': priv.proxypass = optarg; break; + case 'A': priv.proxy = optarg; break; + case 'l': priv.listingpath = optarg; break; + case 'c': priv.ohcaptainmycaptain = optarg; break; case 'o': faimtest_mode = 1; break; /* half old interface */ case 'O': faimtest_mode = 2; break; /* full old interface */ - case 'b': aimbinarypath = optarg; break; + case 'b': priv.aimbinarypath = optarg; break; case 'i': buddyiconpath = optarg; break; case 'h': default: @@ -397,18 +233,15 @@ int main(int argc, char **argv) /* Pass zero as flags if you want blocking connects */ aim_session_init(&aimsess, AIM_SESS_FLAGS_NONBLOCKCONNECT, 1); aim_setdebuggingcb(&aimsess, faimtest_debugcb); /* still needed even if debuglevel = 0 ! */ + aimsess.aux_data = &priv; - if (listingpath) { + if (priv.listingpath) { char *listingname; - if (!(listingname = (char *)calloc(1, strlen(listingpath)+strlen("/listing.txt")))) { - dperror("listingname calloc"); - exit(-1); - } - - sprintf(listingname, "%s/listing.txt", listingpath); + listingname = (char *)calloc(1, strlen(priv.listingpath)+strlen("/listing.txt")); + sprintf(listingname, "%s/listing.txt", priv.listingpath); - if ((listingfile = fopen(listingname, "r")) == NULL) + if ((priv.listingfile = fopen(listingname, "r")) == NULL) dvprintf("Couldn't open %s... disabling that shit.\n", listingname); free(listingname); @@ -420,14 +253,14 @@ int main(int argc, char **argv) if ((stat(buddyiconpath, &st) != -1) && (st.st_size <= MAXICONLEN) && (f = fopen(buddyiconpath, "r"))) { - buddyiconlen = st.st_size; - buddyiconstamp = st.st_mtime; - buddyicon = malloc(buddyiconlen); - fread(buddyicon, 1, st.st_size, f); + priv.buddyiconlen = st.st_size; + priv.buddyiconstamp = st.st_mtime; + priv.buddyicon = malloc(priv.buddyiconlen); + fread(priv.buddyicon, 1, st.st_size, f); - buddyiconsum = aim_iconsum(buddyicon, buddyiconlen); + priv.buddyiconsum = aim_iconsum(priv.buddyicon, priv.buddyiconlen); - dvprintf("read %d bytes of %s for buddy icon (sum 0x%08x)\n", buddyiconlen, buddyiconpath, buddyiconsum); + dvprintf("read %d bytes of %s for buddy icon (sum 0x%08x)\n", priv.buddyiconlen, buddyiconpath, priv.buddyiconsum); fclose(f); @@ -442,7 +275,7 @@ int main(int argc, char **argv) cmd_init(); if (faimtest_mode >= 1) { - if (login(screenname, password) == -1) { + if (login(&aimsess, priv.screenname, priv.password) == -1) { if (faimtest_mode < 2) cmd_uninit(); exit(-1); @@ -451,12 +284,13 @@ int main(int argc, char **argv) while (keepgoing) { + /* XXX uh. */ tv.tv_sec = 5; tv.tv_usec = 0; waitingconn = aim_select(&aimsess, &tv, &selstat); - if (connected && ((time(NULL) - lastnop) > 30)) { + if (priv.connected && ((time(NULL) - lastnop) > 30)) { lastnop = time(NULL); aim_flap_nop(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS)); } @@ -472,10 +306,12 @@ int main(int argc, char **argv) cmd_gotkey(); } else { if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { +#if 0 if (aim_handlerendconnect(&aimsess, waitingconn) < 0) { dprintf("connection error (rend out)\n"); aim_conn_kill(&aimsess, &waitingconn); } +#endif } else { if (aim_get_command(&aimsess, waitingconn) >= 0) { aim_rxdispatch(&aimsess); @@ -506,65 +342,229 @@ int main(int argc, char **argv) cmd_uninit(); } - free(buddyicon); + free(priv.buddyicon); /* Get out */ exit(0); } -int faimtest_rateresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) +int faimtest_serverready(aim_session_t *sess, aim_frame_t *fr, ...) { + int famcount, i; + fu16_t *families; + va_list ap; - switch(command->conn->type) { - case AIM_CONN_TYPE_BOS: { - /* this is the new buddy list */ - char buddies[128]; - /* this is the new profile */ - char profile[256]; - char awaymsg[] = {"blah blah blah Ole! blah blah blah"}; + va_start(ap, fr); + famcount = va_arg(ap, int); + families = va_arg(ap, fu16_t *); + va_end(ap); + + dvprintf("faimtest: SNAC families supported by this host (type %d): ", fr->conn->type); + for (i = 0; i < famcount; i++) + dvinlineprintf("0x%04x ", families[i]); + dinlineprintf("\n"); - /* Caution: Buddy1 and Buddy2 are real people! (who I don't know) */ - snprintf(buddies, sizeof(buddies), "Buddy1&Buddy2&%s&", ohcaptainmycaptain?ohcaptainmycaptain:"blah"); - snprintf(profile, sizeof(profile), "Hello.
My captain is %s. They were dumb enough to leave this message in their client, or they are using faimtest. Shame on them.", ohcaptainmycaptain); + if (fr->conn->type == AIM_CONN_TYPE_AUTH) { - aim_bos_ackrateresp(sess, command->conn); /* ack rate info response */ - aim_bos_reqpersonalinfo(sess, command->conn); - aim_bos_reqlocaterights(sess, command->conn); - aim_bos_setprofile(sess, command->conn, profile, awaymsg, AIM_CAPS_BUDDYICON | AIM_CAPS_CHAT | AIM_CAPS_GETFILE | AIM_CAPS_SENDFILE | AIM_CAPS_IMIMAGE /*| AIM_CAPS_GAMES | AIM_CAPS_SAVESTOCKS*/); - aim_bos_reqbuddyrights(sess, command->conn); + aim_auth_setversions(sess, fr->conn); + aim_bos_reqrate(sess, fr->conn); /* request rate info */ - /* send the buddy list and profile (required, even if empty) */ - aim_bos_setbuddylist(sess, command->conn, buddies); + dprintf("done with auth server ready\n"); - aim_reqicbmparams(sess, command->conn); + } else if (fr->conn->type == AIM_CONN_TYPE_BOS) { - aim_bos_reqrights(sess, command->conn); - /* set group permissions -- all user classes */ - aim_bos_setgroupperm(sess, command->conn, AIM_FLAG_ALLUSERS); - aim_bos_setprivacyflags(sess, command->conn, AIM_PRIVFLAGS_ALLOWIDLE); + aim_setversions(sess, fr->conn); + aim_bos_reqrate(sess, fr->conn); /* request rate info */ - break; + dprintf("done with BOS server ready\n"); } - case AIM_CONN_TYPE_AUTH: - aim_bos_ackrateresp(sess, command->conn); - aim_auth_clientready(sess, command->conn); - dprintf("faimtest: connected to authorization/admin service\n"); - break; - - default: - dvprintf("faimtest: got rate response for unhandled connection type %04x\n", command->conn->type); - break; + + return 1; +} + +int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...) +{ + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + va_list ap; + fu16_t code; + char *msg; + + va_start(ap, fr); + code = va_arg(ap, int); + msg = va_arg(ap, char *); + va_end(ap); + + dvprintf("connerr: Code 0x%04x: %s\n", code, msg); + aim_conn_kill(sess, &fr->conn); /* this will break the main loop */ + + priv->connected = 0; + + return 1; +} + +#if 0 +static int faimtest_rateresp_auth(aim_session_t *sess, aim_frame_t *fr, ...) +{ + + aim_bos_ackrateresp(sess, fr->conn); + aim_auth_clientready(sess, fr->conn); + + dprintf("faimtest: connected to authorization/admin service\n"); + + return 1; +} + +int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...) +{ + int status; + va_list ap; + + va_start(ap, fr); + status = va_arg(ap, int); /* status code of confirmation request */ + va_end(ap); + + dvprintf("account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown"); + + return 1; +} + + +#endif + +#if 0 +/* + * This kind of function is really not legal in the new bstream way... + * In fact, clients should never access the aim_frame_t directly in handlers, + * since that may leave it in a bizare state for the lower layers. In fact, + * clients should probably not even get passed a pointer like this. + * + */ +int faimtest_parse_unknown(aim_session_t *sess, aim_frame_t *fr, ...) +{ + int i; + + aim_bstream_rewind(&fr->data); /* boo! */ + + dprintf("\nReceived unknown packet:"); + for (i = 0; aim_bstream_empty(&fr->data); i++) { + if ((i % 8) == 0) + dinlineprintf("\n\t"); + dvinlineprintf("0x%2x ", aimbs_get8(&fr->data)); } + dinlineprintf("\n\n"); return 1; } +#endif -static int faimtest_icbmparaminfo(struct aim_session_t *sess, struct command_rx_struct *command, ...) +int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + int serviceid; + char *ip; + fu8_t *cookie; + + va_start(ap, fr); + serviceid = va_arg(ap, int); + ip = va_arg(ap, char *); + cookie = va_arg(ap, fu8_t *); + + if (serviceid == 0x0005) { /* Adverts */ +#if 0 + aim_conn_t *tstconn; + + tstconn = aim_newconn(sess, AIM_CONN_TYPE_ADS, ip); + if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) { + dprintf("faimtest: unable to reconnect with authorizer\n"); + } else { + aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0); + aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0); + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */ + aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0); + aim_auth_sendcookie(sess, tstconn, cookie); + dprintf("sent cookie to adverts host\n"); + } +#endif + } else if (serviceid == 0x0007) { /* Authorizer */ +#if 0 + aim_conn_t *tstconn; + + tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, ip); + if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) { + dprintf("faimtest: unable to reconnect with authorizer\n"); + } else { + aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0); + aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0); + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */ + aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0); + aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0); + aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0); + aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0); + /* Send the cookie to the Auth */ + aim_auth_sendcookie(sess, tstconn, cookie); + dprintf("sent cookie to authorizer host\n"); + } +#endif + } else if (serviceid == 0x000d) { /* ChatNav */ + + chatnav_redirect(sess, ip, cookie); + + } else if (serviceid == 0x000e) { /* Chat */ + char *roomname = NULL; + int exchange; + + roomname = va_arg(ap, char *); + exchange = va_arg(ap, int); + + chat_redirect(sess, ip, cookie, roomname, exchange); + + } else { + dvprintf("uh oh... got redirect for unknown service 0x%04x!!\n", serviceid); + } + + va_end(ap); + + return 1; +} + +static int faimtest_rateresp_bos(aim_session_t *sess, aim_frame_t *fr, ...) +{ + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + char buddies[128]; /* this is the new buddy list */ + char profile[256]; /* this is the new profile */ + char awaymsg[] = {"blah blah blah Ole! blah blah blah"}; + + /* Caution: Buddy1 and Buddy2 are real people! (who I don't know) */ + snprintf(buddies, sizeof(buddies), "Buddy1&Buddy2&%s&", priv->ohcaptainmycaptain ? priv->ohcaptainmycaptain : "blah"); + snprintf(profile, sizeof(profile), "Hello.
My captain is %s. They were dumb enough to leave this message in their client, or they are using faimtest. Shame on them.", priv->ohcaptainmycaptain); + + aim_bos_ackrateresp(sess, fr->conn); /* ack rate info response */ + aim_bos_reqpersonalinfo(sess, fr->conn); + aim_bos_reqlocaterights(sess, fr->conn); + aim_bos_setprofile(sess, fr->conn, profile, awaymsg, AIM_CAPS_BUDDYICON | AIM_CAPS_CHAT | AIM_CAPS_GETFILE | AIM_CAPS_SENDFILE | AIM_CAPS_IMIMAGE /*| AIM_CAPS_GAMES | AIM_CAPS_SAVESTOCKS*/); + aim_bos_reqbuddyrights(sess, fr->conn); + + /* send the buddy list and profile (required, even if empty) */ + aim_bos_setbuddylist(sess, fr->conn, buddies); + + aim_reqicbmparams(sess, fr->conn); + + aim_bos_reqrights(sess, fr->conn); + /* set group permissions -- all user classes */ + aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS); + aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE); + + return 1; +} + +static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...) { struct aim_icbmparameters *params; va_list ap; - va_start(ap, command); + va_start(ap, fr); params = va_arg(ap, struct aim_icbmparameters *); va_end(ap); @@ -579,20 +579,20 @@ static int faimtest_icbmparaminfo(struct aim_session_t *sess, struct command_rx_ params->maxmsglen = 8000; params->minmsginterval = 0; /* in milliseconds */ - aim_seticbmparam(sess, command->conn, params); + aim_seticbmparam(sess, fr->conn, params); return 1; } -int faimtest_hostversions(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_hostversions(aim_session_t *sess, aim_frame_t *fr, ...) { int vercount, i; - unsigned char *versions; + fu8_t *versions; va_list ap; - va_start(ap, command); + va_start(ap, fr); vercount = va_arg(ap, int); /* number of family/version pairs */ - versions = va_arg(ap, unsigned char *); + versions = va_arg(ap, fu8_t *); va_end(ap); dprintf("faimtest: SNAC versions supported by this host: "); @@ -606,264 +606,105 @@ int faimtest_hostversions(struct aim_session_t *sess, struct command_rx_struct * return 1; } -int faimtest_accountconfirm(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...) { - int status; va_list ap; + fu16_t maxbuddies, maxwatchers; - va_start(ap, command); - status = va_arg(ap, int); /* status code of confirmation request */ + va_start(ap, fr); + maxbuddies = va_arg(ap, int); + maxwatchers = va_arg(ap, int); va_end(ap); - dvprintf("account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown"); + dvprintf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers); return 1; } -int faimtest_serverready(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...) { - int famcount, i; - unsigned short *families; - va_list ap; - - va_start(ap, command); - famcount = va_arg(ap, int); - families = va_arg(ap, unsigned short *); - va_end(ap); - - dvprintf("faimtest: SNAC families supported by this host (type %d): ", command->conn->type); - for (i = 0; i < famcount; i++) - dvinlineprintf("0x%04x ", families[i]); - dinlineprintf("\n"); - - switch (command->conn->type) { - case AIM_CONN_TYPE_AUTH: - aim_auth_setversions(sess, command->conn); - aim_bos_reqrate(sess, command->conn); /* request rate info */ - - dprintf("faimtest: done with auth ServerReady\n"); - break; - - case AIM_CONN_TYPE_BOS: - - aim_setversions(sess, command->conn); - aim_bos_reqrate(sess, command->conn); /* request rate info */ - - dprintf("faimtest: done with BOS ServerReady\n"); - break; - - case AIM_CONN_TYPE_CHATNAV: - dprintf("faimtest: chatnav: got server ready\n"); - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0); - aim_bos_reqrate(sess, command->conn); - aim_bos_ackrateresp(sess, command->conn); - aim_chatnav_clientready(sess, command->conn); - aim_chatnav_reqrights(sess, command->conn); - - break; - - case AIM_CONN_TYPE_CHAT: - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0); - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0); - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0); - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0); - aim_bos_reqrate(sess, command->conn); - aim_bos_ackrateresp(sess, command->conn); - aim_chat_clientready(sess, command->conn); - break; - - case AIM_CONN_TYPE_RENDEZVOUS: /* empty */ - break; - - default: - dvprintf("faimtest: unknown connection type on Host Online (0x%04x)\n", command->conn->type); - } - - return 1; -} + va_list ap; + fu16_t maxpermits, maxdenies; -int faimtest_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - unsigned short maxbuddies, maxwatchers; + va_start(ap, fr); + maxpermits = va_arg(ap, int); + maxdenies = va_arg(ap, int); + va_end(ap); + + dvprintf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies); - va_start(ap, command); - maxbuddies = va_arg(ap, int); - maxwatchers = va_arg(ap, int); - va_end(ap); + aim_bos_clientready(sess, fr->conn); - dvprintf("faimtest: buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers); + dprintf("officially connected to BOS.\n"); - return 1; + return 1; } -int faimtest_bosrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...) { - unsigned short maxpermits, maxdenies; - va_list ap; - - va_start(ap, command); - maxpermits = va_arg(ap, int); - maxdenies = va_arg(ap, int); - va_end(ap); - - dvprintf("faimtest: BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies); + va_list ap; + fu16_t maxsiglen; - aim_bos_clientready(sess, command->conn); + va_start(ap, fr); + maxsiglen = va_arg(ap, int); + va_end(ap); - dprintf("faimtest: officially connected to BOS.\n"); + dvprintf("locate rights: max signature length = %d\n", maxsiglen); - return 1; + return 1; } -int faimtest_locrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...) { - unsigned short maxsiglen; - va_list ap; + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + va_list ap; + fu16_t interval; - va_start(ap, command); - maxsiglen = va_arg(ap, int); - va_end(ap); + va_start(ap, fr); + interval = va_arg(ap, int); + va_end(ap); - dvprintf("faimtest: locate rights: max signature length = %d\n", maxsiglen); + dvprintf("minimum report interval: %d (seconds?)\n", interval); - return 1; -} + if (!priv->connected) + priv->connected++; -int faimtest_parse_unknown(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - int i = 0; +#if 0 + aim_bos_reqservice(sess, fr->conn, 0x0005); /* adverts */ + aim_bos_reqservice(sess, fr->conn, 0x000f); /* user directory */ - if (!sess || !command) - return 1; + /* Don't know what this does... */ + /* XXX sess->sn should be normalized by the 0001/000f handler */ + aim_0002_000b(sess, fr->conn, sess->sn); +#endif - dprintf("\nReceived unknown packet:"); - for (i = 0; i < command->commandlen; i++) { - if ((i % 8) == 0) - dinlineprintf("\n\t"); - dvinlineprintf("0x%2x ", command->data[i]); - } - dinlineprintf("\n\n"); + aim_reqicbmparams(sess, fr->conn); - return 1; + return 1; } -/* - handleredirect()... - - This, of course, handles Service Redirects from OSCAR. - - Should get passed in the following: - struct command_rx_struct *command - the raw command data - int serviceid - the destination service ID - char *serverip - the IP address of the service's server - char *cookie - the raw auth cookie - */ -int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...) { - va_list ap; - int serviceid; - char *ip; - unsigned char *cookie; - - va_start(ap, command); - serviceid = va_arg(ap, int); - ip = va_arg(ap, char *); - cookie = va_arg(ap, unsigned char *); - - switch(serviceid) { - case 0x0005: { /* Adverts */ - struct aim_conn_t *tstconn; - - tstconn = aim_newconn(sess, AIM_CONN_TYPE_ADS, ip); - if ((tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) { - dprintf("faimtest: unable to reconnect with authorizer\n"); - } else { - aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0); - aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); - aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0); - aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */ - aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0); - aim_auth_sendcookie(sess, tstconn, cookie); - dprintf("sent cookie to adverts host\n"); - } - break; - } - case 0x0007: { /* Authorizer */ - struct aim_conn_t *tstconn; - /* Open a connection to the Auth */ - tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, ip); - if ((tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) { - dprintf("faimtest: unable to reconnect with authorizer\n"); - } else { - aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0); - aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); - aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0); - aim_conn_addhandler(sess, tstconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */ - aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0); - aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0); - aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0); - aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0); - /* Send the cookie to the Auth */ - aim_auth_sendcookie(sess, tstconn, cookie); - dprintf("sent cookie to authorizer host\n"); - } - break; - } - case 0x000d: { /* ChatNav */ - struct aim_conn_t *tstconn = NULL; - tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, ip); - if ( (tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) { - dprintf("faimtest: unable to connect to chatnav server\n"); - if (tstconn) aim_conn_kill(sess, &tstconn); - return 1; - } - - aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0); - aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); - aim_auth_sendcookie(sess, tstconn, cookie); - dprintf("\achatnav: connected\n"); - break; - } - case 0x000e: { /* Chat */ - char *roomname = NULL; - int exchange; - struct aim_conn_t *tstconn = NULL; - - roomname = va_arg(ap, char *); - exchange = va_arg(ap, int); - - tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, ip); - if ( (tstconn==NULL) || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) { - dprintf("faimtest: unable to connect to chat server\n"); - if (tstconn) aim_conn_kill(sess, &tstconn); - return 1; - } - dvprintf("faimtest: chat: connected to %s on exchange %d\n", roomname, exchange); - - /* - * We must do this to attach the stored name to the connection! - */ - aim_chat_attachname(tstconn, roomname); - - aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, faimtest_serverready, 0); - aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); - aim_auth_sendcookie(sess, tstconn, cookie); - - break; - } - default: - dvprintf("uh oh... got redirect for unknown service 0x%04x!!\n", serviceid); - /* dunno */ - } - - va_end(ap); - - return 1; + static char *codes[] = { + "Unknown", + "Mandatory upgrade", + "Advisory upgrade", + "System bulletin", + "Top o' the world!" + }; + static int codeslen = 5; + char *msg; + fu16_t id; + va_list ap; + + va_start(ap, fr); + id = va_arg(ap, int); + msg = va_arg(ap, char *); + va_end(ap); + + dvprintf("motd: %s (%d / %s)\n", msg, id, (id < codeslen)?codes[id]:"unknown"); + + return 1; } /* @@ -886,133 +727,134 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct * module name on an invalid request. * */ -static int getaimdata(unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname) +static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname) { - FILE *f; - static const char defaultmod[] = "aim.exe"; - char *filename = NULL; - struct stat st; - unsigned char *buf; - int invalid = 0; + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + FILE *f; + static const char defaultmod[] = "aim.exe"; + char *filename = NULL; + struct stat st; + unsigned char *buf; + int invalid = 0; + + if (!bufret || !buflenret) + return -1; - if (!bufret || !buflenret) - return -1; + if (modname) { - if (modname) { - - if (!(filename = malloc(strlen(aimbinarypath)+1+strlen(modname)+4+1))) { - dperror("memrequest: malloc"); - return -1; - } - - sprintf(filename, "%s/%s.ocm", aimbinarypath, modname); + if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) { + dperror("memrequest: malloc"); + return -1; + } - } else { - - if (!(filename = malloc(strlen(aimbinarypath)+1+strlen(defaultmod)+1))) { - dperror("memrequest: malloc"); - return -1; - } + sprintf(filename, "%s/%s.ocm", priv->aimbinarypath, modname); - sprintf(filename, "%s/%s", aimbinarypath, defaultmod); + } else { - } + if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) { + dperror("memrequest: malloc"); + return -1; + } - if (stat(filename, &st) == -1) { - if (!modname) { - dperror("memrequest: stat"); - free(filename); - return -1; - } - invalid = 1; - } + sprintf(filename, "%s/%s", priv->aimbinarypath, defaultmod); - if (!invalid) { - if ((offset > st.st_size) || (len > st.st_size)) - invalid = 1; - else if ((st.st_size - offset) < len) - len = st.st_size - offset; - else if ((st.st_size - len) < len) - len = st.st_size - len; - } + } - if (!invalid && len) - len %= 4096; + if (stat(filename, &st) == -1) { + if (!modname) { + dperror("memrequest: stat"); + free(filename); + return -1; + } + invalid = 1; + } - if (invalid) { - int i; + if (!invalid) { + if ((offset > st.st_size) || (len > st.st_size)) + invalid = 1; + else if ((st.st_size - offset) < len) + len = st.st_size - offset; + else if ((st.st_size - len) < len) + len = st.st_size - len; + } - free(filename); /* not needed */ + if (!invalid && len) + len %= 4096; - dvprintf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname); + if (invalid) { + int i; - i = 8; - if (modname) - i += strlen(modname); + free(filename); /* not needed */ - if (!(buf = malloc(i))) - return -1; + dvprintf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname); - i = 0; + i = 8; + if (modname) + i += strlen(modname); - if (modname) { - memcpy(buf, modname, strlen(modname)); - i += strlen(modname); - } + if (!(buf = malloc(i))) + return -1; - /* Damn endianness. This must be little (LSB first) endian. */ - buf[i++] = offset & 0xff; - buf[i++] = (offset >> 8) & 0xff; - buf[i++] = (offset >> 16) & 0xff; - buf[i++] = (offset >> 24) & 0xff; - buf[i++] = len & 0xff; - buf[i++] = (len >> 8) & 0xff; - buf[i++] = (len >> 16) & 0xff; - buf[i++] = (len >> 24) & 0xff; + i = 0; - *bufret = buf; - *buflenret = i; + if (modname) { + memcpy(buf, modname, strlen(modname)); + i += strlen(modname); + } - } else { + /* Damn endianness. This must be little (LSB first) endian. */ + buf[i++] = offset & 0xff; + buf[i++] = (offset >> 8) & 0xff; + buf[i++] = (offset >> 16) & 0xff; + buf[i++] = (offset >> 24) & 0xff; + buf[i++] = len & 0xff; + buf[i++] = (len >> 8) & 0xff; + buf[i++] = (len >> 16) & 0xff; + buf[i++] = (len >> 24) & 0xff; - if (!(buf = malloc(len))) { - free(filename); - return -1; - } + *bufret = buf; + *buflenret = i; - dvprintf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename); + } else { - if (!(f = fopen(filename, "r"))) { - dperror("memrequest: fopen"); - free(filename); - free(buf); - return -1; - } + if (!(buf = malloc(len))) { + free(filename); + return -1; + } - free(filename); + dvprintf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename); - if (fseek(f, offset, SEEK_SET) == -1) { - dperror("memrequest: fseek"); - fclose(f); - free(buf); - return -1; - } + if (!(f = fopen(filename, "r"))) { + dperror("memrequest: fopen"); + free(filename); + free(buf); + return -1; + } - if (fread(buf, len, 1, f) != 1) { - dperror("memrequest: fread"); - fclose(f); - free(buf); - return -1; - } + free(filename); - fclose(f); + if (fseek(f, offset, SEEK_SET) == -1) { + dperror("memrequest: fseek"); + fclose(f); + free(buf); + return -1; + } - *bufret = buf; - *buflenret = len; - - } + if (fread(buf, len, 1, f) != 1) { + dperror("memrequest: fread"); + fclose(f); + free(buf); + return -1; + } - return 0; /* success! */ + fclose(f); + + *bufret = buf; + *buflenret = len; + + } + + return 0; /* success! */ } /* @@ -1022,1129 +864,605 @@ static int getaimdata(unsigned char **bufret, int *buflenret, unsigned long offs * buffer back to libfaim so it can hash the data and send it to AOL for * inspection by the client police. */ -static int faimtest_memrequest(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...) { - va_list ap; - unsigned long offset, len; - char *modname; - unsigned char *buf; - int buflen; - - va_start(ap, command); - offset = va_arg(ap, unsigned long); - len = va_arg(ap, unsigned long); - modname = va_arg(ap, char *); - va_end(ap); + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + va_list ap; + fu32_t offset, len; + char *modname; + unsigned char *buf; + int buflen; + + va_start(ap, fr); + offset = va_arg(ap, fu32_t); + len = va_arg(ap, fu32_t); + modname = va_arg(ap, char *); + va_end(ap); - if (aimbinarypath && (getaimdata(&buf, &buflen, offset, len, modname) == 0)) { + if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) { - aim_sendmemblock(sess, command->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST); + aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST); - free(buf); + free(buf); - } else { + } else { - dvprintf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", aimbinarypath, modname); + dvprintf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname); - aim_sendmemblock(sess, command->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST); + aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST); - } + } - return 1; + return 1; } -static int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static void printuserflags(fu16_t flags) { - va_list ap; - struct aim_conn_t *bosconn = NULL; - char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL; - unsigned char *cookie = NULL; - int errorcode = 0, regstatus = 0; - int latestbuild = 0, latestbetabuild = 0; - char *latestrelease = NULL, *latestbeta = NULL; - char *latestreleaseurl = NULL, *latestbetaurl = NULL; - char *latestreleaseinfo = NULL, *latestbetainfo = NULL; - - va_start(ap, command); - sn = va_arg(ap, char *); - errorcode = va_arg(ap, int); - errurl = va_arg(ap, char *); - regstatus = va_arg(ap, int); - email = va_arg(ap, char *); - bosip = va_arg(ap, char *); - cookie = va_arg(ap, unsigned char *); - - latestrelease = va_arg(ap, char *); - latestbuild = va_arg(ap, int); - latestreleaseurl = va_arg(ap, char *); - latestreleaseinfo = va_arg(ap, char *); - - latestbeta = va_arg(ap, char *); - latestbetabuild = va_arg(ap, int); - latestbetaurl = va_arg(ap, char *); - latestbetainfo = va_arg(ap, char *); - - va_end(ap); - - dvprintf("Screen name: %s\n", sn); - - /* - * Check for error. - */ - if (errorcode || !bosip || !cookie) { - dvprintf("Login Error Code 0x%04x\n", errorcode); - dvprintf("Error URL: %s\n", errurl); - aim_conn_kill(sess, &command->conn); - return 1; - } - - dvprintf("Reg status: %2d\n", regstatus); - dvprintf("Email: %s\n", email); - dvprintf("BOS IP: %s\n", bosip); - - if (latestbeta) - dvprintf("Latest beta version: %s, build %d, at %s (more info at %s)\n", latestbeta, latestbetabuild, latestbetaurl, latestbetainfo); - - if (latestrelease) - dvprintf("Latest released version: %s, build %d, at %s (more info at %s)\n", latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo); - - dprintf("Closing auth connection...\n"); - aim_conn_kill(sess, &command->conn); - if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) { - dprintf("faimtest: could not connect to BOS: internal error\n"); - return 1; - } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) { - dprintf("faimtest: could not connect to BOS\n"); - aim_conn_kill(sess, &bosconn); - return 1; - } - - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); - aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0); - aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, faimtest_rateresp, 0); /* rate info */ - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 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, faimtest_handleredirect, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0); - aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0); - aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, faimtest_locrights, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0); - - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0); - - aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0); - aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0); - aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0); - aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0); - - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0); - aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0); - aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0); - - aim_auth_sendcookie(sess, bosconn, cookie); - - return 1; + if (flags & AIM_FLAG_UNCONFIRMED) + dinlineprintf("UNCONFIRMED "); + if (flags & AIM_FLAG_ADMINISTRATOR) + dinlineprintf("ADMINISTRATOR "); + if (flags & AIM_FLAG_AOL) + dinlineprintf("AOL "); + if (flags & AIM_FLAG_OSCAR_PAY) + dinlineprintf("OSCAR_PAY "); + if (flags & AIM_FLAG_FREE) + dinlineprintf("FREE "); + if (flags & AIM_FLAG_AWAY) + dinlineprintf("AWAY "); + if (flags & AIM_FLAG_UNKNOWN40) + dinlineprintf("ICQ? "); + if (flags & AIM_FLAG_UNKNOWN80) + dinlineprintf("UNKNOWN80 "); + return; } -static void printuserflags(unsigned short flags) +static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...) { - if (flags & AIM_FLAG_UNCONFIRMED) - dinlineprintf("UNCONFIRMED "); - if (flags & AIM_FLAG_ADMINISTRATOR) - dinlineprintf("ADMINISTRATOR "); - if (flags & AIM_FLAG_AOL) - dinlineprintf("AOL "); - if (flags & AIM_FLAG_OSCAR_PAY) - dinlineprintf("OSCAR_PAY "); - if (flags & AIM_FLAG_FREE) - dinlineprintf("FREE "); - if (flags & AIM_FLAG_AWAY) - dinlineprintf("AWAY "); - if (flags & AIM_FLAG_UNKNOWN40) - dinlineprintf("ICQ? "); - if (flags & AIM_FLAG_UNKNOWN80) - dinlineprintf("UNKNOWN80 "); - return; -} + struct aim_userinfo_s *userinfo; + char *prof_encoding = NULL; + char *prof = NULL; + fu16_t inforeq = 0; -int faimtest_parse_userinfo(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - struct aim_userinfo_s *userinfo; - char *prof_encoding = NULL; - char *prof = NULL; - unsigned short inforeq = 0; - - va_list ap; - va_start(ap, command); - userinfo = va_arg(ap, struct aim_userinfo_s *); - prof_encoding = va_arg(ap, char *); - prof = va_arg(ap, char *); - inforeq = va_arg(ap, int); - va_end(ap); - - dvprintf("faimtest: userinfo: sn: %s\n", userinfo->sn); - dvprintf("faimtest: userinfo: warnlevel: 0x%04x\n", userinfo->warnlevel); - dvprintf("faimtest: userinfo: flags: 0x%04x = ", userinfo->flags); - printuserflags(userinfo->flags); - dinlineprintf("\n"); - - dvprintf("faimtest: userinfo: membersince: %lu\n", userinfo->membersince); - dvprintf("faimtest: userinfo: onlinesince: %lu\n", userinfo->onlinesince); - dvprintf("faimtest: userinfo: idletime: 0x%04x\n", userinfo->idletime); - - if (inforeq == AIM_GETINFO_GENERALINFO) { - dvprintf("faimtest: userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]"); - dvprintf("faimtest: userinfo: prof: %s\n", prof ? prof : "[none]"); - } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) { - dvprintf("faimtest: userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]"); - dvprintf("faimtest: userinfo: awaymsg: %s\n", prof ? prof : "[none]"); - } else - dprintf("faimtest: userinfo: unknown info request\n"); - - return 1; + va_list ap; + va_start(ap, fr); + userinfo = va_arg(ap, struct aim_userinfo_s *); + prof_encoding = va_arg(ap, char *); + prof = va_arg(ap, char *); + inforeq = va_arg(ap, fu16_t); + va_end(ap); + + dvprintf("faimtest: userinfo: sn: %s\n", userinfo->sn); + dvprintf("faimtest: userinfo: warnlevel: 0x%04x\n", userinfo->warnlevel); + dvprintf("faimtest: userinfo: flags: 0x%04x = ", userinfo->flags); + printuserflags(userinfo->flags); + dinlineprintf("\n"); + + dvprintf("faimtest: userinfo: membersince: %lu\n", userinfo->membersince); + dvprintf("faimtest: userinfo: onlinesince: %lu\n", userinfo->onlinesince); + dvprintf("faimtest: userinfo: idletime: 0x%04x\n", userinfo->idletime); + + if (inforeq == AIM_GETINFO_GENERALINFO) { + dvprintf("faimtest: userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]"); + dvprintf("faimtest: userinfo: prof: %s\n", prof ? prof : "[none]"); + } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) { + dvprintf("faimtest: userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]"); + dvprintf("faimtest: userinfo: awaymsg: %s\n", prof ? prof : "[none]"); + } else + dprintf("faimtest: userinfo: unknown info request\n"); + + return 1; } -static int faimtest_handlecmd(struct aim_session_t *sess, struct command_rx_struct *command, struct aim_userinfo_s *userinfo, char *tmpstr) +static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, const char *tmpstr) { + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; - if (!strncmp(tmpstr, "disconnect", 10)) { - - logout(); + if (!strncmp(tmpstr, "disconnect", 10)) { - } else if (strstr(tmpstr, "goodday")) { + logout(sess); - aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too."); + } else if (strstr(tmpstr, "goodday")) { - } else if (strstr(tmpstr, "haveicon") && buddyicon) { - struct aim_sendimext_args args; - static const char iconmsg[] = {"I have an icon"}; + aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too."); - args.destsn = userinfo->sn; - args.flags = AIM_IMFLAGS_HASICON; - args.msg = iconmsg; - args.msglen = strlen(iconmsg); - args.iconlen = buddyiconlen; - args.iconstamp = buddyiconstamp; - args.iconsum = buddyiconsum; + } else if (strstr(tmpstr, "haveicon") && priv->buddyicon) { + struct aim_sendimext_args args; + static const char iconmsg[] = {"I have an icon"}; - aim_send_im_ext(sess, command->conn, &args); + args.destsn = userinfo->sn; + args.flags = AIM_IMFLAGS_HASICON; + args.msg = iconmsg; + args.msglen = strlen(iconmsg); + args.iconlen = priv->buddyiconlen; + args.iconstamp = priv->buddyiconstamp; + args.iconsum = priv->buddyiconsum; - } else if (strstr(tmpstr, "sendicon") && buddyicon) { + aim_send_im_ext(sess, conn, &args); - aim_send_icon(sess, command->conn, userinfo->sn, buddyicon, buddyiconlen, buddyiconstamp, buddyiconsum); + } else if (strstr(tmpstr, "sendicon") && priv->buddyicon) { - } else if (strstr(tmpstr, "warnme")) { + aim_send_icon(sess, conn, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum); - dprintf("faimtest: icbm: sending non-anon warning\n"); - aim_send_warning(sess, command->conn, userinfo->sn, 0); + } else if (strstr(tmpstr, "warnme")) { - } else if (strstr(tmpstr, "anonwarn")) { + dprintf("faimtest: icbm: sending non-anon warning\n"); + aim_send_warning(sess, conn, userinfo->sn, 0); - dprintf("faimtest: icbm: sending anon warning\n"); - aim_send_warning(sess, command->conn, userinfo->sn, AIM_WARN_ANON); + } else if (strstr(tmpstr, "anonwarn")) { - } else if (strstr(tmpstr, "setdirectoryinfo")) { + dprintf("faimtest: icbm: sending anon warning\n"); + aim_send_warning(sess, conn, userinfo->sn, AIM_WARN_ANON); - dprintf("faimtest: icbm: sending backwards profile data\n"); - aim_setdirectoryinfo(sess, command->conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1); + } else if (strstr(tmpstr, "setdirectoryinfo")) { - } else if (strstr(tmpstr, "setinterests")) { + dprintf("faimtest: icbm: sending backwards profile data\n"); + aim_setdirectoryinfo(sess, conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1); - dprintf("faimtest: icbm: setting fun interests\n"); - aim_setuserinterests(sess, command->conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1); + } else if (strstr(tmpstr, "setinterests")) { - } else if (!strncmp(tmpstr, "getfile", 7)) { + dprintf("faimtest: icbm: setting fun interests\n"); + aim_setuserinterests(sess, conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1); - if (!ohcaptainmycaptain) { + } else if (!strncmp(tmpstr, "getfile", 7)) { - aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!"); + if (!priv->ohcaptainmycaptain) { - } else { - struct aim_conn_t *newconn; + aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!"); - newconn = aim_getfile_initiate(sess, command->conn, (strlen(tmpstr) < 8)?ohcaptainmycaptain:tmpstr+8); - dvprintf("faimtest: getting file listing from %s\n", (strlen(tmpstr) < 8)?ohcaptainmycaptain:tmpstr+8); - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE, faimtest_getfile_initiate,0); - } + } else + getfile_start(sess, conn, (strlen(tmpstr) < 8)?priv->ohcaptainmycaptain:tmpstr+8); + + } else if (!strncmp(tmpstr, "open chatnav", 12)) { - } else if (!strncmp(tmpstr, "open chatnav", 12)) { + aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_CHATNAV); - aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV); + } else if (!strncmp(tmpstr, "create", 6)) { - } else if (!strncmp(tmpstr, "create", 6)) { + aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004); - aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004); + } else if (!strncmp(tmpstr, "close chatnav", 13)) { + aim_conn_t *chatnavconn; - } else if (!strncmp(tmpstr, "close chatnav", 13)) { - struct aim_conn_t *chatnavconn; + if ((chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV))) + aim_conn_kill(sess, &chatnavconn); - chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV); - aim_conn_kill(sess, &chatnavconn); + } else if (!strncmp(tmpstr, "join", 4)) { - } else if (!strncmp(tmpstr, "join", 4)) { + aim_chat_join(sess, conn, 0x0004, "worlddomination", 0x0000); - aim_chat_join(sess, command->conn, 0x0004, "worlddomination"); + } else if (!strncmp(tmpstr, "leave", 5)) { - } else if (!strncmp(tmpstr, "leave", 5)) { + aim_chat_leaveroom(sess, "worlddomination"); - aim_chat_leaveroom(sess, "worlddomination"); + } else if (!strncmp(tmpstr, "getinfo", 7)) { - } else if (!strncmp(tmpstr, "getinfo", 7)) { + aim_getinfo(sess, conn, "75784102", AIM_GETINFO_GENERALINFO); + aim_getinfo(sess, conn, "15853637", AIM_GETINFO_AWAYMESSAGE); + aim_getinfo(sess, conn, "midendian", AIM_GETINFO_GENERALINFO); + aim_getinfo(sess, conn, "midendian", AIM_GETINFO_AWAYMESSAGE); - aim_getinfo(sess, command->conn, "75784102", AIM_GETINFO_GENERALINFO); - aim_getinfo(sess, command->conn, "15853637", AIM_GETINFO_AWAYMESSAGE); - aim_getinfo(sess, command->conn, "midendian", AIM_GETINFO_GENERALINFO); - aim_getinfo(sess, command->conn, "midendian", AIM_GETINFO_AWAYMESSAGE); + } else if (!strncmp(tmpstr, "open directim", 13)) { - } else if (!strncmp(tmpstr, "open directim", 13)) { - struct aim_conn_t *newconn; + directim_start(sess, conn, (strlen(tmpstr) < 14)?userinfo->sn:tmpstr+14); - printf("faimtest: opening directim to %s\n", (strlen(tmpstr) < 14)?userinfo->sn:tmpstr+14); - newconn = aim_directim_initiate(sess, command->conn, NULL, (strlen(tmpstr) < 14)?userinfo->sn:tmpstr+14); - if(!newconn || newconn->fd == -1) - printf("connection failed!\n"); - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, faimtest_directim_initiate,0); + } else if(!(strncmp(tmpstr, "lookup", 6))) { - } else if(!(strncmp(tmpstr, "lookup", 6))) { + aim_usersearch_address(sess, conn, tmpstr+7); - aim_usersearch_address(sess, command->conn, tmpstr+7); + } else if (!strncmp(tmpstr, "reqsendmsg", 10)) { - } else if (!strncmp(tmpstr, "reqsendmsg", 10)) { + aim_send_im(sess, conn, priv->ohcaptainmycaptain, 0, "sendmsg 7900"); - aim_send_im(sess, command->conn, ohcaptainmycaptain, 0, "sendmsg 7900"); + } else if (!strncmp(tmpstr, "reqauth", 7)) { - } else if (!strncmp(tmpstr, "reqauth", 7)) { + aim_bos_reqservice(sess, conn, AIM_CONN_TYPE_AUTH); - aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_AUTH); + } else if (!strncmp(tmpstr, "reqconfirm", 10)) { - } else if (!strncmp(tmpstr, "reqconfirm", 10)) { + aim_auth_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH)); - aim_auth_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH)); + } else if (!strncmp(tmpstr, "reqemail", 8)) { - } else if (!strncmp(tmpstr, "reqemail", 8)) { + aim_auth_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011); - aim_auth_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011); + } else if (!strncmp(tmpstr, "changepass", 8)) { - } else if (!strncmp(tmpstr, "changepass", 8)) { + aim_auth_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD"); - aim_auth_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD"); + } else if (!strncmp(tmpstr, "setemail", 8)) { - } else if (!strncmp(tmpstr, "setemail", 8)) { + aim_auth_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS"); - aim_auth_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS"); + } else if (!strncmp(tmpstr, "sendmsg", 7)) { + int i; - } else if (!strncmp(tmpstr, "sendmsg", 7)) { - int i; - i = atoi(tmpstr+8); - if (i < 10000) { - char *newbuf; - int z; + i = atoi(tmpstr+8); + if (i < 10000) { + char *newbuf; + int z; - newbuf = malloc(i+1); - for (z = 0; z < i; z++) { - newbuf[z] = (z % 10)+0x30; - } - newbuf[i] = '\0'; - aim_send_im(sess, command->conn, userinfo->sn, 0, newbuf); - free(newbuf); - } + newbuf = malloc(i+1); + for (z = 0; z < i; z++) + newbuf[z] = (z % 10)+0x30; + newbuf[i] = '\0'; + aim_send_im(sess, conn, userinfo->sn, 0, newbuf); + free(newbuf); + } - } else { + } else { - dprintf("unknown command.\n"); - aim_add_buddy(sess, command->conn, userinfo->sn); + dprintf("unknown command.\n"); + aim_add_buddy(sess, conn, userinfo->sn); - } + } - return 0; + return 0; } /* - * The user-level Incoming ICBM callback. - * + * Channel 1: Standard Message */ -int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap) { - int channel; - struct aim_userinfo_s *userinfo; - va_list ap; - - va_start(ap, command); - channel = va_arg(ap, int); - userinfo = va_arg(ap, struct aim_userinfo_s *); - - /* - * Channel 1: Standard Message - */ - if (channel == 1) { - char *tmpstr; - struct aim_incomingim_ch1_args *args; - int clienttype = AIM_CLIENTTYPE_UNKNOWN; - char realmsg[8192+1] = {""}; - - args = va_arg(ap, struct aim_incomingim_ch1_args *); - va_end(ap); - - clienttype = aim_fingerprintclient(args->fingerprint, args->finlen); - - dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn); - dvprintf("faimtest: icbm: probable client type: %d\n", clienttype); - dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel); - dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags); - printuserflags(userinfo->flags); - dinlineprintf("\n"); - - dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince); - dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince); - dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime); - dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities); - - dprintf("faimtest: icbm: icbmflags = "); - if (args->icbmflags & AIM_IMFLAGS_AWAY) - dinlineprintf("away "); - if (args->icbmflags & AIM_IMFLAGS_ACK) - dinlineprintf("ackrequest "); - if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ) - dinlineprintf("buddyreq "); - if (args->icbmflags & AIM_IMFLAGS_HASICON) - dinlineprintf("hasicon "); - dinlineprintf("\n"); - - dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", args->flag1, args->flag2); - - /* - * Quickly convert it to eight bit format, replacing non-ASCII UNICODE - * characters with their equivelent HTML entity. - */ - if (args->icbmflags & AIM_IMFLAGS_UNICODE) { - int i; - - for (i = 0; i < args->msglen; i += 2) { - unsigned short uni; - - uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff); - - if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */ - - snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), - "%c", uni); - - } else { /* something else, do UNICODE entity */ - - snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), - "&#%04x;", uni); + char *tmpstr; + struct aim_incomingim_ch1_args *args; + int clienttype = AIM_CLIENTTYPE_UNKNOWN; + char realmsg[8192+1] = {""}; - } + args = va_arg(ap, struct aim_incomingim_ch1_args *); + va_end(ap); - } - - } else { - - /* - * For non-UNICODE encodings (ASCII and ISO 8859-1), there is no - * need to do anything special here. Most terminals/whatever will - * be able to display such characters unmodified. - * - * Beware that PC-ASCII 128 through 159 are _not_ actually defined in - * ASCII or ISO 8859-1, and you should send them as UNICODE. WinAIM - * will send these characters in a UNICODE message, so you need - * to do so as well. - * - * You may not think it necessary to handle UNICODE messages. You're - * probably wrong. For one thing, Microsoft "Smart Quotes" will - * be sent by WinAIM as UNICODE (not HTML UNICODE, but real UNICODE). - * If you don't parse UNICODE at all, your users will get a blank - * message instead of the message containing Smart Quotes. - * - */ - strncpy(realmsg, args->msg, sizeof(realmsg)); - } - - dvprintf("faimtest: icbm: message: %s\n", realmsg); - - if (args->icbmflags & AIM_IMFLAGS_HASICON) - aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon"); - - if (realmsg) { - int i = 0; - - while (realmsg[i] == '<') { - if (realmsg[i] == '<') { - while (realmsg[i] != '>') - i++; - i++; - } - } - tmpstr = realmsg+i; - - faimtest_handlecmd(sess, command, userinfo, tmpstr); - - } - } - /* - * Channel 2: Rendevous Request - */ - else if (channel == 2) { - struct aim_incomingim_ch2_args *args; - - args = va_arg(ap, struct aim_incomingim_ch2_args *); - va_end(ap); - - switch (args->reqclass) { - case AIM_CAPS_VOICE: { - - dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn); - dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel); - dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags); - printuserflags(userinfo->flags); - dinlineprintf("\n"); - - /* we dont get membersince on chat invites! */ - dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince); - dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime); - - break; - } - case AIM_CAPS_GETFILE: { - struct aim_conn_t *newconn; - struct aim_fileheader_t *fh; - - dvprintf("faimtest: get file request from %s (at %s) %x\n", userinfo->sn, args->info.getfile.ip, args->reqclass); - - fh = aim_getlisting(sess, listingfile); - - newconn = aim_accepttransfer(sess, command->conn, userinfo->sn, args->info.getfile.cookie, args->info.getfile.ip, fh->totfiles, fh->totsize, fh->size, fh->checksum, args->reqclass); - - if ( (!newconn) || (newconn->fd == -1) ) { - dprintf("faimtest: getfile: requestconn: apparent error in accepttransfer\n"); - if(newconn) - aim_conn_kill(sess, &newconn); - break; - } - - free(fh); - - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0); - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ, faimtest_getfile_filereq, 0); - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0); - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0); - - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0); - - dprintf("faimtest: getfile connect succeeded, handlers added.\n"); - - break; - } - case AIM_CAPS_SENDFILE: { - dprintf("faimtest: send file!\n"); - break; - } - case AIM_CAPS_CHAT: { - - dvprintf("faimtest: chat invitation: source sn = %s\n", userinfo->sn); - dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel); - dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags); - printuserflags(userinfo->flags); - dinlineprintf("\n"); - - /* we dont get membersince on chat invites! */ - dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince); - dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime); - - dvprintf("faimtest: chat invitation: message = %s\n", args->info.chat.msg); - dvprintf("faimtest: chat invitation: room name = %s\n", args->info.chat.roominfo.name); - dvprintf("faimtest: chat invitation: encoding = %s\n", args->info.chat.encoding); - dvprintf("faimtest: chat invitation: language = %s\n", args->info.chat.lang); - dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange); - dvprintf("faimtest: chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance); - dvprintf("faimtest: chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); - - /* - * Automatically join room... - */ - aim_chat_join(sess, command->conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name); - break; - } - case AIM_CAPS_IMIMAGE: { - struct aim_conn_t *newconn; - - dprintf("faimtest: icbm: rendezvous imimage\n"); - - dvprintf("faimtest: OFT: DirectIM: request from %s (%s)\n", userinfo->sn, args->info.directim->ip); - - newconn = aim_directim_connect(sess, command->conn, args->info.directim); - - if ( (!newconn) || (newconn->fd == -1) ) { - dprintf("faimtest: icbm: imimage: could not connect\n"); - - if (newconn) - aim_conn_kill(sess, &newconn); - - break; - } - - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0); - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0); - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0); - - dvprintf("faimtest: OFT: DirectIM: connected to %s\n", userinfo->sn); - - aim_send_im_direct(sess, newconn, "goodday"); - - break; - } - case AIM_CAPS_BUDDYICON: { - - dvprintf("faimtest: Buddy Icon from %s, length = %u\n", userinfo->sn, args->info.icon.length); - break; - } - default: - dvprintf("faimtest: icbm: unknown reqclass (%d)\n", args->reqclass); - } /* switch */ - } else - dvprintf("faimtest does not support channels > 2 (chan = %02x)\n", channel); - - dprintf("faimtest: icbm: done with ICBM handling\n"); - - return 1; -} + clienttype = aim_fingerprintclient(args->fingerprint, args->finlen); -int faimtest_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_directim_priv *priv; - struct aim_conn_t *newconn, *listenerconn; + dvprintf("faimtest: icbm: sn = \"%s\"\n", userinfo->sn); + dvprintf("faimtest: icbm: probable client type: %d\n", clienttype); + dvprintf("faimtest: icbm: warnlevel = 0x%04x\n", userinfo->warnlevel); + dvprintf("faimtest: icbm: flags = 0x%04x = ", userinfo->flags); + printuserflags(userinfo->flags); + dinlineprintf("\n"); - va_start(ap, command); - newconn = va_arg(ap, struct aim_conn_t *); - listenerconn = va_arg(ap, struct aim_conn_t *); - va_end(ap); + dvprintf("faimtest: icbm: membersince = %lu\n", userinfo->membersince); + dvprintf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince); + dvprintf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime); + dvprintf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities); + + dprintf("faimtest: icbm: icbmflags = "); + if (args->icbmflags & AIM_IMFLAGS_AWAY) + dinlineprintf("away "); + if (args->icbmflags & AIM_IMFLAGS_ACK) + dinlineprintf("ackrequest "); + if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ) + dinlineprintf("buddyreq "); + if (args->icbmflags & AIM_IMFLAGS_HASICON) + dinlineprintf("hasicon "); + dinlineprintf("\n"); - aim_conn_close(listenerconn); - aim_conn_kill(sess, &listenerconn); + dvprintf("faimtest: icbm: encoding flags = {%04x, %04x}\n", args->flag1, args->flag2); - priv = (struct aim_directim_priv *)newconn->priv; + /* + * Quickly convert it to eight bit format, replacing non-ASCII UNICODE + * characters with their equivelent HTML entity. + */ + if (args->icbmflags & AIM_IMFLAGS_UNICODE) { + int i; - dvprintf("faimtest: OFT: DirectIM: intitiate success to %s\n", priv->ip); - - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0); - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0); - aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0); + for (i = 0; i < args->msglen; i += 2) { + fu16_t uni; - aim_send_im_direct(sess, newconn, "goodday"); + uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff); - dvprintf("faimtest: OFT: DirectIM: connected to %s\n", priv->sn); + if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */ - return 1; -} + snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni); -int faimtest_directim_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_directim_priv *priv; - - va_start(ap, command); - priv = va_arg(ap, struct aim_directim_priv *); + } else { /* something else, do UNICODE entity */ - va_end(ap); - - dprintf("faimtest: directim_connect\n"); + snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni); - return 1; -} - -int faimtest_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - char *msg = NULL; - struct aim_conn_t *conn; - struct aim_directim_priv *priv; - - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); - msg = va_arg(ap, char *); - va_end(ap); - - if(!(priv = conn->priv)) { - dvprintf("faimtest: directim: no private struct on conn with fd %d\n", conn->fd); - return -1; - } - - dvprintf("faimtest: Directim from %s: %s\n", priv->sn, msg); - if (!strncmp(msg, "sendmsg", 7)) { - int i; - i = atoi(msg+8); - if (i < 10000) { - char *newbuf; - int z; - - newbuf = malloc(i+1); - for (z = 0; z < i; z++) { - newbuf[z] = (z % 10)+0x30; - } - newbuf[i] = '\0'; - aim_send_im_direct(sess, conn, newbuf); - free(newbuf); - } - } else if (!strncmp(msg, "goodday", 7)) { - aim_send_im_direct(sess, conn, "Good day to you, too"); - } else { - char newmsg[1024]; - snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg); - aim_send_im_direct(sess, conn, newmsg); - } - return 1; -} - -int faimtest_directim_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_conn_t *conn; - char *sn; + } - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); - sn = va_arg(ap, char *); - va_end(ap); + } - dvprintf("faimtest: directim: disconnected from %s\n", sn); + } else { + + /* + * For non-UNICODE encodings (ASCII and ISO 8859-1), there is + * no need to do anything special here. Most + * terminals/whatever will be able to display such characters + * unmodified. + * + * Beware that PC-ASCII 128 through 159 are _not_ actually + * defined in ASCII or ISO 8859-1, and you should send them as + * UNICODE. WinAIM will send these characters in a UNICODE + * message, so you need to do so as well. + * + * You may not think it necessary to handle UNICODE messages. + * You're probably wrong. For one thing, Microsoft "Smart + * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE, + * but real UNICODE). If you don't parse UNICODE at all, your + * users will get a blank message instead of the message + * containing Smart Quotes. + * + */ + strncpy(realmsg, args->msg, sizeof(realmsg)); + } - aim_conn_kill(sess, &conn); - return 1; -} + dvprintf("faimtest: icbm: message: %s\n", realmsg); -int faimtest_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_conn_t *conn; - struct aim_directim_priv *priv; - - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); - va_end(ap); - - if(!(priv = (struct aim_directim_priv *)conn->priv)) { - dvprintf("faimtest: no private struct on conn with fd %d!\n", conn->fd); - return -1; - } - - dvprintf("faimtest: ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", priv->sn); - return 1; -} + if (args->icbmflags & AIM_IMFLAGS_HASICON) + aim_send_im(sess, conn, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon"); -int faimtest_infochange(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - unsigned short change = 0; - int perms, type, length, str; - char *val; - va_list ap; + if (realmsg) { + int i = 0; - va_start(ap, command); - perms = va_arg(ap, int); - type = va_arg(ap, int); - length = va_arg(ap, int); - val = va_arg(ap, char *); - str = va_arg(ap, int); - va_end(ap); + while (realmsg[i] == '<') { + if (realmsg[i] == '<') { + while (realmsg[i] != '>') + i++; + i++; + } + } + tmpstr = realmsg+i; - if (aimutil_get16(command->data+2) == 0x0005) - change = 1; + faimtest_handlecmd(sess, conn, userinfo, tmpstr); - dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)"); + } - return 1; + return 1; } -int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct *command, ...) +/* + * Channel 2: Rendevous Request + */ +static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, va_list ap) { - struct aim_userinfo_s *userinfo; - - va_list ap; - va_start(ap, command); - userinfo = va_arg(ap, struct aim_userinfo_s *); - va_end(ap); - - dvprintf("%ld %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n", - time(NULL), - userinfo->sn, userinfo->flags, - (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"", - (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"", - (userinfo->flags&AIM_FLAG_AOL)?" AOL":"", - (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"", - (userinfo->flags&AIM_FLAG_FREE)?" FREE":"", - (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"", - (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"", - (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"", - userinfo->capabilities); - return 1; -} + struct aim_incomingim_ch2_args *args; -int faimtest_parse_offgoing(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - struct aim_userinfo_s *userinfo; - - va_list ap; - va_start(ap, command); - userinfo = va_arg(ap, struct aim_userinfo_s *); - va_end(ap); - - dvprintf("%ld %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n", - time(NULL), - userinfo->sn, userinfo->flags, - (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"", - (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"", - (userinfo->flags&AIM_FLAG_AOL)?" AOL":"", - (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"", - (userinfo->flags&AIM_FLAG_FREE)?" FREE":"", - (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"", - (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"", - (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"", - userinfo->capabilities); - return 1; -} + args = va_arg(ap, struct aim_incomingim_ch2_args *); + va_end(ap); -int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - static char *codes[] = { - "Unknown", - "Mandatory upgrade", - "Advisory upgrade", - "System bulletin", - "Top o' the world!" - }; - static int codeslen = 5; - char *msg; - unsigned short id; - va_list ap; + if (args->reqclass == AIM_CAPS_VOICE) { - va_start(ap, command); - id = va_arg(ap, int); - msg = va_arg(ap, char *); - va_end(ap); + dvprintf("faimtest: voice invitation: source sn = %s\n", userinfo->sn); + dvprintf("faimtest: voice invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel); + dvprintf("faimtest: voice invitation: \tclass = 0x%04x = ", userinfo->flags); + printuserflags(userinfo->flags); + dinlineprintf("\n"); - dvprintf("faimtest: motd: %s (%d / %s)\n", msg, id, (id < codeslen)?codes[id]:"unknown"); + dvprintf("faimtest: voice invitation: \tonlinesince = %lu\n", userinfo->onlinesince); + dvprintf("faimtest: voice invitation: \tidletime = 0x%04x\n", userinfo->idletime); - return 1; -} + } else if (args->reqclass == AIM_CAPS_GETFILE) { + + getfile_requested(sess, conn, userinfo, args); + + } else if (args->reqclass == AIM_CAPS_SENDFILE) { -int faimtest_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - unsigned short reason; + dprintf("faimtest: send file!\n"); - va_start(ap, command); - reason = va_arg(ap, int); - va_end(ap); + } else if (args->reqclass == AIM_CAPS_CHAT) { - dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reasonsn); + dvprintf("faimtest: chat invitation: \twarnlevel = 0x%04x\n", userinfo->warnlevel); + dvprintf("faimtest: chat invitation: \tclass = 0x%04x = ", userinfo->flags); + printuserflags(userinfo->flags); + dinlineprintf("\n"); - return 1; -} + /* we dont get membersince on chat invites! */ + dvprintf("faimtest: chat invitation: \tonlinesince = %lu\n", userinfo->onlinesince); + dvprintf("faimtest: chat invitation: \tidletime = 0x%04x\n", userinfo->idletime); -int faimtest_parse_msgerr(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - char *destsn; - unsigned short reason; + dvprintf("faimtest: chat invitation: message = %s\n", args->info.chat.msg); + dvprintf("faimtest: chat invitation: room name = %s\n", args->info.chat.roominfo.name); + dvprintf("faimtest: chat invitation: encoding = %s\n", args->info.chat.encoding); + dvprintf("faimtest: chat invitation: language = %s\n", args->info.chat.lang); + dvprintf("faimtest: chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange); + dvprintf("faimtest: chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance); + dvprintf("faimtest: chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); - va_start(ap, command); - reason = va_arg(ap, int); - destsn = va_arg(ap, char *); - va_end(ap); + /* Automatically join room... */ + aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance); - dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reasonreqclass == AIM_CAPS_IMIMAGE) { - return 1; -} + dprintf("faimtest: icbm: rendezvous imimage\n"); -int faimtest_parse_locerr(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - char *destsn; - unsigned short reason; + directim_requested(sess, conn, userinfo, args); - va_start(ap, command); - reason = va_arg(ap, int); - destsn = va_arg(ap, char *); - va_end(ap); + } else if (args->reqclass == AIM_CAPS_BUDDYICON) { - dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reasonsn, args->info.icon.length); + + } else { + + dvprintf("faimtest: icbm: unknown reqclass (%d)\n", args->reqclass); + } return 1; } -/* - * Handles callbacks for AIM_CB_MISSED_CALL. - */ -int faimtest_parse_misses(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...) { - static char *missedreasons[] = { - "Invalid (0)", - "Message too large", - "Rate exceeded", - "Evil Sender", - "Evil Receiver" - }; - static int missedreasonslen = 5; - - va_list ap; - unsigned short chan, nummissed, reason; + fu16_t channel; struct aim_userinfo_s *userinfo; + va_list ap; + int ret = 0; - va_start(ap, command); - chan = va_arg(ap, int); + va_start(ap, fr); + channel = va_arg(ap, fu16_t); userinfo = va_arg(ap, struct aim_userinfo_s *); - nummissed = va_arg(ap, int); - reason = va_arg(ap, int); - va_end(ap); - dvprintf("faimtest: missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reasonconn, userinfo, ap); + else if (channel == 2) + ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, ap); + else + dvprintf("unsupported channel 0x%04x\n", channel); + + dvprintf("faimtest: icbm: done with ICBM handling (ret = %d)\n", ret); return 1; } -int faimtest_parse_login(struct aim_session_t *sess, struct command_rx_struct *command, ...) +#ifdef MID_REWROTE_ALL_THE_CRAP +static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...) { - struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD; - char *key; + fu16_t change = 0, perms, type; + int length, str; + char *val; va_list ap; - va_start(ap, command); - key = va_arg(ap, char *); + va_start(ap, fr); + perms = va_arg(ap, fu16_t); + type = va_arg(ap, fu16_t); + length = va_arg(ap, int); + val = va_arg(ap, char *); + str = va_arg(ap, int); va_end(ap); - aim_send_login(sess, command->conn, screenname, password, &info, key); + if (aimutil_get16(command->data+2) == 0x0005) + change = 1; + + dvprintf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)"); return 1; } +#endif -int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) { - va_list ap; struct aim_userinfo_s *userinfo; - int count = 0, i = 0; - va_start(ap, command); - count = va_arg(ap, int); + va_list ap; + va_start(ap, fr); userinfo = va_arg(ap, struct aim_userinfo_s *); va_end(ap); - dvprintf("faimtest: chat: %s: New occupants have joined:\n", (char *)command->conn->priv); - while (i < count) - dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn); - + dvprintf("%ld %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n", + time(NULL), + userinfo->sn, userinfo->flags, + (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"", + (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"", + (userinfo->flags&AIM_FLAG_AOL)?" AOL":"", + (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"", + (userinfo->flags&AIM_FLAG_FREE)?" FREE":"", + (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"", + (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"", + (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"", + userinfo->capabilities); return 1; } -int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...) { - va_list ap; struct aim_userinfo_s *userinfo; - int count = 0, i = 0; - - va_start(ap, command); - count = va_arg(ap, int); + va_list ap; + + va_start(ap, fr); userinfo = va_arg(ap, struct aim_userinfo_s *); va_end(ap); - dvprintf("faimtest: chat: %s: Some occupants have left:\n", (char *)command->conn->priv); - - for (i = 0; i < count; ) - dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn); + dvprintf("%ld %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n", + time(NULL), + userinfo->sn, userinfo->flags, + (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"", + (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"", + (userinfo->flags&AIM_FLAG_AOL)?" AOL":"", + (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"", + (userinfo->flags&AIM_FLAG_FREE)?" FREE":"", + (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"", + (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"", + (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"", + userinfo->capabilities); return 1; } -int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - struct aim_userinfo_s *userinfo; - struct aim_chat_roominfo *roominfo; - char *roomname; - int usercount,i; - char *roomdesc; - unsigned short unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen; - unsigned long creationtime; - - va_start(ap, command); - roominfo = va_arg(ap, struct aim_chat_roominfo *); - roomname = va_arg(ap, char *); - usercount= va_arg(ap, int); - userinfo = va_arg(ap, struct aim_userinfo_s *); - roomdesc = va_arg(ap, char *); - unknown_c9 = va_arg(ap, int); - creationtime = va_arg(ap, unsigned long); - maxmsglen = va_arg(ap, int); - unknown_d2 = va_arg(ap, int); - unknown_d5 = va_arg(ap, int); - maxvisiblemsglen = va_arg(ap, int); - va_end(ap); - - dvprintf("faimtest: chat: %s: info update:\n", (char *)command->conn->priv); - dvprintf("faimtest: chat: %s: \tRoominfo: {%04x, %s, %04x}\n", (char *)command->conn->priv, roominfo->exchange, roominfo->name, roominfo->instance); - dvprintf("faimtest: chat: %s: \tRoomname: %s\n", (char *)command->conn->priv, roomname); - dvprintf("faimtest: chat: %s: \tRoomdesc: %s\n", (char *)command->conn->priv, roomdesc); - dvprintf("faimtest: chat: %s: \tOccupants: (%d)\n", (char *)command->conn->priv, usercount); + fu16_t reason; - for (i = 0; i < usercount; ) - dvprintf("faimtest: chat: %s: \t\t%s\n", (char *)command->conn->priv, userinfo[i++].sn); + va_start(ap, fr); + reason = va_arg(ap, fu16_t); + va_end(ap); - dvprintf("faimtest: chat: %s: \tUnknown_c9: 0x%04x\n", (char *)command->conn->priv, unknown_c9); - dvprintf("faimtest: chat: %s: \tCreation time: %lu (time_t)\n", (char *)command->conn->priv, creationtime); - dvprintf("faimtest: chat: %s: \tUnknown_d2: 0x%04x\n", (char *)command->conn->priv, unknown_d2); - dvprintf("faimtest: chat: %s: \tUnknown_d5: 0x%02x\n", (char *)command->conn->priv, unknown_d5); - dvprintf("faimtest: chat: %s: \tMax message length: %d bytes\n", (char *)command->conn->priv, maxmsglen); - dvprintf("faimtest: chat: %s: \tMax visible message length: %d bytes\n", (char *)command->conn->priv, maxvisiblemsglen); + dvprintf("faimtest: snac threw error (reason 0x%04x: %s)\n", reason, (reasonconn->priv, userinfo->sn, msg); - - /* - * Do an echo for testing purposes. But not for ourselves ("oops!") - */ - if (strcmp(userinfo->sn, sess->sn) != 0) { - sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); - aim_chat_send_im(sess, command->conn, 0, tmpbuf, strlen(tmpbuf)); - } + dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reasonconn); /* this will break the main loop */ - - connected = 0; + dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reasonconn->type = AIM_CONN_TYPE_BOS; + va_list ap; + fu16_t chan, nummissed, reason; + struct aim_userinfo_s *userinfo; - aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0); + va_start(ap, fr); + chan = va_arg(ap, fu16_t); + userinfo = va_arg(ap, struct aim_userinfo_s *); + nummissed = va_arg(ap, fu16_t); + reason = va_arg(ap, fu16_t); + va_end(ap); - /* tell the aimddebugd we're ready */ - aim_debugconn_sendconnect(sess, command->conn); + dvprintf("faimtest: missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reasonname); - - return 1; -} - - -int faimtest_getfile_filesend(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_conn_t *oftconn; - struct aim_fileheader_t *fh; - char *path, *cookie; - int pos, bufpos = 0, bufsize = 2048, i; - char *buf; - - FILE *file; - - va_start(ap, command); - oftconn = va_arg(ap, struct aim_conn_t *); - fh = va_arg(ap, struct aim_fileheader_t *); - cookie = va_arg(ap, char *); - va_end(ap); - - dvprintf("faimtest: sending file %s(%ld).\n", fh->name, fh->size); - - if(!(buf = malloc(2048))) - return -1; - - if( (path = (char *)calloc(1, strlen(listingpath) +strlen(fh->name)+2)) == NULL) { - dperror("calloc"); - dprintf("faimtest: error in calloc of path\n"); - return 0; /* XXX: no idea what winaim expects here =) */ - } - - snprintf(path, strlen(listingpath)+strlen(fh->name)+2, "%s/%s", listingpath, fh->name); - - - if( (file = fopen(path, "r")) == NULL) { - dvprintf("faimtest: getfile_send fopen failed for %s. damn.\n", path); - return 0; - } - - /* - * This is a mess. Remember that faimtest is demonstration code - * only and for the sake of the gods, don't use this code in any - * of your clients. --mid - */ - for(pos = 0; pos < fh->size; pos++) { - bufpos = pos % bufsize; - - if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */ - if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) { - dperror("faim: getfile_send: write1"); - dprintf("faim: getfile_send: whoopsy, didn't write it all...\n"); - free(buf); - return -1; - } - } - if( (buf[bufpos] = fgetc(file)) == EOF) { - if(pos != fh->size) { - dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size); - free(buf); - return -1; - } - } - dvprintf("%c(0x%02x) ", buf[pos], buf[pos]); - } - - if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) { - dperror("faim: getfile_send: write2"); - dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n"); - free(buf); - return -1; - } - - free(buf); - free(fh); - return 1; -} - -int faimtest_getfile_complete(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_conn_t *conn; - struct aim_fileheader_t *fh; - - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); - fh = va_arg(ap, struct aim_fileheader_t *); - va_end(ap); - - dvprintf("faimtest: completed file transfer for %s.\n", fh->name); - - aim_conn_close(conn); - aim_conn_kill(sess, &conn); - return 1; -} - -int faimtest_getfile_disconnect(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_conn_t *conn; - char *sn; - - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); - sn = va_arg(ap, char *); - va_end(ap); - - aim_conn_kill(sess, &conn); - - dvprintf("faimtest: getfile: disconnected from %s\n", sn); - return 1; -} - -int faimtest_getfile_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_conn_t *conn, *listenerconn; - struct aim_filetransfer_priv *priv; - - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); - listenerconn = va_arg(ap, struct aim_conn_t *); - va_end(ap); - - aim_conn_close(listenerconn); - aim_conn_kill(sess, &listenerconn); - - aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ, faimtest_getfile_filereq, 0); - aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0); - aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0); - aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0); - aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0); - aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0); - aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE, faimtest_getfile_receive, 0); - aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4, faimtest_getfile_state4, 0); - - priv = (struct aim_filetransfer_priv *)conn->priv; - - dvprintf("faimtest: getfile: %s (%s) connected to us on %d\n", priv->sn, priv->ip, conn->fd); - return 1; -} - -int faimtest_getfile_listing(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_conn_t *conn; - char *listing; - struct aim_filetransfer_priv *ft; - char *filename, *nameend, *sizec; - int filesize, namelen; - - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); - ft = va_arg(ap, struct aim_filetransfer_priv *); - listing = va_arg(ap, char *); - va_end(ap); - - dvprintf("listing on %d==================\n%s\n===========\n", conn->fd, listing); - - nameend = strstr(listing+0x1a, "\r"); + fu16_t code, rateclass; + fu32_t windowsize, clear, alert, limit, disconnect; + fu32_t currentavg, maxavg; - namelen = nameend - (listing + 0x1a); + va_start(ap, fr); - filename = malloc(namelen + 1); - strncpy(filename, listing+0x1a, namelen); - filename[namelen] = 0x00; - - sizec = malloc(8+1); - memcpy(sizec, listing + 0x11, 8); - sizec[8] = 0x00; - - filesize = strtol(sizec, (char **)NULL, 10); - - dvprintf("faimtest: requesting %d %s(%d long)\n", namelen, filename, filesize); - - aim_oft_getfile_request(sess, conn, filename, filesize); - - free(filename); - free(sizec); - - return 0; -} + /* See code explanations below */ + code = va_arg(ap, fu16_t); -int faimtest_getfile_listingreq(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_conn_t *oftconn; - struct aim_fileheader_t *fh; - int pos, bufpos = 0, bufsize = 2048, i; - char *buf; - - va_start(ap, command); - oftconn = va_arg(ap, struct aim_conn_t *); - fh = va_arg(ap, struct aim_fileheader_t *); - va_end(ap); - - dvprintf("faimtest: sending listing of size %ld\n", fh->size); - - if(!(buf = malloc(2048))) - return -1; - - for(pos = 0; pos < fh->size; pos++) { - bufpos = pos % bufsize; - - if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */ - if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) { - dperror("faim: getfile_send: write1"); - dprintf("faim: getfile_send: whoopsy, didn't write it all...\n"); - free(buf); - return -1; - } - } - if( (buf[bufpos] = fgetc(listingfile)) == EOF) { - if(pos != fh->size) { - dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size); - free(buf); - return -1; - } - } - } - - if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) { - dperror("faim: getfile_send: write2"); - dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n"); - free(buf); - return -1; - } - - dprintf("faimtest: sent listing\n"); - free(buf); - return 0; -} - -int faimtest_getfile_receive(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_conn_t *conn; - struct aim_filetransfer_priv *ft; - unsigned char data; - int pos; - - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); - ft = va_arg(ap, struct aim_filetransfer_priv *); - va_end(ap); - - dvprintf("faimtest: receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name); - - for(pos = 0; pos < ft->fh.size; pos++) { - read(conn->fd, &data, 1); - printf("%c(%02x) ", data, data); - } - - printf("\n"); - - aim_oft_getfile_end(sess, conn); + /* + * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c. + */ + rateclass = va_arg(ap, fu16_t); - return 0; -} + /* + * Not sure what this is exactly. I think its the temporal + * relation factor (ie, how to make the rest of the numbers + * make sense in the real world). + */ + windowsize = va_arg(ap, fu32_t); -int faimtest_getfile_state4(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - va_list ap; - struct aim_conn_t *conn; + /* Explained below */ + clear = va_arg(ap, fu32_t); + alert = va_arg(ap, fu32_t); + limit = va_arg(ap, fu32_t); + disconnect = va_arg(ap, fu32_t); + currentavg = va_arg(ap, fu32_t); + maxavg = va_arg(ap, fu32_t); - va_start(ap, command); - conn = va_arg(ap, struct aim_conn_t *); - va_end(ap); + va_end(ap); - aim_conn_close(conn); - aim_conn_kill(sess, &conn); - return 0; -} + dvprintf("faimtest: rate %s (rate class 0x%04x): curavg = %ld, maxavg = %ld, alert at %ld, clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n", + (code < 5)?codes[code]:"invalid", + rateclass, + currentavg, maxavg, + alert, clear, + limit, disconnect, + windowsize); + + if (code == AIM_RATE_CODE_CHANGE) { + /* + * Not real sure when these get sent. + */ + if (currentavg >= clear) + aim_conn_setlatency(fr->conn, 0); + + } else if (code == AIM_RATE_CODE_WARNING) { + /* + * We start getting WARNINGs the first time we go below the + * 'alert' limit (currentavg < alert) and they stop when + * either we pause long enough for currentavg to go above + * 'clear', or until we flood it bad enough to go below + * 'limit' (and start getting LIMITs instead) or even further + * and go below 'disconnect' and get disconnected completely + * (and won't be able to login right away either). + */ + aim_conn_setlatency(fr->conn, windowsize/4); /* XXX this is bogus! */ + + } else if (code == AIM_RATE_CODE_LIMIT) { + /* + * When we hit LIMIT, messages will start getting dropped. + */ + aim_conn_setlatency(fr->conn, windowsize/2); /* XXX this is bogus! */ + + } else if (code == AIM_RATE_CODE_CLEARLIMIT) { + /* + * The limit is cleared when curavg goes above 'clear'. + */ + aim_conn_setlatency(fr->conn, 0); + } -int faimtest_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...) -{ - static char *codes[5] = {"invalid", - "change", - "warning", - "limit", - "limit cleared"}; - va_list ap; - int code; - unsigned long rateclass, windowsize, clear, alert, limit, disconnect; - unsigned long currentavg, maxavg; - - va_start(ap, command); - - /* See code explanations below */ - code = va_arg(ap, int); - - /* - * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c. - */ - rateclass = va_arg(ap, unsigned long); - - /* - * Not sure what this is exactly. I think its the temporal - * relation factor (ie, how to make the rest of the numbers - * make sense in the real world). - */ - windowsize = va_arg(ap, unsigned long); - - /* Explained below */ - clear = va_arg(ap, unsigned long); - alert = va_arg(ap, unsigned long); - limit = va_arg(ap, unsigned long); - disconnect = va_arg(ap, unsigned long); - currentavg = va_arg(ap, unsigned long); - maxavg = va_arg(ap, unsigned long); - - va_end(ap); - - - dvprintf("faimtest: rate %s (rate class 0x%04lx): curavg = %ld, maxavg = %ld, alert at %ld, clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n", - (code < 5)?codes[code]:"invalid", - rateclass, - currentavg, maxavg, - alert, clear, - limit, disconnect, - windowsize); - - if (code == AIM_RATE_CODE_CHANGE) { - /* - * Not real sure when these get sent. - */ - if (currentavg >= clear) - aim_conn_setlatency(command->conn, 0); - - } else if (code == AIM_RATE_CODE_WARNING) { - /* - * We start getting WARNINGs the first time we go below the 'alert' - * limit (currentavg < alert) and they stop when either we pause - * long enough for currentavg to go above 'clear', or until we - * flood it bad enough to go below 'limit' (and start getting - * LIMITs instead) or even further and go below 'disconnect' and - * get disconnected completely (and won't be able to login right - * away either). - */ - aim_conn_setlatency(command->conn, windowsize/4); /* XXX this is bogus! */ - - } else if (code == AIM_RATE_CODE_LIMIT) { - /* - * When we hit LIMIT, messages will start getting dropped. - */ - aim_conn_setlatency(command->conn, windowsize/2); /* XXX this is bogus! */ - - } else if (code == AIM_RATE_CODE_CLEARLIMIT) { - /* - * The limit is cleared when curavg goes above 'clear'. - */ - aim_conn_setlatency(command->conn, 0); - } - - return 1; + return 1; } -int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; - int newevil; + fu16_t newevil; struct aim_userinfo_s *userinfo; - va_start(ap, command); - newevil = va_arg(ap, int); + va_start(ap, fr); + newevil = va_arg(ap, fu16_t); userinfo = va_arg(ap, struct aim_userinfo_s *); va_end(ap); @@ -2550,13 +1580,13 @@ int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_stru return 1; } -int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *address, *SNs; int i, num; - va_start(ap, command); + va_start(ap, fr); address = va_arg(ap, char *); num = va_arg(ap, int); SNs = va_arg(ap, char *); @@ -2571,12 +1601,12 @@ int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_str return 1; } -int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...) +static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *address; - va_start(ap, command); + va_start(ap, fr); address = va_arg(ap, char *); va_end(ap); @@ -2584,3 +1614,46 @@ int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_str return 1; } + +void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn) +{ + + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); + + aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0); + aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, faimtest_rateresp_bos, 0); /* rate info */ + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, 0x0018, faimtest_hostversions, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 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, faimtest_handleredirect, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0); + aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, faimtest_locrights, 0); + aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0); + aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0); + aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0); + + aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0); + aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0); + aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0); + +#ifdef MID_REWROTE_ALL_THE_CRAP + aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0); +#endif + + return; +} + diff --git a/utils/faimtest/faimtest.h b/utils/faimtest/faimtest.h index 15fc33c..abd95ee 100644 --- a/utils/faimtest/faimtest.h +++ b/utils/faimtest/faimtest.h @@ -4,13 +4,76 @@ #include extern int keepgoing; -extern struct aim_session_t aimsess; +extern aim_session_t aimsess; -int login(const char *sn, const char *passwd); -int logout(void); +/* This is kept in the aim_session_t and accessible by handlers. */ +struct faimtest_priv { + char *aimbinarypath; + char *screenname; + char *password; + char *server; + char *proxy; + char *proxyusername; + char *proxypass; + char *ohcaptainmycaptain; + int connected; + FILE *listingfile; + char *listingpath; + + fu8_t *buddyicon; + int buddyiconlen; + time_t buddyiconstamp; + fu16_t buddyiconsum; +}; + +/* login.c */ +int login(aim_session_t *sess, const char *sn, const char *passwd); +int logout(aim_session_t *sess); + +/* commands.c */ void cmd_init(void); void cmd_gotkey(void); void cmd_uninit(void); +/* faimtest.c */ +int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...); +int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...); +int faimtest_serverready(aim_session_t *sess, aim_frame_t *fr, ...); +int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...); +int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...); +int faimtest_init(void); +char *dprintf_ctime(void); +void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn); + +/* ft.c */ +void getfile_start(aim_session_t *sess, aim_conn_t *conn, const char *sn); +void getfile_requested(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args); +void directim_start(aim_session_t *sess, aim_conn_t *conn, const char *sn); +void directim_requested(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args); + +/* chat.c */ +void chatnav_redirect(aim_session_t *sess, const char *ip, const fu8_t *cookie); +void chat_redirect(aim_session_t *sess, const char *ip, const fu8_t *cookie, const char *roomname, fu16_t exchange); + +#define DPRINTF_OUTSTREAM stdout +#define dprintf(x) { \ + fprintf(DPRINTF_OUTSTREAM, "%s %s: " x, dprintf_ctime(), "faimtest"); \ + fflush(DPRINTF_OUTSTREAM); \ +} +#define dvprintf(x, y...) { \ + fprintf(DPRINTF_OUTSTREAM, "%s %s: " x, dprintf_ctime(), "faimtest", y); \ + fflush(DPRINTF_OUTSTREAM); \ +} +#define dinlineprintf(x) { \ + fprintf(DPRINTF_OUTSTREAM, x); \ + fflush(DPRINTF_OUTSTREAM); \ +} +#define dvinlineprintf(x, y...) { \ + fprintf(DPRINTF_OUTSTREAM, x, y); \ + fflush(DPRINTF_OUTSTREAM); \ +} +#define dperror(x) dvprintf("%s: %s\n", x, strerror(errno)); + + #endif /* __FAIMTEST_H__ */ diff --git a/utils/faimtest/ft.c b/utils/faimtest/ft.c new file mode 100644 index 0000000..c7168e6 --- /dev/null +++ b/utils/faimtest/ft.c @@ -0,0 +1,530 @@ + +#include "faimtest.h" + +static int faimtest_directim_connect(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + struct aim_directim_priv *priv; + + va_start(ap, fr); + priv = va_arg(ap, struct aim_directim_priv *); + + va_end(ap); + + dprintf("faimtest: directim_connect\n"); + + return 1; +} + +static int faimtest_directim_incoming(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + char *msg; + aim_conn_t *conn; + struct aim_directim_priv *priv; + + va_start(ap, fr); + conn = va_arg(ap, aim_conn_t *); + msg = va_arg(ap, char *); + va_end(ap); + + if (!(priv = conn->priv)) { + dvprintf("faimtest: directim: no private struct on conn with fd %d\n", conn->fd); + return 0; + } + + dvprintf("faimtest: Directim from %s: %s\n", priv->sn, msg); + + if (!strncmp(msg, "sendmsg", 7)) { + int i; + + i = atoi(msg+8); + if (i < 10000) { + char *newbuf; + int z; + + newbuf = malloc(i+1); + for (z = 0; z < i; z++) + newbuf[z] = (z % 10)+0x30; + newbuf[i] = '\0'; + aim_send_im_direct(sess, conn, newbuf); + free(newbuf); + } + + } else if (!strncmp(msg, "goodday", 7)) { + + aim_send_im_direct(sess, conn, "Good day to you, too"); + + } else { + char newmsg[1024]; + + snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg); + aim_send_im_direct(sess, conn, newmsg); + } + + return 1; +} + +static int faimtest_directim_disconnect(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + aim_conn_t *conn; + char *sn; + + va_start(ap, fr); + conn = va_arg(ap, aim_conn_t *); + sn = va_arg(ap, char *); + va_end(ap); + + dvprintf("faimtest: directim: disconnected from %s\n", sn); + + aim_conn_kill(sess, &conn); + + return 1; +} + +static int faimtest_directim_typing(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + aim_conn_t *conn; + struct aim_directim_priv *priv; + + va_start(ap, fr); + conn = va_arg(ap, aim_conn_t *); + va_end(ap); + + if (!(priv = (struct aim_directim_priv *)conn->priv)) { + dvprintf("faimtest: no private struct on conn with fd %d!\n", conn->fd); + return 0; + } + + dvprintf("faimtest: ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", priv->sn); + + return 1; +} + +static int faimtest_directim_initiate(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + struct aim_directim_priv *priv; + aim_conn_t *newconn, *listenerconn; + + va_start(ap, fr); + newconn = va_arg(ap, aim_conn_t *); + listenerconn = va_arg(ap, aim_conn_t *); + va_end(ap); + + aim_conn_close(listenerconn); + aim_conn_kill(sess, &listenerconn); + + priv = (struct aim_directim_priv *)newconn->priv; + + dvprintf("faimtest: OFT: DirectIM: intitiate success to %s\n", priv->ip); + + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0); + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0); + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0); + + aim_send_im_direct(sess, newconn, "goodday"); + + dvprintf("faimtest: OFT: DirectIM: connected to %s\n", priv->sn); + + return 1; +} + +static int faimtest_getfile_filereq(aim_session_t *ses, aim_frame_t *fr, ...) +{ + va_list ap; + aim_conn_t *oftconn; + struct aim_fileheader_t *fh; + fu8_t *cookie; + + va_start(ap, fr); + oftconn = va_arg(ap, aim_conn_t *); + fh = va_arg(ap, struct aim_fileheader_t *); + cookie = va_arg(ap, fu8_t *); + va_end(ap); + + dvprintf("faimtest: request for file %s.\n", fh->name); + + return 1; +} + +static int faimtest_getfile_filesend(aim_session_t *sess, aim_frame_t *fr, ...) +{ + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + va_list ap; + aim_conn_t *oftconn; + struct aim_fileheader_t *fh; + char *path; + fu8_t *cookie; + int pos, bufpos = 0, bufsize = 2048, i; + char *buf; + FILE *file; + + va_start(ap, fr); + oftconn = va_arg(ap, aim_conn_t *); + fh = va_arg(ap, struct aim_fileheader_t *); + cookie = va_arg(ap, fu8_t *); + va_end(ap); + + dvprintf("faimtest: sending file %s(%ld).\n", fh->name, fh->size); + + if (!(buf = malloc(2048))) + return -1; + + if (!(path = (char *)calloc(1, strlen(priv->listingpath) +strlen(fh->name)+2))) { + dperror("calloc"); + dprintf("faimtest: error in calloc of path\n"); + + return 0; /* XXX: no idea what winaim expects here =) */ + } + + snprintf(path, strlen(priv->listingpath)+strlen(fh->name)+2, "%s/%s", priv->listingpath, fh->name); + + if (!(file = fopen(path, "r"))) { + dvprintf("faimtest: getfile_send fopen failed for %s. damn.\n", path); + return 0; + } + + /* + * This is a mess. Remember that faimtest is demonstration code + * only and for the sake of the gods, don't use this code in any + * of your clients. --mid + */ + for(pos = 0; pos < fh->size; pos++) { + + bufpos = pos % bufsize; + + if (bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */ + if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) { + dperror("faim: getfile_send: write1"); + dprintf("faim: getfile_send: whoopsy, didn't write it all...\n"); + free(buf); + return 0; + } + } + + if( (buf[bufpos] = fgetc(file)) == EOF) { + if(pos != fh->size) { + dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size); + free(buf); + return 0; + } + } + dvprintf("%c(0x%02x) ", buf[pos], buf[pos]); + } + + if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) { + dperror("faim: getfile_send: write2"); + dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n"); + free(buf); + return 0; + } + + free(buf); + free(fh); + + return 1; +} + +static int faimtest_getfile_complete(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + aim_conn_t *conn; + struct aim_fileheader_t *fh; + + va_start(ap, fr); + conn = va_arg(ap, aim_conn_t *); + fh = va_arg(ap, struct aim_fileheader_t *); + va_end(ap); + + dvprintf("faimtest: completed file transfer for %s.\n", fh->name); + + aim_conn_close(conn); + aim_conn_kill(sess, &conn); + + return 1; +} + +static int faimtest_getfile_disconnect(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + aim_conn_t *conn; + char *sn; + + va_start(ap, fr); + conn = va_arg(ap, aim_conn_t *); + sn = va_arg(ap, char *); + va_end(ap); + + aim_conn_kill(sess, &conn); + + dvprintf("faimtest: getfile: disconnected from %s\n", sn); + + return 1; +} + +static int faimtest_getfile_listing(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + aim_conn_t *conn; + char *listing; + struct aim_filetransfer_priv *ft; + char *filename, *nameend, *sizec; + int filesize, namelen; + + va_start(ap, fr); + conn = va_arg(ap, aim_conn_t *); + ft = va_arg(ap, struct aim_filetransfer_priv *); + listing = va_arg(ap, char *); + va_end(ap); + + dvprintf("listing on %d==================\n%s\n===========\n", conn->fd, listing); + + nameend = strstr(listing+0x1a, "\r"); + + namelen = nameend - (listing + 0x1a); + + filename = malloc(namelen + 1); + strncpy(filename, listing+0x1a, namelen); + filename[namelen] = 0x00; + + sizec = malloc(8+1); + memcpy(sizec, listing + 0x11, 8); + sizec[8] = 0x00; + + filesize = strtol(sizec, (char **)NULL, 10); + + dvprintf("faimtest: requesting %d %s(%d long)\n", namelen, filename, filesize); + + aim_oft_getfile_request(sess, conn, filename, filesize); + + free(filename); + free(sizec); + + return 0; +} + +static int faimtest_getfile_listingreq(aim_session_t *sess, aim_frame_t *fr, ...) +{ + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + va_list ap; + aim_conn_t *oftconn; + struct aim_fileheader_t *fh; + int pos, bufpos = 0, bufsize = 2048, i; + char *buf; + + va_start(ap, fr); + oftconn = va_arg(ap, aim_conn_t *); + fh = va_arg(ap, struct aim_fileheader_t *); + va_end(ap); + + dvprintf("faimtest: sending listing of size %ld\n", fh->size); + + if(!(buf = malloc(2048))) + return -1; + + for(pos = 0; pos < fh->size; pos++) { + + bufpos = pos % bufsize; + + if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */ + if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) { + dperror("faim: getfile_send: write1"); + dprintf("faim: getfile_send: whoopsy, didn't write it all...\n"); + free(buf); + return 0; + } + } + if( (buf[bufpos] = fgetc(priv->listingfile)) == EOF) { + if(pos != fh->size) { + dvprintf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size); + free(buf); + return 0; + } + } + } + + if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) { + dperror("faim: getfile_send: write2"); + dprintf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n"); + free(buf); + return 0; + } + + dprintf("faimtest: sent listing\n"); + free(buf); + + return 0; +} + +static int faimtest_getfile_receive(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + aim_conn_t *conn; + struct aim_filetransfer_priv *ft; + unsigned char data; + int pos; + + va_start(ap, fr); + conn = va_arg(ap, aim_conn_t *); + ft = va_arg(ap, struct aim_filetransfer_priv *); + va_end(ap); + + dvprintf("faimtest: receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name); + + for(pos = 0; pos < ft->fh.size; pos++) { + read(conn->fd, &data, 1); + printf("%c(%02x) ", data, data); + } + + printf("\n"); + + aim_oft_getfile_end(sess, conn); + + return 0; +} + +static int faimtest_getfile_state4(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + aim_conn_t *conn; + + va_start(ap, fr); + conn = va_arg(ap, aim_conn_t *); + va_end(ap); + + aim_conn_close(conn); + aim_conn_kill(sess, &conn); + + return 0; +} + +static int faimtest_getfile_initiate(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + aim_conn_t *conn, *listenerconn; + struct aim_filetransfer_priv *priv; + + va_start(ap, fr); + conn = va_arg(ap, aim_conn_t *); + listenerconn = va_arg(ap, aim_conn_t *); + va_end(ap); + + aim_conn_close(listenerconn); + aim_conn_kill(sess, &listenerconn); + + aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ, faimtest_getfile_filereq, 0); + aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0); + aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0); + aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0); + aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0); + aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0); + aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE, faimtest_getfile_receive, 0); + aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4, faimtest_getfile_state4, 0); + + priv = (struct aim_filetransfer_priv *)conn->priv; + + dvprintf("faimtest: getfile: %s (%s) connected to us on %d\n", priv->sn, priv->ip, conn->fd); + + return 1; +} + +void getfile_start(aim_session_t *sess, aim_conn_t *conn, const char *sn) +{ + aim_conn_t *newconn; + + newconn = aim_getfile_initiate(sess, conn, sn); + dvprintf("faimtest: getting file listing from %s\n", sn); + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE, faimtest_getfile_initiate,0); + + return; +} + +void getfile_requested(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args) +{ + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + aim_conn_t *newconn; + struct aim_fileheader_t *fh; + + dvprintf("faimtest: get file request from %s (at %s) %x\n", userinfo->sn, args->info.getfile.ip, args->reqclass); + + fh = aim_getlisting(sess, priv->listingfile); + + newconn = aim_accepttransfer(sess, conn, userinfo->sn, args->info.getfile.cookie, args->info.getfile.ip, fh->totfiles, fh->totsize, fh->size, fh->checksum, args->reqclass); + + free(fh); + + if ( (!newconn) || (newconn->fd == -1) ) { + + dprintf("faimtest: getfile: requestconn: apparent error in accepttransfer\n"); + + if (newconn) + aim_conn_kill(sess, &newconn); + + return; + } + + + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0); + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ, faimtest_getfile_filereq, 0); + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0); + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0); + + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0); + + dprintf("faimtest: getfile connect succeeded, handlers added.\n"); + + return; +} + +void directim_start(aim_session_t *sess, aim_conn_t *conn, const char *sn) +{ + aim_conn_t *newconn; + + printf("faimtest: opening directim to %s\n", sn); + + newconn = aim_directim_initiate(sess, conn, NULL, sn); + + if (!newconn || (newconn->fd == -1)) { + + printf("connection failed!\n"); + + if (newconn) + aim_conn_kill(sess, &newconn); + + } else + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, faimtest_directim_initiate, 0); + + return; +} + +void directim_requested(aim_session_t *sess, aim_conn_t *conn, struct aim_userinfo_s *userinfo, struct aim_incomingim_ch2_args *args) +{ + aim_conn_t *newconn; + + + dvprintf("faimtest: OFT: DirectIM: request from %s (%s)\n", userinfo->sn, args->info.directim->ip); + + /* XXX why does these need conn? */ + newconn = aim_directim_connect(sess, conn, args->info.directim); + + if (!newconn || (newconn->fd == -1)) { + dprintf("faimtest: icbm: imimage: could not connect\n"); + + if (newconn) + aim_conn_kill(sess, &newconn); + } else { + + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, faimtest_directim_incoming, 0); + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMDISCONNECT, faimtest_directim_disconnect, 0); + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, faimtest_directim_typing, 0); + + dvprintf("faimtest: OFT: DirectIM: connected to %s\n", userinfo->sn); + + aim_send_im_direct(sess, newconn, "goodday"); + } + +} + diff --git a/utils/faimtest/login.c b/utils/faimtest/login.c new file mode 100644 index 0000000..bacf297 --- /dev/null +++ b/utils/faimtest/login.c @@ -0,0 +1,192 @@ +/* + * Most of the stuff used for login. + * + */ + +#include "faimtest.h" + +int logout(aim_session_t *sess) +{ + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + + if (priv->ohcaptainmycaptain) + aim_send_im(sess, aim_getconn_type(sess, AIM_CONN_TYPE_BOS), priv->ohcaptainmycaptain, 0, "ta ta..."); + + aim_session_kill(sess); + + if (faimtest_init() == -1) + dprintf("faimtest_init failed\n"); + + return 0; +} + +static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...) +{ + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD; + char *key; + va_list ap; + + va_start(ap, fr); + key = va_arg(ap, char *); + va_end(ap); + + aim_send_login(sess, fr->conn, priv->screenname, priv->password, &info, key); + + return 1; +} + +/* Does this thing even work anymore? */ +static int faimtest_debugconn_connect(aim_session_t *sess, aim_frame_t *fr, ...) +{ + + dprintf("faimtest: connecting to an aimdebugd!\n"); + + /* convert the authorizer connection to a BOS connection */ + fr->conn->type = AIM_CONN_TYPE_BOS; + +#if 0 + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0); +#endif + + /* tell the aimddebugd we're ready */ + aim_debugconn_sendconnect(sess, fr->conn); + + /* go right into main loop (don't open a BOS connection, etc) */ + return 1; +} + + +/* + * This marks the end of authorization, and probably the beginning of BOS. + * + * If there was an error, everything ends here. Otherwise, we use the cookie + * and IP from the authorizer to connect to our assigned BOS. This connection + * will be used for the major stuff. New connections may be opened later for + * things like chat. + * + */ +static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...) +{ + va_list ap; + aim_conn_t *bosconn; + char *sn, *bosip, *errurl, *email; + fu8_t *cookie; + int errorcode, regstatus; + int latestbuild, latestbetabuild; + char *latestrelease, *latestbeta; + char *latestreleaseurl, *latestbetaurl; + char *latestreleaseinfo, *latestbetainfo; + + va_start(ap, fr); + sn = va_arg(ap, char *); + errorcode = va_arg(ap, int); + errurl = va_arg(ap, char *); + regstatus = va_arg(ap, int); + email = va_arg(ap, char *); + bosip = va_arg(ap, char *); + cookie = va_arg(ap, unsigned char *); + + latestrelease = va_arg(ap, char *); + latestbuild = va_arg(ap, int); + latestreleaseurl = va_arg(ap, char *); + latestreleaseinfo = va_arg(ap, char *); + + latestbeta = va_arg(ap, char *); + latestbetabuild = va_arg(ap, int); + latestbetaurl = va_arg(ap, char *); + latestbetainfo = va_arg(ap, char *); + + va_end(ap); + + dvprintf("Screen name: %s\n", sn); + + /* + * Check for error. + */ + if (errorcode || !bosip || !cookie) { + dvprintf("Login Error Code 0x%04x\n", errorcode); + dvprintf("Error URL: %s\n", errurl); + //aim_conn_kill(sess, &fr->conn); + return 1; + } + + dvprintf("Reg status: %2d\n", regstatus); + dvprintf("Email: %s\n", email); + dvprintf("BOS IP: %s\n", bosip); + + if (latestbeta) + dvprintf("Latest beta version: %s, build %d, at %s (more info at %s)\n", latestbeta, latestbetabuild, latestbetaurl, latestbetainfo); + + if (latestrelease) + dvprintf("Latest released version: %s, build %d, at %s (more info at %s)\n", latestrelease, latestbuild, latestreleaseurl, latestreleaseinfo); + + dprintf("Closing auth connection...\n"); + aim_conn_kill(sess, &fr->conn); + + if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) { + dprintf("could not connect to BOS: internal error\n"); + return 1; + } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) { + dprintf("could not connect to BOS\n"); + aim_conn_kill(sess, &bosconn); + return 1; + } + + addcb_bos(sess, bosconn); + + aim_auth_sendcookie(sess, bosconn, cookie); + + return 1; +} + +int login(aim_session_t *sess, const char *sn, const char *passwd) +{ + struct faimtest_priv *priv = (struct faimtest_priv *)sess->aux_data; + aim_conn_t *authconn; + + if (sn) + priv->screenname = strdup(sn); + if (passwd) + priv->password = strdup(passwd); + + if (priv->proxy) + aim_setupproxy(sess, priv->proxy, priv->proxyusername, priv->proxypass); + + if (!priv->screenname || !priv->password) { + dprintf("need SN and password\n"); + return -1; + } + + if (!(authconn = aim_newconn(&aimsess, AIM_CONN_TYPE_AUTH, + priv->server ? priv->server : FAIM_LOGIN_SERVER))) { + dprintf("internal connection error during login\n"); + return -1; + } else if (authconn->fd == -1) { + + if (authconn->status & AIM_CONN_STATUS_RESOLVERR) { + dprintf("could not resolve authorizer name\n"); + } else if (authconn->status & AIM_CONN_STATUS_CONNERR) { + dprintf("could not connect to authorizer\n"); + } + aim_conn_kill(sess, &authconn); + + return -1; + } + + aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0); + aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0); + aim_conn_addhandler(sess, authconn, 0x0017, 0x0007, faimtest_parse_login, 0); + aim_conn_addhandler(sess, authconn, 0x0017, 0x0003, faimtest_parse_authresp, 0); + + aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT, faimtest_debugconn_connect, 0); + + /* If the connection is in progress, this will just be queued */ + aim_request_login(sess, authconn, priv->screenname); + + dprintf("login request sent\n"); + + return 0; +} + + -- 2.45.1