source: libfaim/rxhandlers.c @ dab82f29

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