]> andersk Git - libfaim.git/blame_incremental - src/rxhandlers.c
- Sun Oct 14 19:45:54 PDT 2001
[libfaim.git] / src / rxhandlers.c
... / ...
CommitLineData
1/*
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 *
8 */
9
10#define FAIM_INTERNAL
11#include <aim.h>
12
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)
22{
23 aim_module_t *cur;
24
25 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
26 if (strcmp(name, cur->name) == 0)
27 return cur;
28 }
29
30 return NULL;
31}
32
33faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *))
34{
35 aim_module_t *mod;
36
37 if (!sess || !modfirst)
38 return -1;
39
40 if (!(mod = malloc(sizeof(aim_module_t))))
41 return -1;
42 memset(mod, 0, sizeof(aim_module_t));
43
44 if (modfirst(sess, mod) == -1) {
45 free(mod);
46 return -1;
47 }
48
49 if (findmodule(sess, mod->name)) {
50 if (mod->shutdown)
51 mod->shutdown(sess, mod);
52 free(mod);
53 return -1;
54 }
55
56 mod->next = (aim_module_t *)sess->modlistv;
57 (aim_module_t *)sess->modlistv = mod;
58
59 faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family);
60
61 return 0;
62}
63
64faim_internal void aim__shutdownmodules(aim_session_t *sess)
65{
66 aim_module_t *cur;
67
68 for (cur = (aim_module_t *)sess->modlistv; cur; ) {
69 aim_module_t *tmp;
70
71 tmp = cur->next;
72
73 if (cur->shutdown)
74 cur->shutdown(sess, cur);
75
76 free(cur);
77
78 cur = tmp;
79 }
80
81 sess->modlistv = NULL;
82
83 return;
84}
85
86static int consumesnac(aim_session_t *sess, aim_frame_t *rx)
87{
88 aim_module_t *cur;
89 aim_modsnac_t snac;
90
91 if (aim_bstream_empty(&rx->data) < 10)
92 return 0;
93
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);
98
99 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
100
101 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
102 (cur->family != snac.family))
103 continue;
104
105 if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
106 return 1;
107
108 }
109
110 return 0;
111}
112
113static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, fu16_t family, fu16_t subtype)
114{
115 aim_module_t *cur;
116 aim_modsnac_t snac;
117
118 snac.family = family;
119 snac.subtype = subtype;
120 snac.flags = snac.id = 0;
121
122 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
123
124 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
125 (cur->family != snac.family))
126 continue;
127
128 if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
129 return 1;
130
131 }
132
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;
170}
171
172/*
173 * Bleck functions get called when there's no non-bleck functions
174 * around to cleanup the mess...
175 */
176faim_internal int bleck(aim_session_t *sess, aim_frame_t *frame, ...)
177{
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;
359}
360
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)
362{
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;
390}
391
392faim_export int aim_clearhandlers(aim_conn_t *conn)
393{
394 struct aim_rxcblist_s *cur;
395
396 if (!conn)
397 return -1;
398
399 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) {
400 struct aim_rxcblist_s *tmp;
401
402 tmp = cur->next;
403 free(cur);
404 cur = tmp;
405 }
406 conn->handlerlist = NULL;
407
408 return 0;
409}
410
411faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type)
412{
413 struct aim_rxcblist_s *cur;
414
415 if (!conn)
416 return NULL;
417
418 faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
419
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 }
424
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 }
429
430 faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type);
431
432 return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
433}
434
435faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src)
436{
437 struct aim_rxcblist_s *cur;
438
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);
442 }
443
444 return;
445}
446
447faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn,fu16_t family, fu16_t type, aim_frame_t *ptr)
448{
449 aim_rxcallback_t userfunc;
450
451 if ((userfunc = aim_callhandler(sess, conn, family, type)))
452 return userfunc(sess, ptr);
453
454 return 1; /* XXX */
455}
456
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 }
542
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);
550
551 return;
552}
553
554faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...)
555{
556 int i;
557
558 faimdprintf(sess, 1, "\nRecieved unknown packet:");
559
560 for (i = 0; aim_bstream_empty(&frame->data); i++) {
561 if ((i % 8) == 0)
562 faimdprintf(sess, 1, "\n\t");
563
564 faimdprintf(sess, 1, "0x%2x ", aimbs_get8(&frame->data));
565 }
566
567 faimdprintf(sess, 1, "\n\n");
568
569 return 1;
570}
571
572
573
This page took 4.346532 seconds and 5 git commands to generate.