]> andersk Git - libfaim.git/blame - src/rxhandlers.c
- Mon Sep 3 18:48:26 PDT 2001
[libfaim.git] / src / rxhandlers.c
CommitLineData
9de3ca7e 1/*
24286d93 2 * aim_rxhandlers.c
3 *
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.
7 *
9de3ca7e 8 */
9
37ee990e 10#define FAIM_INTERNAL
dd60ff8b 11#include <aim.h>
9de3ca7e 12
d410cf58 13struct aim_rxcblist_s {
14 fu16_t family;
15 fu16_t type;
16 aim_rxcallback_t handler;
17 u_short flags;
18 struct aim_rxcblist_s *next;
19};
20
21static aim_module_t *findmodule(aim_session_t *sess, const char *name)
9f1a4013 22{
d410cf58 23 aim_module_t *cur;
9f1a4013 24
d410cf58 25 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
26 if (strcmp(name, cur->name) == 0)
27 return cur;
28 }
9f1a4013 29
d410cf58 30 return NULL;
9f1a4013 31}
32
d410cf58 33faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *))
9f1a4013 34{
d410cf58 35 aim_module_t *mod;
9f1a4013 36
d410cf58 37 if (!sess || !modfirst)
38 return -1;
9f1a4013 39
d410cf58 40 if (!(mod = malloc(sizeof(aim_module_t))))
41 return -1;
42 memset(mod, 0, sizeof(aim_module_t));
9f1a4013 43
d410cf58 44 if (modfirst(sess, mod) == -1) {
45 free(mod);
46 return -1;
47 }
9f1a4013 48
d410cf58 49 if (findmodule(sess, mod->name)) {
50 if (mod->shutdown)
51 mod->shutdown(sess, mod);
52 free(mod);
53 return -1;
54 }
9f1a4013 55
d410cf58 56 mod->next = (aim_module_t *)sess->modlistv;
57 (aim_module_t *)sess->modlistv = mod;
9f1a4013 58
d410cf58 59 faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family);
9f1a4013 60
d410cf58 61 return 0;
9f1a4013 62}
63
d410cf58 64faim_internal void aim__shutdownmodules(aim_session_t *sess)
9f1a4013 65{
d410cf58 66 aim_module_t *cur;
9f1a4013 67
d410cf58 68 for (cur = (aim_module_t *)sess->modlistv; cur; ) {
69 aim_module_t *tmp;
9f1a4013 70
d410cf58 71 tmp = cur->next;
9f1a4013 72
d410cf58 73 if (cur->shutdown)
74 cur->shutdown(sess, cur);
9f1a4013 75
d410cf58 76 free(cur);
9f1a4013 77
d410cf58 78 cur = tmp;
79 }
9f1a4013 80
d410cf58 81 sess->modlistv = NULL;
9f1a4013 82
d410cf58 83 return;
9f1a4013 84}
85
d410cf58 86static int consumesnac(aim_session_t *sess, aim_frame_t *rx)
9f1a4013 87{
d410cf58 88 aim_module_t *cur;
89 aim_modsnac_t snac;
9f1a4013 90
d410cf58 91 if (aim_bstream_empty(&rx->data) < 10)
92 return 0;
9f1a4013 93
d410cf58 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);
9f1a4013 98
d410cf58 99 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
9f1a4013 100
d410cf58 101 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
102 (cur->family != snac.family))
103 continue;
9f1a4013 104
d410cf58 105 if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
106 return 1;
9f1a4013 107
d410cf58 108 }
109
110 return 0;
9f1a4013 111}
112
d410cf58 113static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, fu16_t family, fu16_t subtype)
9f1a4013 114{
d410cf58 115 aim_module_t *cur;
116 aim_modsnac_t snac;
9f1a4013 117
d410cf58 118 snac.family = family;
119 snac.subtype = subtype;
120 snac.flags = snac.id = 0;
9f1a4013 121
d410cf58 122 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
9f1a4013 123
d410cf58 124 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
125 (cur->family != snac.family))
126 continue;
9f1a4013 127
d410cf58 128 if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
129 return 1;
9f1a4013 130
d410cf58 131 }
9f1a4013 132
d410cf58 133 return 0;
134}
135
136static int negchan_middle(aim_session_t *sess, aim_frame_t *fr)
137{
138 aim_tlvlist_t *tlvlist;
139 char *msg = NULL;
140 fu16_t code = 0;
141 aim_rxcallback_t userfunc;
142 int ret = 1;
143
144 if (aim_bstream_empty(&fr->data) == 0) {
145 /* XXX should do something with this */
146 return 1;
147 }
148
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);
153
154 tlvlist = aim_readtlvchain(&fr->data);
155
156 if (aim_gettlv(tlvlist, 0x0009, 1))
157 code = aim_gettlv16(tlvlist, 0x0009, 1);
158
159 if (aim_gettlv(tlvlist, 0x000b, 1))
160 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
161
162 if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
163 ret = userfunc(sess, fr, code, msg);
164
165 aim_freetlvchain(&tlvlist);
166
167 free(msg);
168
169 return ret;
9f1a4013 170}
171
24286d93 172/*
173 * Bleck functions get called when there's no non-bleck functions
174 * around to cleanup the mess...
175 */
d410cf58 176faim_internal int bleck(aim_session_t *sess, aim_frame_t *frame, ...)
9de3ca7e 177{
d410cf58 178 fu16_t family, subtype;
179 fu16_t maxf, maxs;
180
181 static const char *channels[6] = {
182 "Invalid (0)",
183 "FLAP Version",
184 "SNAC",
185 "Invalid (3)",
186 "Negotiation",
187 "FLAP NOP"
188 };
189 static const int maxchannels = 5;
190
191 /* XXX: this is ugly. and big just for debugging. */
192 static const char *literals[14][25] = {
193 {"Invalid",
194 NULL
195 },
196 {"General",
197 "Invalid",
198 "Error",
199 "Client Ready",
200 "Server Ready",
201 "Service Request",
202 "Redirect",
203 "Rate Information Request",
204 "Rate Information",
205 "Rate Information Ack",
206 NULL,
207 "Rate Information Change",
208 "Server Pause",
209 NULL,
210 "Server Resume",
211 "Request Personal User Information",
212 "Personal User Information",
213 "Evil Notification",
214 NULL,
215 "Migration notice",
216 "Message of the Day",
217 "Set Privacy Flags",
218 "Well Known URL",
219 "NOP"
220 },
221 {"Location",
222 "Invalid",
223 "Error",
224 "Request Rights",
225 "Rights Information",
226 "Set user information",
227 "Request User Information",
228 "User Information",
229 "Watcher Sub Request",
230 "Watcher Notification"
231 },
232 {"Buddy List Management",
233 "Invalid",
234 "Error",
235 "Request Rights",
236 "Rights Information",
237 "Add Buddy",
238 "Remove Buddy",
239 "Watcher List Query",
240 "Watcher List Response",
241 "Watcher SubRequest",
242 "Watcher Notification",
243 "Reject Notification",
244 "Oncoming Buddy",
245 "Offgoing Buddy"
246 },
247 {"Messeging",
248 "Invalid",
249 "Error",
250 "Add ICBM Parameter",
251 "Remove ICBM Parameter",
252 "Request Parameter Information",
253 "Parameter Information",
254 "Outgoing Message",
255 "Incoming Message",
256 "Evil Request",
257 "Evil Reply",
258 "Missed Calls",
259 "Message Error",
260 "Host Ack"
261 },
262 {"Advertisements",
263 "Invalid",
264 "Error",
265 "Request Ad",
266 "Ad Data (GIFs)"
267 },
268 {"Invitation / Client-to-Client",
269 "Invalid",
270 "Error",
271 "Invite a Friend",
272 "Invitation Ack"
273 },
274 {"Administrative",
275 "Invalid",
276 "Error",
277 "Information Request",
278 "Information Reply",
279 "Information Change Request",
280 "Information Chat Reply",
281 "Account Confirm Request",
282 "Account Confirm Reply",
283 "Account Delete Request",
284 "Account Delete Reply"
285 },
286 {"Popups",
287 "Invalid",
288 "Error",
289 "Display Popup"
290 },
291 {"BOS",
292 "Invalid",
293 "Error",
294 "Request Rights",
295 "Rights Response",
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",
301 "Server Error"
302 },
303 {"User Lookup",
304 "Invalid",
305 "Error",
306 "Search Request",
307 "Search Response"
308 },
309 {"Stats",
310 "Invalid",
311 "Error",
312 "Set minimum report interval",
313 "Report Events"
314 },
315 {"Translate",
316 "Invalid",
317 "Error",
318 "Translate Request",
319 "Translate Reply",
320 },
321 {"Chat Navigation",
322 "Invalid",
323 "Error",
324 "Request rights",
325 "Request Exchange Information",
326 "Request Room Information",
327 "Request Occupant List",
328 "Search for Room",
329 "Outgoing Message",
330 "Incoming Message",
331 "Evil Request",
332 "Evil Reply",
333 "Chat Error",
334 }
335 };
336
337 maxf = sizeof(literals) / sizeof(literals[0]);
338 maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
339
340 if (frame->hdr.flap.type == 0x02) {
341
342 family = aimbs_get16(&frame->data);
343 subtype = aimbs_get16(&frame->data);
344
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]);
347 else
348 faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->hdr.flap.type], family, subtype);
349 } else {
350
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);
353 else
354 faimdprintf(sess, 0, "bleck: unknown channel 0x%02x\n", frame->hdr.flap.type);
355
356 }
357
358 return 1;
9de3ca7e 359}
360
d410cf58 361faim_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)
9de3ca7e 362{
d410cf58 363 struct aim_rxcblist_s *newcb;
364
365 if (!conn)
366 return -1;
367
368 faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
369
370 if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s))))
371 return -1;
372
373 newcb->family = family;
374 newcb->type = type;
375 newcb->flags = flags;
376 newcb->handler = newhandler ? newhandler : bleck;
377 newcb->next = NULL;
378
379 if (!conn->handlerlist)
380 conn->handlerlist = (void *)newcb;
381 else {
382 struct aim_rxcblist_s *cur;
383
384 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next)
385 ;
386 cur->next = newcb;
387 }
388
389 return 0;
9de3ca7e 390}
391
d410cf58 392faim_export int aim_clearhandlers(aim_conn_t *conn)
9de3ca7e 393{
d410cf58 394 struct aim_rxcblist_s *cur;
871e2fd0 395
d410cf58 396 if (!conn)
397 return -1;
9de3ca7e 398
d410cf58 399 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) {
400 struct aim_rxcblist_s *tmp;
871e2fd0 401
d410cf58 402 tmp = cur->next;
403 free(cur);
404 cur = tmp;
405 }
406 conn->handlerlist = NULL;
871e2fd0 407
d410cf58 408 return 0;
9de3ca7e 409}
410
d410cf58 411faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type)
9de3ca7e 412{
d410cf58 413 struct aim_rxcblist_s *cur;
414
415 if (!conn)
416 return NULL;
9de3ca7e 417
d410cf58 418 faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
9de3ca7e 419
d410cf58 420 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) {
421 if ((cur->family == family) && (cur->type == type))
422 return cur->handler;
423 }
9de3ca7e 424
d410cf58 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 */
428 }
646c6b52 429
d410cf58 430 faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type);
871e2fd0 431
d410cf58 432 return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
9de3ca7e 433}
434
d410cf58 435faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src)
9de3ca7e 436{
d410cf58 437 struct aim_rxcblist_s *cur;
9de3ca7e 438
d410cf58 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);
b8d0da45 442 }
d410cf58 443
444 return;
9de3ca7e 445}
446
d410cf58 447faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn,fu16_t family, fu16_t type, aim_frame_t *ptr)
9de3ca7e 448{
d410cf58 449 aim_rxcallback_t userfunc;
9de3ca7e 450
d410cf58 451 if ((userfunc = aim_callhandler(sess, conn, family, type)))
452 return userfunc(sess, ptr);
22517493 453
d410cf58 454 return 1; /* XXX */
455}
9de3ca7e 456
d410cf58 457/*
458 * aim_rxdispatch()
459 *
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
466 *
467 * TODO: Clean up.
468 * TODO: More support for mid-level handlers.
469 * TODO: Allow for NULL handlers.
470 *
471 */
472faim_export void aim_rxdispatch(aim_session_t *sess)
473{
474 int i;
475 aim_frame_t *cur;
476
477 for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) {
478
479 /*
480 * XXX: This is still fairly ugly.
481 */
482
483 if (cur->handled)
484 continue;
485
486 /*
487 * This is a debugging/sanity check only and probably
488 * could/should be removed for stable code.
489 */
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);
495 cur->handled = 1;
496 continue;
497 }
498
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 */
503 } else {
504 /* XXX: implement this */
505 faimdprintf(sess, 0, "faim: OFT frame!\n");
506 cur->handled = 1; /* get rid of it */
507 }
508 continue;
509 }
510
511 if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
512 /* not possible */
513 faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n");
514 cur->handled = 1;
515 continue;
516 }
517
518 if (cur->hdr.flap.type == 0x01) {
519
520 cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
521
522 continue;
523
524 } else if (cur->hdr.flap.type == 0x02) {
525
526 if ((cur->handled = consumesnac(sess, cur)))
527 continue;
528
529 } else if (cur->hdr.flap.type == 0x04) {
530
531 cur->handled = negchan_middle(sess, cur);
532 continue;
533
534 } else if (cur->hdr.flap.type == 0x05)
535 ;
536
537 if (!cur->handled) {
538 consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */
539 cur->handled = 1;
540 }
541 }
9de3ca7e 542
d410cf58 543 /*
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
547 * you'll have :)
548 */
549 aim_purge_rxqueue(sess);
9de3ca7e 550
d410cf58 551 return;
9de3ca7e 552}
553
d410cf58 554faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...)
5e02cf44 555{
d410cf58 556 int i;
bb010ae0 557
d410cf58 558 faimdprintf(sess, 1, "\nRecieved unknown packet:");
5e02cf44 559
d410cf58 560 for (i = 0; aim_bstream_empty(&frame->data); i++) {
561 if ((i % 8) == 0)
562 faimdprintf(sess, 1, "\n\t");
5e02cf44 563
d410cf58 564 faimdprintf(sess, 1, "0x%2x ", aimbs_get8(&frame->data));
565 }
5e02cf44 566
d410cf58 567 faimdprintf(sess, 1, "\n\n");
5e02cf44 568
d410cf58 569 return 1;
570}
1ea867e3 571
5e02cf44 572
5e02cf44 573
This page took 0.311791 seconds and 5 git commands to generate.