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 aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
24 /* XXX: this is ugly. and big just for debugging. */
25 char *literals[14][25] = {
36 "Rate Information Request",
38 "Rate Information Ack",
40 "Rate Information Change",
44 "Request Personal User Information",
45 "Personal User Information",
59 "Set user information",
60 "Request User Information",
62 "Watcher Sub Request",
63 "Watcher Notification"
65 {"Buddy List Management",
73 "Watcher List Response",
75 "Watcher Notification",
76 "Reject Notification",
84 "Remove ICBM Parameter",
85 "Request Parameter Information",
86 "Parameter Information",
101 {"Invitation / Client-to-Client",
110 "Information Request",
112 "Information Change Request",
113 "Information Chat Reply",
114 "Account Confirm Request",
115 "Account Confirm Reply",
116 "Account Delete Request",
117 "Account Delete Reply"
129 "Set group permission mask",
130 "Add permission list entries",
131 "Delete permission list entries",
132 "Add deny list entries",
133 "Delete deny list entries",
145 "Set minimum report interval",
158 "Request Exchange Information",
159 "Request Room Information",
160 "Request Occupant List",
170 maxf = sizeof(literals) / sizeof(literals[0]);
171 maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
173 family = aimutil_get16(workingPtr->data+0);
174 subtype= aimutil_get16(workingPtr->data+2);
176 if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
177 printf("bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
179 printf("bleck: null handler for %04x/%04x (no literal)\n",family,subtype);
184 int aim_conn_addhandler(struct aim_session_t *sess,
185 struct aim_conn_t *conn,
188 rxcallback_t newhandler,
191 struct aim_rxcblist_t *new,*cur;
196 faimdprintf(1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
198 new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
199 new->family = family;
203 new->handler = &bleck;
205 new->handler = newhandler;
208 cur = conn->handlerlist;
210 conn->handlerlist = new;
221 int aim_clearhandlers(struct aim_conn_t *conn)
223 struct aim_rxcblist_t *cur,*tmp;
227 cur = conn->handlerlist;
237 rxcallback_t aim_callhandler(struct aim_conn_t *conn,
241 struct aim_rxcblist_t *cur;
246 faimdprintf(1, "aim_callhandler: calling for %04x/%04x\n", family, type);
248 cur = conn->handlerlist;
251 if ( (cur->family == family) && (cur->type == type) )
258 return aim_callhandler(conn, family, 0xffff);
261 int aim_callhandler_noparam(struct aim_session_t *sess,
262 struct aim_conn_t *conn,
265 struct command_rx_struct *ptr)
267 rxcallback_t userfunc = NULL;
268 userfunc = aim_callhandler(conn, family, type);
270 return userfunc(sess, ptr);
277 Basically, heres what this should do:
278 1) Determine correct packet handler for this packet
279 2) Mark the packet handled (so it can be dequeued in purge_queue())
280 3) Send the packet to the packet handler
281 4) Go to next packet in the queue and start over
282 5) When done, run purge_queue() to purge handled commands
284 Note that any unhandlable packets should probably be left in the
285 queue. This is the best way to prevent data loss. This means
286 that a single packet may get looked at by this function multiple
287 times. This is more good than bad! This behavior may change.
291 TODO: Get rid of all the ugly if's.
293 TODO: More support for mid-level handlers.
294 TODO: Allow for NULL handlers.
297 int aim_rxdispatch(struct aim_session_t *sess)
300 struct command_rx_struct *workingPtr = NULL;
302 if (sess->queue_incoming == NULL) {
303 faimdprintf(1, "parse_generic: incoming packet queue empty.\n");
306 workingPtr = sess->queue_incoming;
307 for (i = 0; workingPtr != NULL; i++) {
309 * XXX: This is still fairly ugly.
311 switch(workingPtr->conn->type) {
314 * This can happen if we have a queued command
315 * that was recieved after a connection has
316 * been terminated. In which case, the handler
317 * list has been cleared, and there's nothing we
318 * can do for it. We can only cancel it.
320 workingPtr->handled = 1;
322 case AIM_CONN_TYPE_AUTH: {
325 head = aimutil_get32(workingPtr->data);
326 if (head == 0x00000001) {
327 faimdprintf(1, "got connection ack on auth line\n");
328 workingPtr->handled = 1;
330 u_short family,subtype;
332 family = aimutil_get16(workingPtr->data);
333 subtype = aimutil_get16(workingPtr->data+2);
336 /* New login protocol */
339 if (subtype == 0x0001)
340 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
341 else if (subtype == 0x0003)
342 workingPtr->handled = aim_authparse(sess, workingPtr);
343 else if (subtype == 0x0007)
344 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr);
346 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
349 /* XXX: this isnt foolproof */
351 if (subtype == 0x0003)
352 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr);
354 workingPtr->handled = aim_authparse(sess, workingPtr);
357 if (subtype == 0x0005)
358 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
361 /* Old login protocol */
362 /* any user callbacks will be called from here */
363 workingPtr->handled = aim_authparse(sess, workingPtr);
369 case AIM_CONN_TYPE_BOS: {
373 family = aimutil_get16(workingPtr->data);
374 subtype = aimutil_get16(workingPtr->data+2);
377 case 0x0000: /* not really a family, but it works */
378 if (subtype == 0x0001)
379 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
381 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
383 case 0x0001: /* Family: General */
386 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
389 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
392 workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
395 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
398 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
401 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
404 workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
407 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
410 case 0x0002: /* Family: Location */
413 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
416 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
419 workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
422 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
425 case 0x0003: /* Family: Buddy List */
428 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
431 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
433 case 0x000b: /* oncoming buddy */
434 workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
436 case 0x000c: /* offgoing buddy */
437 workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
440 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
443 case 0x0004: /* Family: Messeging */
446 workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
449 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
452 workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
455 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr);
458 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
462 if (subtype == 0x0001)
463 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
464 else if (subtype == 0x0003)
465 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr);
467 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
469 case 0x000a: /* Family: User lookup */
472 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
475 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
478 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
482 if (subtype == 0x0001)
483 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
484 else if (subtype == 0x0002)
485 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
487 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
490 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
495 case AIM_CONN_TYPE_CHATNAV: {
498 family = aimutil_get16(workingPtr->data);
499 subtype= aimutil_get16(workingPtr->data+2);
501 if ((family == 0x0002) && (subtype == 0x0006)) {
502 workingPtr->handled = 1;
503 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
504 } else if ((family == 0x000d) && (subtype == 0x0009)) {
505 workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
507 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
511 case AIM_CONN_TYPE_CHAT: {
512 u_short family, subtype;
514 family = aimutil_get16(workingPtr->data);
515 subtype= aimutil_get16(workingPtr->data+2);
517 if ((family == 0x0000) && (subtype == 0x00001))
518 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
519 else if (family == 0x0001) {
520 if (subtype == 0x0001)
521 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
522 else if (subtype == 0x0003)
523 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
524 else if (subtype == 0x0007)
525 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
527 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
528 } else if (family == 0x000e) {
529 if (subtype == 0x0002)
530 workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
531 else if (subtype == 0x0003)
532 workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);
533 else if (subtype == 0x0004)
534 workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);
535 else if (subtype == 0x0006)
536 workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
538 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
540 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
541 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
546 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);
547 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
550 /* move to next command */
551 workingPtr = workingPtr->next;
556 * This doesn't have to be called here. It could easily be done
557 * by a seperate thread or something. It's an administrative operation,
558 * and can take a while. Though the less you call it the less memory
561 aim_purge_rxqueue(sess);
566 int aim_parsemotd_middle(struct aim_session_t *sess,
567 struct command_rx_struct *command, ...)
569 rxcallback_t userfunc = NULL;
572 struct aim_tlvlist_t *tlvlist;
578 id = aimutil_get16(command->data+10);
583 tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
585 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
587 userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
589 ret = userfunc(sess, command, id, msg);
591 aim_freetlvchain(&tlvlist);
597 int aim_handleredirect_middle(struct aim_session_t *sess,
598 struct command_rx_struct *command, ...)
600 struct aim_tlv_t *tmptlv = NULL;
601 int serviceid = 0x00;
602 char cookie[AIM_COOKIELEN];
604 rxcallback_t userfunc = NULL;
605 struct aim_tlvlist_t *tlvlist;
608 if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10)))
610 printf("libfaim: major bug: unable to read tlvchain from redirect\n");
614 if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1)))
616 printf("libfaim: major bug: no service ID in tlvchain from redirect\n");
617 aim_freetlvchain(&tlvlist);
620 serviceid = aimutil_get16(tmptlv->value);
622 if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1)))
624 printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
625 aim_freetlvchain(&tlvlist);
629 if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
631 printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
632 aim_freetlvchain(&tlvlist);
635 memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
637 if (serviceid == AIM_CONN_TYPE_CHAT)
643 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
645 ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
646 free(sess->pendingjoin);
647 sess->pendingjoin = NULL;
651 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
653 ret = userfunc(sess, command, serviceid, ip, cookie);
657 * XXX: Is there a leak here? Where does IP get freed?
659 aim_freetlvchain(&tlvlist);
664 int aim_parse_unknown(struct aim_session_t *sess,
665 struct command_rx_struct *command, ...)
669 faimdprintf(1, "\nRecieved unknown packet:");
671 for (i = 0; i < command->commandlen; i++)
676 printf("0x%2x ", command->data[i]);
686 * aim_parse_generalerrs()
688 * Middle handler for 0x0001 snac of each family.
691 int aim_parse_generalerrs(struct aim_session_t *sess,
692 struct command_rx_struct *command, ...)
697 family = aimutil_get16(command->data+0);
698 subtype= aimutil_get16(command->data+2);
704 return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);