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