+
+int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ va_list ap;
+ struct aim_userinfo_s *userinfo;
+ int count = 0, i = 0;
+
+ va_start(ap, command);
+ 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 *)command->conn->priv);
+ while (i < count)
+ dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
+
+ return 1;
+}
+
+int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ va_list ap;
+ struct aim_userinfo_s *userinfo;
+ int count = 0, i = 0;
+
+ va_start(ap, command);
+ 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 *)command->conn->priv);
+
+ for (i = 0; i < count; )
+ dvprintf("faimtest: chat: %s: \t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
+
+ return 1;
+}
+
+int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ 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;
+ 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);
+ 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);
+
+ for (i = 0; i < usercount; )
+ dvprintf("faimtest: chat: %s: \t\t%s\n", (char *)command->conn->priv, userinfo[i++].sn);
+
+ 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: \tMax message length: %d bytes\n", (char *)command->conn->priv, maxmsglen);
+ 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);
+
+ return 1;
+}
+
+int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ va_list ap;
+ struct aim_userinfo_s *userinfo;
+ char *msg;
+ char tmpbuf[1152];
+
+ va_start(ap, command);
+ 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 *)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, tmpbuf);
+ }
+
+ 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, ...)
+{
+ va_list ap;
+ unsigned short code;
+ char *msg = NULL;
+
+ va_start(ap, command);
+ code = va_arg(ap, int);
+ msg = 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 */
+
+ return 1;
+}
+
+int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ dprintf("faimtest: connecting to an aimdebugd!\n");
+
+ /* convert the authorizer connection to a BOS connection */
+ command->conn->type = AIM_CONN_TYPE_BOS;
+
+ aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
+
+ /* tell the aimddebugd we're ready */
+ aim_debugconn_sendconnect(sess, command->conn);
+
+ /* 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, ...)
+{
+ va_list ap;
+ unsigned short type;
+ char *sn = NULL;
+
+ va_start(ap, command);
+ type = va_arg(ap, int);
+ sn = va_arg(ap, char *);
+ va_end(ap);
+
+ dvprintf("faimtest: msgack: 0x%04x / %s\n", type, sn);
+
+ return 1;
+}
+
+int faimtest_getfile_filereq(struct aim_session_t *ses, struct command_rx_struct *command, ...)
+{
+ 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");
+
+ 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;
+}
+
+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);
+
+ return 0;
+}
+
+int faimtest_getfile_state4(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ va_list ap;
+ struct aim_conn_t *conn;
+
+ va_start(ap, command);
+ conn = va_arg(ap, struct aim_conn_t *);
+ va_end(ap);
+
+ aim_conn_close(conn);
+ aim_conn_kill(sess, &conn);
+ return 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;
+}
+
+int faimtest_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ va_list ap;
+ int newevil;
+ struct aim_userinfo_s *userinfo;
+
+ va_start(ap, command);
+ newevil = va_arg(ap, int);
+ userinfo = va_arg(ap, struct aim_userinfo_s *);
+ va_end(ap);
+
+ /*
+ * Evil Notifications that are lacking userinfo->sn are anon-warns
+ * if they are an evil increases, but are not warnings at all if its
+ * a decrease (its the natural backoff happening).
+ *
+ * newevil is passed as an int representing the new evil value times
+ * ten.
+ */
+ dvprintf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");
+
+ return 1;
+}
+
+int faimtest_parse_searchreply(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ va_list ap;
+ char *address, *SNs;
+ int i, num;
+
+ va_start(ap, command);
+ address = va_arg(ap, char *);
+ num = va_arg(ap, int);
+ SNs = va_arg(ap, char *);
+ va_end(ap);
+
+ dvprintf("faimtest: E-Mail Search Results for %s: ", address);
+
+ for(i = 0; i < num; i++)
+ dvinlineprintf("%s, ", &SNs[i*(MAXSNLEN+1)]);
+ dinlineprintf("\n");
+
+ return 1;
+}
+
+int faimtest_parse_searcherror(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ va_list ap;
+ char *address;
+
+ va_start(ap, command);
+ address = va_arg(ap, char *);
+ va_end(ap);
+
+ dvprintf("faimtest: E-Mail Search Results for %s: No Results or Invalid Email\n", address);
+
+ return 1;
+}