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