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