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.
#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, \
}
/*
#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() */
/*
#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
* 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" */
*/
/* 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 */
#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
#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 {
} 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
#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
#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
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);
#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
#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
#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;
}
/*
* 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);
}
/*
* 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;
}
#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);
}
/*
- 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;
}
/*
* 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;
}
/*
* 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;
}
+
* 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;
}
+
+
* 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;
}
/*
* 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;
}
/*
* 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;
}
#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;
}
/*
*
* 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;
}
/*
*
* 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.
*/
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++]);
}
/*
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;
}
/*
* 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;
}
+
+
/*
* 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;
}
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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 */
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/*
* 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;
}
#endif
+#if 0
+
/* TODO:
o look for memory leaks.. there's going to be shitloads, i'm sure.
*/
return ret;
}
-
+#endif
+
/**
* aim_send_im_direct - send IM client-to-client over established connection
* @sess: session to conn
* 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;
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;
}
}
}
newpacket->lock = 0;
aim_tx_enqueue(sess, newpacket);
+
return 0;
+#endif
}
/* XXX: give the client author the responsibility of setting up a
* @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;
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
faim_mutex_unlock(&sess->connlistlock);
return hit;
}
+#endif
/**
* aim_directim_connect - connect to buddy for directim
*
* 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)
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,
} faim_mutex_unlock(&sess->connlistlock);
return cur;
}
+#endif
/**
* aim_accepttransfer - accept a file transfer request
* @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;
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;
aim_tx_enqueue(sess, newpacket);
return newconn;
+#endif
}
/**
* 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;
faimdprintf(sess, 2, "faim: OFT: listing fh name %s / %s\n", fh->name, (fh->name+(strlen(fh->name))));
return fh;
+#endif
}
/**
* 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;
}
return listenfd;
#endif
+#endif
}
/**
* 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;
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;
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;
}
if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) {
newoft->lock = 0;
- aim_tx_destroy(newoft);
+ aim_frame_destroy(newoft);
return -1;
}
if (!(newoft->hdr.oft.hdr2 = calloc(1,newoft->hdr.oft.hdr2len))) {
newoft->lock = 0;
- aim_tx_destroy(newoft);
+ aim_frame_destroy(newoft);
return -1;
}
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
i += 64;
return fh;
}
+#endif
/**
* aim_oft_checksum - calculate oft checksum of buffer
* 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++) {
*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
* 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)
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
*
* 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;
faimdprintf(sess, 2,"faim: listening (fd = %d, unconnected)\n", newconn->fd);
return newconn;
+#endif
}
/**
*
* 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)
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;
}
aim_tx_enqueue(sess, newoft);
return 0;
+#endif
}
/**
* 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;
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;
}
newoft->lock = 0;
aim_tx_enqueue(sess, newoft);
return 0;
+#endif
}
/**
* 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;
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;
}
aim_tx_enqueue(sess, newoft);
return 0;
+#endif /* 0 */
}
+
* 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}
};
}
/* 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)
* 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;
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
* 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?
* 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
* 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;
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
* 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));
* 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)
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) &&
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 */
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) {
} 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));
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
* 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;
}
*
* 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) {
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 */
* 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);
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;
}
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);
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);
} 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;
}
} 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;
}
* 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));
* 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.
* 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;
}
/*
* 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.
*/
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);
* 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;
}
* Request ICBM parameter information.
*
*/
-faim_export unsigned long aim_reqicbmparams(struct aim_session_t *sess, struct aim_conn_t *conn)
+faim_export int aim_reqicbmparams(aim_session_t *sess, aim_conn_t *conn)
{
return aim_genericreq_n(sess, conn, 0x0004, 0x0004);
}
/*
*
+ * I definitly recommend sending this. If you don't, you'll be stuck
+ * with the rather unreasonable defaults. You don't want those. Send this.
+ *
*/
-faim_export unsigned long aim_seticbmparam(struct aim_session_t *sess, struct aim_conn_t *conn, struct aim_icbmparameters *params)
+faim_export int aim_seticbmparam(aim_session_t *sess, aim_conn_t *conn, struct aim_icbmparameters *params)
{
- struct command_tx_struct *newpacket;
- int curbyte;
+ aim_frame_t *fr;
+ aim_snacid_t snacid;
if (!sess || !conn || !params)
return -EINVAL;
- if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+16)))
+ if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+16)))
return -ENOMEM;
- newpacket->lock = 1;
+ snacid = aim_cachesnac(sess, 0x0004, 0x0002, 0x0000, NULL, 0);
+ aim_putsnac(&fr->data, 0x0004, 0x0002, 0x0000, snacid);
- curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0002, 0x0000, sess->snac_nextid++);
-
- /* This is read-only (in Parameter Reply). Must be set to zero here. */
- curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
+ /* This is read-only (see Parameter Reply). Must be set to zero here. */
+ aimbs_put16(&fr->data, 0x0000);
/* These are all read-write */
- curbyte += aimutil_put32(newpacket->data+curbyte, params->flags);
- curbyte += aimutil_put16(newpacket->data+curbyte, params->maxmsglen);
- curbyte += aimutil_put16(newpacket->data+curbyte, params->maxsenderwarn);
- curbyte += aimutil_put16(newpacket->data+curbyte, params->maxrecverwarn);
- curbyte += aimutil_put32(newpacket->data+curbyte, params->minmsginterval);
+ aimbs_put32(&fr->data, params->flags);
+ aimbs_put16(&fr->data, params->maxmsglen);
+ aimbs_put16(&fr->data, params->maxsenderwarn);
+ aimbs_put16(&fr->data, params->maxrecverwarn);
+ aimbs_put32(&fr->data, params->minmsginterval);
- newpacket->lock = 0;
- aim_tx_enqueue(sess, newpacket);
+ aim_tx_enqueue(sess, fr);
return 0;
}
-static int paraminfo(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen)
+static int paraminfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
struct aim_icbmparameters params;
aim_rxcallback_t userfunc;
- int i = 0;
-
- params.maxchan = aimutil_get16(data+i);
- i += 2;
-
- params.flags = aimutil_get32(data+i);
- i += 4;
-
- params.maxmsglen = aimutil_get16(data+i);
- i += 2;
-
- params.maxsenderwarn = aimutil_get16(data+i);
- i += 2;
-
- params.maxrecverwarn = aimutil_get16(data+i);
- i += 2;
-
- params.minmsginterval = aimutil_get32(data+i);
- i += 4;
+ params.maxchan = aimbs_get16(bs);
+ params.flags = aimbs_get32(bs);
+ params.maxmsglen = aimbs_get16(bs);
+ params.maxsenderwarn = aimbs_get16(bs);
+ params.maxrecverwarn = aimbs_get16(bs);
+ params.minmsginterval = aimbs_get32(bs);
+
if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
return userfunc(sess, rx, ¶ms);
return 0;
}
-static int missedcall(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen)
+static int missedcall(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
{
- int i, ret = 0;
+ int ret = 0;
aim_rxcallback_t userfunc;
- unsigned short channel, nummissed, reason;
+ fu16_t channel, nummissed, reason;
struct aim_userinfo_s userinfo;
-
- for (i = 0; i < datalen; ) {
-
- /* Channel ID. */
- channel = aimutil_get16(data+i);
- i += 2;
- /* Extract the standard user info block. */
- i += aim_extractuserinfo(sess, data+i, &userinfo);
+ while (aim_bstream_empty(bs)) {
- nummissed = aimutil_get16(data+i);
- i += 2;
-
- reason = aimutil_get16(data+i);
- i += 2;
+ channel = aimbs_get16(bs);
+ aim_extractuserinfo(sess, bs, &userinfo);
+ nummissed = aimbs_get16(bs);
+ reason = aimbs_get16(bs);
if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
ret = userfunc(sess, rx, channel, &userinfo, nummissed, reason);
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;
* 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;
}
/*
* 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);
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;
}
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;
}
/*
* 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;
* 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,
/*
* 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;
/*
* 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) ||
*/
/* 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;
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);
}
/* 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;
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);
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.
* 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);
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;
}
* 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");
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;
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
*/
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 {
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;
ghost@aladdin.com
*/
-/*$Id$ */
/*
Independent implementation of MD5 (RFC 1321).
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;
}
+
* 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);
}
* - 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;
}
* 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;
}
/*
*
*
*/
-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;
}
/*
* 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;
}
/*
* 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;
}
* 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);
}
/*
* 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);
}
/*
* 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;
}
/*
* 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);
}
/*
* 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);
}
/*
* 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;
}
*
* 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);
}
/*
* 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;
}
/*
* 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;
}
* 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;
}
/**
*
* 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;
}
/**
* 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;
}
/**
*
*/
-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
* 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;
+ }
}
+
+
#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;
-}
#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;
}
/*
* 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;
}
/*
* 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;
}
+
#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;
}
+
+
/*
* 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;
}
/*
* 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;
}
/*
* 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;
}
#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;
}
#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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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);
}
/**
* 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);
}
/**
* %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);
}
/**
* 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;
}
/**
* 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 */
}
* 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;
}
/**
* 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;
}
/**
* 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);
}
/**
* 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);
}
/**
* 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
* 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);
}
/**
* 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
* 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
+
* 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;
}
/*
* 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;
}
/*
* 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);
}
/*
* 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;
}
/*
* 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;
}
/**
* 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;
}
-
-
+
+
#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;
}
/*
*/
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;
}
+
+
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
--- /dev/null
+
+#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;
+}
+
+
+
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;
}
+
+
/*
- * -----------------------------------------------------------
- * 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);
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
* 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)
* 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;
}
#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");
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:
/* 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);
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);
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);
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));
}
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);
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);
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: ");
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;
}
/*
* 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! */
}
/*
* 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);
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);
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 *);
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);
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;
+}
+
#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__ */
--- /dev/null
+
+#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");
+ }
+
+}
+
--- /dev/null
+/*
+ * 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;
+}
+
+