X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/blobdiff_plain/871e2fd07a6381b9e2dcacc27608541ca826e3d6..37ee990eab0e60fadbc1555d3f4a7e85d2026297:/aim_rxhandlers.c diff --git a/aim_rxhandlers.c b/aim_rxhandlers.c index 4f5cf74..8e55514 100644 --- a/aim_rxhandlers.c +++ b/aim_rxhandlers.c @@ -7,6 +7,7 @@ * */ +#define FAIM_INTERNAL #include /* @@ -228,14 +229,14 @@ faim_export int aim_clearhandlers(struct aim_conn_t *conn) if (!conn) return -1; - cur = conn->handlerlist; - while(cur) { + for (cur = conn->handlerlist; cur; ) { struct aim_rxcblist_t *tmp; tmp = cur->next; free(cur); cur = tmp; } + conn->handlerlist = NULL; return 0; } @@ -343,16 +344,17 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) workingPtr->handled = 1; break; case AIM_CONN_TYPE_AUTH: { - u_long head; + unsigned long head; head = aimutil_get32(workingPtr->data); - if (head == 0x00000001) { + if ((head == 0x00000001) && (workingPtr->commandlen == 4)) { faimdprintf(1, "got connection ack on auth line\n"); - workingPtr->handled = 1; - } else if (workingPtr->hdr.oscar.type == 0x0004) { + 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 { - u_short family,subtype; + unsigned short family,subtype; family = aimutil_get16(workingPtr->data); subtype = aimutil_get16(workingPtr->data+2); @@ -369,21 +371,24 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) 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 + case 0x0001: + if (subtype == 0x0003) + workingPtr->handled = aim_parse_hostonline(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; + } else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr); + break; + default: break; } } @@ -404,7 +409,7 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) 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); + 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; @@ -414,7 +419,7 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); break; case 0x0003: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr); + workingPtr->handled = aim_parse_hostonline(sess, workingPtr); break; case 0x0005: workingPtr->handled = aim_handleredirect_middle(sess, workingPtr); @@ -434,6 +439,9 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) case 0x0013: workingPtr->handled = aim_parsemotd_middle(sess, workingPtr); break; + case 0x0018: + workingPtr->handled = aim_parse_hostversions(sess, workingPtr); + break; default: workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr); break; @@ -473,7 +481,7 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr); } break; - case 0x0004: /* Family: Messeging */ + case 0x0004: /* Family: Messaging */ switch (subtype) { case 0x0001: workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr); @@ -508,10 +516,10 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) case 0x000a: /* Family: User lookup */ switch (subtype) { case 0x0001: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr); + workingPtr->handled = aim_parse_searcherror(sess, workingPtr); break; case 0x0003: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr); + workingPtr->handled = aim_parse_searchreply(sess, workingPtr); break; default: workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr); @@ -526,6 +534,10 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr); break; } + case 0x0013: { + printf("lalala: 0x%04x/0x%04x\n", family, subtype); + break; + } case AIM_CB_FAM_SPECIAL: workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); break; @@ -540,10 +552,11 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) 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); + + 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) && (subtype == 0x0003)) { + workingPtr->handled = aim_parse_hostonline(sess, workingPtr); } else if ((family == 0x000d) && (subtype == 0x0009)) { workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr); } else { @@ -557,15 +570,17 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) 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 ((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); + workingPtr->handled = aim_parse_hostonline(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 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); } else if (family == 0x000e) { @@ -645,21 +660,89 @@ faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct com 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; - unsigned long newrate; + int i; + int code; + unsigned long rateclass, windowsize, clear, alert, limit, disconnect; + unsigned long currentavg, maxavg; - if (command->commandlen != 0x2f) { - printf("faim: unknown rate change length 0x%04x\n", command->commandlen); - return 1; - } - - newrate = aimutil_get32(command->data+34); + 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(command->conn, 0x0001, 0x000a))) - ret = userfunc(sess, command, newrate); + ret = userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg); return ret; } @@ -667,25 +750,22 @@ faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct 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; + int ret = 1; + int i; + unsigned short newevil; + struct aim_userinfo_s userinfo; - if(!(sn = (char *)calloc(1, pos+1))) - return 1; + i = 10; + newevil = aimutil_get16(command->data+10); + i += 2; - memcpy(sn, command->data+13, pos); + memset(&userinfo, 0, sizeof(struct aim_userinfo_s)); + if (command->commandlen-i) + i += aim_extractuserinfo(command->data+i, &userinfo); if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0010))) - ret = userfunc(sess, command, sn); + ret = userfunc(sess, command, newevil, &userinfo); - free(sn); - return ret; } @@ -731,68 +811,86 @@ faim_internal int aim_parsemotd_middle(struct aim_session_t *sess, 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(command->conn, 0x0001, 0x0003))) + ret = userfunc(sess, command, famcount, families); + + free(families); + + return ret; +} + +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(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, ...) + struct command_rx_struct *command, ...) { - struct aim_tlv_t *tmptlv = NULL; - int serviceid = 0x00; - unsigned char cookie[AIM_COOKIELEN]; + int serviceid = 0; + unsigned char *cookie = NULL; 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); - - if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1))) - { - printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid); - free(ip); - aim_freetlvchain(&tlvlist); - return ret; - } - - 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); + 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(command->conn, 0x0001, 0x0005))) + ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin, (int)sess->pendingjoinexchange); free(sess->pendingjoin); sess->pendingjoin = NULL; - } - else - { - userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); - if (userfunc) - ret = userfunc(sess, command, serviceid, ip, cookie); - } + sess->pendingjoinexchange = 0; + } else if (!serviceid || !ip || !cookie) { /* yeep! */ + ret = 1; + } else { + if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0005))) + ret = userfunc(sess, command, serviceid, ip, cookie); + } + + if (ip) + free(ip); + if (cookie) + free(cookie); - free(ip); aim_freetlvchain(&tlvlist); return ret; @@ -803,6 +901,9 @@ faim_internal int aim_parse_unknown(struct aim_session_t *sess, { u_int i = 0; + if (!sess || !command) + return 1; + faimdprintf(1, "\nRecieved unknown packet:"); for (i = 0; i < command->commandlen; i++) @@ -825,25 +926,24 @@ faim_internal int aim_negchan_middle(struct aim_session_t *sess, 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 (aim_gettlv(tlvlist, 0x0009, 1)) + code = aim_gettlv16(tlvlist, 0x0009, 1); - if ((tmptlv = aim_gettlv(tlvlist, 0x000b, 1))) + if (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) + if ((userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) ret = userfunc(sess, command, code, msg); aim_freetlvchain(&tlvlist); - free(msg); + + if (msg) + free(msg); return ret; } @@ -857,20 +957,22 @@ faim_internal int aim_negchan_middle(struct aim_session_t *sess, faim_internal int aim_parse_generalerrs(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - u_short family; - u_short subtype; + 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); - switch(family) - { - default: - /* Unknown family */ - return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command); - } + if (command->commandlen > 10) + error = aimutil_get16(command->data+10); - return 1; + if ((userfunc = aim_callhandler(command->conn, family, subtype))) + ret = userfunc(sess, command, error); + + return ret; }