Mercurial > pidgin
view libfaim/aim_rxhandlers.c @ 229:e8ea7f37e28f
[gaim-migrate @ 239]
One minor tweak to the buddy list cache. If we read a non-zero buddy list
from TOC and there is not a cache yet, create it.
committer: Tailor Script <tailor@pidgin.im>
author | Syd Logan <slogan> |
---|---|
date | Wed, 10 May 2000 08:29:02 +0000 |
parents | 68b230f8da5f |
children | 6ced2f1c8b24 |
line wrap: on
line source
/* aim_rxhandlers.c This file contains most all of the incoming packet handlers, along with aim_rxdispatch(), the Rx dispatcher. Queue/list management is actually done in aim_rxqueue.c. */ #include "aim.h" /* for most everything */ int bleck(struct command_rx_struct *param, ...) { return 1; } /* * The callbacks. Used to pass data up from the wire into the client. * * TODO: MASSIVE OVERHAUL. This method of doing it (array of function * pointers) is ugly. Overhaul may mean including chained callbacks * for having client features such as run-time loadable modules. * */ rxcallback_t aim_callbacks[] = { bleck, /* incoming IM */ bleck, /* oncoming buddy */ bleck, /* offgoing buddy */ bleck, /* messaging error */ bleck, /* server missed call */ bleck, /* login phase 4 packet C command 1*/ bleck, /* login phase 4 packet C command 2 */ bleck, /* login phase 2, first resp */ bleck, /* login phase 2, second resp -- **REQUIRED** */ bleck, /* login phase 3 packet B */ bleck, /* login phase 3D packet A */ bleck, /* login phase 3D packet B */ bleck, /* login phase 3D packet C */ bleck, /* login phase 3D packet D */ bleck, /* login phase 3D packet E */ bleck, /* redirect -- **REQUIRED** */ bleck, /* server rate change */ bleck, /* user location error */ aim_parse_unknown, /* completely unknown command */ bleck, /* User Info Response */ bleck, /* User Search by Address response */ bleck, /* User Search by Name response */ bleck, /* user search fail */ bleck, /* auth error */ bleck, /* auth success */ bleck, /* auth server ready */ bleck, /* auth other */ bleck, /* info change reply */ bleck, /* ChatNAV: server ready */ 0x00 }; int aim_register_callbacks(rxcallback_t *newcallbacks) { int i = 0; for (i = 0; aim_callbacks[i] != 0x00; i++) { if ( (newcallbacks[i] != NULL) && (newcallbacks[i] != 0x00) ) { #if debug > 3 printf("aim_register_callbacks: changed handler %d\n", i); #endif aim_callbacks[i] = newcallbacks[i]; } } return 0; } /* aim_rxdispatch() Basically, heres what this should do: 1) Determine correct packet handler for this packet 2) Mark the packet handled (so it can be dequeued in purge_queue()) 3) Send the packet to the packet handler 4) Go to next packet in the queue and start over 5) When done, run purge_queue() to purge handled commands Note that any unhandlable packets should probably be left in the queue. This is the best way to prevent data loss. This means that a single packet may get looked at by this function multiple times. This is more good than bad! This behavior may change. Aren't queue's fun? TODO: Get rid of all the ugly if's. TODO: Clean up. TODO: More support for mid-level handlers. TODO: Allow for NULL handlers. */ int aim_rxdispatch(void) { int i = 0; struct command_rx_struct *workingPtr = NULL; if (aim_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 = aim_queue_incoming; for (i = 0; workingPtr != NULL; i++) { switch(workingPtr->conn->type) { case AIM_CONN_TYPE_AUTH: if ( (workingPtr->data[0] == 0x00) && (workingPtr->data[1] == 0x00) && (workingPtr->data[2] == 0x00) && (workingPtr->data[3] == 0x01) ) { #if debug > 0 fprintf(stderr, "got connection ack on auth line\n"); #endif workingPtr->handled = 1; } else { /* any user callbacks will be called from here */ workingPtr->handled = aim_authparse(workingPtr); } break; case AIM_CONN_TYPE_BOS: { u_short family; u_short subtype; family = (workingPtr->data[0] << 8) + workingPtr->data[1]; subtype = (workingPtr->data[2] << 8) + workingPtr->data[3]; switch (family) { case 0x0000: /* not really a family, but it works */ if (subtype == 0x0001) workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P2_1])(workingPtr); else workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); break; case 0x0001: /* Family: General */ switch (subtype) { case 0x0001: workingPtr->handled = aim_parse_generalerrs(workingPtr); break; case 0x0003: workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P2_2])(workingPtr); break; case 0x0005: workingPtr->handled = aim_handleredirect_middle(workingPtr); break; case 0x0007: workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3_B])(workingPtr); break; case 0x000a: workingPtr->handled = (aim_callbacks[AIM_CB_RATECHANGE])(workingPtr); break; case 0x000f: workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_A])(workingPtr); break; case 0x0013: workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P4_C2])(workingPtr); break; default: workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); } break; case 0x0002: /* Family: Location */ switch (subtype) { case 0x0001: workingPtr->handled = (aim_callbacks[AIM_CB_MISSED_IM])(workingPtr); break; case 0x0003: workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_D])(workingPtr); break; case 0x0006: workingPtr->handled = aim_parse_userinfo_middle(workingPtr); break; default: workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); } break; case 0x0003: /* Family: Buddy List */ switch (subtype) { case 0x0001: workingPtr->handled = aim_parse_generalerrs(workingPtr); break; case 0x0003: workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_C])(workingPtr); break; case 0x000b: workingPtr->handled = (aim_callbacks[AIM_CB_ONCOMING_BUDDY])(workingPtr); break; case 0x000c: workingPtr->handled = (aim_callbacks[AIM_CB_OFFGOING_BUDDY])(workingPtr); break; default: workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); } break; case 0x0004: /* Family: Messeging */ switch (subtype) { case 0x0001: workingPtr->handled = (aim_callbacks[AIM_CB_USERERROR])(workingPtr); break; case 0x0005: workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_E])(workingPtr); break; case 0x0007: workingPtr->handled = aim_parse_incoming_im_middle(workingPtr); break; case 0x000a: workingPtr->handled = (aim_callbacks[AIM_CB_MISSED_CALL])(workingPtr); break; default: workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); } break; case 0x0009: if (subtype == 0x0001) workingPtr->handled = aim_parse_generalerrs(workingPtr); else if (subtype == 0x0003) workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_B])(workingPtr); else workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); break; case 0x000a: /* Family: User lookup */ switch (subtype) { case 0x0001: workingPtr->handled = (aim_callbacks[AIM_CB_SEARCH_FAIL])(workingPtr); break; case 0x0003: workingPtr->handled = (aim_callbacks[AIM_CB_SEARCH_ADDRESS])(workingPtr); break; default: workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); } break; case 0x000b: if (subtype == 0x0001) workingPtr->handled = aim_parse_generalerrs(workingPtr); else if (subtype == 0x0002) workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P4_C1])(workingPtr); else workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); break; default: workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); break; } } break; case AIM_CONN_TYPE_CHATNAV: if ( (workingPtr->data[0] == 0x00) && (workingPtr->data[1] == 0x02) && (workingPtr->data[2] == 0x00) && (workingPtr->data[3] == 0x06) ) { workingPtr->handled = 1; aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY); } else workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); break; case AIM_CONN_TYPE_CHAT: fprintf(stderr, "\nAHH! Dont know what to do with CHAT stuff yet!\n"); workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); break; default: fprintf(stderr, "\nAHHHHH! UNKNOWN CONNECTION TYPE!\n\n"); workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr); break; } /* move to next command */ workingPtr = workingPtr->next; } } aim_queue_incoming = aim_purge_rxqueue(aim_queue_incoming); return 0; } /* * TODO: check and cure memory leakage in this function. */ int aim_authparse(struct command_rx_struct *command) { int iserror = 0; struct aim_tlv_t *tlv = NULL; char *errorurl = NULL; short errorcode; int z = 0; if ( (command->data[0] == 0x00) && (command->data[1] == 0x01) && (command->data[2] == 0x00) && (command->data[3] == 0x03) ) { /* "server ready" -- can be ignored */ return (aim_callbacks[AIM_CB_AUTH_SVRREADY])(command); } else if ( (command->data[0] == 0x00) && (command->data[1] == 0x07) && (command->data[2] == 0x00) && (command->data[3] == 0x05) ) { /* "information change reply" */ return (aim_callbacks[AIM_CB_AUTH_INFOCHNG_REPLY])(command); } else { /* anything else -- usually used for login; just parse as pure TLVs */ /* 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 */ aim_logininfo.screen_name = tlv->value; 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 */ aim_logininfo.BOSIP = tlv->value; z += 2 + 2 + tlv->length; free(tlv); tlv = NULL; break; case 0x0006: /* auth cookie */ aim_logininfo.cookie = tlv->value; z += 2 + 2 + tlv->length; free(tlv); tlv=NULL; break; case 0x0011: /* email addy */ aim_logininfo.email = tlv->value; z += 2 + 2 + tlv->length; free(tlv); tlv = NULL; break; case 0x0013: /* registration status */ aim_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 (iserror && errorurl && errorcode) return (aim_callbacks[AIM_CB_AUTH_ERROR])(command, &aim_logininfo, errorurl, errorcode); else if (aim_logininfo.screen_name && aim_logininfo.cookie && aim_logininfo.BOSIP) return (aim_callbacks[AIM_CB_AUTH_SUCCESS])(command, &aim_logininfo); else return (aim_callbacks[AIM_CB_AUTH_OTHER])(command); } } /* * TODO: check for and cure any memory leaks here. */ int aim_handleredirect_middle(struct command_rx_struct *command, ...) { struct aim_tlv_t *tlv = NULL; int z = 10; int serviceid; char *cookie; char *ip; while (z < command->commandlen) { 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 = (tlv->value[0] << 8) + tlv->value[1]; /* hehe */ 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); } } return (aim_callbacks[AIM_CB_LOGIN_P3D_F])(command, serviceid, ip, cookie); } int aim_parse_unknown(struct command_rx_struct *command, ...) { int i = 0; printf("\nRecieved unknown packet:"); for (i = 0; i < command->commandlen; i++) { if ((i % 8) == 0) printf("\n\t"); printf("0x%2x ", command->data[i]); } printf("\n\n"); return 1; } /* * aim_parse_generalerrs() * * Middle handler for 0x0001 snac of each family. * */ int aim_parse_generalerrs(struct command_rx_struct *command, ...) { u_short family; u_short subtype; family = (command->data[0] << 8) + command->data[1]; subtype = (command->data[2] << 8) + command->data[3]; switch(family) { default: /* Unknown family */ return (aim_callbacks[AIM_CB_UNKNOWN])(command); } return 1; }