Mercurial > pidgin
diff libfaim/aim_rxhandlers.c @ 237:6ced2f1c8b24
[gaim-migrate @ 247]
How cool is this, libfaim is making a comeback. I completely redid everything,
as was necessary because of the updates to libfaim since gaim 0.9.7. You can
sign on and send/recv IMs, but there's a bad lag between display updates that
I haven't figured out how to fix yet.
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Sat, 20 May 2000 00:30:53 +0000 |
parents | 68b230f8da5f |
children | 1eeece1c7b7b |
line wrap: on
line diff
--- a/libfaim/aim_rxhandlers.c Thu May 18 18:20:18 2000 +0000 +++ b/libfaim/aim_rxhandlers.c Sat May 20 00:30:53 2000 +0000 @@ -1,80 +1,274 @@ +/* + * aim_rxhandlers.c + * + * This file contains most all of the incoming packet handlers, along + * with aim_rxdispatch(), the Rx dispatcher. Queue/list management is + * actually done in aim_rxqueue.c. + * + */ + +#include <aim.h> /* - aim_rxhandlers.c - - This file contains most all of the incoming packet handlers, along - with aim_rxdispatch(), the Rx dispatcher. Queue/list management is - actually done in aim_rxqueue.c. - + * Bleck functions get called when there's no non-bleck functions + * around to cleanup the mess... */ +int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...) +{ + u_short family; + u_short subtype; + u_short maxf; + u_short maxs; -#include "aim.h" /* for most everything */ + /* XXX: this is ugly. and big just for debugging. */ + char *literals[14][25] = { + {"Invalid", + NULL + }, + {"General", + "Invalid", + "Error", + "Client Ready", + "Server Ready", + "Service Request", + "Redirect", + "Rate Information Request", + "Rate Information", + "Rate Information Ack", + NULL, + "Rate Information Change", + "Server Pause", + NULL, + "Server Resume", + "Request Personal User Information", + "Personal User Information", + "Evil Notification", + NULL, + "Migration notice", + "Message of the Day", + "Set Privacy Flags", + "Well Known URL", + "NOP" + }, + {"Location", + "Invalid", + "Error", + "Request Rights", + "Rights Information", + "Set user information", + "Request User Information", + "User Information", + "Watcher Sub Request", + "Watcher Notification" + }, + {"Buddy List Management", + "Invalid", + "Error", + "Request Rights", + "Rights Information", + "Add Buddy", + "Remove Buddy", + "Watcher List Query", + "Watcher List Response", + "Watcher SubRequest", + "Watcher Notification", + "Reject Notification", + "Oncoming Buddy", + "Offgoing Buddy" + }, + {"Messeging", + "Invalid", + "Error", + "Add ICBM Parameter", + "Remove ICBM Parameter", + "Request Parameter Information", + "Parameter Information", + "Outgoing Message", + "Incoming Message", + "Evil Request", + "Evil Reply", + "Missed Calls", + "Message Error", + "Host Ack" + }, + {"Advertisements", + "Invalid", + "Error", + "Request Ad", + "Ad Data (GIFs)" + }, + {"Invitation / Client-to-Client", + "Invalid", + "Error", + "Invite a Friend", + "Invitation Ack" + }, + {"Administrative", + "Invalid", + "Error", + "Information Request", + "Information Reply", + "Information Change Request", + "Information Chat Reply", + "Account Confirm Request", + "Account Confirm Reply", + "Account Delete Request", + "Account Delete Reply" + }, + {"Popups", + "Invalid", + "Error", + "Display Popup" + }, + {"BOS", + "Invalid", + "Error", + "Request Rights", + "Rights Response", + "Set group permission mask", + "Add permission list entries", + "Delete permission list entries", + "Add deny list entries", + "Delete deny list entries", + "Server Error" + }, + {"User Lookup", + "Invalid", + "Error", + "Search Request", + "Search Response" + }, + {"Stats", + "Invalid", + "Error", + "Set minimum report interval", + "Report Events" + }, + {"Translate", + "Invalid", + "Error", + "Translate Request", + "Translate Reply", + }, + {"Chat Navigation", + "Invalid", + "Error", + "Request rights", + "Request Exchange Information", + "Request Room Information", + "Request Occupant List", + "Search for Room", + "Outgoing Message", + "Incoming Message", + "Evil Request", + "Evil Reply", + "Chat Error", + } + }; -int bleck(struct command_rx_struct *param, ...) -{ + maxf = sizeof(literals) / sizeof(literals[0]); + maxs = sizeof(literals[0]) / sizeof(literals[0][0]); + + family = aimutil_get16(workingPtr->data+0); + subtype= aimutil_get16(workingPtr->data+2); + + if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL)) + printf("bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]); + else + printf("bleck: null handler for %04x/%04x (no literal)\n",family,subtype); + return 1; } -/* - * The callbacks. Used to pass data up from the wire into the client. - * - * TODO: MASSIVE OVERHAUL. This method of doing it (array of function - * pointers) is ugly. Overhaul may mean including chained callbacks - * for having client features such as run-time loadable modules. - * - */ -rxcallback_t aim_callbacks[] = { - bleck, /* incoming IM */ - bleck, /* oncoming buddy */ - bleck, /* offgoing buddy */ - bleck, /* messaging error */ - bleck, /* server missed call */ - bleck, /* login phase 4 packet C command 1*/ - bleck, /* login phase 4 packet C command 2 */ - bleck, /* login phase 2, first resp */ - bleck, /* login phase 2, second resp -- **REQUIRED** */ - bleck, /* login phase 3 packet B */ - bleck, /* login phase 3D packet A */ - bleck, /* login phase 3D packet B */ - bleck, /* login phase 3D packet C */ - bleck, /* login phase 3D packet D */ - bleck, /* login phase 3D packet E */ - bleck, /* redirect -- **REQUIRED** */ - bleck, /* server rate change */ - bleck, /* user location error */ - aim_parse_unknown, /* completely unknown command */ - bleck, /* User Info Response */ - bleck, /* User Search by Address response */ - bleck, /* User Search by Name response */ - bleck, /* user search fail */ - bleck, /* auth error */ - bleck, /* auth success */ - bleck, /* auth server ready */ - bleck, /* auth other */ - bleck, /* info change reply */ - bleck, /* ChatNAV: server ready */ - 0x00 -}; +int aim_conn_addhandler(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_short family, + u_short type, + rxcallback_t newhandler, + u_short flags) +{ + struct aim_rxcblist_t *new,*cur; + + if (!conn) + return -1; + + 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; + new->type = type; + new->flags = flags; + if (!newhandler) + new->handler = &bleck; + else + new->handler = newhandler; + new->next = NULL; + + cur = conn->handlerlist; + if (!cur) + conn->handlerlist = new; + else + { + while (cur->next) + cur = cur->next; + cur->next = new; + } + + return 0; +} + +int aim_clearhandlers(struct aim_conn_t *conn) +{ + struct aim_rxcblist_t *cur,*tmp; + if (!conn) + return -1; + cur = conn->handlerlist; + while(cur) + { + tmp = cur->next; + free(cur); + cur = tmp; + } + return 0; +} -int aim_register_callbacks(rxcallback_t *newcallbacks) +rxcallback_t aim_callhandler(struct aim_conn_t *conn, + u_short family, + u_short type) { - int i = 0; + struct aim_rxcblist_t *cur; + + if (!conn) + return NULL; + + faimdprintf(1, "aim_callhandler: calling for %04x/%04x\n", family, type); - for (i = 0; aim_callbacks[i] != 0x00; i++) + cur = conn->handlerlist; + while(cur) { - if ( (newcallbacks[i] != NULL) && - (newcallbacks[i] != 0x00) ) - { -#if debug > 3 - printf("aim_register_callbacks: changed handler %d\n", i); -#endif - aim_callbacks[i] = newcallbacks[i]; - } + if ( (cur->family == family) && (cur->type == type) ) + return cur->handler; + cur = cur->next; } - - return 0; + + if (type==0xffff) + return NULL; + return aim_callhandler(conn, family, 0xffff); +} + +int aim_callhandler_noparam(struct aim_session_t *sess, + struct aim_conn_t *conn, + u_short family, + u_short type, + struct command_rx_struct *ptr) +{ + rxcallback_t userfunc = NULL; + userfunc = aim_callhandler(conn, family, type); + if (userfunc) + return userfunc(sess, ptr); + return 1; /* XXX */ } /* @@ -100,349 +294,380 @@ TODO: Allow for NULL handlers. */ -int aim_rxdispatch(void) +int aim_rxdispatch(struct aim_session_t *sess) { int i = 0; struct command_rx_struct *workingPtr = NULL; - if (aim_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 = aim_queue_incoming; - for (i = 0; workingPtr != NULL; i++) - { - switch(workingPtr->conn->type) - { - case AIM_CONN_TYPE_AUTH: - if ( (workingPtr->data[0] == 0x00) && - (workingPtr->data[1] == 0x00) && - (workingPtr->data[2] == 0x00) && - (workingPtr->data[3] == 0x01) ) - { -#if debug > 0 - fprintf(stderr, "got connection ack on auth line\n"); + 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; workingPtr = workingPtr->next, i++) { + /* + * XXX: This is still fairly ugly. + */ + if (workingPtr->handled) + continue; + + 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); #endif - workingPtr->handled = 1; - } - else - { - /* any user callbacks will be called from here */ - workingPtr->handled = aim_authparse(workingPtr); - } - break; - case AIM_CONN_TYPE_BOS: - { - u_short family; - u_short subtype; - family = (workingPtr->data[0] << 8) + workingPtr->data[1]; - subtype = (workingPtr->data[2] << 8) + workingPtr->data[3]; - switch (family) - { - case 0x0000: /* not really a family, but it works */ - if (subtype == 0x0001) - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P2_1])(workingPtr); - else - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - case 0x0001: /* Family: General */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = aim_parse_generalerrs(workingPtr); - break; - case 0x0003: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P2_2])(workingPtr); - break; - case 0x0005: - workingPtr->handled = aim_handleredirect_middle(workingPtr); - break; - case 0x0007: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3_B])(workingPtr); - break; - case 0x000a: - workingPtr->handled = (aim_callbacks[AIM_CB_RATECHANGE])(workingPtr); - break; - case 0x000f: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_A])(workingPtr); - break; - case 0x0013: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P4_C2])(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - } - break; - case 0x0002: /* Family: Location */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = (aim_callbacks[AIM_CB_MISSED_IM])(workingPtr); - break; - case 0x0003: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_D])(workingPtr); - break; - case 0x0006: - workingPtr->handled = aim_parse_userinfo_middle(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - } - break; - case 0x0003: /* Family: Buddy List */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = aim_parse_generalerrs(workingPtr); - break; - case 0x0003: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_C])(workingPtr); - break; - case 0x000b: - workingPtr->handled = (aim_callbacks[AIM_CB_ONCOMING_BUDDY])(workingPtr); - break; - case 0x000c: - workingPtr->handled = (aim_callbacks[AIM_CB_OFFGOING_BUDDY])(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - } - break; - case 0x0004: /* Family: Messeging */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = (aim_callbacks[AIM_CB_USERERROR])(workingPtr); - break; - case 0x0005: - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_E])(workingPtr); - break; - case 0x0007: - workingPtr->handled = aim_parse_incoming_im_middle(workingPtr); - break; - case 0x000a: - workingPtr->handled = (aim_callbacks[AIM_CB_MISSED_CALL])(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - } - break; - case 0x0009: - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_B])(workingPtr); - else - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - case 0x000a: /* Family: User lookup */ - switch (subtype) - { - case 0x0001: - workingPtr->handled = (aim_callbacks[AIM_CB_SEARCH_FAIL])(workingPtr); - break; - case 0x0003: - workingPtr->handled = (aim_callbacks[AIM_CB_SEARCH_ADDRESS])(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - } - break; - case 0x000b: - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(workingPtr); - else if (subtype == 0x0002) - workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P4_C1])(workingPtr); - else - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - default: - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - } - } - break; - case AIM_CONN_TYPE_CHATNAV: - if ( (workingPtr->data[0] == 0x00) && - (workingPtr->data[1] == 0x02) && - (workingPtr->data[2] == 0x00) && - (workingPtr->data[3] == 0x06) ) - { - workingPtr->handled = 1; - aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY); - } - else - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - case AIM_CONN_TYPE_CHAT: - fprintf(stderr, "\nAHH! Dont know what to do with CHAT stuff yet!\n"); - workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); - break; - default: - fprintf(stderr, "\nAHHHHH! UNKNOWN CONNECTION TYPE!\n\n"); - workingPtr->handled = (aim_callbacks[AIM_CB_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; + } } + } - aim_queue_incoming = aim_purge_rxqueue(aim_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; } -/* - * TODO: check and cure memory leakage in this function. - */ -int aim_authparse(struct command_rx_struct *command) +int aim_parsemotd_middle(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { - int iserror = 0; - struct aim_tlv_t *tlv = NULL; - char *errorurl = NULL; - short errorcode; - int z = 0; + rxcallback_t userfunc = NULL; + char *msg; + int ret=1; + struct aim_tlvlist_t *tlvlist; + u_short id; + + /* + * Dunno. + */ + id = aimutil_get16(command->data+10); + + /* + * TLVs follow + */ + tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12); + + msg = aim_gettlv_str(tlvlist, 0x000b, 1); + + userfunc = aim_callhandler(command->conn, 0x0001, 0x0013); + if (userfunc) + ret = userfunc(sess, command, id, msg); + + aim_freetlvchain(&tlvlist); + + return ret; + +} - if ( (command->data[0] == 0x00) && - (command->data[1] == 0x01) && - (command->data[2] == 0x00) && - (command->data[3] == 0x03) ) +int aim_handleredirect_middle(struct aim_session_t *sess, + struct command_rx_struct *command, ...) +{ + struct aim_tlv_t *tmptlv = NULL; + int serviceid = 0x00; + char cookie[AIM_COOKIELEN]; + char *ip = NULL; + rxcallback_t userfunc = NULL; + struct aim_tlvlist_t *tlvlist; + int ret = 1; + + if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10))) { - /* "server ready" -- can be ignored */ - return (aim_callbacks[AIM_CB_AUTH_SVRREADY])(command); + printf("libfaim: major bug: unable to read tlvchain from redirect\n"); + return ret; + } + + if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1))) + { + printf("libfaim: major bug: no service ID in tlvchain from redirect\n"); + aim_freetlvchain(&tlvlist); + return ret; } - else if ( (command->data[0] == 0x00) && - (command->data[1] == 0x07) && - (command->data[2] == 0x00) && - (command->data[3] == 0x05) ) + serviceid = aimutil_get16(tmptlv->value); + + if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1))) + { + printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid); + aim_freetlvchain(&tlvlist); + return ret; + } + + if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1))) { - /* "information change reply" */ - return (aim_callbacks[AIM_CB_AUTH_INFOCHNG_REPLY])(command); + printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid); + aim_freetlvchain(&tlvlist); + return ret; + } + memcpy(cookie, tmptlv->value, AIM_COOKIELEN); + + if (serviceid == AIM_CONN_TYPE_CHAT) + { + /* + * Chat hack. + * + */ + userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); + if (userfunc) + ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin); + free(sess->pendingjoin); + sess->pendingjoin = NULL; } else { - /* anything else -- usually used for login; just parse as pure TLVs */ - + userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); + if (userfunc) + ret = userfunc(sess, command, serviceid, ip, cookie); + } - /* all this block does is figure out if it's an - error or a success, nothing more */ - while (z < command->commandlen) - { - tlv = aim_grabtlvstr(&(command->data[z])); - switch(tlv->type) - { - case 0x0001: /* screen name */ - aim_logininfo.screen_name = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0004: /* error URL */ - errorurl = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0005: /* BOS IP */ - aim_logininfo.BOSIP = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0006: /* auth cookie */ - aim_logininfo.cookie = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv=NULL; - break; - case 0x0011: /* email addy */ - aim_logininfo.email = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0013: /* registration status */ - aim_logininfo.regstatus = *(tlv->value); - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - break; - case 0x0008: /* error code */ - errorcode = *(tlv->value); - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - iserror = 1; - break; - default: - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - /* dunno */ - } - } + /* + * XXX: Is there a leak here? Where does IP get freed? + */ + aim_freetlvchain(&tlvlist); - if (iserror && - errorurl && - errorcode) - return (aim_callbacks[AIM_CB_AUTH_ERROR])(command, &aim_logininfo, errorurl, errorcode); - else if (aim_logininfo.screen_name && - aim_logininfo.cookie && aim_logininfo.BOSIP) - return (aim_callbacks[AIM_CB_AUTH_SUCCESS])(command, &aim_logininfo); - else - return (aim_callbacks[AIM_CB_AUTH_OTHER])(command); - } + return ret; } -/* - * TODO: check for and cure any memory leaks here. - */ -int aim_handleredirect_middle(struct command_rx_struct *command, ...) +int aim_parse_unknown(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { - struct aim_tlv_t *tlv = NULL; - int z = 10; - int serviceid; - char *cookie; - char *ip; + u_int i = 0; - while (z < command->commandlen) - { - tlv = aim_grabtlvstr(&(command->data[z])); - switch(tlv->type) - { - case 0x000d: /* service id */ - aim_freetlv(&tlv); - /* regrab as an int */ - tlv = aim_grabtlv(&(command->data[z])); - serviceid = (tlv->value[0] << 8) + tlv->value[1]; /* hehe */ - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - break; - case 0x0005: /* service server IP */ - ip = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0006: /* auth cookie */ - cookie = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - default: - /* dunno */ - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - } - } - return (aim_callbacks[AIM_CB_LOGIN_P3D_F])(command, serviceid, ip, cookie); -} - -int aim_parse_unknown(struct command_rx_struct *command, ...) -{ - int i = 0; - - printf("\nRecieved unknown packet:"); + faimdprintf(1, "\nRecieved unknown packet:"); for (i = 0; i < command->commandlen; i++) { @@ -464,18 +689,20 @@ * Middle handler for 0x0001 snac of each family. * */ -int aim_parse_generalerrs(struct command_rx_struct *command, ...) +int aim_parse_generalerrs(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { u_short family; u_short subtype; - family = (command->data[0] << 8) + command->data[1]; - subtype = (command->data[2] << 8) + command->data[3]; + + family = aimutil_get16(command->data+0); + subtype= aimutil_get16(command->data+2); switch(family) { default: /* Unknown family */ - return (aim_callbacks[AIM_CB_UNKNOWN])(command); + return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command); } return 1;