4 * This file contains most all of the incoming packet handlers, along
5 * with aim_rxdispatch(), the Rx dispatcher. Queue/list management is
6 * actually done in aim_rxqueue.c.
13 * Bleck functions get called when there's no non-bleck functions
14 * around to cleanup the mess...
16 int bleck(struct command_rx_struct *workingPtr, ...)
20 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
21 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
22 printf("bleck: null handler for %04x/%04x\n", family, subtype);
26 int aim_conn_addhandler(struct aim_conn_t *conn,
29 rxcallback_t newhandler,
32 struct aim_rxcblist_t *new,*cur;
38 printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type);
41 new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
46 new->handler = &bleck;
48 new->handler = newhandler;
51 cur = conn->handlerlist;
53 conn->handlerlist = new;
64 int aim_clearhandlers(struct aim_conn_t *conn)
66 struct aim_rxcblist_t *cur,*tmp;
70 cur = conn->handlerlist;
80 rxcallback_t aim_callhandler(struct aim_conn_t *conn,
84 struct aim_rxcblist_t *cur;
90 printf("aim_callhandler: calling for %04x/%04x\n", family, type);
93 cur = conn->handlerlist;
96 if ( (cur->family == family) && (cur->type == type) )
103 return aim_callhandler(conn, family, 0xffff);
106 int aim_callhandler_noparam(struct aim_conn_t *conn,
109 struct command_rx_struct *ptr)
111 rxcallback_t userfunc = NULL;
112 userfunc = aim_callhandler(conn, family, type);
114 return userfunc(ptr);
121 Basically, heres what this should do:
122 1) Determine correct packet handler for this packet
123 2) Mark the packet handled (so it can be dequeued in purge_queue())
124 3) Send the packet to the packet handler
125 4) Go to next packet in the queue and start over
126 5) When done, run purge_queue() to purge handled commands
128 Note that any unhandlable packets should probably be left in the
129 queue. This is the best way to prevent data loss. This means
130 that a single packet may get looked at by this function multiple
131 times. This is more good than bad! This behavior may change.
135 TODO: Get rid of all the ugly if's.
137 TODO: More support for mid-level handlers.
138 TODO: Allow for NULL handlers.
141 int aim_rxdispatch(void)
144 struct command_rx_struct *workingPtr = NULL;
146 if (aim_queue_incoming == NULL)
147 /* this shouldn't really happen, unless the main loop's select is broke */
148 printf("parse_generic: incoming packet queue empty.\n");
151 workingPtr = aim_queue_incoming;
152 for (i = 0; workingPtr != NULL; i++)
154 switch(workingPtr->conn->type)
156 case AIM_CONN_TYPE_AUTH:
157 if ( (workingPtr->data[0] == 0x00) &&
158 (workingPtr->data[1] == 0x00) &&
159 (workingPtr->data[2] == 0x00) &&
160 (workingPtr->data[3] == 0x01) )
163 printf("got connection ack on auth line\n");
165 workingPtr->handled = 1;
169 /* any user callbacks will be called from here */
170 workingPtr->handled = aim_authparse(workingPtr);
173 case AIM_CONN_TYPE_BOS:
177 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
178 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
181 case 0x0000: /* not really a family, but it works */
182 if (subtype == 0x0001)
183 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0000, 0x0001, workingPtr);
185 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
187 case 0x0001: /* Family: General */
191 workingPtr->handled = aim_parse_generalerrs(workingPtr);
194 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0003, workingPtr);
197 workingPtr->handled = aim_handleredirect_middle(workingPtr);
200 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0007, workingPtr);
203 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x000a, workingPtr);
206 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x000f, workingPtr);
209 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0013, workingPtr);
212 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
215 case 0x0002: /* Family: Location */
219 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0002, 0x0001, workingPtr);
222 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0002, 0x0003, workingPtr);
225 workingPtr->handled = aim_parse_userinfo_middle(workingPtr);
228 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
231 case 0x0003: /* Family: Buddy List */
235 workingPtr->handled = aim_parse_generalerrs(workingPtr);
238 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0003, 0x0003, workingPtr);
240 case 0x000b: /* oncoming buddy */
241 workingPtr->handled = aim_parse_oncoming_middle(workingPtr);
243 case 0x000c: /* offgoing buddy */
244 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0003, 0x000c, workingPtr);
247 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
250 case 0x0004: /* Family: Messeging */
254 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x0001, workingPtr);
257 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x0005, workingPtr);
260 workingPtr->handled = aim_parse_incoming_im_middle(workingPtr);
263 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x000a, workingPtr);
266 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
270 if (subtype == 0x0001)
271 workingPtr->handled = aim_parse_generalerrs(workingPtr);
272 else if (subtype == 0x0003)
273 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0009, 0x0003, workingPtr);
275 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
277 case 0x000a: /* Family: User lookup */
281 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000a, 0x0001, workingPtr);
284 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000a, 0x0003, workingPtr);
287 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
291 if (subtype == 0x0001)
292 workingPtr->handled = aim_parse_generalerrs(workingPtr);
293 else if (subtype == 0x0002)
294 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000b, 0x0002, workingPtr);
296 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
299 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
304 case AIM_CONN_TYPE_CHATNAV:
308 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
309 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
310 if ( (workingPtr->data[0] == 0x00) &&
311 (workingPtr->data[1] == 0x02) &&
312 (workingPtr->data[2] == 0x00) &&
313 (workingPtr->data[3] == 0x06) )
315 workingPtr->handled = 1;
316 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
320 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, family, subtype, workingPtr);
324 case AIM_CONN_TYPE_CHAT:
325 printf("\nAHH! Dont know what to do with CHAT stuff yet!\n");
326 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
329 printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type);
330 workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
333 /* move to next command */
334 workingPtr = workingPtr->next;
338 aim_queue_incoming = aim_purge_rxqueue(aim_queue_incoming);
344 * TODO: check and cure memory leakage in this function.
346 int aim_authparse(struct command_rx_struct *command)
348 rxcallback_t userfunc = NULL;
350 struct aim_tlv_t *tlv = NULL;
351 char *errorurl = NULL;
352 short errorcode = 0x00;
355 if ( (command->data[0] == 0x00) &&
356 (command->data[1] == 0x01) &&
357 (command->data[2] == 0x00) &&
358 (command->data[3] == 0x03) )
360 /* "server ready" -- can be ignored */
361 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY);
363 else if ( (command->data[0] == 0x00) &&
364 (command->data[1] == 0x07) &&
365 (command->data[2] == 0x00) &&
366 (command->data[3] == 0x05) )
368 /* "information change reply" */
369 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY);
373 /* anything else -- usually used for login; just parse as pure TLVs */
376 * Free up the loginstruct first.
378 if (aim_logininfo.screen_name)
380 free(aim_logininfo.screen_name);
381 aim_logininfo.screen_name = NULL;
383 if (aim_logininfo.BOSIP)
385 free(aim_logininfo.BOSIP);
386 aim_logininfo.BOSIP = NULL;
388 if (aim_logininfo.cookie)
390 free(aim_logininfo.cookie);
391 aim_logininfo.cookie = NULL;
393 if (aim_logininfo.email)
395 free(aim_logininfo.email);
396 aim_logininfo.email = NULL;
398 aim_logininfo.regstatus = 0;
400 /* all this block does is figure out if it's an
401 error or a success, nothing more */
402 while (z < command->commandlen)
404 tlv = aim_grabtlvstr(&(command->data[z]));
407 case 0x0001: /* screen name */
408 aim_logininfo.screen_name = tlv->value;
409 z += 2 + 2 + tlv->length;
413 case 0x0004: /* error URL */
414 errorurl = tlv->value;
415 z += 2 + 2 + tlv->length;
419 case 0x0005: /* BOS IP */
420 aim_logininfo.BOSIP = tlv->value;
421 z += 2 + 2 + tlv->length;
425 case 0x0006: /* auth cookie */
426 aim_logininfo.cookie = tlv->value;
427 z += 2 + 2 + tlv->length;
431 case 0x0011: /* email addy */
432 aim_logininfo.email = tlv->value;
433 z += 2 + 2 + tlv->length;
437 case 0x0013: /* registration status */
438 aim_logininfo.regstatus = *(tlv->value);
439 z += 2 + 2 + tlv->length;
442 case 0x0008: /* error code */
443 errorcode = *(tlv->value);
444 z += 2 + 2 + tlv->length;
449 z += 2 + 2 + tlv->length;
458 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR);
460 return userfunc(command, &aim_logininfo, errorurl, errorcode);
463 else if (aim_logininfo.screen_name &&
464 aim_logininfo.cookie && aim_logininfo.BOSIP)
466 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS);
468 return userfunc(command, &aim_logininfo);
472 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHOTHER);
476 return userfunc(command);
477 printf("handler not available!\n");
482 * TODO: check for and cure any memory leaks here.
484 int aim_handleredirect_middle(struct command_rx_struct *command, ...)
486 struct aim_tlv_t *tlv = NULL;
488 int serviceid = 0x00;
491 rxcallback_t userfunc = NULL;
493 while (z < command->commandlen)
495 tlv = aim_grabtlvstr(&(command->data[z]));
498 case 0x000d: /* service id */
500 /* regrab as an int */
501 tlv = aim_grabtlv(&(command->data[z]));
502 serviceid = (tlv->value[0] << 8) + tlv->value[1]; /* hehe */
503 z += 2 + 2 + tlv->length;
506 case 0x0005: /* service server IP */
508 z += 2 + 2 + tlv->length;
512 case 0x0006: /* auth cookie */
514 z += 2 + 2 + tlv->length;
520 z += 2 + 2 + tlv->length;
524 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
526 return userfunc(command, serviceid, ip, cookie);
530 int aim_parse_unknown(struct command_rx_struct *command, ...)
534 printf("\nRecieved unknown packet:");
536 for (i = 0; i < command->commandlen; i++)
541 printf("0x%2x ", command->data[i]);
551 * aim_parse_generalerrs()
553 * Middle handler for 0x0001 snac of each family.
556 int aim_parse_generalerrs(struct command_rx_struct *command, ...)
560 family = (command->data[0] << 8) + command->data[1];
561 subtype = (command->data[2] << 8) + command->data[3];
567 return aim_callhandler_noparam(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);