X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/blobdiff_plain/ee49b735a9cbcb7b15f86e0e3dc69118ba2a4607..64c78745f1e1ef7ecd8166b3af5b80d0d142cfb9:/aim_rxhandlers.c diff --git a/aim_rxhandlers.c b/aim_rxhandlers.c index 75167b8..5097342 100644 --- a/aim_rxhandlers.c +++ b/aim_rxhandlers.c @@ -7,6 +7,7 @@ * */ +#define FAIM_INTERNAL #include /* @@ -370,16 +371,27 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) else workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr); break; + case 0x0001: if (subtype == 0x0003) 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 == 0x0018) + workingPtr->handled = aim_parse_hostversions(sess, workingPtr); else - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr); + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 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); + 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; + case AIM_CB_FAM_SPECIAL: if (subtype == AIM_CB_SPECIAL_DEBUGCONN_CONNECT) { workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); @@ -387,6 +399,7 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) } else workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr); break; + default: break; } @@ -480,7 +493,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); @@ -515,10 +528,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); @@ -533,6 +546,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; @@ -542,6 +559,22 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) } /* switch(family) */ break; } /* AIM_CONN_TYPE_BOS */ + case AIM_CONN_TYPE_ADS: { + unsigned short family; + unsigned 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 == 0x0001) && (subtype == 0x0003)) { + workingPtr->handled = aim_parse_hostonline(sess, workingPtr); + } else { + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); + } + break; + } case AIM_CONN_TYPE_CHATNAV: { u_short family; u_short subtype; @@ -574,6 +607,8 @@ faim_export int aim_rxdispatch(struct aim_session_t *sess) 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) { @@ -653,21 +688,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; } @@ -675,25 +778,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; } @@ -762,6 +862,78 @@ faim_internal int aim_parse_hostonline(struct aim_session_t *sess, 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(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(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, ...) { @@ -885,20 +1057,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; }