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 static aim_module_t *findmodule(struct aim_session_t *sess, const char *name)
17 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
18 if (strcmp(name, cur->name) == 0)
25 faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst)(struct aim_session_t *, aim_module_t *))
29 if (!sess || !modfirst)
32 if (!(mod = malloc(sizeof(aim_module_t))))
34 memset(mod, 0, sizeof(aim_module_t));
36 if (modfirst(sess, mod) == -1) {
41 if (findmodule(sess, mod->name)) {
43 mod->shutdown(sess, mod);
48 mod->next = (aim_module_t *)sess->modlistv;
49 (aim_module_t *)sess->modlistv = mod;
51 faimdprintf(sess, 0, "registered module %s (family 0x%04x)\n", mod->name, mod->family);
56 faim_internal void aim__shutdownmodules(struct aim_session_t *sess)
60 for (cur = (aim_module_t *)sess->modlistv; cur; ) {
66 cur->shutdown(sess, cur);
73 sess->modlistv = NULL;
78 static int consumesnac(struct aim_session_t *sess, struct command_rx_struct *rx)
83 snac.family = aimutil_get16(rx->data+0);
84 snac.subtype = aimutil_get16(rx->data+2);
85 snac.flags = aimutil_get16(rx->data+4);
86 snac.id = aimutil_get32(rx->data+6);
88 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
90 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
91 (cur->family != snac.family))
94 if (cur->snachandler(sess, cur, rx, &snac, rx->data+10, rx->commandlen-10))
102 static int consumenonsnac(struct aim_session_t *sess, struct command_rx_struct *rx, unsigned short family, unsigned short subtype)
107 snac.family = family;
108 snac.subtype = subtype;
109 snac.flags = snac.id = 0;
111 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
113 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
114 (cur->family != snac.family))
117 if (cur->snachandler(sess, cur, rx, &snac, rx->data, rx->commandlen))
126 * Bleck functions get called when there's no non-bleck functions
127 * around to cleanup the mess...
129 faim_internal int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
137 /* XXX: this is ugly. and big just for debugging. */
138 char *literals[14][25] = {
149 "Rate Information Request",
151 "Rate Information Ack",
153 "Rate Information Change",
157 "Request Personal User Information",
158 "Personal User Information",
162 "Message of the Day",
171 "Rights Information",
172 "Set user information",
173 "Request User Information",
175 "Watcher Sub Request",
176 "Watcher Notification"
178 {"Buddy List Management",
182 "Rights Information",
185 "Watcher List Query",
186 "Watcher List Response",
187 "Watcher SubRequest",
188 "Watcher Notification",
189 "Reject Notification",
196 "Add ICBM Parameter",
197 "Remove ICBM Parameter",
198 "Request Parameter Information",
199 "Parameter Information",
214 {"Invitation / Client-to-Client",
223 "Information Request",
225 "Information Change Request",
226 "Information Chat Reply",
227 "Account Confirm Request",
228 "Account Confirm Reply",
229 "Account Delete Request",
230 "Account Delete Reply"
242 "Set group permission mask",
243 "Add permission list entries",
244 "Delete permission list entries",
245 "Add deny list entries",
246 "Delete deny list entries",
258 "Set minimum report interval",
271 "Request Exchange Information",
272 "Request Room Information",
273 "Request Occupant List",
283 maxf = sizeof(literals) / sizeof(literals[0]);
284 maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
286 family = aimutil_get16(workingPtr->data+0);
287 subtype= aimutil_get16(workingPtr->data+2);
289 if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
290 faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
292 faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (no literal)\n",family,subtype);
297 faim_export int aim_conn_addhandler(struct aim_session_t *sess,
298 struct aim_conn_t *conn,
301 rxcallback_t newhandler,
304 struct aim_rxcblist_t *newcb;
309 faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
311 if (!(newcb = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t))))
313 newcb->family = family;
315 newcb->flags = flags;
317 newcb->handler = &bleck;
319 newcb->handler = newhandler;
322 if (!conn->handlerlist)
323 conn->handlerlist = newcb;
325 struct aim_rxcblist_t *cur;
327 cur = conn->handlerlist;
337 faim_export int aim_clearhandlers(struct aim_conn_t *conn)
339 struct aim_rxcblist_t *cur;
344 for (cur = conn->handlerlist; cur; ) {
345 struct aim_rxcblist_t *tmp;
351 conn->handlerlist = NULL;
356 faim_internal rxcallback_t aim_callhandler(struct aim_session_t *sess,
357 struct aim_conn_t *conn,
358 unsigned short family,
361 struct aim_rxcblist_t *cur;
366 faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
368 for (cur = conn->handlerlist; cur; cur = cur->next) {
369 if ((cur->family == family) && (cur->type == type))
373 if (type == AIM_CB_SPECIAL_DEFAULT) {
374 faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family);
375 return NULL; /* prevent infinite recursion */
378 faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type);
380 return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
383 faim_internal int aim_callhandler_noparam(struct aim_session_t *sess,
384 struct aim_conn_t *conn,
387 struct command_rx_struct *ptr)
389 rxcallback_t userfunc = NULL;
390 userfunc = aim_callhandler(sess, conn, family, type);
392 return userfunc(sess, ptr);
399 Basically, heres what this should do:
400 1) Determine correct packet handler for this packet
401 2) Mark the packet handled (so it can be dequeued in purge_queue())
402 3) Send the packet to the packet handler
403 4) Go to next packet in the queue and start over
404 5) When done, run purge_queue() to purge handled commands
406 Note that any unhandlable packets should probably be left in the
407 queue. This is the best way to prevent data loss. This means
408 that a single packet may get looked at by this function multiple
409 times. This is more good than bad! This behavior may change.
413 TODO: Get rid of all the ugly if's.
415 TODO: More support for mid-level handlers.
416 TODO: Allow for NULL handlers.
419 faim_export int aim_rxdispatch(struct aim_session_t *sess)
422 struct command_rx_struct *workingPtr = NULL;
423 static int critical = 0;
426 return 0; /* don't call recursively! */
430 if (sess->queue_incoming == NULL) {
431 faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n");
433 workingPtr = sess->queue_incoming;
434 for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
435 unsigned short family,subtype;
438 * XXX: This is still fairly ugly.
440 if (workingPtr->handled)
444 * This is a debugging/sanity check only and probably could/should be removed
447 if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) &&
448 (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) ||
449 ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) &&
450 (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
451 faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
452 workingPtr->handled = 1;
456 if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
457 /* make sure that we only get OFT frames on these connections */
458 if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
459 faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n");
460 workingPtr->handled = 1; /* get rid of it */
462 /* XXX: implement this */
463 faimdprintf(sess, 0, "faim: OFT frame!\n");
464 workingPtr->handled = 1; /* get rid of it */
469 if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
471 faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n");
472 workingPtr->handled = 1;
476 if ((workingPtr->commandlen == 4) &&
477 (aimutil_get32(workingPtr->data) == 0x00000001)) {
478 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
482 if (workingPtr->hdr.oscar.type == 0x04) {
483 workingPtr->handled = aim_negchan_middle(sess, workingPtr);
487 if ((workingPtr->handled = consumesnac(sess, workingPtr)))
490 family = aimutil_get16(workingPtr->data);
491 subtype = aimutil_get16(workingPtr->data+2);
493 if (family == 0x0001) {
495 if (subtype == 0x0001)
496 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
497 else if (subtype == 0x0003)
498 workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
499 else if (subtype == 0x0005)
500 workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
501 else if (subtype == 0x0007)
502 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
503 else if (subtype == 0x000a)
504 workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
505 else if (subtype == 0x000f)
506 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
507 else if (subtype == 0x0010)
508 workingPtr->handled = aim_parse_evilnotify_middle(sess, workingPtr);
509 else if (subtype == 0x0013)
510 workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
511 else if (subtype == 0x0018)
512 workingPtr->handled = aim_parse_hostversions(sess, workingPtr);
514 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0xffff, workingPtr);
516 } else if (family == 0x0002) {
518 if (subtype == 0x0001)
519 workingPtr->handled = aim_parse_locateerr(sess, workingPtr);
520 else if (subtype == 0x0003)
521 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
522 else if (subtype == 0x0006)
523 workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
525 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
527 } else if (family == 0x0003) {
529 if (subtype == 0x0001)
530 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
532 } else if (family == 0x0004) {
534 if (subtype == 0x0001)
535 workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
536 else if (subtype == 0x0005)
537 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
538 else if (subtype == 0x0006)
539 workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr);
540 else if (subtype == 0x0007)
541 workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
542 else if (subtype == 0x000a)
543 workingPtr->handled = aim_parse_missedcall(sess, workingPtr);
544 else if (subtype == 0x000c)
545 workingPtr->handled = aim_parse_msgack_middle(sess, workingPtr);
547 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
549 } else if (family == 0x000d) {
551 if (subtype == 0x0009)
552 workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
554 } else if (family == 0x000e) {
556 if (subtype == 0x0002)
557 workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
558 else if (subtype == 0x0003)
559 workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);
560 else if (subtype == 0x0004)
561 workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);
562 else if (subtype == 0x0006)
563 workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
565 } else if (family == 0x0013) {
567 faimdprintf(sess, 0, "lalala: 0x%04x/0x%04x\n", family, subtype);
569 } else if (family == AIM_CB_FAM_SPECIAL) {
571 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
578 * This doesn't have to be called here. It could easily be done
579 * by a seperate thread or something. It's an administrative operation,
580 * and can take a while. Though the less you call it the less memory
583 aim_purge_rxqueue(sess);
590 faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command)
592 rxcallback_t userfunc = NULL;
595 int i = 10+8; /* skip SNAC and cookie */
599 type = aimutil_get16(command->data+i);
602 snlen = aimutil_get8(command->data+i);
605 memset(sn, 0, sizeof(sn));
606 strncpy(sn, (char *)command->data+i, snlen);
608 if ((userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x000c)))
609 ret = userfunc(sess, command, type, sn);
615 * The Rate Limiting System, An Abridged Guide to Nonsense.
617 * OSCAR defines several 'rate classes'. Each class has seperate
618 * rate limiting properties (limit level, alert level, disconnect
619 * level, etc), and a set of SNAC family/type pairs associated with
620 * it. The rate classes, their limiting properties, and the definitions
621 * of which SNACs are belong to which class, are defined in the
622 * Rate Response packet at login to each host.
624 * Logically, all rate offenses within one class count against further
625 * offenses for other SNACs in the same class (ie, sending messages
626 * too fast will limit the number of user info requests you can send,
627 * since those two SNACs are in the same rate class).
629 * Since the rate classes are defined dynamically at login, the values
630 * below may change. But they seem to be fairly constant.
632 * Currently, BOS defines five rate classes, with the commonly used
633 * members as follows...
636 * - Everything thats not in any of the other classes
639 * - Buddy list add/remove
640 * - Permit list add/remove
641 * - Deny list add/remove
644 * - User information requests
648 * - A few unknowns: 2/9, 2/b, and f/2
652 * - Outgoing chat ICBMs
654 * The only other thing of note is that class 5 (chat) has slightly looser
655 * limiting properties than class 3 (normal messages). But thats just a
656 * small bit of trivia for you.
658 * The last thing that needs to be learned about the rate limiting
659 * system is how the actual numbers relate to the passing of time. This
660 * seems to be a big mystery.
663 faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
665 rxcallback_t userfunc = NULL;
669 unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
670 unsigned long currentavg, maxavg;
674 code = aimutil_get16(command->data+i);
677 rateclass = aimutil_get16(command->data+i);
680 windowsize = aimutil_get32(command->data+i);
682 clear = aimutil_get32(command->data+i);
684 alert = aimutil_get32(command->data+i);
686 limit = aimutil_get32(command->data+i);
688 disconnect = aimutil_get32(command->data+i);
690 currentavg = aimutil_get32(command->data+i);
692 maxavg = aimutil_get32(command->data+i);
695 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x000a)))
696 ret = userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
701 faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command)
703 rxcallback_t userfunc = NULL;
706 unsigned short newevil;
707 struct aim_userinfo_s userinfo;
710 newevil = aimutil_get16(command->data+10);
713 memset(&userinfo, 0, sizeof(struct aim_userinfo_s));
714 if (command->commandlen-i)
715 i += aim_extractuserinfo(sess, command->data+i, &userinfo);
717 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0010)))
718 ret = userfunc(sess, command, newevil, &userinfo);
723 faim_internal int aim_parsemotd_middle(struct aim_session_t *sess,
724 struct command_rx_struct *command, ...)
726 rxcallback_t userfunc = NULL;
729 struct aim_tlvlist_t *tlvlist;
736 * 1 Mandatory upgrade
739 * 4 Nothing's wrong ("top o the world" -- normal)
742 id = aimutil_get16(command->data+10);
747 if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12)))
750 if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) {
751 aim_freetlvchain(&tlvlist);
755 userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0013);
757 ret = userfunc(sess, command, id, msg);
759 aim_freetlvchain(&tlvlist);
765 faim_internal int aim_parse_hostonline(struct aim_session_t *sess,
766 struct command_rx_struct *command, ...)
768 rxcallback_t userfunc = NULL;
770 unsigned short *families = NULL;
773 famcount = (command->commandlen-10)/2;
774 if (!(families = malloc(command->commandlen-10)))
777 for (i = 0; i < famcount; i++)
778 families[i] = aimutil_get16(command->data+((i*2)+10));
780 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0003)))
781 ret = userfunc(sess, command, famcount, families);
788 faim_internal int aim_parse_hostversions(struct aim_session_t *sess,
789 struct command_rx_struct *command, ...)
791 rxcallback_t userfunc = NULL;
795 vercount = (command->commandlen-10)/4;
797 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0018)))
798 ret = userfunc(sess, command, vercount, command->data+10);
803 faim_internal int aim_handleredirect_middle(struct aim_session_t *sess,
804 struct command_rx_struct *command, ...)
807 unsigned char *cookie = NULL;
809 rxcallback_t userfunc = NULL;
810 struct aim_tlvlist_t *tlvlist;
813 tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
815 if (aim_gettlv(tlvlist, 0x000d, 1))
816 serviceid = aim_gettlv16(tlvlist, 0x000d, 1);
817 if (aim_gettlv(tlvlist, 0x0005, 1))
818 ip = aim_gettlv_str(tlvlist, 0x0005, 1);
819 if (aim_gettlv(tlvlist, 0x0006, 1))
820 cookie = aim_gettlv_str(tlvlist, 0x0006, 1);
822 if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) {
828 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
829 ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin, (int)sess->pendingjoinexchange);
830 free(sess->pendingjoin);
831 sess->pendingjoin = NULL;
832 sess->pendingjoinexchange = 0;
833 } else if (!serviceid || !ip || !cookie) { /* yeep! */
836 if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
837 ret = userfunc(sess, command, serviceid, ip, cookie);
845 aim_freetlvchain(&tlvlist);
850 faim_internal int aim_parse_unknown(struct aim_session_t *sess,
851 struct command_rx_struct *command, ...)
855 if (!sess || !command)
858 faimdprintf(sess, 1, "\nRecieved unknown packet:");
860 for (i = 0; i < command->commandlen; i++)
863 faimdprintf(sess, 1, "\n\t");
865 faimdprintf(sess, 1, "0x%2x ", command->data[i]);
868 faimdprintf(sess, 1, "\n\n");
874 faim_internal int aim_negchan_middle(struct aim_session_t *sess,
875 struct command_rx_struct *command)
877 struct aim_tlvlist_t *tlvlist;
879 unsigned short code = 0;
880 rxcallback_t userfunc = NULL;
883 /* Used only by the older login protocol */
884 /* XXX remove this special case? */
885 if (command->conn->type == AIM_CONN_TYPE_AUTH)
886 return consumenonsnac(sess, command, 0x0017, 0x0003);
888 tlvlist = aim_readtlvchain(command->data, command->commandlen);
890 if (aim_gettlv(tlvlist, 0x0009, 1))
891 code = aim_gettlv16(tlvlist, 0x0009, 1);
893 if (aim_gettlv(tlvlist, 0x000b, 1))
894 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
896 if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
897 ret = userfunc(sess, command, code, msg);
899 aim_freetlvchain(&tlvlist);
908 * aim_parse_generalerrs()
910 * Middle handler for 0x0001 snac of each family.
913 faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
914 struct command_rx_struct *command, ...)
916 unsigned short family;
917 unsigned short subtype;
920 rxcallback_t userfunc = NULL;
922 family = aimutil_get16(command->data+0);
923 subtype= aimutil_get16(command->data+2);
925 if (command->commandlen > 10)
926 error = aimutil_get16(command->data+10);
928 if ((userfunc = aim_callhandler(sess, command->conn, family, subtype)))
929 ret = userfunc(sess, command, error);