From b8d0da450de7ce933bd9cf9622baa650e469693d Mon Sep 17 00:00:00 2001 From: mid Date: Sun, 19 Mar 2000 08:55:50 +0000 Subject: [PATCH] - Sun Mar 19 06:07:52 UTC 2000 - Added a parameter to aim_select to return event type - REQUIRES CLIENT CHANGES. - For the most part rewrote the tx and rx queuing code - Should fix many, many outstanding problems in and related to that code, including one that keeps memory from freeing - Fixed several bugs in various places - Reformated a lot of code, and did general cleanups - Should have a generally more robust lib now. --- CHANGES | 10 + aim_conn.c | 57 ++-- aim_rxhandlers.c | 543 ++++++++++++++++++-------------------- aim_rxqueue.c | 204 +++++++------- aim_txqueue.c | 310 +++++++++------------- faim/aim.h | 14 +- utils/faimtest/faimtest.c | 40 ++- 7 files changed, 551 insertions(+), 627 deletions(-) diff --git a/CHANGES b/CHANGES index 3bf1aeb..b70fa8a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,16 @@ No release numbers ------------------ + - Sun Mar 19 06:07:52 UTC 2000 + - Added a parameter to aim_select to return event type + - REQUIRES CLIENT CHANGES. + - For the most part rewrote the tx and rx queuing code + - Should fix many, many outstanding problems in and related + to that code, including one that keeps memory from freeing + - Fixed several bugs in various places + - Reformated a lot of code, and did general cleanups + - Should have a generally more robust lib now. + - Sun Mar 12 00:07:40 UTC 2000 - Fixed a robustness problem in aim_handleredirect_middle() - Added TLV chain creation routines (yes, aimd is progressing) diff --git a/aim_conn.c b/aim_conn.c index b47b42b..75ad013 100644 --- a/aim_conn.c +++ b/aim_conn.c @@ -157,12 +157,17 @@ int aim_countconn(struct aim_session_t *sess) * Waits for a socket with data or for timeout, whichever comes first. * See select(2). * + * Return codes in *status: + * -1 error in select() (NULL returned) + * 0 no events pending (NULL returned) + * 1 outgoing data pending (NULL returned) + * 2 incoming data pending (connection with pending data returned) + * */ struct aim_conn_t *aim_select(struct aim_session_t *sess, - struct timeval *timeout) + struct timeval *timeout, int *status) { fd_set fds; - fd_set errfds; int i; if (aim_countconn(sess) <= 0) @@ -171,42 +176,32 @@ struct aim_conn_t *aim_select(struct aim_session_t *sess, /* * If we have data waiting to be sent, return immediatly */ - if (sess->queue_outgoing) - return (struct aim_conn_t *)1; + if (sess->queue_outgoing != NULL) { + *status = 1; + return NULL; + } FD_ZERO(&fds); - FD_ZERO(&errfds); for(i=0;iconns[i].fd>-1) - { - FD_SET(sess->conns[i].fd, &fds); - FD_SET(sess->conns[i].fd, &errfds); - } + FD_SET(sess->conns[i].fd, &fds); - i = select(aim_conngetmaxfd(sess)+1, &fds, NULL, &errfds, timeout); - if (i>=1) - { - int j; - for (j=0;jconns[j].fd > -1) - { - if ((FD_ISSET(sess->conns[j].fd, &errfds))) - { - /* got an exception; close whats left of it up */ - aim_conn_close(&(sess->conns[j])); - return (struct aim_conn_t *)-1; - } - else if ((FD_ISSET(sess->conns[j].fd, &fds))) - return &(sess->conns[j]); /* return the first waiting struct */ + if ((i = select(aim_conngetmaxfd(sess)+1, &fds, NULL, NULL, timeout))>=1) { + int j; + for (j=0;jconns[j].fd > -1) { + if ((FD_ISSET(sess->conns[j].fd, &fds))) { + *status = 2; + return &(sess->conns[j]); /* return the first waiting struct */ } - } - /* should never get here */ - } - else - return (struct aim_conn_t *)i; /* no waiting or error, return -- FIXME: return type funnies */ - return NULL; /* NO REACH */ + } + } + /* should never get here */ + } + + *status = i; /* may be 0 or -1 */ + return NULL; /* no waiting or error, return */ } int aim_conn_isready(struct aim_conn_t *conn) diff --git a/aim_rxhandlers.c b/aim_rxhandlers.c index 0022a4e..7b0a0f9 100644 --- a/aim_rxhandlers.c +++ b/aim_rxhandlers.c @@ -193,9 +193,7 @@ int aim_conn_addhandler(struct aim_session_t *sess, if (!conn) return -1; -#if debug > 0 - printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type); -#endif + faimdprintf(1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type); new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t)); new->family = family; @@ -245,9 +243,7 @@ rxcallback_t aim_callhandler(struct aim_conn_t *conn, if (!conn) return NULL; -#if debug > 0 - printf("aim_callhandler: calling for %04x/%04x\n", family, type); -#endif + faimdprintf(1, "aim_callhandler: calling for %04x/%04x\n", family, type); cur = conn->handlerlist; while(cur) @@ -272,7 +268,7 @@ int aim_callhandler_noparam(struct aim_session_t *sess, userfunc = aim_callhandler(conn, family, type); if (userfunc) return userfunc(sess, ptr); - return 0; + return 1; /* XXX */ } /* @@ -303,287 +299,266 @@ int aim_rxdispatch(struct aim_session_t *sess) int i = 0; struct command_rx_struct *workingPtr = NULL; - if (sess->queue_incoming == NULL) - /* this shouldn't really happen, unless the main loop's select is broke */ - printf("parse_generic: incoming packet queue empty.\n"); - else - { - workingPtr = sess->queue_incoming; - for (i = 0; workingPtr != NULL; i++) - { - /* - * XXX: This is still fairly ugly. - */ - switch(workingPtr->conn->type) - { - case -1: - /* - * This can happen if we have a queued command - * that was recieved after a connection has - * been terminated. In which case, the handler - * list has been cleared, and there's nothing we - * can do for it. We can only cancel it. - */ - workingPtr->handled = 1; - break; - case AIM_CONN_TYPE_AUTH: - { - u_long head; - - head = aimutil_get32(workingPtr->data); - if (head == 0x00000001) - { -#if debug > 0 - printf("got connection ack on auth line\n"); -#endif - workingPtr->handled = 1; - } - else - { - u_short family,subtype; - - family = aimutil_get16(workingPtr->data); - subtype = aimutil_get16(workingPtr->data+2); - - switch (family) - { - /* New login protocol */ + if (sess->queue_incoming == NULL) { + faimdprintf(1, "parse_generic: incoming packet queue empty.\n"); + return 0; + } else { + workingPtr = sess->queue_incoming; + for (i = 0; workingPtr != NULL; i++) { + /* + * XXX: This is still fairly ugly. + */ + switch(workingPtr->conn->type) { + case -1: + /* + * This can happen if we have a queued command + * that was recieved after a connection has + * been terminated. In which case, the handler + * list has been cleared, and there's nothing we + * can do for it. We can only cancel it. + */ + workingPtr->handled = 1; + break; + case AIM_CONN_TYPE_AUTH: { + u_long head; + + head = aimutil_get32(workingPtr->data); + if (head == 0x00000001) { + faimdprintf(1, "got connection ack on auth line\n"); + workingPtr->handled = 1; + } else { + u_short family,subtype; + + family = aimutil_get16(workingPtr->data); + subtype = aimutil_get16(workingPtr->data+2); + + switch (family) { + /* New login protocol */ #ifdef SNACLOGIN - case 0x0017: - if (subtype == 0x0001) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_authparse(sess, workingPtr); - else if (subtype == 0x0007) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr); - break; -#else - /* XXX: this isnt foolproof */ - case 0x0001: - if (subtype == 0x0003) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr); - else - workingPtr->handled = aim_authparse(sess, workingPtr); - break; - case 0x0007: - if (subtype == 0x0005) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr); - break; - default: - /* Old login protocol */ - /* any user callbacks will be called from here */ - workingPtr->handled = aim_authparse(sess, workingPtr); + case 0x0017: + if (subtype == 0x0001) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_authparse(sess, workingPtr); + else if (subtype == 0x0007) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr); + else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr); + break; +#else + /* XXX: this isnt foolproof */ + case 0x0001: + if (subtype == 0x0003) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr); + else + workingPtr->handled = aim_authparse(sess, workingPtr); + break; + case 0x0007: + if (subtype == 0x0005) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr); + break; + default: + /* Old login protocol */ + /* any user callbacks will be called from here */ + workingPtr->handled = aim_authparse(sess, workingPtr); #endif - } - } - } - break; - case AIM_CONN_TYPE_BOS: - { - u_short family; - u_short subtype; - - family = aimutil_get16(workingPtr->data); - subtype = aimutil_get16(workingPtr->data+2); - - switch (family) - { - case 0x0000: /* not really a family, but it works */ - if (subtype == 0x0001) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); - break; - case 0x0001: /* Family: General */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); - break; - case 0x0003: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr); - break; - case 0x0005: - workingPtr->handled = aim_handleredirect_middle(sess, workingPtr); - break; - case 0x0007: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr); - break; - case 0x000a: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr); - break; - case 0x000f: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr); - break; - case 0x0013: - workingPtr->handled = aim_parsemotd_middle(sess, workingPtr); - break; - default: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr); - } - break; - case 0x0002: /* Family: Location */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr); - break; - case 0x0003: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr); - break; - case 0x0006: - workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr); - break; - default: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr); - } - break; - case 0x0003: /* Family: Buddy List */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); - break; - case 0x0003: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr); - break; - case 0x000b: /* oncoming buddy */ - workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr); - break; - case 0x000c: /* offgoing buddy */ - workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr); - break; - default: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr); - } - break; - case 0x0004: /* Family: Messeging */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr); - break; - case 0x0005: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr); - break; - case 0x0007: - workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr); - break; - case 0x000a: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr); - break; - default: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr); - } - break; - case 0x0009: - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr); - break; - case 0x000a: /* Family: User lookup */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr); - break; - case 0x0003: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr); - break; - default: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr); - } - break; - case 0x000b: - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); - else if (subtype == 0x0002) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr); - break; - default: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); - break; - } - } - break; - case AIM_CONN_TYPE_CHATNAV: - { - u_short family; - u_short subtype; - family = aimutil_get16(workingPtr->data); - subtype= aimutil_get16(workingPtr->data+2); - - if ((family == 0x0002) && (subtype == 0x0006)) - { - workingPtr->handled = 1; - aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY); - } - else if ((family == 0x000d) && (subtype == 0x0009)) - workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr); - else - { - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); - } - } - break; - case AIM_CONN_TYPE_CHAT: - { - u_short family, subtype; - - family = aimutil_get16(workingPtr->data); - subtype= aimutil_get16(workingPtr->data+2); - - if ((family == 0x0000) && (subtype == 0x00001)) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr); - else if (family == 0x0001) - { - if (subtype == 0x0001) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr); - else if (subtype == 0x0007) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr); - else - printf("Chat: unknown snac %04x/%04x\n", family, subtype); - } - else if (family == 0x000e) - { - if (subtype == 0x0002) - workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_chat_parse_joined(sess, workingPtr); - else if (subtype == 0x0004) - workingPtr->handled = aim_chat_parse_leave(sess, workingPtr); - else if (subtype == 0x0006) - workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr); - else - printf("Chat: unknown snac %04x/%04x\n", family, subtype); - } - else - { - printf("Chat: unknown snac %04x/%04x\n", family, subtype); - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr); - } - } - break; - default: - printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (type = %d, fd = %d, channel = %02x, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->type, workingPtr->commandlen); - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); - break; - } - /* move to next command */ - workingPtr = workingPtr->next; + } + } + break; + } + case AIM_CONN_TYPE_BOS: { + u_short family; + u_short subtype; + + family = aimutil_get16(workingPtr->data); + subtype = aimutil_get16(workingPtr->data+2); + + switch (family) { + case 0x0000: /* not really a family, but it works */ + if (subtype == 0x0001) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr); + else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); + break; + case 0x0001: /* Family: General */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); + break; + case 0x0003: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr); + break; + case 0x0005: + workingPtr->handled = aim_handleredirect_middle(sess, workingPtr); + break; + case 0x0007: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr); + break; + case 0x000a: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr); + break; + case 0x000f: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr); + break; + case 0x0013: + workingPtr->handled = aim_parsemotd_middle(sess, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr); + break; + } + case 0x0002: /* Family: Location */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr); + break; + case 0x0003: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr); + break; + case 0x0006: + workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr); + break; + } + case 0x0003: /* Family: Buddy List */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); + break; + case 0x0003: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr); + break; + case 0x000b: /* oncoming buddy */ + workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr); + break; + case 0x000c: /* offgoing buddy */ + workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr); + } + break; + case 0x0004: /* Family: Messeging */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr); + break; + case 0x0005: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr); + break; + case 0x0007: + workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr); + break; + case 0x000a: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr); + } + break; + case 0x0009: + if (subtype == 0x0001) + workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr); + else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr); + break; + case 0x000a: /* Family: User lookup */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr); + break; + case 0x0003: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr); + } + break; + case 0x000b: + if (subtype == 0x0001) + workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); + else if (subtype == 0x0002) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr); + else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); + break; + } + break; + } + case AIM_CONN_TYPE_CHATNAV: { + u_short family; + u_short subtype; + family = aimutil_get16(workingPtr->data); + subtype= aimutil_get16(workingPtr->data+2); + + if ((family == 0x0002) && (subtype == 0x0006)) { + workingPtr->handled = 1; + aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY); + } else if ((family == 0x000d) && (subtype == 0x0009)) { + workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr); + } else { + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); } + break; + } + case AIM_CONN_TYPE_CHAT: { + u_short family, subtype; + + family = aimutil_get16(workingPtr->data); + subtype= aimutil_get16(workingPtr->data+2); + + if ((family == 0x0000) && (subtype == 0x00001)) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr); + else if (family == 0x0001) { + if (subtype == 0x0001) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr); + else if (subtype == 0x0007) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr); + else + printf("Chat: unknown snac %04x/%04x\n", family, subtype); + } else if (family == 0x000e) { + if (subtype == 0x0002) + workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_chat_parse_joined(sess, workingPtr); + else if (subtype == 0x0004) + workingPtr->handled = aim_chat_parse_leave(sess, workingPtr); + else if (subtype == 0x0006) + workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr); + else + printf("Chat: unknown snac %04x/%04x\n", family, subtype); + } else { + printf("Chat: unknown snac %04x/%04x\n", family, subtype); + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr); + } + break; + } + default: + printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, channel = %02x, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->type, workingPtr->commandlen); + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); + break; + } + /* move to next command */ + workingPtr = workingPtr->next; } + } - sess->queue_incoming = aim_purge_rxqueue(sess->queue_incoming); + /* + * 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 0; } @@ -691,7 +666,7 @@ int aim_parse_unknown(struct aim_session_t *sess, { u_int i = 0; - printf("\nRecieved unknown packet:"); + faimdprintf(1, "\nRecieved unknown packet:"); for (i = 0; i < command->commandlen; i++) { diff --git a/aim_rxqueue.c b/aim_rxqueue.c index 8baa058..88721c4 100644 --- a/aim_rxqueue.c +++ b/aim_rxqueue.c @@ -9,6 +9,7 @@ #include + /* * This is a modified read() to make SURE we get the number * of bytes we are told to, otherwise block. @@ -16,7 +17,7 @@ * Modified to count errno (Sébastien Carpe ) * */ -int Read(int fd, u_char *buf, int len) +int aim_failsaferead(int fd, u_char *buf, int len) { int i = 0; int j = 0; @@ -59,19 +60,17 @@ int aim_get_command(struct aim_session_t *sess) struct timeval tv; char generic[6]; struct command_rx_struct *workingStruct = NULL; - struct command_rx_struct *workingPtr = NULL; struct aim_conn_t *conn = NULL; -#if debug > 0 - printf("Reading generic/unknown response..."); -#endif - - + int selstat = 0; + + faimdprintf(1, "Reading generic/unknown response..."); + /* dont wait at all (ie, never call this unless something is there) */ tv.tv_sec = 0; tv.tv_usec = 0; - conn = aim_select(sess, &tv); + conn = aim_select(sess, &tv, &selstat); - if (conn==NULL) + if (conn==NULL) return 0; /* nothing waiting */ s = conn->fd; @@ -92,7 +91,7 @@ int aim_get_command(struct aim_session_t *sess) /* read first 6 bytes (the FLAP header only) off the socket */ while ( (select(s+1, &fds, NULL, NULL, &tv) == 1) && (i < 6)) { - if ((err = Read(s, &(generic[i]), 1)) < 0) + if ((err = aim_failsaferead(s, &(generic[i]), 1)) < 0) { /* error is probably not recoverable...(must be a pessimistic day) */ aim_conn_close(conn); @@ -104,26 +103,18 @@ int aim_get_command(struct aim_session_t *sess) if (generic[i] == 0x2a) { readgood = 1; -#if debug > 1 - printf("%x ", generic[i]); - fflush(stdout); -#endif + faimdprintf(1, "%x ", generic[i]); i++; } else { -#if debug > 1 - printf("skipping 0x%d ", generic[i]); - fflush(stdout); -#endif + faimdprintf(1, "skipping 0x%d ", generic[i]); j++; } } else { -#if debug > 1 - printf("%x ", generic[i]); -#endif + faimdprintf(1, "%x ", generic[i]); i++; } FD_ZERO(&fds); @@ -132,19 +123,21 @@ int aim_get_command(struct aim_session_t *sess) tv.tv_usec= 2; } - if (generic[0] != 0x2a) - { - /* this really shouldn't happen, since the main loop - select() should protect us from entering this function - without data waiting */ - printf("Bad incoming data!"); - 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) { + printf("Bad incoming data!"); + return -1; + } isav = i; /* allocate a new struct */ workingStruct = (struct command_rx_struct *) malloc(sizeof(struct command_rx_struct)); + memset(workingStruct, 0x00, sizeof(struct command_rx_struct)); + workingStruct->lock = 1; /* lock the struct */ /* store channel -- byte 2 */ @@ -156,20 +149,18 @@ int aim_get_command(struct aim_session_t *sess) /* store commandlen -- bytes 5 and 6 */ workingStruct->commandlen = aimutil_get16(generic+4); + workingStruct->nofree = 0; /* free by default */ + /* malloc for data portion */ workingStruct->data = (u_char *) malloc(workingStruct->commandlen); /* read the data portion of the packet */ - i = Read(s, workingStruct->data, workingStruct->commandlen); - if (i < 0) - { - aim_conn_close(conn); - return i; - } + if (aim_failsaferead(s, workingStruct->data, workingStruct->commandlen) < 0){ + aim_conn_close(conn); + return -1; + } -#if debug > 0 - printf(" done. (%db+%db read, %db skipped)\n", isav, i, j); -#endif + faimdprintf(1, " done. (%db+%db read, %db skipped)\n", isav, i, j); workingStruct->conn = conn; @@ -177,18 +168,21 @@ int aim_get_command(struct aim_session_t *sess) workingStruct->lock = 0; /* unlock */ /* enqueue this packet */ - if (sess->queue_incoming == NULL) - { - sess->queue_incoming = workingStruct; - } - else - { - workingPtr = sess->queue_incoming; - while (workingPtr->next != NULL) - workingPtr = workingPtr->next; - workingPtr->next = workingStruct; - } - + if (sess->queue_incoming == NULL) { + sess->queue_incoming = workingStruct; + } 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 = workingStruct; + } workingStruct->conn->lastactivity = time(NULL); @@ -196,71 +190,59 @@ int aim_get_command(struct aim_session_t *sess) } /* - * purge_rxqueue() + * Purge recieve queue of all handled commands (->handled==1). Also + * allows for selective freeing using ->nofree so that the client can + * keep the data for various purposes. * - * This is just what it sounds. It purges the receive (rx) queue of - * all handled commands. This is normally called from inside - * aim_rxdispatch() after it's processed all the commands in the queue. + * If ->nofree is nonzero, the frame will be delinked from the global list, + * but will not be free'ed. The client _must_ keep a pointer to the + * data -- libfaim will not! If the client marks ->nofree but + * does not keep a pointer, it's lost forever. * */ -struct command_rx_struct *aim_purge_rxqueue(struct command_rx_struct *queue) +void aim_purge_rxqueue(struct aim_session_t *sess) { - struct command_rx_struct *workingPtr = NULL; - struct command_rx_struct *workingPtr2 = NULL; + struct command_rx_struct *cur = NULL; + struct command_rx_struct *tmp; - if (queue == (struct command_rx_struct *)NULL) - { - /* do nothing */ - } - else if (queue->next == (struct command_rx_struct *)NULL) - { - if (queue->handled == 1) { - workingPtr = queue; - queue = NULL; - free(workingPtr->data); - free(workingPtr); - } - } - else - { - while (queue && queue->handled == 1) - { - workingPtr = queue; - queue = queue->next; - free(workingPtr->data); - free(workingPtr); - } - - workingPtr = queue; - - while (workingPtr && (workingPtr->next != (struct command_rx_struct *)NULL)) - { - if (workingPtr->next->handled == 1) - { - workingPtr2 = workingPtr->next; - workingPtr->next = workingPtr->next->next; - free(workingPtr2->data); - free(workingPtr2); - } - else /* TODO: rework this so the additional if isn't needed */ - { - if (workingPtr->next == (struct command_rx_struct *)NULL) - { - if (workingPtr->handled == 1) - { - workingPtr2 = workingPtr; - workingPtr = NULL; - free(workingPtr2->data); - free(workingPtr2); - return queue; - } - } - else - { - workingPtr = workingPtr->next; - } - } - } + 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) { + free(tmp->data); + free(tmp); + } else + tmp->next = NULL; } - return queue; + return; + } + + for(cur = sess->queue_incoming; cur->next != NULL; ) { + if (cur->next->handled) { + tmp = cur->next; + cur->next = tmp->next; + if (!tmp->nofree) { + 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; } diff --git a/aim_txqueue.c b/aim_txqueue.c index f2ed1e8..8a42e33 100644 --- a/aim_txqueue.c +++ b/aim_txqueue.c @@ -20,18 +20,16 @@ * 6) Return * */ - int aim_tx_enqueue(struct aim_session_t *sess, struct command_tx_struct *newpacket) { - struct command_tx_struct *workingPtr = NULL; + struct command_tx_struct *cur; struct command_tx_struct *newpacket_copy = NULL; - if (newpacket->conn == NULL) - { - printf("aim_tx_enqueue: WARNING: enqueueing packet with no connecetion, defaulting to BOS\n"); + if (newpacket->conn == NULL) { + faimdprintf(1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion, defaulting to BOS\n"); newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); - } + } newpacket_copy = (struct command_tx_struct *) malloc (sizeof(struct command_tx_struct)); memcpy(newpacket_copy, newpacket, sizeof(struct command_tx_struct)); @@ -43,33 +41,23 @@ int aim_tx_enqueue(struct aim_session_t *sess, newpacket_copy->sent = 0; /* not sent yet */ newpacket_copy->next = NULL; /* always last */ - if (sess->queue_outgoing == NULL) - { - sess->queue_outgoing = newpacket_copy; - } - else - { - workingPtr = sess->queue_outgoing; - while (workingPtr->next != NULL) - workingPtr = workingPtr->next; - workingPtr->next = newpacket_copy; - } + /* see overhead note in aim_rxqueue counterpart */ + if (sess->queue_outgoing == NULL) { + sess->queue_outgoing = newpacket_copy; + } else { + for (cur = sess->queue_outgoing; + cur->next; + cur = cur->next) + ; + cur->next = newpacket_copy; + } newpacket_copy->lock = 0; /* unlock so it can be sent */ -#if debug > 2 - printf("calling aim_tx_printqueue()\n"); +#if debug == 2 + faimdprintf(2, "calling aim_tx_printqueue()\n"); aim_tx_printqueue(sess); - printf("back from aim_tx_printqueue()\n"); -#endif - - /* we'll force a flush for now -- this behavior probably will change */ -#if debug > 1 - printf("calling aim_tx_flushqueue()\n"); -#endif - aim_tx_flushqueue(sess); -#if debug > 1 - printf("back from aim_tx_flushqueue()\n"); + faimdprintf(2, "back from aim_tx_printqueue()\n"); #endif return 0; @@ -97,29 +85,26 @@ u_int aim_get_next_txseqnum(struct aim_conn_t *conn) * if the queue isn't working quite right. * */ -#if debug > 2 +#if debug == 2 int aim_tx_printqueue(struct aim_session_t *sess) { - struct command_tx_struct *workingPtr = NULL; + struct command_tx_struct *cur; - workingPtr = sess->queue_outgoing; -#if debug > 2 - printf("\ncurrent aim_queue_outgoing...\n"); - printf("\ttype seqnum len lock sent\n"); -#endif - if (workingPtr == NULL) - printf("aim_tx_flushqueue(): queue empty"); - else - { - while (workingPtr != NULL) - { - printf("\t %2x %4x %4x %1d %1d\n", workingPtr->type, workingPtr->seqnum, workingPtr->commandlen, workingPtr->lock, workingPtr->sent); - - workingPtr = workingPtr->next; - } - } + faimdprintf(2, "\ncurrent aim_queue_outgoing...\n"); + faimdprintf(2, "\ttype seqnum len lock sent\n"); + + if (sess->queue_outgoing == NULL) + faimdprintf(2, "aim_tx_flushqueue(): queue empty"); + else { + for (cur = sess->queue_outgoing; cur; cur = cur->next) { + faimdprintf(2, "\t %2x %4x %4x %1d %1d\n", + cur->type, cur->seqnum, + cur->commandlen, cur->lock, + cur->sent); + } + } - printf("\n(done printing queue)\n"); + faimdprintf(2, "\n(done printing queue)\n"); return 0; } @@ -151,97 +136,81 @@ int aim_tx_printqueue(struct aim_session_t *sess) */ int aim_tx_flushqueue(struct aim_session_t *sess) { - struct command_tx_struct *workingPtr = NULL; + struct command_tx_struct *cur; u_char *curPacket = NULL; #if debug > 1 int i = 0; #endif - workingPtr = sess->queue_outgoing; -#if debug > 1 - printf("beginning txflush...\n"); -#endif - while (workingPtr != NULL) - { - /* only process if its unlocked and unsent */ - if ( (workingPtr->lock == 0) && - (workingPtr->sent == 0) ) - { - - /* - * And now for the meager attempt to force transmit - * latency and avoid missed messages. - */ - if ((workingPtr->conn->lastactivity + workingPtr->conn->forcedlatency) - >= time(NULL)) - { - /* FIXME FIXME -- should be a break! we dont want to block the upper layers */ - sleep((workingPtr->conn->lastactivity + workingPtr->conn->forcedlatency) - time(NULL)); - } - - workingPtr->lock = 1; /* lock the struct */ - - /* allocate full-packet buffer */ - curPacket = (char *) malloc(workingPtr->commandlen + 6); - - /* command byte */ - curPacket[0] = 0x2a; + if (sess->queue_outgoing == NULL) + return 0; - /* type/family byte */ - curPacket[1] = workingPtr->type; + faimdprintf(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) { - /* bytes 3+4: word: FLAP sequence number */ - aimutil_put16(curPacket+2, workingPtr->seqnum); + /* + * 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)); + } + + cur->lock = 1; /* lock the struct */ + + /* allocate full-packet buffer */ + curPacket = (char *) malloc(cur->commandlen + 6); + + /* command byte */ + curPacket[0] = 0x2a; + + /* type/family byte */ + curPacket[1] = cur->type; + + /* bytes 3+4: word: FLAP sequence number */ + aimutil_put16(curPacket+2, cur->seqnum); - /* bytes 5+6: word: SNAC len */ - aimutil_put16(curPacket+4, workingPtr->commandlen); + /* bytes 5+6: word: SNAC len */ + aimutil_put16(curPacket+4, cur->commandlen); + + /* bytes 7 and on: raw: SNAC data */ + memcpy(&(curPacket[6]), cur->data, cur->commandlen); + + /* full image of raw packet data now in curPacket */ + if ( (u_int)write(cur->conn->fd, curPacket, (cur->commandlen + 6)) != (cur->commandlen + 6)) { + printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", cur->seqnum); + cur->sent = 0; /* mark it unsent */ + continue; /* bail out */ + } else { + faimdprintf(2, "\nSENT 0x%4x\n\n", cur->seqnum); - /* bytes 7 and on: raw: SNAC data */ - memcpy(&(curPacket[6]), workingPtr->data, workingPtr->commandlen); - - /* full image of raw packet data now in curPacket */ - if ( (u_int)write(workingPtr->conn->fd, curPacket, (workingPtr->commandlen + 6)) != (workingPtr->commandlen + 6)) - { - printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", workingPtr->seqnum); - workingPtr->sent = 0; /* mark it unsent */ - return -1; /* bail out */ - } - else - { -#if debug > 2 - printf("\nSENT 0x%4x\n\n", workingPtr->seqnum); -#endif - workingPtr->sent = 1; /* mark the struct as sent */ - workingPtr->conn->lastactivity = time(NULL); - } + cur->sent = 1; /* mark the struct as sent */ + cur->conn->lastactivity = time(NULL); + } #if debug > 2 - printf("\nPacket:"); - for (i = 0; i < (workingPtr->commandlen + 6); i++) - { - if ((i % 8) == 0) - printf("\n\t"); - if (curPacket[i] >= ' ' && curPacket[i]<127) - printf("%c=%02x ",curPacket[i], curPacket[i]); - else - printf("0x%2x ", curPacket[i]); - } - printf("\n"); -#endif - workingPtr->lock = 0; /* unlock the struct */ - free(curPacket); /* free up full-packet buffer */ + faimdprintf(2, "\nPacket:"); + for (i = 0; i < (cur->commandlen + 6); i++) { + if ((i % 8) == 0) { + faimdprintf(2, "\n\t"); + } + if (curPacket[i] >= ' ' && curPacket[i]<127) { + faimdprintf(2, "%c=%02x ", curPacket[i], curPacket[i]); + } else { + faimdprintf(2, "0x%2x ", curPacket[i]); } - workingPtr = workingPtr->next; + } + faimdprintf(2, "\n"); +#endif + cur->lock = 0; /* unlock the struct */ + free(curPacket); /* free up full-packet buffer */ } + } /* purge sent commands from queue */ - /* this may not always occur explicitly--i may put this on a timer later */ -#if debug > 1 - printf("calling aim_tx_purgequeue()\n"); -#endif aim_tx_purgequeue(sess); -#if debug > 1 - printf("back from aim_tx_purgequeu() [you must be a lucky one]\n"); -#endif return 0; } @@ -254,68 +223,41 @@ int aim_tx_flushqueue(struct aim_session_t *sess) * reduce memory footprint at run time! * */ -int aim_tx_purgequeue(struct aim_session_t *sess) +void aim_tx_purgequeue(struct aim_session_t *sess) { - struct command_tx_struct *workingPtr = NULL; - struct command_tx_struct *workingPtr2 = NULL; -#if debug > 1 - printf("purgequeue(): starting purge\n"); -#endif - /* Empty queue: nothing to do */ + struct command_tx_struct *cur = NULL; + struct command_tx_struct *tmp; + if (sess->queue_outgoing == NULL) - { -#if debug > 1 - printf("purgequeue(): purge done (len=0)\n"); -#endif - return 0; - } - /* One Node queue: free node and return */ - else if (sess->queue_outgoing->next == NULL) - { -#if debug > 1 - printf("purgequeue(): entered case len=1\n"); -#endif - /* only free if sent AND unlocked -- dont assume sent structs are done */ - if ( (sess->queue_outgoing->lock == 0) && - (sess->queue_outgoing->sent == 1) ) - { -#if debug > 1 - printf("purgequeue(): purging seqnum 0x%04x\n", sess->queue_outgoing->seqnum); -#endif - workingPtr2 = sess->queue_outgoing; - sess->queue_outgoing = NULL; - free(workingPtr2->data); - free(workingPtr2); - } -#if debug > 1 - printf("purgequeue(): purge done (len=1)\n"); -#endif - return 0; - } - else - { -#if debug > 1 - printf("purgequeue(): entering case len>1\n"); -#endif - while(workingPtr->next != NULL) - { - if ( (workingPtr->next->lock == 0) && - (workingPtr->next->sent == 1) ) - { -#if debug > 1 - printf("purgequeue(): purging seqnum 0x%04x\n", workingPtr->next->seqnum); -#endif - workingPtr2 = workingPtr->next; - workingPtr->next = workingPtr2->next; - free(workingPtr2->data); - free(workingPtr2); - } - } -#if debug > 1 - printf("purgequeue(): purge done (len>1)\n"); -#endif - return 0; + return; + + if (sess->queue_outgoing->next == NULL) { + if (!sess->queue_outgoing->lock && sess->queue_outgoing->sent) { + tmp = sess->queue_outgoing; + sess->queue_outgoing = NULL; + 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; + free(tmp->data); + free(tmp); + } + cur = cur->next; - /* no reach */ + /* + * 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; } diff --git a/faim/aim.h b/faim/aim.h index bf813bc..96b2059 100644 --- a/faim/aim.h +++ b/faim/aim.h @@ -50,6 +50,12 @@ */ #define AIM_COOKIELEN 0x100 +#if debug > 0 +#define faimdprintf(l, x...) {if (l >= debug) printf(x); } +#else +#define faimdprintf(l, x...) +#endif + /* * Login info. Passes information from the Authorization * stage of login to the service (BOS, etc) connection @@ -126,6 +132,7 @@ struct command_rx_struct { u_char *data; /* packet data (from 7 byte on) */ u_int lock; /* 0 = open, !0 = locked */ u_int handled; /* 0 = new, !0 = been handled */ + u_int 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 */ }; @@ -247,7 +254,6 @@ int aim_puttlv_32(u_char *, u_short, u_long); int aim_puttlv_str(u_char *buf, u_short t, u_short l, u_char *v); int aim_writetlvchain(u_char *buf, int buflen, struct aim_tlvlist_t **list); int aim_addtlvtochain16(struct aim_tlvlist_t **list, unsigned short type, unsigned short val); -int aim_addtlvtochain32(struct aim_tlvlist_t **list, unsigned short type, unsigned long val); int aim_addtlvtochain_str(struct aim_tlvlist_t **list, unsigned short type, char *str); /* @@ -274,7 +280,7 @@ int aim_send_login (struct aim_session_t *, struct aim_conn_t *, char *, char *, int aim_encode_password(const char *, u_char *); -struct command_rx_struct *aim_purge_rxqueue(struct command_rx_struct *queue); +void aim_purge_rxqueue(struct aim_session_t *); int aim_parse_unknown(struct aim_session_t *, struct command_rx_struct *command, ...); @@ -285,7 +291,7 @@ int aim_tx_enqueue(struct aim_session_t *, struct command_tx_struct *); u_int aim_get_next_txseqnum(struct aim_conn_t *); int aim_tx_flushqueue(struct aim_session_t *); int aim_tx_printqueue(struct aim_session_t *); -int aim_tx_purgequeue(struct aim_session_t *); +void aim_tx_purgequeue(struct aim_session_t *); struct aim_rxcblist_t { u_short family; @@ -325,7 +331,7 @@ void aim_conn_close(struct aim_conn_t *deadconn); struct aim_conn_t *aim_getconn_type(struct aim_session_t *, int type); struct aim_conn_t *aim_newconn(struct aim_session_t *, int type, char *dest); int aim_conngetmaxfd(struct aim_session_t *); -struct aim_conn_t *aim_select(struct aim_session_t *, struct timeval *); +struct aim_conn_t *aim_select(struct aim_session_t *, struct timeval *, int *); int aim_conn_isready(struct aim_conn_t *); int aim_conn_setstatus(struct aim_conn_t *, int); void aim_session_init(struct aim_session_t *); diff --git a/utils/faimtest/faimtest.c b/utils/faimtest/faimtest.c index 1456a0f..fc400f5 100644 --- a/utils/faimtest/faimtest.c +++ b/utils/faimtest/faimtest.c @@ -71,9 +71,10 @@ int main(void) { struct aim_session_t aimsess; struct aim_conn_t *authconn = NULL; - int stayconnected = 1; + int keepgoing = 1, stayconnected = 1; struct client_info_s info = {"FAIMtest (Hi guys!)", 3, 5, 1670, "us", "en"}; - + int selstat = 0; + aim_session_init(&aimsess); if ( !(screenname = getenv("SCREENNAME")) || @@ -120,27 +121,40 @@ int main(void) #endif } - while (aim_select(&aimsess, NULL) > (struct aim_conn_t *)0) - { - if (aimsess.queue_outgoing) - aim_tx_flushqueue(&aimsess); + while (keepgoing) { + aim_select(&aimsess, NULL, &selstat); - if (aim_get_command(&aimsess) < 0) - { + switch(selstat) { + case -1: /* error */ + keepgoing = 0; + break; + + case 0: /* no events pending */ + break; + + case 1: /* outgoing data pending */ + aim_tx_flushqueue(&aimsess); + break; + + case 2: /* incoming data pending */ + if (aim_get_command(&aimsess) < 0) { printf("\afaimtest: connection error!\n"); - } - else + } else aim_rxdispatch(&aimsess); + break; + + default: + break; /* invalid */ } + } /* Close up */ - printf("AIM just decided we didn't need to be here anymore, closing up.,,\n"); + printf("AIM just decided we didn't need to be here anymore, closing up...\n"); /* close up all connections, dead or no */ aim_logoff(&aimsess); - if (stayconnected) - { + if (stayconnected) { printf("\nTrying to reconnect in 2 seconds...\n"); sleep(2); goto enter; -- 2.45.2