X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/blobdiff_plain/a25832e66b80e7159f37795cff5593b748ac5f59..313a06b7b4be217e90a17413862dc04552f693c3:/aim_rxhandlers.c diff --git a/aim_rxhandlers.c b/aim_rxhandlers.c index d6bdc98..bc67cbf 100644 --- a/aim_rxhandlers.c +++ b/aim_rxhandlers.c @@ -13,83 +13,243 @@ * 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, ...) +faim_internal int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...) { u_short family; u_short subtype; - family = (workingPtr->data[0] << 8) + workingPtr->data[1]; - subtype = (workingPtr->data[2] << 8) + workingPtr->data[3]; - printf("bleck: null handler for %04x/%04x\n", family, subtype); + + u_short maxf; + u_short maxs; + + /* 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", + } + }; + + 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; } -int aim_conn_addhandler(struct aim_session_t *sess, +faim_export 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; + struct aim_rxcblist_t *newcb; 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; - new->type = type; - new->flags = flags; + if (!(newcb = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t)))) + return -1; + newcb->family = family; + newcb->type = type; + newcb->flags = flags; if (!newhandler) - new->handler = &bleck; + newcb->handler = &bleck; else - new->handler = newhandler; - new->next = NULL; + newcb->handler = newhandler; + newcb->next = NULL; - cur = conn->handlerlist; - if (!cur) - conn->handlerlist = new; - else - { - while (cur->next) - cur = cur->next; - cur->next = new; - } + if (!conn->handlerlist) + conn->handlerlist = newcb; + else { + struct aim_rxcblist_t *cur; + + cur = conn->handlerlist; + + while (cur->next) + cur = cur->next; + cur->next = newcb; + } return 0; } -int aim_clearhandlers(struct aim_conn_t *conn) +faim_export int aim_clearhandlers(struct aim_conn_t *conn) { - struct aim_rxcblist_t *cur,*tmp; + struct aim_rxcblist_t *cur; + if (!conn) return -1; cur = conn->handlerlist; - while(cur) - { - tmp = cur->next; - free(cur); - cur = tmp; - } + while(cur) { + struct aim_rxcblist_t *tmp; + + tmp = cur->next; + free(cur); + cur = tmp; + } + return 0; } -rxcallback_t aim_callhandler(struct aim_conn_t *conn, - u_short family, - u_short type) +faim_internal rxcallback_t aim_callhandler(struct aim_conn_t *conn, + u_short family, + u_short type) { struct aim_rxcblist_t *cur; 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) @@ -101,20 +261,21 @@ rxcallback_t aim_callhandler(struct aim_conn_t *conn, 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) +faim_internal 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 0; + return 1; /* XXX */ } /* @@ -140,427 +301,564 @@ int aim_callhandler_noparam(struct aim_session_t *sess, TODO: Allow for NULL handlers. */ -int aim_rxdispatch(struct aim_session_t *sess) +faim_export 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++) - { - switch(workingPtr->conn->type) - { - 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"); + 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; + + /* + * This is a debugging/sanity check only and probably could/should be removed + * for stable code. + */ + if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) && + (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || + ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) && + (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) { + printf("faim: rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type); + workingPtr->handled = 1; + 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: { + unsigned long head; + + head = aimutil_get32(workingPtr->data); + if ((head == 0x00000001) && (workingPtr->commandlen == 4)) { + faimdprintf(1, "got connection ack on auth line\n"); + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr); + } else if (workingPtr->hdr.oscar.type == 0x04) { + /* Used only by the older login protocol */ + workingPtr->handled = aim_authparse(sess, workingPtr); + } else { + unsigned short family,subtype; + + family = aimutil_get16(workingPtr->data); + subtype = aimutil_get16(workingPtr->data+2); + + switch (family) { + /* New login protocol */ + 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_authkeyparse(sess, workingPtr); + else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, 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; + case AIM_CB_FAM_SPECIAL: + if (subtype == AIM_CB_SPECIAL_DEBUGCONN_CONNECT) { + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); + break; + } /* others fall through */ + default: +#if 0 + /* 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(sess, workingPtr); - } - } - 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_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0013, 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 - { - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); - } - } - break; - case AIM_CONN_TYPE_CHAT: - printf("\nAHH! Dont know what to do with CHAT stuff yet!\n"); - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr); - break; - default: - printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type); - 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; + } + } + break; + } + case AIM_CONN_TYPE_BOS: { + u_short family; + u_short subtype; + + if (workingPtr->hdr.oscar.type == 0x04) { + workingPtr->handled = aim_negchan_middle(sess, workingPtr); + break; } - } - sess->queue_incoming = aim_purge_rxqueue(sess->queue_incoming); + 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, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, 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_parse_ratechange_middle(sess, workingPtr); + break; + case 0x000f: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr); + break; + case 0x0010: + workingPtr->handled = aim_parse_evilnotify_middle(sess, 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; + } + break; + case 0x0002: /* Family: Location */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_parse_locateerr(sess, 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; + } + break; + case 0x0003: /* Family: Buddy List */ + switch (subtype) { + case 0x0001: + workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); + break; + case 0x0003: + workingPtr->handled = aim_parse_buddyrights(sess, 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 0x0006: + workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr); + break; + case 0x0007: + workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr); + break; + case 0x000a: + workingPtr->handled = aim_parse_missedcall(sess, workingPtr); + break; + case 0x000c: + workingPtr->handled = aim_parse_msgack_middle(sess, 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_parse_bosrights(sess, 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; + } + case AIM_CB_FAM_SPECIAL: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); + break; + default: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); + break; + } /* switch(family) */ + break; + } /* AIM_CONN_TYPE_BOS */ + case AIM_CONN_TYPE_CHATNAV: { + u_short family; + u_short 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, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr); + } 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, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, 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 + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); + } 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; + } + case AIM_CONN_TYPE_RENDEZVOUS: { + /* make sure that we only get OFT frames on these connections */ + if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) { + printf("faim: internal error: non-OFT frames on OFT connection\n"); + workingPtr->handled = 1; /* get rid of it */ + break; + } + + /* XXX: implement this */ + printf("faim: OFT frame!\n"); + + break; + } + case AIM_CONN_TYPE_RENDEZVOUS_OUT: { + /* not possible */ + break; + } + default: + printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->commandlen); + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); + break; + } + } + } + + /* + * 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. - * TODO: update to use new tlvlist routines - */ -int aim_authparse(struct aim_session_t *sess, - struct command_rx_struct *command) +faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command) { rxcallback_t userfunc = NULL; - int iserror = 0; - struct aim_tlv_t *tlv = NULL; - char *errorurl = NULL; - short errorcode = 0x00; - u_int z = 0; - u_short family,subtype; - - family = aimutil_get16(command->data); - subtype= aimutil_get16(command->data+2); + char sn[MAXSNLEN]; + unsigned short type; + int i = 10+8; /* skip SNAC and cookie */ + int ret = 1; + unsigned char snlen; + + type = aimutil_get16(command->data+i); + i += 2; + + snlen = aimutil_get8(command->data+i); + i++; + + memset(sn, 0, sizeof(sn)); + strncpy(sn, (char *)command->data+i, snlen); + + if ((userfunc = aim_callhandler(command->conn, 0x0004, 0x000c))) + ret = userfunc(sess, command, type, sn); + + return ret; +} + +faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command) +{ + rxcallback_t userfunc = NULL; + int ret = 1; + unsigned long newrate; + + if (command->commandlen != 0x2f) { + printf("faim: unknown rate change length 0x%04x\n", command->commandlen); + return 1; + } - if ( (family == 0x0001) && - (subtype== 0x0003) ) - { - /* "server ready" -- can be ignored */ - userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY); - } - else if ( (family == 0x0007) && - (subtype== 0x0005) ) - { - /* "information change reply" */ - userfunc = aim_callhandler(command->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY); - } - else - { - /* anything else -- usually used for login; just parse as pure TLVs */ + newrate = aimutil_get32(command->data+34); - /* - * Free up the loginstruct first. - */ - sess->logininfo.screen_name[0] = '\0'; - if (sess->logininfo.BOSIP) - { - free(sess->logininfo.BOSIP); - sess->logininfo.BOSIP = NULL; - } - if (sess->logininfo.email) - { - free(sess->logininfo.email); - sess->logininfo.email = NULL; - } - sess->logininfo.regstatus = 0; - - /* 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 */ - if (tlv->length >= MAXSNLEN) - { - /* SN too large... truncate */ - printf("faim: login: screen name from OSCAR too long! (%d)\n", tlv->length); - strncpy(sess->logininfo.screen_name, tlv->value, MAXSNLEN); - } - else - strncpy(sess->logininfo.screen_name, tlv->value, tlv->length); - 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 */ - sess->logininfo.BOSIP = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0006: /* auth cookie */ - memcpy(sess->logininfo.cookie, tlv->value, AIM_COOKIELEN); - z += 2 + 2 + tlv->length; - free(tlv); - tlv=NULL; - break; - case 0x0011: /* email addy */ - sess->logininfo.email = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0013: /* registration status */ - sess->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 */ - } - } + if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x000a))) + ret = userfunc(sess, command, newrate); - if (iserror && - errorurl) - { - userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR); - if (userfunc) - return userfunc(sess, command, errorurl, errorcode); - return 0; - } - else if (sess->logininfo.screen_name[0] && - sess->logininfo.cookie[0] && sess->logininfo.BOSIP) - { - userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS); - if (userfunc) - return userfunc(sess, command); - return 0; - } - else - userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHOTHER); - } + return ret; +} +faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command) +{ + rxcallback_t userfunc = NULL; + int ret = 1, pos; + char *sn = NULL; + + if(command->commandlen < 12) /* a warning level dec sends this */ + return 1; + + if ((pos = aimutil_get8(command->data+ 12)) > MAXSNLEN) + return 1; + + if(!(sn = (char *)calloc(1, pos+1))) + return 1; + + memcpy(sn, command->data+13, pos); + + if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0010))) + ret = userfunc(sess, command, sn); + + free(sn); + + return ret; +} + +faim_internal int aim_parsemotd_middle(struct aim_session_t *sess, + struct command_rx_struct *command, ...) +{ + rxcallback_t userfunc = NULL; + char *msg; + int ret=1; + struct aim_tlvlist_t *tlvlist; + u_short id; + + /* + * Code. + * + * Valid values: + * 1 Mandatory upgrade + * 2 Advisory upgrade + * 3 System bulletin + * 4 Nothing's wrong ("top o the world" -- normal) + * + */ + id = aimutil_get16(command->data+10); + + /* + * TLVs follow + */ + if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12))) + return ret; + + if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) { + aim_freetlvchain(&tlvlist); + return ret; + } + + userfunc = aim_callhandler(command->conn, 0x0001, 0x0013); if (userfunc) - return userfunc(sess, command); - printf("handler not available!\n"); - return 0; + ret = userfunc(sess, command, id, msg); + + aim_freetlvchain(&tlvlist); + free(msg); + + return ret; } -/* - * TODO: check for and cure any memory leaks here. - */ -int aim_handleredirect_middle(struct aim_session_t *sess, +faim_internal int aim_handleredirect_middle(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - struct aim_tlv_t *tlv = NULL; - u_int z = 10; + struct aim_tlv_t *tmptlv = NULL; int serviceid = 0x00; - char *cookie = NULL; + unsigned 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))) + { + 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; + } + serviceid = aimutil_get16(tmptlv->value); - while (z < command->commandlen) + if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1))) { - 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 = aimutil_get16(tlv->value); - 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); - } + printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid); + free(ip); + aim_freetlvchain(&tlvlist); + return ret; } - userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); - if (userfunc) - return userfunc(sess, command, serviceid, ip, cookie); - return 0; + + if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1))) + { + printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid); + free(ip); + 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 + { + userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); + if (userfunc) + ret = userfunc(sess, command, serviceid, ip, cookie); + } + + free(ip); + aim_freetlvchain(&tlvlist); + + return ret; } -int aim_parse_unknown(struct aim_session_t *sess, - struct command_rx_struct *command, ...) +faim_internal int aim_parse_unknown(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { u_int i = 0; - printf("\nRecieved unknown packet:"); + if (!sess || !command) + return 1; + + faimdprintf(1, "\nRecieved unknown packet:"); for (i = 0; i < command->commandlen; i++) { if ((i % 8) == 0) - printf("\n\t"); + faimdprintf(1, "\n\t"); - printf("0x%2x ", command->data[i]); + faimdprintf(1, "0x%2x ", command->data[i]); } - printf("\n\n"); + faimdprintf(1, "\n\n"); return 1; } +faim_internal int aim_negchan_middle(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + struct aim_tlvlist_t *tlvlist; + char *msg = NULL; + unsigned short code = 0; + struct aim_tlv_t *tmptlv; + rxcallback_t userfunc = NULL; + int ret = 1; + + tlvlist = aim_readtlvchain(command->data, command->commandlen); + + if ((tmptlv = aim_gettlv(tlvlist, 0x0009, 1))) + code = aimutil_get16(tmptlv->value); + + if ((tmptlv = aim_gettlv(tlvlist, 0x000b, 1))) + msg = aim_gettlv_str(tlvlist, 0x000b, 1); + + userfunc = aim_callhandler(command->conn, + AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR); + if (userfunc) + ret = userfunc(sess, command, code, msg); + + aim_freetlvchain(&tlvlist); + free(msg); + + return ret; +} + /* * aim_parse_generalerrs() * * Middle handler for 0x0001 snac of each family. * */ -int aim_parse_generalerrs(struct aim_session_t *sess, - struct command_rx_struct *command, ...) +faim_internal int aim_parse_generalerrs(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { u_short family; u_short subtype;