]> andersk Git - libfaim.git/blob - src/rxhandlers.c
16ce8205df5bf873bb421e45f09f27494f7e0d67
[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 /*
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     faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
179   else
180     faimdprintf(sess, 0, "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(sess, 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_session_t *sess,
245                                            struct aim_conn_t *conn,
246                                            unsigned short family,
247                                            unsigned short type)
248 {
249   struct aim_rxcblist_t *cur;
250
251   if (!conn)
252     return NULL;
253
254   faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
255   
256   for (cur = conn->handlerlist; cur; cur = cur->next) {
257     if ((cur->family == family) && (cur->type == type))
258       return cur->handler;
259   }
260
261   if (type == AIM_CB_SPECIAL_DEFAULT) {
262     faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family);
263     return NULL; /* prevent infinite recursion */
264   }
265
266   faimdprintf(sess, 1, "aim_callhandler: no handler for  0x%04x/0x%04x\n", family, type);
267
268   return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
269 }
270
271 faim_internal int aim_callhandler_noparam(struct aim_session_t *sess,
272                                           struct aim_conn_t *conn,
273                                           u_short family,
274                                           u_short type,
275                                           struct command_rx_struct *ptr)
276 {
277   rxcallback_t userfunc = NULL;
278   userfunc = aim_callhandler(sess, conn, family, type);
279   if (userfunc)
280     return userfunc(sess, ptr);
281   return 1; /* XXX */
282 }
283
284 /*
285   aim_rxdispatch()
286
287   Basically, heres what this should do:
288     1) Determine correct packet handler for this packet
289     2) Mark the packet handled (so it can be dequeued in purge_queue())
290     3) Send the packet to the packet handler
291     4) Go to next packet in the queue and start over
292     5) When done, run purge_queue() to purge handled commands
293
294   Note that any unhandlable packets should probably be left in the
295   queue.  This is the best way to prevent data loss.  This means
296   that a single packet may get looked at by this function multiple
297   times.  This is more good than bad!  This behavior may change.
298
299   Aren't queue's fun? 
300
301   TODO: Get rid of all the ugly if's.
302   TODO: Clean up.
303   TODO: More support for mid-level handlers.
304   TODO: Allow for NULL handlers.
305   
306  */
307 faim_export int aim_rxdispatch(struct aim_session_t *sess)
308 {
309   int i = 0;
310   struct command_rx_struct *workingPtr = NULL;
311   
312   if (sess->queue_incoming == NULL) {
313     faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n");
314     return 0;
315   } else {
316     workingPtr = sess->queue_incoming;
317     for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
318       /*
319        * XXX: This is still fairly ugly.
320        */
321       if (workingPtr->handled)
322         continue;
323
324       /*
325        * This is a debugging/sanity check only and probably could/should be removed
326        * for stable code.
327        */
328       if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) && 
329            (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || 
330           ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) && 
331            (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
332         faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
333         workingPtr->handled = 1;
334         continue;
335       }
336
337       switch(workingPtr->conn->type) {
338       case -1:
339         /*
340          * This can happen if we have a queued command
341          * that was recieved after a connection has 
342          * been terminated.  In which case, the handler
343          * list has been cleared, and there's nothing we
344          * can do for it.  We can only cancel it.
345          */
346         workingPtr->handled = 1;
347         break;
348       case AIM_CONN_TYPE_AUTH: {
349         unsigned long head;
350         
351         head = aimutil_get32(workingPtr->data);
352         if ((head == 0x00000001) && (workingPtr->commandlen == 4)) {
353           faimdprintf(sess, 1, "got connection ack on auth line\n");
354           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
355         } else if (workingPtr->hdr.oscar.type == 0x04) {
356           /* Used only by the older login protocol */
357           workingPtr->handled = aim_authparse(sess, workingPtr);
358         } else {
359           unsigned short family,subtype;
360           
361           family = aimutil_get16(workingPtr->data);
362           subtype = aimutil_get16(workingPtr->data+2);
363           
364           switch (family) {
365             /* New login protocol */
366           case 0x0017:
367             if (subtype == 0x0001)
368               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
369             else if (subtype == 0x0003)
370               workingPtr->handled = aim_authparse(sess, workingPtr);
371             else if (subtype == 0x0007)
372               workingPtr->handled = aim_authkeyparse(sess, workingPtr);
373             else
374               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
375             break;
376
377           case 0x0001:
378             if (subtype == 0x0003)
379               workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
380             else if (subtype == 0x0007)
381               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
382             else if (subtype == 0x0018)
383               workingPtr->handled = aim_parse_hostversions(sess, workingPtr);
384             else
385               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0xffff, workingPtr);
386             break;
387
388           case 0x0007:
389             if (subtype == 0x0003)
390               workingPtr->handled = aim_parse_infochange(sess, workingPtr);
391             else if (subtype == 0x0005)
392               workingPtr->handled = aim_parse_infochange(sess, workingPtr);
393             else if (subtype == 0x0007)
394               workingPtr->handled = aim_parse_accountconfirm(sess, workingPtr);
395             break;
396
397           case AIM_CB_FAM_SPECIAL:
398             if (subtype == AIM_CB_SPECIAL_DEBUGCONN_CONNECT) {
399               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
400               break;
401             } else
402               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
403             break;
404
405           default:
406             break;
407           }
408         }
409         break;
410       }
411       case AIM_CONN_TYPE_BOS: {
412         u_short family;
413         u_short subtype;
414
415         if (workingPtr->hdr.oscar.type == 0x04) {
416           workingPtr->handled = aim_negchan_middle(sess, workingPtr);
417           break;
418         }
419
420         family = aimutil_get16(workingPtr->data);
421         subtype = aimutil_get16(workingPtr->data+2);
422         
423         switch (family) {
424         case 0x0000: /* not really a family, but it works */
425           if (subtype == 0x0001)
426             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
427           else
428             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
429           break;
430         case 0x0001: /* Family: General */
431           switch (subtype) {
432           case 0x0001:
433             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
434             break;
435           case 0x0003:
436             workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
437             break;
438           case 0x0005:
439             workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
440             break;
441           case 0x0007:
442             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
443             break;
444           case 0x000a:
445             workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
446             break;
447           case 0x000f:
448             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
449             break;
450           case 0x0010:
451             workingPtr->handled = aim_parse_evilnotify_middle(sess, workingPtr);
452             break;
453           case 0x0013:
454             workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
455             break;
456           case 0x0018:
457             workingPtr->handled = aim_parse_hostversions(sess, workingPtr);
458             break;
459           default:
460             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
461             break;
462           }
463           break;
464         case 0x0002: /* Family: Location */
465           switch (subtype) {
466           case 0x0001:
467             workingPtr->handled = aim_parse_locateerr(sess, workingPtr);
468             break;
469           case 0x0003:
470             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
471             break;
472           case 0x0006:
473             workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
474             break;
475           default:
476             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
477             break;
478           }
479           break;
480         case 0x0003: /* Family: Buddy List */
481           switch (subtype) {
482           case 0x0001:
483             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
484             break;
485           case 0x0003:
486             workingPtr->handled = aim_parse_buddyrights(sess, workingPtr);
487             break;
488           case 0x000b: /* oncoming buddy */
489             workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
490             break;
491           case 0x000c: /* offgoing buddy */
492             workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
493             break;
494           default:
495             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
496           }
497           break;
498         case 0x0004: /* Family: Messaging */
499           switch (subtype) {
500           case 0x0001:
501             workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
502             break;
503           case 0x0005:
504             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
505             break;
506           case 0x0006:
507             workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr);
508             break;
509           case 0x0007:
510             workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
511             break;
512           case 0x000a:
513             workingPtr->handled = aim_parse_missedcall(sess, workingPtr);
514             break;
515           case 0x000c:
516             workingPtr->handled = aim_parse_msgack_middle(sess, workingPtr);
517             break;
518           default:
519             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
520           }
521           break;
522         case 0x0009:
523           if (subtype == 0x0001)
524             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
525           else if (subtype == 0x0003)
526             workingPtr->handled = aim_parse_bosrights(sess, workingPtr);
527           else
528             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
529           break;
530         case 0x000a:  /* Family: User lookup */
531           switch (subtype) {
532           case 0x0001:
533             workingPtr->handled = aim_parse_searcherror(sess, workingPtr);
534             break;
535           case 0x0003:
536             workingPtr->handled = aim_parse_searchreply(sess, workingPtr);
537             break;
538           default:
539             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
540           }
541           break;
542         case 0x000b: {
543           if (subtype == 0x0001)
544             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
545           else if (subtype == 0x0002)
546             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
547           else
548             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
549           break;
550         }
551         case 0x0013: {
552           faimdprintf(sess, 0, "lalala: 0x%04x/0x%04x\n", family, subtype);
553           break;
554         }
555         case AIM_CB_FAM_SPECIAL: 
556           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
557           break;
558         default:
559           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
560           break;
561         } /* switch(family) */
562         break;
563       } /* AIM_CONN_TYPE_BOS */
564       case AIM_CONN_TYPE_ADS: {
565         unsigned short family;
566         unsigned short subtype;
567
568         family = aimutil_get16(workingPtr->data);
569         subtype= aimutil_get16(workingPtr->data+2);
570
571         if ((family == 0x0000) && (subtype == 0x00001)) {
572           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
573         } else if ((family == 0x0001) && (subtype == 0x0003)) {
574           workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
575         } else {
576           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
577         }
578         break;
579       }
580       case AIM_CONN_TYPE_CHATNAV: {
581         u_short family;
582         u_short subtype;
583         family = aimutil_get16(workingPtr->data);
584         subtype= aimutil_get16(workingPtr->data+2);
585
586         if ((family == 0x0000) && (subtype == 0x00001)) {
587           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
588         } else if ((family == 0x0001) && (subtype == 0x0003)) {
589           workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
590         } else if ((family == 0x000d) && (subtype == 0x0009)) {
591           workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
592         } else {
593           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
594         }
595         break;
596       }
597       case AIM_CONN_TYPE_CHAT: {
598         u_short family, subtype;
599         
600         family = aimutil_get16(workingPtr->data);
601         subtype= aimutil_get16(workingPtr->data+2);
602         
603         if ((family == 0x0000) && (subtype == 0x00001)) {
604           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
605         } else if (family == 0x0001) {
606           if (subtype == 0x0001)
607             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
608           else if (subtype == 0x0003)
609             workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
610           else if (subtype == 0x0007)
611             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
612           else if (subtype == 0x000a)
613             workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
614           else
615             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
616         } else if (family == 0x000e) {
617           if (subtype == 0x0002)
618             workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
619           else if (subtype == 0x0003)
620             workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);      
621           else if (subtype == 0x0004)
622             workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);       
623           else if (subtype == 0x0006)
624             workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
625           else  
626             faimdprintf(sess, 0, "Chat: unknown snac %04x/%04x\n", family, subtype); 
627         } else {
628           faimdprintf(sess, 0, "Chat: unknown snac %04x/%04x\n", family, subtype);
629           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
630         }
631         break;
632       }
633       case AIM_CONN_TYPE_RENDEZVOUS: {
634         /* make sure that we only get OFT frames on these connections */
635         if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
636           faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n");
637           workingPtr->handled = 1; /* get rid of it */
638           break;
639         }
640         
641         /* XXX: implement this */
642         faimdprintf(sess, 0, "faim: OFT frame!\n");
643         
644         break;
645       }
646       case AIM_CONN_TYPE_RENDEZVOUS_OUT: {
647         /* not possible */
648         break;
649       }
650       default:
651         faimdprintf(sess, 0, "internal error: unknown connection type (very bad.) (type = %d, fd = %d, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->commandlen);
652         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
653         break;
654       } 
655     }
656   }
657
658   /* 
659    * This doesn't have to be called here.  It could easily be done
660    * by a seperate thread or something. It's an administrative operation,
661    * and can take a while. Though the less you call it the less memory
662    * you'll have :)
663    */
664   aim_purge_rxqueue(sess);
665   
666   return 0;
667 }
668
669 faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command)
670 {
671   rxcallback_t userfunc = NULL;
672   char sn[MAXSNLEN];
673   unsigned short type;
674   int i = 10+8; /* skip SNAC and cookie */
675   int ret = 1;
676   unsigned char snlen;
677
678   type = aimutil_get16(command->data+i);
679   i += 2;
680
681   snlen = aimutil_get8(command->data+i);
682   i++;
683
684   memset(sn, 0, sizeof(sn));
685   strncpy(sn, (char *)command->data+i, snlen);
686
687   if ((userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x000c)))
688     ret =  userfunc(sess, command, type, sn);
689
690   return ret;
691 }
692
693 /*
694  * The Rate Limiting System, An Abridged Guide to Nonsense.
695  *
696  * OSCAR defines several 'rate classes'.  Each class has seperate
697  * rate limiting properties (limit level, alert level, disconnect
698  * level, etc), and a set of SNAC family/type pairs associated with
699  * it.  The rate classes, their limiting properties, and the definitions
700  * of which SNACs are belong to which class, are defined in the
701  * Rate Response packet at login to each host.  
702  *
703  * Logically, all rate offenses within one class count against further
704  * offenses for other SNACs in the same class (ie, sending messages
705  * too fast will limit the number of user info requests you can send,
706  * since those two SNACs are in the same rate class).
707  *
708  * Since the rate classes are defined dynamically at login, the values
709  * below may change. But they seem to be fairly constant.
710  *
711  * Currently, BOS defines five rate classes, with the commonly used
712  * members as follows...
713  *
714  *  Rate class 0x0001:
715  *      - Everything thats not in any of the other classes
716  *
717  *  Rate class 0x0002:
718  *      - Buddy list add/remove
719  *      - Permit list add/remove
720  *      - Deny list add/remove
721  *
722  *  Rate class 0x0003:
723  *      - User information requests
724  *      - Outgoing ICBMs
725  *
726  *  Rate class 0x0004:
727  *      - A few unknowns: 2/9, 2/b, and f/2
728  *
729  *  Rate class 0x0005:
730  *      - Chat room create
731  *      - Outgoing chat ICBMs
732  *
733  * The only other thing of note is that class 5 (chat) has slightly looser
734  * limiting properties than class 3 (normal messages).  But thats just a 
735  * small bit of trivia for you.
736  *
737  * The last thing that needs to be learned about the rate limiting
738  * system is how the actual numbers relate to the passing of time.  This
739  * seems to be a big mystery.
740  * 
741  */
742 faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
743 {
744   rxcallback_t userfunc = NULL;
745   int ret = 1;
746   int i;
747   int code;
748   unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
749   unsigned long currentavg, maxavg;
750
751   i = 10;
752
753   code = aimutil_get16(command->data+i);
754   i += 2;
755
756   rateclass = aimutil_get16(command->data+i);
757   i += 2;
758
759   windowsize = aimutil_get32(command->data+i);
760   i += 4;
761   clear = aimutil_get32(command->data+i);
762   i += 4;
763   alert = aimutil_get32(command->data+i);
764   i += 4;
765   limit = aimutil_get32(command->data+i);
766   i += 4;
767   disconnect = aimutil_get32(command->data+i);
768   i += 4;
769   currentavg = aimutil_get32(command->data+i);
770   i += 4;
771   maxavg = aimutil_get32(command->data+i);
772   i += 4;
773
774   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x000a)))
775     ret =  userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
776
777   return ret;
778 }
779
780 faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command)
781 {
782   rxcallback_t userfunc = NULL;
783   int ret = 1;
784   int i;
785   unsigned short newevil;
786   struct aim_userinfo_s userinfo;
787
788   i = 10;
789   newevil = aimutil_get16(command->data+10);
790   i += 2;
791
792   memset(&userinfo, 0, sizeof(struct aim_userinfo_s));
793   if (command->commandlen-i)
794     i += aim_extractuserinfo(sess, command->data+i, &userinfo);
795
796   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0010)))
797     ret = userfunc(sess, command, newevil, &userinfo);
798   
799   return ret;
800 }
801
802 faim_internal int aim_parsemotd_middle(struct aim_session_t *sess,
803                                        struct command_rx_struct *command, ...)
804 {
805   rxcallback_t userfunc = NULL;
806   char *msg;
807   int ret=1;
808   struct aim_tlvlist_t *tlvlist;
809   u_short id;
810
811   /*
812    * Code.
813    *
814    * Valid values:
815    *   1 Mandatory upgrade
816    *   2 Advisory upgrade
817    *   3 System bulletin
818    *   4 Nothing's wrong ("top o the world" -- normal)
819    *
820    */
821   id = aimutil_get16(command->data+10);
822
823   /* 
824    * TLVs follow 
825    */
826   if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12)))
827     return ret;
828
829   if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) {
830     aim_freetlvchain(&tlvlist);
831     return ret;
832   }
833   
834   userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0013);
835   if (userfunc)
836     ret =  userfunc(sess, command, id, msg);
837
838   aim_freetlvchain(&tlvlist);
839   free(msg);
840
841   return ret;  
842 }
843
844 faim_internal int aim_parse_hostonline(struct aim_session_t *sess,
845                                        struct command_rx_struct *command, ...)
846 {
847   rxcallback_t userfunc = NULL;
848   int ret = 1;
849   unsigned short *families = NULL;
850   int famcount = 0, i;
851
852   famcount = (command->commandlen-10)/2;
853   if (!(families = malloc(command->commandlen-10)))
854     return ret;
855
856   for (i = 0; i < famcount; i++)
857     families[i] = aimutil_get16(command->data+((i*2)+10));
858
859   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0003)))
860     ret = userfunc(sess, command, famcount, families);
861
862   free(families);
863
864   return ret;  
865 }
866
867 faim_internal int aim_parse_accountconfirm(struct aim_session_t *sess,
868                                            struct command_rx_struct *command)
869 {
870   rxcallback_t userfunc = NULL;
871   int ret = 1;
872   int status = -1;
873
874   status = aimutil_get16(command->data+10);
875
876   if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, 0x0007)))
877     ret = userfunc(sess, command, status);
878
879   return ret;  
880 }
881
882 faim_internal int aim_parse_infochange(struct aim_session_t *sess,
883                                        struct command_rx_struct *command)
884 {
885   unsigned short subtype; /* called for both reply and change-reply */
886   int i;
887
888   subtype = aimutil_get16(command->data+2);
889
890   /*
891    * struct {
892    *    unsigned short perms;
893    *    unsigned short tlvcount;
894    *    aim_tlv_t tlvs[tlvcount];
895    *  } admin_info[n];
896    */
897   for (i = 10; i < command->commandlen; ) {
898     int perms, tlvcount;
899
900     perms = aimutil_get16(command->data+i);
901     i += 2;
902
903     tlvcount = aimutil_get16(command->data+i);
904     i += 2;
905
906     while (tlvcount) {
907       rxcallback_t userfunc;
908       struct aim_tlv_t *tlv;
909       int str = 0;
910
911       if ((aimutil_get16(command->data+i) == 0x0011) ||
912           (aimutil_get16(command->data+i) == 0x0004))
913         str = 1;
914
915       if (str)
916         tlv = aim_grabtlvstr(command->data+i);
917       else
918         tlv = aim_grabtlv(command->data+i);
919
920       /* XXX fix so its only called once for the entire packet */
921       if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, subtype)))
922         userfunc(sess, command, perms, tlv->type, tlv->length, tlv->value, str);
923
924       if (tlv)
925         i += 2+2+tlv->length;
926
927       if (tlv && tlv->value)
928         free(tlv->value);
929       if (tlv)
930         free(tlv);
931
932       tlvcount--;
933     }
934   }
935
936   return 1;
937 }
938
939 faim_internal int aim_parse_hostversions(struct aim_session_t *sess,
940                                          struct command_rx_struct *command, ...)
941 {
942   rxcallback_t userfunc = NULL;
943   int ret = 1;
944   int vercount;
945
946   vercount = (command->commandlen-10)/4;
947   
948   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0018)))
949     ret = userfunc(sess, command, vercount, command->data+10);
950
951   return ret;  
952 }
953
954 faim_internal int aim_handleredirect_middle(struct aim_session_t *sess,
955                                             struct command_rx_struct *command, ...)
956 {
957   int serviceid = 0;
958   unsigned char *cookie = NULL;
959   char *ip = NULL;
960   rxcallback_t userfunc = NULL;
961   struct aim_tlvlist_t *tlvlist;
962   int ret = 1;
963   
964   tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
965
966   if (aim_gettlv(tlvlist, 0x000d, 1))
967     serviceid = aim_gettlv16(tlvlist, 0x000d, 1);
968   if (aim_gettlv(tlvlist, 0x0005, 1))
969     ip = aim_gettlv_str(tlvlist, 0x0005, 1);
970   if (aim_gettlv(tlvlist, 0x0006, 1))
971     cookie = aim_gettlv_str(tlvlist, 0x0006, 1);
972
973   if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) {
974
975     /*
976      * Chat hack.
977      *
978      */
979     if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
980       ret =  userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin, (int)sess->pendingjoinexchange);
981       free(sess->pendingjoin);
982       sess->pendingjoin = NULL;
983       sess->pendingjoinexchange = 0;
984   } else if (!serviceid || !ip || !cookie) { /* yeep! */
985     ret = 1;
986   } else {
987     if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
988       ret =  userfunc(sess, command, serviceid, ip, cookie);
989   }
990
991   if (ip)
992     free(ip);
993   if (cookie)
994     free(cookie);
995
996   aim_freetlvchain(&tlvlist);
997
998   return ret;
999 }
1000
1001 faim_internal int aim_parse_unknown(struct aim_session_t *sess,
1002                                           struct command_rx_struct *command, ...)
1003 {
1004   u_int i = 0;
1005
1006   if (!sess || !command)
1007     return 1;
1008
1009   faimdprintf(sess, 1, "\nRecieved unknown packet:");
1010
1011   for (i = 0; i < command->commandlen; i++)
1012     {
1013       if ((i % 8) == 0)
1014         faimdprintf(sess, 1, "\n\t");
1015
1016       faimdprintf(sess, 1, "0x%2x ", command->data[i]);
1017     }
1018   
1019   faimdprintf(sess, 1, "\n\n");
1020
1021   return 1;
1022 }
1023
1024
1025 faim_internal int aim_negchan_middle(struct aim_session_t *sess,
1026                                      struct command_rx_struct *command)
1027 {
1028   struct aim_tlvlist_t *tlvlist;
1029   char *msg = NULL;
1030   unsigned short code = 0;
1031   rxcallback_t userfunc = NULL;
1032   int ret = 1;
1033
1034   tlvlist = aim_readtlvchain(command->data, command->commandlen);
1035
1036   if (aim_gettlv(tlvlist, 0x0009, 1))
1037     code = aim_gettlv16(tlvlist, 0x0009, 1);
1038
1039   if (aim_gettlv(tlvlist, 0x000b, 1))
1040     msg = aim_gettlv_str(tlvlist, 0x000b, 1);
1041
1042   if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) 
1043     ret =  userfunc(sess, command, code, msg);
1044
1045   aim_freetlvchain(&tlvlist);
1046
1047   if (msg)
1048     free(msg);
1049
1050   return ret;
1051 }
1052
1053 /*
1054  * aim_parse_generalerrs()
1055  *
1056  * Middle handler for 0x0001 snac of each family.
1057  *
1058  */
1059 faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
1060                                         struct command_rx_struct *command, ...)
1061 {
1062   unsigned short family;
1063   unsigned short subtype;
1064   int ret = 1;
1065   int error = 0;
1066   rxcallback_t userfunc = NULL;
1067   
1068   family = aimutil_get16(command->data+0);
1069   subtype= aimutil_get16(command->data+2);
1070   
1071   if (command->commandlen > 10)
1072     error = aimutil_get16(command->data+10);
1073
1074   if ((userfunc = aim_callhandler(sess, command->conn, family, subtype))) 
1075     ret = userfunc(sess, command, error);
1076
1077   return ret;
1078 }
1079
1080
1081
This page took 0.108625 seconds and 3 git commands to generate.