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;
197 printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type);
200 new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
201 new->family = family;
205 new->handler = &bleck;
207 new->handler = newhandler;
210 cur = conn->handlerlist;
212 conn->handlerlist = new;
223 int aim_clearhandlers(struct aim_conn_t *conn)
225 struct aim_rxcblist_t *cur,*tmp;
229 cur = conn->handlerlist;
239 rxcallback_t aim_callhandler(struct aim_conn_t *conn,
243 struct aim_rxcblist_t *cur;
249 printf("aim_callhandler: calling for %04x/%04x\n", family, type);
252 cur = conn->handlerlist;
255 if ( (cur->family == family) && (cur->type == type) )
262 return aim_callhandler(conn, family, 0xffff);
265 int aim_callhandler_noparam(struct aim_session_t *sess,
266 struct aim_conn_t *conn,
269 struct command_rx_struct *ptr)
271 rxcallback_t userfunc = NULL;
272 userfunc = aim_callhandler(conn, family, type);
274 return userfunc(sess, ptr);
281 Basically, heres what this should do:
282 1) Determine correct packet handler for this packet
283 2) Mark the packet handled (so it can be dequeued in purge_queue())
284 3) Send the packet to the packet handler
285 4) Go to next packet in the queue and start over
286 5) When done, run purge_queue() to purge handled commands
288 Note that any unhandlable packets should probably be left in the
289 queue. This is the best way to prevent data loss. This means
290 that a single packet may get looked at by this function multiple
291 times. This is more good than bad! This behavior may change.
295 TODO: Get rid of all the ugly if's.
297 TODO: More support for mid-level handlers.
298 TODO: Allow for NULL handlers.
301 int aim_rxdispatch(struct aim_session_t *sess)
304 struct command_rx_struct *workingPtr = NULL;
306 if (sess->queue_incoming == NULL)
307 /* this shouldn't really happen, unless the main loop's select is broke */
308 printf("parse_generic: incoming packet queue empty.\n");
311 workingPtr = sess->queue_incoming;
312 for (i = 0; workingPtr != NULL; i++)
315 * XXX: This is still fairly ugly.
317 switch(workingPtr->conn->type)
321 * This can happen if we have a queued command
322 * that was recieved after a connection has
323 * been terminated. In which case, the handler
324 * list has been cleared, and there's nothing we
325 * can do for it. We can only cancel it.
327 workingPtr->handled = 1;
329 case AIM_CONN_TYPE_AUTH:
333 head = aimutil_get32(workingPtr->data);
334 if (head == 0x00000001)
337 printf("got connection ack on auth line\n");
339 workingPtr->handled = 1;
343 u_short family,subtype;
345 family = aimutil_get16(workingPtr->data);
346 subtype = aimutil_get16(workingPtr->data+2);
350 /* New login protocol */
353 if (subtype == 0x0001)
354 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
355 else if (subtype == 0x0003)
356 workingPtr->handled = aim_authparse(sess, workingPtr);
357 else if (subtype == 0x0007)
358 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr);
360 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
363 /* XXX: this isnt foolproof */
365 if (subtype == 0x0003)
366 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr);
368 workingPtr->handled = aim_authparse(sess, workingPtr);
371 if (subtype == 0x0005)
372 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
375 /* Old login protocol */
376 /* any user callbacks will be called from here */
377 workingPtr->handled = aim_authparse(sess, workingPtr);
383 case AIM_CONN_TYPE_BOS:
388 family = aimutil_get16(workingPtr->data);
389 subtype = aimutil_get16(workingPtr->data+2);
393 case 0x0000: /* not really a family, but it works */
394 if (subtype == 0x0001)
395 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
397 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
399 case 0x0001: /* Family: General */
403 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
406 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
409 workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
412 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
415 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
418 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
421 workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
424 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
427 case 0x0002: /* Family: Location */
431 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
434 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
437 workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
440 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
443 case 0x0003: /* Family: Buddy List */
447 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
450 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
452 case 0x000b: /* oncoming buddy */
453 workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
455 case 0x000c: /* offgoing buddy */
456 workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
459 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
462 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 */
493 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
496 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
499 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
503 if (subtype == 0x0001)
504 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
505 else if (subtype == 0x0002)
506 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
508 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
511 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
516 case AIM_CONN_TYPE_CHATNAV:
520 family = aimutil_get16(workingPtr->data);
521 subtype= aimutil_get16(workingPtr->data+2);
523 if ((family == 0x0002) && (subtype == 0x0006))
525 workingPtr->handled = 1;
526 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
528 else if ((family == 0x000d) && (subtype == 0x0009))
529 workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
532 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
536 case AIM_CONN_TYPE_CHAT:
538 u_short family, subtype;
540 family = aimutil_get16(workingPtr->data);
541 subtype= aimutil_get16(workingPtr->data+2);
543 if ((family == 0x0000) && (subtype == 0x00001))
544 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
545 else if (family == 0x0001)
547 if (subtype == 0x0001)
548 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
549 else if (subtype == 0x0003)
550 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
551 else if (subtype == 0x0007)
552 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
554 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
556 else if (family == 0x000e)
558 if (subtype == 0x0002)
559 workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
560 else if (subtype == 0x0003)
561 workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);
562 else if (subtype == 0x0004)
563 workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);
564 else if (subtype == 0x0006)
565 workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
567 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
571 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
572 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
577 printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (type = %d, fd = %d, channel = %02x, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->type, workingPtr->commandlen);
578 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
581 /* move to next command */
582 workingPtr = workingPtr->next;
586 sess->queue_incoming = aim_purge_rxqueue(sess->queue_incoming);
591 int aim_parsemotd_middle(struct aim_session_t *sess,
592 struct command_rx_struct *command, ...)
594 rxcallback_t userfunc = NULL;
597 struct aim_tlvlist_t *tlvlist;
603 id = aimutil_get16(command->data+10);
608 tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
610 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
612 userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
614 ret = userfunc(sess, command, id, msg);
616 aim_freetlvchain(&tlvlist);
622 int aim_handleredirect_middle(struct aim_session_t *sess,
623 struct command_rx_struct *command, ...)
625 struct aim_tlv_t *tmptlv = NULL;
626 int serviceid = 0x00;
627 char cookie[AIM_COOKIELEN];
629 rxcallback_t userfunc = NULL;
630 struct aim_tlvlist_t *tlvlist;
633 if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10)))
635 printf("libfaim: major bug: unable to read tlvchain from redirect\n");
639 if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1)))
641 printf("libfaim: major bug: no service ID in tlvchain from redirect\n");
642 aim_freetlvchain(&tlvlist);
645 serviceid = aimutil_get16(tmptlv->value);
647 if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1)))
649 printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
650 aim_freetlvchain(&tlvlist);
654 if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
656 printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
657 aim_freetlvchain(&tlvlist);
660 memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
662 if (serviceid == AIM_CONN_TYPE_CHAT)
668 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
670 ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
671 free(sess->pendingjoin);
672 sess->pendingjoin = NULL;
676 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
678 ret = userfunc(sess, command, serviceid, ip, cookie);
682 * XXX: Is there a leak here? Where does IP get freed?
684 aim_freetlvchain(&tlvlist);
689 int aim_parse_unknown(struct aim_session_t *sess,
690 struct command_rx_struct *command, ...)
694 printf("\nRecieved unknown packet:");
696 for (i = 0; i < command->commandlen; i++)
701 printf("0x%2x ", command->data[i]);
711 * aim_parse_generalerrs()
713 * Middle handler for 0x0001 snac of each family.
716 int aim_parse_generalerrs(struct aim_session_t *sess,
717 struct command_rx_struct *command, ...)
722 family = aimutil_get16(command->data+0);
723 subtype= aimutil_get16(command->data+2);
729 return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);