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, 1, "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 aim_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 aim_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 aim_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 if (!workingPtr->handled) {
491 family = aimutil_get16(workingPtr->data);
492 subtype = aimutil_get16(workingPtr->data+2);
494 faimdprintf(sess, 1, "warning: unhandled packet %04x/%04x\n", family, subtype);
495 consumenonsnac(sess, workingPtr, 0xffff, 0xffff); /* last chance! */
496 workingPtr->handled = 1;
502 * This doesn't have to be called here. It could easily be done
503 * by a seperate thread or something. It's an administrative operation,
504 * and can take a while. Though the less you call it the less memory
507 aim_purge_rxqueue(sess);
514 faim_internal int aim_parse_unknown(struct aim_session_t *sess,
515 struct command_rx_struct *command, ...)
519 if (!sess || !command)
522 faimdprintf(sess, 1, "\nRecieved unknown packet:");
524 for (i = 0; i < command->commandlen; i++)
527 faimdprintf(sess, 1, "\n\t");
529 faimdprintf(sess, 1, "0x%2x ", command->data[i]);
532 faimdprintf(sess, 1, "\n\n");
538 faim_internal int aim_negchan_middle(struct aim_session_t *sess,
539 struct command_rx_struct *command)
541 struct aim_tlvlist_t *tlvlist;
543 unsigned short code = 0;
544 aim_rxcallback_t userfunc = NULL;
547 /* Used only by the older login protocol */
548 /* XXX remove this special case? */
549 if (command->conn->type == AIM_CONN_TYPE_AUTH)
550 return consumenonsnac(sess, command, 0x0017, 0x0003);
552 tlvlist = aim_readtlvchain(command->data, command->commandlen);
554 if (aim_gettlv(tlvlist, 0x0009, 1))
555 code = aim_gettlv16(tlvlist, 0x0009, 1);
557 if (aim_gettlv(tlvlist, 0x000b, 1))
558 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
560 if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
561 ret = userfunc(sess, command, code, msg);
563 aim_freetlvchain(&tlvlist);