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 struct aim_rxcblist_s {
16 aim_rxcallback_t handler;
18 struct aim_rxcblist_s *next;
21 static aim_module_t *findmodule(aim_session_t *sess, const char *name)
25 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
26 if (strcmp(name, cur->name) == 0)
33 faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *))
37 if (!sess || !modfirst)
40 if (!(mod = malloc(sizeof(aim_module_t))))
42 memset(mod, 0, sizeof(aim_module_t));
44 if (modfirst(sess, mod) == -1) {
49 if (findmodule(sess, mod->name)) {
51 mod->shutdown(sess, mod);
56 mod->next = (aim_module_t *)sess->modlistv;
57 (aim_module_t *)sess->modlistv = mod;
59 faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family);
64 faim_internal void aim__shutdownmodules(aim_session_t *sess)
68 for (cur = (aim_module_t *)sess->modlistv; cur; ) {
74 cur->shutdown(sess, cur);
81 sess->modlistv = NULL;
86 static int consumesnac(aim_session_t *sess, aim_frame_t *rx)
91 if (aim_bstream_empty(&rx->data) < 10)
94 snac.family = aimbs_get16(&rx->data);
95 snac.subtype = aimbs_get16(&rx->data);
96 snac.flags = aimbs_get16(&rx->data);
97 snac.id = aimbs_get32(&rx->data);
99 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
101 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
102 (cur->family != snac.family))
105 if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
113 static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, fu16_t family, fu16_t subtype)
118 snac.family = family;
119 snac.subtype = subtype;
120 snac.flags = snac.id = 0;
122 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
124 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
125 (cur->family != snac.family))
128 if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
136 static int negchan_middle(aim_session_t *sess, aim_frame_t *fr)
138 aim_tlvlist_t *tlvlist;
141 aim_rxcallback_t userfunc;
144 if (aim_bstream_empty(&fr->data) == 0) {
145 /* XXX should do something with this */
149 /* Used only by the older login protocol */
150 /* XXX remove this special case? */
151 if (fr->conn->type == AIM_CONN_TYPE_AUTH)
152 return consumenonsnac(sess, fr, 0x0017, 0x0003);
154 tlvlist = aim_readtlvchain(&fr->data);
156 if (aim_gettlv(tlvlist, 0x0009, 1))
157 code = aim_gettlv16(tlvlist, 0x0009, 1);
159 if (aim_gettlv(tlvlist, 0x000b, 1))
160 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
162 if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
163 ret = userfunc(sess, fr, code, msg);
165 aim_freetlvchain(&tlvlist);
173 * Bleck functions get called when there's no non-bleck functions
174 * around to cleanup the mess...
176 faim_internal int bleck(aim_session_t *sess, aim_frame_t *frame, ...)
178 fu16_t family, subtype;
181 static const char *channels[6] = {
189 static const int maxchannels = 5;
191 /* XXX: this is ugly. and big just for debugging. */
192 static const char *literals[14][25] = {
203 "Rate Information Request",
205 "Rate Information Ack",
207 "Rate Information Change",
211 "Request Personal User Information",
212 "Personal User Information",
216 "Message of the Day",
225 "Rights Information",
226 "Set user information",
227 "Request User Information",
229 "Watcher Sub Request",
230 "Watcher Notification"
232 {"Buddy List Management",
236 "Rights Information",
239 "Watcher List Query",
240 "Watcher List Response",
241 "Watcher SubRequest",
242 "Watcher Notification",
243 "Reject Notification",
250 "Add ICBM Parameter",
251 "Remove ICBM Parameter",
252 "Request Parameter Information",
253 "Parameter Information",
268 {"Invitation / Client-to-Client",
277 "Information Request",
279 "Information Change Request",
280 "Information Chat Reply",
281 "Account Confirm Request",
282 "Account Confirm Reply",
283 "Account Delete Request",
284 "Account Delete Reply"
296 "Set group permission mask",
297 "Add permission list entries",
298 "Delete permission list entries",
299 "Add deny list entries",
300 "Delete deny list entries",
312 "Set minimum report interval",
325 "Request Exchange Information",
326 "Request Room Information",
327 "Request Occupant List",
337 maxf = sizeof(literals) / sizeof(literals[0]);
338 maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
340 if (frame->hdr.flap.type == 0x02) {
342 family = aimbs_get16(&frame->data);
343 subtype = aimbs_get16(&frame->data);
345 if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
346 faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->hdr.flap.type], family, subtype, literals[family][subtype+1]);
348 faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->hdr.flap.type], family, subtype);
351 if (frame->hdr.flap.type <= maxchannels)
352 faimdprintf(sess, 0, "bleck: channel %s (0x%02x)\n", channels[frame->hdr.flap.type], frame->hdr.flap.type);
354 faimdprintf(sess, 0, "bleck: unknown channel 0x%02x\n", frame->hdr.flap.type);
361 faim_export int aim_conn_addhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_rxcallback_t newhandler, fu16_t flags)
363 struct aim_rxcblist_s *newcb;
368 faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
370 if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s))))
373 newcb->family = family;
375 newcb->flags = flags;
376 newcb->handler = newhandler ? newhandler : bleck;
379 if (!conn->handlerlist)
380 conn->handlerlist = (void *)newcb;
382 struct aim_rxcblist_s *cur;
384 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next)
392 faim_export int aim_clearhandlers(aim_conn_t *conn)
394 struct aim_rxcblist_s *cur;
399 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) {
400 struct aim_rxcblist_s *tmp;
406 conn->handlerlist = NULL;
411 faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type)
413 struct aim_rxcblist_s *cur;
418 faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
420 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) {
421 if ((cur->family == family) && (cur->type == type))
425 if (type == AIM_CB_SPECIAL_DEFAULT) {
426 faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family);
427 return NULL; /* prevent infinite recursion */
430 faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type);
432 return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
435 faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src)
437 struct aim_rxcblist_s *cur;
439 for (cur = (struct aim_rxcblist_s *)src->handlerlist; cur; cur = cur->next) {
440 aim_conn_addhandler(sess, dest, cur->family, cur->type,
441 cur->handler, cur->flags);
447 faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn,fu16_t family, fu16_t type, aim_frame_t *ptr)
449 aim_rxcallback_t userfunc;
451 if ((userfunc = aim_callhandler(sess, conn, family, type)))
452 return userfunc(sess, ptr);
460 * Basically, heres what this should do:
461 * 1) Determine correct packet handler for this packet
462 * 2) Mark the packet handled (so it can be dequeued in purge_queue())
463 * 3) Send the packet to the packet handler
464 * 4) Go to next packet in the queue and start over
465 * 5) When done, run purge_queue() to purge handled commands
468 * TODO: More support for mid-level handlers.
469 * TODO: Allow for NULL handlers.
472 faim_export void aim_rxdispatch(aim_session_t *sess)
477 for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) {
480 * XXX: This is still fairly ugly.
487 * This is a debugging/sanity check only and probably
488 * could/should be removed for stable code.
490 if (((cur->hdrtype == AIM_FRAMETYPE_OFT) &&
491 (cur->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) ||
492 ((cur->hdrtype == AIM_FRAMETYPE_FLAP) &&
493 (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
494 faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", cur->hdrtype, cur->conn->type);
499 if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
500 if (cur->hdrtype != AIM_FRAMETYPE_OFT) {
501 faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n");
502 cur->handled = 1; /* get rid of it */
504 /* XXX: implement this */
505 faimdprintf(sess, 0, "faim: OFT frame!\n");
506 cur->handled = 1; /* get rid of it */
511 if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
513 faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n");
518 if (cur->hdr.flap.type == 0x01) {
520 cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
524 } else if (cur->hdr.flap.type == 0x02) {
526 if ((cur->handled = consumesnac(sess, cur)))
529 } else if (cur->hdr.flap.type == 0x04) {
531 cur->handled = negchan_middle(sess, cur);
534 } else if (cur->hdr.flap.type == 0x05)
538 consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */
544 * This doesn't have to be called here. It could easily be done
545 * by a seperate thread or something. It's an administrative operation,
546 * and can take a while. Though the less you call it the less memory
549 aim_purge_rxqueue(sess);
554 faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...)
558 faimdprintf(sess, 1, "\nRecieved unknown packet:");
560 for (i = 0; aim_bstream_empty(&frame->data); i++) {
562 faimdprintf(sess, 1, "\n\t");
564 faimdprintf(sess, 1, "0x%2x ", aimbs_get8(&frame->data));
567 faimdprintf(sess, 1, "\n\n");