]> andersk Git - libfaim.git/blob - src/rxhandlers.c
- Sun Oct 14 19:45:54 PDT 2001
[libfaim.git] / src / rxhandlers.c
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
13 struct 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
21 static 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
33 faim_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
64 faim_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
86 static 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
113 static 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
136 static 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  */
176 faim_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
361 faim_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
392 faim_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
411 faim_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
435 faim_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
447 faim_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  */
472 faim_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
554 faim_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 0.106886 seconds and 5 git commands to generate.