+ 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, ...)
+{
+ printf("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;
+}
+
+/*
+ * Recieved 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);
+
+ printf("faimtest: msgack: 0x%04x / %s\n", type, sn);
+
+ return 1;
+}
+
+#ifdef FILESUPPORT
+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);
+
+ printf("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;
+
+ 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);
+
+ printf("faimtest: sending file %s.\n", fh->name);
+
+ if( (path = (char *)calloc(1, strlen(sess->oft.listingdir) +strlen(fh->name)+2)) == NULL) {
+ perror("calloc:");
+ printf("faimtest: error in calloc of path\n");
+ return 0; /* XXX: no idea what winaim expects here =) */
+ }
+
+ snprintf(path, strlen(sess->oft.listingdir)+strlen(fh->name)+2, "%s/%s", sess->oft.listingdir, fh->name);
+
+
+ if( (file = fopen(path, "r")) == NULL) {
+ printf("faimtest: getfile_send fopen failed for %s. damn.\n", path);
+ return 0;
+ }
+
+ if (aim_getfile_send(oftconn, file, fh) == -1) {
+ printf("faimtest: getfile_send failed. damn.\n");
+ } else {
+ printf("faimtest: looks like getfile went clean\n");
+ }
+
+ 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);
+
+ printf("faimtest: completed file transfer for %s.\n", fh->name);
+
+ /* aim_conn_kill(sess, &conn); */ /* we'll let winaim close the 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);
+
+ printf("faimtest: getfile: disconnected from %s\n", sn);
+ return 1;
+}
+#endif
+
+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);
+
+
+ printf("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.
+ */
+ printf("faimtest: evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous");