5 This file contains most all of the incoming packet handlers, along
6 with aim_rxdispatch(), the Rx dispatcher. Queue/list management is
7 actually done in aim_rxqueue.c.
12 #include "aim.h" /* for most everything */
15 int bleck(struct command_rx_struct *workingPtr, ...)
19 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
20 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
22 fprintf(stderr, "bleck: null handler for %04x/%04x\n", family, subtype);
27 int bleck2(struct command_rx_struct *workingPtr, ...)
31 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
32 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
33 printf("OLDbleck: called for %04x/%04x -- OBSOLETE\n", family, subtype);
37 int aim_conn_addhandler(struct aim_conn_t *conn,
40 rxcallback_t newhandler,
43 struct aim_rxcblist_t *new,*cur;
49 printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type);
52 new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
57 new->handler = &bleck;
59 new->handler = newhandler;
62 cur = conn->handlerlist;
64 conn->handlerlist = new;
75 int aim_clearhandlers(struct aim_conn_t *conn)
77 struct aim_rxcblist_t *cur,*tmp;
81 cur = conn->handlerlist;
91 rxcallback_t aim_callhandler(struct aim_conn_t *conn,
95 struct aim_rxcblist_t *cur;
101 printf("aim_callhandler: calling for %04x/%04x\n", family, type);
104 cur = conn->handlerlist;
107 if ( (cur->family == family) && (cur->type == type) )
114 return aim_callhandler(conn, family, 0xffff);
117 int aim_callhandler_noparam(struct aim_conn_t *conn,
120 struct command_rx_struct *ptr)
122 rxcallback_t userfunc = NULL;
123 userfunc = aim_callhandler(conn, family, type);
125 return userfunc(ptr);
132 Basically, heres what this should do:
133 1) Determine correct packet handler for this packet
134 2) Mark the packet handled (so it can be dequeued in purge_queue())
135 3) Send the packet to the packet handler
136 4) Go to next packet in the queue and start over
137 5) When done, run purge_queue() to purge handled commands
139 Note that any unhandlable packets should probably be left in the
140 queue. This is the best way to prevent data loss. This means
141 that a single packet may get looked at by this function multiple
142 times. This is more good than bad! This behavior may change.
146 TODO: Get rid of all the ugly if's.
148 TODO: More support for mid-level handlers.
149 TODO: Allow for NULL handlers.
152 int aim_rxdispatch(void)
155 struct command_rx_struct *workingPtr = NULL;
157 if (aim_queue_incoming == NULL)
158 /* this shouldn't really happen, unless the main loop's select is broke */
159 printf("parse_generic: incoming packet queue empty.\n");
162 workingPtr = aim_queue_incoming;
163 for (i = 0; workingPtr != NULL; i++)
165 switch(workingPtr->conn->type)
167 case AIM_CONN_TYPE_AUTH:
168 if ( (workingPtr->data[0] == 0x00) &&
169 (workingPtr->data[1] == 0x00) &&
170 (workingPtr->data[2] == 0x00) &&
171 (workingPtr->data[3] == 0x01) )
174 fprintf(stderr, "got connection ack on auth line\n");
176 workingPtr->handled = 1;
180 /* any user callbacks will be called from here */
181 workingPtr->handled = aim_authparse(workingPtr);
184 case AIM_CONN_TYPE_BOS:
188 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
189 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
192 case 0x0000: /* not really a family, but it works */
193 if (subtype == 0x0001)
194 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0000, 0x0001, workingPtr);
196 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
198 case 0x0001: /* Family: General */
202 workingPtr->handled = aim_parse_generalerrs(workingPtr);
205 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0003, workingPtr);
208 workingPtr->handled = aim_handleredirect_middle(workingPtr);
211 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0007, workingPtr);
214 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x000a, workingPtr);
217 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x000f, workingPtr);
220 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0013, workingPtr);
223 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
226 case 0x0002: /* Family: Location */
230 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0002, 0x0001, workingPtr);
233 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0002, 0x0003, workingPtr);
236 workingPtr->handled = aim_parse_userinfo_middle(workingPtr);
239 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
242 case 0x0003: /* Family: Buddy List */
246 workingPtr->handled = aim_parse_generalerrs(workingPtr);
249 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0003, 0x0003, workingPtr);
251 case 0x000b: /* oncoming buddy */
252 workingPtr->handled = aim_parse_oncoming_middle(workingPtr);
254 case 0x000c: /* offgoing buddy */
255 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0003, 0x000c, workingPtr);
258 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
261 case 0x0004: /* Family: Messeging */
265 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x0001, workingPtr);
268 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x0005, workingPtr);
271 workingPtr->handled = aim_parse_incoming_im_middle(workingPtr);
274 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x000a, workingPtr);
277 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
281 if (subtype == 0x0001)
282 workingPtr->handled = aim_parse_generalerrs(workingPtr);
283 else if (subtype == 0x0003)
284 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0009, 0x0003, workingPtr);
286 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
288 case 0x000a: /* Family: User lookup */
292 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000a, 0x0001, workingPtr);
295 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000a, 0x0003, workingPtr);
298 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
302 if (subtype == 0x0001)
303 workingPtr->handled = aim_parse_generalerrs(workingPtr);
304 else if (subtype == 0x0002)
305 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000b, 0x0002, workingPtr);
307 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
310 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
315 case AIM_CONN_TYPE_CHATNAV:
319 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
320 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
321 if ( (workingPtr->data[0] == 0x00) &&
322 (workingPtr->data[1] == 0x02) &&
323 (workingPtr->data[2] == 0x00) &&
324 (workingPtr->data[3] == 0x06) )
326 workingPtr->handled = 1;
327 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
331 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, family, subtype, workingPtr);
335 case AIM_CONN_TYPE_CHAT:
336 fprintf(stderr, "\nAHH! Dont know what to do with CHAT stuff yet!\n");
337 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
340 fprintf(stderr, "\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type);
341 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
344 /* move to next command */
345 workingPtr = workingPtr->next;
349 aim_queue_incoming = aim_purge_rxqueue(aim_queue_incoming);
355 * TODO: check and cure memory leakage in this function.
357 int aim_authparse(struct command_rx_struct *command)
359 rxcallback_t userfunc = NULL;
361 struct aim_tlv_t *tlv = NULL;
362 char *errorurl = NULL;
363 short errorcode = 0x00;
366 if ( (command->data[0] == 0x00) &&
367 (command->data[1] == 0x01) &&
368 (command->data[2] == 0x00) &&
369 (command->data[3] == 0x03) )
371 /* "server ready" -- can be ignored */
372 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY);
374 else if ( (command->data[0] == 0x00) &&
375 (command->data[1] == 0x07) &&
376 (command->data[2] == 0x00) &&
377 (command->data[3] == 0x05) )
379 /* "information change reply" */
380 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY);
384 /* anything else -- usually used for login; just parse as pure TLVs */
387 * Free up the loginstruct first.
389 if (aim_logininfo.screen_name)
391 free(aim_logininfo.screen_name);
392 aim_logininfo.screen_name = NULL;
394 if (aim_logininfo.BOSIP)
396 free(aim_logininfo.BOSIP);
397 aim_logininfo.BOSIP = NULL;
399 if (aim_logininfo.cookie)
401 free(aim_logininfo.cookie);
402 aim_logininfo.cookie = NULL;
404 if (aim_logininfo.email)
406 free(aim_logininfo.email);
407 aim_logininfo.email = NULL;
409 aim_logininfo.regstatus = 0;
411 /* all this block does is figure out if it's an
412 error or a success, nothing more */
413 while (z < command->commandlen)
415 tlv = aim_grabtlvstr(&(command->data[z]));
418 case 0x0001: /* screen name */
419 aim_logininfo.screen_name = tlv->value;
420 z += 2 + 2 + tlv->length;
424 case 0x0004: /* error URL */
425 errorurl = tlv->value;
426 z += 2 + 2 + tlv->length;
430 case 0x0005: /* BOS IP */
431 aim_logininfo.BOSIP = tlv->value;
432 z += 2 + 2 + tlv->length;
436 case 0x0006: /* auth cookie */
437 aim_logininfo.cookie = tlv->value;
438 z += 2 + 2 + tlv->length;
442 case 0x0011: /* email addy */
443 aim_logininfo.email = tlv->value;
444 z += 2 + 2 + tlv->length;
448 case 0x0013: /* registration status */
449 aim_logininfo.regstatus = *(tlv->value);
450 z += 2 + 2 + tlv->length;
453 case 0x0008: /* error code */
454 errorcode = *(tlv->value);
455 z += 2 + 2 + tlv->length;
460 z += 2 + 2 + tlv->length;
469 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR);
471 return userfunc(command, &aim_logininfo, errorurl, errorcode);
474 else if (aim_logininfo.screen_name &&
475 aim_logininfo.cookie && aim_logininfo.BOSIP)
477 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS);
479 return userfunc(command, &aim_logininfo);
483 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHOTHER);
487 return userfunc(command);
488 printf("handler not available!\n");
493 * TODO: check for and cure any memory leaks here.
495 int aim_handleredirect_middle(struct command_rx_struct *command, ...)
497 struct aim_tlv_t *tlv = NULL;
499 int serviceid = 0x00;
502 rxcallback_t userfunc = NULL;
504 while (z < command->commandlen)
506 tlv = aim_grabtlvstr(&(command->data[z]));
509 case 0x000d: /* service id */
511 /* regrab as an int */
512 tlv = aim_grabtlv(&(command->data[z]));
513 serviceid = (tlv->value[0] << 8) + tlv->value[1]; /* hehe */
514 z += 2 + 2 + tlv->length;
517 case 0x0005: /* service server IP */
519 z += 2 + 2 + tlv->length;
523 case 0x0006: /* auth cookie */
525 z += 2 + 2 + tlv->length;
531 z += 2 + 2 + tlv->length;
535 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
537 return userfunc(command, serviceid, ip, cookie);
541 int aim_parse_unknown(struct command_rx_struct *command, ...)
545 printf("\nRecieved unknown packet:");
547 for (i = 0; i < command->commandlen; i++)
552 printf("0x%2x ", command->data[i]);
562 * aim_parse_generalerrs()
564 * Middle handler for 0x0001 snac of each family.
567 int aim_parse_generalerrs(struct command_rx_struct *command, ...)
571 family = (command->data[0] << 8) + command->data[1];
572 subtype = (command->data[2] << 8) + command->data[3];
578 return aim_callhandler_noparam(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);