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)
315 * This is a debugging/sanity check only and probably could/should be removed
318 if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) &&
319 (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) ||
320 ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) &&
321 (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
322 printf("faim: rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
323 workingPtr->handled = 1;
327 switch(workingPtr->conn->type) {
330 * This can happen if we have a queued command
331 * that was recieved after a connection has
332 * been terminated. In which case, the handler
333 * list has been cleared, and there's nothing we
334 * can do for it. We can only cancel it.
336 workingPtr->handled = 1;
338 case AIM_CONN_TYPE_AUTH: {
341 head = aimutil_get32(workingPtr->data);
342 if (head == 0x00000001) {
343 faimdprintf(1, "got connection ack on auth line\n");
344 workingPtr->handled = 1;
345 } else if (workingPtr->hdr.oscar.type == 0x0004) {
346 workingPtr->handled = aim_authparse(sess, workingPtr);
348 u_short family,subtype;
350 family = aimutil_get16(workingPtr->data);
351 subtype = aimutil_get16(workingPtr->data+2);
354 /* New login protocol */
357 if (subtype == 0x0001)
358 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
359 else if (subtype == 0x0003)
360 workingPtr->handled = aim_authparse(sess, workingPtr);
361 else if (subtype == 0x0007)
362 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr);
364 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
367 /* XXX: this isnt foolproof */
369 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr);
372 if (subtype == 0x0005)
373 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
376 /* Old login protocol */
377 /* any user callbacks will be called from here */
378 workingPtr->handled = aim_authparse(sess, workingPtr);
384 case AIM_CONN_TYPE_BOS: {
388 if (workingPtr->hdr.oscar.type == 0x04) {
389 workingPtr->handled = aim_negchan_middle(sess, workingPtr);
393 family = aimutil_get16(workingPtr->data);
394 subtype = aimutil_get16(workingPtr->data+2);
397 case 0x0000: /* not really a family, but it works */
398 if (subtype == 0x0001)
399 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
401 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
403 case 0x0001: /* Family: General */
406 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
409 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
412 workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
415 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
418 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
421 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
424 workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
427 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
430 case 0x0002: /* Family: Location */
433 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
436 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
439 workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
442 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
445 case 0x0003: /* Family: Buddy List */
448 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
451 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
453 case 0x000b: /* oncoming buddy */
454 workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
456 case 0x000c: /* offgoing buddy */
457 workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
460 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
463 case 0x0004: /* Family: Messeging */
466 workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
469 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
472 workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
475 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr);
478 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
482 if (subtype == 0x0001)
483 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
484 else if (subtype == 0x0003)
485 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr);
487 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
489 case 0x000a: /* Family: User lookup */
492 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
495 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
498 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
502 if (subtype == 0x0001)
503 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
504 else if (subtype == 0x0002)
505 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
507 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
510 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
515 case AIM_CONN_TYPE_CHATNAV: {
518 family = aimutil_get16(workingPtr->data);
519 subtype= aimutil_get16(workingPtr->data+2);
521 if ((family == 0x0002) && (subtype == 0x0006)) {
522 workingPtr->handled = 1;
523 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
524 } else if ((family == 0x000d) && (subtype == 0x0009)) {
525 workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
527 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
531 case AIM_CONN_TYPE_CHAT: {
532 u_short family, subtype;
534 family = aimutil_get16(workingPtr->data);
535 subtype= aimutil_get16(workingPtr->data+2);
537 if ((family == 0x0000) && (subtype == 0x00001))
538 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
539 else if (family == 0x0001) {
540 if (subtype == 0x0001)
541 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
542 else if (subtype == 0x0003)
543 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
544 else if (subtype == 0x0007)
545 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
547 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
548 } else if (family == 0x000e) {
549 if (subtype == 0x0002)
550 workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
551 else if (subtype == 0x0003)
552 workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);
553 else if (subtype == 0x0004)
554 workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);
555 else if (subtype == 0x0006)
556 workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
558 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
560 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
561 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
565 case AIM_CONN_TYPE_RENDEZVOUS: {
566 /* make sure that we only get OFT frames on these connections */
567 if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
568 printf("faim: internal error: non-OFT frames on OFT connection\n");
569 workingPtr->handled = 1; /* get rid of it */
573 /* XXX: implement this */
574 printf("faim: OFT frame!\n");
579 printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->commandlen);
580 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
587 * This doesn't have to be called here. It could easily be done
588 * by a seperate thread or something. It's an administrative operation,
589 * and can take a while. Though the less you call it the less memory
592 aim_purge_rxqueue(sess);
597 int aim_parsemotd_middle(struct aim_session_t *sess,
598 struct command_rx_struct *command, ...)
600 rxcallback_t userfunc = NULL;
603 struct aim_tlvlist_t *tlvlist;
609 id = aimutil_get16(command->data+10);
614 tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
616 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
618 userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
620 ret = userfunc(sess, command, id, msg);
622 aim_freetlvchain(&tlvlist);
628 int aim_handleredirect_middle(struct aim_session_t *sess,
629 struct command_rx_struct *command, ...)
631 struct aim_tlv_t *tmptlv = NULL;
632 int serviceid = 0x00;
633 char cookie[AIM_COOKIELEN];
635 rxcallback_t userfunc = NULL;
636 struct aim_tlvlist_t *tlvlist;
639 if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10)))
641 printf("libfaim: major bug: unable to read tlvchain from redirect\n");
645 if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1)))
647 printf("libfaim: major bug: no service ID in tlvchain from redirect\n");
648 aim_freetlvchain(&tlvlist);
651 serviceid = aimutil_get16(tmptlv->value);
653 if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1)))
655 printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
656 aim_freetlvchain(&tlvlist);
660 if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
662 printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
663 aim_freetlvchain(&tlvlist);
666 memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
668 if (serviceid == AIM_CONN_TYPE_CHAT)
674 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
676 ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
677 free(sess->pendingjoin);
678 sess->pendingjoin = NULL;
682 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
684 ret = userfunc(sess, command, serviceid, ip, cookie);
688 * XXX: Is there a leak here? Where does IP get freed?
690 aim_freetlvchain(&tlvlist);
695 int aim_parse_unknown(struct aim_session_t *sess,
696 struct command_rx_struct *command, ...)
700 faimdprintf(1, "\nRecieved unknown packet:");
702 for (i = 0; i < command->commandlen; i++)
705 faimdprintf(1, "\n\t");
707 faimdprintf(1, "0x%2x ", command->data[i]);
710 faimdprintf(1, "\n\n");
716 int aim_negchan_middle(struct aim_session_t *sess,
717 struct command_rx_struct *command)
719 struct aim_tlvlist_t *tlvlist;
721 unsigned short code = 0;
722 struct aim_tlv_t *tmptlv;
723 rxcallback_t userfunc = NULL;
726 tlvlist = aim_readtlvchain(command->data, command->commandlen);
728 if ((tmptlv = aim_gettlv(tlvlist, 0x0009, 1)))
729 code = aimutil_get16(tmptlv->value);
731 if ((tmptlv = aim_gettlv(tlvlist, 0x000b, 1)))
732 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
734 userfunc = aim_callhandler(command->conn,
735 AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR);
737 ret = userfunc(sess, command, code, msg);
739 aim_freetlvchain(&tlvlist);
746 * aim_parse_generalerrs()
748 * Middle handler for 0x0001 snac of each family.
751 int aim_parse_generalerrs(struct aim_session_t *sess,
752 struct command_rx_struct *command, ...)
757 family = aimutil_get16(command->data+0);
758 subtype= aimutil_get16(command->data+2);
764 return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);