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; workingPtr = workingPtr->next, i++) {
309 * XXX: This is still fairly ugly.
311 if (workingPtr->handled)
314 switch(workingPtr->conn->type) {
317 * This can happen if we have a queued command
318 * that was recieved after a connection has
319 * been terminated. In which case, the handler
320 * list has been cleared, and there's nothing we
321 * can do for it. We can only cancel it.
323 workingPtr->handled = 1;
325 case AIM_CONN_TYPE_AUTH: {
328 head = aimutil_get32(workingPtr->data);
329 if (head == 0x00000001) {
330 faimdprintf(1, "got connection ack on auth line\n");
331 workingPtr->handled = 1;
333 u_short family,subtype;
335 family = aimutil_get16(workingPtr->data);
336 subtype = aimutil_get16(workingPtr->data+2);
339 /* New login protocol */
342 if (subtype == 0x0001)
343 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
344 else if (subtype == 0x0003)
345 workingPtr->handled = aim_authparse(sess, workingPtr);
346 else if (subtype == 0x0007)
347 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr);
349 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
352 /* XXX: this isnt foolproof */
354 if (subtype == 0x0003)
355 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr);
357 workingPtr->handled = aim_authparse(sess, workingPtr);
360 if (subtype == 0x0005)
361 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
364 /* Old login protocol */
365 /* any user callbacks will be called from here */
366 workingPtr->handled = aim_authparse(sess, workingPtr);
372 case AIM_CONN_TYPE_BOS: {
376 if (workingPtr->type == 0x04) {
377 workingPtr->handled = aim_negchan_middle(sess, workingPtr);
381 family = aimutil_get16(workingPtr->data);
382 subtype = aimutil_get16(workingPtr->data+2);
385 case 0x0000: /* not really a family, but it works */
386 if (subtype == 0x0001)
387 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
389 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
391 case 0x0001: /* Family: General */
394 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
397 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
400 workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
403 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
406 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
409 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
412 workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
415 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
418 case 0x0002: /* Family: Location */
421 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
424 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
427 workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
430 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
433 case 0x0003: /* Family: Buddy List */
436 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
439 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
441 case 0x000b: /* oncoming buddy */
442 workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
444 case 0x000c: /* offgoing buddy */
445 workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
448 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
451 case 0x0004: /* Family: Messeging */
454 workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
457 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
460 workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
463 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr);
466 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
470 if (subtype == 0x0001)
471 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
472 else if (subtype == 0x0003)
473 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr);
475 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
477 case 0x000a: /* Family: User lookup */
480 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
483 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
486 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
490 if (subtype == 0x0001)
491 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
492 else if (subtype == 0x0002)
493 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
495 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
498 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
503 case AIM_CONN_TYPE_CHATNAV: {
506 family = aimutil_get16(workingPtr->data);
507 subtype= aimutil_get16(workingPtr->data+2);
509 if ((family == 0x0002) && (subtype == 0x0006)) {
510 workingPtr->handled = 1;
511 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
512 } else if ((family == 0x000d) && (subtype == 0x0009)) {
513 workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
515 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
519 case AIM_CONN_TYPE_CHAT: {
520 u_short family, subtype;
522 family = aimutil_get16(workingPtr->data);
523 subtype= aimutil_get16(workingPtr->data+2);
525 if ((family == 0x0000) && (subtype == 0x00001))
526 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
527 else if (family == 0x0001) {
528 if (subtype == 0x0001)
529 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
530 else if (subtype == 0x0003)
531 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
532 else if (subtype == 0x0007)
533 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
535 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
536 } else if (family == 0x000e) {
537 if (subtype == 0x0002)
538 workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
539 else if (subtype == 0x0003)
540 workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);
541 else if (subtype == 0x0004)
542 workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);
543 else if (subtype == 0x0006)
544 workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
546 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
548 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
549 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
554 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);
555 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
562 * This doesn't have to be called here. It could easily be done
563 * by a seperate thread or something. It's an administrative operation,
564 * and can take a while. Though the less you call it the less memory
567 aim_purge_rxqueue(sess);
572 int aim_parsemotd_middle(struct aim_session_t *sess,
573 struct command_rx_struct *command, ...)
575 rxcallback_t userfunc = NULL;
578 struct aim_tlvlist_t *tlvlist;
584 id = aimutil_get16(command->data+10);
589 tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
591 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
593 userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
595 ret = userfunc(sess, command, id, msg);
597 aim_freetlvchain(&tlvlist);
603 int aim_handleredirect_middle(struct aim_session_t *sess,
604 struct command_rx_struct *command, ...)
606 struct aim_tlv_t *tmptlv = NULL;
607 int serviceid = 0x00;
608 char cookie[AIM_COOKIELEN];
610 rxcallback_t userfunc = NULL;
611 struct aim_tlvlist_t *tlvlist;
614 if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10)))
616 printf("libfaim: major bug: unable to read tlvchain from redirect\n");
620 if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1)))
622 printf("libfaim: major bug: no service ID in tlvchain from redirect\n");
623 aim_freetlvchain(&tlvlist);
626 serviceid = aimutil_get16(tmptlv->value);
628 if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1)))
630 printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
631 aim_freetlvchain(&tlvlist);
635 if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
637 printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
638 aim_freetlvchain(&tlvlist);
641 memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
643 if (serviceid == AIM_CONN_TYPE_CHAT)
649 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
651 ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
652 free(sess->pendingjoin);
653 sess->pendingjoin = NULL;
657 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
659 ret = userfunc(sess, command, serviceid, ip, cookie);
663 * XXX: Is there a leak here? Where does IP get freed?
665 aim_freetlvchain(&tlvlist);
670 int aim_parse_unknown(struct aim_session_t *sess,
671 struct command_rx_struct *command, ...)
675 faimdprintf(1, "\nRecieved unknown packet:");
677 for (i = 0; i < command->commandlen; i++)
682 printf("0x%2x ", command->data[i]);
691 int aim_negchan_middle(struct aim_session_t *sess,
692 struct command_rx_struct *command)
694 struct aim_tlvlist_t *tlvlist;
696 unsigned short code = 0;
697 struct aim_tlv_t *tmptlv;
698 rxcallback_t userfunc = NULL;
701 tlvlist = aim_readtlvchain(command->data, command->commandlen);
703 if ((tmptlv = aim_gettlv(tlvlist, 0x0009, 1)))
704 code = aimutil_get16(tmptlv->value);
706 if ((tmptlv = aim_gettlv(tlvlist, 0x000b, 1)))
707 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
709 userfunc = aim_callhandler(command->conn,
710 AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR);
712 ret = userfunc(sess, command, code, msg);
714 aim_freetlvchain(&tlvlist);
721 * aim_parse_generalerrs()
723 * Middle handler for 0x0001 snac of each family.
726 int aim_parse_generalerrs(struct aim_session_t *sess,
727 struct command_rx_struct *command, ...)
732 family = aimutil_get16(command->data+0);
733 subtype= aimutil_get16(command->data+2);
739 return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);