source: libfaim/rxhandlers.c @ 8c46404

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 8c46404 was e374dee, checked in by James M. Kretchmar <kretch@mit.edu>, 20 years ago
*** empty log message ***
  • Property mode set to 100644
File size: 13.2 KB
Line 
1/*
2 * 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        fu16_t 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        /* SNAC flags are apparently uniform across all SNACs, so we handle them here */
112        if (snac.flags & 0x0001) {
113                /*
114                 * This means the SNAC will be followed by another SNAC with
115                 * related information.  We don't need to do anything about
116                 * this here.
117                 */
118        }
119        if (snac.flags & 0x8000) {
120                /*
121                 * This packet contains the version of the family that this SNAC is
122                 * in.  You get this when your SSI module is version 2 or higher. 
123                 * For now we have no need for this, but you could always save
124                 * it as a part of aim_modnsac_t, or something.  The format is...
125                 * 2 byte length of total mini-header (which is 6 bytes), then TLV
126                 * of  type 0x0001, length 0x0002, value is the 2 byte version
127                 * number
128                 */
129                aim_bstream_advance(&rx->data, aimbs_get16(&rx->data));
130        }
131
132        for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
133
134                if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && 
135                                (cur->family != snac.family))
136                        continue;
137
138                if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
139                        return 1;
140
141        }
142
143        return 0;
144}
145
146static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, fu16_t family, fu16_t subtype)
147{
148        aim_module_t *cur;
149        aim_modsnac_t snac;
150
151        snac.family = family;
152        snac.subtype = subtype;
153        snac.flags = snac.id = 0;
154
155        for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
156
157                if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && 
158                                (cur->family != snac.family))
159                        continue;
160
161                if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
162                        return 1;
163
164        }
165
166        return 0;
167}
168
169static int negchan_middle(aim_session_t *sess, aim_frame_t *fr)
170{
171        aim_tlvlist_t *tlvlist;
172        char *msg = NULL;
173        fu16_t code = 0;
174        aim_rxcallback_t userfunc;
175        int ret = 1;
176
177        if (aim_bstream_empty(&fr->data) == 0) {
178                /* XXX should do something with this */
179                return 1;
180        }
181
182        /* Used only by the older login protocol */
183        /* XXX remove this special case? */
184        if (fr->conn->type == AIM_CONN_TYPE_AUTH)
185                return consumenonsnac(sess, fr, 0x0017, 0x0003);
186
187        tlvlist = aim_readtlvchain(&fr->data);
188
189        if (aim_gettlv(tlvlist, 0x0009, 1))
190                code = aim_gettlv16(tlvlist, 0x0009, 1);
191
192        if (aim_gettlv(tlvlist, 0x000b, 1))
193                msg = aim_gettlv_str(tlvlist, 0x000b, 1);
194
195        if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) 
196                ret = userfunc(sess, fr, code, msg);
197
198        aim_freetlvchain(&tlvlist);
199
200        free(msg);
201
202        return ret;
203}
204
205/*
206 * Bleck functions get called when there's no non-bleck functions
207 * around to cleanup the mess...
208 */
209faim_internal int bleck(aim_session_t *sess, aim_frame_t *frame, ...)
210{
211        fu16_t family, subtype;
212        fu16_t maxf, maxs;
213
214        static const char *channels[6] = {
215                "Invalid (0)",
216                "FLAP Version",
217                "SNAC",
218                "Invalid (3)",
219                "Negotiation",
220                "FLAP NOP"
221        };
222        static const int maxchannels = 5;
223       
224        /* XXX: this is ugly. and big just for debugging. */
225        static const char *literals[14][25] = {
226                {"Invalid", 
227                 NULL
228                },
229                {"General", 
230                 "Invalid",
231                 "Error",
232                 "Client Ready",
233                 "Server Ready",
234                 "Service Request",
235                 "Redirect",
236                 "Rate Information Request",
237                 "Rate Information",
238                 "Rate Information Ack",
239                 NULL,
240                 "Rate Information Change",
241                 "Server Pause",
242                 NULL,
243                 "Server Resume",
244                 "Request Personal User Information",
245                 "Personal User Information",
246                 "Evil Notification",
247                 NULL,
248                 "Migration notice",
249                 "Message of the Day",
250                 "Set Privacy Flags",
251                 "Well Known URL",
252                 "NOP"
253                },
254                {"Location", 
255                 "Invalid",
256                 "Error",
257                 "Request Rights",
258                 "Rights Information", 
259                 "Set user information", 
260                 "Request User Information", 
261                 "User Information", 
262                 "Watcher Sub Request",
263                 "Watcher Notification"
264                },
265                {"Buddy List Management", 
266                 "Invalid", 
267                 "Error", 
268                 "Request Rights",
269                 "Rights Information",
270                 "Add Buddy", 
271                 "Remove Buddy", 
272                 "Watcher List Query", 
273                 "Watcher List Response", 
274                 "Watcher SubRequest", 
275                 "Watcher Notification", 
276                 "Reject Notification", 
277                 "Oncoming Buddy", 
278                 "Offgoing Buddy"
279                },
280                {"Messeging", 
281                 "Invalid",
282                 "Error", 
283                 "Add ICBM Parameter",
284                 "Remove ICBM Parameter", 
285                 "Request Parameter Information",
286                 "Parameter Information",
287                 "Outgoing Message", 
288                 "Incoming Message",
289                 "Evil Request",
290                 "Evil Reply", 
291                 "Missed Calls",
292                 "Message Error", 
293                 "Host Ack"
294                },
295                {"Advertisements", 
296                 "Invalid", 
297                 "Error", 
298                 "Request Ad",
299                 "Ad Data (GIFs)"
300                },
301                {"Invitation / Client-to-Client", 
302                 "Invalid",
303                 "Error",
304                 "Invite a Friend",
305                 "Invitation Ack"
306                },
307                {"Administrative", 
308                 "Invalid",
309                 "Error",
310                 "Information Request",
311                 "Information Reply",
312                 "Information Change Request",
313                 "Information Chat Reply",
314                 "Account Confirm Request",
315                 "Account Confirm Reply",
316                 "Account Delete Request",
317                 "Account Delete Reply"
318                },
319                {"Popups", 
320                 "Invalid",
321                 "Error",
322                 "Display Popup"
323                },
324                {"BOS", 
325                 "Invalid",
326                 "Error",
327                 "Request Rights",
328                 "Rights Response",
329                 "Set group permission mask",
330                 "Add permission list entries",
331                 "Delete permission list entries",
332                 "Add deny list entries",
333                 "Delete deny list entries",
334                 "Server Error"
335                },
336                {"User Lookup", 
337                 "Invalid",
338                 "Error",
339                 "Search Request",
340                 "Search Response"
341                },
342                {"Stats", 
343                 "Invalid",
344                 "Error",
345                 "Set minimum report interval",
346                 "Report Events"
347                },
348                {"Translate", 
349                 "Invalid",
350                 "Error",
351                 "Translate Request",
352                 "Translate Reply",
353                },
354                {"Chat Navigation", 
355                 "Invalid",
356                 "Error",
357                 "Request rights",
358                 "Request Exchange Information",
359                 "Request Room Information",
360                 "Request Occupant List",
361                 "Search for Room",
362                 "Outgoing Message", 
363                 "Incoming Message",
364                 "Evil Request", 
365                 "Evil Reply", 
366                 "Chat Error",
367                }
368        };
369
370        maxf = sizeof(literals) / sizeof(literals[0]);
371        maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
372
373        if (frame->hdr.flap.type == 0x02) {
374
375                family = aimbs_get16(&frame->data);
376                subtype = aimbs_get16(&frame->data);
377               
378                if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
379                        faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->hdr.flap.type], family, subtype, literals[family][subtype+1]);
380                else
381                        faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->hdr.flap.type], family, subtype);
382        } else {
383
384                if (frame->hdr.flap.type <= maxchannels)
385                        faimdprintf(sess, 0, "bleck: channel %s (0x%02x)\n", channels[frame->hdr.flap.type], frame->hdr.flap.type);
386                else
387                        faimdprintf(sess, 0, "bleck: unknown channel 0x%02x\n", frame->hdr.flap.type);
388
389        }
390               
391        return 1;
392}
393
394faim_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)
395{
396        struct aim_rxcblist_s *newcb;
397
398        if (!conn)
399                return -1;
400
401        faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
402
403        if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s))))
404                return -1;
405
406        newcb->family = family;
407        newcb->type = type;
408        newcb->flags = flags;
409        newcb->handler = newhandler ? newhandler : bleck;
410        newcb->next = NULL;
411
412        if (!conn->handlerlist)
413                conn->handlerlist = (void *)newcb;
414        else {
415                struct aim_rxcblist_s *cur;
416
417                for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next)
418                        ;
419                cur->next = newcb;
420        }
421
422        return 0;
423}
424
425faim_export int aim_clearhandlers(aim_conn_t *conn)
426{
427        struct aim_rxcblist_s *cur;
428
429        if (!conn)
430                return -1;
431
432        for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) {
433                struct aim_rxcblist_s *tmp;
434
435                tmp = cur->next;
436                free(cur);
437                cur = tmp;
438        }
439        conn->handlerlist = NULL;
440
441        return 0;
442}
443
444faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type)
445{
446        struct aim_rxcblist_s *cur;
447
448        if (!conn)
449                return NULL;
450
451        faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
452
453        for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) {
454                if ((cur->family == family) && (cur->type == type))
455                        return cur->handler;
456        }
457
458        if (type == AIM_CB_SPECIAL_DEFAULT) {
459                faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family);
460                return NULL; /* prevent infinite recursion */
461        }
462
463        faimdprintf(sess, 1, "aim_callhandler: no handler for  0x%04x/0x%04x\n", family, type);
464
465        return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
466}
467
468faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src)
469{
470        struct aim_rxcblist_s *cur;
471
472        for (cur = (struct aim_rxcblist_s *)src->handlerlist; cur; cur = cur->next) {
473                aim_conn_addhandler(sess, dest, cur->family, cur->type, 
474                                                cur->handler, cur->flags);
475        }
476
477        return;
478}
479
480faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn,fu16_t family, fu16_t type, aim_frame_t *ptr)
481{
482        aim_rxcallback_t userfunc;
483
484        if ((userfunc = aim_callhandler(sess, conn, family, type)))
485                return userfunc(sess, ptr);
486
487        return 1; /* XXX */
488}
489
490/*
491 * aim_rxdispatch()
492 *
493 * Basically, heres what this should do:
494 *   1) Determine correct packet handler for this packet
495 *   2) Mark the packet handled (so it can be dequeued in purge_queue())
496 *   3) Send the packet to the packet handler
497 *   4) Go to next packet in the queue and start over
498 *   5) When done, run purge_queue() to purge handled commands
499 *
500 * TODO: Clean up.
501 * TODO: More support for mid-level handlers.
502 * TODO: Allow for NULL handlers.
503 *
504 */
505faim_export void aim_rxdispatch(aim_session_t *sess)
506{
507        int i;
508        aim_frame_t *cur;
509
510        for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) {
511
512                /*
513                 * XXX: This is still fairly ugly.
514                 */
515
516                if (cur->handled)
517                        continue;
518
519                if (cur->hdrtype == AIM_FRAMETYPE_FLAP) {
520                        if (cur->hdr.flap.type == 0x01) {
521                                cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
522                                continue;
523
524                        } else if (cur->hdr.flap.type == 0x02) {
525                                if ((cur->handled = consumesnac(sess, cur)))
526                                        continue;
527
528                        } else if (cur->hdr.flap.type == 0x04) {
529                                cur->handled = negchan_middle(sess, cur);
530                                continue;
531
532                        } else if (cur->hdr.flap.type == 0x05) {
533
534                        }
535
536                } else if (cur->hdrtype == AIM_FRAMETYPE_OFT) {
537                        if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
538                                aim_rxdispatch_rendezvous(sess, cur);
539                                cur->handled = 1;
540                                continue;
541
542                        } else if (cur->conn->type == AIM_CONN_TYPE_LISTENER) {
543                                /* not possible */
544                                faimdprintf(sess, 0, "rxdispatch called on LISTENER connection!\n");
545                                cur->handled = 1;
546                                continue;
547                        }
548                }
549
550                if (!cur->handled) {
551                        consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */
552                        cur->handled = 1;
553                }
554        }
555
556        /*
557         * This doesn't have to be called here.  It could easily be done
558         * by a seperate thread or something. It's an administrative operation,
559         * and can take a while. Though the less you call it the less memory
560         * you'll have :)
561         */
562        aim_purge_rxqueue(sess);
563
564        return;
565}
566
567faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...)
568{
569        int i;
570
571        faimdprintf(sess, 1, "\nRecieved unknown packet:");
572
573        for (i = 0; aim_bstream_empty(&frame->data); i++) {
574                if ((i % 8) == 0)
575                        faimdprintf(sess, 1, "\n\t");
576
577                faimdprintf(sess, 1, "0x%2x ", aimbs_get8(&frame->data));
578        }
579
580        faimdprintf(sess, 1, "\n\n");
581
582        return 1;
583}
Note: See TracBrowser for help on using the repository browser.