]> andersk Git - libfaim.git/commitdiff
- Mon Sep 3 18:48:26 PDT 2001
authormid <mid>
Sat, 8 Sep 2001 02:10:29 +0000 (02:10 +0000)
committermid <mid>
Sat, 8 Sep 2001 02:10:29 +0000 (02:10 +0000)
  - 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.

34 files changed:
CHANGES
include/aim.h
include/aim_internal.h
src/admin.c
src/adverts.c
src/auth.c
src/bos.c
src/buddylist.c
src/chat.c
src/chatnav.c
src/conn.c
src/ft.c
src/im.c
src/info.c
src/login.c
src/md5.c
src/meta.c
src/misc.c
src/msgcookie.c
src/rxhandlers.c
src/rxqueue.c
src/search.c
src/snac.c
src/stats.c
src/tlv.c
src/txqueue.c
src/util.c
utils/faimtest/Makefile.am
utils/faimtest/chat.c [new file with mode: 0644]
utils/faimtest/commands.c
utils/faimtest/faimtest.c
utils/faimtest/faimtest.h
utils/faimtest/ft.c [new file with mode: 0644]
utils/faimtest/login.c [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 864512c7d0673e83116b39f763fb9c25b8751d78..7506427dd8053bf8a16a633f9c8feee770df770b 100644 (file)
--- 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.
index 3148acff9b04acd4f38b457e880478911b2e4323..a12b95c91fdb47aa5b899a0345d84d300a97afe9 100644 (file)
 #include <sys/socket.h>
 #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 <pthread.h>
 #define faim_mutex_t pthread_mutex_t 
  * 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)
  *
  */
 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);
index fff1e52014466050c7282cac054ebe91c949d657..1c79bd51bf1860cf61eed81312c4ff70031e3217 100644 (file)
 #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
index 4a461b6aee09427b57715766b971a0d1b8550881..260c8fe67a39b567b4a7b710ea78c43fc6efd33c 100644 (file)
 #include <aim.h>
 
 /* called for both reply and change-reply */
-static int infochange(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen)
+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;
 }
index 3f717c6bf78d9583ad9404bc676817e3680c8e64..0c40e73f70141459ba8f90956a00ca96e3ab1f2f 100644 (file)
@@ -6,38 +6,34 @@
 #define FAIM_INTERNAL
 #include <aim.h>
 
-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);
 }
index 6db41c4a77ad5f5723dbce92ac37f6efa07e814d..ff1ad08a4c0d9dc98f2c83e11599a7a1e0d6b3e5 100644 (file)
@@ -1,33 +1,30 @@
 /*
-  aim_auth.c
-
-  Deals with the authorizer.
-
 aim_auth.c
+ *
* Deals with the authorizer.
+ *
  */
 
 #define FAIM_INTERNAL
 #include <aim.h> 
 
 /* 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;
 }
+
index 8d6810ba76fb280af426d66e7a2ba4d88233021c..3149111feb6b2ce0b096edc2970a8518a9e6b2bd 100644 (file)
--- a/src/bos.c
+++ b/src/bos.c
  * 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;
 }
+
+
index cebcb6fe39ad4fa255064375e0e87cc35f738a74..975fccf9dfa514603fa568f4334daafbdb17fec0 100644 (file)
  * 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;
 }
 
index 0a4820561024223ac54d21daf07314d36337253c..7a09c0b46221025aaec3e87b3f4fa88aa72dcc7c 100644 (file)
@@ -8,47 +8,50 @@
 #define FAIM_INTERNAL
 #include <aim.h> 
 
-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;
 }
+
+
index 1c0196ce831b79e0d2d88fb8110862d6fd1cdaf2..3551ab2c101235714410e4af715c63fa247fe439 100644 (file)
 /*
  * 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;
 }
index 517cb0c933ed55fd28dac2caf60caec0323ff1b6..0c6168671da0c54ac7854fb8d2f2738b12250892 100644 (file)
  * 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;
 
 }
 
index c9f4a9bc88b103c1742b5911ff6c59c63e9b80d3..fabd309dd03a512b0c3b0ff2124a631e4b7fca69 100644 (file)
--- 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 */
 }
+
index 143f4d765a04ab32317ec2c11cfcbc24e105bb0e..6494b6d2457fef9646d5da3e6f1b1295c8974d12 100644 (file)
--- a/src/im.c
+++ b/src/im.c
  *  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, &params);
 
        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;
index a36a7f52525f522d457cd9a8a1cbf56d784836b8..5ae956dd435eb66a4b3767b89328a25a67a68a9b 100644 (file)
@@ -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. 
  *
  */
 
 #include <aim.h>
 
 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 <darkagl@pcnet.com>
-       */
-    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 (z<len)
-         {
-           x = snprintf(tmpstr, sizeof(tmpstr), "userinfo:      ");
-           for (y = 0; y < 8; y++)
-             {
-               if (z<len)
-                 {
-                   snprintf(tmpstr+x, sizeof(tmpstr)-x, "%02x ", buf[i+4+z]);
-                   z++;
-                   x += 3;
-                 }
-               else
-                 break;
-             }
-           faimdprintf(sess, 0, "%s\n", tmpstr);
-         }
-      }
-      break;
-    }  
-    /*
-     * No matter what, TLV triplets should always look like this:
-     *
-     *   u_short type;
-     *   u_short length;
-     *   u_char  data[length];
-     *
-     */
-    if (lastvalid) {
-      i += (2 + 2 + aimutil_get16(&buf[i+2]));            
-      curtlv++;
-    }
-  }
-  
-  return i;
+       int curtlv, tlvcnt;
+       fu8_t snlen;
+
+       if (!bs || !outinfo)
+               return -EINVAL;
+
+       /* Clear out old data first */
+       memset(outinfo, 0x00, sizeof(struct aim_userinfo_s));
+
+       /*
+        * Screen name.  Stored as an unterminated string prepended with a 
+        * byte containing its length.
+        */
+       snlen = aimbs_get8(bs);
+       aimbs_getrawbuf(bs, outinfo->sn, snlen);
+
+       /*
+        * 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 <darkagl@pcnet.com>
+                        */
+                       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;
 }
index 041f823b5ab562ec63f5d010c1815adc7323d241..784ac1b8840122d9844443af08be6bcb91c6d704 100644 (file)
 
 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;
index 9b1ce6fa86ef91b2761434a089e9821b44ce89d9..e6273585be997a181f4faf8b05eb803515bcd29a 100644 (file)
--- a/src/md5.c
+++ b/src/md5.c
@@ -21,7 +21,6 @@
   ghost@aladdin.com
 
  */
-/*$Id$ */
 /*
   Independent implementation of MD5 (RFC 1321).
 
index 55fff2abe39e02e8c62792ee9db023699f572947..5f40129b4c98f7c558514279ead15fddd88713c8 100644 (file)
@@ -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;
 }
+
index 4f1a229c687058bc04713916d1c5721a09ecb2fc..acc65be1f7ec3e9d6af7e867b3925a4b03ec0007 100644 (file)
  *  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;
 }
index 5ffa5902bc734e6d88ce9854dc4572aac2e02e6e..50f186ffffd1992e90bd9563f6dfaf31c8c27e84 100644 (file)
  * 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;
+       }           
 }
+
+
index 19baded0cf9071f1bbf2c8f02eb9dab7386e34af..33b51f0d8e547200858a082acd715b14141d62b3 100644 (file)
 #define FAIM_INTERNAL
 #include <aim.h>
 
-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;
-}
 
index d177c8278f5bcc18e53d2a971ddb74167b490256..be2a85e9a07c33ce89de7761c91de6029e1533e4 100644 (file)
 #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;
 }
+
index 0a5966273f9993a2c09f65d42af424655f599f4a..32793096cebc177d579f57c7fb6ea39589b43387 100644 (file)
 #define FAIM_INTERNAL
 #include <aim.h>
 
-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;
 }
+
+
index 96f288fb48685b8f01385626f65d57b9bd3a836a..4ab1bbbf0f88199ca0cb453096ac121e38d0cf1b 100644 (file)
 /*
  * 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;
 }
index 523305c5ad2f1f6b5eb6d8cd3be40b0302b4ac09..ae3101e869d9e24276a5ef8803694fb404275b7e 100644 (file)
@@ -2,36 +2,36 @@
 #define FAIM_INTERNAL
 #include <aim.h>
 
-static int reportinterval(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen)
+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;
 }
index 5d7deee8a3bb523c1aa1cfc8f359ebd1faf73c27..e7d27ab28444d4b06c84b8ef35da123dd6102252 100644 (file)
--- a/src/tlv.c
+++ b/src/tlv.c
@@ -2,6 +2,30 @@
 #define FAIM_INTERNAL
 #include <aim.h>
 
+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
  * 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
+
index 49a669f870a0f3fec0c9a62a084f7cde6d59aeee..0d28b0e6e66a2f4897beb4b8b9ac678c308e2eb5 100644 (file)
  * 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;
 }
-    
-      
+
+
index e859400c4638329f4b0134ec69a1f8c4bf5337d3..b6080910902ee2aca1ebb19abf2d731969dbb4a8 100644 (file)
@@ -7,62 +7,10 @@
 #include <aim.h>
 #include <ctype.h>
 
-#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;
 }
+
+
index c07f0f49cb8066b5a7185e2dd7a5454cf2da1fc4..b2107ec4cdc716cff342239fcdfbb25475d02fe7 100644 (file)
@@ -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 (file)
index 0000000..31ce24b
--- /dev/null
@@ -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; 
+}
+
+
+
index ec57c8225b88937e088c675976e3087290a5eeaa..2cad4de52dfd9e6b2ca5da5c6ac14e4358271c17 100644 (file)
@@ -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;
 }
+
+
index 0c8264a0acf835b57cff7cbb8cd5f35769e4cda9..2ad710b3999c479aeb06914b06996d2493cd9c87 100644 (file)
 /* 
- *  -----------------------------------------------------------
- *  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 <sys/stat.h>
 
-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.<br>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.<br>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, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
+               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");
 
-       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, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
+       } else if (args->reqclass == 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, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
+               dvprintf("faimtest: Buddy Icon from %s, length = %u\n", userinfo->sn, 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, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
+       if (channel == 1)
+               ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, 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, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
 
        return 1;
 }
 
-int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
 {
        va_list ap;
-       struct aim_userinfo_s *userinfo;
-       char *msg;
-       char tmpbuf[1152];
+       char *destsn;
+       fu16_t reason;
 
-       va_start(ap, command);
-       userinfo = va_arg(ap, struct aim_userinfo_s *); 
-       msg = va_arg(ap, char *);
+       va_start(ap, fr);
+       reason = va_arg(ap, fu16_t);
+       destsn = va_arg(ap, char *);
        va_end(ap);
 
-       dvprintf("faimtest: chat: %s: incoming msg from %s: %s\n", (char *)command->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, command->conn, 0, tmpbuf, strlen(tmpbuf));
-       }
+       dvprintf("faimtest: message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
 
        return 1;
 }
 
-int faimtest_chatnav_info(struct aim_session_t *sess, struct command_rx_struct *command, ...)
-{
-  unsigned short type;
-  va_list ap;
-
-  va_start(ap, command);
-  type = va_arg(ap, int);
-
-  switch(type) {
-  case 0x0002: {
-    int maxrooms;
-    struct aim_chat_exchangeinfo *exchanges;
-    int exchangecount,i = 0;
-    
-    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);
-    }
-    
-  }
-  break;
-  case 0x0008: {
-    char *fqcn, *name, *ck;
-    unsigned short instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
-    unsigned char createperms;
-    unsigned long createtime;
-
-    fqcn = va_arg(ap, char *);
-    instance = va_arg(ap, int);
-    exchange = va_arg(ap, int);
-    flags = va_arg(ap, int);
-    createtime = va_arg(ap, unsigned long);
-    maxmsglen = va_arg(ap, int);
-    maxoccupancy = va_arg(ap, int);
-    createperms = va_arg(ap, int);
-    unknown = va_arg(ap, int);
-    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);
-  }
-  break;
-  default:
-    va_end(ap);
-    dvprintf("faimtest: chatnav info: unknown type (%04x)\n", type);
-  }
-  return 1;
-}
-
-int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
 {
        va_list ap;
-       unsigned short code;
-       char *msg = NULL;
+       char *destsn;
+       fu16_t reason;
 
-       va_start(ap, command);
-       code = va_arg(ap, int);
-       msg = va_arg(ap, char *);
+       va_start(ap, fr);
+       reason = va_arg(ap, fu16_t);
+       destsn = va_arg(ap, char *);
        va_end(ap);
 
-       dvprintf("faimtest: connerr: Code 0x%04x: %s\n", code, msg);
-       aim_conn_kill(sess, &command->conn); /* this will break the main loop */
-
-       connected = 0;
+       dvprintf("faimtest: user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown");
 
        return 1;
 }
 
-int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
-{      
-       dprintf("faimtest: connecting to an aimdebugd!\n");
+static int faimtest_parse_misses(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;
 
-       /* convert the authorizer connection to a BOS connection */
-       command->conn->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, (reason<missedreasonslen)?missedreasons[reason]:"unknown");
 
-       /* go right into main loop (don't open a BOS connection, etc) */
        return 1;
 }
 
 /*
  * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
  */
-int faimtest_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
 {
        va_list ap;
-       unsigned short type;
+       fu16_t type;
        char *sn = NULL;
 
-       va_start(ap, command);
-       type = va_arg(ap, int);
+       va_start(ap, fr);
+       type = va_arg(ap, fu16_t);
        sn = va_arg(ap, char *);
        va_end(ap);
 
@@ -2153,387 +1471,99 @@ int faimtest_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *
        return 1;
 }
 
-int faimtest_getfile_filereq(struct aim_session_t *ses, struct command_rx_struct *command, ...)
+static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
 {
+       static char *codes[5] = {
+               "invalid",
+               "change",
+               "warning",
+               "limit",
+               "limit cleared"
+       };
        va_list ap;
-       struct aim_conn_t *oftconn;
-       struct aim_fileheader_t *fh;
-       char *cookie;
-
-       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: request for file %s.\n", fh->name);
-
-       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;
+}
+
index 15fc33c9637c1c0d3be37a85c98c98f30fc3342e..abd95eec1d561bb97e7de6a1f4e008a0f62c1d52 100644 (file)
@@ -4,13 +4,76 @@
 #include <aim.h> 
 
 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 (file)
index 0000000..c7168e6
--- /dev/null
@@ -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 (file)
index 0000000..bacf297
--- /dev/null
@@ -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;
+}
+
+
This page took 0.975338 seconds and 5 git commands to generate.