source: libfaim/rxhandlers.c.orig @ 88cbd0a

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 88cbd0a was 5e53c4a, checked in by James M. Kretchmar <kretch@mit.edu>, 19 years ago
*** empty log message ***
  • Property mode set to 100644
File size: 13.7 KB
Line 
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
21faim_internal aim_module_t *aim__findmodulebygroup(aim_session_t *sess, fu16_t group)
22{
23        aim_module_t *cur;
24
25        for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
26                if (cur->family == group)
27                        return cur;
28        }
29
30        return NULL;
31}
32
33faim_internal aim_module_t *aim__findmodule(aim_session_t *sess, const char *name)
34{
35        aim_module_t *cur;
36
37        for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
38                if (strcmp(name, cur->name) == 0)
39                        return cur;
40        }
41
42        return NULL;
43}
44
45faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *))
46{
47        aim_module_t *mod;
48
49        if (!sess || !modfirst)
50                return -1;
51
52        if (!(mod = malloc(sizeof(aim_module_t))))
53                return -1;
54        memset(mod, 0, sizeof(aim_module_t));
55
56        if (modfirst(sess, mod) == -1) {
57                free(mod);
58                return -1;
59        }
60
61        if (aim__findmodule(sess, mod->name)) {
62                if (mod->shutdown)
63                        mod->shutdown(sess, mod);
64                free(mod);
65                return -1;
66        }
67
68        mod->next = (aim_module_t *)sess->modlistv;
69        (aim_module_t *)sess->modlistv = mod;
70
71        faimdprintf(sess, 1, "registered module %s (family 0x%04x, version = 0x%04x, tool 0x%04x, tool version 0x%04x)\n", mod->name, mod->family, mod->version, mod->toolid, mod->toolversion);
72
73        return 0;
74}
75
76faim_internal void aim__shutdownmodules(aim_session_t *sess)
77{
78        aim_module_t *cur;
79
80        for (cur = (aim_module_t *)sess->modlistv; cur; ) {
81                aim_module_t *tmp;
82
83                tmp = cur->next;
84
85                if (cur->shutdown)
86                        cur->shutdown(sess, cur);
87
88                free(cur);
89
90                cur = tmp;
91        }
92
93        sess->modlistv = NULL;
94
95        return;
96}
97
98static int consumesnac(aim_session_t *sess, aim_frame_t *rx)
99{
100        aim_module_t *cur;
101        aim_modsnac_t snac;
102
103        if (aim_bstream_empty(&rx->data) < 10)
104                return 0;
105
106        snac.family = aimbs_get16(&rx->data);
107        snac.subtype = aimbs_get16(&rx->data);
108        snac.flags = aimbs_get16(&rx->data);
109        snac.id = aimbs_get32(&rx->data);
110
111        for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
112
113                if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
114                                (cur->family != snac.family))
115                        continue;
116
117                if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
118                        return 1;
119
120        }
121
122        return 0;
123}
124
125static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, fu16_t family, fu16_t subtype)
126{
127        aim_module_t *cur;
128        aim_modsnac_t snac;
129
130        snac.family = family;
131        snac.subtype = subtype;
132        snac.flags = snac.id = 0;
133
134        for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
135
136                if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
137                                (cur->family != snac.family))
138                        continue;
139
140                if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
141                        return 1;
142
143        }
144
145        return 0;
146}
147
148static int negchan_middle(aim_session_t *sess, aim_frame_t *fr)
149{
150        aim_tlvlist_t *tlvlist;
151        char *msg = NULL;
152        fu16_t code = 0;
153        aim_rxcallback_t userfunc;
154        int ret = 1;
155
156        if (aim_bstream_empty(&fr->data) == 0) {
157                /* XXX should do something with this */
158                return 1;
159        }
160
161        /* Used only by the older login protocol */
162        /* XXX remove this special case? */
163        if (fr->conn->type == AIM_CONN_TYPE_AUTH)
164                return consumenonsnac(sess, fr, 0x0017, 0x0003);
165
166        tlvlist = aim_readtlvchain(&fr->data);
167
168        if (aim_gettlv(tlvlist, 0x0009, 1))
169                code = aim_gettlv16(tlvlist, 0x0009, 1);
170
171        if (aim_gettlv(tlvlist, 0x000b, 1))
172                msg = aim_gettlv_str(tlvlist, 0x000b, 1);
173
174        if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
175                ret = userfunc(sess, fr, code, msg);
176
177        aim_freetlvchain(&tlvlist);
178
179        free(msg);
180
181        return ret;
182}
183
184/*
185 * Bleck functions get called when there's no non-bleck functions
186 * around to cleanup the mess...
187 */
188faim_internal int bleck(aim_session_t *sess, aim_frame_t *frame, ...)
189{
190        fu16_t family, subtype;
191        fu16_t maxf, maxs;
192
193        static const char *channels[6] = {
194                "Invalid (0)",
195                "FLAP Version",
196                "SNAC",
197                "Invalid (3)",
198                "Negotiation",
199                "FLAP NOP"
200        };
201        static const int maxchannels = 5;
202       
203        /* XXX: this is ugly. and big just for debugging. */
204        static const char *literals[14][25] = {
205                {"Invalid",
206                 NULL
207                },
208                {"General",
209                 "Invalid",
210                 "Error",
211                 "Client Ready",
212                 "Server Ready",
213                 "Service Request",
214                 "Redirect",
215                 "Rate Information Request",
216                 "Rate Information",
217                 "Rate Information Ack",
218                 NULL,
219                 "Rate Information Change",
220                 "Server Pause",
221                 NULL,
222                 "Server Resume",
223                 "Request Personal User Information",
224                 "Personal User Information",
225                 "Evil Notification",
226                 NULL,
227                 "Migration notice",
228                 "Message of the Day",
229                 "Set Privacy Flags",
230                 "Well Known URL",
231                 "NOP"
232                },
233                {"Location",
234                 "Invalid",
235                 "Error",
236                 "Request Rights",
237                 "Rights Information",
238                 "Set user information",
239                 "Request User Information",
240                 "User Information",
241                 "Watcher Sub Request",
242                 "Watcher Notification"
243                },
244                {"Buddy List Management",
245                 "Invalid",
246                 "Error",
247                 "Request Rights",
248                 "Rights Information",
249                 "Add Buddy",
250                 "Remove Buddy",
251                 "Watcher List Query",
252                 "Watcher List Response",
253                 "Watcher SubRequest",
254                 "Watcher Notification",
255                 "Reject Notification",
256                 "Oncoming Buddy",
257                 "Offgoing Buddy"
258                },
259                {"Messeging",
260                 "Invalid",
261                 "Error",
262                 "Add ICBM Parameter",
263                 "Remove ICBM Parameter",
264                 "Request Parameter Information",
265                 "Parameter Information",
266                 "Outgoing Message",
267                 "Incoming Message",
268                 "Evil Request",
269                 "Evil Reply",
270                 "Missed Calls",
271                 "Message Error",
272                 "Host Ack"
273                },
274                {"Advertisements",
275                 "Invalid",
276                 "Error",
277                 "Request Ad",
278                 "Ad Data (GIFs)"
279                },
280                {"Invitation / Client-to-Client",
281                 "Invalid",
282                 "Error",
283                 "Invite a Friend",
284                 "Invitation Ack"
285                },
286                {"Administrative",
287                 "Invalid",
288                 "Error",
289                 "Information Request",
290                 "Information Reply",
291                 "Information Change Request",
292                 "Information Chat Reply",
293                 "Account Confirm Request",
294                 "Account Confirm Reply",
295                 "Account Delete Request",
296                 "Account Delete Reply"
297                },
298                {"Popups",
299                 "Invalid",
300                 "Error",
301                 "Display Popup"
302                },
303                {"BOS",
304                 "Invalid",
305                 "Error",
306                 "Request Rights",
307                 "Rights Response",
308                 "Set group permission mask",
309                 "Add permission list entries",
310                 "Delete permission list entries",
311                 "Add deny list entries",
312                 "Delete deny list entries",
313                 "Server Error"
314                },
315                {"User Lookup",
316                 "Invalid",
317                 "Error",
318                 "Search Request",
319                 "Search Response"
320                },
321                {"Stats",
322                 "Invalid",
323                 "Error",
324                 "Set minimum report interval",
325                 "Report Events"
326                },
327                {"Translate",
328                 "Invalid",
329                 "Error",
330                 "Translate Request",
331                 "Translate Reply",
332                },
333                {"Chat Navigation",
334                 "Invalid",
335                 "Error",
336                 "Request rights",
337                 "Request Exchange Information",
338                 "Request Room Information",
339                 "Request Occupant List",
340                 "Search for Room",
341                 "Outgoing Message",
342                 "Incoming Message",
343                 "Evil Request",
344                 "Evil Reply",
345                 "Chat Error",
346                }
347        };
348
349        maxf = sizeof(literals) / sizeof(literals[0]);
350        maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
351
352        if (frame->hdr.flap.type == 0x02) {
353
354                family = aimbs_get16(&frame->data);
355                subtype = aimbs_get16(&frame->data);
356               
357                if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
358                        faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->hdr.flap.type], family, subtype, literals[family][subtype+1]);
359                else
360                        faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->hdr.flap.type], family, subtype);
361        } else {
362
363                if (frame->hdr.flap.type <= maxchannels)
364                        faimdprintf(sess, 0, "bleck: channel %s (0x%02x)\n", channels[frame->hdr.flap.type], frame->hdr.flap.type);
365                else
366                        faimdprintf(sess, 0, "bleck: unknown channel 0x%02x\n", frame->hdr.flap.type);
367
368        }
369               
370        return 1;
371}
372
373/*
374 * Some SNACs we do not allow to be hooked, for good reason.
375 */
376static int checkdisallowed(fu16_t group, fu16_t type)
377{
378        static const struct {
379                fu16_t group;
380                fu16_t type;
381        } dontuse[] = {
382                {0x0001, 0x0002},
383                {0x0001, 0x0003},
384                {0x0001, 0x0006},
385                {0x0001, 0x0007},
386                {0x0001, 0x0008},
387                {0x0001, 0x0017},
388                {0x0001, 0x0018},
389                {0x0000, 0x0000}
390        };
391        int i;
392
393        for (i = 0; dontuse[i].group != 0x0000; i++) {
394                if ((dontuse[i].group == group) && (dontuse[i].type == type))
395                        return 1;
396        }
397
398        return 0;
399}
400
401faim_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)
402{
403        struct aim_rxcblist_s *newcb;
404
405        if (!conn)
406                return -1;
407
408        faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
409
410        if (checkdisallowed(family, type)) {
411                faimdprintf(sess, 0, "aim_conn_addhandler: client tried to hook %x/%x -- BUG!!!\n", family, type);
412                return -1;
413        }
414
415        if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s))))
416                return -1;
417
418        newcb->family = family;
419        newcb->type = type;
420        newcb->flags = flags;
421        newcb->handler = newhandler ? newhandler : bleck;
422        newcb->next = NULL;
423
424        if (!conn->handlerlist)
425                conn->handlerlist = (void *)newcb;
426        else {
427                struct aim_rxcblist_s *cur;
428
429                for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next)
430                        ;
431                cur->next = newcb;
432        }
433
434        return 0;
435}
436
437faim_export int aim_clearhandlers(aim_conn_t *conn)
438{
439        struct aim_rxcblist_s *cur;
440
441        if (!conn)
442                return -1;
443
444        for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) {
445                struct aim_rxcblist_s *tmp;
446
447                tmp = cur->next;
448                free(cur);
449                cur = tmp;
450        }
451        conn->handlerlist = NULL;
452
453        return 0;
454}
455
456faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type)
457{
458        struct aim_rxcblist_s *cur;
459
460        if (!conn)
461                return NULL;
462
463        faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
464
465        for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) {
466                if ((cur->family == family) && (cur->type == type))
467                        return cur->handler;
468        }
469
470        if (type == AIM_CB_SPECIAL_DEFAULT) {
471                faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family);
472                return NULL; /* prevent infinite recursion */
473        }
474
475        faimdprintf(sess, 1, "aim_callhandler: no handler for  0x%04x/0x%04x\n", family, type);
476
477        return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
478}
479
480faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src)
481{
482        struct aim_rxcblist_s *cur;
483
484        for (cur = (struct aim_rxcblist_s *)src->handlerlist; cur; cur = cur->next) {
485                aim_conn_addhandler(sess, dest, cur->family, cur->type,
486                                                cur->handler, cur->flags);
487        }
488
489        return;
490}
491
492faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn,fu16_t family, fu16_t type, aim_frame_t *ptr)
493{
494        aim_rxcallback_t userfunc;
495
496        if ((userfunc = aim_callhandler(sess, conn, family, type)))
497                return userfunc(sess, ptr);
498
499        return 1; /* XXX */
500}
501
502/*
503 * aim_rxdispatch()
504 *
505 * Basically, heres what this should do:
506 *   1) Determine correct packet handler for this packet
507 *   2) Mark the packet handled (so it can be dequeued in purge_queue())
508 *   3) Send the packet to the packet handler
509 *   4) Go to next packet in the queue and start over
510 *   5) When done, run purge_queue() to purge handled commands
511 *
512 * TODO: Clean up.
513 * TODO: More support for mid-level handlers.
514 * TODO: Allow for NULL handlers.
515 *
516 */
517faim_export void aim_rxdispatch(aim_session_t *sess)
518{
519        int i;
520        aim_frame_t *cur;
521
522        for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) {
523
524                /*
525                 * XXX: This is still fairly ugly.
526                 */
527
528                if (cur->handled)
529                        continue;
530
531                /*
532                 * This is a debugging/sanity check only and probably
533                 * could/should be removed for stable code.
534                 */
535                if (((cur->hdrtype == AIM_FRAMETYPE_OFT) &&
536                   (cur->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) ||
537                  ((cur->hdrtype == AIM_FRAMETYPE_FLAP) &&
538                   (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
539                        faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", cur->hdrtype, cur->conn->type);
540                        cur->handled = 1;
541                        continue;
542                }
543
544                if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
545                        if (cur->hdrtype != AIM_FRAMETYPE_OFT) {
546                                faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n");
547                                cur->handled = 1; /* get rid of it */
548                        } else {
549                                /* XXX: implement this */
550                                faimdprintf(sess, 0, "faim: OFT frame!\n");
551                                cur->handled = 1; /* get rid of it */
552                        }
553                        continue;
554                }
555
556                if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
557                        /* not possible */
558                        faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n");
559                        cur->handled = 1;
560                        continue;
561                }
562
563                if (cur->hdr.flap.type == 0x01) {
564                       
565                        cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
566                       
567                        continue;
568                       
569                } else if (cur->hdr.flap.type == 0x02) {
570
571                        if ((cur->handled = consumesnac(sess, cur)))
572                                continue;
573
574                } else if (cur->hdr.flap.type == 0x04) {
575
576                        cur->handled = negchan_middle(sess, cur);
577                        continue;
578
579                } else if (cur->hdr.flap.type == 0x05)
580                        ;
581               
582                if (!cur->handled) {
583                        consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */
584                        cur->handled = 1;
585                }
586        }
587
588        /*
589         * This doesn't have to be called here.  It could easily be done
590         * by a seperate thread or something. It's an administrative operation,
591         * and can take a while. Though the less you call it the less memory
592         * you'll have :)
593         */
594        aim_purge_rxqueue(sess);
595
596        return;
597}
598
599faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...)
600{
601        int i;
602
603        faimdprintf(sess, 1, "\nRecieved unknown packet:");
604
605        for (i = 0; aim_bstream_empty(&frame->data); i++) {
606                if ((i % 8) == 0)
607                        faimdprintf(sess, 1, "\n\t");
608
609                faimdprintf(sess, 1, "0x%2x ", aimbs_get8(&frame->data));
610        }
611
612        faimdprintf(sess, 1, "\n\n");
613
614        return 1;
615}
616
617
618
Note: See TracBrowser for help on using the repository browser.