X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/blobdiff_plain/bb010ae088b7747f753d1f25a08c7aa30574af71..00ef5271216e3bea9b233ce26a3c0f21fbca931f:/src/rxhandlers.c diff --git a/src/rxhandlers.c b/src/rxhandlers.c index e9c09bf..2f897da 100644 --- a/src/rxhandlers.c +++ b/src/rxhandlers.c @@ -10,6 +10,118 @@ #define FAIM_INTERNAL #include +static aim_module_t *findmodule(struct aim_session_t *sess, const char *name) +{ + aim_module_t *cur; + + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + if (strcmp(name, cur->name) == 0) + return cur; + } + + return NULL; +} + +faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst)(struct aim_session_t *, aim_module_t *)) +{ + aim_module_t *mod; + + if (!sess || !modfirst) + return -1; + + if (!(mod = malloc(sizeof(aim_module_t)))) + return -1; + memset(mod, 0, sizeof(aim_module_t)); + + if (modfirst(sess, mod) == -1) { + free(mod); + return -1; + } + + if (findmodule(sess, mod->name)) { + if (mod->shutdown) + mod->shutdown(sess, mod); + free(mod); + return -1; + } + + mod->next = (aim_module_t *)sess->modlistv; + (aim_module_t *)sess->modlistv = mod; + + faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family); + + return 0; +} + +faim_internal void aim__shutdownmodules(struct aim_session_t *sess) +{ + aim_module_t *cur; + + for (cur = (aim_module_t *)sess->modlistv; cur; ) { + aim_module_t *tmp; + + tmp = cur->next; + + if (cur->shutdown) + cur->shutdown(sess, cur); + + free(cur); + + cur = tmp; + } + + sess->modlistv = NULL; + + return; +} + +static int consumesnac(struct aim_session_t *sess, struct command_rx_struct *rx) +{ + aim_module_t *cur; + aim_modsnac_t snac; + + snac.family = aimutil_get16(rx->data+0); + snac.subtype = aimutil_get16(rx->data+2); + snac.flags = aimutil_get16(rx->data+4); + snac.id = aimutil_get32(rx->data+6); + + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + + if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && + (cur->family != snac.family)) + continue; + + if (cur->snachandler(sess, cur, rx, &snac, rx->data+10, rx->commandlen-10)) + return 1; + + } + + return 0; +} + +static int consumenonsnac(struct aim_session_t *sess, struct command_rx_struct *rx, unsigned short family, unsigned short subtype) +{ + aim_module_t *cur; + aim_modsnac_t snac; + + snac.family = family; + snac.subtype = subtype; + snac.flags = snac.id = 0; + + for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { + + if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && + (cur->family != snac.family)) + continue; + + if (cur->snachandler(sess, cur, rx, &snac, rx->data, rx->commandlen)) + return 1; + + } + + return 0; +} + /* * Bleck functions get called when there's no non-bleck functions * around to cleanup the mess... @@ -308,10 +420,15 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) { int i = 0; struct command_rx_struct *workingPtr = NULL; + static int critical = 0; + if (critical) + return 0; /* don't call recursively! */ + + critical = 1; + if (sess->queue_incoming == NULL) { faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n"); - return 0; } else { workingPtr = sess->queue_incoming; for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) { @@ -366,146 +483,17 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) workingPtr->handled = aim_negchan_middle(sess, workingPtr); continue; } + + if ((workingPtr->handled = consumesnac(sess, workingPtr))) + continue; - family = aimutil_get16(workingPtr->data); - subtype = aimutil_get16(workingPtr->data+2); - - if (family == 0x0001) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_parse_hostonline(sess, workingPtr); - else if (subtype == 0x0005) - workingPtr->handled = aim_handleredirect_middle(sess, workingPtr); - else if (subtype == 0x0007) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr); - else if (subtype == 0x000a) - workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr); - else if (subtype == 0x000f) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr); - else if (subtype == 0x0010) - workingPtr->handled = aim_parse_evilnotify_middle(sess, workingPtr); - else if (subtype == 0x0013) - workingPtr->handled = aim_parsemotd_middle(sess, workingPtr); - else if (subtype == 0x0018) - workingPtr->handled = aim_parse_hostversions(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0xffff, workingPtr); - - } else if (family == 0x0002) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_locateerr(sess, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr); - else if (subtype == 0x0006) - workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr); - - } else if (family == 0x0003) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_parse_buddyrights(sess, workingPtr); - else if (subtype == 0x000b) - workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr); - else if (subtype == 0x000c) - workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr); - - } else if (family == 0x0004) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr); - else if (subtype == 0x0005) - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr); - else if (subtype == 0x0006) - workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr); - else if (subtype == 0x0007) - workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr); - else if (subtype == 0x000a) - workingPtr->handled = aim_parse_missedcall(sess, workingPtr); - else if (subtype == 0x000c) - workingPtr->handled = aim_parse_msgack_middle(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr); - - } else if (family == 0x0007) { - - if (subtype == 0x0003) - workingPtr->handled = aim_parse_infochange(sess, workingPtr); - else if (subtype == 0x0005) - workingPtr->handled = aim_parse_infochange(sess, workingPtr); - else if (subtype == 0x0007) - workingPtr->handled = aim_parse_accountconfirm(sess, workingPtr); - break; - - } else if (family == 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); - - } else if (family == 0x000a) { - - if (subtype == 0x0001) - workingPtr->handled = aim_parse_searcherror(sess, workingPtr); - else if (subtype == 0x0003) - workingPtr->handled = aim_parse_searchreply(sess, workingPtr); - else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr); - - } else if (family == 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); - - } else if (family == 0x000d) { - - if (subtype == 0x0009) - workingPtr->handled = aim_chatnav_parse_info(sess, 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 if (family == 0x0013) { - - faimdprintf(sess, 0, "lalala: 0x%04x/0x%04x\n", family, subtype); - - } else if (family == 0x0017) { /* New login protocol */ - - 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); - - } else if (family == AIM_CB_FAM_SPECIAL) { - - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); + if (!workingPtr->handled) { + family = aimutil_get16(workingPtr->data); + subtype = aimutil_get16(workingPtr->data+2); + faimdprintf(sess, 1, "warning: unhandled packet %04x/%04x\n", family, subtype); + consumenonsnac(sess, workingPtr, 0xffff, 0xffff); /* last chance! */ + workingPtr->handled = 1; } } } @@ -517,340 +505,10 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) * you'll have :) */ aim_purge_rxqueue(sess); - - return 0; -} - -faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command) -{ - rxcallback_t userfunc = NULL; - 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(sess, command->conn, 0x0004, 0x000c))) - ret = userfunc(sess, command, type, sn); - - return ret; -} - -/* - * The Rate Limiting System, An Abridged Guide to Nonsense. - * - * OSCAR defines several 'rate classes'. Each class has seperate - * rate limiting properties (limit level, alert level, disconnect - * level, etc), and a set of SNAC family/type pairs associated with - * it. The rate classes, their limiting properties, and the definitions - * of which SNACs are belong to which class, are defined in the - * Rate Response packet at login to each host. - * - * Logically, all rate offenses within one class count against further - * offenses for other SNACs in the same class (ie, sending messages - * too fast will limit the number of user info requests you can send, - * since those two SNACs are in the same rate class). - * - * Since the rate classes are defined dynamically at login, the values - * below may change. But they seem to be fairly constant. - * - * Currently, BOS defines five rate classes, with the commonly used - * members as follows... - * - * Rate class 0x0001: - * - Everything thats not in any of the other classes - * - * Rate class 0x0002: - * - Buddy list add/remove - * - Permit list add/remove - * - Deny list add/remove - * - * Rate class 0x0003: - * - User information requests - * - Outgoing ICBMs - * - * Rate class 0x0004: - * - A few unknowns: 2/9, 2/b, and f/2 - * - * Rate class 0x0005: - * - Chat room create - * - Outgoing chat ICBMs - * - * The only other thing of note is that class 5 (chat) has slightly looser - * limiting properties than class 3 (normal messages). But thats just a - * small bit of trivia for you. - * - * The last thing that needs to be learned about the rate limiting - * system is how the actual numbers relate to the passing of time. This - * seems to be a big mystery. - * - */ -faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command) -{ - rxcallback_t userfunc = NULL; - int ret = 1; - int i; - int code; - unsigned long rateclass, windowsize, clear, alert, limit, disconnect; - unsigned long currentavg, maxavg; - - i = 10; - - code = aimutil_get16(command->data+i); - i += 2; - - rateclass = aimutil_get16(command->data+i); - i += 2; - - windowsize = aimutil_get32(command->data+i); - i += 4; - clear = aimutil_get32(command->data+i); - i += 4; - alert = aimutil_get32(command->data+i); - i += 4; - limit = aimutil_get32(command->data+i); - i += 4; - disconnect = aimutil_get32(command->data+i); - i += 4; - currentavg = aimutil_get32(command->data+i); - i += 4; - maxavg = aimutil_get32(command->data+i); - i += 4; - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x000a))) - ret = userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg); - - 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; - int i; - unsigned short newevil; - struct aim_userinfo_s userinfo; - - i = 10; - newevil = aimutil_get16(command->data+10); - i += 2; - - memset(&userinfo, 0, sizeof(struct aim_userinfo_s)); - if (command->commandlen-i) - i += aim_extractuserinfo(sess, command->data+i, &userinfo); - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0010))) - ret = userfunc(sess, command, newevil, &userinfo); + critical = 0; - 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(sess, command->conn, 0x0001, 0x0013); - if (userfunc) - ret = userfunc(sess, command, id, msg); - - aim_freetlvchain(&tlvlist); - free(msg); - - return ret; -} - -faim_internal int aim_parse_hostonline(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - rxcallback_t userfunc = NULL; - int ret = 1; - unsigned short *families = NULL; - int famcount = 0, i; - - famcount = (command->commandlen-10)/2; - if (!(families = malloc(command->commandlen-10))) - return ret; - - for (i = 0; i < famcount; i++) - families[i] = aimutil_get16(command->data+((i*2)+10)); - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0003))) - ret = userfunc(sess, command, famcount, families); - - free(families); - - return ret; -} - -faim_internal int aim_parse_accountconfirm(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - rxcallback_t userfunc = NULL; - int ret = 1; - int status = -1; - - status = aimutil_get16(command->data+10); - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, 0x0007))) - ret = userfunc(sess, command, status); - - return ret; -} - -faim_internal int aim_parse_infochange(struct aim_session_t *sess, - struct command_rx_struct *command) -{ - unsigned short subtype; /* called for both reply and change-reply */ - int i; - - subtype = aimutil_get16(command->data+2); - - /* - * struct { - * unsigned short perms; - * unsigned short tlvcount; - * aim_tlv_t tlvs[tlvcount]; - * } admin_info[n]; - */ - for (i = 10; i < command->commandlen; ) { - int perms, tlvcount; - - perms = aimutil_get16(command->data+i); - i += 2; - - tlvcount = aimutil_get16(command->data+i); - i += 2; - - while (tlvcount) { - rxcallback_t userfunc; - struct aim_tlv_t *tlv; - int str = 0; - - if ((aimutil_get16(command->data+i) == 0x0011) || - (aimutil_get16(command->data+i) == 0x0004)) - str = 1; - - if (str) - tlv = aim_grabtlvstr(command->data+i); - else - tlv = aim_grabtlv(command->data+i); - - /* XXX fix so its only called once for the entire packet */ - if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, subtype))) - userfunc(sess, command, perms, tlv->type, tlv->length, tlv->value, str); - - if (tlv) - i += 2+2+tlv->length; - - if (tlv && tlv->value) - free(tlv->value); - if (tlv) - free(tlv); - - tlvcount--; - } - } - - return 1; -} - -faim_internal int aim_parse_hostversions(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - rxcallback_t userfunc = NULL; - int ret = 1; - int vercount; - - vercount = (command->commandlen-10)/4; - - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0018))) - ret = userfunc(sess, command, vercount, command->data+10); - - return ret; -} - -faim_internal int aim_handleredirect_middle(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - int serviceid = 0; - unsigned char *cookie = NULL; - char *ip = NULL; - rxcallback_t userfunc = NULL; - struct aim_tlvlist_t *tlvlist; - int ret = 1; - - tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10); - - if (aim_gettlv(tlvlist, 0x000d, 1)) - serviceid = aim_gettlv16(tlvlist, 0x000d, 1); - if (aim_gettlv(tlvlist, 0x0005, 1)) - ip = aim_gettlv_str(tlvlist, 0x0005, 1); - if (aim_gettlv(tlvlist, 0x0006, 1)) - cookie = aim_gettlv_str(tlvlist, 0x0006, 1); - - if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) { - - /* - * Chat hack. - * - */ - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005))) - ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin, (int)sess->pendingjoinexchange); - free(sess->pendingjoin); - sess->pendingjoin = NULL; - sess->pendingjoinexchange = 0; - } else if (!serviceid || !ip || !cookie) { /* yeep! */ - ret = 1; - } else { - if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005))) - ret = userfunc(sess, command, serviceid, ip, cookie); - } - - if (ip) - free(ip); - if (cookie) - free(cookie); - - aim_freetlvchain(&tlvlist); - - return ret; + return 0; } faim_internal int aim_parse_unknown(struct aim_session_t *sess, @@ -889,7 +547,7 @@ faim_internal int aim_negchan_middle(struct aim_session_t *sess, /* Used only by the older login protocol */ /* XXX remove this special case? */ if (command->conn->type == AIM_CONN_TYPE_AUTH) - return aim_authparse(sess, command); + return consumenonsnac(sess, command, 0x0017, 0x0003); tlvlist = aim_readtlvchain(command->data, command->commandlen); @@ -900,7 +558,7 @@ faim_internal int aim_negchan_middle(struct aim_session_t *sess, msg = aim_gettlv_str(tlvlist, 0x000b, 1); if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) - ret = userfunc(sess, command, code, msg); + ret = userfunc(sess, command, code, msg); aim_freetlvchain(&tlvlist); @@ -910,32 +568,3 @@ faim_internal int aim_negchan_middle(struct aim_session_t *sess, return ret; } -/* - * aim_parse_generalerrs() - * - * Middle handler for 0x0001 snac of each family. - * - */ -faim_internal int aim_parse_generalerrs(struct aim_session_t *sess, - struct command_rx_struct *command, ...) -{ - unsigned short family; - unsigned short subtype; - int ret = 1; - int error = 0; - rxcallback_t userfunc = NULL; - - family = aimutil_get16(command->data+0); - subtype= aimutil_get16(command->data+2); - - if (command->commandlen > 10) - error = aimutil_get16(command->data+10); - - if ((userfunc = aim_callhandler(sess, command->conn, family, subtype))) - ret = userfunc(sess, command, error); - - return ret; -} - - -