]> andersk Git - libfaim.git/blob - aim_rxhandlers.c
8e5551429236fe7159b3627ee025983b705e1816
[libfaim.git] / aim_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 <faim/aim.h>
12
13 /*
14  * Bleck functions get called when there's no non-bleck functions
15  * around to cleanup the mess...
16  */
17 faim_internal int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
18 {
19   u_short family;
20   u_short subtype;
21
22   u_short maxf;
23   u_short maxs;
24
25   /* XXX: this is ugly. and big just for debugging. */
26   char *literals[14][25] = {
27     {"Invalid", 
28      NULL
29     },
30     {"General", 
31      "Invalid",
32      "Error",
33      "Client Ready",
34      "Server Ready",
35      "Service Request",
36      "Redirect",
37      "Rate Information Request",
38      "Rate Information",
39      "Rate Information Ack",
40      NULL,
41      "Rate Information Change",
42      "Server Pause",
43      NULL,
44      "Server Resume",
45      "Request Personal User Information",
46      "Personal User Information",
47      "Evil Notification",
48      NULL,
49      "Migration notice",
50      "Message of the Day",
51      "Set Privacy Flags",
52      "Well Known URL",
53      "NOP"
54     },
55     {"Location", 
56       "Invalid",
57       "Error",
58       "Request Rights",
59       "Rights Information", 
60       "Set user information", 
61       "Request User Information", 
62       "User Information", 
63       "Watcher Sub Request",
64       "Watcher Notification"
65     },
66     {"Buddy List Management", 
67       "Invalid", 
68       "Error", 
69       "Request Rights",
70       "Rights Information",
71       "Add Buddy", 
72       "Remove Buddy", 
73       "Watcher List Query", 
74       "Watcher List Response", 
75       "Watcher SubRequest", 
76       "Watcher Notification", 
77       "Reject Notification", 
78       "Oncoming Buddy", 
79       "Offgoing Buddy"
80     },
81     {"Messeging", 
82       "Invalid",
83       "Error", 
84       "Add ICBM Parameter",
85       "Remove ICBM Parameter", 
86       "Request Parameter Information",
87       "Parameter Information",
88       "Outgoing Message", 
89       "Incoming Message",
90       "Evil Request",
91       "Evil Reply", 
92       "Missed Calls",
93       "Message Error", 
94       "Host Ack"
95     },
96     {"Advertisements", 
97       "Invalid", 
98       "Error", 
99       "Request Ad",
100       "Ad Data (GIFs)"
101     },
102     {"Invitation / Client-to-Client", 
103      "Invalid",
104      "Error",
105      "Invite a Friend",
106      "Invitation Ack"
107     },
108     {"Administrative", 
109       "Invalid",
110       "Error",
111       "Information Request",
112       "Information Reply",
113       "Information Change Request",
114       "Information Chat Reply",
115       "Account Confirm Request",
116       "Account Confirm Reply",
117       "Account Delete Request",
118       "Account Delete Reply"
119     },
120     {"Popups", 
121       "Invalid",
122       "Error",
123       "Display Popup"
124     },
125     {"BOS", 
126       "Invalid",
127       "Error",
128       "Request Rights",
129       "Rights Response",
130       "Set group permission mask",
131       "Add permission list entries",
132       "Delete permission list entries",
133       "Add deny list entries",
134       "Delete deny list entries",
135       "Server Error"
136     },
137     {"User Lookup", 
138       "Invalid",
139       "Error",
140       "Search Request",
141       "Search Response"
142     },
143     {"Stats", 
144       "Invalid",
145       "Error",
146       "Set minimum report interval",
147       "Report Events"
148     },
149     {"Translate", 
150       "Invalid",
151       "Error",
152       "Translate Request",
153       "Translate Reply",
154     },
155     {"Chat Navigation", 
156       "Invalid",
157       "Error",
158       "Request rights",
159       "Request Exchange Information",
160       "Request Room Information",
161       "Request Occupant List",
162       "Search for Room",
163       "Outgoing Message", 
164       "Incoming Message",
165       "Evil Request", 
166       "Evil Reply", 
167       "Chat Error",
168     }
169   };
170
171   maxf = sizeof(literals) / sizeof(literals[0]);
172   maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
173
174   family = aimutil_get16(workingPtr->data+0);
175   subtype= aimutil_get16(workingPtr->data+2);
176
177   if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
178     printf("bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
179   else
180     printf("bleck: null handler for %04x/%04x (no literal)\n",family,subtype);
181
182   return 1;
183 }
184
185 faim_export int aim_conn_addhandler(struct aim_session_t *sess,
186                         struct aim_conn_t *conn,
187                         u_short family,
188                         u_short type,
189                         rxcallback_t newhandler,
190                         u_short flags)
191 {
192   struct aim_rxcblist_t *newcb;
193
194   if (!conn)
195     return -1;
196
197   faimdprintf(1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
198
199   if (!(newcb = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t))))
200     return -1;
201   newcb->family = family;
202   newcb->type = type;
203   newcb->flags = flags;
204   if (!newhandler)
205     newcb->handler = &bleck;
206   else
207     newcb->handler = newhandler;
208   newcb->next = NULL;
209   
210   if (!conn->handlerlist)
211     conn->handlerlist = newcb;
212   else {
213     struct aim_rxcblist_t *cur;
214
215     cur = conn->handlerlist;
216
217     while (cur->next)
218       cur = cur->next;
219     cur->next = newcb;
220   }
221
222   return 0;
223 }
224
225 faim_export int aim_clearhandlers(struct aim_conn_t *conn)
226 {
227  struct aim_rxcblist_t *cur;
228
229  if (!conn)
230    return -1;
231
232  for (cur = conn->handlerlist; cur; ) {
233    struct aim_rxcblist_t *tmp;
234
235    tmp = cur->next;
236    free(cur);
237    cur = tmp;
238  }
239  conn->handlerlist = NULL;
240
241  return 0;
242 }
243
244 faim_internal rxcallback_t aim_callhandler(struct aim_conn_t *conn,
245                                          u_short family,
246                                          u_short type)
247 {
248   struct aim_rxcblist_t *cur;
249
250   if (!conn)
251     return NULL;
252
253   faimdprintf(1, "aim_callhandler: calling for %04x/%04x\n", family, type);
254   
255   cur = conn->handlerlist;
256   while(cur)
257     {
258       if ( (cur->family == family) && (cur->type == type) )
259         return cur->handler;
260       cur = cur->next;
261     }
262
263   if (type==0xffff)
264     return NULL;
265
266   return aim_callhandler(conn, family, 0xffff);
267 }
268
269 faim_internal int aim_callhandler_noparam(struct aim_session_t *sess,
270                                           struct aim_conn_t *conn,
271                                           u_short family,
272                                           u_short type,
273                                           struct command_rx_struct *ptr)
274 {
275   rxcallback_t userfunc = NULL;
276   userfunc = aim_callhandler(conn, family, type);
277   if (userfunc)
278     return userfunc(sess, ptr);
279   return 1; /* XXX */
280 }
281
282 /*
283   aim_rxdispatch()
284
285   Basically, heres what this should do:
286     1) Determine correct packet handler for this packet
287     2) Mark the packet handled (so it can be dequeued in purge_queue())
288     3) Send the packet to the packet handler
289     4) Go to next packet in the queue and start over
290     5) When done, run purge_queue() to purge handled commands
291
292   Note that any unhandlable packets should probably be left in the
293   queue.  This is the best way to prevent data loss.  This means
294   that a single packet may get looked at by this function multiple
295   times.  This is more good than bad!  This behavior may change.
296
297   Aren't queue's fun? 
298
299   TODO: Get rid of all the ugly if's.
300   TODO: Clean up.
301   TODO: More support for mid-level handlers.
302   TODO: Allow for NULL handlers.
303   
304  */
305 faim_export int aim_rxdispatch(struct aim_session_t *sess)
306 {
307   int i = 0;
308   struct command_rx_struct *workingPtr = NULL;
309   
310   if (sess->queue_incoming == NULL) {
311     faimdprintf(1, "parse_generic: incoming packet queue empty.\n");
312     return 0;
313   } else {
314     workingPtr = sess->queue_incoming;
315     for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
316       /*
317        * XXX: This is still fairly ugly.
318        */
319       if (workingPtr->handled)
320         continue;
321
322       /*
323        * This is a debugging/sanity check only and probably could/should be removed
324        * for stable code.
325        */
326       if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) && 
327            (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || 
328           ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) && 
329            (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
330         printf("faim: rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
331         workingPtr->handled = 1;
332         continue;
333       }
334
335       switch(workingPtr->conn->type) {
336       case -1:
337         /*
338          * This can happen if we have a queued command
339          * that was recieved after a connection has 
340          * been terminated.  In which case, the handler
341          * list has been cleared, and there's nothing we
342          * can do for it.  We can only cancel it.
343          */
344         workingPtr->handled = 1;
345         break;
346       case AIM_CONN_TYPE_AUTH: {
347         unsigned long head;
348         
349         head = aimutil_get32(workingPtr->data);
350         if ((head == 0x00000001) && (workingPtr->commandlen == 4)) {
351           faimdprintf(1, "got connection ack on auth line\n");
352           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
353         } else if (workingPtr->hdr.oscar.type == 0x04) {
354           /* Used only by the older login protocol */
355           workingPtr->handled = aim_authparse(sess, workingPtr);
356         } else {
357           unsigned short family,subtype;
358           
359           family = aimutil_get16(workingPtr->data);
360           subtype = aimutil_get16(workingPtr->data+2);
361           
362           switch (family) {
363             /* New login protocol */
364           case 0x0017:
365             if (subtype == 0x0001)
366               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
367             else if (subtype == 0x0003)
368               workingPtr->handled = aim_authparse(sess, workingPtr);
369             else if (subtype == 0x0007)
370               workingPtr->handled = aim_authkeyparse(sess, workingPtr);
371             else
372               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
373             break;
374           case 0x0001:
375             if (subtype == 0x0003)
376               workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
377             else
378               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
379             break;
380           case 0x0007:
381             if (subtype == 0x0005)
382               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
383             break;
384           case AIM_CB_FAM_SPECIAL:
385             if (subtype == AIM_CB_SPECIAL_DEBUGCONN_CONNECT) {
386               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
387               break;
388             } else
389               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
390             break;
391           default:
392             break;
393           }
394         }
395         break;
396       }
397       case AIM_CONN_TYPE_BOS: {
398         u_short family;
399         u_short subtype;
400
401         if (workingPtr->hdr.oscar.type == 0x04) {
402           workingPtr->handled = aim_negchan_middle(sess, workingPtr);
403           break;
404         }
405
406         family = aimutil_get16(workingPtr->data);
407         subtype = aimutil_get16(workingPtr->data+2);
408         
409         switch (family) {
410         case 0x0000: /* not really a family, but it works */
411           if (subtype == 0x0001)
412             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
413           else
414             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
415           break;
416         case 0x0001: /* Family: General */
417           switch (subtype) {
418           case 0x0001:
419             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
420             break;
421           case 0x0003:
422             workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
423             break;
424           case 0x0005:
425             workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
426             break;
427           case 0x0007:
428             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
429             break;
430           case 0x000a:
431             workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
432             break;
433           case 0x000f:
434             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
435             break;
436           case 0x0010:
437             workingPtr->handled = aim_parse_evilnotify_middle(sess, workingPtr);
438             break;
439           case 0x0013:
440             workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
441             break;
442           case 0x0018:
443             workingPtr->handled = aim_parse_hostversions(sess, workingPtr);
444             break;
445           default:
446             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
447             break;
448           }
449           break;
450         case 0x0002: /* Family: Location */
451           switch (subtype) {
452           case 0x0001:
453             workingPtr->handled = aim_parse_locateerr(sess, workingPtr);
454             break;
455           case 0x0003:
456             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
457             break;
458           case 0x0006:
459             workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
460             break;
461           default:
462             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
463             break;
464           }
465           break;
466         case 0x0003: /* Family: Buddy List */
467           switch (subtype) {
468           case 0x0001:
469             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
470             break;
471           case 0x0003:
472             workingPtr->handled = aim_parse_buddyrights(sess, workingPtr);
473             break;
474           case 0x000b: /* oncoming buddy */
475             workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
476             break;
477           case 0x000c: /* offgoing buddy */
478             workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
479             break;
480           default:
481             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
482           }
483           break;
484         case 0x0004: /* Family: Messaging */
485           switch (subtype) {
486           case 0x0001:
487             workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
488             break;
489           case 0x0005:
490             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
491             break;
492           case 0x0006:
493             workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr);
494             break;
495           case 0x0007:
496             workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
497             break;
498           case 0x000a:
499             workingPtr->handled = aim_parse_missedcall(sess, workingPtr);
500             break;
501           case 0x000c:
502             workingPtr->handled = aim_parse_msgack_middle(sess, workingPtr);
503             break;
504           default:
505             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
506           }
507           break;
508         case 0x0009:
509           if (subtype == 0x0001)
510             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
511           else if (subtype == 0x0003)
512             workingPtr->handled = aim_parse_bosrights(sess, workingPtr);
513           else
514             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
515           break;
516         case 0x000a:  /* Family: User lookup */
517           switch (subtype) {
518           case 0x0001:
519             workingPtr->handled = aim_parse_searcherror(sess, workingPtr);
520             break;
521           case 0x0003:
522             workingPtr->handled = aim_parse_searchreply(sess, workingPtr);
523             break;
524           default:
525             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
526           }
527           break;
528         case 0x000b: {
529           if (subtype == 0x0001)
530             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
531           else if (subtype == 0x0002)
532             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
533           else
534             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
535           break;
536         }
537         case 0x0013: {
538           printf("lalala: 0x%04x/0x%04x\n", family, subtype);
539           break;
540         }
541         case AIM_CB_FAM_SPECIAL: 
542           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
543           break;
544         default:
545           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
546           break;
547         } /* switch(family) */
548         break;
549       } /* AIM_CONN_TYPE_BOS */
550       case AIM_CONN_TYPE_CHATNAV: {
551         u_short family;
552         u_short subtype;
553         family = aimutil_get16(workingPtr->data);
554         subtype= aimutil_get16(workingPtr->data+2);
555
556         if ((family == 0x0000) && (subtype == 0x00001)) {
557           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
558         } else if ((family == 0x0001) && (subtype == 0x0003)) {
559           workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
560         } else if ((family == 0x000d) && (subtype == 0x0009)) {
561           workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
562         } else {
563           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
564         }
565         break;
566       }
567       case AIM_CONN_TYPE_CHAT: {
568         u_short family, subtype;
569         
570         family = aimutil_get16(workingPtr->data);
571         subtype= aimutil_get16(workingPtr->data+2);
572         
573         if ((family == 0x0000) && (subtype == 0x00001)) {
574           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
575         } else if (family == 0x0001) {
576           if (subtype == 0x0001)
577             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
578           else if (subtype == 0x0003)
579             workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
580           else if (subtype == 0x0007)
581             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
582           else if (subtype == 0x000a)
583             workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
584           else
585             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
586         } else if (family == 0x000e) {
587           if (subtype == 0x0002)
588             workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
589           else if (subtype == 0x0003)
590             workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);      
591           else if (subtype == 0x0004)
592             workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);       
593           else if (subtype == 0x0006)
594             workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
595           else  
596             printf("Chat: unknown snac %04x/%04x\n", family, subtype); 
597         } else {
598           printf("Chat: unknown snac %04x/%04x\n", family, subtype);
599           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
600         }
601         break;
602       }
603       case AIM_CONN_TYPE_RENDEZVOUS: {
604         /* make sure that we only get OFT frames on these connections */
605         if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
606           printf("faim: internal error: non-OFT frames on OFT connection\n");
607           workingPtr->handled = 1; /* get rid of it */
608           break;
609         }
610         
611         /* XXX: implement this */
612         printf("faim: OFT frame!\n");
613         
614         break;
615       }
616       case AIM_CONN_TYPE_RENDEZVOUS_OUT: {
617         /* not possible */
618         break;
619       }
620       default:
621         printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->commandlen);
622         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
623         break;
624       } 
625     }
626   }
627
628   /* 
629    * This doesn't have to be called here.  It could easily be done
630    * by a seperate thread or something. It's an administrative operation,
631    * and can take a while. Though the less you call it the less memory
632    * you'll have :)
633    */
634   aim_purge_rxqueue(sess);
635   
636   return 0;
637 }
638
639 faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command)
640 {
641   rxcallback_t userfunc = NULL;
642   char sn[MAXSNLEN];
643   unsigned short type;
644   int i = 10+8; /* skip SNAC and cookie */
645   int ret = 1;
646   unsigned char snlen;
647
648   type = aimutil_get16(command->data+i);
649   i += 2;
650
651   snlen = aimutil_get8(command->data+i);
652   i++;
653
654   memset(sn, 0, sizeof(sn));
655   strncpy(sn, (char *)command->data+i, snlen);
656
657   if ((userfunc = aim_callhandler(command->conn, 0x0004, 0x000c)))
658     ret =  userfunc(sess, command, type, sn);
659
660   return ret;
661 }
662
663 /*
664  * The Rate Limiting System, An Abridged Guide to Nonsense.
665  *
666  * OSCAR defines several 'rate classes'.  Each class has seperate
667  * rate limiting properties (limit level, alert level, disconnect
668  * level, etc), and a set of SNAC family/type pairs associated with
669  * it.  The rate classes, their limiting properties, and the definitions
670  * of which SNACs are belong to which class, are defined in the
671  * Rate Response packet at login to each host.  
672  *
673  * Logically, all rate offenses within one class count against further
674  * offenses for other SNACs in the same class (ie, sending messages
675  * too fast will limit the number of user info requests you can send,
676  * since those two SNACs are in the same rate class).
677  *
678  * Since the rate classes are defined dynamically at login, the values
679  * below may change. But they seem to be fairly constant.
680  *
681  * Currently, BOS defines five rate classes, with the commonly used
682  * members as follows...
683  *
684  *  Rate class 0x0001:
685  *      - Everything thats not in any of the other classes
686  *
687  *  Rate class 0x0002:
688  *      - Buddy list add/remove
689  *      - Permit list add/remove
690  *      - Deny list add/remove
691  *
692  *  Rate class 0x0003:
693  *      - User information requests
694  *      - Outgoing ICBMs
695  *
696  *  Rate class 0x0004:
697  *      - A few unknowns: 2/9, 2/b, and f/2
698  *
699  *  Rate class 0x0005:
700  *      - Chat room create
701  *      - Outgoing chat ICBMs
702  *
703  * The only other thing of note is that class 5 (chat) has slightly looser
704  * limiting properties than class 3 (normal messages).  But thats just a 
705  * small bit of trivia for you.
706  *
707  * The last thing that needs to be learned about the rate limiting
708  * system is how the actual numbers relate to the passing of time.  This
709  * seems to be a big mystery.
710  * 
711  */
712 faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
713 {
714   rxcallback_t userfunc = NULL;
715   int ret = 1;
716   int i;
717   int code;
718   unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
719   unsigned long currentavg, maxavg;
720
721   i = 10;
722
723   code = aimutil_get16(command->data+i);
724   i += 2;
725
726   rateclass = aimutil_get16(command->data+i);
727   i += 2;
728
729   windowsize = aimutil_get32(command->data+i);
730   i += 4;
731   clear = aimutil_get32(command->data+i);
732   i += 4;
733   alert = aimutil_get32(command->data+i);
734   i += 4;
735   limit = aimutil_get32(command->data+i);
736   i += 4;
737   disconnect = aimutil_get32(command->data+i);
738   i += 4;
739   currentavg = aimutil_get32(command->data+i);
740   i += 4;
741   maxavg = aimutil_get32(command->data+i);
742   i += 4;
743
744   if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x000a)))
745     ret =  userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
746
747   return ret;
748 }
749
750 faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command)
751 {
752   rxcallback_t userfunc = NULL;
753   int ret = 1;
754   int i;
755   unsigned short newevil;
756   struct aim_userinfo_s userinfo;
757
758   i = 10;
759   newevil = aimutil_get16(command->data+10);
760   i += 2;
761
762   memset(&userinfo, 0, sizeof(struct aim_userinfo_s));
763   if (command->commandlen-i)
764     i += aim_extractuserinfo(command->data+i, &userinfo);
765
766   if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0010)))
767     ret = userfunc(sess, command, newevil, &userinfo);
768   
769   return ret;
770 }
771
772 faim_internal int aim_parsemotd_middle(struct aim_session_t *sess,
773                                        struct command_rx_struct *command, ...)
774 {
775   rxcallback_t userfunc = NULL;
776   char *msg;
777   int ret=1;
778   struct aim_tlvlist_t *tlvlist;
779   u_short id;
780
781   /*
782    * Code.
783    *
784    * Valid values:
785    *   1 Mandatory upgrade
786    *   2 Advisory upgrade
787    *   3 System bulletin
788    *   4 Nothing's wrong ("top o the world" -- normal)
789    *
790    */
791   id = aimutil_get16(command->data+10);
792
793   /* 
794    * TLVs follow 
795    */
796   if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12)))
797     return ret;
798
799   if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) {
800     aim_freetlvchain(&tlvlist);
801     return ret;
802   }
803   
804   userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
805   if (userfunc)
806     ret =  userfunc(sess, command, id, msg);
807
808   aim_freetlvchain(&tlvlist);
809   free(msg);
810
811   return ret;  
812 }
813
814 faim_internal int aim_parse_hostonline(struct aim_session_t *sess,
815                                        struct command_rx_struct *command, ...)
816 {
817   rxcallback_t userfunc = NULL;
818   int ret = 1;
819   unsigned short *families = NULL;
820   int famcount = 0, i;
821
822   famcount = (command->commandlen-10)/2;
823   if (!(families = malloc(command->commandlen-10)))
824     return ret;
825
826   for (i = 0; i < famcount; i++)
827     families[i] = aimutil_get16(command->data+((i*2)+10));
828
829   if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0003)))
830     ret = userfunc(sess, command, famcount, families);
831
832   free(families);
833
834   return ret;  
835 }
836
837 faim_internal int aim_parse_hostversions(struct aim_session_t *sess,
838                                          struct command_rx_struct *command, ...)
839 {
840   rxcallback_t userfunc = NULL;
841   int ret = 1;
842   int vercount;
843
844   vercount = (command->commandlen-10)/4;
845   
846   if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0018)))
847     ret = userfunc(sess, command, vercount, command->data+10);
848
849   return ret;  
850 }
851
852 faim_internal int aim_handleredirect_middle(struct aim_session_t *sess,
853                                             struct command_rx_struct *command, ...)
854 {
855   int serviceid = 0;
856   unsigned char *cookie = NULL;
857   char *ip = NULL;
858   rxcallback_t userfunc = NULL;
859   struct aim_tlvlist_t *tlvlist;
860   int ret = 1;
861   
862   tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
863
864   if (aim_gettlv(tlvlist, 0x000d, 1))
865     serviceid = aim_gettlv16(tlvlist, 0x000d, 1);
866   if (aim_gettlv(tlvlist, 0x0005, 1))
867     ip = aim_gettlv_str(tlvlist, 0x0005, 1);
868   if (aim_gettlv(tlvlist, 0x0006, 1))
869     cookie = aim_gettlv_str(tlvlist, 0x0006, 1);
870
871   if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) {
872
873     /*
874      * Chat hack.
875      *
876      */
877     if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0005)))
878       ret =  userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin, (int)sess->pendingjoinexchange);
879       free(sess->pendingjoin);
880       sess->pendingjoin = NULL;
881       sess->pendingjoinexchange = 0;
882   } else if (!serviceid || !ip || !cookie) { /* yeep! */
883     ret = 1;
884   } else {
885     if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0005)))
886       ret =  userfunc(sess, command, serviceid, ip, cookie);
887   }
888
889   if (ip)
890     free(ip);
891   if (cookie)
892     free(cookie);
893
894   aim_freetlvchain(&tlvlist);
895
896   return ret;
897 }
898
899 faim_internal int aim_parse_unknown(struct aim_session_t *sess,
900                                           struct command_rx_struct *command, ...)
901 {
902   u_int i = 0;
903
904   if (!sess || !command)
905     return 1;
906
907   faimdprintf(1, "\nRecieved unknown packet:");
908
909   for (i = 0; i < command->commandlen; i++)
910     {
911       if ((i % 8) == 0)
912         faimdprintf(1, "\n\t");
913
914       faimdprintf(1, "0x%2x ", command->data[i]);
915     }
916   
917   faimdprintf(1, "\n\n");
918
919   return 1;
920 }
921
922
923 faim_internal int aim_negchan_middle(struct aim_session_t *sess,
924                                      struct command_rx_struct *command)
925 {
926   struct aim_tlvlist_t *tlvlist;
927   char *msg = NULL;
928   unsigned short code = 0;
929   rxcallback_t userfunc = NULL;
930   int ret = 1;
931
932   tlvlist = aim_readtlvchain(command->data, command->commandlen);
933
934   if (aim_gettlv(tlvlist, 0x0009, 1))
935     code = aim_gettlv16(tlvlist, 0x0009, 1);
936
937   if (aim_gettlv(tlvlist, 0x000b, 1))
938     msg = aim_gettlv_str(tlvlist, 0x000b, 1);
939
940   if ((userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) 
941     ret =  userfunc(sess, command, code, msg);
942
943   aim_freetlvchain(&tlvlist);
944
945   if (msg)
946     free(msg);
947
948   return ret;
949 }
950
951 /*
952  * aim_parse_generalerrs()
953  *
954  * Middle handler for 0x0001 snac of each family.
955  *
956  */
957 faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
958                                         struct command_rx_struct *command, ...)
959 {
960   unsigned short family;
961   unsigned short subtype;
962   int ret = 1;
963   int error = 0;
964   rxcallback_t userfunc = NULL;
965   
966   family = aimutil_get16(command->data+0);
967   subtype= aimutil_get16(command->data+2);
968   
969   if (command->commandlen > 10)
970     error = aimutil_get16(command->data+10);
971
972   if ((userfunc = aim_callhandler(command->conn, family, subtype))) 
973     ret = userfunc(sess, command, error);
974
975   return ret;
976 }
977
978
979
This page took 1.290385 seconds and 3 git commands to generate.