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)
* 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)
/*
* 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;i<AIM_CONN_MAX;i++)
if (sess->conns[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;j<AIM_CONN_MAX;j++)
- {
- if (sess->conns[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;j<AIM_CONN_MAX;j++) {
+ if (sess->conns[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)
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;
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)
userfunc = aim_callhandler(conn, family, type);
if (userfunc)
return userfunc(sess, ptr);
- return 0;
+ return 1; /* XXX */
}
/*
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;
}
{
u_int i = 0;
- printf("\nRecieved unknown packet:");
+ faimdprintf(1, "\nRecieved unknown packet:");
for (i = 0; i < command->commandlen; i++)
{
#include <faim/aim.h>
+
/*
* This is a modified read() to make SURE we get the number
* of bytes we are told to, otherwise block.
* Modified to count errno (Sébastien Carpe <scarpe@atos-group.com>)
*
*/
-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;
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;
/* 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);
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);
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 */
/* 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;
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);
}
/*
- * 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;
}
* 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));
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;
* 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;
}
*/
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;
}
* 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;
}
*/
#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
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 */
};
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);
/*
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, ...);
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;
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 *);
{
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")) ||
#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;