X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/blobdiff_plain/5e02cf4469b54ab840378d8830db7bdb28ef46ea..1449ad2bc8b00bd9171d392d71da0a45dff71f0a:/aim_rxhandlers.c diff --git a/aim_rxhandlers.c b/aim_rxhandlers.c index 7e4fc75..16b7744 100644 --- a/aim_rxhandlers.c +++ b/aim_rxhandlers.c @@ -13,7 +13,7 @@ * 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; @@ -181,62 +181,68 @@ int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...) 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; 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; - } + for (cur = conn->handlerlist; cur; ) { + struct aim_rxcblist_t *tmp; + + tmp = cur->next; + free(cur); + cur = tmp; + } + conn->handlerlist = NULL; + 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; @@ -255,14 +261,15 @@ 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); @@ -294,7 +301,7 @@ 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; @@ -311,6 +318,19 @@ int aim_rxdispatch(struct aim_session_t *sess) 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: /* @@ -323,48 +343,52 @@ 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 { - u_short family,subtype; + 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 */ -#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); + workingPtr->handled = aim_authkeyparse(sess, 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); + workingPtr->handled = aim_parse_hostonline(sess, workingPtr); else - workingPtr->handled = aim_authparse(sess, workingPtr); + 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: - /* Old login protocol */ - /* any user callbacks will be called from here */ - workingPtr->handled = aim_authparse(sess, workingPtr); -#endif + break; } } break; @@ -373,7 +397,7 @@ int aim_rxdispatch(struct aim_session_t *sess) u_short family; u_short subtype; - if (workingPtr->type == 0x04) { + if (workingPtr->hdr.oscar.type == 0x04) { workingPtr->handled = aim_negchan_middle(sess, workingPtr); break; } @@ -384,7 +408,7 @@ 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; @@ -394,7 +418,7 @@ 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); @@ -403,22 +427,29 @@ int aim_rxdispatch(struct aim_session_t *sess) 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); + 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; + 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; } + break; case 0x0002: /* Family: Location */ switch (subtype) { case 0x0001: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr); + workingPtr->handled = aim_parse_locateerr(sess, workingPtr); break; case 0x0003: workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr); @@ -430,13 +461,14 @@ int aim_rxdispatch(struct aim_session_t *sess) 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_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr); + workingPtr->handled = aim_parse_buddyrights(sess, workingPtr); break; case 0x000b: /* oncoming buddy */ workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr); @@ -448,7 +480,7 @@ 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); @@ -456,11 +488,17 @@ int aim_rxdispatch(struct aim_session_t *sess) 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_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr); + 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); @@ -470,7 +508,7 @@ int aim_rxdispatch(struct aim_session_t *sess) 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); + 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; @@ -486,7 +524,7 @@ int aim_rxdispatch(struct aim_session_t *sess) workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr); } break; - case 0x000b: + case 0x000b: { if (subtype == 0x0001) workingPtr->handled = aim_parse_generalerrs(sess, workingPtr); else if (subtype == 0x0002) @@ -494,21 +532,30 @@ int aim_rxdispatch(struct aim_session_t *sess) else 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; 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 == 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 { @@ -522,17 +569,19 @@ 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 - printf("Chat: unknown snac %04x/%04x\n", family, subtype); + 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); @@ -550,8 +599,25 @@ int aim_rxdispatch(struct aim_session_t *sess) } 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, channel = %02x, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->type, workingPtr->commandlen); + 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; } @@ -569,8 +635,92 @@ int aim_rxdispatch(struct aim_session_t *sess) return 0; } -int aim_parsemotd_middle(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; + 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; + int i; + int code; + unsigned long parmid, windowsize, clear, alert, limit, disconnect; + unsigned long currentavg, maxavg; + + i = 10; + + code = aimutil_get16(command->data+i); + i += 2; + + parmid = 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, code, parmid, 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(command->data+i, &userinfo); + + if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0010))) + ret = userfunc(sess, command, newevil, &userinfo); + + return ret; +} + +faim_internal int aim_parsemotd_middle(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { rxcallback_t userfunc = NULL; char *msg; @@ -579,140 +729,171 @@ int aim_parsemotd_middle(struct aim_session_t *sess, u_short id; /* - * Dunno. + * 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 */ - tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12); - - msg = aim_gettlv_str(tlvlist, 0x000b, 1); + 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) ret = userfunc(sess, command, id, msg); aim_freetlvchain(&tlvlist); + free(msg); - return ret; + 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; } -int aim_handleredirect_middle(struct aim_session_t *sess, - struct command_rx_struct *command, ...) +faim_internal 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]; + 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); - 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); - 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); - /* - * XXX: Is there a leak here? Where does IP get freed? - */ 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; + 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; } -int aim_negchan_middle(struct aim_session_t *sess, - struct command_rx_struct *command) +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 (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; } @@ -723,23 +904,25 @@ int aim_negchan_middle(struct aim_session_t *sess, * 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; + 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; }