No release numbers
------------------
+ - Mon Jun 26 07:53:02 UTC 2000
+ - Added utils/aimdebugd for playing with things -- see the README
+ - Added aim_im.c::aim_parse_outgoing_im(). Probably not useful
+ unless you're writing a server or something (or hacking aimdebugd).
+ - aim_send_im() now sends the same data as AIM4 does (three more bytes)
+ - Added aim_debugconn_sendconnect() for aimdebugd-enablement.
+
- Sat Jun 24 02:14:07 UTC 2000
- Added fakelocks for platforms without pthreads or that have no
use for them.
* metaTLV start.
*/
curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
- curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg) + 0x0d);
+ curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg) + 0x10);
/*
- * Flag data?
+ * Flag data / ICBM Parameters?
*/
- curbyte += aimutil_put16(newpacket->data+curbyte, 0x0501);
- curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
+ curbyte += aimutil_put8(newpacket->data+curbyte, 0x05);
+ curbyte += aimutil_put8(newpacket->data+curbyte, 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);
+
curbyte += aimutil_put16(newpacket->data+curbyte, 0x0101);
- curbyte += aimutil_put8 (newpacket->data+curbyte, 0x01);
/*
* Message block length.
return 0;
}
+int aim_parse_outgoing_im_middle(struct aim_session_t *sess,
+ struct command_rx_struct *command)
+{
+ unsigned int i = 0, z;
+ rxcallback_t userfunc = NULL;
+ 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;
+
+ i = 10;
+
+ /* ICBM Cookie. */
+ for (z=0; z<8; z++,i++)
+ cookie[z] = command->data[i];
+
+ /* Channel ID */
+ channel = aimutil_get16(command->data+i);
+ i += 2;
+
+ if (channel != 0x01) {
+ printf("faim: icbm: ICBM recieved on unsupported channel. Ignoring. (chan = %04x)\n", channel);
+ return 1;
+ }
+
+ strncpy(sn, command->data+i+1, (int) *(command->data+i));
+ i += 1 + (int) *(command->data+i);
+
+ tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i);
+
+ if (aim_gettlv(tlvlist, 0x0003, 1))
+ icbmflags |= AIM_IMFLAGS_ACK;
+ if (aim_gettlv(tlvlist, 0x0004, 1))
+ icbmflags |= AIM_IMFLAGS_AWAY;
+
+ if (aim_gettlv(tlvlist, 0x0002, 1)) {
+ int j = 0;
+
+ msgblock = aim_gettlv_str(tlvlist, 0x0002, 1);
+
+ /* no, this really is correct. I'm not high or anything either. */
+ j += 2;
+ j += 2 + aimutil_get16(msgblock+j);
+ j += 2;
+
+ j += 2; /* final block length */
+
+ flag1 = aimutil_get16(msgblock);
+ j += 2;
+ flag2 = aimutil_get16(msgblock);
+ j += 2;
+
+ msg = msgblock+j;
+ }
+
+ if ((userfunc = aim_callhandler(command->conn, 0x0004, 0x0006)) || (i = 0))
+ i = userfunc(sess, command, channel, sn, msg, icbmflags, flag1, flag2);
+
+ if (msgblock)
+ free(msgblock);
+ aim_freetlvchain(&tlvlist);
+
+ return 0;
+}
+
/*
* It can easily be said that parsing ICBMs is THE single
* most difficult thing to do in the in AIM protocol. In
return aim_genericreq_n(sess, conn, 0x0003, 0x0002);
}
+/*
+ * aim_debugconn_sendconnect()
+ *
+ * For aimdebugd. If you don't know what it is, you don't want to.
+ */
+u_long aim_debugconn_sendconnect(struct aim_session_t *sess,
+ struct aim_conn_t *conn)
+{
+ return aim_genericreq_n(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT);
+}
+
/*
* Generic routine for sending commands.
*
if (subtype == 0x0005)
workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
break;
+ case AIM_CB_FAM_SPECIAL:
+ if (subtype == AIM_CB_SPECIAL_DEBUGCONN_CONNECT) {
+ workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
+ break;
+ } /* others fall through */
default:
/* Old login protocol */
/* any user callbacks will be called from here */
case 0x0005:
workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
break;
+ case 0x0006:
+ workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr);
+ break;
case 0x0007:
workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
break;
else
workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
break;
+ case AIM_CB_FAM_SPECIAL:
+ workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
+ break;
default:
workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
break;
*/
int aim_get_command(struct aim_session_t *, struct aim_conn_t *);
int aim_rxdispatch(struct aim_session_t *);
-
+u_long aim_debugconn_sendconnect(struct aim_session_t *sess,
+ struct aim_conn_t *conn);
int aim_logoff(struct aim_session_t *);
void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn);
u_long aim_send_im(struct aim_session_t *, struct aim_conn_t *, char *, u_int, char *);
int aim_parse_incoming_im_middle(struct aim_session_t *, struct command_rx_struct *);
+int aim_parse_outgoing_im_middle(struct aim_session_t *, struct command_rx_struct *);
u_long aim_seticbmparam(struct aim_session_t *, struct aim_conn_t *conn);
int aim_parse_msgerror_middle(struct aim_session_t *, struct command_rx_struct *);
int aim_negchan_middle(struct aim_session_t *sess, struct command_rx_struct *command);
#define AIM_CB_SPECIAL_AUTHSUCCESS 0x0001
#define AIM_CB_SPECIAL_AUTHOTHER 0x0002
#define AIM_CB_SPECIAL_CONNERR 0x0003
+#define AIM_CB_SPECIAL_DEBUGCONN_CONNECT 0xe001
#define AIM_CB_SPECIAL_UNKNOWN 0xffff
#define AIM_CB_SPECIAL_DEFAULT AIM_CB_SPECIAL_UNKNOWN
096d 6964 656e 6469 616e
0003 0000
-0002 003a 0501 0003 01 01 01 01 01
+0002 003a
+ 05
+ 01
+ 0003
+ 0101 01
+ 0101
002f 00
0000 00
G=47 o=6f o=6f d=64 =20 d=64 a=61 y=79
=20 t=74 o=6f =20 y=79 o=6f u=75 =20
t=74 o=6f o=6f .=2e
+
+---------
+
+ 2a02 602f 006f
+ 0004 0006 0000 0000 8001
+ 3135 3642 4538 3800
+ 0001
+ 06 xx xxxx xxxx xx
+ 0002 0050
+ 0501
+ 0004
+ 0101 0102
+ 0101
+ 0044
+ 0000 0000
+
+ 3c 4854
+ 4d4c 3e3c 424f 4459 2042 4743 4f4c 4f52
+ 3d22 2366 6666 6666 6622 3e3c 464f 4e54
+ 3e6b 3b73 616a 6466 3c2f 464f 4e54 3e3c
+ 2f42 4f44 593e 3c2f 4854 4d4c 3e
\ No newline at end of file
include Makefile.dynamicrules
-UTIL_DIRS = faimtest #aimdump aimpasswd
+UTIL_DIRS = faimtest aimdebugd #aimdump aimpasswd
utils_all:
@dirs='$(UTIL_DIRS)'; \
for i in $$dirs; do \
- cd $$i; \
- $(MAKE); \
- cd ..; \
+ $(MAKE) -C $$i; \
done;
clean:
@dirs='$(UTIL_DIRS)'; \
for i in $$dirs; do \
- cd $$i; \
- $(MAKE) clean; \
- cd ..; \
+ $(MAKE) -C $$i clean; \
done;
@rm -f Makefile.dynamicrules
--- /dev/null
+include ../Makefile.dynamicrules
+include $(LIBFAIM_LIB)/Makefile.rules
+
+EXEC_NAME = aimdebugd
+EXEC_OBJECTS = \
+ aimdebugd.o \
+ network.o \
+ file.o \
+ icbm.o
+
+all: $(EXEC_OBJECTS)
+ $(CC) $(CFLAGS) -o $(EXEC_NAME) $(EXEC_OBJECTS) $(LDFLAGS)
+
+clean:
+ rm -f *~ $(EXEC_OBJECTS) $(EXEC_NAME)
--- /dev/null
+
+aimdebugd. Slightly ambiguous name. Basically, its a
+micro-aim-server thats meant to be hacked. Its completely useless the
+way it is, but it does let you poke and prod at clients while they're
+in their main loop. It won't help for debugging the login process,
+but it will allow you to test various ICBM types, etc -- anything you
+want to implement packet handlers and transmitters for.
+
+How to make your client work with aimdebugd
+-------------------------------------------
+ 1. Create a handler for the debug connection SNAC like this:
+
+int debugconn_connect_handler(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+
+ printf("connecting to an aimdebugd!\n");
+
+ /* convert the authorizer connection to a BOS connection */
+ command->conn->type = AIM_CONN_TYPE_BOS;
+
+ /* You may want to add some of your BOS callbacks here */
+
+ /* tell the aimdebugd we're ready */
+ aim_debugconn_sendconnect(sess, command->conn);
+
+ /* go right into main loop (don't open a BOS connection, etc) */
+ return 1;
+}
+
+ 2. Connect the handler to your authorizer connection before
+ calling aim_send_login() or aim_select():
+
+ ...
+ aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL,
+ AIM_CB_SPECIAL_DEBUGCONN_CONNECT,
+ debugconn_connect_handler, 0);
+ ...
+
+ 3. Start your client with the authorizer host set to the box
+ running the aimddebugd.
+
+
+Writing Halfscripts
+-------------------
+
+Some hacking of aimdebugd can be done without writing any C. But it
+its write-only.
+
+Once aimdebugd gets the acknowledgment from the client, it can begin
+to run through a file (passed through a command line) that contains a
+listing of excruciatingly simple "commands" and react to it. The
+commandset is very small, and, as mentioned above, is write-only --
+its not event driven. The list of commands is executed linearly and
+does not stop until it hits the break command, hits the end of the
+file, hits the disconnect command, or the connection to the client
+dies.
+
+Commands:
+ # -- Comment
+ b -- Breaks execution, leaves connection open
+ d -- Disconnects from client (results in connection termination)
+ e <msg> -- Prints msg to stderr
+ m <srcsn>/<msg> -- Sends msg from srcsn to the client
+ s <seconds> -- Sleeps for an arbitrary number of seconds
+
+Note that the client must have callbacks connected to the appropriate
+handlers if it wants to react to any of the output from these commands
+(except 'e', thats just there).
+
+
+
--- /dev/null
+
+#include <faim/aim.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include "network.h"
+
+#define RUNNAME "aimdebugd"
+#define RUNPREFIX RUNNAME ": "
+
+typedef struct {
+ struct aim_session_t sess;
+} client_t;
+
+int stayalive = 1;
+
+int clientready = 0;
+int scriptfd = -1;
+
+void sigchld(int signum)
+{
+ pid_t pid;
+ int status;
+
+ pid = wait(&status);
+
+ return;
+}
+
+int cb_login(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ return 1;
+}
+
+int incomingim(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ int channel;
+ va_list ap;
+
+ va_start(ap, command);
+ channel = va_arg(ap, int);
+
+ if (channel == 1) {
+ char *sn = NULL;
+ char *msg = NULL;
+ u_int icbmflags = 0;
+ u_short flag1, flag2;
+
+ sn = va_arg(ap, char *);
+ msg = va_arg(ap, char *);
+ icbmflags = va_arg(ap, u_int);
+ flag1 = va_arg(ap, u_short);
+ flag2 = va_arg(ap, u_short);
+ va_end(ap);
+
+ printf("aimdebugd: client %d: %s/0x%04x/0x%02x/0x%02x/%s\n",
+ getpid(),
+ sn,
+ icbmflags, flag1,
+ flag2, msg);
+
+ } else
+ printf("aimdebugd: client %d: unsupported ICBM channel %d\n", getpid(), channel);
+
+ return 1;
+}
+
+int debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...)
+{
+ struct aim_conn_t *scriptconn;
+
+ clientready = 1;
+
+ if (!(scriptconn = aim_newconn(sess, 0, NULL))) {
+ printf(RUNPREFIX "unable to allocate script structures\n");
+ aim_logoff(sess);
+ return 1;
+ }
+ scriptconn->fd = scriptfd;
+
+ return 1;
+}
+
+int parsescriptline(struct aim_session_t *sess, struct aim_conn_t **conn); /* file.c */
+
+int handlechild(int fd, char *scriptname)
+{
+ int stayalive = 1, selstat;
+ client_t client;
+ struct aim_conn_t *inconn, *waitingconn;
+
+ aim_session_init(&client.sess);
+
+ if (!(inconn = aim_newconn(&client.sess, AIM_CONN_TYPE_BOS, NULL))) {
+ printf(RUNPREFIX "unable to allocate client structures\n");
+ exit(-1);
+ }
+ inconn->fd = fd;
+
+ if (scriptname) {
+ if (scriptname[0] == '-')
+ scriptfd = STDIN_FILENO;
+ else if ((scriptfd = open(scriptname, O_RDONLY)) < 0) {
+ perror(RUNPREFIX "open");
+ return -1;
+ }
+ }
+
+ aim_conn_addhandler(&client.sess, inconn, 0x0000, 0x0001, cb_login, 0);
+ aim_conn_addhandler(&client.sess, inconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT, debugconn_connect, 0);
+ aim_conn_addhandler(&client.sess, inconn, 0x0004, 0x0006, incomingim, 0);
+
+ aim_debugconn_sendconnect(&client.sess, inconn);
+
+ while (stayalive) {
+ waitingconn = aim_select(&client.sess, NULL, &selstat);
+
+ switch(selstat) {
+ case -1: /* error */
+ stayalive = 0; /* fall through and hit aim_logoff() */
+ break;
+ case 0: /* nothing pending */
+ break;
+ case 1: /* outgoing data pending */
+ aim_tx_flushqueue(&client.sess);
+ break;
+ case 2: /* incoming data pending */
+ if (waitingconn->fd == scriptfd) {
+ if (clientready) {
+ if (parsescriptline(&client.sess, &waitingconn) < 0) {
+ stayalive = 0;
+ }
+ }
+ } else {
+ if (aim_get_command(&client.sess, waitingconn) < 0) {
+ printf(RUNPREFIX "connection error\n");
+ stayalive = 0; /* fall through to aim_logoff() */
+ } else {
+ aim_rxdispatch(&client.sess);
+ }
+ }
+ break;
+ default: /* invalid */
+ break;
+ }
+ }
+
+ printf(RUNPREFIX "client disconnected\n");
+
+ aim_logoff(&client.sess);
+
+ return fd;
+}
+
+int main(int argc, char **argv)
+{
+ int listener = -1;
+ int client = -1;
+ int n;
+ char *scriptname = NULL;
+ int nofork = 0;
+ int runonce = 0, runsleft = 1;
+
+ while ((n = getopt(argc, argv, "c:noh")) != EOF) {
+ switch(n) {
+ case 'c':
+ scriptname = optarg;
+ break;
+ case 'n': /* don't fork */
+ nofork = 1;
+ break;
+ case 'o': /* run once only */
+ runonce = 1;
+ break;
+ usage:
+ case 'h':
+ printf("aimdebugd v0.10 -- Adam Fritzler (mid@auk.cx)\n");
+ printf("Usage:\n");
+ printf("\taimdebugd [-c file] [-n] [-o]\n");
+ printf("\t\t-c file\tScript file or - for stdin\n");
+ printf("\t\t-n\tDo not fork for each client, process serially\n");
+ printf("\t\t-o\tRun once and exit (required if script from stdin)\n");
+ printf("\n");
+ exit(2);
+ }
+ }
+
+ if (scriptname && (scriptname[0] == '-') && (!nofork || !runonce)) {
+ printf(RUNPREFIX "stdin script is not valid without -n and -o\n");
+ return -1;
+ }
+
+ printf(RUNPREFIX "starting\n");
+
+ signal(SIGCHLD, sigchld);
+
+ if ((listener = establish(5190)) < 0) {
+ perror(RUNPREFIX "establish");
+ exit(-1);
+ }
+
+ while (stayalive) {
+ if (runonce && !runsleft)
+ break;
+ if ((client = get_connection(listener)) < 0) {
+ perror(RUNPREFIX "get_connection");
+ stayalive = 0;
+ } else {
+ runsleft--;
+ if (nofork)
+ handlechild(client, scriptname);
+ else {
+ switch(fork()) {
+ case -1:
+ perror(RUNPREFIX "fork");
+ break;
+ case 0:
+ return handlechild(client, scriptname);
+ break;
+ default:
+ close(client); /* let the child have it */
+ break;
+ }
+ }
+ }
+ }
+
+ printf(RUNPREFIX "stopping\n");
+ return 0;
+}
--- /dev/null
+
+#include <faim/aim.h>
+
+static int readln(int fd, char *buf, int buflen)
+{
+ int i = 0;
+ int ret = 0;
+
+ while ((i < buflen) && ((ret = read(fd, buf, 1)) > 0)) {
+ if (*buf == '\n') {
+ *buf = '\0';
+ return i;
+ }
+ buf++;
+ i++;
+ }
+
+ if (ret == 0) {
+ *buf = '\0';
+ return i;
+ }
+
+ if (ret == -1)
+ perror("read");
+
+ return -1;
+}
+
+static inline char *killwhite(char *inbuf)
+{
+ char *buf;
+ buf = inbuf;
+ while(buf && ((*buf==' ') || (*buf=='\t'))) /* skip leading whitespace */
+ buf++;
+ return buf;
+}
+
+static inline char *nextwhite(char *inbuf)
+{
+ char *buf;
+ buf = inbuf;
+ while(buf) {
+ if ((*buf != ' '))
+ buf++;
+ else
+ return buf;
+ }
+ return buf;
+}
+
+int parsescriptline2(struct aim_session_t *sess, struct aim_conn_t **scriptconn, char *buf)
+{
+ if (!buf)
+ return 0;
+
+ switch (buf[0]) {
+ case '#': /* comment */
+ break;
+ case 'b': /* break */
+ aim_conn_kill(sess, scriptconn);
+ break;
+ case 'd': /* disconnect */
+ aim_conn_kill(sess, scriptconn);
+ aim_logoff(sess);
+ return -1;
+ break;
+ case 'e': /* print to stderr */
+ buf = nextwhite(buf)+1;
+ fprintf(stderr, "%s\n", buf);
+ break;
+ case 'm': /* message */
+ {
+ char *sn, *msg;
+ buf = nextwhite(buf)+1;
+ sn = strsep(&buf, "/");
+ msg = strsep(&buf, "/");
+ sendimtoclient(sess, aim_getconn_type(sess, AIM_CONN_TYPE_BOS), sn, 0, msg);
+ }
+ break;
+ case 's': /* sleep */
+ buf = nextwhite(buf)+1;
+ printf("sleeping for %d seconds\n", atoi(buf));
+ sleep(atoi(buf));
+ break;
+ default:
+ printf("unknown script command %c\n", buf[0]);
+ break;
+ }
+ return 0;
+}
+
+int parsescriptline(struct aim_session_t *sess, struct aim_conn_t **conn)
+{
+ char buf[256];
+ if (readln((*conn)->fd, buf, 255) > 0)
+ return parsescriptline2(sess, conn, buf);
+ else {
+ aim_conn_kill(sess, conn);
+ }
+ return 0;
+}
--- /dev/null
+
+#include <faim/aim.h>
+
+int sendimtoclient(struct aim_session_t *sess, struct aim_conn_t *conn,
+ char *srcsn, u_int flags, char *msg)
+{
+ struct command_tx_struct *tx;
+ struct aimd_clientinfo *client = NULL;
+ struct aim_tlvlist_t *tlvlist = NULL;
+ struct aim_tlvlist_t *tlvlist2 = NULL;
+ int i = 0, y, z;
+ char *msgblock;
+
+ if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, strlen(msg)+256)))
+ return -1;
+
+ tx->lock = 1;
+
+ msgblock = malloc(strlen(msg)+128); /* ?? */
+ memset(msgblock, 0, strlen(msg)+128);
+
+ z = 0;
+ z += aimutil_put8(msgblock+z, 0x00);
+ z += aimutil_put8(msgblock+z, 0x00);
+
+ z += aimutil_put16(msgblock+z, 0x02);
+ z += aimutil_put8(msgblock+z, 0x00);
+ z += aimutil_put8(msgblock+z, 0x00);
+
+ z += aimutil_put8(msgblock+z, 0x00);
+ z += aimutil_put8(msgblock+z, 0x00);
+
+ z += aimutil_put16(msgblock+z, strlen(msg)+4);
+ /* flag words */
+ z += aimutil_put16(msgblock+z, 0x0000);
+ z += aimutil_put16(msgblock+z, 0x0000);
+
+ /* msg */
+ z += aimutil_putstr(msgblock+z, msg, strlen(msg));
+
+ /*
+ * SNAC header
+ */
+ i = 0;
+ i += aimutil_put16(tx->data+i, 0x0004);
+ i += aimutil_put16(tx->data+i, 0x0007);
+ i += aimutil_put16(tx->data+i, 0x0000);
+ i += aimutil_put16(tx->data+i, 0x0000);
+ i += aimutil_put16(tx->data+i, 0x0000);
+
+ /*
+ * Message cookie
+ */
+ for (y=0;y<8;y++)
+ i += aimutil_put8(tx->data+i+y, (u_char) random());
+
+ /*
+ * Channel ID
+ */
+ i += aimutil_put16(tx->data+i, 0x0001);
+
+ /*
+ * Source SN
+ */
+ i += aimutil_put8(tx->data+i, strlen(srcsn));
+ i += aimutil_putstr(tx->data+i, srcsn, strlen(srcsn));
+
+ /*
+ * Warning level
+ */
+ i += aimutil_put16(tx->data+i, 0x0000);
+
+ /* class */
+ aim_addtlvtochain16(&tlvlist, 0x0001, AIM_CLASS_FREE | AIM_CLASS_TRIAL);
+
+ /* member-since date */
+ aim_addtlvtochain32(&tlvlist, 0x0002, 0);
+
+ /* on-since date */
+ aim_addtlvtochain32(&tlvlist, 0x0003, 0);
+
+ /* idle-time */
+ aim_addtlvtochain16(&tlvlist, 0x0004, 0);
+
+ /* session length (AIM) */
+ aim_addtlvtochain16(&tlvlist, 0x000f, 0);
+
+ /* add msgblock to chain */
+ aim_addtlvtochain_str(&tlvlist2, 0x0002, msgblock, z);
+
+ i += aimutil_put16(tx->data+i, aim_counttlvchain(&tlvlist));
+ i += aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist);
+ tx->commandlen = aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist2)+i;
+
+
+ free(msgblock);
+ aim_freetlvchain(&tlvlist);
+
+ tx->lock = 0;
+
+ aim_tx_enqueue(sess, tx);
+
+ sess->snac_nextid++;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Misc network functions
+ *
+ */
+
+#include <faim/aim.h>
+
+int Read(int fd, unsigned char *buf, int len)
+{
+ int i = 0;
+ int j = 0;
+ int err_count=0;
+
+ while ((i < len) && (!(i < 0)))
+ {
+ j = read(fd, &(buf[i]), len-i);
+ if ( (j < 0) && (errno != EAGAIN))
+ return -errno; /* fail */
+ else if (j==0)
+ {
+ err_count++;
+ if (err_count> 100) {
+ /*
+ * Reached maximum number of allowed read errors.
+ *
+ * Lets suppose the connection is lost and errno didn't
+ * know it.
+ *
+ */
+ return (-1);
+ }
+ }
+ else
+ i += j; /* success, continue */
+ }
+ return i;
+}
+
+/*
+ * Create a listener socket.
+ *
+ * We go out of our way to make this interesting. (The Easy Way is not
+ * thread-safe.)
+ *
+ */
+int establish(u_short portnum)
+{
+ int listenfd;
+ const int on = 1;
+ struct addrinfo hints, *res, *ressave;
+ char serv[5];
+
+ sprintf(serv, "%d", portnum);
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo(NULL/*any IP*/, serv, &hints, &res) != 0) {
+ perror("getaddrinfo");
+ return -1;
+ }
+
+ ressave = res;
+ do {
+ listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (listenfd < 0)
+ continue;
+ setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
+ break; /* sucess */
+ close(listenfd);
+ } while ( (res = res->ai_next) );
+
+ if (!res)
+ return -1;
+
+ if (listen(listenfd, 1024)!=0) {
+ perror("listen");
+ return -1;
+ }
+
+ freeaddrinfo(ressave);
+
+ return listenfd;
+}
+
+int get_connection(int s)
+{
+ struct sockaddr isa;
+ int addrlen = 0;
+ int t; /* socket of connection */
+
+ memset(&isa, 0, sizeof(struct sockaddr));
+ if ((t = accept(s,&isa,&addrlen)) < 0) {
+ perror("accept");
+ return -1;
+ }
+
+ return t;
+}
+
+int openconn(char *hostname, int port)
+{
+ struct sockaddr_in sa;
+ struct hostent *hp;
+ int ret;
+
+ if (!(hp = gethostbyname(hostname))) {
+ perror("gethostbyname");
+ return -1;
+ }
+
+ memset(&sa.sin_zero, 0, 8);
+ sa.sin_port = htons(port);
+ memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
+ sa.sin_family = hp->h_addrtype;
+
+ ret = socket(hp->h_addrtype, SOCK_STREAM, 0);
+ if (connect(ret, (struct sockaddr *)&sa, sizeof(struct sockaddr_in))<0) {
+ perror("connect");
+ return -1;
+ }
+
+ return ret;
+}
--- /dev/null
+/*
+ * Common functions used in all apps
+ */
+
+int Read(int fd, unsigned char *buf, int len);
+int establish(u_short portnum);
+int get_connection(int s);
+int openconn(char *hostname, int port);
--- /dev/null
+# Simple test script
+e Starting test script...
+m bleu/goodday
+e Breaking...
+b
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_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...)
{
aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_authsvrready, 0);
aim_send_login(&aimsess, authconn, screenname, password, &info);
#endif
+ aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT, faimtest_debugconn_connect, 0);
printf("faimtest: login sent\n");
while (keepgoing) {
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;
+}